> ## Documentation Index
> Fetch the complete documentation index at: https://docs.canton.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Canton

> Release notes for Canton tools, including PQS, Daml Shell, Daml language, and more.

The latest stable Canton release is reproduced below verbatim from the upstream release notes. For the full Canton release history, including older versions, see the [Canton release notes on the Digital Asset blog](https://blog.digitalasset.com/developers/release-notes/author/curtis-hrischuk).

# Release of Canton 3.5.3

## Introduction

The Canton 3.5.3 release notes for Splice 0.6.0 are provided below. The content here focuses  on Canton updates only. For Splice related changes, please refer to the [Splice Release Notes](https://docs.canton.network/global-synchronizer/release-notes/splice).

These notes are broken down into the key sections below:

* Application Development and Tooling
* Ledger API
* Admin API and Console
* Deployment and Configuration
* Operational Procedures

dApp developers will be interested in the top three while validator (or SuperValidator) operators are interested in the bottom three.

Each section has three sub-sections that are self explanatory:

* New Features and Enhancements
* Important Changes
* New Deprecations

It is recommended to read all of the "Important Changes" sections to avoid missing an important update.

Please note that the Canton 3.5 binary can operate like Canton 3.4 when the Protocol Version (PV) is set to 34 and the Daml-LF version is 2.2. The new features described below are enabled when the PV is updated to 35 and, in some cases, Daml-LF to 2.3. This document describes the latter case, when PV is 35 and Daml-LF is 2.3. Note that to make use of DamlLF 2.3 features, a recompilation of the dApp may be needed.

Although much of the discussion is applicable to the Canton Network or Splice, many of the improvements will be relevant to application developers for private synchronizer or multi-synchronizer applications.

## Application Development and Tooling

### New Features and Enhancements

#### Introducing Contract Keys

This release introduces the contract key feature which was previously available in Daml 2.x.
A *contract key* is a stable identifier that simplifies reasoning and programming with the UTXO contracts. They make it easier to track contract IDs as the contract evolves: as a contract is updated, via archive and create operations, the currently active contract(s) can easily be referenced via the contract key. The contract key feature simplifies both the Daml business logic developer as well as the client of that Daml business logic (e.g., backend service).

Contract keys will enable Ethereum or Solana developers to more easily develop applications on the Canton Network because the UTXO mental model is simplified. Services that integrate with the ledger will be simpler because they have a stable identifier to program.

Contract keys are similar in concept to primary or secondary keys in relational databases. Contract keys do not change and can be used to refer to a contract even when the contract ID changes. Technically, the contract key can be any value that does not contain contract IDs.

In this release, a contract key can refer to zero, one, or several contracts at the same time. In Canton 3.x, allowing a key to refer to one, zero, or several contracts does have the advantage that a contract key can act like a secondary key of a database.  This version of contract keys assumes that key uniqueness is provided by the dApp or other  external enforcement mechanisms.

##### Daml Language Primitives

The Daml language and compiler are reintroducing the two keywords: `key` and `maintainer`. To define a contract key in a Daml template, you use the `key` keyword and specify the `maintainer`.

* The `key` expression identifies the contract (always includes a `Party` for scoping).
* A `maintainer` is the party that validates all action on a key to guarantee their consistency. The central task of the `maintainer` is to verify the keys are retrieved in a consistent order within the transaction. A `maintainer` must be a signatory. The maintainer must be expressed in terms of the key, which is available via the `key` identifier in the maintainer expression.

Here’s an example of setting up a contract key for a bank account, to act as a bank account ID:

```
type AccountKey = (Party, Text)

template Account with
   bank : Party
    number : Text
    owner : Party
    balance : Decimal
    observers : [Party]
    subaccount: optional AccountKey
  where
    signatory [bank, owner]
    observer observers

    key (bank, number) : AccountKey
    maintainer key._1
```

Daml language now supports several primitives associated with contract keys. The following primitives are available:

* `lookupByKey` - It checks whether a contract with the given key exists and if yes, returns the contract id. If multiple contracts exist, the first one according to the lookup order below is returned.
* `fetchByKey` - It fetches the first contract id and contract data associated with the given contract key. If multiple contracts exist, the first one according to the lookup order below is returned.
* `exerciseByKey` - Exercise a choice on the first contract associated with the given key according to the order below.
* `lookupNByKey` - Available in `DA.ContractKeys`. It looks up up to `n` contracts associated with the passed key, sorted according to the order below.

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.

##### Daml Script Functions

There are Daml Script functions - counterparts of the standard library primitives:

* `queryByKey` - It looks up a contract associated with the passed key and returns its ids and data. It is of type `Script`, 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 type `Script`, 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 type `Commands` and must therefore be wrapped by a submit operation, and can be combined with other `Commands`.

##### Smart Contract Upgrade (SCU)

To support SCU upgrade for contract `key` and `maintainer` definitions, new guidelines have been added. Simply, the `key` and `maintainer` values are not allowed to be changed. At upgrade time, the recomputed key and maintainers are verified to be identical to the upgraded contract’s original key and maintainers. If they aren't, an upgrade error is raised and the transaction is aborted. It is forbidden to add or remove a key definition from a template in a later version of that template. The default is to enforce this at package vetting time.

### Important Changes

#### Daml-LF 2.3

A new version of Daml-LF is released: Daml-LF 2.3. To benefit from new features (like Contract Keys) this LF version enables, the package needs to be recompiled and its semantic version must be bumped to form a new element in the package lineage. (Please note that this will cause the package ID to change.)

You can target Daml-LF 2.3 by setting the `--target=2.3`, either as direct argument on the command line or as part of a `daml.yaml`:

```
sdk-version: 3.5.1
name: some-name
source: daml
version: 0.0.2 # updated from 0.0.1
dependencies:
 - daml-prim
 - daml-stdlib
build-options:
  - --target=2.3
```

#### `dpm` Replaces the Daml Assistant (`daml`) CLI

`dpm` is a command-line tool that allows users to run the SDK components. It is a drop-in replacement for the Daml Assistant (`daml`), which is removed in this release. It has an extensible plug-in architecture(see [Publishing Components](https://docs.canton.network/sdks-tools/cli-tools/dpm#publishing-components)). The Daml Assistant (daml) was [deprecated in Canton 3.4](https://blog.digitalasset.com/developers/release-notes/canton-3.4-release-notes-for-splice-0.5.0#changes-daml-language-and-ide).

The `dpm` CLI is documented [here](https://docs.canton.network/sdks-tools/cli-tools/dpm#dpm-daml-package-manager). A command migration table, from `daml` to `dpm` commands, is available [here](https://docs.canton.network/sdks-tools/cli-tools/dpm#command-migration-table).

#### Daml Exception Handling Updates

Daml exception handling has been [deprecated since Canton 3.3](https://blog.digitalasset.com/developers/release-notes/splice-0.4.0-canton-3.3#a_use_error_description). deprecated. It is not removed in this release but there is a change:

* Protocol version 35 does not support transactions which roll back write effects.

User exceptions can still be thrown and caught. However, if a consuming choice is exercised or a contract is created within the try-catch block before the exception is caught, the entire command will fail and abort. The mitigation is to remove Daml exceptions and to recompile your Daml code.

### New Deprecations

#### Use PQS's `prune_archived_to_offset` instead of `prune_to_offset`

The PQS `prune_to_offset` SQL function is deprecated. You should not use it anymore as it can introduce a deadlock with accompanying poor performance. The mitigation is to use the newly introduced `prune_archived_to_offset` as a replacement: It is non-blocking and 10x faster.

## Ledger API

### New Features and Enhancements

#### Ledger API Contract Key Support

The following contract-key related extensions have been made to the Ledger API

* `contract_key_hash` has been added to the `CreatedEvent` message returned in the `State-` and `UpdateService` responses
* `prefetch_contract_keys` field present in the `Command` and `PrepareSubmissionRequest` used by the `Command-` `CommandSubmission-` and `InteractiveSubmissionService` are available to allow the caller to request prefetching the contract key cache underpinning the command interpretation. Use it when performance tests indicate that many sequential contract key lookups adversely impact the command interpretation speed.

#### PQS Contract Key Support

In PQS, contract keys are mere metadata that can be queried like any other metadata. It is possible to query for all contracts with a given key:

```
select contract_id, payload ->> 'label'
from __contracts
where contract_key = jsonb_build_object(...)
order by created_at_ix
```

#### Party Replication Topology Events To Signal Begin and End of Replication

The `PartyToParticipant` topology "onboarding" state used in the process of replicating a party with existing contracts is now visible via the Ledger API, when a party onboards on a synchronizer on protocol version 35 or higher. Starting with PV=35, the newly introduced `ParticipantAuthorizationOnboarding` Ledger API topology event signals the beginning of party replication and transitions to `ParticipantAuthorizationAdded` once the party's ACS is fully visible on the Ledger API.

#### New Transaction Hashing Scheme v3 for `InteractiveSubmissionService`

The Ledger API prepare `InteractiveSubmissionService` has been modified to take in a specific hashing scheme version in the request. The default hashing scheme is `HASHING_SCHEME_VERSION_V2`. Integrators are encouraged to move to `HASHING_SCHEME_VERSION_V3` for synchronizers using protocol version 35. **In particular, usage of contract keys requires `HASHING_SCHEME_VERSION_V3`.**

* A new hashing scheme version `HASHING_SCHEME_VERSION_V3` has been introduced that includes the transaction's `max_record_time` in the hash computation and covers the new transaction node and fields of contract keys. This new version is available from Protocol Version 35.
* See the [hashing algorithm documentation](https://docs.canton.network/appdev/deep-dives/external-signing-hashing-algorithm#hashing-scheme-version) for the updated version.
* The `max_record_time` is now enforced by all confirming participants.

See the versioning [documentation](https://docs.canton.network/appdev/deep-dives/external-signing-hashing-algorithm#versioning) for more details.

#### LAPI ACS Stream Enhancements

The `GetActiveContracts` stream request has been extended with an optional `stream_continuation_token` field that allows clients to continue an interrupted ACS stream from the last element which made it through. The field can be populated with the `stream_continuation_token` field of the last response element received before the interruption, and the stream will continue from the next element after that.

A new `GetActiveContractsPage` endpoint added to the State Service API. This enables the client to retrieve the ACS in paginated form, by specifying a `max_page_size`. The pages can be accessed sequentially by using the `page_token` field. The token can be obtained from the `GetActiveContractsPageResponse` of the last page.

#### GetUpdates Stream Enhancements

The `GetUpdatesRequest` object has a new optional parameter `descending_order`. When this parameter is `true` the events are streamed from the newest to the oldest ones. The pages can be accessed sequentially by using the `page_token` field.  An example use for this feature is to view the transaction history from newest to oldest.

A new `GetUpdatesPage` endpoint has been added to the Update Service API that supports pagination. This allows retrieval of updates in paginated form instead of requesting the stream.

#### Optimizing ACS Queries using Active Contracts Head Snapshot (ACHS)

The Active Contracts Head Snapshot (ACHS) is a new optional feature that maintains a continuously updated snapshot of the currently active contracts. When enabled, the ACHS accelerates `GetActiveContracts` (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:

```
canton.participants.<participant>.parameters.ledger-api-server.indexer.achs-config {
  valid-at-distance-target = 1000000
  last-populated-distance-target = 500000
}
```

The `valid-at-distance-target` controls how far behind the ledger end (in event sequential IDs) the snapshot's validity point is maintained. The ACHS is not used for serving queries below its validity point, logging at INFO level `ACHS for (...) skipped since validAt (...) already surpassed requested activeAt (...)`. If the `valid-at-distance-target` value is too small, long-running ACS queries may observe the ACHS validity point moving (mid-stream) past their requested offset, causing the stream to fall back to the slower filter tables query, logging at INFO level `ACHS stream for (...) fell back to filter tables from (...) since validAt (...) surpassed activeAtEventSeqId (...)`. If the value is too large, the tail portion of the ACS (between the ACHS validity point and the requested offset) must be resolved from the filter tables, making that last segment more expensive.

As described above, when the ACHS validity point moves or is past the requested offset, an info-level log message is emitted indicating that the stream fell back to the filter tables. Two corresponding metrics, `achs_skips` and `achs_midstream_fallbacks`, are available under `daml.participant.api.index` to help operators monitor the frequency of these fallbacks and tune the `valid-at-distance-target` accordingly.

The `last-populated-distance-target` controls the additional lag (in event sequential IDs) for the population of ACHS in order to store only the long-lived contracts. A larger value reduces database I/O by skipping short-lived contracts that are created and archived before they would be added to the snapshot. However, setting it too large increases the cost of the remaining ACS tail, as more data must be fetched from the filter tables to cover the gap between the last populated point and the ACHS validity point.

Further tuning parameters include:

* `population-parallelism`: number of parallel threads for adding activations to the ACHS during normal operation.
* `removal-parallelism`: number of parallel threads for removing deactivated activations from the ACHS during normal operation.
* `aggregation-threshold`: minimum batch size (in event sequential IDs) before ACHS maintenance work is emitted.
* `init-parallelism`: number of parallel threads for ACHS population and removal during initialization.
* `init-aggregation-threshold`: minimum batch size (in event sequential IDs) for ACHS maintenance during initialization.
* `buffer-size`: size of the internal buffer between the indexer pipeline and the ACHS maintenance flow.

The `deactivation_distances` histogram metric which is available under `daml.participant.api.indexer.deactivation_distances` can help operators understand the distribution of contract lifetimes (the event sequential ID distance between a contract's activation and its deactivation) and set an appropriate `last-populated-distance-target`. Ideally, the population distance should be large enough so that most short-lived contracts are already deactivated and thus not added to the snapshot.

Three Prometheus gauge metrics are available under `daml.participant.api.indexer` to monitor the ACHS state:

* `achs_valid_at`: the event sequential ID at which the ACHS is currently valid. ACS queries with a requested offset at or after this value can be read directly from the ACHS.
* `achs_last_populated`: the last event sequential ID for which activations were added to the ACHS.
* `achs_last_removed`: the last event sequential ID for which deactivations were looked up and the corresponding activations were removed from the ACHS.

#### Other Ledger API Improvements

* `ApiRequestLogger is now` also used by Ledger JSON API. Changes are:
  * Redundant Request `TID` removed from logs.
  * Additional CLI options added: `--log-access` captures API access logs in a separate file (default: `log/canton_access.log`), and `--log-access-errors` captures API access errors in a separate file (default: `log/canton_access_error.log`).
  * Additional config options added: `debugInProcessRequests` logs in-process gRPC requests at DEBUG instead of TRACE, and `prefixGrpcAddresses` prefixes gRPC client addresses with `grpc:` (enabled by default).
* Ledger API `ListKnownParties` supports an optional prefix filter argument `filterParty`. The respective JSON API endpoint now additionally supports `identity-provider-id` as an optional argument, as well as `filter-party`.
* To protect the admin participant from self lock-out, it is now impossible for an admin to remove its own admin rights or delete itself.
* On Ledger API interface subscriptions, the `CreatedEvent.interface_views` now returns the ID of the package containing the interface implementation that was used to compute the specific interface view as `InterfaceView.implementation_package_id`.
* `OffsetCheckpoints` are now always generated when an open-ended update or completion stream is requested, even if there are no updates. The checkpoint can have the same offset as the exclusive start of the stream, making checkpoints visible even when starting from the ledger end. This enables client systems to recognize when the ledger end is advancing, even if the stream of updates is inactive.
* Extended the set of characters allowed in user-id in the ledger api to contain brackets: `()`. This also makes those characters accepted as part of the `sub` claims 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.

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

By default the value of this parameter is 0.

* An IDP administrator can now only allocate parties confined to their own IDP perimeter.

### Important Changes

#### Only Package-Name is Now Accepted for the Ledger API Queries

The package-id reference format has been [deprecated since Canton 3.3](https://blog.digitalasset.com/developers/release-notes/splice-0.4.0-canton-3.3#a_identifier_addressing_by_package_name) and is no longer supported in this release for read Ledger API queries.   This applies for both Protocol Version 34 and 35.

Specifying interface and template identifiers to the Ledger API read queries must use the package-name reference format, where the package name is the root identifier, such as `#<package-name>:<module>:<entity>`. The package-id reference format was deprecated and is no longer supported so it will now fail.

The impacted LAPIs are:

* `GetUpdates`
* `GetUpdateByOffset`
* `GetUpdateById`
* `GetActiveContracts`
* `GetEventsByContractIdRequest`
* `SubmitAndWaitForTransaction` (the optional `transaction_format`)
* `SubmitAndWaitForReassignmentRequest`
* `ExecuteSubmissionAndWaitForTransactionRequest`

#### `synchronizer_id` Format Changes in Protocol Version 35

In PV 35, the `synchronizer_id` field in an externally signed prepared transaction metadata will be populated with the physical synchronizer ID of the synchronizer on which the transaction will be processed, instead of the logical synchronizer ID, as is the case in PV 34. Applications must ensure they do not rely on the format of the synchronizer\_id value. This was announced in this [Canton Forum post](https://forum.canton.network/t/format-of-synchronizer-id-will-change-in-canton-3-5-potential-breaking-change/8445).

The change is that the format of the [`synchronizer_id`](https://github.com/digital-asset/canton/blob/8d252e6592354ac244eb65c850c4ef2a9a9b63c2/community/ledger-api-proto/src/main/protobuf/com/daml/ledger/api/v2/interactive/interactive_submission_service.proto#L187) metadata field value in a prepared transaction will change when upgrading from Canton 3.4 (protocol version 34) to Canton 3.5 (protocol version 35). This is not an API breaking change but a change to the format of the `synchronizer_id` field shown below:

**Current format example (protocol version 34):**
**`global_sync::12204457ac942c4d839331d402f82ecc941c6232de06a88097ade653350a2d6fc9c5`**

**New format example (protocol version 35):**
**`global_sync::12204457ac942c4d839331d402f82ecc941c6232de06a88097ade653350a2d6fc9c5::35-0`**

As shown, the 3.5 format adds a suffix (`::35-0`) compared to the current 3.4 format. Applications must ensure that they do not rely on the format of this field in a way that would break functionality. If the field must be parsed then it is recommended to support both formats.

NOTE: This will cause the DSO Global Synchronizer ID to change as shown in the example above.

Please note that the API specification does not give any guarantee on the `synchronizer_id` format, so the recommended approach is to treat `synchronizer_id` metadata as an opaque string in the application logic. In general, this is the recommended approach since the `synchronizer_id` field may change in the future. If you parse the `synchronizer_id`, the recommendation is to support both formats.

#### Ledger API Specification Changes

The OpenAPI and AsyncAPI specifications for the Ledger API (LAPI) are now aligned with the gRPC transport. All gRPC `optional` fields are now marked as `optional` in the other specifications, which can impact the generated code. This is mostly transparent for several OpenAPI (AsyncAPI) language generators because it is a backwards compatible step to go from `required` to `optional`.

A summary of the changes to the generated code varies by language:

* No changes are expected for Java.
* TypeScript will require minor changes.
* Clients in languages like Rust will need more (but trivial) changes.
* Languages using dynamic typing should not be affected.

Refer to the *Appendix: OpenAPI / AsyncAPI Migration impact for users* for the migration guidance which is at the end of this release note.

To support multiple OpenAPI specifications in a single Canton release while allowing for backwards compatibility, the OpenAPI (AsyncAPI) file name is now aligned with the corresponding canton version. For example: `openapi-3.5.0.yaml.`

For backward compatibility, the Canton 3.4 OpenAPI and AsyncAPI specifications can be used unchanged. If you want to use new endpoints, features or leverage the new less strict spec, migrate to the new 3.5 OpenAPI/AsyncAPI specifications.

#### Maximum Number of Signatures per External Submission

As an availability security measure, the Ledger API now enforces a maximum number of signatures per party that can be provided for external submissions. This value defaults to 50 and can be changed at the following config path: `canton.participants.<participant_name>.ledger-api.interactive-submission-service.maximum-number-of-signatures-per-party`

#### Removed Deprecated `UpdateService` JSON APIs

Several `UpdateService` JSON APIs were [deprecated in Canton 3.4](https://blog.digitalasset.com/developers/release-notes/canton-3.4-release-notes-for-splice-0.5.0#changes-json-api). These `UpdateService` requests are removed in this release:

* `/v2/updates/trees`
* `/v2/updates/transaction-tree-by-offset`
* `/v2/updates/transaction-tree-by-id`
* `/v2/updates/transaction-by-offset`
* `/v2/updates/transaction-by-id`

### New Deprecations

#### Ledger JSON API Package Vetting Endpoints

The Ledger JSON API `v2/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/list` accepts a `POST` request with the same body as the deprecated `GET v2/package-vetting` endpoint and returns the list of vetted packages in the same format.
* `v2/package-vetting/update` accepts a `POST` request with the same body as the deprecated `POST endpoint v2/package-vetting` and returns the updated vetting state of the package in the same format.

#### Scope Based JWT Tokens

Scope based JWT tokens that are identified by the `scope` claim in their body are deprecated in this release and will be removed in version 3.7. Going forward only the audience based tokens identified by their `aud` claim will be supported. In keeping with this change, the configuration entry allowing specifying the target scope expected on incoming JWT tokens has been deprecated as well.

If you are currently using the scope based tokens,

* Reconfigure your IDP system to issue `aud` based tokens instead and
* Change the Canton configuration accordingly specifying the expected target audience.

Similar reconfiguration must be performed for each IDP configured through the Identity Provider Config Service.

## Admin API and Console

### New Features and Enhancements

#### Improved Party and Repair ACS Imports

For performance reasons, the ACS import endpoints for both party replication and participant repair were overhauled to be memory-efficient streaming endpoints:

* Console command `participant.parties.import_party_acs`
* Console command `participant.repair.import_acs`
* gRPC RPC `PartyManagementService.ImportPartyAcs`
* gRPC RPC `ParticipantRepairService.ImportAcs`

This resolves previous memory limitations, as these endpoints no longer load the entire ACS snapshot into memory at once.  This works for both Protocol Version 34 and 35.

#### Changes to use the New Endpoints

**The `synchronizerId` 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")`

For import\_acs:

* Old usage: `participant.repair.import_acs("canton-ACS-export.gz")`
* New usage: `participant.repair.import_acs(mySynchronizerId, importFilePath = "canton-ACS-export.gz")`

Because of the mandatory `synchronizerId` parameter, to import a multi-synchronizer ACS snapshot, you must now call the endpoint sequentially for each synchronizer your participant is connected to, using the exact same snapshot file. The import process will ignore any contracts in the snapshot that are associated with a different synchronizer.

#### Details on the grpc `ImportAcs` Repair Endpoint

The `ImportAcs` and `ImportAcsV2` RPCs have been consolidated, introducing the following changes and migration steps:

* `ImportAcsV2` (along with its request/response messages) is completely removed. All clients must migrate to the standard `ImportAcs` RPC.
* Request signature and type changes:
  * Fields `workflow_id_prefix` (2), `contract_import_mode` (3), and `representative_package_id_override` (5) in `ImportAcsRequest` are now explicitly optional.
  * A new optional string `synchronizer_id` = 6 field was added.
  * Migration (ScalaPB): Adding optional changes generated code from base types to `Option[T]`. Existing clients will fail to compile and must be updated to wrap assigned values (e.g., `workflowIdPrefix = Some("prefix")`) and explicitly handle reading `Option` types.
* 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`:

* A new optional `string party_id = 6` field was added. Providing this in the first request of the stream enables automatic, crash-resilient scheduling of the onboarding flag clearance. If omitted, the participant logs a warning, and the flag must be cleared manually.
* The `synchronizer_id` (field 2) temporarily accepts either a logical or physical synchronizer ID to better support Logical Synchronizer Upgrade (LSU) scenarios. This support is subject to change.

#### Removal of Legacy ACS Export and Import Endpoints

The following legacy repair endpoints for the ACS export and import were [deprecated in Canton 3.4](https://blog.digitalasset.com/developers/release-notes/canton-3.4-release-notes-for-splice-0.5.0#changes-acs-import) and are removed in this release:

* Console `command participant.repair.export_acs_old`
* Console `command participant.repair.import_acs_old`
* gRPC `rpc ParticipantRepairService.ExportAcsOld`
* gRPC `rpc ParticipantRepairService.ImportAcsOld`

To use the repair endpoints simply remove the 'old' suffix:

* Migrate to `participant.repair.export_acs` from `participant.repair.export_acs_old`
* Migrate to `participant.repair.import_acs` from `participant.repair.import_acs_old`
* Migrate to `ParticipantRepairService.ExportAcs` from `ParticipantRepairService.ExportAcsOld`
* Migrate to `ParticipantRepairService.ImportAcs` from `ParticipantRepairService.ImportAcsOld`

Note that previously created ACS snapshots with the legacy endpoints cannot be imported with the current endpoints as the underlying data format has completely changed.

**Migrating to `export_acs`**
The most significant change is the removal of the timestamp parameter, which has been replaced by a mandatory `ledgerOffset` parameter.

Console parameter changes:

* New mandatory parameter: `ledgerOffset (Long)`. You must now specify the exact ledger offset for the snapshot instead of a timestamp.
* Removed parameters: `partiesOffboarding`, `timestamp` (replaced by `ledgerOffset`), force.
* Renamed parameters: `outputFile` is now `exportFilePath` (default is `"canton-acs-export.gz"`), `filterSynchronizerId` is now `synchronizerId`.
* New optional parameters: `excludedStakeholders` allows you to omit contracts that have one or more of these parties as a stakeholder; `contractSynchronizerRenames` allows mapping contracts from one synchronizer to another during export.

gRPC changes for `ExportAcsRequest`:

* `parties` to `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` to `ledger_offset` (Breaking): You must provide an exact `int64 ledger_offset` instead of a timestamp.
* `Filter_synchronizer_id` to `synchronizer_id`: Field renamed for consistency.
* Removed fields: `force` and `parties_offboarding` have been completely removed.
* New fields: `contract_synchronizer_renames` and `excluded_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: `inputFile` is now `importFilePath` (default is `"canton-acs-export.gz"`).
* New optional parameters: `contractImportMode` governs contract validation upon import (defaults to `ContractImportMode.Validation`); `representativePackageIdOverride` allows overriding representative package IDs during import; `excludedStakeholders` allows omitting contracts that have one or more of these parties as a stakeholder.

gRPC changes for `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 binary `acs_snapshot` chunks.
* New mandatory fields: `contract_import_mode` and `synchronizer_id` must be explicitly defined in the first stream request.
* Removed fields: `allow_contract_id_suffix_recomputation` is completely removed.
* New fields: `excluded_stakeholder_ids` and `representative_package_id_override`.
* Response update: `ImportAcsResponse` is now a completely empty message (previously returned a contract ID mapping).

#### Improvements for `repair.add`

The `participant.repair.add` admin command has been revised to use the new `ImportAcs` backend, bringing significant memory performance improvements, stricter default safety validations, and several new parameters.

Previously, `repair.add` implicitly accepted all injected contracts without re-evaluating their cryptographic hashes. To prevent accidental data corruption, the command now defaults to `Validation` mode (`contractImportMode = ContractImportMode.Validation`).

So, if you have existing scripts or recovery procedures that inject manually modified, synthetic, or inconsistent contracts (where the payload does not strictly match the ContractId hash), they will now fail with a `"Failed to authenticate contract with id"` error.

To restore the legacy behavior and bypass this cryptographic validation, explicitly pass the `Accept` mode in your command call:

```
participant.repair.add(
 synchronizerId = mySynchronizer,
 protocolVersion = myProtocolVersion,
 contracts = myContracts,
 contractImportMode = ContractImportMode.Accept // Bypasses strict validation
 )
```

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 to import-\<UUID>).
* `contractImportMode`: Choose between Validation (default, validates that contract IDs comply with the scheme associated with the synchronizer where the contracts are assigned), or `Accept` the contracts as they are (if you know what you are doing).
* `representativePackageIdOverride`: Allows you to remap or override the representative package IDs of the contracts as they are imported.
* `excludedStakeholders`: When defined, any contract that has one or more of these parties as a stakeholder will not be added.

#### Admin API Error Reporting now Uses Canonical gRPC Error Propagation

The previous method of returning errors via response fields has been replaced in favor of the consistency of canonical gRPC error propagation. The following fields are now obsolete:

* `HandshakeResponse.value.failure`
* `VerifyActiveResponse.value.failure`

Errors are now communicated strictly through `io.grpc.Status` codes to ensure a consistent and secure interface.

The following status codes have changed as follows:

* `SequencerAuthenticationService`.challenge now fails with `INVALID_ARGUMENT` (instead of `FAILED_PRECONDITION`), if the client does not support the sequencer's protocol version.
* `SequencerConnectService` now fails with `INVALID_ARGUMENT` (instead of `FAILED_PRECONDITION`) if a non-participant tries to connect.
* `SequencerConnectService.registerOnboardingTopologyTransactions` newly fails with `INTERNAL` (instead of `FAILED_PRECONDITIONS`) if there are missing dynamic synchronizer parameters.
* `SequencerConnectService.registerOnboardingTopologyTransactions` newly fails with `FAILED_PRECONDITION` if the transactions cannot be added to the topology state and sanitization of error messages is enabled.

#### Single Topology Transaction for External Parties

Multiple topology transactions for external parties can now be represented with a single `PartyToParticipant` topology transaction.

The `generateExternalPartyTopology` endpoint on the Ledger API now returns a single `PartyToParticipant` topology transaction to onboard the party. The transaction contains a signing threshold and signing keys. This effectively deprecates the usage of `PartyToKeyMapping`. For parties with signing keys both in `PartyToParticipant` and `PartyToKeyMapping`, the keys from `PartyToParticipant` take precedence.

Deprecated usage of `PartyToKeyMapping`. The functionality provided by `PartyToKeyMapping` is now available directly in `PartyToParticipant`. Please use `PartyToParticipant` for new transactions. `PartyToKeyMapping` is still fully supported in this version (including existing and new transactions). In a future version, creation of new `PartyToKeyMapping` transactions may be disallowed.

Deprecated `TopologyManagerReadService.ExportTopologySnapshot` and `TopologyManagerWriteService.ImportTopologySnapshot`, along with their console counterparts `topology.transactions.export_topology_snapshot`, `topology.transactions.import_topology_snapshot`, `topology.transactions.import_topology_snapshot_from`, and `topology.transactions.export_identity_transactions`. Please use the corresponding V2 variants (`ExportTopologySnapshotV2` / `ImportTopologySnapshotV2`, `export_topology_snapshotV2`, `import_topology_snapshotV2`, `import_topology_snapshot_fromV2`, `export_identity_transactionsV2`) instead, which use an updated internal bytestring format.

#### Offline Party Replication

Concluding an offline party replication by clearing the onboarding flag now includes two major updates when using protocol version 35:

* Additional crash resilience for ongoing clearances.
* Automatic scheduling for clearances when a participant (re)connects to the synchronizer.

These changes apply only to the `participant.parties.import_party_acs` and `participant.parties.clear_party_onboarding_flag` endpoints.

Note: The replicated party ID must be included in the party ACS import call to enable automatic scheduling. The original behaviour is retained for protocol version 34.

#### Hardened Error Handling in Sequencer Connect Service

We more completely redacted sensitive information from error messages for the `SequencerConnectService` to avoid information leakage. Detailed internal error messages are now redacted before being sent to clients.

If detailed diagnostics are required in a non-production environment, sanitization can be toggled off via:

```
canton.monitoring.sanitize-public-error-messages = false
```

#### Mediator Verdicts Resilience

The mediator now guarantees that all verdicts will eventually be persisted and available on the inspection API.

#### Enhanced Reliability for `GetHighestOffsetByTimestamp`

Previously, the `GetHighestOffsetByTimestamp` RPC and the `find_highest_offset_by_timestamp` console command could return offsets not yet synced with the participant's local cache due to a race condition. In this circumstance, using this returned value with a future timestamp resulted in an error.

Specific changes:

* The required state is now retrieved atomically via a consistent database snapshot.
* The endpoint now includes an internal barrier (waiting up to 10 seconds) to ensure the local Ledger API cache catches up with the database before returning the offset.
* When `force` is true, requesting a future timestamp now gracefully returns the current ledger end instead of failing.

No migration required.

#### Topology-Aware Package Selection (TAPS) improvements

Topology-Aware Package Selection (TAPS) better handles inconsistent vetting states:

* The algorithm now considers a party's package vetting state only for packages required by that party in the interpreted transaction. It starts with a minimal set of restrictions derived from the command's root nodes and progressively accumulates more restrictions over a configurable number of passes. This iterative process increases the likelihood of finding a valid package selection set for the routing of the transaction.
* The maximum number of TAPS passes can be set at the request-level via the optional `taps_max_passes` field in `Commands` or `PrepareSubmissionRequest` messages. If not specified, the default value is taken from the participant configuration via `participants.participant.ledger-api.topology-aware-package-selection.max-passes-default` (defaults to `3`). A hard limit is enforced by `participants.participant.ledger-api.topology-aware-package-selection.max-passes-limit` (defaults to `4`).
* TAPS now ignores unvetted dependencies of packages that are not required for interpretation. complying now with the support of unvetted dependencies in the Canton protocol.

#### Online Party Replication

Online party replication available as an Alpha feature. High level changes and additions are:

* Added the file-based online party replication command `participant.parties.add_party_with_acs_async` to be used along with `participant.parties.export_party_acs` and instead of the sequencer-channel-based `add_party_async` command.
* 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_status` command and `com.digitalasset.canton.admin.participant.v30.PartyManagementService.GetAddPartyStatus` gRPC response type.
* The participant configuration to enable online party replication has been renamed to `alpha-online-party-replication-support` from `unsafe-online-party-replication` for 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-support` from `unsafe-enable-online-party-replication` for consistency and to refer specifically to sequencer channels.

Please consult the documentation for further details.

#### ACS Ledger API Counting

The new memory-efficient console command `participant.ledger_api.acs.count()` has been introduced to count the number of active contracts on a participant node.

Note: This command is currently under the Testing feature flag.

### Important Changes

#### Removal of Automatic Recomputation of Contract IDs upon ACS Import

The ability to recompute contract IDs upon ACS import has been removed. This is a result of the many improvements for ACS import and export.

#### Changes from `NonNegativeLong` to `Long`

Some console commands using a `NonNegativeLong` for the offset are changed to accept a `Long` instead. Similarly, some console commands returning an offset now return a `Long` instead of a `NonNegativeLong`. It brings consistency and allows passing the output of `participant.ledger_api.state.end()`.

Impacted commands:

* `participant.repair.export_acs`
* `participant.parties.find_party_max_activation_offset`
* `participant.parties.find_party_max_deactivation_offset`
* `participant.parties.find_highest_offset_by_timestamp`

#### Removal of Legacy Party Replication Repair Console Macros

The original party replication method, which relied on a silent synchronizer, has been superseded by the offline party replication process. Consequently, the obsolete repair console macros associated with the legacy approach are no longer needed and have been removed.

Specifically, the following macros are no longer available:

* `step1_hold_and_store_acs`
* `step2_import_acs`

If you previously relied on the *Silent synchronizer replication procedure*, you will need to transition to the current offline party replication process. For details, please consult the [Offline Party Replication documentation](https://docs.canton.network/global-synchronizer/production-operations/party-management#offline-party-replication)

#### Miscellaneous Console Changes

* Removed the `LastErrorsAppender` along with the Admin API endpoints `StatusService.GetLastErrors` and `StatusServiceGetLastErrorTrace`, as well as the corresponding console commands `last_errors` and `last_error_trace`.

### New Deprecations

#### Protocol Version parameter in Topology List Commands

The `protocolVersion` parameter in all `<node>.topology.<mapping>.list` console commands has been deprecated and will be removed in a future version.

## Deployment and Configuration

### New Features and Enhancements

#### Session Signing Keys

Session signing keys can now be used to reduce the number of calls to external KMS (Key Management Service) providers. When enabled, session signing keys are generated and cached locally for a limited duration and used for signing operations during their validity period.

Please read the documentation on [Session Signing Keys](https://docs.canton.network/overview/learn/cryptographic-keys#session-encryption-keys) for details on how to enable and configure this feature. Session signing keys are only available from Protocol Version 35 and are not enabled by default.

#### Multi-Synchronizer Improvements

Multi-synchronizer support has been part of the Canton 3.x distribution from its initial release. The recommendation is to start developing multi-synchronizer applications using this release. The main components for multi-synchronizer development, including the surface APIs for [multiple synchronizer connection configurations](https://docs.canton.network/global-synchronizer/reference/canton-console-commands#synchronizer-connectivity), are implemented and the [mechanics are documented](https://docs.canton.network/overview/learn/multi-synchronizer#transactions-with-multiple-synchronizers). As an example, Digital Asset maintains a multi-synchronizer sample application “[Splitwell](https://github.com/hyperledger-labs/splice/tree/main/apps/splitwell)” and continuously tests that it works in a multi-synchronizer deployment as part of [CI/CD testing](https://github.com/hyperledger-labs/splice/blob/main/apps/app/src/test/scala/org/lfdecentralizedtrust/splice/integration/tests/SplitwellIntegrationTest.scala).

Integration testing can be done by deploying your own ScratchNet (to mimic the Global Synchronizer and another private synchronizer), along with setting two configuration values.  The configuration values to be set to fully enable multi-synchronizer are:

* `EnableMultiSynchronizer` enables the validator to perform assign and unassign operations (referred to as reassignment).
* `enable-all-ledger-api-reassignments` is a multi-synchronizer setting so that if an  ACS import or the repair service is done, it will signal the ACS import using assigned events (instead of created). This is necessary if the ACS snapshot contains contracts with non-zero reassignment counters.

To enable contract reassignment across synchronizers, the flag `EnableMultiSynchronizer` must be activated on all validators hosting a stakeholder of the contract on both the source and target synchronizers. For a validator, `EnableMultiSynchronizer` is enabled as follows:

```
participant.topology.synchronizer_trust_certificates.propose(
 p.id,
 synchronizerId,
 featureFlags = Seq(ParticipantTopologyFeatureFlag.EnableMultiSynchronizer),
)
```

The flag `enable-all-ledger-api-reassignments` is a new `Boolean` participant node parameter which differentiates between the types of events when an ACS import is performed:

* The default is `false` so ACS import or repair service will generate standard `Create` events.
* Setting it to `true` enables `Assign` events instead.

This flag preserves the reassignment counter value of a contract on an ACS import. Using the default (`Create` events) resets this counter to zero upon an ACS import. Ledger API clients will need to accommodate the Assign/Unassign events when this is enabled.

These flags also need to be set if integration testing with DevNet is performed.

#### Other Deployment and Configuration Enhancements

* Added a field `MaxConcurrentCallsPerConnection` and corresponding default `defaultMaxConcurrentCallsPerConnection` (set to 100000) to `ServerConfig`. This corresponds to `max-concurrent-streams-per-connection` in the app configs, e.g., `docker/canton/images/canton-sequencer/app.conf` and 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-timeout` for network timeout of the Ledger API server and `canton.participants.<participant>.parameters.ledger-api-server.indexer.postgres-data-source.client-connection-check-interval` for the client\_connection\_check\_interval of the indexer.
* `<canton-node>.replication.connection-pool.connection.client-connection-check-interval` is introduced that allows configuring the PostgreSQL-specific `client_connection_check_interval` parameter for DB locked connections. This is a safety mechanism to prevent hanging connections in case of network issues. The default value is 5 seconds.
* This value defaults to 50 and can be changed at the following config path: `canton.participants.<participant_name>.ledger-api.interactive-submission-service.maximum-number-of-signatures-per-party`
* Added a new configuration parameter `canton.participants.<participant_name>.ledger-api.index-service.max-lookup-limit` that 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.

### Important Changes

#### PQS and Daml Shell Docker Image Changes

In past releases a single docker image supported multiple PQS major and minor versions, with additional environment variable setup to select the PQS version to run. This has been simplified where each PQS `major.minor` version has their own separate Docker image. Please see the [PQS download documentation](https://docs.canton.network/sdks-tools/development-tools/pqs#install-and-download) for details.

The same simplification has been made to the Daml Shell Docker image and is described [here](https://docs.canton.network/sdks-tools/cli-tools/daml-shell#download).

#### Removal of Multi-Host Name Resolution Tooling

Support for the multi-host name resolution was removed. This was only used if synchronizer connectivity defined a sequencer with multiple endpoints, which is not supported with our current sequencers: we now have multiple sequencers each with exactly one endpoint.

#### Removal of the Old Sequencer Connection Transports

The old sequencer connections transports have been removed, and only the new sequencer connection pool remains. Consequently, the configuration `<node>.sequencer-client.use-new-connection-pool` has been deprecated and no longer has any effect.

#### Other Important Changes

* The expert `keep-alive-client` configuration parameter for various client services moved to `channel.keep-alive-client`.
* We reduced the defaults for `setBalanceRequestSubmissionWindowSize` and `defaultMaxSequencingTimeOffset` to 2 minutes.
* The default OTLP gRPC port that the Canton connects to in order to export the traces has been changed from 4318 to 4317. This aligns the default configuration of Canton with the default configuration of the OpenTelemetry Collector. This change affects only the users who have configured an OTLP trace export through `canton.monitoring.tracing.tracer.exporter.type=otlp`

### New Deprecations

#### Deprecate Initial Protocol Version Configuration

The config key `participant.parameters.initial-protocol-version` was unused and has been marked as deprecated.

#### Canton Configuration Deprecations

* The configuration parameters `topology.use-new-processor` and `topology.use-new-client` have 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-interval` is 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-warning` is now ignored.
* The individual JVM metric flags classes, cpu, memoryPools, threads, gc, and buffers in `canton.monitoring.metrics.jvm-metrics` are 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 when `jvm-metrics.enabled = true`. A new experimental flag has been added to control experimental JVM metrics (e.g. buffer pools). Users who previously set `buffers = true` should migrate to `experimental = true`. See [open-telemetry/opentelemetry-java-instrumentation#16087](https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/16087) for details.
* The Zipkin trace exporter configuration `canton.monitoring.tracing.tracer.exporter.type=zipkin` is 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/](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) to `crypto.session-signing-keys` so 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 with `non-standard-config=true`.
* `package-dependency-cache` field in caching configuration is deprecated. It can be removed safely from node configurations.

## Operational Procedures

### New Features and Enhancements

#### Change from `grpcurl` to `grpc-health-probe` in all Docker Images

The tool used for health check probes changed from `grpcurl` to `grpc-health-probe` in all the docker images.

### Important Changes

#### `Offline Root Namespace Key` Script Updates

The helper offline root namespace key scripts have the following changes:

* Renamed `prepare-certs.sh` to `prepare-cert.sh`
* Changed `assemble-certs.sh` to automatically suffix the generated certificate with a `.cert` extension, similarly to what is being done in `prepare-cert.sh`
* Removed the `10-offline-root-namespace-init` example folder as its content is now integrated in the [documented how-to](https://docs.canton.network/global-synchronizer/production-operations/key-management#offline-root-namespace-key).
* Committed the buf image necessary to run the script to the repository (also available in the release artifact), making usage from the open source repo easier

### New Deprecations

None

## Compatibility

The following Canton protocol versions are supported:

| Dependency               | Version |
| ------------------------ | ------- |
| Canton protocol versions | 34, 35  |

Canton has been tested against the following versions of its dependencies:

| Dependency   | Version                                                                                                                                                                                                 |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Java Runtime | OpenJDK 64-Bit Server VM (build 21.0.10+7-nixos, mixed mode, sharing)                                                                                                                                   |
| Postgres     | Recommended: PostgreSQL 17.9 (Debian 17.9-1.pgdg13+1) – Also tested: PostgreSQL 14.23 (Debian 14.23-1.pgdg13+1), PostgreSQL 15.18 (Debian 15.18-1.pgdg13+1), PostgreSQL 16.14 (Debian 16.14-1.pgdg13+1) |

## Appendix: OpenAPI / AsyncAPI Migration

### Runtime Compatibility

JSON Messages are compatible so a client built using existing (for instance 3.4.9) code will continue to work properly.

### Compile-Time Compatibility of the Generated Code

Users that replace the 3.4 `openapi.yaml` with a new one and regenerate code might be forced to fix compilation errors because some parameters have changed from required to optional(or vice versa).

However, users may decide to continue to use previous versions of OpenAPI.
In that case there are no changes required to code.

Information about compatible OpenAPI versions for each release will be in the RELEASE NOTES and openapi.yaml files.

If you decide to use a newer openapi file and regenerate the binding code, the impact of this change varies by language:

* No changes are expected for Java.
* TypeScript will require minor changes (use of !! and ?. operators).
* Clients in languages like Rust will need more (but trivial) changes (use of Option and unwrapping).
* Languages using dynamic typing should not be affected.

Migration instructions are provided below. The example code below is generated from canton Ledger JSON Api openapi.yaml using [https://openapi-generator.tech/docs/installation/](https://openapi-generator.tech/docs/installation/) with default options for each language. The code examples are fragments of `CompletionStreamRequest and JsGetActiveContractsResponse` with a before and after comparison.

#### TypeScript Example

Before:

```
export class CompletionStreamRequest {
 /** …
  Required unless authentication is used with a user token.
 */
 'userId': string;
 /** …
 * Required
 */
 'parties'?: Array<string>;
 /**
 * This optional field…
 */
 'beginExclusive': number;
```

After:

```
export class CompletionStreamRequest {
 /**
 * … Required unless authentication is used with a user token…
 */
 'userId'?: string;
 /**
 * … Required
 */
 'parties'?: Array<string>;
 /**
 * …. Optional
 */
 'beginExclusive'?: number;
```

This is a code compatible change, as it is possible to assign \`T\` to a variable of type \`T?\`.
Before:

```
export class JsGetActiveContractsResponse {
 /**
 *... Optional
 */
 'workflowId': string;
 'contractEntry': JsContractEntry;
```

After:

```
export class JsGetActiveContractsResponse {
 /**
 * …Optional
 */
 'workflowId'?: string;
 'contractEntry'?: JsContractEntry;
```

This might require code changes, in places previously clients were expecting values, now can be null/undefined values. It means use of operator ?? or some other if checking will be needed.
In practice - while converting from gRPC proto those values will be always populated anyway.

Migration instructions (proposal):

If you decide to use new openapi yaml with a typescript projects, you might get compilation errors such as:
**error TS2322: Type 'string | undefined' is not assignable to type 'string'.**

Use ! or ?? to fix the error.

```
//before
let party:string = externalPartyTopologyResponse.partyId;
//after
let party:string = externalPartyTopologyResponse.partyId!;
```

Summary: Generally Typescript developers are not expected to do any changes in code when creating requests.

There are however trivial changes expected when processing results.

We will put a note in NOTES and openapi description that users might continue to use old openapi.yaml.

#### Java Example

There are various code generators for java and popular ones such as [https://openapi-generator.tech/docs/generators/java/](https://openapi-generator.tech/docs/generators/java/)  provides tons of options. Given the way Java treats optional fields, we expect them all to behave as described below, although we cannot guarantee it in all instances.. (Optional in Java should be used as return type only. There are libraries such as Guava or Vavr that provide an alternative Optional, but they are not popular).

Before:

```
public class CompletionStreamRequest {
 public static final String SERIALIZED_NAME_USER_ID = "userId";
 @SerializedName(SERIALIZED_NAME_USER_ID)
 @javax.annotation.Nonnull
 private String userId;

 public static final String SERIALIZED_NAME_PARTIES = "parties";
 @SerializedName(SERIALIZED_NAME_PARTIES)
 @javax.annotation.Nullable
 private List<String> parties = new ArrayList<>();

 public static final String SERIALIZED_NAME_BEGIN_EXCLUSIVE = "beginExclusive";
 @SerializedName(SERIALIZED_NAME_BEGIN_EXCLUSIVE)
 @javax.annotation.Nonnull
 private Long beginExclusive;
```

After:

```
|public class CompletionStreamRequest {
 public static final String SERIALIZED_NAME_USER_ID = "userId";
 @SerializedName(SERIALIZED_NAME_USER_ID)
 @javax.annotation.Nullable
 private String userId;

 public static final String SERIALIZED_NAME_PARTIES = "parties";
 @SerializedName(SERIALIZED_NAME_PARTIES)
 @javax.annotation.Nullable
 private List<String> parties = new ArrayList<>();

 public static final String SERIALIZED_NAME_BEGIN_EXCLUSIVE = "beginExclusive";
 @SerializedName(SERIALIZED_NAME_BEGIN_EXCLUSIVE)
 @javax.annotation.Nullable
 private Long beginExclusive;
```

Migration instruction for Java:
There are no expected changes needed in code if you use java.

We generally do not expect any code changes for java, due to nullability not being enforced by the compiler. There might be some changes needed for people using linters.

#### Rust Example

Before:

```
pub struct CompletionStreamRequest {
 /// …Required unless authentication …
 #[serde(rename = "userId")]
 pub user_id: String,
 /// … Required
 #[serde(rename = "parties", skip_serializing_if = "Option::is_none")]
 pub parties: Option<Vec<String>>,
 /// This optional…
 #[serde(rename = "beginExclusive")]
 pub begin_exclusive: i64,
}
```

After:

```
pub struct CompletionStreamRequest {
 /// … Required unless …
 #[serde(rename = "userId", skip_serializing_if = "Option::is_none")]
 pub user_id: Option<String>,
 /// …Required
 #[serde(rename = "parties", skip_serializing_if = "Option::is_none")]
 pub parties: Option<Vec<String>>,
 /// …Optional
 #[serde(rename = "beginExclusive", skip_serializing_if = "Option::is_none")]
 pub begin_exclusive: Option<i64>,
}
```
