Multi-Synchronizer Operations with the JSON Ledger API and TypeScript
This tutorial shows you how to work with a multi-synchronizer Canton setup using the JSON Ledger API and TypeScript.Overview
You will explore an example project that demonstrates five key scenarios:- Allocating parties and packages across multiple synchronizers
- Manually reassigning a contract from one synchronizer to another
- Triggering automatic reassignment via a cross-synchronizer contract fetch
- Observing a failed reassignment caused by a missing party on the target synchronizer
- Observing a failed reassignment caused by an unvetted package on the target synchronizer
Topology
The Canton sandbox is started with the--multi-sync flag, which brings up the following topology:
- Three participants:
sandbox(V1),pebblebox(V2),sidebox(V3) - Two synchronizers:
synchronizer-1(S1),synchronizer-2(S2) - Connectivity: V1 connected to S1 and S2, V2 connected to S1 and S2, V3 connected to S2 only
Prerequisites
Tools
Before starting, ensure you have the following installed:- Node.js and npm — Download from https://nodejs.org/en/download/. Recommended version:
18.20.xor later. - Dpm — Install following these instructions
- Canton — Includes pre-built examples. See the Canton installation for details.
Example Project
Open a terminal and navigate to the multi-synchronizer example folder:Scenario 1: Allocations
File:src/scenario1_allocations.ts
This scenario sets up the full topology needed by all subsequent scenarios. It performs the following steps:
- Discovers the connected synchronizers on V1 and identifies S1 and S2 by alias.
- Verifies that V2 is connected to both synchronizers and that V3 is connected to S2 only.
- Generates Ed25519 key pairs for three external parties: P1, P2, and P3.
- Allocates P1 and P2 on both S1 and S2 (via V1 and V2 respectively) and allocates P3 on S2 only (via V3).
- Uploads and vets the DAR on V1 and V2 for both synchronizers, and on V3 for S2 only.
- Creates one user per participant, granting the appropriate
CanActAsrights.
Topology object that is passed into all subsequent scenarios.
Scenario 2: Manual Reassignment
File:src/scenario2_manual_reassignment.ts
This scenario shows how to move a contract from one synchronizer to another using the explicit unassign/assign API.
Steps:
- P1 and P2 co-sign the creation of an
Ioucontract on S1. - P1 unassigns the
Ioufrom S1, targeting S2. This produces areassignmentId. - P1 assigns the
Iouto S2 using thereassignmentId. - P3 exercises the
Iou_Inspectchoice on the contract via explicit disclosure, using V2 as the submitting participant.
Scenario 3: Automatic Reassignment
File:src/scenario3_automatic_reassignment.ts
This scenario demonstrates that Canton can automatically reassign a contract when a transaction requires it on a different synchronizer.
Steps:
- P1 and P2 create an
Ioucontract (C1) on S1. - P1 creates an
IouLinkedcontract (C2) on S2 that holds a reference to C1. - P1 exercises the
ProcessWithIouchoice on C2 targeting S2. Because C1 is on S1, Canton automatically reassigns it to S2 before executing the choice. - P3 inspects C1 (now on S2) via explicit disclosure.
Scenario 4: Failed Reassignment (Missing Party)
File:src/scenario4_failed_missing_party.ts
This scenario shows that reassignment is rejected when a signatory’s participant is not connected to the target synchronizer.
Recall from Scenario 1 that P3’s participant (V3) is only connected to S2. If a contract has P3 as a signatory, it cannot be reassigned to S1 because V3 has no connection there.
Steps:
- P1 and P3 create an
Ioucontract on S2 (P3 is a signatory via theownerfield). - P1 attempts to unassign the contract from S2 to S1.
- The unassign call is rejected by Canton with a message indicating that P3 is not active on the target synchronizer.
"not active on the target synchronizer".
Scenario 5: Failed Reassignment (Missing Vetting)
File:src/scenario5_failed_missing_vetting.ts
This scenario shows that reassignment is also rejected when the contract’s package is not vetted on the target synchronizer, even if all parties are present there.
Steps:
- The
model-testspackage is unvetted on S2 for both V1 and V2. - P1 and P2 create an
Ioucontract on S1 (the package is still vetted on S1). - P1 attempts to unassign the contract from S1 to S2.
- The unassign call is rejected because the package is not vetted on S2.
- The package is re-vetted on S2 (in a
finallyblock, so the topology is restored regardless of the outcome).
"has not vetted".
Vetting is a per-participant, per-synchronizer property. A package must be vetted on every participant that hosts a stakeholder of the contract on the target synchronizer for a contract using that package to be reassigned there.
Related
- Get Started with Canton, the JSON Ledger API, and TypeScript covers the basics of the JSON Ledger API with TypeScript using a single synchronizer.
- A WebSocket variant demonstrates how to build a browser-based client.