Release of Canton 3.6.1
Canton 3.6.1 has been released on October 05, 2026.Summary
This minor release brings new features, scalability improvements, as well as many other improvements. For scalability a complete redesign and new implementation of ACS commitments landed in protocol version 36.- Decouples the validator memory usage from the number of hosted parties and their stakeholder groups to lift party growth restrictions on the network
- Constant-time effort for processing non-local party hosting changes for improved security and availability resilience
What’s New
New ACS commitment pipeline
ACS commitments have been completely reimplemented. The new implementation consists of three components:- The digest processor aggregates the ACS and the changes to it into per-party and per-counterparticipant digests.
- The sender turns digests into commitments by signing them and sends them to the counterparticipants.
- The matcher receives the commitments from counterparticipants and compares them to the local digests to detect mismatches.
canton.participants.<participant>.parameters.acs-commitment.enable-new-acs-commitment-processor (default true)
and canton.participants.<participant>.parameters.acs-commitment.disable-old-acs-commitment-processor (default on-new-protocol-versions).
Each time the new commitment processor is enabled afresh, the digest processor will reinitialize all the new digests from the current ledger end.
While this happens in the background, the participant and its DB may see increased load.
Conversely, whenever the new commitment processor is disabled, all the new digests are deleted from the DB to free the space.
When the old commitment processor is reenabled after it has been disabled, commitments must be manually reinitialized on all connected synchronizers.
Otherwise the old commitments are likely inconsistent with the ACS and commitment mismatches are to be expected.
The existing ACS commitment inspection and tooling APIs work only against the old commitment processor.
So when the old commitment processor is disabled, the APIs may produce outdated information or fail outright.
In particular, no-wait and pruning configurations have no effect. The new commitment processor always operates
in the safe-to-prune mode SAFE_TO_PRUNE_COMMITMENT_STATE_MATCH, i.e., outstanding commitments from counterparticipants
never prevent pruning.
The new commitment processor provides an API to trigger reinitialization <participant reference>.commitments.reinitialize_digest_commitments
and query the status of reinitialization <participant reference>.commitments.digest_commitments_reinitialization_status.
Reinitialization now also works when the participant is not connected to the targeted synchronizer.
The new commitment processor also provides an API to trigger a consistency check of the ACS digests <participant reference>.commitments.run_digest_consistency_check
and query the status of the check <participant reference>.commitments.digest_consistency_check_status. This can be used before performing a LSU.
The new commitment processor exposes among others the following metrics. They are disjoint from the old commitment processor metrics.
daml.participant.sync.commitments.checkpoint-watermarktracks the progress of the digest processor in record time of the connected synchronizer. It corresponds to the formerdaml.participant.sync.commitments.last-locally-checkpointedmetric.daml.participant.sync.commitments.tick-watermarktracks the finished reconciliation interval of the digest processor. It corresponds to the formerdaml.participant.sync.commitments.last-locally-completedmetric.daml.participant.sync.commitments.received-watermarktracks the sequencing time of the latest received new ACS commitment. It corresponds to the formerdaml.participant.sync.commitments.last-incoming-receivedmetric.daml.participant.sync.commitments.matching-watermarktracks the record time up to where the matcher has progressed. It replaces the formerdaml.participant.sync.commitments.last-incoming-processed, which measures the end of the period of the received commitment instead of the record time of when the commitment was sequenced.daml.participant.sync.commitments.sender.watermark-timestamptracks the period end record time up to where the node has sent its commitments.daml.participant.sync.commitments.digest-processor-health,daml.participant.sync.commitments.matcher-health, anddaml.participant.sync.commitments.sender.sender-health, report on the health of the different components.daml.participant.sync.commitments.running-digest-processor.loaded-digestscounts the number of loaded digests in memory and gives an indication of the memory usage of the new processor.daml.participant.sync.commitments.latest-matching-statustracks the matching status of the youngest reported commitment period. The metric is labeled with thecounterparticipant.daml.participant.sync.commitments.latest-matching-status-period-endtracks the timestamp of the end of the youngest reported commitment period. The metric is labeled with thecounterparticipant.
canton.participants.<participant>.parameters.journal-garbage-collection-minimum-gap (default 30 minutes) determines
how frequently journal garbage collection shall be triggered if there is a continuous stream of ACS changes. Previously,
this was tied to the reconciliation interval of the connected synchronizer.
Daml
Daml-LF 2.3 is now the default target version
A Daml project that does not specify an LF version indaml.yaml now compiles to Daml-LF 2.3 by default. Canton’s convention is to make an LF version the default one release after it first ships, and 2.3 shipped in 3.5.
A project previously compiled for LF 2.2, whether by an explicit --target=2.2 or by relying on the prior default, will still operate. See Canton 3.5.1: Targeting LF 2.3 for the original guidance.
To restore the previous behavior:
Daml choices can now make external calls
Daml choices can call out to participant-configured extension services during interpretation, configured throughExtensionServiceConfig under:
Daml Script: cross-SDK dependencies
Daml Script now supports dependencies on packages built with a different SDK version, through data-dependencies. All participating daml-script versions must be 3.6.0 or later. A 3.6.x script cannot depend on a 3.5.x script, and the script runner must be at least as up to date as the highest daml-script version in use. Action required: submit-error types renamed (breaking).SubmitError, UpgradeErrorType, CryptoErrorType, ExternalCallErrorType, and DevErrorType are renamed to their Any<X> equivalents, and now use an IsX typeclass providing fromX and toX functions for each error type. Pattern synonyms preserve most of the existing source syntax, but some fields had to be renamed to stay unique. See Compatibility.daml in the daml-script sources for the mapping.
Daml Stdlib updates
(:|)and(<|)are added as synonyms forDA.NonEmpty, andShowis defined using the same representation.Logic.reduceno longer incorrectly merges a nested Disjunction as a Conjunction.toNNFinDA.Logicis now idempotent for stacked negations.toDNSinDA.Logicis now idempotent for stacked negations.
Participant Query Store (PQS): renamed from Scribe
Overview
Scribe is renamed to Participant Query Store (PQS) across every deployment artifact. During the transition, both the new participant-query-store and the legacy scribe name, including their Docker images, are published side by side. Both configure the same pqs command and the samejava -jar pqs.jar entrypoint, so existing deployments keep working while teams migrate to the new names. Environment variables using the new PQS_ prefix, for example PQS_TARGET_POSTGRES_HOST, are now supported. The old SCRIBE_ prefix still works as a fallback, but it now prints a deprecation warning. Migrate to PQS_ going forward.
The target release to remove the deprecated scribe artifacts and configurations is Canton 3.8.
Action required: renamed deployment artifacts (breaking)
Anything that references Scribe’s binary names, container metadata, or metric prefixes needs to be updated:
PQS configuration also no longer supplies default Postgres credentials. Supplying
--target-postgres-username and --target-postgres-password, or the corresponding PQS_TARGET_POSTGRES_USERNAME and PQS_TARGET_POSTGRES_PASSWORD environment variables, is now mandatory.
SQL and query changes
Interface view rows no longer storecontract_key_hash. Previously the hash of the underlying template’s contract key was duplicated onto every interface view row, even though contract_key was already empty there. Both columns are now empty for interface views, and the hash remains available on the template row. Upgrading clears the hash from interface view rows already stored. SQL migration V042__Clear_contract_key_hash_for_interface_views.sql performs this cleanup, with impact under 1 minute.
A new print_create_index_for_contract SQL function generates the statement to create a concurrent index for a contract.
A new --target-postgres-properties-<key>=<value> flag passes arbitrary pgjdbc connection properties through to the driver, enabling driver-level features such as JDBC authentication plugins, for example Azure Entra ID:
Reliability improvements
A performance optimization is that the core SQL functions now compute the nearest offset only once per query instead of repeatedly:creates, exercises, active, and archives.
A timestamp (or duration) prune target older than all recorded history is now treated as a successful no-op instead of raising an error.
Experimental Post Quantum Cryptography
Added experimental support for ML-DSA. Currently only ML-DSA-65 is supported. Experimental algorithms need to be explicitly enabled via a node’s crypto configuration in<node>.crypto.enable-experimental = true.
Ledger API Improvements
Lookup by Transaction Hash
The Ledger API update service now exposes aGetUpdateByHash endpoint. Given a transaction hash, it returns the corresponding transaction if the caller has visibility over it. The hash is available on externally-signed (Interactive Submission Service) transactions.
- gRPC:
UpdateService.GetUpdateByHash - JSON API:
POST /v2/updates/update-by-hash
Completion Lookup by Transaction Hash
The Ledger API command completion service now exposes aGetCompletionByHash endpoint. Given a transaction hash, it returns the accepted completion (if any) and recent rejected completions for that hash. The hash is available on externally-signed (Interactive Submission Service) transactions.
- gRPC:
CommandCompletionService.GetCompletionByHash - JSON API:
POST /v2/commands/completion-by-hash
Party JWTs (self-signed JWTs)
- The Ledger API now exposes a
GetJwksendpoint. This can be used to obtain public keys for specific parties in JWK format.- gRPC:
JoseService.GetJwks - JSON API:
GET /v2/jose/jwks/synchronizer/<synchronizer-id>/party/<party-id>
- gRPC:
- A
type = party-jwtcan be added toparticipants.<participant>.ledger-api.auth-servicesto enable this feature.
New Sequencer Aggregator
Re-implemented the Sequencer Aggregator to be more resilient to misbehaving sequencers. Switching between the old and new implementation is controlled by thesequencer-client.use-new-aggregator configuration option, which defaults to true.
One of the improvements allows the aggregator to detect sequencers that provide an incorrect event after that event has already reached consensus with sufficiently many other sequencers. A cache of past processed events is kept for that purpose, whose size is controlled by the sequencer-client.past-events-cache-size configuration option (default: 1000).
Support for Postgres 18
Canton is now supported on Postgres 18. Heads-up: Postgres 14 is becoming end-of-life by Nov 2026 and support of PG14 will be removed in future Canton versions.Traffic Enforcement App
- Add admin endpoint to prune events from the traffic enforcement event table -
PruneEvents. This is used to keep the event table from growing indefinitely. This does not affect the account balance. WARNING: Affects de-duplication. If an event is pruned, de-duplication UpdateAccount requests on it will NOT be possible. - The configuration field for the traffic enforcement app has been renamed from
traffic-enforcementtotraffic-accounting. The old name is still accepted for backwards compatibility, but will be removed in a future release.
Synchronizer Limits
AddedSynchronizerLimits in the StaticSynchronizerParameters, which are size limits on various collections, globally enforced by all synchronizer members. These limits are effective only starting with PV36.
Synchronizer operators are required to choose explicit values for those limits when upgrading to PV36.
Note: when using the console to bootstrap a synchronizer, the console will automatically set the limits to default values.
However we strongly recommend to explicitly choose those values instead of relying on the defaults.
When interactive with the gRPC API directly, limits must be explicitly set on the StaticSynchronizerParameters protobuf message when bootstrapping a synchronizer on PV36.
String Validation
Strings in protocol messages and APIs are strictly validated in protocol version 36 to be valid UTF16, not contain invalid escape characters or null characters. Invalid strings will be rejected during parsing.Improved Sequencer Logging
On the sequencer, the log line mentioning all events in a block now also can contain the outcome of the event. By settingcanton.sequencers.sequencer.parameters.enable-async-sequencer-logging = true, the logging will be
moved to the end of the block processing, but will include the outcome of the events in the block. The default
remains false to preserve the current behavior.
Note that as part of this change, the sequencer-id of the traffic control metrics and of the block event processor
metrics dropped the superfluous leading “SEQ::” string.
Heavy DB Migrations
The following DB migrations are applied automatically at startup and may have a impact on startup times the first time.lapi_events_party_to_participant Database Migration
On upgrade, the participant database is migrated as follows:
- A
partycolumn is added to thelapi_events_party_to_participanttable. The migration takes roughly 30 seconds per 1 million parties. - The
external_stringcolumn of thestring_interningtable now enforces anot nullconstraint. This is a no-op for existing data, but prevents future inserts of null values.
Reassignment store database migration
On upgrade, a participant database migration updates the reassignment store: it backfills the newstakeholders column from the persisted contracts and drops the old contracts column. This runs
automatically as part of the startup migration step. Its duration scales with the number of
reassignments in the store, taking roughly 1 second per 10,000 reassignments.
Breaking changes
Removal of Deprecated Configuration keys
- The following configuration keys were deprecated in 3.5 and no long exist in 3.6; and need to be removed from the configuration files:
- `topology.use-new-processor
topology.use-new-client
Admin API
Canton console command<sequencerReference>.setup.initialize_from_lsu_predecessor, admin console command class SequencerAdminCommands.InitializeFromLsuPredecessor and the respective proto InitializeSequencerFromLsuPredecessorRequest now require to specify synchronizerId (logical) on the request.
Sequencer API
The sequencers now also enforce confirmation throughput caps. If throughput caps are configured, they will also apply to confirmations. The cap for confirmations can be configured withconfirmation-response.per-client-tps-cap. It should be set slightly above the global confirmation request cap, as a member should not need to confirm more requests than can be submitted globally. The confirmation-response.global-tps-cap can be set to the maximum sequencer event capacity.
Error Codes
(Potentially) Breaking: Aggregatable submissions are now rejected eagerly to preserve bandwidth. This means that the submission error codeSEQUENCER_AGGREGATE_SUBMISSION_ALREADY_SENT may now also be returned during
the synchronous submission of the sequencer, as the state of the aggregation is
also checked before ordering.
In addition, the gRPC error code has been modified from FAILED_PRECONDITION to
ALREADY_EXISTS to better reflect the nature of the error. Clients should be
updated to handle this error code accordingly. Due to backwards compatibility,
the old gRPC error code will be returned for PV35 and before on the async path,
and the new capability must only be turned on when all nodes have been upgraded
to a Canton version that supports this change. The new capability can be enabled
using
canton.sequencers.seq.parameters.enable-reject-delivered-aggregations-on-pv-35 = MED for mediators. This can be combined with the new configuration option of
the mediator
canton.mediators.mymediator.parameters.delayed-verdict-sender.enabled = true.
Generally, the sequencer will send out the verdict after reaching the threshold.
All subsequent sent verdicts are thrown away. The new option now allows
threshold + extra verdicts to be sent immediately, while the rest of the
mediators will wait a short amount of time. This allows to reduce the load on
the sequencer by 30%, creating more capacity for other transactions.
Scala Console
The following changes may impact bootstrap scripts or console usage:- Removed the
protocolVersionparameter from all<node>.topology.<mapping>.listconsole commands as it was not working properly. - The
com.digitalasset.canton.config.PositiveInt.incrementmethod now returns anEither[InvariantViolation, PositiveInt]instead of aPositiveInt. - The
com.digitalasset.canton.config.NonNegativeNumeric.incrementmethod now returns anEither[InvariantViolation, NonNegativeNumeric]instead of aNonNegativeNumeric. NonEmptyhas moved fromcom.daml.nonemptytocom.digitalasset.nonempty, and its scalaz type class instances have been replaced by cats ones. Separately, scalaz has been removed from the published Daml-LF modules: for example theOrderandEqualinstances onValue.ContractIdare now a standard ScalaOrdering.
Security
TLS Versions
Public API servers now reject client connections using TLS 1.0 and 1.1. Clients must use TLS 1.2 or higher. This security enforcement aligns all public APIs with the existing Admin API requirement. For details on TLS version deprecations, see RFC 8996.TLS Default Cipher Suites
Updated the list of default cipher suites according to the current OWASP recommendations. The list of removed suites:TLS_DHE_RSA_WITH_AES_256_GCM_SHA384TLS_DHE_RSA_WITH_AES_128_GCM_SHA256TLS_DHE_RSA_WITH_AES_256_CBC_SHA256TLS_DHE_RSA_WITH_AES_128_CBC_SHA256TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
canton.participants.<participant>.ledger-api.tls.ciphersif you havecanton.participants.<participant>.ledger-api.tlsset alreadycanton.sequencers.<sequencer>.public-api.tls.ciphersif you havecanton.sequencers.<sequencer>.public-api.tlsset already
Metrics
Ledger API and Indexer Metrics
- The indexer queue metrics
daml.participant.api.indexer.indexer_queue_blocked,daml.participant.api.indexer.indexer_queue_bufferedanddaml.participant.api.indexer.indexer_queue_uncommittedare now exposed as gauges instead of meters. - The metric
daml.participant.api.services.pruning.contract_pruning_retried, which tracks how many times contract pruning was retried, is now a histogram. - Removed the unused metrics
daml.participant.api.lapi.streams.transaction_trees_sentanddaml.participant.api.index.transaction_trees_buffer_size.
ACS Commitment Metrics
ACS commitment metrics distinguish the synchronizer alias and distinguished counterparticipants via a label instead of including it in the metric name. Affected are the following metrics:daml.participant.sync.commitments.<synchronizer-alias>.counter-participant-latency.<participant>->daml.participant.sync.commitments.counter-participant-latencydaml.participant.sync.commitments.<synchronizer-alias>.largest-counter-participant-latency->daml.participant.sync.commitments.largest-counter-participant-latencydaml.participant.sync.commitments.<synchronizer-alias>.largest-distinguished-counter-participant-latency->daml.participant.sync.commitments.largest-distinguished-counter-participant-latency
ACHS Processing Metrics
Fine-grained metrics for Active Contracts Head Snapshot (ACHS) processing. Please note ACHS is disabled by default.- Removed database metric
daml.participant.api.indexer.achs_processing.*which captured runtime metrics for all types of database calls. - Added the following metrics to capture individual database metrics for ACHS initialization (establish snapshot baseline):
daml.participant.api.indexer.achs_processing.initialization.store_achs_valid_atdaml.participant.api.indexer.achs_processing.initialization.update_achs_last_pointersdaml.participant.api.indexer.achs_processing.initialization.add_activations_to_achsdaml.participant.api.indexer.achs_processing.initialization.remove_deactivated_from_achs
- Added the following metrics to capture individual database metrics for ACHS maintenance (during indexing):
daml.participant.api.indexer.achs_processing.maintenance.store_achs_valid_atdaml.participant.api.indexer.achs_processing.maintenance.update_achs_last_pointersdaml.participant.api.indexer.achs_processing.maintenance.add_activations_to_achsdaml.participant.api.indexer.achs_processing.maintenance.remove_deactivated_from_achs
Configuration
Renamed participant parameter commit-after-failed-activeness-check
The participant parameter commit-after-failed-activeness-check has been renamed to
crash-after-failed-validation, and its meaning is inverted. The default behavior is unchanged, so
no action is needed unless the parameter was set explicitly:
The old name is no longer accepted, so a configuration that still sets it is rejected at startup.
Minor Breaking Configuration Changes
- Unknown config keys are now making config parsing failing. This mechanism was already in place, but it didn’t include all the config keys, which is now fixed.
- Separated the config for support of dev and alpha protocol versions. In order to use pv=dev, you now have to specify
dev-version-support = trueinstead ofalpha-version-support = true(canton.parameters.non-standard-config = trueis still needed).
Artifacts
kms-driver-apiandkms-driver-testingare now published to Maven Central, and will no longer be available in Artifactory.canton-protobuf.ziphas been renamed tocanton-api.zipto reflect that the archive now contains more than protobuf files.
Deprecations
Legacy Ledger API / JSON API endpoints disabled by default (removal in 3.7)
The Ledger API and Ledger JSON API endpoints and request fields that were deprecated in Canton 3.4 and 3.5 remain available in Canton 3.6, but they are now disabled by default. Calls to them fail with theDEPRECATED_API_DISABLED error (gRPC status FAILED_PRECONDITION) unless the participant is started with the
feature flag that the error message names:
canton.participants.<participant>.features.deprecated.enable-deprecated-endpoints-34:
- gRPC
InteractiveSubmissionService.GetPreferredPackageVersionand the console commandpreferred_package_version. UseGetPreferredPackages/preferred_packagesinstead, which resolve the preferred packages for one or more package-name vetting requirements in a single call. GET /v2/interactive-submission/preferred-package-version. UsePOST /v2/interactive-submission/preferred-packagesinstead.(WebSocket) GET/POST /v2/updates/trees. Use/v2/updatesinstead withupdateFormat.includeTransactions.transactionShape = TRANSACTION_SHAPE_LEDGER_EFFECTS(WebSocket) GET/POST /v2/updates/flats. Use/v2/updatesinstead withupdateFormat.includeTransactions.transactionShape = TRANSACTION_SHAPE_ACS_DELTAGET /v2/updates/transaction-tree-by-offset/{offset}. UsePOST /v2/updates/update-by-offsetinstead withupdateFormat.includeTransactions.transactionShape = TRANSACTION_SHAPE_LEDGER_EFFECTS.POST /v2/updates/transaction-by-offset. UsePOST /v2/updates/update-by-offsetinstead withupdateFormat.includeTransactions.transactionShape = TRANSACTION_SHAPE_ACS_DELTAGET /v2/updates/transaction-tree-by-id/{update-id}. UsePOST /v2/updates/update-by-idinstead withupdateFormat.includeTransactions.transactionShape = TRANSACTION_SHAPE_LEDGER_EFFECTSPOST /v2/updates/transaction-by-id. UsePOST /v2/updates/update-by-idinstead withupdateFormat.includeTransactions.transactionShape = TRANSACTION_SHAPE_ACS_DELTAPOST /v2/commands/submit-and-wait-for-transaction-tree. UsePOST /v2/commands/submit-and-wait-for-transactionwithtransactionFormat.transactionShape = TRANSACTION_SHAPE_LEDGER_EFFECTSinstead. Note that the response carries a flattransaction.eventsarray rather than atransactionTree.eventsByIdmap.
canton.participants.<participant>.features.deprecated.enable-deprecated-parameters-34:
- The deprecated
filterandverbosefields of(WebSocket) GET/POST /v2/updatesand(WebSocket) GET/POST /v2/state/active-contracts. UseupdateFormatrespectivelyeventFormatinstead.
canton.participants.<participant>.features.deprecated.enable-deprecated-endpoints-35:
GET /v2/package-vetting. UsePOST /v2/package-vetting/listinstead.POST /v2/package-vetting. UsePOST /v2/package-vetting/updateinstead.GET /v2/state/active-contracts-page. UsePOST /v2/state/active-contracts-pageinstead.
Reminder: Legacy Ledger API / JSON API endpoints will be removed in version 3.7.
The Ledger API and JSON API endpoints and request fields deprecated in Canton 3.4 and 3.5 (see “Legacy Ledger API / JSON API endpoints disabled by default” above) are disabled by default in 3.6 and can only be re-enabled temporarily withcanton.participants.<participant>.features.deprecated.enable-deprecated-endpoints-34,
canton.participants.<participant>.features.deprecated.enable-deprecated-parameters-34 respectively
canton.participants.<participant>.features.deprecated.enable-deprecated-endpoints-35. They will be removed in Canton 3.7.
Reminder: Support for scope-based access tokens will be removed in version 3.7
- “Scope-based” access tokens, i.e. JWTs without any audience specified, have been deprecated in version 3.5.
- Versions 3.5 and 3.6 allow configurations using the default or explicitly configured target audiences, and log a warning for non-compliant configurations.
- In release 3.7, support for “scope-based” tokens will be removed entirely to enforce a valid
audfield in every incoming JWT. Thescopefield will be repurposed to serve exclusively as an additional, optional claim for fine-grained permissions.
Logback upgraded to 1.6 deprecates conditionals
The<if condition= syntax is now deprecated due to security vulnerabilities. The recommended style is to use the <condition ...><if> syntax.
For more information on conditional configuration see:
https://logback.qos.ch/manual/configuration-conditional.html
Minor Deprecations
StaticSynchronizerParameters.defaultsWithoutKMShas been deprecated in favor ofStaticSynchronizerParameters.defaults. Supported cryptographic schemes now have parity between KMS and non-KMS configurations.- The
ledger-api-server-parameters.contract-id-seedingconfiguration parameter is deprecated and no longer used. The contract ID seeding now uses the same random source as the rest of Canton, which is the equivalent of thestrongtype. - Ledger JSON API
/v2/state/active-contracts-pageis now available via POST; the GET variant that expects a request body is deprecated. - Deprecated configuration settings:
canton.participants.<participant>.parameters.ledger-api-server.indexer.use-weighted-batchingandcanton.participants.<participant>.parameters.ledger-api-server.indexer.submission-batch-insertion-size. These are no longer supported.
Minor Improvements
- Mediator: Fix for the mediator verdict sender to correctly stop retrying to send verdicts if the sequencer reports that the verdict has already been successfully aggregated.
- Minor performance fix: time proofs have now a max sequencing timeout of 2 minutes and they no longer create a performance regression during synchronizer catch-up. Furthermore, synchronous rejects were not properly cleaned up by the sequencer client immediately after the reject was processed, but relied on the timeout logic to pick up the requests.
- Improved observability of indexer initialization (all related logs populated with a newly forged trace-context, terminating log-reporter upon failed ACHS initialization, additional WARN logs on failed ACHS initialization).
- Improved observability of Ledger API streaming (improved DEBUG log markers to of ID queries, DEBUG logging with timing information for payload queries).
- InternalIndexService streams improved with default retry/recovery and better observability.
- Database network timeout errors reported via error code
INDEX_DB_SQL_NETWORK_TIMEOUT_ERRORerror category changed toTransientServerFailuremaking it retryable. This problems logged on WARN log level. - The HTTP server now rejects too deeply nested json structures. The check uses the same values as the already existing gRPC check for nested daml records. This means that the Ledger JSON API client may now observe an error from HTTP (BadRequest) where previously the
INVALID_ARGUMENT/COMMAND_PREPROCESSING_FAILEDorINVALID_ARGUMENT/VALUE_NESTINGerror was returned. - The submitter does not have to be a stakeholder of all contracts during automatic reassignment, only of those that are actually reassigned to a target synchronizer. The previous check was considered too strict: it required the submitter to be a stakeholder of all involved contracts, even ones that were, for instance, disclosed contracts already on the target synchronizer.
- The HTTP server for the Ledger JSON API is now explicitly configured with a maximum content length. A new config option
http-ledger-api.max-inbound-message-sizehas been added. If not configured, the gRPC settingledger-api.max-inbound-message-sizewill be used. Previously, an implicit limit of 8 MB was used, so this change should not affect existing configurations. - The concurrency limit interceptor
ActiveRequestInterceptornow caches rejection responses instead of generating a new error (and thereby filling the stack trace) for each rejected response, once the concurrency limit is filled. - Onboarding party submission prevention: Ensures a participant does not submit a transaction or reassignment on behalf of an onboarding party.
- OpenAPI and AsyncAPI files are now included in the API archive, and the bundle is published as a Maven artifact on GAR.
- New metric to track the number of active stakeholder groups of a participant:
daml.participant.sync.commitments.active-stakeholder-groups <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.<canton-node>.replication.connection-pool.connection.max-inconclusive-read-only-checksis introduced that allows configuring the maximum number of inconclusive read-only checks before a connection is closed. The default value is 3.- Connection pool metrics:
- Add a
psidlabel, populated if it is provided when connecting. This should be the case starting from the second connection to a synchronizer, or upon LSU. - Close the
connection-healthandsubscription-healthmetrics associated to thepsidwhen the pool is closed, instead of closing all the existing ones when the pool is started.
- Add a
- Updated com.google.protobuf libs from 3.25.5 to 4.35.1
- A call to
AcknowledgeSignedwith a timestamp before the upgrade time returns immediately, without any acknowledgement being done. - The
ActAsAnyPartyaccess right has been added to the Ledger API. This allows a user to submit transactions on behalf of any party. This feature is intended for use cases where a user needs to act on behalf of multiple parties, such as in a multi-tenant environment. The new access right can be granted to the users only by a participant administrator either at user creation time or through theGrantAccessRightcommand. - The JSON Ledger API now rejects malformed identifiers (e.g. template-id) provided in requests (one that does not follow the
<package>:<moduleName>:<entityName>format) with a descriptive400 Bad Requesterror that names the expected format, instead of surfacing it as an internal error. - The JSON Ledger API now honours an optional, client-supplied
Request-Timeoutheader (value in milliseconds) that sets a per-request timeout. The value is validated against a configurable[lower-bound; upper-bound]window (defaulting to[1s; 60s]): values within the window are enforced as-is, values above, or below the lower bound, a non-positive value, or a non-numeric value is rejected with a descriptive400 Bad Request. When the header is absent, the server default request timeout applies unchanged. The window can be configured underhttp-ledger-api.client-request-timeout: - The default size of the Ledger API in-memory fan-out buffer (
<participant>.ledger-api.index-service.max-transactions-in-memory-fan-out-buffer-size) has been increased from 1000 to 1100 to accommodate serving ACS commitments from the buffer. - Health check service improvements:
livenessgRPC health check is now up and reporting asSERVINGbefore the database migrations are performed (when used withmigrate-and-start = true), to address the issue of k8s liveness probe failures during long-running migrations.- Mediators will report
readinessNOT_SERVINGwhenlivenessis alsoNOT_SERVING, where previously it was possible for a mediator to reportreadinessSERVINGwhilelivenesswasNOT_SERVING. - HTTP health checks now expose the
livenessandreadiness, under the URIs/health/livenessorhealth/liveand/health/readinessor/health/readyendpoints, respectively./healthis still available for backward compatibility, mapping toreadiness.
- Improved log trace correlation in the JSON Ledger API: package and health endpoints that previously logged with an empty trace context now propagate the caller’s
TraceContext. - Protocol messages now use Zstandard (
zstd) compression starting with protocol version 36, while earlier protocol versions continue to use gzip. This internal optimization is applied automatically and does not require configuration changes. - getLedgerEnd endpoint in StateService can now return latest observed record time for the requested synchronizers along with ledger end offset.
- Participant health state now includes indexer as a soft dependency. Indexer health state will be present in readiness endpoint response, but it won’t influece response code.
- Removed redundant root-hash signature from informee and encrypted view messages.
- participant_id label is added onto participant metrics
- Added
ErrorInfometadata to traffic enforcement rejections so callers don’t need to parse the message text.TRAFFIC_ACCOUNT_VALIDATION_FAILED:account_id,balance,traffic_costTRAFFIC_UPDATE_OUT_OF_BOUND:account_id,traffic_delta,delta_type
- Support for OTLP remote metrics reporting, including optional OAuth2 Client Credentials authentication
- AWS KMS keys created by Canton can now be configured with custom tags through the
custom-tagssetting. - The default of the indexer’s uncommitted-queue warning threshold (
<participant>.ledger-api.indexer.queue-uncommitted-warn-threshold) has been increased from 5000 to 14000. This threshold controls when theUncommitted queue is growing too largewarning is emitted. - Admin API streaming calls are now bounded to protect nodes from resource exhaustion:
- Their duration is capped by the new
<node>.parameters.processing-timeouts.admin-stream-open-boundvalue (default: 2 hours). - The number of concurrently open calls is capped per method (default: 10) via the admin server’s
limitsconfiguration.
- Their duration is capped by the new
- Changing identity providers for a party through
UpdatePartyDetailsis no longer possible,UpdatePartyIdentityProviderIdmust be used instead. - An internal change is introduced which grants
ReadAsAnyPartypermissions to the traffic enforcement service. This removes the need to use non-standard config options to run local traffic enforcement with auth enabled: - The participant admin party is now exempt from the traffic enforcement balance check during submission.
- Subview package vetting, checked at submission time, is now verified during confirmation request validation.
- Fixed the parsing of the
Sec-WebSocket-Protocolheader in the Ledger JSON API. As specified by RFC 6455, clients send the subprotocol values separated by a comma and a space (for exampledaml.ws.auth, jwt.token.<token>). Canton split the header on the comma only, so the leading space stayed attached to the following value and that value was silently discarded, making the request fail with anUNAUTHENTICATEDerror. The values are now trimmed, so such requests are accepted. - The Ledger API vetting endpoints are exposed in the Canton console:
- The Ledger API endpoint
PackageService.ListVettedPackagesis exposed asparticipant.ledger_api.packages.list_vetted_packages - The Ledger API endpoint
PackageManagementService.UpdateVettedPackagesis exposed asparticipant.ledger_api.packages.update_vetted_packages
- The Ledger API endpoint
- Added the request type to the sequencer cap rejection message.
PrefetchContractKeyhas a new optionallimitfield stating how many contracts to prefetch for that key, on top of disclosed contracts. Absence is interpreted as1(the previous behavior),0is rejected, and values are capped at2^31 - 1. The system may impose further limits.- Commands referencing a contract ID whose Canton contract ID version is not supported (for example a malformed or foreign-format ID, including via a disclosed contract) are now rejected with
UNSUPPORTED_CONTRACT_ID(gRPCNOT_FOUND), carrying the contract ID as an error resource. Previously this path raised an internal error. The same applies to contract key lookups resolving to such a contract. canton.participants.<participant>.parameters.engine.transaction-limitsbounds what the engine may produce during interpretation (value-size,node-children,transaction-nodes,total-informees, and others). All bounds default to their maximum, so the default behavior is unchanged.- The
nonemptyandbase-validationlibraries are now published to Maven Central. - The docker da-base-image has been bumped to 1.0.15 to fix an issue with bash in certain kubernetes environments.
- Sequencer: fixed the V2 sequencer initialization endpoints (
InitializeSequencerFromGenesisStateV2,InitializeSequencerFromLsuPredecessor,InitializeSequencerFromOnboardingStateV2) failing when the uploaded state exceeded 2GB, the maximum size of a single protobufByteString. - Parsing of protobuf messages carrying an unknown version number is now failing.
- Participant: fixed the memory growth during ACS import caused by the repair indexer keeping all imported contract activations in an in-memory cache until the end of the import.
Compatibility
The following Canton protocol versions are supported:
Canton has been tested against the following versions of its dependencies: