Skip to content

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 layersConcept
4 · INTEGRATION3 · EVIDENCE2 · EXECUTION1 · CONSENSUSAPIs and clientssubmit, read, proveEffect runtimeafter finalityConnectorswebhook, Kafka, S3, IPFSState rootone per blockProofsinclusion and exclusionCardano anchoroptionalState machinedeterministic rulesCompositeseveral machines, one rootAuthenticated stateMPF or JMTMemberssigned envelopesTwo-phase roundPREPARE, then COMMITFinality certificatethreshold signatures4 · INTEGRATION3 · EVIDENCE2 · EXECUTION1 · CONSENSUSAPIs and clientssubmit, read, proveEffect runtimeafter finalityConnectorswebhook, Kafka, S3, IPFSState rootone per blockProofsinclusion and exclusionCardano anchoroptionalState machinedeterministic rulesCompositeseveral machines, one rootAuthenticated stateMPF or JMTMemberssigned envelopesTwo-phase roundPREPARE, then COMMITFinality certificatethreshold signatures
  • 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.
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-log built 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.
Consensus at the bottom, integration at the top. Members run the execution layer while they vote, so the finality certificate covers its result.
LayerWhat it doesProvided byWhat it guarantees
1. ConsensusMembers order messages into blocks and certify each block with a threshold of signatures.YanoA final block is never rolled back.
2. ExecutionOne 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. EvidenceA state root after every block, proofs against it, and optional Cardano anchors.YanoA record can be checked without trusting the node that served it.
4. IntegrationAPIs 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.

This is the boundary to internalize: deterministic intent and external execution never mix.

The two planesConcept
CONSENSUS PLANE · IDENTICAL ON EVERY MEMBEREXECUTION PLANE · OUTSIDE CONSENSUSMessagesin a final blockState machineapply()Application stateEffect recordauthorized, not runState rootcovers bothFinality gateblock is finalExecutorruns the actionExternal systemResult message~fx/result, signedafter finalityat least onceoutcomein a later blockCONSENSUS PLANE · IDENTICAL ON EVERY MEMBEREXECUTION PLANE · OUTSIDE CONSENSUSMessagesin a final blockState machineapply()Application stateEffect recordauthorized, not runState rootcovers bothFinality gateblock is finalExecutorruns the actionExternal systemResult message~fx/result, signedafter finality
  • 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).
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 an effectsRoot, 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, and apply() records it exactly once.
The state machine records what is authorized; it never performs it. An effect record crosses to the execution plane only after its block is final, and the outcome crosses back only as a new message.
  • 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 nodeConcept
ONE YANO NODEAPPCHAINSUBSYSTEM · ONE PER HOSTED CHAINCardano nodesync, relay, L1 eventsAppChainManagerone per node: shared transport and catch-upMessage pooladmission, backpressureConsensus engineAppChainEngineMember groupstatic or governedState machineyour rulesLedger storeRocksDB, MPF or JMTAnchor and effectsoptional servicesREST, SSE, clients/api/v1/app-chain/…Plugin catalogmanifested bundlesL1 eventsverified envelopessubmit, read, provecontributionsONE YANO NODEAPPCHAINSUBSYSTEM · ONE PER HOSTED CHAINCardano nodesync and relayAppChainManagertransport, catch-upMessage pooladmissionConsensus engineAppChainEngineMember groupstatic or governedState machineyour rulesLedger storeRocksDB, MPF or JMTAnchor, effectsoptionalREST, SSE, clientsper chainPlugin catalogmanifested bundles
  • 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).
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-log is 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 →
One node can host several ledgers. Each hosted chain has its own subsystem, ledger, state machine, and members; chains share only the node’s networking and its view of Cardano.
ComponentResponsibilityKey property
REST API, SSE, and clientsSubmit messages, read blocks and state, stream finality, request proofs.Clients can verify evidence rather than trust a response.
AppChainManagerOne per node: shared message transport, catch-up server, dispatch by chain id.Chains share only networking and the node’s view of Cardano.
Message poolHolds admitted messages until a block includes them.In memory; a full pool answers 429.
Consensus engineRuns the two-phase round, view changes, and catch-up for one chain.A serial event loop; each final block is one atomic write.
Member groupKnows the members and threshold at every height.Old blocks verify against the members of their time.
State machineInterprets message bodies and writes deterministic state.No clock, randomness, or external I/O.
Ledger storeBlocks, certificates, authenticated state, indexes, vote locks.One RocksDB instance per chain.
Anchor and effect servicesOptional anchoring, L1 observers, sinks, and the effect runtime.External failures neither fork nor block consensus.
Plugin catalogLoads manifested bundles and activates their contributions.Trusted in-process code; it checks manifests, but it is not a sandbox.

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.

A composite profileConcept
COMPOSITE PROFILE · EXAMPLE PRESETregistryregistry.command.v1approvalsapprovals.command.v1doc-traildoc-trail.command.v1evidenceno public topicevidence-notifyworkflow 1 · evidence.command.v1evidence-releaseworkflow 2 · evidence.release.v1One state rootprofile marker from height 1one atomic transition per blockCOMPOSITE PROFILE · EXAMPLE PRESETregistryregistry.command.v1approvalsapprovals.command.v1doc-traildoc-trail.command.v1evidenceno public topicevidence-notifyworkflow 1 · evidence.command.v1evidence-releaseworkflow 2 · evidence.release.v1One state rootprofile marker from height 1
  • 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).
registry
The kv-registry machine as component registry, on topic registry.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 approvals machine as component approvals, on topic approvals.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-trail machine as component doc-trail, on topic doc-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 the evidence/get query.
evidence-notify
Runs first, for messages on evidence.command.v1. Its only participant is the evidence component.
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.
Example: the stock 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.

Each node keeps three sibling stores. Mixing them up is a correctness bug:

StoreContentsAuthority
chainstate/Cardano L1 stateAuthoritative
appchain-chainstate/App ledger stateAuthoritative
appchain-indexers/Local read indexesRebuildable, never authoritative

Derived indexes never advance beyond authoritative app ledger state, and app ledger data is never placed below L1 chainstate.

  • 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.