Architecture
An app ledger has four layers and one boundary that matters more than the rest. This page names the layers, shows that boundary, and maps both onto the components of a Yano node. To follow a single message through them, see Life of a message.
You’ll learn: what each layer does and who provides it, why consensus code never performs external actions, which component of a node does what, and how a composite runs several state machines under one root.
Before you start: read What is an app ledger?
The four layers
Section titled “The four layers”- 4 · Integration: APIs and clients, Effect runtime, Connectors.
- 3 · Evidence: State root, Proofs, Cardano anchor.
- 2 · Execution: State machine, Composite, Authenticated state.
- 1 · Consensus: Members, Two-phase round, Finality certificate.
Select a block to see what it does and who provides it.
- APIs and clients
- Each node serves a REST API and an SSE stream per chain. The CLI, the Java client, App-Chain Studio, and the products use them. Provided by Yano; clients and SDKs by Yano X.
- Effect runtime
- Runs effect records after their block is final, outside consensus, and returns each result as a new message. Provided by Yano. Effects →
- Connectors
- Executors that perform effects. Yano provides the webhook executor; Yano X adds Kafka, S3-compatible object storage, IPFS, and Cardano payments as optional plugins.
- State root
- The root of the authenticated state after each block, identical on every honest member. Provided by Yano.
- Proofs
- A proof shows that a record is, or is not, in the state under a root. Proof subjects let a client ask in application terms. Yano provides proofs; state machines declare their subjects. State and proofs →
- Cardano anchor
- Publishes a certified height, block hash, and state root to Cardano, in transaction metadata or a script-controlled anchor. Finality never waits for it. Provided by Yano. Cardano anchoring →
- State machine
- The only component that reads message bodies. Every member applies each block with the same code and gets the same result. Yano has
ordered-logbuilt in; Yano X provides the other stock machines. Determinism rules → - Composite
- One state machine that hosts several components and the workflows between them under one state root. Provided by Yano X. Composite state machines →
- Authenticated state
- Every write a state machine makes is an entry in one authenticated tree. Its type, MPF or JMT, is fixed when the ledger is created. Provided by Yano.
- Members
- Each organization runs a member identified by an Ed25519 key. The member that accepts a message signs its envelope. A ledger has at most 32 members. Provided by Yano.
- Two-phase round
- A leader proposes each block; members re-execute it and vote twice. A failed leader is replaced through a certified view change. Provided by Yano. Consensus and finality →
- Finality certificate
- COMMIT signatures from a threshold of members. With it, a block is final and is never rolled back. Provided by Yano.
| Layer | What it does | Provided by | What it guarantees |
|---|---|---|---|
| 1. Consensus | Members order messages into blocks and certify each block with a threshold of signatures. | Yano | A final block is never rolled back. |
| 2. Execution | One deterministic state machine computes each block’s new state. Members run it while they vote. | Yano runs it. ordered-log is built in; Yano X provides the other stock machines and composites. | Every honest member computes the same state. |
| 3. Evidence | A state root after every block, proofs against it, and optional Cardano anchors. | Yano | A record can be checked without trusting the node that served it. |
| 4. Integration | APIs and clients, plus effects that act on external systems after finality. | Yano provides the APIs, the effect runtime, and the webhook executor. Yano X adds connectors, SDKs, and products. | External actions never run inside consensus. |
Two identities stay separate across the layers. The member that accepts a message signs its envelope; that is transport. When a workflow needs a person or organization to approve something, their signature travels inside the message body; that is business authority.
The two-plane design
Section titled “The two-plane design”This is the boundary to internalize: deterministic intent and external execution never mix.
- Consensus plane · identical on every member: Messages, State machine, Application state, Effect record, State root.
- Execution plane · outside consensus: Result message, Finality gate, Executor.
- Messages → State machine.
- State machine → Application state.
- State machine → Effect record.
- Application state → State root.
- Effect record → State root.
- Effect record → Finality gate (after finality).
- Finality gate → Executor.
- Executor → External system (at least once).
- Executor → Result message (outcome).
- Result message → Messages (in a later block).
Select a block to see what it does.
- Messages
- The ordered messages of a block. Every member runs the same block through the same state machine.
- State machine
- Deterministic code that reads message bodies, writes state, and emits effect records. It never calls the network, reads a clock, or touches files. Determinism rules →
- Application state
- The application’s records, written through
AppStateWriter. Every write is an entry in the authenticated state. - Effect record
- An immutable description of an external action, emitted through
AppEffectEmitter. It is committed to the state root through aneffectsRoot, so an authorized action is provable before it runs. - State root
- One root commits to the application state and the effect records. Members sign it, and proofs and anchors refer to it.
- Finality gate
- An effect becomes eligible only after its block is final and its gate is satisfied. The default gate is
app-final. - Executor
- An executor outside consensus performs the action: a webhook, Kafka, object storage, IPFS, or a Cardano payment. It may run more than once, so executors and receivers must be idempotent. Effects →
- External system
- The system that receives the action. It is not part of the ledger and cannot change state directly.
- Result message
- The outcome returns as an ordinary member-signed message on
~fx/result. It is ordered and finalized like any other message, andapply()records it exactly once.
- deterministic, on every member
- node-local execution
- outside the ledger
The state machine records what is authorized. It never calls Kafka, IPFS, S3, Cardano, an ERP, or a webhook during consensus. After the block is final, an executor outside consensus performs the action and reports the outcome back as a new message.
The guarantee is:
- exactly-once incorporation of each result into state; and
- at-least-once external execution.
So every executor and every receiver must be idempotent under the supplied idempotency identity. See Effects.
Inside a Yano node
Section titled “Inside a Yano node”- One Yano node: Cardano node, AppChainManager, REST, SSE, clients, Plugin catalog.
- AppChainSubsystem · one per hosted chain: Message pool, Consensus engine, Member group, State machine, Ledger store, Anchor and effects.
- Cardano node → AppChainManager (L1 events).
- AppChainManager → AppChainSubsystem · one per hosted chain (verified envelopes).
- REST, SSE, clients → AppChainSubsystem · one per hosted chain (submit, read, prove).
- Plugin catalog → AppChainSubsystem · one per hosted chain (contributions).
Select a component to see what it does.
- Cardano node
- Yano’s Cardano node: chain sync, relay, and block production on a devnet. Hosted ledgers use its view of Cardano for the optional L1 reference, L1 observations, and anchoring.
- AppChainManager
- One per node. It runs one shared inbound transport for app messages (protocol 100) and one catch-up server (protocol 103), and dispatches each verified envelope to the chain it belongs to.
- Message pool
- Admitted messages wait here until a block includes them. A full pool answers 429. The pool lives in memory and is lost on restart.
- Consensus engine
- The two-phase round, view changes, and catch-up, on one serial event loop per chain. It commits each final block, its certificate, and the new state in one atomic RocksDB batch. Consensus and finality →
- Member group
MemberGroup: the members and threshold at every height, from configuration (static) or from finalized governance commands (governed).- State machine
AppStateMachine: the deterministic application rules for this chain.ordered-logis built in; Yano X plugins provide the others. State machines →- Ledger store
AppLedgerStore: one RocksDB instance per chain holding blocks, certificates, the authenticated state, indexes, and vote locks.- Anchor and effects
- Optional per-chain services: anchoring on the anchor leader, L1 observers, finalized-block sinks, and the effect runtime with its executors.
- REST, SSE, clients
- The node’s REST API and server-sent event stream, scoped per chain under
/api/v1/app-chain/chains/{chainId}/. The CLI, the Java client, App-Chain Studio, and the products use them. REST API → - Plugin catalog
- Loads manifested bundles from the plugin directory and activates their contributions: state machines, effect executors, sinks, APIs, and queries. Plugins run in the node’s process as trusted code; the catalog checks manifests and compatibility, but it is not a sandbox. Plugin framework →
| Component | Responsibility | Key property |
|---|---|---|
| REST API, SSE, and clients | Submit messages, read blocks and state, stream finality, request proofs. | Clients can verify evidence rather than trust a response. |
AppChainManager | One per node: shared message transport, catch-up server, dispatch by chain id. | Chains share only networking and the node’s view of Cardano. |
| Message pool | Holds admitted messages until a block includes them. | In memory; a full pool answers 429. |
| Consensus engine | Runs the two-phase round, view changes, and catch-up for one chain. | A serial event loop; each final block is one atomic write. |
| Member group | Knows the members and threshold at every height. | Old blocks verify against the members of their time. |
| State machine | Interprets message bodies and writes deterministic state. | No clock, randomness, or external I/O. |
| Ledger store | Blocks, certificates, authenticated state, indexes, vote locks. | One RocksDB instance per chain. |
| Anchor and effect services | Optional anchoring, L1 observers, sinks, and the effect runtime. | External failures neither fork nor block consensus. |
| Plugin catalog | Loads manifested bundles and activates their contributions. | Trusted in-process code; it checks manifests, but it is not a sandbox. |
Composite state machines
Section titled “Composite state machines”One app ledger selects exactly one state machine. A composite is a state machine that hosts several reusable components and the workflows between them under one state root.
- Composite profile · example preset: registry, approvals, doc-trail, evidence, evidence-notify, evidence-release.
- Composite profile · example preset → One state root (one atomic transition per block).
Select a component or workflow to see what the profile commits for it.
- registry
- The
kv-registrymachine as componentregistry, on topicregistry.command.v1. Each component declares its version, configuration id, topics, query paths, effect quota, and the heights at which it is active. It reads and writes only its own namespace. - approvals
- The
approvalsmachine as componentapprovals, on topicapprovals.command.v1, with its on-approved effect disabled in this preset. Each component declares its version, configuration id, topics, query paths, effect quota, and the heights at which it is active. It reads and writes only its own namespace. - doc-trail
- The
doc-trailmachine as componentdoc-trail, on topicdoc-trail.command.v1. Each component declares its version, configuration id, topics, query paths, effect quota, and the heights at which it is active. It reads and writes only its own namespace. - evidence
- The evidence registry as component
evidence. In the gated preset it has no public topic: evidence changes only through the two workflows. It answers theevidence/getquery. - evidence-notify
- Runs first, for messages on
evidence.command.v1. Its only participant is theevidencecomponent. - evidence-release
- Runs second, for messages on
evidence.release.v1, and coordinates all four components in one atomic step. Workflows are the only way to change several components together. Workflow order is execution order, so it is part of the committed profile. - One state root
- All components and workflows write to one authenticated state. In fixed mode the profile’s canonical bytes are stored as a marker at height 1 and checked on restart and at the start of every block, so a different order or configuration fails instead of silently forming another application. Governed mode records profile epochs instead.
evidence-v1-gated preset. The profile is canonical data, committed to the state, so every member runs the same components in the same order.- component
- workflow, in committed order
A composite profile declares each component’s id, version, configuration id, topics, query paths, effect quota, and activation heights, plus its workflows in execution order. Components read and write only their own namespace; changes that span components go through a declared workflow. The profile is canonical data: in fixed mode it is stored at height 1 and checked on restart and at the start of every block, so a different order or configuration fails rather than silently forming a different application.
Two modes:
- Fixed keeps one profile for the life of the chain.
- Governed keeps an append-only chain of profile epochs. Operators install the reviewed current and future profiles on every member first, then a threshold authorizes one exact profile digest and a future activation height. Changing YAML or a JAR alone never changes consensus behavior.
Declarative bindings, an experimental feature, build a composite from YAML instead of Java; the compiled rules are part of the committed profile.
Data on disk
Section titled “Data on disk”Each node keeps three sibling stores. Mixing them up is a correctness bug:
| Store | Contents | Authority |
|---|---|---|
chainstate/ | Cardano L1 state | Authoritative |
appchain-chainstate/ | App ledger state | Authoritative |
appchain-indexers/ | Local read indexes | Rebuildable, never authoritative |
Derived indexes never advance beyond authoritative app ledger state, and app
ledger data is never placed below L1 chainstate.
Deployment shape
Section titled “Deployment shape”- JVM: copy a self-contained manifested bundle into every member’s plugin directory, select it in configuration, and restart. No Yano rebuild is needed.
- Native: Yano’s native image is core-only. Yano X extensions are JVM-only.
- Several ledgers per node: one node can host several independently configured chains.
- Executor placement: effects can run on a designated member, a dedicated executor node, or an external worker through the claim and report API.
See the deployment guide for running members.
Where to go next
Section titled “Where to go next”- Consensus and finality: how a block becomes final.
- State and proofs: what a root commits to and how to verify it.
- Effects: the execution plane in detail.
- Determinism rules: what consensus code may not do.