did-btcr2-js

ADR 018: Beacon Hierarchy: Singleton, CAS, and SMT Beacon Types

Status: Accepted

Date: 2026-03-28

Commit: bb8aee7

Context

In did:btcr2, a beacon is how a DID controller announces updates to their DID document on-chain. The protocol supports three distinct shapes: each with different trust, throughput, and resolution-complexity trade-offs:

Before this landed, the codebase had an earlier experiment where beacon types were modeled as configuration flags on a single class. That made the factory logic gnarly (many if (type === 'x') branches) and obscured the fundamentally different resolution paths each type implies.

Options considered

  1. Configuration flags on a single Beacon class. Lowest file count; highest per-type branching at every call site.
  2. Union type with discriminated variants. Works for pure-data beacon records but awkward for the stateful broadcastSignal() / processSignals() methods each type needs.
  3. Class hierarchy: abstract Beacon base + three concrete subclasses + a factory.

Decision

Option 3. Beacon is an abstract base class encoding the common contract (fee estimation, PSBT construction, signal broadcast). Three concrete subclasses: SingletonBeacon, CASBeacon, SMTBeacon: implement their type-specific behavior. BeaconFactory.establish(service) dispatches on the service record to instantiate the correct subclass.

Each subclass owns:

Aggregate beacons (CAS, SMT) ship a second multi-party path via the AggregationService subsystem (ADR 020).

Consequences

Positive

Negative

References