> For the complete documentation index, see [llms.txt](https://docs.bitsafe.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bitsafe.finance/decentralization-manager/concepts-and-development/architecture-overview.md).

# Architecture overview

[Overview](/decentralization-manager/overview.md)

## Purpose

Decentralization Manager coordinates Canton topology, package distribution, contract deployment and governance for a party that several organizations control. This page describes the components, the trust model between nodes and the background tasks.

Task pages hold the procedures. The [API and workflow reference](/decentralization-manager/operations-and-reference/api-and-workflow-reference.md) holds the routes and the status values.

## One node per organization

Each organization runs its own Decentralization Manager node. A node is one running Decentralization Manager process. Each node connects to one Canton participant.

The organization controls the operator login, the Noise key, the database, the Canton credentials and the upgrades of its node.

## Component map

| Component                  | What it does                                                                                                                                                    | Boundary                                                                                       |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| Web interface and HTTP API | Serves the operator UI and the REST API on the HTTP port (default `8080`).                                                                                      | Operator login through the identity provider, the admin role and input validation.             |
| Tenant API                 | Serves the `/v0/tenant/*` routes. A wallet or a party owner uses them to create a co-validated external party, or to add hosts to an existing party.            | A bearer API key from `DECPM_TENANT_API_KEYS`. The operator login does not apply.              |
| Peer listener              | Accepts Noise connections from other nodes on the Noise port (default `9000`).                                                                                  | The peer allowlist and the wire protocol version.                                              |
| Workflow engine            | Runs the coordinated workflows as fixed step sequences.                                                                                                         | Each peer checks every command against the invitation that it accepted.                        |
| Canton Admin API client    | Reads and writes topology, manages vault keys, uploads DARs and copies the active contracts of a party.                                                         | Node-level administrative access to the participant.                                           |
| Canton Ledger API client   | Submits commands, reads contracts, and prepares and executes interactive submissions.                                                                           | The party credentials that the node stores for each Decentralized Party.                       |
| Transaction signer         | Signs a prepared transaction of the party with the Daml key of the member.                                                                                      | The key custody of the participant. See [Transaction signing](#transaction-signing).           |
| Reward automation          | Assigns the reward coupons of a party to the beneficiary split that governance approved.                                                                        | An on-ledger delegation that names the assigners. See [Reward automation](#reward-automation). |
| Metrics listener           | Serves Prometheus metrics at `/metrics` on its own port (default `9464`).                                                                                       | None. The listener has no authentication and binds to `DECPM_HOST`.                            |
| Data directory             | Holds the Noise key, the staged DARs and the database under `data/`. The database stores the peers, the party credentials, the workflow runs and the audit log. | File permissions, `DECPM_DB_ENCRYPTION_KEY` and backups.                                       |
| Daml governance packages   | Define the governance rules, proposals, confirmations and execution results on the ledger.                                                                      | The vetted package versions and on-ledger authorization.                                       |

Two clients come with the repository. The `decman-cli` terminal UI calls the operator API of a node. The `decman-wallet` Rust library calls the tenant API for a wallet.

{% hint style="warning" %}
Keep the metrics port on a private network, because the metrics listener answers every request without a login. A fresh node also accepts its first `PUT /party-config` without a token. Configure the party credentials before you expose the HTTP port. See [Authentication and operator roles](/decentralization-manager/operations-and-reference/authentication-and-operator-roles.md).
{% endhint %}

## Peers

A peer is another Decentralization Manager node with a verified peer record. The record holds the participant ID, a name, the Noise address and port, and the Noise public key. Operators exchange peer records through an authenticated channel outside Decentralization Manager. See [Connect peers](/decentralization-manager/get-started/connect-peers.md).

A peer connection alone creates no Canton topology, no hosting and no governance membership. A changed Noise public key is a different peer identity. Every node that lists the peer must then update its record.

## Wire protocol

Nodes talk to each other with the Noise Protocol Framework over TCP. The protocol has these parts:

* **Keys.** Each node has one secp256k1 Noise key. The node generates the key at its first start and keeps it in its data directory.
* **Handshake.** Two nodes derive a shared secret from their Noise keys. The handshake uses that secret as its pre-shared key, so it fails when a public key is wrong.
* **Allowlist.** A node accepts a connection only from a public key in its peer list.
* **Messages.** Each message is an HTTP request or an HTTP response inside the encrypted channel.
* **Heartbeats.** Each node pings its peers every 5 seconds to track reachability.
* **Message kinds.** The protocol carries invitations, commands, replies, data uploads, chunked transfers and active contract blocks.
* **Run routing.** Each frame names its workflow run. One node can therefore coordinate more than one workflow run at a time.
* **Version.** Each frame starts with a wire protocol version. A node rejects a frame with a different version.

A node accepts a peer only when the peer uses the same wire version and runs version `0.1.9` or later. All nodes of a Decentralized Party must run the same release. A release that changes the wire version needs a lockstep upgrade of every node. See [Backup, recovery, and upgrades](/decentralization-manager/operations-and-reference/backup-recovery-and-upgrades.md).

Peer traffic uses Noise encryption, not TLS. The Noise port therefore needs a plain TCP path between the nodes. The byte layout of a frame is in [`crates/decman/src/noise/mod.rs`](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/noise/mod.rs).

## Workflows and the coordinator

The node that starts a workflow run is the coordinator of that run. Any node can coordinate a workflow run. The role lasts for one run and gives no lasting control of the party.

| Workflow         | What it does                                                                                                             |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Onboarding       | Creates a Decentralized Party with several owner participants.                                                           |
| Kick             | Removes a member participant from a Decentralized Party.                                                                 |
| Add party        | Adds a member participant and copies the active contracts of the party to it. The UI calls this workflow **Add Member**. |
| Change threshold | Changes the namespace threshold of a Decentralized Party.                                                                |
| DARs             | Uploads DAR files to every participant.                                                                                  |
| Contracts        | Creates contracts as the Decentralized Party, with signatures from the members.                                          |

The contracts workflow does not upload DARs. Distribute the packages with the DARs workflow before a contract deployment.

A typical workflow run has these steps:

1. The coordinator checks the health and the wire version of each peer.
2. The coordinator sends an invitation to each peer.
3. Each peer operator reviews the invitation and accepts it or declines it.
4. Each peer that accepts connects to the coordinator and asks for commands.
5. Each peer does its local step and sends the result back.
6. The coordinator goes to the next step when enough peers answer.
7. The coordinator submits the result to Canton.
8. Every operator checks the resulting Canton state on their own node.

For kick, add-party and change-threshold, the coordinator signs its proposals in a temporary topology store. No proposal that can take effect reaches the synchronizer before the submit step.

## Coordinator and peer trust model

The coordinator orders the steps of a workflow run. A peer runs the commands that the coordinator sends. The two roles have different trust:

* **Peers trust the coordinator to order the run.** The coordinator decides when each step runs, collects the signatures and submits the result.
* **Peers do not trust the coordinator for content.** The coordinator builds the topology proposals, the DAR bytes and the prepared ledger submissions. A compromised or modified coordinator can put anything in them.
* **The invitation holds the consent of the peer operator.** It names the party, the members, the threshold, the participant that joins or leaves, and the file name and SHA-256 hash of each DAR.
* **A contracts invitation also names each contract to create.** For each contract, it names the package ID, the module, the template and a hash of the create arguments.

The peer stores the accepted invitation. Before the peer signs or installs anything, it checks these rules against the invitation:

* The command belongs to the accepted workflow kind.
* Each topology proposal targets the accepted party, member set and threshold.
* For kick, add-party and change-threshold, each proposal is exactly the expected change to the current on-chain state. The proposal must also use the next serial number.
* The peer computes the hash of each prepared ledger submission again from its transaction. The submission must act as the accepted party.
* A contract deployment contains exactly the accepted creates, in the accepted order, and nothing else.
* Each DAR file matches the file name and the SHA-256 hash in the invitation.

A mismatch fails the step. The peer tries a failed step again after 2 seconds. After 6 consecutive step failures, the peer stops the workflow run and reports the reason to the coordinator.

The coordinator also stops counting a peer that stays silent for 10 minutes. The coordinator then fails the workflow run when the current step can no longer reach its peer quorum.

These checks limit what a coordinator can get a signature for. They do not make the coordinator trustworthy. For example, a peer cannot check the keys of the other members during onboarding, because the party does not exist yet.

The repository lists every remaining gap in its [coordinator and peer trust model](https://github.com/DLC-link/decentralization-manager/blob/main/docs/ARCHITECTURE.md#coordinator--peer-trust-model). Accept an invitation only when you agree with every value in it. See also [Security architecture](/decentralization-manager/operations-and-reference/security-architecture.md).

Governance confirm and execute are not coordinated workflows. Each node builds these commands itself. The Daml contracts then check each command against the on-ledger proposal.

## Tenant API path

The tenant API is a separate path from the Noise workflows. A wallet calls the node of each host over HTTP. The nodes keep no shared run state. Canton holds the only shared state.

A wallet creates a co-validated external party in these steps:

1. The wallet calls `prepare` on every host. Each host builds the hosting proposal independently.
2. The wallet compares the proposal bytes from all hosts. The wallet stops when the bytes differ.
3. The wallet signs the proposal hashes with the party key. The private key never leaves the wallet.
4. The wallet calls `execute` on every host. Each host checks the bytes again, adds its own signature and submits the proposal.
5. The wallet polls the status route on every host until each host reports the party as hosted.

The tenant API also adds hosts to an existing external party or local party. It also raises the threshold and copies the active contracts of the party to the joining hosts. The [`decman-wallet`](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman-wallet/README.md) Rust library runs these steps for a wallet.

For the procedures, see [Decentralize an external party](/decentralization-manager/operations-and-reference/decentralize-an-external-party.md) and [Decentralize an existing party](/decentralization-manager/operations-and-reference/decentralize-an-existing-party.md).

The tenant routes do not use the operator login. Each route checks a bearer key from `DECPM_TENANT_API_KEYS`. When `DECPM_TENANT_API_KEYS` is unset, the node refuses every tenant call.

{% hint style="warning" %}
Insecure mode accepts tenant calls without a key. The node starts in insecure mode only on DevNet. When `DECPM_CANTON_NETWORK` is unset, the network defaults to `devnet`. Route the HTTP port to a wallet only over TLS, because the tenant key travels in each request.
{% endhint %}

## Transaction signing

A Decentralized Party signs its ledger transactions with the Daml keys of its members. The contracts workflow uses this path, for example to deploy the governance rules. Each member node signs the prepared transaction hash with its own Daml key.

The node selects the signing method from the custody of the key:

| Crypto provider of the participant | How the node signs                                                                                                                                          |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| JCE (exportable keys)              | The node exports the Daml private key from the participant vault through the Admin API each time it signs. The node signs locally and never stores the key. |
| AWS KMS                            | The key stays in AWS KMS. The node calls the AWS KMS `Sign` API with the default AWS credential chain.                                                      |

On an AWS KMS participant, the operator grants `kms:Sign` on the Daml key of the party to the AWS identity of the node. The node accepts only a bare KMS key ID from the key metadata of the participant. See [Sign with AWS KMS](/decentralization-manager/operations-and-reference/sign-with-aws-kms.md).

Namespace keys never leave the participant. The participant signs topology changes itself, through the Admin API.

{% hint style="warning" %}
On a JCE participant, the node exports the Daml private key of the member through the Admin API. Allow Admin API access only from the node. Protect the host of the node as well as you protect the key.
{% endhint %}

## Reward automation

Under CIP-104, a featured-app party earns reward coupons. A coupon expires when nobody uses it in time. A Decentralized Party has no wallet automation of its own. The `governance-rewards-automation-v1` package therefore gives it two modes:

* **Minting delegation.** Governance names a validator as the delegate. The automation of the validator mints the coupons of the party after the validator accepts.
* **Coupon reassignment.** Governance approves a fixed beneficiary split and a set of assigners once. Decentralization Manager nodes then assign each coupon to that split with no further vote.

Each node runs the coupon reassignment loop as a background task:

1. The node visits each Decentralized Party that it has party credentials for. The interval is `DECPM_REWARD_AUTOMATION_INTERVAL_SECS` seconds (default `300`).
2. The node reads the active coupon reassignment delegation of the party. The node skips a party without a delegation.
3. When the delegation names the member party of the node as an assigner, the node assigns every assignable coupon. Before each assignment, the node checks the package, module and template of the delegation.
4. When the delegation does not name the member party of the node, the node assigns nothing. The node only reads the coupon backlog for the expiry metric.

Any assigner can assign the coupons of the party at any time. The delegation fixes the split. A single assigner therefore controls only the timing. Do not run both modes on one party, because they compete for the same coupons. See [Reward automation](/decentralization-manager/operations-and-reference/reward-automation.md).

## Failure and recovery

A workflow run makes no progress while its coordinator is offline. The coordinator stores the run and resumes it after a restart. A peer that cannot reach the coordinator tries 3 times, 5 seconds apart. The peer then stops the workflow run.

A node refuses a new kick, add-party, change-threshold or contracts run for a Decentralized Party while another run for that party is in progress. The check covers the workflow runs of this node in either role, coordinator or peer. Workflow runs for different parties can proceed at the same time. The guard is local to each node. Decentralization Manager does not stop two different nodes from coordinating conflicting runs on the same party.

Do not start a second state-changing run until you know the state of the first run and of Canton. See [API and workflow reference](/decentralization-manager/operations-and-reference/api-and-workflow-reference.md) and [Compatibility, releases, and troubleshooting](/decentralization-manager/operations-and-reference/compatibility-releases-and-troubleshooting.md).

## Canton, governance, and persistence

The Admin API and the Ledger API need separate least-privilege access. The governance core supplies the choices that confirm and execute an action, and that revoke or expire a confirmation. The `governance-action-v1` package supplies the choices that cancel a proposal. A member proposes an action when it creates a proposal contract. Application packages define the governed behavior.

Back up the data directory of each node. The directory holds the Noise key, the database and the staged DARs that a node needs to resume its workflow runs.

## Technical sources

* [Architecture](https://github.com/DLC-link/decentralization-manager/blob/main/docs/ARCHITECTURE.md)
* [Signing with AWS KMS party keys](https://github.com/DLC-link/decentralization-manager/blob/main/docs/KMS_SIGNING.md)
* [governance-rewards-automation-v1 README](https://github.com/DLC-link/decentralization-manager/blob/main/daml/governance-rewards-automation/README.md)
* [decman-wallet README](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman-wallet/README.md)
* [Environment variables in the README](https://github.com/DLC-link/decentralization-manager/blob/main/README.md#environment-variables)
* [Noise protocol module](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/noise/mod.rs)
* [Contracts workflow steps](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/workflow/contracts/mod.rs)
* [Signing backends](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/signing/mod.rs)
* [Reward automation loop](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/server/reward_automation.rs)
* [Authentication middleware](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/server/middleware/auth.rs)

## Related pages

* [Decentralized Party and Canton topology](/decentralization-manager/concepts-and-development/decentralized-party-and-canton-topology.md)
* [Governance lifecycle](/decentralization-manager/concepts-and-development/governance-lifecycle.md)
* [Production deployment](/decentralization-manager/get-started/production-deployment.md)
* [Security architecture](/decentralization-manager/operations-and-reference/security-architecture.md)
* [API and workflow reference](/decentralization-manager/operations-and-reference/api-and-workflow-reference.md)
* [Configuration reference](/decentralization-manager/operations-and-reference/configuration-reference.md)

## Next step

👉 **Understand the identities and hosting model:** [Decentralized Party and Canton topology](/decentralization-manager/concepts-and-development/decentralized-party-and-canton-topology.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.bitsafe.finance/decentralization-manager/concepts-and-development/architecture-overview.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
