Release of Canton 3.5.3
Introduction
The Canton 3.5.3 release notes for Splice 0.6.0 are provided below. The content here focuses on Canton updates only. For Splice related changes, please refer to the Splice Release Notes. These notes are broken down into the key sections below:- Application Development and Tooling
- Ledger API
- Admin API and Console
- Deployment and Configuration
- Operational Procedures
- New Features and Enhancements
- Important Changes
- New Deprecations
Application Development and Tooling
New Features and Enhancements
Introducing Contract Keys
This release introduces the contract key feature which was previously available in Daml 2.x. A contract key is a stable identifier that simplifies reasoning and programming with the UTXO contracts. They make it easier to track contract IDs as the contract evolves: as a contract is updated, via archive and create operations, the currently active contract(s) can easily be referenced via the contract key. The contract key feature simplifies both the Daml business logic developer as well as the client of that Daml business logic (e.g., backend service). Contract keys will enable Ethereum or Solana developers to more easily develop applications on the Canton Network because the UTXO mental model is simplified. Services that integrate with the ledger will be simpler because they have a stable identifier to program. Contract keys are similar in concept to primary or secondary keys in relational databases. Contract keys do not change and can be used to refer to a contract even when the contract ID changes. Technically, the contract key can be any value that does not contain contract IDs. In this release, a contract key can refer to zero, one, or several contracts at the same time. In Canton 3.x, allowing a key to refer to one, zero, or several contracts does have the advantage that a contract key can act like a secondary key of a database. This version of contract keys assumes that key uniqueness is provided by the dApp or other external enforcement mechanisms.Daml Language Primitives
The Daml language and compiler are reintroducing the two keywords:key and maintainer. To define a contract key in a Daml template, you use the key keyword and specify the maintainer.
- The
keyexpression identifies the contract (always includes aPartyfor scoping). - A
maintaineris the party that validates all action on a key to guarantee their consistency. The central task of themaintaineris to verify the keys are retrieved in a consistent order within the transaction. Amaintainermust be a signatory. The maintainer must be expressed in terms of the key, which is available via thekeyidentifier in the maintainer expression.
lookupByKey- It checks whether a contract with the given key exists and if yes, returns the contract id. If multiple contracts exist, the first one according to the lookup order below is returned.fetchByKey- It fetches the first contract id and contract data associated with the given contract key. If multiple contracts exist, the first one according to the lookup order below is returned.exerciseByKey- Exercise a choice on the first contract associated with the given key according to the order below.lookupNByKey- Available inDA.ContractKeys. It looks up up toncontracts associated with the passed key, sorted according to the order below.
- First the contracts created within a transaction, starting with the most recent,
- Then explicitly disclosed contracts,
- Then contracts known to the participant in recency order.
Daml Script Functions
There are Daml Script functions - counterparts of the standard library primitives:queryByKey- It looks up a contract associated with the passed key and returns its ids and data. It is of typeScript, which means it must appear as top-level instruction as part of a Script.queryNByKey- It looks up up toncontracts associated with the passed key and returns their ids and data. It is of typeScript, which means it must appear as top-level instruction as part of a Script.exerciseByKeyCmd- It exercises a choice on the first contract with the given key. It is of typeCommandsand must therefore be wrapped by a submit operation, and can be combined with otherCommands.
Smart Contract Upgrade (SCU)
To support SCU upgrade for contractkey and maintainer definitions, new guidelines have been added. Simply, the key and maintainer values are not allowed to be changed. At upgrade time, the recomputed key and maintainers are verified to be identical to the upgraded contract’s original key and maintainers. If they aren’t, an upgrade error is raised and the transaction is aborted. It is forbidden to add or remove a key definition from a template in a later version of that template. The default is to enforce this at package vetting time.
Important Changes
Daml-LF 2.3
A new version of Daml-LF is released: Daml-LF 2.3. To benefit from new features (like Contract Keys) this LF version enables, the package needs to be recompiled and its semantic version must be bumped to form a new element in the package lineage. (Please note that this will cause the package ID to change.) You can target Daml-LF 2.3 by setting the--target=2.3, either as direct argument on the command line or as part of a daml.yaml:
dpm Replaces the Daml Assistant (daml) CLI
dpm is a command-line tool that allows users to run the SDK components. It is a drop-in replacement for the Daml Assistant (daml), which is removed in this release. It has an extensible plug-in architecture(see Publishing Components). The Daml Assistant (daml) was deprecated in Canton 3.4.
The dpm CLI is documented here. A command migration table, from daml to dpm commands, is available here.
Daml Exception Handling Updates
Daml exception handling has been deprecated since Canton 3.3. deprecated. It is not removed in this release but there is a change:- Protocol version 35 does not support transactions which roll back write effects.
New Deprecations
Use PQS’s prune_archived_to_offset instead of prune_to_offset
The PQS prune_to_offset SQL function is deprecated. You should not use it anymore as it can introduce a deadlock with accompanying poor performance. The mitigation is to use the newly introduced prune_archived_to_offset as a replacement: It is non-blocking and 10x faster.
Ledger API
New Features and Enhancements
Ledger API Contract Key Support
The following contract-key related extensions have been made to the Ledger APIcontract_key_hashhas been added to theCreatedEventmessage returned in theState-andUpdateServiceresponsesprefetch_contract_keysfield present in theCommandandPrepareSubmissionRequestused by theCommand-CommandSubmission-andInteractiveSubmissionServiceare available to allow the caller to request prefetching the contract key cache underpinning the command interpretation. Use it when performance tests indicate that many sequential contract key lookups adversely impact the command interpretation speed.
PQS Contract Key Support
In PQS, contract keys are mere metadata that can be queried like any other metadata. It is possible to query for all contracts with a given key:Party Replication Topology Events To Signal Begin and End of Replication
ThePartyToParticipant topology “onboarding” state used in the process of replicating a party with existing contracts is now visible via the Ledger API, when a party onboards on a synchronizer on protocol version 35 or higher. Starting with PV=35, the newly introduced ParticipantAuthorizationOnboarding Ledger API topology event signals the beginning of party replication and transitions to ParticipantAuthorizationAdded once the party’s ACS is fully visible on the Ledger API.
New Transaction Hashing Scheme v3 for InteractiveSubmissionService
The Ledger API prepare InteractiveSubmissionService has been modified to take in a specific hashing scheme version in the request. The default hashing scheme is HASHING_SCHEME_VERSION_V2. Integrators are encouraged to move to HASHING_SCHEME_VERSION_V3 for synchronizers using protocol version 35. In particular, usage of contract keys requires HASHING_SCHEME_VERSION_V3.
- A new hashing scheme version
HASHING_SCHEME_VERSION_V3has been introduced that includes the transaction’smax_record_timein the hash computation and covers the new transaction node and fields of contract keys. This new version is available from Protocol Version 35. - See the hashing algorithm documentation for the updated version.
- The
max_record_timeis now enforced by all confirming participants.
LAPI ACS Stream Enhancements
TheGetActiveContracts stream request has been extended with an optional stream_continuation_token field that allows clients to continue an interrupted ACS stream from the last element which made it through. The field can be populated with the stream_continuation_token field of the last response element received before the interruption, and the stream will continue from the next element after that.
A new GetActiveContractsPage endpoint added to the State Service API. This enables the client to retrieve the ACS in paginated form, by specifying a max_page_size. The pages can be accessed sequentially by using the page_token field. The token can be obtained from the GetActiveContractsPageResponse of the last page.
GetUpdates Stream Enhancements
TheGetUpdatesRequest object has a new optional parameter descending_order. When this parameter is true the events are streamed from the newest to the oldest ones. The pages can be accessed sequentially by using the page_token field. An example use for this feature is to view the transaction history from newest to oldest.
A new GetUpdatesPage endpoint has been added to the Update Service API that supports pagination. This allows retrieval of updates in paginated form instead of requesting the stream.
Optimizing ACS Queries using Active Contracts Head Snapshot (ACHS)
The Active Contracts Head Snapshot (ACHS) is a new optional feature that maintains a continuously updated snapshot of the currently active contracts. When enabled, the ACHS acceleratesGetActiveContracts (ACS) queries by allowing them to read directly from a pre-computed snapshot rather than scanning the full event log to reconstruct the active set.
ACHS is disabled by default. To enable it, configure the achs-config block under the participant’s indexer settings:
valid-at-distance-target controls how far behind the ledger end (in event sequential IDs) the snapshot’s validity point is maintained. The ACHS is not used for serving queries below its validity point, logging at INFO level ACHS for (...) skipped since validAt (...) already surpassed requested activeAt (...). If the valid-at-distance-target value is too small, long-running ACS queries may observe the ACHS validity point moving (mid-stream) past their requested offset, causing the stream to fall back to the slower filter tables query, logging at INFO level ACHS stream for (...) fell back to filter tables from (...) since validAt (...) surpassed activeAtEventSeqId (...). If the value is too large, the tail portion of the ACS (between the ACHS validity point and the requested offset) must be resolved from the filter tables, making that last segment more expensive.
As described above, when the ACHS validity point moves or is past the requested offset, an info-level log message is emitted indicating that the stream fell back to the filter tables. Two corresponding metrics, achs_skips and achs_midstream_fallbacks, are available under daml.participant.api.index to help operators monitor the frequency of these fallbacks and tune the valid-at-distance-target accordingly.
The last-populated-distance-target controls the additional lag (in event sequential IDs) for the population of ACHS in order to store only the long-lived contracts. A larger value reduces database I/O by skipping short-lived contracts that are created and archived before they would be added to the snapshot. However, setting it too large increases the cost of the remaining ACS tail, as more data must be fetched from the filter tables to cover the gap between the last populated point and the ACHS validity point.
Further tuning parameters include:
population-parallelism: number of parallel threads for adding activations to the ACHS during normal operation.removal-parallelism: number of parallel threads for removing deactivated activations from the ACHS during normal operation.aggregation-threshold: minimum batch size (in event sequential IDs) before ACHS maintenance work is emitted.init-parallelism: number of parallel threads for ACHS population and removal during initialization.init-aggregation-threshold: minimum batch size (in event sequential IDs) for ACHS maintenance during initialization.buffer-size: size of the internal buffer between the indexer pipeline and the ACHS maintenance flow.
deactivation_distances histogram metric which is available under daml.participant.api.indexer.deactivation_distances can help operators understand the distribution of contract lifetimes (the event sequential ID distance between a contract’s activation and its deactivation) and set an appropriate last-populated-distance-target. Ideally, the population distance should be large enough so that most short-lived contracts are already deactivated and thus not added to the snapshot.
Three Prometheus gauge metrics are available under daml.participant.api.indexer to monitor the ACHS state:
achs_valid_at: the event sequential ID at which the ACHS is currently valid. ACS queries with a requested offset at or after this value can be read directly from the ACHS.achs_last_populated: the last event sequential ID for which activations were added to the ACHS.achs_last_removed: the last event sequential ID for which deactivations were looked up and the corresponding activations were removed from the ACHS.
Other Ledger API Improvements
ApiRequestLogger is nowalso used by Ledger JSON API. Changes are:- Redundant Request
TIDremoved from logs. - Additional CLI options added:
--log-accesscaptures API access logs in a separate file (default:log/canton_access.log), and--log-access-errorscaptures API access errors in a separate file (default:log/canton_access_error.log). - Additional config options added:
debugInProcessRequestslogs in-process gRPC requests at DEBUG instead of TRACE, andprefixGrpcAddressesprefixes gRPC client addresses withgrpc:(enabled by default).
- Redundant Request
- Ledger API
ListKnownPartiessupports an optional prefix filter argumentfilterParty. The respective JSON API endpoint now additionally supportsidentity-provider-idas an optional argument, as well asfilter-party. - To protect the admin participant from self lock-out, it is now impossible for an admin to remove its own admin rights or delete itself.
- On Ledger API interface subscriptions, the
CreatedEvent.interface_viewsnow returns the ID of the package containing the interface implementation that was used to compute the specific interface view asInterfaceView.implementation_package_id. OffsetCheckpointsare now always generated when an open-ended update or completion stream is requested, even if there are no updates. The checkpoint can have the same offset as the exclusive start of the stream, making checkpoints visible even when starting from the ledger end. This enables client systems to recognize when the ledger end is advancing, even if the stream of updates is inactive.- Extended the set of characters allowed in user-id in the ledger api to contain brackets:
(). This also makes those characters accepted as part of thesubclaims in JWT tokens. - Functionality for managing internal and external parties has been improved, removing previous asymmetry:
- User rights can now be assigned to an external party during allocation.
- External parties can be allocated by the user themselves in the self-administration mode. Please note that users in self-administration mode can allocate up to N parties, depending on a setting of the parameter.
- An IDP administrator can now only allocate parties confined to their own IDP perimeter.
Important Changes
Only Package-Name is Now Accepted for the Ledger API Queries
The package-id reference format has been deprecated since Canton 3.3 and is no longer supported in this release for read Ledger API queries. This applies for both Protocol Version 34 and 35. Specifying interface and template identifiers to the Ledger API read queries must use the package-name reference format, where the package name is the root identifier, such as#<package-name>:<module>:<entity>. The package-id reference format was deprecated and is no longer supported so it will now fail.
The impacted LAPIs are:
GetUpdatesGetUpdateByOffsetGetUpdateByIdGetActiveContractsGetEventsByContractIdRequestSubmitAndWaitForTransaction(the optionaltransaction_format)SubmitAndWaitForReassignmentRequestExecuteSubmissionAndWaitForTransactionRequest
synchronizer_id Format Changes in Protocol Version 35
In PV 35, the synchronizer_id field in an externally signed prepared transaction metadata will be populated with the physical synchronizer ID of the synchronizer on which the transaction will be processed, instead of the logical synchronizer ID, as is the case in PV 34. Applications must ensure they do not rely on the format of the synchronizer_id value. This was announced in this Canton Forum post.
The change is that the format of the synchronizer_id metadata field value in a prepared transaction will change when upgrading from Canton 3.4 (protocol version 34) to Canton 3.5 (protocol version 35). This is not an API breaking change but a change to the format of the synchronizer_id field shown below:
Current format example (protocol version 34):
global_sync::12204457ac942c4d839331d402f82ecc941c6232de06a88097ade653350a2d6fc9c5
New format example (protocol version 35):
global_sync::12204457ac942c4d839331d402f82ecc941c6232de06a88097ade653350a2d6fc9c5::35-0
As shown, the 3.5 format adds a suffix (::35-0) compared to the current 3.4 format. Applications must ensure that they do not rely on the format of this field in a way that would break functionality. If the field must be parsed then it is recommended to support both formats.
NOTE: This will cause the DSO Global Synchronizer ID to change as shown in the example above.
Please note that the API specification does not give any guarantee on the synchronizer_id format, so the recommended approach is to treat synchronizer_id metadata as an opaque string in the application logic. In general, this is the recommended approach since the synchronizer_id field may change in the future. If you parse the synchronizer_id, the recommendation is to support both formats.
Ledger API Specification Changes
The OpenAPI and AsyncAPI specifications for the Ledger API (LAPI) are now aligned with the gRPC transport. All gRPCoptional fields are now marked as optional in the other specifications, which can impact the generated code. This is mostly transparent for several OpenAPI (AsyncAPI) language generators because it is a backwards compatible step to go from required to optional.
A summary of the changes to the generated code varies by language:
- No changes are expected for Java.
- TypeScript will require minor changes.
- Clients in languages like Rust will need more (but trivial) changes.
- Languages using dynamic typing should not be affected.
openapi-3.5.0.yaml.
For backward compatibility, the Canton 3.4 OpenAPI and AsyncAPI specifications can be used unchanged. If you want to use new endpoints, features or leverage the new less strict spec, migrate to the new 3.5 OpenAPI/AsyncAPI specifications.
Maximum Number of Signatures per External Submission
As an availability security measure, the Ledger API now enforces a maximum number of signatures per party that can be provided for external submissions. This value defaults to 50 and can be changed at the following config path:canton.participants.<participant_name>.ledger-api.interactive-submission-service.maximum-number-of-signatures-per-party
Removed Deprecated UpdateService JSON APIs
Several UpdateService JSON APIs were deprecated in Canton 3.4. These UpdateService requests are removed in this release:
/v2/updates/trees/v2/updates/transaction-tree-by-offset/v2/updates/transaction-tree-by-id/v2/updates/transaction-by-offset/v2/updates/transaction-by-id
New Deprecations
Ledger JSON API Package Vetting Endpoints
The Ledger JSON APIv2/package-vetting endpoint exposes list functionality on the GET method by accepting a request body. This is not recommended by the HTTP specification, hence the endpoint is deprecated. For consistency, the POST method, used for updating the vetting state, of the same endpoint is also deprecated.
In turn, two new endpoints are implemented to provide the same functionality:
v2/package-vetting/listaccepts aPOSTrequest with the same body as the deprecatedGET v2/package-vettingendpoint and returns the list of vetted packages in the same format.v2/package-vetting/updateaccepts aPOSTrequest with the same body as the deprecatedPOST endpoint v2/package-vettingand returns the updated vetting state of the package in the same format.
Scope Based JWT Tokens
Scope based JWT tokens that are identified by thescope claim in their body are deprecated in this release and will be removed in version 3.7. Going forward only the audience based tokens identified by their aud claim will be supported. In keeping with this change, the configuration entry allowing specifying the target scope expected on incoming JWT tokens has been deprecated as well.
If you are currently using the scope based tokens,
- Reconfigure your IDP system to issue
audbased tokens instead and - Change the Canton configuration accordingly specifying the expected target audience.
Admin API and Console
New Features and Enhancements
Improved Party and Repair ACS Imports
For performance reasons, the ACS import endpoints for both party replication and participant repair were overhauled to be memory-efficient streaming endpoints:- Console command
participant.parties.import_party_acs - Console command
participant.repair.import_acs - gRPC RPC
PartyManagementService.ImportPartyAcs - gRPC RPC
ParticipantRepairService.ImportAcs
Changes to use the New Endpoints
ThesynchronizerId is now a mandatory first parameter for both the import_party_acs and import_acs console commands as well as their analogous gRPC endpoints. You will need to update any existing scripts.
For import_party_acs:
- Old usage:
participant.parties.import_party_acs("canton-ACS-export.gz") - New usage:
participant.parties.import_party_acs(mySynchronizerId, importFilePath = "canton-ACS-export.gz")
- Old usage:
participant.repair.import_acs("canton-ACS-export.gz") - New usage:
participant.repair.import_acs(mySynchronizerId, importFilePath = "canton-ACS-export.gz")
synchronizerId parameter, to import a multi-synchronizer ACS snapshot, you must now call the endpoint sequentially for each synchronizer your participant is connected to, using the exact same snapshot file. The import process will ignore any contracts in the snapshot that are associated with a different synchronizer.
Details on the grpc ImportAcs Repair Endpoint
The ImportAcs and ImportAcsV2 RPCs have been consolidated, introducing the following changes and migration steps:
ImportAcsV2(along with its request/response messages) is completely removed. All clients must migrate to the standardImportAcsRPC.- Request signature and type changes:
- Fields
workflow_id_prefix(2),contract_import_mode(3), andrepresentative_package_id_override(5) inImportAcsRequestare now explicitly optional. - A new optional string
synchronizer_id= 6 field was added. - Migration (ScalaPB): Adding optional changes generated code from base types to
Option[T]. Existing clients will fail to compile and must be updated to wrap assigned values (e.g.,workflowIdPrefix = Some("prefix")) and explicitly handle readingOptiontypes.
- Fields
- Behavioral change (
synchronizer_id): When filtering by synchronizer, mismatched contracts are now ignored. This breaks previous logic that relied on the import strictly aborting upon a mismatch.
Details on the gRPC ImportPartyAcs Party Replication Endpoint
TheImportPartyAcs endpoint underwent the exact same consolidation (removing ImportPartyAcsV2), streaming semantics updates, generated code changes (ScalaPB Option[T]), and mismatched synchronizer behavior (ignoring rather than failing) as ImportAcs.
Key differences specific to ImportPartyAcs:
- A new optional
string party_id = 6field was added. Providing this in the first request of the stream enables automatic, crash-resilient scheduling of the onboarding flag clearance. If omitted, the participant logs a warning, and the flag must be cleared manually. - The
synchronizer_id(field 2) temporarily accepts either a logical or physical synchronizer ID to better support Logical Synchronizer Upgrade (LSU) scenarios. This support is subject to change.
Removal of Legacy ACS Export and Import Endpoints
The following legacy repair endpoints for the ACS export and import were deprecated in Canton 3.4 and are removed in this release:- Console
command participant.repair.export_acs_old - Console
command participant.repair.import_acs_old - gRPC
rpc ParticipantRepairService.ExportAcsOld - gRPC
rpc ParticipantRepairService.ImportAcsOld
- Migrate to
participant.repair.export_acsfromparticipant.repair.export_acs_old - Migrate to
participant.repair.import_acsfromparticipant.repair.import_acs_old - Migrate to
ParticipantRepairService.ExportAcsfromParticipantRepairService.ExportAcsOld - Migrate to
ParticipantRepairService.ImportAcsfromParticipantRepairService.ImportAcsOld
export_acs
The most significant change is the removal of the timestamp parameter, which has been replaced by a mandatory ledgerOffset parameter.
Console parameter changes:
- New mandatory parameter:
ledgerOffset (Long). You must now specify the exact ledger offset for the snapshot instead of a timestamp. - Removed parameters:
partiesOffboarding,timestamp(replaced byledgerOffset), force. - Renamed parameters:
outputFileis nowexportFilePath(default is"canton-acs-export.gz"),filterSynchronizerIdis nowsynchronizerId. - New optional parameters:
excludedStakeholdersallows you to omit contracts that have one or more of these parties as a stakeholder;contractSynchronizerRenamesallows mapping contracts from one synchronizer to another during export.
ExportAcsRequest:
partiestoparty_ids: Field renamed for consistency. If left empty, the endpoint will act as a wildcard and export the ACS for all parties hosted by the participant.timestamptoledger_offset(Breaking): You must provide an exactint64 ledger_offsetinstead of a timestamp.Filter_synchronizer_idtosynchronizer_id: Field renamed for consistency.- Removed fields:
forceandparties_offboardinghave been completely removed. - New fields:
contract_synchronizer_renamesandexcluded_stakeholder_ids.
import_acs
The import command remains largely the same in basic usage, but introduces new optional parameters for advanced validation and overrides, alongside strict memory-efficient streaming semantics for gRPC.
Console parameter changes:
- Renamed parameter:
inputFileis nowimportFilePath(default is"canton-acs-export.gz"). - New optional parameters:
contractImportModegoverns contract validation upon import (defaults toContractImportMode.Validation);representativePackageIdOverrideallows overriding representative package IDs during import;excludedStakeholdersallows omitting contracts that have one or more of these parties as a stakeholder.
ImportAcsRequest:
- Streaming Semantics (Breaking): The new endpoint requires metadata fields (like
contract_import_mode,synchronizer_id, etc.) to be populated only in the first request of the stream. Subsequent requests must omit metadata and only contain the binaryacs_snapshotchunks. - New mandatory fields:
contract_import_modeandsynchronizer_idmust be explicitly defined in the first stream request. - Removed fields:
allow_contract_id_suffix_recomputationis completely removed. - New fields:
excluded_stakeholder_idsandrepresentative_package_id_override. - Response update:
ImportAcsResponseis now a completely empty message (previously returned a contract ID mapping).
Improvements for repair.add
The participant.repair.add admin command has been revised to use the new ImportAcs backend, bringing significant memory performance improvements, stricter default safety validations, and several new parameters.
Previously, repair.add implicitly accepted all injected contracts without re-evaluating their cryptographic hashes. To prevent accidental data corruption, the command now defaults to Validation mode (contractImportMode = ContractImportMode.Validation).
So, if you have existing scripts or recovery procedures that inject manually modified, synthetic, or inconsistent contracts (where the payload does not strictly match the ContractId hash), they will now fail with a "Failed to authenticate contract with id" error.
To restore the legacy behavior and bypass this cryptographic validation, explicitly pass the Accept mode in your command call:
workflowIdPrefix: Allows you to set a custom prefix for the generated workflow ID to easily track the repair transactions (defaults to import-<UUID>).contractImportMode: Choose between Validation (default, validates that contract IDs comply with the scheme associated with the synchronizer where the contracts are assigned), orAcceptthe contracts as they are (if you know what you are doing).representativePackageIdOverride: Allows you to remap or override the representative package IDs of the contracts as they are imported.excludedStakeholders: When defined, any contract that has one or more of these parties as a stakeholder will not be added.
Admin API Error Reporting now Uses Canonical gRPC Error Propagation
The previous method of returning errors via response fields has been replaced in favor of the consistency of canonical gRPC error propagation. The following fields are now obsolete:HandshakeResponse.value.failureVerifyActiveResponse.value.failure
io.grpc.Status codes to ensure a consistent and secure interface.
The following status codes have changed as follows:
SequencerAuthenticationService.challenge now fails withINVALID_ARGUMENT(instead ofFAILED_PRECONDITION), if the client does not support the sequencer’s protocol version.SequencerConnectServicenow fails withINVALID_ARGUMENT(instead ofFAILED_PRECONDITION) if a non-participant tries to connect.SequencerConnectService.registerOnboardingTopologyTransactionsnewly fails withINTERNAL(instead ofFAILED_PRECONDITIONS) if there are missing dynamic synchronizer parameters.SequencerConnectService.registerOnboardingTopologyTransactionsnewly fails withFAILED_PRECONDITIONif the transactions cannot be added to the topology state and sanitization of error messages is enabled.
Single Topology Transaction for External Parties
Multiple topology transactions for external parties can now be represented with a singlePartyToParticipant topology transaction.
The generateExternalPartyTopology endpoint on the Ledger API now returns a single PartyToParticipant topology transaction to onboard the party. The transaction contains a signing threshold and signing keys. This effectively deprecates the usage of PartyToKeyMapping. For parties with signing keys both in PartyToParticipant and PartyToKeyMapping, the keys from PartyToParticipant take precedence.
Deprecated usage of PartyToKeyMapping. The functionality provided by PartyToKeyMapping is now available directly in PartyToParticipant. Please use PartyToParticipant for new transactions. PartyToKeyMapping is still fully supported in this version (including existing and new transactions). In a future version, creation of new PartyToKeyMapping transactions may be disallowed.
Deprecated TopologyManagerReadService.ExportTopologySnapshot and TopologyManagerWriteService.ImportTopologySnapshot, along with their console counterparts topology.transactions.export_topology_snapshot, topology.transactions.import_topology_snapshot, topology.transactions.import_topology_snapshot_from, and topology.transactions.export_identity_transactions. Please use the corresponding V2 variants (ExportTopologySnapshotV2 / ImportTopologySnapshotV2, export_topology_snapshotV2, import_topology_snapshotV2, import_topology_snapshot_fromV2, export_identity_transactionsV2) instead, which use an updated internal bytestring format.
Offline Party Replication
Concluding an offline party replication by clearing the onboarding flag now includes two major updates when using protocol version 35:- Additional crash resilience for ongoing clearances.
- Automatic scheduling for clearances when a participant (re)connects to the synchronizer.
participant.parties.import_party_acs and participant.parties.clear_party_onboarding_flag endpoints.
Note: The replicated party ID must be included in the party ACS import call to enable automatic scheduling. The original behaviour is retained for protocol version 34.
Hardened Error Handling in Sequencer Connect Service
We more completely redacted sensitive information from error messages for theSequencerConnectService to avoid information leakage. Detailed internal error messages are now redacted before being sent to clients.
If detailed diagnostics are required in a non-production environment, sanitization can be toggled off via:
Mediator Verdicts Resilience
The mediator now guarantees that all verdicts will eventually be persisted and available on the inspection API.Enhanced Reliability for GetHighestOffsetByTimestamp
Previously, the GetHighestOffsetByTimestamp RPC and the find_highest_offset_by_timestamp console command could return offsets not yet synced with the participant’s local cache due to a race condition. In this circumstance, using this returned value with a future timestamp resulted in an error.
Specific changes:
- The required state is now retrieved atomically via a consistent database snapshot.
- The endpoint now includes an internal barrier (waiting up to 10 seconds) to ensure the local Ledger API cache catches up with the database before returning the offset.
- When
forceis true, requesting a future timestamp now gracefully returns the current ledger end instead of failing.
Topology-Aware Package Selection (TAPS) improvements
Topology-Aware Package Selection (TAPS) better handles inconsistent vetting states:- The algorithm now considers a party’s package vetting state only for packages required by that party in the interpreted transaction. It starts with a minimal set of restrictions derived from the command’s root nodes and progressively accumulates more restrictions over a configurable number of passes. This iterative process increases the likelihood of finding a valid package selection set for the routing of the transaction.
- The maximum number of TAPS passes can be set at the request-level via the optional
taps_max_passesfield inCommandsorPrepareSubmissionRequestmessages. If not specified, the default value is taken from the participant configuration viaparticipants.participant.ledger-api.topology-aware-package-selection.max-passes-default(defaults to3). A hard limit is enforced byparticipants.participant.ledger-api.topology-aware-package-selection.max-passes-limit(defaults to4). - TAPS now ignores unvetted dependencies of packages that are not required for interpretation. complying now with the support of unvetted dependencies in the Canton protocol.
Online Party Replication
Online party replication available as an Alpha feature. High level changes and additions are:- Added the file-based online party replication command
participant.parties.add_party_with_acs_asyncto be used along withparticipant.parties.export_party_acsand instead of the sequencer-channel-basedadd_party_asynccommand. - The online party replication status command now returns status in a very different, “vector-status” format rather than the old “oneof” style. This impacts the
participant.parties.get_add_party_statuscommand andcom.digitalasset.canton.admin.participant.v30.PartyManagementService.GetAddPartyStatusgRPC response type. - The participant configuration to enable online party replication has been renamed to
alpha-online-party-replication-supportfromunsafe-online-party-replicationfor consistency with other alpha features and to reflect that the default file-based mode is more secure not relying on sequencer channels. - The sequencer configuration to enable sequencer channels for online party replication has been renamed to
unsafe-sequencer-channel-supportfromunsafe-enable-online-party-replicationfor consistency and to refer specifically to sequencer channels.
ACS Ledger API Counting
The new memory-efficient console commandparticipant.ledger_api.acs.count() has been introduced to count the number of active contracts on a participant node.
Note: This command is currently under the Testing feature flag.
Important Changes
Removal of Automatic Recomputation of Contract IDs upon ACS Import
The ability to recompute contract IDs upon ACS import has been removed. This is a result of the many improvements for ACS import and export.Changes from NonNegativeLong to Long
Some console commands using a NonNegativeLong for the offset are changed to accept a Long instead. Similarly, some console commands returning an offset now return a Long instead of a NonNegativeLong. It brings consistency and allows passing the output of participant.ledger_api.state.end().
Impacted commands:
participant.repair.export_acsparticipant.parties.find_party_max_activation_offsetparticipant.parties.find_party_max_deactivation_offsetparticipant.parties.find_highest_offset_by_timestamp
Removal of Legacy Party Replication Repair Console Macros
The original party replication method, which relied on a silent synchronizer, has been superseded by the offline party replication process. Consequently, the obsolete repair console macros associated with the legacy approach are no longer needed and have been removed. Specifically, the following macros are no longer available:step1_hold_and_store_acsstep2_import_acs
Miscellaneous Console Changes
- Removed the
LastErrorsAppenderalong with the Admin API endpointsStatusService.GetLastErrorsandStatusServiceGetLastErrorTrace, as well as the corresponding console commandslast_errorsandlast_error_trace.
New Deprecations
Protocol Version parameter in Topology List Commands
TheprotocolVersion parameter in all <node>.topology.<mapping>.list console commands has been deprecated and will be removed in a future version.
Deployment and Configuration
New Features and Enhancements
Session Signing Keys
Session signing keys can now be used to reduce the number of calls to external KMS (Key Management Service) providers. When enabled, session signing keys are generated and cached locally for a limited duration and used for signing operations during their validity period. Please read the documentation on Session Signing Keys for details on how to enable and configure this feature. Session signing keys are only available from Protocol Version 35 and are not enabled by default.Multi-Synchronizer Improvements
Multi-synchronizer support has been part of the Canton 3.x distribution from its initial release. The recommendation is to start developing multi-synchronizer applications using this release. The main components for multi-synchronizer development, including the surface APIs for multiple synchronizer connection configurations, are implemented and the mechanics are documented. As an example, Digital Asset maintains a multi-synchronizer sample application “Splitwell” and continuously tests that it works in a multi-synchronizer deployment as part of CI/CD testing. Integration testing can be done by deploying your own ScratchNet (to mimic the Global Synchronizer and another private synchronizer), along with setting two configuration values. The configuration values to be set to fully enable multi-synchronizer are:EnableMultiSynchronizerenables the validator to perform assign and unassign operations (referred to as reassignment).enable-all-ledger-api-reassignmentsis a multi-synchronizer setting so that if an ACS import or the repair service is done, it will signal the ACS import using assigned events (instead of created). This is necessary if the ACS snapshot contains contracts with non-zero reassignment counters.
EnableMultiSynchronizer must be activated on all validators hosting a stakeholder of the contract on both the source and target synchronizers. For a validator, EnableMultiSynchronizer is enabled as follows:
enable-all-ledger-api-reassignments is a new Boolean participant node parameter which differentiates between the types of events when an ACS import is performed:
- The default is
falseso ACS import or repair service will generate standardCreateevents. - Setting it to
trueenablesAssignevents instead.
Create events) resets this counter to zero upon an ACS import. Ledger API clients will need to accommodate the Assign/Unassign events when this is enabled.
These flags also need to be set if integration testing with DevNet is performed.
Other Deployment and Configuration Enhancements
- Added a field
MaxConcurrentCallsPerConnectionand corresponding defaultdefaultMaxConcurrentCallsPerConnection(set to 100000) toServerConfig. This corresponds tomax-concurrent-streams-per-connectionin the app configs, e.g.,docker/canton/images/canton-sequencer/app.confand can be changed there. At present the value for sequencers is configured to be 500 for the public API and 100 for the Admin API. - Added network timeout and
client_connection_check_intervalfor db operations in the Ledger API server and indexer to avoid hanging connections for Postgres (seePostgresDataSourceConfig). The defaults are 60 seconds network timeout and 5 secondsclient_connection_check_intervalfor the Ledger API server, and 20 seconds network timeout and 5 secondsclient_connection_check_intervalfor the indexer. These values can be configured via the new configuration parameterscanton.participants.<participant>.ledger-api.postgres-data-source.network-timeoutfor network timeout of the Ledger API server andcanton.participants.<participant>.parameters.ledger-api-server.indexer.postgres-data-source.client-connection-check-intervalfor the client_connection_check_interval of the indexer. <canton-node>.replication.connection-pool.connection.client-connection-check-intervalis introduced that allows configuring the PostgreSQL-specificclient_connection_check_intervalparameter for DB locked connections. This is a safety mechanism to prevent hanging connections in case of network issues. The default value is 5 seconds.- This value defaults to 50 and can be changed at the following config path:
canton.participants.<participant_name>.ledger-api.interactive-submission-service.maximum-number-of-signatures-per-party - Added a new configuration parameter
canton.participants.<participant_name>.ledger-api.index-service.max-lookup-limitthat caps the maximum number of contracts returned by a contract key lookup per request. The default value is 1000. - When the
AcsCommitmentProcessoris initializing, read stakeholder groups from the snapshot in batches of sizecanton.parameters.general.batching.max-stakeholder-groups-batch-size(default 1000), rather than all at once. This allows early termination of this initialization if the node is shutting down. - The release version is now exposed in
NodeStatus.NotInitialized, so the node version can be retrieved even before the node is initialized.
Important Changes
PQS and Daml Shell Docker Image Changes
In past releases a single docker image supported multiple PQS major and minor versions, with additional environment variable setup to select the PQS version to run. This has been simplified where each PQSmajor.minor version has their own separate Docker image. Please see the PQS download documentation for details.
The same simplification has been made to the Daml Shell Docker image and is described here.
Removal of Multi-Host Name Resolution Tooling
Support for the multi-host name resolution was removed. This was only used if synchronizer connectivity defined a sequencer with multiple endpoints, which is not supported with our current sequencers: we now have multiple sequencers each with exactly one endpoint.Removal of the Old Sequencer Connection Transports
The old sequencer connections transports have been removed, and only the new sequencer connection pool remains. Consequently, the configuration<node>.sequencer-client.use-new-connection-pool has been deprecated and no longer has any effect.
Other Important Changes
- The expert
keep-alive-clientconfiguration parameter for various client services moved tochannel.keep-alive-client. - We reduced the defaults for
setBalanceRequestSubmissionWindowSizeanddefaultMaxSequencingTimeOffsetto 2 minutes. - The default OTLP gRPC port that the Canton connects to in order to export the traces has been changed from 4318 to 4317. This aligns the default configuration of Canton with the default configuration of the OpenTelemetry Collector. This change affects only the users who have configured an OTLP trace export through
canton.monitoring.tracing.tracer.exporter.type=otlp
New Deprecations
Deprecate Initial Protocol Version Configuration
The config keyparticipant.parameters.initial-protocol-version was unused and has been marked as deprecated.
Canton Configuration Deprecations
- The configuration parameters
topology.use-new-processorandtopology.use-new-clienthave been deprecated and now default totrue. Configuring those parameters to false will be ignored. - The parameter
canton.participants.<participant>.parameters.package-metadata-view.init-takes-too-long-intervalis now ignored, and a warning will only be printed once, rather than periodically. - The parameter
canton.participants.<participant>.parameters.ledger-api-server.indexer.prepare-package-metadata-time-out-warningis now ignored. - The individual JVM metric flags classes, cpu, memoryPools, threads, gc, and buffers in
canton.monitoring.metrics.jvm-metricsare no longer supported since the upgrade to OpenTelemetry instrumentation 2.26.0. All standard JVM metrics (classes, cpu, memory pools, threads, garbage collector) are now always enabled whenjvm-metrics.enabled = true. A new experimental flag has been added to control experimental JVM metrics (e.g. buffer pools). Users who previously setbuffers = trueshould migrate toexperimental = true. See open-telemetry/opentelemetry-java-instrumentation#16087 for details. - The Zipkin trace exporter configuration
canton.monitoring.tracing.tracer.exporter.type=zipkinis deprecated following the OpenTelemetry specification deprecation of Zipkin exporters. The Zipkin exporter will be removed in a future release. Users should migrate to the OTLP exporter. See https://opentelemetry.io/blog/2025/deprecating-zipkin-exporters/ for details. - Removed the feature flag
canton.sequencers.<node>.parameters.async-writer.enabled, as async writing is now the only supported mode. - Changed the path for
crypto.kms.session-signing-keys(deprecated) tocrypto.session-signing-keysso that session signing key configuration is no longer directly tied to a KMS. However, session signing keys can still only be enabled when using a KMS provider or when running withnon-standard-config=true. package-dependency-cachefield in caching configuration is deprecated. It can be removed safely from node configurations.
Operational Procedures
New Features and Enhancements
Change from grpcurl to grpc-health-probe in all Docker Images
The tool used for health check probes changed from grpcurl to grpc-health-probe in all the docker images.
Important Changes
Offline Root Namespace Key Script Updates
The helper offline root namespace key scripts have the following changes:
- Renamed
prepare-certs.shtoprepare-cert.sh - Changed
assemble-certs.shto automatically suffix the generated certificate with a.certextension, similarly to what is being done inprepare-cert.sh - Removed the
10-offline-root-namespace-initexample folder as its content is now integrated in the documented how-to. - Committed the buf image necessary to run the script to the repository (also available in the release artifact), making usage from the open source repo easier
New Deprecations
NoneCompatibility
The following Canton protocol versions are supported:| Dependency | Version |
|---|---|
| Canton protocol versions | 34, 35 |
| Dependency | Version |
|---|---|
| Java Runtime | OpenJDK 64-Bit Server VM (build 21.0.10+7-nixos, mixed mode, sharing) |
| Postgres | Recommended: PostgreSQL 17.9 (Debian 17.9-1.pgdg13+1) – Also tested: PostgreSQL 14.23 (Debian 14.23-1.pgdg13+1), PostgreSQL 15.18 (Debian 15.18-1.pgdg13+1), PostgreSQL 16.14 (Debian 16.14-1.pgdg13+1) |
Appendix: OpenAPI / AsyncAPI Migration
Runtime Compatibility
JSON Messages are compatible so a client built using existing (for instance 3.4.9) code will continue to work properly.Compile-Time Compatibility of the Generated Code
Users that replace the 3.4openapi.yaml with a new one and regenerate code might be forced to fix compilation errors because some parameters have changed from required to optional(or vice versa).
However, users may decide to continue to use previous versions of OpenAPI.
In that case there are no changes required to code.
Information about compatible OpenAPI versions for each release will be in the RELEASE NOTES and openapi.yaml files.
If you decide to use a newer openapi file and regenerate the binding code, the impact of this change varies by language:
- No changes are expected for Java.
- TypeScript will require minor changes (use of !! and ?. operators).
- Clients in languages like Rust will need more (but trivial) changes (use of Option and unwrapping).
- Languages using dynamic typing should not be affected.
CompletionStreamRequest and JsGetActiveContractsResponse with a before and after comparison.