Documentation Index
Fetch the complete documentation index at: https://docs.canton.network/llms.txt
Use this file to discover all available pages before exploring further.
Externally Signed Topology Transactions
Canton’s Topology formalizes a shared state on a synchronizer and provides a secure, distributed mechanism for modifying this state. This tutorial demonstrates how to build, sign, and submit topology transactions. It is particularly useful for cases where the signature is provided by a key held externally to the network, such as in the case of external party onboarding, or initialization of the root namespace of a participant. This tutorial goes through the steps of importing a root namespace delegation, but can be generalized to any topology mapping. A root namespace delegation is essentially equivalent to a X509v3 CA root certificate in Canton and creates an associated namespace.Prerequisites
For simplicity, this tutorial assumes a minimal Canton setup consisting of one participant node connected to one synchronizer (which includes both a sequencer node and a mediator node).Start Canton
To obtain a Canton artifact refer to the getting started section. From the artifact directory, start Canton using the command:Setup
Navigate to the interactive submission example folder located atexamples/08-interactive-submission in the Canton release artifact.
To proceed, gather the following information by running the commands below in the Canton console:
- Admin API endpoint
- Synchronizer ID
- Admin API endpoint:
localhost:4002 - Synchronizer ID:
da::12207a94aca813c822c6ae10a1b5478c2ba1077447b468cc66dbd255f60f8fa333e1
API
This tutorial interacts with theTopologyManagerWriteService, a gRPC service available on the Admin API of the participant node. It assumes that the Admin API is not authenticated via client certificates.
Python
It is recommended to use a dedicated python environment to avoid conflicting dependencies. Considering using venv.Shell
For a terminal-based approach, install the following tools: The tutorial uses a buf proto image to (de)serialize proto messages.The following functions will be used throughout the tutorial:
Error Handling
When encountering RPC errors, it may be necessary to perform additional deserialization to get actionable information on the cause of the error. Example of an RPC error:type field specifies the protobuf type in which the error is encoded. In this case, it is a google.rpc.ErrorInfo message. The following utility code can be used to deal with errors and extract useful information out of them.
Bash
1. Signing Keys
First, generate an external signing key pair to use in the rest of this tutorial. Bash2. Hash
Hashing is required at several steps to compute a hash over a sequence of bytes. The process uses an underlying algorithm, with specific prefixes added to both the input bytes and the final hash:-
A hash purpose (a 4-byte integer) is prefixed to the byte sequence. Hash purpose values are defined directly in the Canton codebase.
- The resulting data is hashed using the underlying algorithm.
-
The final multihash is prefixed again with two bytes, following the multi-codec specification:
- The identifier for the hash algorithm used.
- The length of the hash.
3. Fingerprint
Canton uses fingerprints to efficiently identify and reference signing keys. A fingerprint is a hash of the public key. Using the hashing algorithm described previously, compute the fingerprint of the public key. For fingerprints, the hash purpose value is12.
Bash
4. Namespace Delegation Mapping
There is a number of different mappings available, each modeling a part of the topology state.NamespaceDelegation mapping, but the same procedure can be applied for any topology mapping.
The Namespace Delegation mapping requires three values:
-
namespace: Root key’s fingerprint -
target_key: Public key expected to be used by delegation. Root namespace delegations are self-signed.- The format (
DER) and specification (EC256) of the key must match those of the key generated in step 1.
- The format (
-
is_root_delegation:truefor root namespace delegations
5. Topology Transaction
The topology state is scoped to a synchronizer. Each synchronizer supports a specific version of the Canton protocol, calledProtocol Version (more details on the versioning page). When integrating with the topology API, it is important to select which synchronizer the topology changes should target. This is especially relevant when interacting with the topology API of a participant node, which may be connected to multiple synchronizers at any given time.
Once a synchronizer is selected, its ProtocolVersion can be retrieved via the SequencerConnectService#GetSynchronizerParameters RPC of the sequencer API.
Protocol Version has a corresponding Protobuf Version for protobuf messages involved in the Canton protocol. That includes the TopologyTransaction message.
| Protocol Version | Topology Transaction Protobuf Version |
|---|---|
| 34 | 30 |
The versioning of protobuf messages is relatively stable and is not expected to change often. The rest of the tutorial assumes the protobuf version used is
30.Topology Mapping
See the Namespace Delegation Mapping sectionSerial
Theserial is a monotonically increasing number, starting from 1. Each transaction creating, replacing, or deleting a unique topology mapping must specify a serial incrementing the serial of the previous accepted transaction for that mapping by 1. Uniqueness is defined differently for each mapping. Refer to the protobuf definition of the mapping for details. This mechanism ensures that concurrent topology transactions updating the same mapping do not accidentally overwrite each other. To obtain the serial of an existing transaction, use the TopologyManagerReadService to list relevant mappings and obtain their current serial.
NamespaceDelegation created is new, in particular there is no pre-existing root namespace delegation with the key created in step 1. The serial is therefore set to 1.
Operation
There are two operations possible:ADD_REPLACE: Adds a new mapping or replaces an existing one.REMOVE: Remove an existing mapping
6. Version Wrapper
In order to guarantee backwards compatibility while supporting changes to the protobuf messages involved in the protocol, Canton wraps serialized messages with a wrapper that includes the protobuf version tied to the message.data: serialized protobuf topology transactionversion: protobuf version of the topology transaction message
UntypedVersionedMessage, and serialize the result:
Bash
7. Transaction Hash
The next step is to compute the hash of the transaction. It is computed from the serialized protobuf of the versioned transaction. Simply reuse the hashing function defined earlier in the tutorial. This time, the hash purpose value is11.
Bash
8. Signature
The hash is now ready to be signed. For root namespace transactions, there is only one key involved, and it therefore needs only one signature. Other topology mappings may require additional signatures, either because the mappings themselves contain additional public keys (e.gOwnerToKeyMapping), or because the authorization rules of the mapping require signatures from several entities (e.g PartyToParticipant). All transactions, however, require a signature either from the root namespace key of the namespace the transaction is targeting or from a delegated key of that namespace registered via a (non-root) NamespaceDelegation. The authorization rules vary by mapping and are out of the scope of this tutorial, but can be found on their protobuf definition.
Sign the hash with the private key:
Bash
9. Submit the transaction
Submit the transaction and its signature. This is done via theAddTransactions RPC of the TopologyManagerWriteService:
Bash
Transaction submitted successfully should be displayed.
Python
Proposal
TheSignedTopologyTransaction message contains a boolean proposal field. When set to true, it allows submitting topology transactions without attaching all the signatures required for the transaction to be fully authorized. This is especially useful in cases where signatures from multiple entities of the network are necessary, that would be tedious and difficult to gather offline.
10. Observe the transaction
The last step of the tutorial is to observe theNamespaceDelegation on the topology state of the synchronizer. Note that the submission is asynchronous, which means it may take some time before the submission is accepted.
Bash
examples/08-interactive-submission folder and can be run with
Bash