Canton 3.4 Release Notes for Splice 0.5.0

author by Curtis Hrischuk November 11, 2025

Share this article

The Canton 3.4 release notes for Splice 0.5.0 are provided below. The CIP-0089 has the motivation for the release. The high-level structure of the release notes are:

The content here is focussed on Canton updates. For Splice related changes, please refer to the Splice Release Notes

Introduction

The new release of Canton 3.4 has several goals:

  • To support Splice features.
  • Improved scaling across multiple dimensions.
  • Enhanced security.
  • Additional support for multi-synchronizer applications.
  • Traffic cost estimation.
  • Preparation to simplify Canton protocol upgrades using logical synchronizer upgrades.
  • Additional small improvements.

Although much of the discussion is about the Canton Network or Splice, many of the improvements will be relevant to application developers for private synchronizer or multi-synchronizer applications. However, deploying private synchronizer or multi-synchronizer applications to production is recommended for a future Canton release.

Impact and Migration Overview

There are two types of application updates discussed in this blog post. 

  • enhancements: This is the majority of changes which introduce new capabilities.
  • changes: These are changes to existing features (e.g., backwards compatible behavioral changes, breaking changes, etc.). 

For easier navigation, the changes are called out in a separate subsections and the links are below:

As a result of ongoing security audits, several default configuration values have changed for increased security out of the box. Of course, it is possible to revert these values to the 3.3 value through a configuration parameter.

Daml Language and SDK

Daml Language and IDE 

Changes

Creating a contract by interface no longer computes the interface view. Thus if the computation of the view throws an error then it is no longer thrown when creating a contract by interface. This aligns the behavior of the create_interface builtin with that of fetch_interface, exercise_interface, and to_interface.

unsafeFromInterface is marked as deprecated and throws an error during interpretation.

To ensure consistency between the Ledger API and Daml models, the computation of an interface view now checks that the view is serializable (i.e. does not contain non-serializable types and is not too deeply nested). If the view is not serializable then an error is thrown. 

The evaluation order of foldr has been changed to match the evaluation order one would observe if foldr was defined with this daml function rather than as a primitive:

foldr f z [] = z

foldr f z (x::xs) = f x (foldr f z xs)

This change only affects usages of foldr in which f throws an error after being partially applied to its first argument.

fromHex now returns None for inputs that do not generate valid UTF-8 strings. This ensures that fromHex x == Some y implies toHex y == x.

Fixed a Daml Studio issue whereby some SCU errors were previously reported as <missing error details> in the transaction view.

Fixed an issue with Daml Studio and daml test in which queryInterface @I did not return contracts upgraded with an instance of the I interface.

Fixed a smart contract upgrade error message in the compiler in which the package IDs of the upgraded package and its upgrade were flipped.

The deprecated @daml/ledger and @daml/react typescript libraries are no longer distributed with Canton 3.4.

The deprecated com.daml/bindings-rxjava library is no longer distributed with Canton 3.4.

You can expect the existing .dar files of applications to continue to work given that the above changes affect corner cases of the language runtime. We recommend migrating Daml code that requires changes by first recompiling it using the 3.4 Daml SDK and rolling out the new .dar files using Smart Contract Upgrading.

Daml Assistant and dpm

Digital Asset Package Manager (dpm) is a new command-line tool that does a lot of useful things for developing dApps with the Canton SDK. Using dpm, you have a tool for your local environment to: build the dApp, generate Java and Typescript code for Daml classes, test local deployment with sandbox, and use PQS and daml shell.

From version 3.4.x onwards, dpm is the preferred CLI tool for a local development experience. If you start a new project on 3.4, or migrate your 3.3 daml project to 3.4, we recommend using dpm. Currently, dpm does not support Canton 3.3 projects. A summary of dpm's features are listed here.

As a result of the introduction of dpm, the Daml Assistant (daml) is deprecated as of version 3.4, but still can be used to work with 3.3 and 3.4 daml projects. If you will be running your 3.3 project as is, and will migrate to 3.4 at a later date, you can continue to use Daml Assistant.

Here is a comparison of dpm with the daml which can help in migrating to dpm. In general, the command set is 1-1.

Further details available from:

Code Generation

The TypeScript codegen has been changed to produce interface definitions that use package names rather than package IDs. The following definition:

exports.Token = damlTypes.assembleInterface(
 '41d34898b0a96f443eef3fa59e0ca61465caa5e1c2ca24ecb8e7de5e1ba611f5:Main:Token',
  function () { return exports.EmptyInterfaceView; },
  {

becomes:

exports.Token = damlTypes.assembleInterface(
  '#tokens:Main:Token',
  function () { return exports.EmptyInterfaceView; },
  {

Please refer to the section Identifier Addressing by-package-name for more details.

Daml Script

There were several changes to UpgradeErrorType

  • The DowngradeFailed, ViewMismatch and DowngradeDropDefinedField upgrade error variants have been removed. The daml-script interpreter will fail to run legacy DARs which use these variants. They are replaced by a new, more generic TranslationFailed variant. Recompiling the Daml code for these legacy .dars is all that’s required to migrate it. 
  • The signature of ValidationFailed has been changed to include more information. 
  • A new AuthenticationFailed variant has been added to denote contract ID authentication errors occurring during contract upgrading.

allocatePartyWithHint and allocatePartyWithHintOn are deprecated and replaced with allocatePartyByHint : PartyIdHint -> Script Party and allocatePartyByHintOn : PartyIdHint -> ParticipantName -> Script Party to reflect the removal of party display names in Canton.

Introduced tryFailureStatus : (HasCallStack => Script a) -> Script (Either FailureStatus a) which allows daml-script tests to observe and act on failures raised during command interpretation.

Cryptographic Primitives

The Canton 3.4 release also introduces Early Access (Alpha) Daml language support for verifying cryptographic signatures. Thereby making it easier to build Daml workflows that bridge between Canton Network and other blockchains. These cryptographic primitives are useful for building bridges or wrapping tokens.

  • Cryptography primitives: keccak256 and secp256k1
  • Introduced sha256 in DA.Crypto.Text. Computes the SHA256 hash of the decoded UTF8 bytes of the hex string, and returns it in its hex-encoded form. The hex encoding uses lowercase letters.
  • BytesHex support (for base 16 encoded byte strings): isHex, byteCount, packHexBytes and sliceHexBytes
  • Bytes32Hex support: isBytes32Hex, minBytes32Hex and maxBytes32Hex
  • UInt32Hex support: isUInt32Hex, minUInt32Hex and maxUInt32Hex
  • UInt64Hex support: isUInt64Hex, minUInt64Hex and maxUInt64Hex
  • UInt256Hex support: isUInt256Hex, minUInt256Hex and maxUInt256Hex
  • Daml data type BytesHex support via type classes HasToHex and HasFromHex
  • Introduced secp256k1WithEcdsaOnly in DA.Crypto.Text which is the same as secp256k1 with no preliminary sha-256 hashing of the message.
  • Introduced -Wno-crypto-text-is-alpha flag to disable warnings about crypto primitives being early access.

Daml Compiler

The daml compiler now provides a consistent flag syntax for disabling warnings and errors and promoting warnings to errors. See the documentation.

Canton Ledger API

JSON and gRPC Ledger API

The JSON Ledger API v2 was introduced in Canton 3.3 and is the supported JSON Ledger API version going forward. The JSON Ledger API v1 was deprecated in Canton 3.3 and is removed in this release. The migration details for v1 are available in "HTTP JSON API Migration to V2 guide". Please note @daml/ledger was for JSON Ledger API v1 so it will no longer work. The rest of this document is about changes to JSON Ledger API v2 since Canton 3.3.

General Enhancements

The JSON Ledger API configuration was simplified. Now the address, port, portFile, pathPrefix, as well as requestTimeout are set directly using the config parameter http-ledger-api like so:

canton.participants.<participant>.http-ledger-api.port=5555

instead of

canton.participants.<participant>.http-ledger-api.server.port=5555

The old configuration paths continue to be supported in 3.4.0, so this is backwards compatible.

The user can now self-administer using new LAPI endpoints. Using the LAPI, a user can now:

  • Query the details of any the party it has any right to operate (ReadAs, ActAs, ExecuteAs or wildcard forms thereof)
    • gRPC: PartyManagementService.getParties
    • JSON: GET /v2/parties/{party-id}
  • Query their own user record
    • gRPC: UserManagementService.getUser
    • JSON: GET /v2/users/{user-id}
  • Query their own rights
    • gRPC: UserManagementService.listUserRights
    • JSON: GET /v2/users/{user-id}/rights
  • Get the current user details
    • JSON: GET /v2/authenticated-user
  • The existing InteractiveSubmissionService.GetPreferredPackageVersion (gRPC) or interactive-submission/preferred-package-version (JSON) functionality is superseded by a new endpoint pair:
    • gRPC: InteractiveSubmissionService.GetPreferredPackages
    • JSON: GET /v2/interactive-submission/preferred-package-version 

The existing endpoints are deprecated but preserved for backwards compatibility.

  • Introduced /v2/dars/validate JSON API endpoint to validate DAR files without uploading them, mirroring the gRPC PackageManagementService.ValidateDarFile endpoint. 
    • gRPC: PackageManagementService.ValidateDarFile
    • JSON: POST /v2/dars/validate
  • Allocate their own party
    • gRPC: PartyManagementService.allocateParty
    • JSON: POST /v2/parties

The users can self-allocate parties only if the number of parties listed in the user’s rights does not exceed the value defined in a configuration parameter:

canton.participants.<participant-id>.ledger-api.party-management-service.max-self-allocated-parties = <N>

To be able to allocate their own party, the participant needs a configuration change because the default is a user cannot allocate any parties (default value of 0).

The GetConnectedSynchronizers command now can be accessed either with ReadAs, Admin or IDPAdmin permissions. As a result, the gRPC command also now has an optional identityProviderId field.

The HTTP connection timeout is configurable in the JSON Ledger API via canton.participants.<participant-id>.http-ledger-api.server.request-timeout=<duration>. Configure this value to allow more complex Ledger API requests to complete (e.g. /state/active-contracts). The default value is 20 seconds.

A configuration parameter has been added for the size of the inbound metadata on the Ledger API. Changing this value allows the server to accept larger JWT tokens. canton.participants.participant.ledger-api.max-inbound-metadata-size=10240

Security Enhancements

The gRPC Admin API IDP configuration service has changed. Authorization of the calls made by the IDP Admins has been tightened. It is no longer possible for them to grant rights to parties which are in other IDPs or in no IDP. This effectively enforces keeping the IDP Admins within their respective IDP scope. Participant Admins can still grant the rights that cross the IDP box boundaries e.g. a User in "IDP A" can be given a right to a party authorized by "IDP B".

NOTE: Below is a set of default configuration changes for the Canton participant node itself. For backwards compatibility, the Canton Network validator sets these values to be the same as the Splice 0.4.x release so there is no impact to a validator.

The default security configuration of the APIs has been tightened. The maximum token lifetime accepted by the Ledger API (gRPC and JSON) and Admin API has been reduced. This change requires using tokens with an exp field set which was not required before. Tokens which have time to live longer than 5 minutes will not be accepted by default. However, this default value can be changed through:

canton.participants.<participant>.ledger-api.max-token-lifetime=10.minutes

and

canton.participants.<participant>.admin-api.max-token-lifetime=10.minutes

This default timeout can be turned off completely by those who use simplified authorization (for instance utilizing HMAC) by doing:

canton.participants.<participant>.ledger-api.max-token-lifetime=Inf

Correspondingly, the JWKS cache expiration has been reduced to a default of 5 minutes. A JWKS key will be evicted from the cache after that time and the participant will access the JWKS address again to pull the fresh keys. You can modify this behavior by setting

canton.participants.<participant>.ledger-api.jwks-cache-config.cache-expiration=10.minutes

and

canton.participants.<participant>.admin-api.jwks-cache-config.cache-expiration=10.minutes

By default, the Canton Admin Tokens no longer entitle the bearer to operate as a ParticipantAdmin nor to ActAs any party. This behavior can be altered by setting

canton.participants.<participant>.ledger-api.admin-token-config.act-as-any-party-claim=true

and

canton.participants.<participant>.ledger-api.admin-token-config.admin-claim=true

The key for configuration-stored, fixed admin tokens has changed. Previously, the setting of the admin token string was possible through Ledger API or Admin API configuration like so:

canton.participants.<participant-id>.ledger-api.admin-token="<your-token>"

or

canton.participants.<participant-id>.admin-api.admin-token="<your-token>"

Now, it is set through canton.participants.<participant-id>.ledger-api.admin-token-config.fixed-admin-token="<your-token>"

or

canton.participants.<participant-id>.admin-api.admin-token-config.fixed-admin-token="<your-token>"

Other parameters of the admin token can also be set through the AdminTokenConfig configuration as seen below:

canton {
  participants {
    <participant-id> {
      ledger-api {
        admin-token-config {
          fixed-admin-token = <your-token>
          admin-token-duration = 30.minutes
          act-as-any-party-claim = true
          admin-claim = true
        }
      }
    }
  }
}

The fixedAdminToken acts as the adminToken did in Canton 3.3 where it defines a token that is valid throughout the entire canton process lifespan. It is only meant for testing purposes and should not be used in production.

Other admin-tokens will be generated and rotated periodically for internal usage (e.g. in the console). They are invisible from the outside. Each admin-token of these is valid for the defined adminTokenDuration. The half of the token duration is used as the rotation interval, after which a new admin-token is generated (if needed) and used. The default value for the token duration is 5 minutes.

Setting the actAsAnyPartyClaim to true allows usage of the admin-token to authorize acting-as and reading-as any party in the participant. Similarly, setting the adminClaim to true allows usage of the admin-token to authorize any admin level operation in the participant. Setting these parameters to true is consistent with the past system behavior. The default values have been changed to false in the 3.4 release to increase default system security. So, the admin-token by default is only strong enough to issue pings.

Changes

gRPC and JSON API payloads for create events (create arguments, interface views, etc.) are now rendered using the normal form of the types defined in CreatedEvent.representative_package_id. This should be transparent on the returned values, with the exception of the record-ids in Ledger API verbose rendering (verbose = true) which now effectively reflect the representative package id as well.

A DAR is said to be self-consistent if the set of packages it contains is exactly the same as the set of packages used or imported by its main package. UploadDarFile now generates an error for DARs compiled in 3.4 that are not self-consistent, and emits a warning for older DARS that are not self-consistent. The error for newly compiled DARs can be downgraded to a warning by setting the enableStrictDarValidation config flag to false.

UploadDarFile now rejects packages that contain unknown protocol buffer fields. This change does not affect DARs generated with damlc.

The legacy gRPC Ledger API method CommandService.SubmitAndWaitForTransactionTree has been removed. Note that the JSON API version of this request /v2/commands/submit-and-wait-for-transaction-tree continues to be supported in 3.4 (marked as deprecated), but will be removed in 3.5. 

The following legacy gRPC Ledger API methods in the UpdateService have been removed:

  • GetUpdateTrees
  • GetTransactionTreeByOffset
  • GetTransactionTreeById
  • GetTransactionByOffset
  • GetTransactionById

The JSON versions of the removed UpdateService requests continue to be supported in 3.4 (marked as deprecated), but will be removed in 3.5.

  • /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

The configuration for the removed Ledger API transaction tree stream related methods have been removed as well

canton.participants.<participant>.ledger-api.index-service.transaction-tree-streams.*

The SubscribeTrees and SubscribeFlat Ledger API commands were removed. The SubscribeUpdates should be used instead.

The SubmitAndWaitTransactionTree Ledger API command was removed. The SubmitAndWaitTransaction should be used instead.

The GetTransactionById and GetTransactionByOffset Ledger API commands were removed. The GetUpdateById should be used instead.

The legacy gRPC Ledger API message TransactionFilter has been removed. As a consequence, the filter field has been dropped from the top level GetUpdatesRequest and GetActiveContractsRequest messages. 

Likewise, the verbose field has been dropped from the top level GetUpdatesRequest and GetActiveContractsRequest messages. As before, the verbosity can be controlled through the EventFormat message. Its effect has been changed:

  • In non-verbose mode event rendering of Ledger API queries, trailing Optional record fields that are not populated are no longer included in the Record representation. The reason for this is so that the same structural representation is produced independently of the package version that was used to enrich it.
  • In verbose mode reporting, record values will no longer contain trailing Optional fields that have a value of None. The reason for this is so that the same structural representation is produced independently of the package version that was used to enrich it.

The JSON versions of the above gRPC messages continue to be supported in their old format. They will be removed in 3.5. This affects:

  • TransactionFilter will be removed in 3.5
  • GetUpdatesRequest will be altered in 3.5, it is used in
    • /v2/updates HTTP POST and websocket GET endpoints
    • /v2/updates/flats HTTP POST and websocket GET endpoints
    • /v2/updates/trees HTTP POST and websocket GET endpoints
  • GetActiveContractsRequest will be altered in 3.5, it is used in
    • /v2/state/active-contracts HTTP POST and websocket GET endpoints

These JSON API enum types are now encoded as strings:

  • HashingSchemeVersion
  • PackageStatus
  • ParticipantPermission
  • SigningAlgorithmSpec
  • SignatureFormat
  • TransactionShape

Corrected the HTTP verb for the JSON Ledger API endpoint interactive-submission/preferred-packages from GET to POST.

Removed the deprecated requesting_parties field from the GetEventsByContractIdRequest message in the Ledger API. Clients should use the event_format field instead, as described in "HTTP JSON API Migration to V2 guide".

A default value is provided for the transaction_format field inside of SubmitAndWaitForTransactionRequest. You can now omit this field in both gRPC and JSON requests, and get behavior consistent with the 3.2 version of Canton. This means you will receive a flat transaction with event visibility dictated by all act_as and read_as parties.

DisclosedContract.template_id and DisclosedContract.contract_id for Ledger API commands are not required anymore. When provided, the fields are used for validation of the analogous fields in the encoded created event blob.

The non-verbose mode of the Ledger API no longer renders trailing None fields in contracts and records. This only affects contracts created with a version of Canton strictly older than 3.3 as Canton 3.3 contracts are stripped of their trailing None fields already. Since clients of Canton 3.3 had to handle missing trailing Nones already, we do not expect this change to cause any disruption.

The INTERPRETATION_UPGRADE_ERROR_DOWNGRADE_DROP_DEFINED_FIELD and INTERPRETATION_UPGRADE_ERROR_DOWNGRADE_FAILED error codes no longer exist and have been replaced with the more general INTERPRETATION_UPGRADE_ERROR_TRANSLATION_FAILED error codes.

The metadata of the INTERPRETATION_UPGRADE_ERROR_VALIDATION_FAILED error now contains more information and its ordering has changed.

A new INTERPRETATION_UPGRADE_ERROR_AUTHENTICATION_FAILED error code has been added to denote contract ID authentication errors occurring during contract upgrading.

There have been some updates to the OpenAPI specification:

  • Any renamed as ProtoAny
  • Event1 renamed to TopologyEvent
  • Fixed Field, FieldMask,JsReassignmentEvent mappings.
  • Fixed documentation for: Completion/Completion1 (status property), ParticipantAuthorizationAdded, ParticipantAuthorizationChanged,ParticipantAuthorizationRevoked

Identifier Addressing by-package-name

In Canton 3.3, Smart Contract Upgrade supported two formats for specifying interface and template identifiers to the Ledger API. They are:

  • package-name reference format which uses the package name as the root identifier, such as #<package-name>:<module>:<entity>. This was introduced with the Smart Contract Upgrade feature..
  • package-id reference format which uses the package-id that has the format <package-id>:<module>:<entity>

The package-id reference format will not be supported in Splice 0.6.0 / Canton 3.5. Applications must switch to using the package-name reference format for all requests submitted to the Ledger API (commands and queries). A warning message will be logged if the package-id format is used, as the system internally converts it to the corresponding package-name format and resolves the query by package-name and not by package-id.

Interactive Submission

Externally signed transactions are an important feature, which has been improved in the following ways:

  • Traffic cost estimate: The PrepareSubmission endpoint of the InteractiveSubmissionService on the Ledger API now returns an estimation of the traffic cost that will be incurred by the submitting participant when submitting the transaction to the synchronizer. 
  • Blocking requests: New blocking endpoints allow executing a prepared transaction and block for its result which simplifies application development and offers now the same functionality as for regular command submission. The InteractiveSubmissionService now offers two additional endpoints: 
    • ExecuteSubmissionAndWait and POST /v2/interactive-submission/executeAndWait
    • ExecuteSubmissionAndWaitForTransaction and POST /v2/interactive-submission/executeAndWaitForTransaction

Refer to the API documentation for details.

Universal Event Streams

Universal Event Streams were introduced in Canton 3.3 to allow a user to subscribe to ledger events and receive a complete view as a flat transaction stream or a transaction tree stream, while providing additional filtering and formatting capabilities. There are several enhancements:

  • Contract arguments for Created events are now always populated for both LedgerEffects and AcsDelta shaped events if there is a party in the filter that is in the witness parties of the event or a party-wildcard filter is defined.
  • Created and exercised events in AcsDelta transactions now include a flag indicating whether this event would be part of the respective ACS_DELTA shaped stream, and should therefore be considered when tracking contract activeness on the client-side. This way clients with LedgerEffects subscriptions are enabled to track contract lifecycle. The Java bindings and the JSON API messages have been extended accordingly.
  • Transactions with transient events for which there was an intersection between submitters and querying parties were previously exposed as transactions with empty events in AcsDelta shape. Those transactions will no longer be exposed at all in the AcsDelta shape. As before, they will still be exposed in the LedgerEffects shape.
  • Participant divulgence (i.e. if there is a party divulgence, and none of the stakeholders of the divulged contracts are hosted on the validator) is no longer performed in Active Contracts Service and AcsDelta transaction shapes.

Canton Network Application Quick Start

There were several enhancements to the application Quick Start since the release of Canton 3.3. They are:

  • Reworked the example application to use the CIP-0056 token standard APIs.
  • Reduced the memory use for running LocalNet by 70%.
  • Users no longer need Artifactory access as the Docker images are publicly accessible.
  • Added YouTube videos to make it easier to install and use the sample application.
  • Added Debugging and troubleshooting with lnav documentation
  • The end-to-end integration test was reworked.

The Canton Platform

Package Vetting and Unvetting

Enhancements

Canton 3.4 relaxes the need for a validator to upload the history of DARs of a dApp. Now, only the latest package version of a dApp needs to be loaded. Previously, when a dApp had multiple package versions the entire package version lineage needed to be uploaded to a validator.

This also simplifies importing an ACS for a new validator because there is no longer the need to load the entire version lineage of a package even if contracts in the ACS were originally created with older package versions. This reduces memory use on the validator.

Package unvetting is now a production-supported operation. When a package is discovered to be faulty or need to be deprecated for other reasons, the operation to "unvet" a package is now fully supported, such that this package can no longer be used on the ledger. Unvetting a package-id referenced by an active contract is not dangerous anymore provided there's another compatible package vetted (the same package-name but with a higher package-version than the unvetted package). If a package is mistakenly unvetted, it can be restored by simply re-vetting the package.

The package vetting and unvetting enhancements are:

  • Add new Ledger API endpoints to improve the UX of package vetting:
    • ListVettedPackages in package_service.proto (gRPC Ledger API) or GET /v2/package-vetting (JSON Ledger API) to easily list which packages are vetted. A current limitation of the ListVettedPackages endpoint is that it is eventually consistent such that the latest vetting state is returned but that state may not have completed internal processing but will be effective shortly.
    • UpdateVettedPackages in package_management_service.proto (gRPC Ledger API) or POST /v2/package-vetting (JSON Ledger API), to easily vet and unvet packages.
  • Modify UploadDarFileRequest in package_management_service.proto to take a vetting_change attribute, which specifies whether the uploaded DAR should be vetted or not.
  • Added support for vetting packages on specific synchronizers, if the participant is connected to multiple synchronizer, by adding an optional synchronizer_id field to the following messages (see Logical Synchronizer Upgrades for more information):
    • ValidateDarRequest, UploadDarRequest, VetDarRequest, and UnvetDarRequest in the Admin API
    • In the Ledger API:
      • UploadDarFileRequest and POST/v2/dars
      • ValidateDarFileRequest and POST /v2/dars/validate
      •  UpdateVettedPackagesRequest and POST /v2/package-vetting
    • These requests no longer use AuthorizedStore for vetting changes, they must specify a target synchronizer via the new synchronizer_id fields if the target validator is connected to more than one synchronizer.
  • Unvetting a package that is used as a dependency by another vetted package now requires FORCE_FLAG_ALLOW_UNVETTED_DEPENDENCIES. It should only be used in case there is a problem with the vetted package dependency check being faulty.
  • Add FORCE_FLAG_ALLOW_VET_INCOMPATIBLE_UPGRADES in topology manager write service. It allows vetting packages that are upgrade incompatible.

The PackageManagementService.UpdateVettedPackages (JSON POST /v2/package-vetting) request is extended with the UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_VET_INCOMPATIBLE_UPGRADES force flag to allow vetting packages that are upgrade incompatible. This should only be used in very rare cases where the upgrade check incorrectly fails and generally should not be used in combination with contracts already created in Canton 3.3.

PackageManagementService.UpdateVettedPackages request is extended with the UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_UNVETTED_DEPENDENCIES force flag to allow vetting packages without vetting one or more of their dependencies.

Changes

Removed force flag FORCE_FLAG_ALLOW_UNVET_PACKAGE and topology manager error TOPOLOGY_DANGEROUS_VETTING_COMMAND_REQUIRES_FORCE_FLAG

Removed force flag FORCE_FLAG_ALLOW_UNVET_PACKAGE_WITH_ACTIVE_CONTRACTS

The VettedPackage validFrom and validUntil fields have been renamed to validFromInclusive and validFromExclusive.

The package upgrade validation is moved to vetting state change. Thus uploading an upgrade-incompatible DAR with vetting disabled is now possible. Related error codes changed:

  • DAR_NOT_VALID_UPGRADE is renamed NOT_VALID_UPGRADE_PACKAGE
  • KNOWN_DAR_VERSION is renamed KNOWN_PACKAGE_VERSION

Scale and Performance

Many improvements have been delivered to improve scale and performance, including more efficient processing in various components of the system, configure explicit rate limits to prevent overload, improve the ledger api indexing schema, and reduce the size of the topology state. Some of these changes were backported to Canton 3.3 and are currently operational. A summary of the improvements is:

  • Rate limiting and throttling of Sequencer APIs to prevent CPU, database, and memory from becoming overloaded.
  • Database caching and query optimizations.
  • Sequencer processing improvements, including asynchronous database writes that remove sequential bottlenecks on the read path.
  • Topology caching and processing improvements, including a reduction of time proofs and more efficient topology broadcast.
  • ACS commitment processing improvements.
  • Improved topology state validation and BFT read validation of the initial topology state, enabling faster onboarding for validators to the network while preserving integrity.
  • Other enhancements that reduce the amount of topology state that a validator needs to hold.

Topology Management

Enhancements

The PartyToParticipant topology mapping has been enhanced to allow external parties to reference the protocol signing public keys and signing threshold they wish to use to authorize transactions. This effectively replaces the functionality provided by the PartyToKeyMapping, which is now deprecated. 

Upgrades of participant permissions in the PartyToParticipant mapping now require the authorization of both the party and respective participant admin. For backwards compatibility, existing transactions in the genesis block do NOT require the authorization of participants for permission upgrades.

Additionally, when one of the signing keys in the PartyToParticipant is also the party’s namespace key, it can be used to “self-sign” the transaction, removing the need for a separate root NamespaceDelegation registering the party’s root namespace key, and thereby allowing a single topology transaction to onboard an external party.

There is now a configurable timeout when waiting to observe the submitted topology transactions. A warning is logged when the timeout occurs and the transaction dispatching will be retried. Additionally, the delay between retries of the topology dispatching loop has been made configurable.

participants.participant1.topology.topology-transaction-observation-timeout = 30s // default value

participants.participant1.topology.broadcast-retry-delay = 10s // default value

mediators.mediator1.topology.topology-transaction-observation-timeout = 30s // default value

mediators.mediator1.topology.broadcast-retry-delay = 10s // default value

sequencers.sequencer1.topology.topology-transaction-observation-timeout = 30s // default value

sequencers.sequencer1.topology.broadcast-retry-delay = 10s // default value

The topology message queue now supports backpressure. This means that topology requests will start to be rejected if the topology message queue is full. The size of the message queue can be configured via canton.<type>.<name>.topology.max-unsent-topology-queue-size = 100 (default).

The number of keys per node or external party are not restricted to a maximum of 20 keys.

Changes

The new party allocation endpoints above come with a copy/replace change for users of the gRPC InteractiveSubmissionService used in external signing workflows. The following protobuf messages have been refactored to a new common protobuf package so they can be re-used across different services. To consume these changes, re-generate any client code using the new protobuf definitions and update the package names accordingly in your application code.

 

The file and FQN changes are:

  • File from com/daml/ledger/api/v2/interactive/interactive_submission_service.proto to com/daml/ledger/api/v2/crypto.proto
    • FQN from  com.daml.ledger.api.v2.interactive.Signature to com.daml.ledger.api.v2.Signature
    • FQN from com.daml.ledger.api.v2.interactive.SigningAlgorithmSpec to com.daml.ledger.api.v2.SigningAlgorithmSpec
  • File from com/daml/ledger/api/v2/interactive/interactive_submission_service.proto to com/daml/ledger/api/v2/crypto.proto
    • FQN from com.daml.ledger.api.v2.interactive.SignatureFormat to com.daml.ledger.api.v2.SignatureFormat

To avoid confusion, the field submission_time for interactive submissions is now called preparation_time. A similar change is that the dynamic domain parameter submission_time_record_time_tolerance is now called preparation_time_record_time_tolerance.

The error codes LOCAL_VERDICT_SUBMISSION_TIME_OUT_OF_BOUND and TOPOLOGY_INCREASE_OF_SUBMISSION_TIME_TOLERANCE are now called LOCAL_VERDICT_PREPARATION_TIME_OUT_OF_BOUND and TOPOLOGY_INCREASE_OF_PREPARATION_TIME_TOLERANCE. Correspondingly, the console commands set_submission_time_record_time_tolerance is now called set_preparation_time_record_time_tolerance.

The console commands for OwnerToKeyMapping (OTK) and PartyToKeyMapping (PTK) have been changed to accept the factory method parameters instead of OTK and PTK values directly. 

Synchronizer owners are implicitly authorized to REMOVE any topology transaction on the synchronizer, even if they are not the "normal" authorizers. As a consequence, the unused topology mapping PurgeTopologyTransaction has been removed from the code base.

Committed NamespaceDelegation transactions with the Remove operations cannot be re-created with a Replace operation anymore.

ACS Export/Import

Enhancements

Added a new, party replication focused ExportPartyAcs endpoint to party_management_service.proto. This endpoint finds the correct ledger offset (party activation on the target participant) and excludes active contracts from the export which have stakeholders that are already hosted on the target participant (contract duplication prevention).

Adds the capability to exclude contracts that have some stakeholders in ExportAcs and ImportAcs endpoints (participant_repair_service.proto).

The participant node Admin API PartyManagementService.ImportPartyAcs endpoint has the request enriched with:

  • The representative_package_id_override field which allows overriding the original package id of the imported contracts.
  • The contract_import_mode field which allows toggling the contract import mode (no validation OR full contract and contract-id validation OR contract-id recomputation) for the imported contracts.

The representative_package_id_override is introduced to allow overriding the original package id of the imported contracts. This allows the target participant to use a compatible alternative package for the contract without needing to upload original contract packages.

Changes

ParticipantRepairService.ExportAcsOld is deprecated.

ParticipantRepairService.ImportAcs is updated.

The ImportAcsRequest.contract_id_suffix_recomputation_mode is renamed to ImportAcsRequest.contract_import_mode and ContractIdSuffixRecomputationMode enum is renamed to ImportAcsRequest.ContractImportMode to better reflect its purpose. Upon import, contracts can be fully validated (including contract-id suffix recomputation).

The ExportAcs endpoint was moved from party_management_service.proto to participant_repair_service.proto. Note that endpoint does not return retriable error(s) since ACS export is defined by the ledger offset.

Removed contractSynchronizerRenames on ACS import legacy.

KMS / Crypto

The GCP KMS driver now supports the Ed25519 scheme for signing.

Updated the KMS driver to support the Ed25519 scheme for signing and EciesHkdfHmacSha256Aes128Cbc for encryption. To enable this, the drivers must be recompiled.

Support for the ecies-hkdf-hmac-sha-256-aes-128-gcm encryption algorithm specification has been removed. Use ecies-hkdf-hmac-sha-256-aes-128-cbc instead.

Canton Console

The console command connect_local_bft now takes a list of SequencerReference instead of a NonEmpty[Map[SequencerAlias, SequencerReference]].

Changes

The console commands ledger_api.users.rights.grant and ledger_api.users.rights.revoke have been changed to return the complete state of current rights assigned to a user instead of the "delta" induced by the command.

The following canton console commands have been removed:

  • ledger_api.updates.{trees, flat}
  • ledger_api.updates.{trees_with_tx_filter, flat_with_tx_filter}
  • ledger_api.updates.{subscribe_trees, subscribe_flat}
  • ledger_api.updates.{by_id, by_offset}
  • ledger_api.commands.submit_flat
  • ledger_api.javaapi.updates.{trees, flat}
  • ledger_api.javaapi.updates.flat_with_tx_filter
  • ledger_api.javaapi.commands.submit_flat

The following canton console commands have been added:

  • ledger_api.updates.updates
  • ledger_api.updates.{transactions, reassignments, topology_transactions}
  • ledger_api.updates.transactions_with_tx_format
  • ledger_api.updates.subscribe_updates
  • ledger_api.javaapi.updates.transactions
  • Ledger_api.javaapi.updates.transactions_with_tx_format

For more info on how to migrate follow the console commands migration guide.

New Canton Docker Images

New docker images for Canton nodes are now published to europe-docker.pkg.dev/da-images/public/docker and include:

  • canton-participant: for a participant node
  • canton-mediator: for a mediator node
  • canton-sequencer: for a sequencer node
  • canton-base: a minimal Canton base image without pre-configuration

Logical Synchronizer Upgrades

Canton 3.4 introduces the preview feature, for testing purposes, of "logical synchronizer upgrades" (LSU), which reduces downtime and operational complexity for protocol version upgrades, as well as supporting data continuity for history across upgrades. This preview feature is for testing purposes only and should not be run in production (yet).

In order to support logical synchronizer upgrades, console commands and admin API endpoints now need to distinguish between logical and physical synchronizer ids:

  • Changed the protobuf definition of the admin API StoreId.Synchronizer from just having a string id field to the following:

    message Synchronizer {
      oneof kind {
        string logical = 1;
        string physical = 2;
      }
    }

  • Some console commands now take TopologyStoreId.Synchronizer instead of SynchronizerId as parameter. This should be non-breaking,because there are implicit conversions from SynchronizerId and PhysicalSynchronizerId to TopologyStoreId.Synchronizer.
  • The synchronizers.id_of console command now returns the SynchronizerId instead of a PhysicalSynchronizerId. Another command synchronizers.physical_id_of has been added to return the PhysicalSynchronizerId.

Protobuf changes:

  • SynchronizerConnectivityService.GetSynchronizerIdResponse.synchronizer_id changed to physical_synchronizer_id
  • SequencerConnectService.GetSynchronizerIdResponse.synchronizer_id changed to physical_synchronizer_id
  • MediatorStatusService.MediatorStatusResponse.MediatorStatusResponseStatus.synchronizer_id changed to physical_synchronizer_id
  • SequencerStatusService.SequencerStatusResponse.SequencerStatusResponseStatus.synchronizer_id changed to physical_synchronizer_id
  • ListConnectedSynchronizersResult.synchronizerId renamed to physicalSynchronizerId

Monitoring Enhancements

The OpenTelemetry (OTLP) trace export configuration has been extended with several new parameters allowing connection to OTLP servers, which require more elaborate set-up:

  • trustCollectionPath should point to a valid CA certificate file. When selected a TLS connection is created instead of an open-text one.
  • additionalHeaders allows specifying key-value pairs that are added to the HTTP2 headers on all trace exporting calls to the OTLP server.
  • timeout sets the maximum time to wait for the collector to process an exported batch of spans. If unset, defaults to 10s.
  • connectTimeout sets the maximum time to wait for new connections to be established. If unset, defaults to 10s.

Multi-Synchronizer Support

Enhancements were made towards supporting more than one synchronizer being connected to a validator. The following changes are backwards compatible since when a validator is connected to a single synchronizer (i.e., the Global Synchronizer). Console commands and API endpoints for allocating/enabling parties now take an optional synchronizer to specify the target synchronizer. The synchronizer ID parameter can be "omitted" or set to None, if the validator is connected to only one synchronizer. This means that party allocations must be done explicitly for each synchronizer, and that the participant must be connected to each synchronizer at the time of enabling the party.

  • The console commands participant.parties.enable and participant.parties.disable have a new parameter synchronizer: Option[SynchronizerAlias] that specifies on which synchronizer the party should be enabled or disabled. The parameter waitForSynchronizer:` SynchronizerChoice has been removed.
  • The console command participant.ledger_api.parties.allocate has a new parameter synchronizer_id for specifying the target synchronizer for the party allocation. 
  • The Ledger API request PartyManagementService.AllocatePartyRequest now has a new field string synchronizer_id for specifying the target synchronizer of the party allocation. 

If the synchronizer parameter is not specified and the participant is connected to multiple synchronizers, the request fails with the error PARTY_ALLOCATION_CANNOT_DETERMINE_SYNCHRONIZER. If the participant is not connected to any synchronizer, the request fails with the error PARTY_ALLOCATION_WITHOUT_CONNECTED_SYNCHRONIZER.

The authorized store can still be used to store PartyToParticipant topology transactions, but users are discouraged from doing so.

Miscellaneous Changes

  • Ports for (admin, gRPC Ledger, JSON Ledger, public) API have to be provided explicitly (they are not generated automatically anymore). However, the CN deployment tools will preconfigure the ports so this should be transparent and backwards compatible for the validator.
  • Renamed command bootstrap.local() to bootstrap.synchronizer_local(). It provides a simple way to bootstrap a local synchronizer.
  • The error code ABORTED_DUE_TO_SHUTDOWN is now used instead of the (duplicate) error code SERVER_IS_SHUTTING_DOWN that was previously used.
  • The SequencerConnections admin API protobuf structure takes a new parameter sequencer_liveness_margin that specifies the number of extra subscriptions to maintain beyond sequencer_trust_threshold in order to ensure liveness. This parameter is only used when the new sequencer connection pool is enabled, and is ignored otherwise. For Canton Network, the configuration is handled through the validator so this will be transparent when the new connection pool is enabled.
  • To modify sequencer connections in the Canton console you have to use the SequencerConnections class The SequencerConnections class' public constructor many(...) takes accordingly a new parameter sequencerLivenessMargin. The single constructor remains unaffected as this only applies to multiple sequencer connections.
  • Renamed mediator scan to mediator inspection for both the commands and the admin API service. Renamed the inspection service gRPC of the participant into ParticipantInspectionService to differentiate from the mediator one.
  • Renamed AuthenticationTokenManagerConfig#pauseRetries to minRetryInterval.
  • Endpoints and console commands LocatePruningTimestamp are renamed to FindPruningTimestamp.

Participant Query Store

Changed the event format filter to use package name instead of package id for Canton 3.x.

Enhanced the support for divulgence in 3.4.

Added documentation about query optimization with expression indexes

Added JSON encoding feature flags

  • Encode numeric as string instead of JSON number (default: true)
    • Command line: --target-encoding-numericasstring boolean 
    • Environment variable: SCRIBE_TARGET_ENCODING_NUMERICASSTRING
    • System property:  target.encoding.numericAsString
  • Omit fields with NULL values from resulting JSON (default: false)
    • Command line: --target-encoding-excludenulls boolean 
    • Environment variable: SCRIBE_TARGET_ENCODING_EXCLUDENULLS
    • System property:  target.encoding.excludeNulls
  • Encode int64 as string instead of JSON number (default: true)
    • Command line: --target-encoding-int64asstring boolean
    • Environment variable: SCRIBE_TARGET_ENCODING_INT64ASSTRING
    • System property:  target.encoding.int64AsStringexcludeNulls target.encoding.int64AsString