Release of Canton 3.5.1
Canton 3.5.1 has been released on May 27, 2026.What’s New
Contract Keys
Overview
Canton 3.5 introduces contract keys. Compared to a similar feature available in Canton 2.x, there are two notable differences:- The keys are not unique, meaning multiple contracts may share the same key.
- Negative lookups are not validated.
Standard library
Daml language now supports several primitives associated with contract keys. In all cases, the contracts are returned in the following order:- 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.
lookupByKey- Available in prelude. It checks whether a contract with the given key exists and if yes, returns the contract id. If multiple contracts exist, the most recently created is returned. Signature is the same as in 2.x.fetchByKey- Available in prelude. It fetches the first contract id and contract data associated with the given contract key. If multiple contracts exist, the most recently created is returned. Signature is the same as in 2.x.exerciseByKey- Available in prelude. Exercise a choice on the first contract associated with the given key. Signature is the same as in 2.x.lookupNByKey- Available inDA.ContractKeys. It looks up up to n contracts associated with the passed key.
Daml Script
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 to n contracts 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 Upgrades (SCU)
To support SCU upgrade for key and maintainer definitions, new guidelines have been added. 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. This is enforced at package vetting time.Ledger API
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-andInteractiveSubmissionServicehave been reactivated to allow the caller to request pre-heating 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
In PQS, keys are mere metadata that can be queried like any other metadata. It is possible to query for all contracts with a given key:Daml-LF 2.3
A new version of Daml-LF is released: Daml-LF 2.3. Its main features are:DA.Crypto.Text, originally released in 3.4 in early access (alpha) status, is part of LF 2.3, which means it is now marked as stable.- Support for Contract Keys.
Targeting LF 2.3
If you want to use new features available in the LF 2.3, select it explicitly as compilation target by setting the--target=2.3, either as direct argument on the command line or as part of a daml.yaml:
Logical Synchronizer Upgrades
Logical Synchronizer Upgrades, or LSU, replace the procedure previously used to upgrade the synchronizer (Synchronizer Upgrade with Downtime). LSU address the following shortcomings of the previous upgrade procedure:- Reduced downtime The downtime for Daml transactions is in the order of dozens of seconds. The downtime for topology transactions is in the order of hours before the upgrade. This will be improved in a subsequent version.
- No manual coordination for validators Operators of validator nodes only need to upgrade their binary before the upgrade time. The rest of the procedure happens through automation
- Reduced coordination for SVs SVs can progress independently with the preparation of the upgrade and signal their progress using dedicated topology transactions.
- Asynchronous upgrade of each validator Each validator independently upgrade its binary before the upgrade time. Each validator automatically perform the upgrade when it processes the last message of the old synchronizer.
- Preserved local history as well as cryptographic evidence Transaction history (including updates and their offsets) is preserved, as well as ACS commitments.
External submissions around upgrade time
External submissions prepared before upgrade time on a synchronizer running protocol version 34 cannot be submitted after LSU on a synchronizer running protocol version 35: they need to be re-prepared and re-signed.DA BFT Beta
DA BFT is a new ordering service as part of the synchronizer that will replace the current single-leader CometBFT ordering service on the Global Synchronizer with a parallel, multi-leader consensus architecture, enabling significantly higher transaction throughput and fault tolerance. As part of this release DA BFT is ready in beta form for early access testing, but not recommended for production or close-to-production testing yet.Multi Synchronizer Alpha
Multi-synchronizer support is available in early access and has to be enabled explicitly. This feature should only be used in test environments. To enable contract reassignment across synchronizers, the flagPARTICIPANT_FEATURE_FLAG_ENABLE_ALPHA_MULTI_SYNCHRONIZER must be activated on all participants hosting a stakeholder of the contract on both the source and target synchronizers. For a synchronizer, it can be done as follows:
Functional Changes
Party Replication
Offline party replication
Concluding an offline party replication by clearing the onboarding flag now includes two major updates when using protocol version 35:- Added 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.
Party replication onboarding topology event is exposed on Ledger API
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.
Preview: Online party replication
- 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.
Minor Improvements
- Onboarding party submission prevention: Ensures a participant does not submit a transaction or reassignment on behalf of an onboarding party.
- Upgraded gRPC to 1.81.0 and AWS SDK to 2.44.3 to resolve Netty 4.1.130 CVEs (CVE-2026-33870, CVE-2026-33871).
New Transaction Hashing Scheme 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 avaialble from Protocol Version 35. - See the hashing algorithm documentation for the updated version.
- The
max_record_timeis now enforced by all confirming participants. - The Ledger API and Ledger JSON API prepare
InteractiveSubmissionServicehas been modified to take in a specific hashing scheme version in the request. The default hashing scheme isHASHING_SCHEME_VERSION_V2. Integrators are encouraged to move toHASHING_SCHEME_VERSION_V3for synchronizers using protocol version 35. In particular, usage of contract keys requiresHASHING_SCHEME_VERSION_V3. See the versioning documentation for details.
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 <filter> 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 <filter> 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 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 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.
Hardened Error Handling in Sequencer Connect Service
We have implemented strict error sanitization and rewording for the SequencerConnectService to mitigate 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:Ignoring of offboarded sequencers for submission requests
In the case where sequencers are offboarded but remain online and kept in the connectivity configuration, it was still possible that members pick them as the target for submission requests. The submission would fail, but the member would incur a delay as it requires retrying. This has now changed, and offboarded sequencers are ignored when sending submission requests.API Changes
The previous method of returning errors via response fields has been removed in favor 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.
Status codes have changed as follows:
- SequencerAuthenticationService.challenge newly fails with
INVALID_ARGUMENT(instead ofFAILED_PRECONDITION), if the client does not support the sequencer’s protocol version. - SequencerConnectService newly fails with
INVALID_ARGUMENT(instead ofFAILED_PRECONDITION) if a non-participant tries to connect. - SequencerConnectService.registerOnboardingTopologyTransactions newly fails with
INTERNAL(instead ofFAILED_PRECONDITIONS) - if there are no dynamic synchronizer parameters.
- SequencerConnectService.registerOnboardingTopologyTransactions newly fails with
FAILED_PRECONDITIONif - the transactions cannot be added to the topology state and sanitization of error messages is enabled.
Mediator Crash Fault Tolerance
The mediator is now crash fault-tolerant and 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. Furthermore, forcing a query 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.
ACS stream continuation
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 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.
ACS Ledger API counting
Introduced a new memory-efficient consoled commandparticipant.ledger_api.acs.count()
to count the number of active contracts on a participant node.
Note: This command is currently under the Testing feature flag.
ACS pagination
A new,GetActiveContractsPage endpoint added to 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 in descending order of events
TheGetUpdatesRequest object has 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.
GetUpdates pagination
A newGetUpdatesPage endpoint has been added to Update Service API. THis allows retrieval of updates in paginated
form instead of requesting the stream.
Improvements for repair.add and migration advice
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.
Important behavioral change: strict Validation by default
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).
- Impact: If you have existing scripts or recovery procedures that inject manually modified, synthetic, or
inconsistent contracts (where the payload does not strictly match the
ContractIdhash), they will now fail with a"Failed to authenticate contract with id"error. - Migration: To bypass this cryptographic validation and restore the legacy behavior, explicitly pass the
Acceptmode in your command call:
New parameters
The command signature has been expanded to support several optional parameters:workflowIdPrefix: Allows you to set a custom prefix for the generated workflow ID to easily track the repair transactions (defaults toimport-<UUID>).contractImportMode: Choose betweenValidation(default, validates that contract IDs comply with the scheme associated to 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.
Improved party and repair ACS imports
We have completely overhauled the ACS import endpoints for both party replication and participant repair 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
Action required: Breaking API change
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")
import_acs:
- 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 to a different synchronizer.
Details on the gRPC ImportAcs repair endpoint
The ImportAcs and ImportAcsV2 RPCs have been consolidated, introducing the following breaking changes and migration
steps:
- Endpoint removed:
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 explicitlyoptional. - A new
optional string synchronizer_id = 6field was added. - Migration (ScalaPB): Adding
optionalchanges generated code from base types toOption[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
The ImportPartyAcs 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:
- New capability (
party_id): A newoptional 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.
Topology-Aware Package Selection (TAPS) improvements
Topology-Aware Package Selection (TAPS) refinement for handling 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.
Ledger API Improvements
- ApiRequestLogger now also used by Ledger JSON Api. Changes:
- Redundant Request TID removed 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).
- LedgerAPI ListKnownParties supports an optional prefix filter argument filterParty.
The respective JSON API endpoint now additionally supports
identity-provider-idas an optional argument, as well asfilter-party. - Protect the admin participant from self lock-out. It is now impossible for an admin to remove 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. - OffsetCheckpoints are now always generated when an open-ended updates or completions 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
By default the value of this parameter is 0. - An IDP administrator can now only allocate parties confined to their own IDP perimeter.
New metrics related to LSU
Some new metrics have been added to monitor the status of an LSU.-
For sequencers: daml.received-lsu-sequencing-test-messages
Allows to track the number of
LsuSequencingTestmessages received by a mediator, per sender. - For participants: daml.participant.lsu_status Exposes the status of an LSU on a participant node.
- For sequencers: daml.sequencer.public-api.handshakes Exposes the number of handshakes per member and status. Can be used to track how many of the participant nodes already performed handshake with the successor.
- For sequencers: daml.sequencer.lsu_contact_successor_status Exposes the status of the handshake between a sequencer and its successor.
Performance Improvements
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.Compatible sibling views compression
In protocol version 35, each envelope inTransactionConfirmationRequest contains multiple views grouped by recipients instead of one envelope per view.
Assignment and re-assignments also use this new format, but they always have one view.
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 signing threshold and signing keys. This effectively deprecate 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 future version, creation of new PartyToKeyMapping transactions may be disallowed.
Deprecated TopologyManagerReadService.ListAll in favor of ListAllV2, which uses an inclusion
list (include_mappings) instead of an exclusion list (exclude_mappings). This avoids sending
mapping codes unknown to older servers. The console method topology.transactions.list now calls
ListAllV2 by default and only falls back to ListAll when targeting a 3.4 node. The
excludeMappings and protocolVersion parameters of topology.transactions.list are deprecated;
use filterMappings instead.
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.
Deprecated SequencerInitializationService.InitializeSequencerFromGenesisState,
SequencerInitializationService.InitializeSequencerFromOnboardingState,
SequencerAdministrationService.OnboardingState, and
TopologyManagerReadService.GenesisState, along with their console counterparts
setup.assign_from_genesis_state, setup.assign_from_onboarding_state,
setup.onboarding_state_for_sequencer, setup.onboarding_state_at_timestamp,
and topology.transactions.genesis_state.
Please use the corresponding V2 variants (InitializeSequencerFromGenesisStateV2,
InitializeSequencerFromOnboardingStateV2, OnboardingStateV2, GenesisStateV2,
assign_from_genesis_stateV2, assign_from_onboarding_stateV2,
onboarding_state_for_sequencerV2, onboarding_state_at_timestampV2,
genesis_stateV2) instead, which use an updated internal bytestring format
that enables streaming ingestion, making snapshot export and import significantly less memory-intensive.
Minor Performance Improvements
- The Postgres connection tuning configuration of the indexer is now separated from the configuration of the Ledger API server
(
canton.participants.<participant>.ledger-api.postgres-data-source). The new configuration sectioncanton.participants.<participant>.parameters.ledger-api-server.indexer.postgres-data-sourceshould be used instead to tune the indexer’s Postgres connections. - A new indexer pipeline batching strategy added under the feature flag
useWeighetdBatching. When switched on, the batches are created using their estimated database processing time using thesubmissionBatchInsertionSizeas a limit for individual batches - Changed the
CompressedBatchstructure in the sequencer protocol for protocol version 35 to separately keep recipients and envelopes (fromgzip(Seq((recp1, payload1), (recp2, payload2)))togzip(Seq(recp1, recp2)), Seq(gzip(payload1), gzip(payload2)))). - Batching configuration now allows setting different parallelism for pruning (currently only for Sequencer pruning):
New option
canton.sequencers.sequencer.parameters.batching.pruning-parallelism(defaults to2) can be used separately from the generalcanton.sequencers.sequencer.parameters.batching.parallelismsetting. - Made the config option
...topology.use-time-proofs-to-observe-effective-timework and changed the default tofalse. Disabling this option activates a more robust time advancement broadcast mechanism on the sequencers, which however still does not tolerate crashes or big gaps in block sequencing times. The parameters can be configured in the sequencer viacanton.sequencers.<sequencer>.parameters.time-advancing-topology. - Additional metrics for the ACS commitment processor:
daml.participant.sync.commitments.last-incoming-received,daml.participant.sync.commitments.last-incoming-processed,daml.participant.sync.commitments.last-locally-completed, anddaml.participant.sync.commitments.last-locally-checkpointed.
Breaking Changes
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 have been removed. Specifically, the following macros are no longer available:step1_hold_and_store_acsstep2_import_acs
Removal of deprecated, legacy ACS export and import endpoints
The legacy repair endpoints for the ACS export and import have been removed:- Console command
participant.repair.export_acs_old - Console command
participant.repair.import_acs_old - gRPC rpc
ParticipantRepairService.ExportAcsOld - gRPC rpc
ParticipantRepairService.ImportAcsOld
Migration advice
Use repair endpoints without the ‘old’ suffix:- 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
Migrating to export_acs
The most significant change is the removal of thetimestamp 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 atimestamp. - 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:
parties->party_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.timestamp->ledger_offset(Breaking): You must provide an exactint64 ledger_offsetinstead of a timestamp.filter_synchronizer_id->synchronizer_id: Field renamed for consistency.- Removed fields:
forceandparties_offboardinghave been completely removed. - New fields:
contract_synchronizer_renamesandexcluded_stakeholder_ids.
Migrating to 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).
Only PackageName is accepted on Ledger API
Usage of package id for ledger queries was deprecated and now the validation will fail if used. The impacted APIs are:- GetUpdates
- GetUpdateByOffset
- GetUpdateById
- GetActiveContracts
- GetEventsByContractIdRequest
- SubmitAndWaitForTransaction (the optional
transaction_format) - SubmitAndWaitForReassignmentRequest
- ExecuteSubmissionAndWaitForTransactionRequest
SynchronizerId field update in Externally signed transactions
In Protocol version 35, thesynchronizer_id field in 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.
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 to pass the output ofparticipant.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 automatic recomputation of contract ids upon ACS import
The ability to recompute contract ids upon ACS import has been removed.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.Ledger JSON API Spec Corrections
JSON Ledger API OpenAPI/AsyncAPI spec corrections-
Fields not marked as required in the Ledger API
.protospecification are now also optional in the OpenAPI/AsyncAPI specifications. If your client code is using code generated using previous versions of these specifications, it may not compile or function correctly with the new version. To migrate:- If you prefer not to update your code, continue using the previous specification versions as the JSON API server preserves backward compatibility.
- If you want to use new endpoints, features or leverage the new less strict spec, migrate to the new OpenAPI/AsyncAPI specifications as follows:
- Java clients: No changes are needed if you use the
OpenAPI Generator. Otherwise, potentially optionality of fields should be handled appropriately for other code generators. - TypeScript clients: Update your code to handle optional fields, using the
!or??operators as appropriate.
- Java clients: No changes are needed if you use the
-
From Canton 3.5 onwards, OpenAPI/AsyncAPI specification files are suffixed with the Canton version (e.g.,
openapi-3.5.0.yaml). - Canton 3.5 is compatible with OpenAPI specification files from version 3.4.0 to 3.5.0 (inclusive).
- The Ledger JSON API server now enforces that only fields marked as required by the Ledger API OpenAPI/AsyncAPI specification are mandatory in request payloads.
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.Minor Breaking 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
- Removed the
LastErrorsAppenderalong with the Admin API endpointsStatusService.GetLastErrorsandStatusServiceGetLastErrorTrace, as well as the corresponding console commandslast_errorsandlast_error_trace.
Deprecations
Deprecate scope-based access tokens
- “Scope-based” access tokens, i.e. JWTs without any audience specified, have been deprecated.
- A configuration that does not specify a
target-audiencewill log a warning on node startup. - Configurations that specify both a
target-audienceand atarget-scopeare not supported in this version and will also log a warning on node startup. - Starting Canton version 3.7, support for “scope-based” tokens will be removed entirely to enforce a valid
audfield in every incoming JWT. - The
scopefield will, in a future version, be repurposed to serve exclusively as an additional, optional claim for fine-grained permissions.
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.
Deprecate initial protocol version configuration
The config keyparticipant.parameters.initial-protocol-version was unused and has been marked as deprecated.
Configuration Deprecations
- The configuration parameters
topology.use-new-processorandtopology.use-new-clienthave been deprecated and now default to true. 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, andbuffersincanton.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 newexperimentalflag has been added to control experimental JVM metrics (e.g. buffer pools). Users who previously setbuffers = trueshould migrate toexperimental = true. See https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/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 incachingconfiguration is deprecated. It can be removed safely from node configurations.
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 a POST request with the same body as the deprecated GETv2/package-vettingendpoint and returns the list of vetted packages in the same format.v2/package-vetting/updateaccepts a POST request with the same body as the deprecated POST endpointv2/package-vettingand returns the updated vetting state of the package in the same format.
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.
Minor Improvements
Bugfixes
- Fixed a mid-crash recovery issue for offline party replication and repair ACS imports. Previously, if an ACS import was interrupted (for example by a participant node restart or crash), a subsequent recovery attempt could result in missing contracts on the Ledger API. The recovery process now properly rolls back uncommitted partial states upon retrying the ACS import, ensuring recovered contracts are completely synchronized across both internal storage and the Ledger API.
- Fixed a bug where the Ledger API
PackageService.ListVettedPackagesused to return a potentially not yet effective state of the vetted packages. Now it returns the state of vetted packages effective at the time of the request. - Sequencer health status used to incorrectly return the synchronizer uid instead of the sequencer uid.
- Prevent Ledger API crashes after running
ParticipantRepairService.PurgeContractsadmin command. Fixes a critical issue where using theParticipantRepairService.PurgeContractscommand (when multi-synchronizer support is disabled) generated malformed Daml values for the choice argument and choice result of theArchivechoice of the purge contract events in the Ledger API event store. This previously caused the Ledger API streams reading the generatedArchiveevents to crash. The repair command now generates correct Daml values for the corresponding entries, that can be safely delivered by the Ledger API. - Fixed a bug in the repair service’s
changeAssignationwhere only a single repair counter was allocated when reassigning multiple contracts, violating the monotonicity expected by the indexer.
Ledger API Multi-Synchronizer Events Alpha Support
Adds a new participant node parameter,alpha-multi-synchronizer-support (Boolean).
- Default (
false): Uses standard Create and Archive events. - Enabled (
true): Uses Assign and Unassign events.
Support for adding table settings for PostgreSQL
Added support for adding table settings for PostgreSQL. One can use a repeatable migration (Flyway feature) in a file provided to Canton externally.- Use the new config
repeatable-migrations-pathsunder thecanton.<node_type>.<node>.storage.parametersconfiguration section. - The config takes a list of directories where repeatable migration files must be placed, paths must be prefixed with
filesystem:for Flyway to recognize them. - Example:
canton.sequencers.sequencer1.storage.parameters.repeatable-migrations-paths = ["filesystem:community/common/src/test/resources/test_table_settings"]. - Only repeatable migrations are allowed in these directories: files with names starting with
R__and ending with.sql. - The files cannot be removed once added, but they can be modified (unlike the
V__versioned schema migrations), and if modified these will be reapplied on each Canton startup. - The files are applied in lexicographical order.
- Example use case: adding
autovacuum_*settings to existing tables. - Only add idempotent changes in repeatable migrations.
Offline root namespace key scripts
Offline root namespace key scripts:- 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: https://docs.digitalasset.com/operate/3.5/howtos/secure/keys/namespace_key.html - 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
Reliability Improvements
- 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_interval for db operations in the Ledger API server and indexer to avoid
hanging connections for Postgres (see PostgresDataSourceConfig). The defaults are 60 seconds network timeout and
5 seconds client_connection_check_interval for the Ledger API server, and 20 seconds network timeout and
5 seconds client_connection_check_interval for the indexer. These values can be configured via the new configuration parameters
canton.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.- 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 - 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 AcsCommitmentProcessor is initializing, read stakeholder groups from the snapshot in batches of size
canton.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.
Compatibility
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) |