> ## 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.

# 3.7.0

> Canton 3.7.0 release notes.

# Release of Canton 3.7.0

Canton 3.7.0 has been released on October 29, 2026.

## Summary

This minor release introduces protocol version 37. The main themes:

* Multi-synchronizer: no feature flag needed on protocol version 37, and Ledger API changes for multi-synchronizer
  applications (see Breaking changes).
* Party replication: new `v31` topology transactions that track the hosting state of each participant of a party,
  to enable Hybrid Party Replication (HyPR). Applications that decode `PartyToParticipant` transactions may need to
  act (see the [migration guide](#migration-guide-for-external-signers-of-partytoparticipant-transactions)).
* CantonBFT: lower ordering latency and faster catch-up and onboarding.
* Traffic management: traffic can be purchased for participants before they register with the sequencer, and cost
  estimation covers reassignments.
* Hardening and scalability: protocol version 37 bounds more protocol, topology, and ACS commitment collections, and
  sequencer and topology states larger than 2 GB can be exported and imported.

**Summary of breaking changes** (see [Breaking changes](#breaking-changes) for details and migration):

| Ledger API | Node APIs and console | Protocol | Configuration |
| :- | :- | :- | :- |
| yes | yes | yes\* | yes |

* Ledger API:
  * `StateService` excludes incomplete reassignments unless `includeIncompleteReassignments` is set, and rejects
    continuation and page tokens of previous versions.
  * `GenerateExternalPartyTopology` returns `v31` topology transactions on protocol version 37, unless explicitly
    requested for protocol version 36.
  * Contracts with a non-zero reassignment counter that repair commands import, add or purge appear as Assigned and
    Unassigned events.
* Node APIs and console:
  * Sequencers and mediators no longer store their onboarding transactions. Use
    `generate_onboarding_transactions` instead of `identity_transactions`.
  * `propose_delta` no longer moves an Active participant back to Onboarding.
* Protocol:
  * (\*) Synchronizers on protocol version 36 are not affected. Protocol version 37 will be rolled out as a new protocol
    version.
* Configuration: changed default values for safety.
  * The participant repair service is disabled by default (`canton.features.enable-repair-commands = false`).
  * Key export is disabled by default (`canton.parameters.enable-key-download = false`).
  * The Docker images no longer set `canton.parameters.non-standard-config = true` by default.

## What's New

### Protocol version 37

#### Multi-synchronizer without feature flag

Starting with protocol version 37:

* The `EnableMultiSynchronizer` feature flag is not needed to enable multi-synchronizer.
* Any stakeholder can submit the assignment as soon as the unassignment is completed. The `assignment_exclusivity` field of unassigned events is not set, and the synchronizer parameter `assignmentExclusivityTimeout` has no effect.
* New participant configuration `canton.participants.<participant>.parameters.reassignments-config.enable-automatic-assignment` (default `true`). When set to `true`, the participant tries to complete the reassignments initiated by other participants by submitting their assignment, and upon reconnection to a synchronizer it tries to complete its pending reassignments.
* New participant configuration `canton.participants.<participant>.parameters.reassignments-config.automatic-assignment-delay` (default `60s`). The automatic assignment is submitted after a delay drawn between this value and twice this value, counted from the sequencing time of the unassignment on the local clock.

Prior to protocol version 37, the creating package of the contract was used for contract authentication during contract assignment.
From protocol version 37, separate source and target validation packages can be specified at the protocol level.
To be valid, these validation packages must be upgradable packages for the contract and be vetted on the respective synchronizer.
See [Source and target validation packages](#source-and-target-validation-packages-can-be-overridden) for how to set them.

#### New collection size limits

Starting with protocol version 37, the following collections are bounded. Messages exceeding a limit are rejected.

| Field | Default limit | How to configure |
| - | - | - |
| Signatures per envelope | 1000 | Static synchronizer parameter `synchronizer_limits.transaction_protocol_limits.max_signatures_per_envelope` |
| Recipients per envelope | 10000 | Static synchronizer parameter `synchronizer_limits.transaction_protocol_limits.max_recipients_per_envelope` |
| Confirming parties per quorum | 100 000 000 | Static synchronizer parameter `synchronizer_limits.transaction_protocol_limits.max_quorum_size` |
| Signing keys per entity (see below) | 20 | Static synchronizer parameter `synchronizer_limits.topology_limits.max_signing_keys_per_entity` |
| Owners of a `DecentralizedNamespaceDefinition` | 100 | Static synchronizer parameter `synchronizer_limits.topology_limits.max_owners_per_decentralized_namespace` |
| Hosting participants per party (`PartyToParticipant`) | 100 | Static synchronizer parameter `synchronizer_limits.topology_limits.max_hosting_participants_per_party` |
| ACS commitment size in bytes | 10 KB | Static synchronizer parameter `synchronizer_limits.acs_commitment_limits.max_acs_commitment_size_bytes` |
| ACS commitment summary size in bytes | 1 MB | Static synchronizer parameter `synchronizer_limits.acs_commitment_limits.max_acs_commitment_summary_size_bytes` |
| Addressed counter-participants in an ACS commitment summary | 10000 | Static synchronizer parameter `synchronizer_limits.acs_commitment_limits.max_addressed_counterparticipants` |
| Unsent digests in an ACS commitment summary | 10000 | Static synchronizer parameter `synchronizer_limits.acs_commitment_limits.max_unsent_digests` |
| ACS commitment digest size in bytes | 50 | Not configurable |
| Mappings in a `NamespaceDelegation` restricted to specific mappings | 50 | Not configurable |
| Feature flags in a `SynchronizerTrustCertificate` | 50 | Not configurable |

The signing key limit applies to `OwnerToKeyMapping`, `PartyToKeyMapping`, and the party signing keys in
`PartyToParticipant`.

Note that the default limits only apply when used through the console.
When using the API directly to bootstrap a synchronizer on PV37, the latest protobuf version (32) of the `StaticSynchronizerParameters` message must be used, which contains the new limit fields.
Values for those new limits must then be set explicitly.

During submission (i.e. phase 1), the engine emits the following limit metrics for transactions (with a `limit` label
for the currently configured threshold limit):

* `daml.participant.transaction-node.acting-parties`
* `daml.participant.transaction-node.choice-authorizers`
* `daml.participant.transaction-node.choice-observers`
* `daml.participant.transaction-node.external-call-result-size`
* `daml.participant.transaction-node.external-call-results`
* `daml.participant.transaction-node.input-contract-count`
* `daml.participant.transaction-node.key-maintainers`
* `daml.participant.transaction-node.lf-value`
* `daml.participant.transaction-node.node-children-size`
* `daml.participant.transaction-node.node-count`
* `daml.participant.transaction-node.root-node-count`
* `daml.participant.transaction-node.signatories`
* `daml.participant.transaction-node.stakeholders`
* `daml.participant.transaction-node.total-informees`

and the following limit metrics for transaction views:

* `daml.participant.sync.protocol-messages.transaction-view.sub-views`
* `daml.participant.sync.protocol-messages.transaction-view.tree-depth`

#### New `v31` topology transactions: action may be required for decoders

Protocol version 37 adds `v31` topology transactions (`com.digitalasset.canton.protocol.v31.TopologyTransaction`)
to enable Hybrid Party Replication (HyPR). In `v31`, the `PartyToParticipant` mapping gives each hosting
participant a hosting state (Nominated, Freezing, Onboarding, Active) instead of the onboarding flag. All other
mappings are unchanged. Synchronizers on protocol version 37 accept both `v30` and `v31` transactions, and a `v30`
entry counts as Onboarding if its onboarding flag is set, and as Active otherwise.

**Do not use the Nominated and Freezing states until a future 3.7 release announces their support.** A Freezing
entry blocks every transaction and reassignment that involves the party on that synchronizer (error
`FROZEN_PARTIES`) until the entry is removed.

Applications that create or decode `PartyToParticipant` transactions need to act, as described in the
[migration guide for external signers](#migration-guide-for-external-signers-of-partytoparticipant-transactions)
below.

Other changes:

* On protocol version 37, moving a hosting entry backward, e.g. from Active to Onboarding, is rejected. A `v30`
  transaction may still set the onboarding flag of an Active entry if the current mapping is `v30` too.
* Ledger API topology events: `ParticipantAuthorizationOnboarding` when an entry becomes Onboarding,
  `ParticipantAuthorizationAdded` when it becomes Active, and `ParticipantAuthorizationRevoked` when an
  Onboarding or Active entry is removed.
* A node skips a `PartyToParticipant` mapping with a Nominated or Freezing entry when it pushes its authorized store
  to a synchronizer on protocol version 36, which cannot express these states, and logs a warning. Propose such
  mappings in the synchronizer's store.

#### Migration guide for external signers of `PartyToParticipant` transactions

For applications that create `PartyToParticipant` (PTP) topology transactions, or decode them to show them to a user
before signing. Protocol version 36 accepts only `v30` PTP transactions. Protocol version 37 accepts `v30` and
`v31`, and nodes create `v31` unless asked for `v30`.

##### Decode `v31`

On protocol version 37, you can receive `v31`

* from `GenerateExternalPartyTopology` unless you request `v30`,
* from the topology admin API `GenerateTransactions` always,
* from changes that participants make themselves, and
* as stored proposals to co-sign.

In order to deal with the two formats:

* Decode the `data` of the `UntypedVersionedMessage` by its `version`: 30 as `v30.TopologyTransaction`, 31 as
  `v31.TopologyTransaction`, and reject others. Never decode `v31` with the `v30` schema: it parses, but drops the
  party signing keys and the hosting states.
* `v31.PartyToParticipant` replaces the `onboarding` flag with a hosting `state` per participant, and moves
  `party_signing_keys` from field number 6 to 4. All other mappings are unchanged.
* Show each participant's hosting state: Nominated and Freezing participants do not host the party yet.
* Hashing and signing are unchanged.
* `ListPartyToParticipant` returns `v30` items unless the client sends a `client_version` of 3.7 or later, as long
  as no entry is Nominated or Freezing.

##### Or keep using `v30` for now

Protocol version 37 accepts `v30` PTP transactions as a transition aid. Plan the move to `v31`.

* Request `v30` with protocol version 36: `protocol_version` in `GenerateExternalPartyTopology` (`protocolVersion`
  in the JSON Ledger API) and the topology admin API `Authorize`, `protocolVersion` in the console commands
  `party_to_participant_mappings.propose` and `propose_delta`, and `--protocol-version` in the topology scripts.
  `GenerateTransactions` always returns `v31`. `AllocateExternalParty` accepts both versions.
* To co-sign, sign the transaction that you received. Do not rebuild it as `v30`: a `v30` and a `v31` proposal of
  the same change never combine.
* While a party has a Nominated or Freezing entry, `v30` PTP transactions for it are rejected with
  `TOPOLOGY_HOSTING_STATES_NOT_EXPRESSIBLE`, as `v30` cannot express these states.

Hybrid Party Replication (HyPR), which a future 3.7 release will announce, requires `v31`: an external party can be
replicated with HyPR only if its signer creates and decodes `v31` PTP transactions.

#### Protocol version downgrades via LSU are forbidden

Logical synchronizer upgrades from a synchronizer running protocol version 37 or higher to a
successor with a lower protocol version are now rejected. Both the topology manager and the topology
processor reject such `LsuAnnouncement` topology mappings with the error
`TOPOLOGY_INVALID_SUCCESSOR_PHYSICAL_SYNCHRONIZER_ID`.

### For application developers

#### Synchronizer record time to offset conversion

A new Ledger API endpoint in the `StateService` converts a pair of synchronizer id and record time into a participant
offset, which makes requests across participants easier.

Synthetic synchronizer events, like repair related events, are put on the same record time as the last observed
synchronizer event at the time of their creation. Multiple participant offsets can therefore exist for a single record
time. The endpoint returns the first offset at the requested record time, or the last offset before it if there is no
offset at the requested record time. If updates at the requested record time were already partially pruned, the
request is rejected with `RECORD_TIME_NOT_FOUND`.

#### Traffic cost estimation for reassignments

When `CostEstimationHints` are passed to `PrepareSubmission`, the `CostEstimation` of the response now also contains
`reassignment_costs`: one `ReassignmentCost` per reassignment that the submission requires, with the source and target
synchronizer, the reassigned contract ids, and the estimated traffic cost of the unassignment and assignment requests
and responses. `total_traffic_cost_estimation` includes these costs. The JSON API exposes the same fields.

#### Source and target validation packages can be overridden

* The following console commands now take optional `overrideSourceValidationPackageIds` and `overrideTargetValidationPackageIds` arguments:
  * `submit_unassign`
  * `submit_unassign_with_format`
  * `submit_reassign`
  * `submit_unassign_async`
* The `UnassignCommand` Java binding also supports these additional fields.

### Synchronizer operators

#### CantonBFT

* Improved configuration defaults for better ordering latency.
* Request pre-prepare via retransmissions if a weak quorum of prepares is reached without having the pre-prepare. This is an important performance improvement when there is high latency between some nodes and pre-prepares are often delayed or lost.
* Starting with PV37, state transfer responses can carry multiple commit certificates. This allows for more efficient
  catch-up and onboarding.
* Patience-based dissemination retries (`availability-dissemination-patience`) are now disabled by default. When
  enabled, they also apply to batches that have reached the minimum dissemination threshold but have neither been
  disseminated to all nodes nor become part of a block proposal.
* Observability:
  * Logs of the dissemination stage of the ordering protocol have been improved for easier troubleshooting.
  * Improved logging about oversized gRPC messages.
  * Improved metrics about P2P connection status and ISS consensus segment leadership.
  * P2P: TCP- and HTTP2-level metrics.
  * Added metrics for the time ordered blocks wait before delivery while lower-numbered blocks are still pending.
  * Added metrics for pre-prepares accepted coming from retransmissions.
* Fixed: the P2P connection direction was incorrectly reported in metrics and console/admin endpoints in some circumstances.

#### Initialization changes for sequencers and mediators

Rather than generating the onboarding topology transactions during node initialization and storing these in the
authorized store, sequencers and mediators now skip this step and generate them when needed.

This ensures these topology transactions are generated in the right protocol version (which is not known during initialization).
See [Breaking changes](#sequencer-and-mediator-onboarding-transactions) for the console command to use instead of
`identity_transactions()`.

#### File-based console commands for sequencer initialization and topology snapshots

Added new console commands that stream the state to or from a file, for states larger than 2 GB:

* `node.topology.transactions.export_genesis_state`
* `node.topology.transactions.export_topology_snapshot_to_file`
* `sequencer.setup.export_onboarding_state_for_sequencer`
* `sequencer.setup.export_onboarding_state_at_timestamp`
* `sequencer.setup.import_genesis_state`
* `sequencer.setup.import_onboarding_state`

`node.topology.transactions.import_topology_snapshot_fromV2` now supports files larger than 2 GB.

#### Traffic purchase for members that are not registered yet

Traffic can now be purchased for a participant that is not yet registered with the sequencer, which improves the
onboarding process of participants. It requires protocol version 37 or higher. On earlier protocol versions, the
sequencer rejects such a purchase with `TRAFFIC_CONTROL_TOP_UP_SUBMISSION_FAILED`, because the sequencer
snapshot format used there cannot represent a member that is still onboarding.

To support this, new `v31` versions of `SequencerSnapshot`, `SequencerPruningStatus`, `SequencerMemberStatus` and
`OnboardingStateForSequencerV2` have been added in `com.digitalasset.canton.sequencer.admin.v31`. Sequencer snapshots
and onboarding states use them from protocol version 37 onwards. Earlier protocol versions keep using the `v30`
messages and are not affected.

### Participant node operators

#### Traffic enforcement app: pruning of submission correlations

Added the traffic enforcement admin endpoint `Prune` (JSON `POST /v2/traffic/prune`, console command `ledger_api.traffic.prune`).
It prunes events and submission correlations, and reports the pruned event and correlation counts separately.
The timestamp must be at least the participant's max deduplication duration (`canton.participants.<participant>.init.ledger-api.max-deduplication-duration`, default 7 days) in the past, otherwise the request fails with `TRAFFIC_UNSAFE_TO_PRUNE`.

WARNING: Prune only correlations of completed submissions. Pruning the correlation of an in-flight submission affects
its traffic accounting.

#### Traffic enforcement app: traffic top-ups from the ledger (experimental)

The traffic enforcement app can credit traffic top-ups from `TrafficPurchaser` contracts on the ledger. Top-up
ingestion is enabled by setting the trusted paymaster parties, which must be hosted on the participant, in
`canton.participants.<participant>.traffic-accounting.traffic-enforcement-server.projection.top-up-paymasters`
(default empty, i.e. disabled). Ingestion starts at the participant's pruning offset unless
`projection.initial-top-up-offset-begin-exclusive` is set. A top-up that cannot be credited is reported with the error
code `TRAFFIC_TOP_UP_NOT_CREDITED`, which carries the `update_id` and `offset` of the top-up.

### All node operators

#### Key management operations are bound to a synchronizer

The following console commands now take an optional `synchronizerId` argument:

* `node.topology.owner_to_key_mappings.add_key`
* `node.topology.owner_to_key_mappings.add_keys`
* `node.topology.owner_to_key_mappings.remove_key`
* `node.topology.owner_to_key_mappings.rotate_key`
* `node.keys.secret.rotate_kms_node_key`
* `node.keys.secret.rotate_node_key`
* `node.keys.secret.rotate_node_keys`

If omitted, we will try to auto-detect the synchronizer instead.
This will only succeed when there is exactly a single registered and connected synchronizer.

It is considered a security best practice to have a distinct key per synchronizer.

## Breaking changes

### Ledger API (application developers)

#### `StateService` excludes incomplete reassignments by default

Incomplete reassignments (`IncompleteAssigned` and `IncompleteUnassigned` events) are only relevant
to clients that work with contracts reassigned between multiple synchronizers. Most clients only
need the active contracts. Until now, the snapshot always included these events.

A flag `includeIncompleteReassignments` has been added to the `GetActiveContractsRequest`
and `GetActiveContractsPageRequest` of the `StateService`, and to the JSON API accordingly (see the OpenAPI
specification). If the flag is not set, the reassignments are excluded from the response stream. For example,
the following request for the `active-contracts-page` endpoint returns only the active contracts
and excludes any reassignments:

```
  POST http://localhost:6865/v2/state/active-contracts-page
  Content-Type: application/json
  {
    "activeAtOffset": 1000000,
    "eventFormat": {...},
    "maxPageSize": 100,
    "pageToken": "",
    "includeIncompleteReassignments": false
  }
```

*Impact and migration:* the default value of the new flag is `false`, so reassignments are excluded from the response
stream. To restore the previous behavior, set `includeIncompleteReassignments` to `true` in the request. This affects
all early adopters of the multi-synchronizer alpha feature.

The `GetActiveContracts` stream continuation token and the `GetActiveContractsPage` page token formats
have changed to take the new flag into account, so tokens issued by previous Canton versions are rejected
with `INVALID_CONTINUATION_TOKEN` and `INVALID_ACS_PAGE_TOKEN` respectively.

#### `GenerateExternalPartyTopology` returns `v31` topology transactions on protocol version 37

For a synchronizer on protocol version 37, the Ledger API `GenerateExternalPartyTopology` returns the topology
transactions to sign as `v31` `TopologyTransaction` (`com.digitalasset.canton.protocol.v31`). Applications that
decode these transactions, for example to show them to the party before signing, must support `v31`, or set the
new `protocol_version` field of the request to 36 to get `v30` transactions. See the
[migration guide for external signers](#migration-guide-for-external-signers-of-partytoparticipant-transactions).

#### Repair commands represent contracts depending on their reassignment counter

ACS imports and the repair `add`/`purge` commands used either Created/Archive events or
Assigned/Unassigned events for all contracts, depending on `enable-all-ledger-api-reassignments`.
Created/Archive events cannot carry a non-zero reassignment counter, so such contracts could not be
imported when the flag was set to false.

The meaning of the participant parameter
`canton.participants.<participant>.parameters.enable-all-ledger-api-reassignments` has changed:

* `true`: unchanged, all contracts are represented as Assigned (import, add) or Unassigned (purge)
  events.
* `false` (default): contracts with a zero reassignment counter are represented as Created (import,
  add) or Archive (purge) events, contracts with a non-zero reassignment counter are represented as
  Assigned (import, add) or Unassigned (purge) events, preserving the reassignment counter.
  Previously, all contracts were represented as Created/Archive events and the import of contracts
  with a non-zero reassignment counter was rejected.

*Impact and migration:* contracts with a non-zero reassignment counter can now be imported without enabling
`enable-all-ledger-api-reassignments`. Ledger API consumers must be able to process Assigned and
Unassigned events for such contracts.

#### Submission ids of automatic reassignments

When a command requires automatic reassignments, the unassignments and assignments get their own submission ids,
derived from the command's submission id as `<submissionId>-u<uuid>` and `<submissionId>-a<uuid>`, instead of reusing
it. Such a command is rejected with the new error code `INVALID_SUBMISSION_ID` if its submission id is longer than
221 characters.

### Synchronizer operators

#### Sequencer and mediator onboarding transactions

Sequencers and mediators no longer store their onboarding topology transactions in the authorized store during
initialization. Instead of the `node.topology.transactions.identity_transactions()` console command, use
`node.topology.transactions.generate_onboarding_transactions(protocolVersion)`.

With an offline root key, pass a `temporaryStore` seeded with the signed root certificate and a namespace delegation
to an intermediate key on the node, or keep signing the transactions manually.

### Participant node operators

#### The participant repair service requires `enable-repair-commands`

The participant serves the repair admin API (`ParticipantRepairService`) only if
`canton.features.enable-repair-commands = true` (default `false`), like the console repair commands. Set it on
participants whose repair endpoints are called through the admin API.

#### Topology: `propose_delta` no longer moves an Active participant back to Onboarding

The submitting node rejects setting the onboarding flag of an Active `PartyToParticipant` entry on every protocol
version, so `propose_delta` with `requiresPartyToBeOnboarded` no longer moves an Active participant back to
Onboarding. Set `topology.disable-optional-topology-checks` to submit it anyway.

### All node operators

#### Key export requires `enable-key-download`

The admin API `VaultService.ExportKeyPair`, used by the console commands `keys.secret.download` and `download_to`, is
only served if `canton.parameters.enable-key-download = true` (default `false`). Otherwise, calls fail with
`FAILED_PRECONDITION`. The console commands still require
`canton.features.enable-preview-commands = yes`. Enable key download only while you export keys, not in production.

#### Docker images no longer set `non-standard-config`

The default `canton.parameters.non-standard-config = true` has been removed from the Docker images configuration, as
it is not required for the default configuration. Deployments that rely on non-standard configuration options must
set it explicitly.

## Deprecations

* The traffic enforcement Ledger API endpoint `TrafficService.PruneEvents`, the JSON endpoint
  `POST /v2/traffic/events/prune` and the console command `ledger_api.traffic.prune_events` are deprecated. Use
  `TrafficService.Prune` (`POST /v2/traffic/prune`, console `ledger_api.traffic.prune`) instead. They will be disabled by
  default in 3.8 and removed in 3.9. Setting
  `canton.participants.<participant>.features.deprecated.enable-deprecated-endpoints-37 = false` (default `true`)
  disables them earlier, and calls then fail with `DEPRECATED_API_DISABLED`.
* The sequencer configuration `canton.sequencers.<sequencer>.parameters.produce-post-ordering-topology-ticks` is
  deprecated and ignored with a warning: post-ordering topology ticks are always produced.

## Minor Improvements

### Ledger API

* Manual pruning over the Ledger API is iterative, like scheduled pruning, with the maximum offset range of one
  iteration set by `canton.participants.<participant>.parameters.batching.max-pruning-batch-size`. Contract pruning
  is iterative as well, with at most `canton.participants.<participant>.ledger-api.index-service.contract-pruning-batch-size`
  contracts per iteration (default 10000).
* Improved the performance of Ledger API pruning. The query plan change behind it can be turned off with
  `canton.participants.<participant>.ledger-api.index-service.disable-merge-and-hash-joins = false` (default `true`).
* Improved the performance of Ledger API update and active contract streams, and of the paged updates endpoint
  (`GetUpdatesPage`).
* Improved the performance of Ledger API party queries, and party listings now reflect changes to the hosting of
  multi-hosted parties faithfully.
* Unassignments and assignments are rejected with `ContractSerializationVersionNotSupported` if a contract requires a
  higher LF serialization version than the target synchronizer's protocol version supports.
* Increased the log level of Ledger API indexer initialization and termination errors to WARN, except known transient failures that stay on INFO.
* Fixed an internal error when calling `JoseService.GetJwks` for Ed25519 keys.
* When the last locally hosted stakeholder of an unassigned contract is offboarded from the participant, the
  reassignment no longer counts as incomplete from that offset on, so the `StateService` with
  `includeIncompleteReassignments` and the check for stuck assignments no longer report it.

### Synchronizer operators

* Sequencer acknowledgements are now rejected synchronously whenever the sequencer cannot accept them.
* The sequencer reports malformed submission requests with the new error codes
  `SEQUENCER_SUBMISSION_REQUEST_MALFORMED_REJECTED` on protocol version 37 and `SEQUENCER_SUBMISSION_REQUEST_MALFORMED`
  on protocol version 36. The alarm codes `INVALID_ENVELOPE_SIGNATURE` and `MULTIPLE_MEDIATOR_RECIPIENTS` have been
  removed: update alerts that match on them.

### Participant node operators

* The participant status report now tracks the health components of all connected synchronizers instead of only the
  last connected one. Each per-synchronizer component status carries the physical synchronizer id in a new `labels`
  field (`synchronizer` key) of `ComponentStatus` in the health admin API, and the `Components:` section of
  `participant.health.status` renders node-level components as before, followed by a `Synchronizers:` section with the
  component states per connected synchronizer. The status can also be restricted to a single synchronizer via
  `participant.health.status(synchronizerId)` (accepting a logical or physical synchronizer id), backed by a new
  optional `synchronizer_id` field on `ParticipantStatusRequest`.
* Participants validate synchronizer connections (connect, register, modify, migrate) through a temporary sequencer
  connection pool. All validation modes except `DISABLED` now behave like `THRESHOLD_ACTIVE`, so `All` and `Active`
  no longer require every configured sequencer to be reachable. Validation failures are reported as
  `FailedToConnectToSequencers` or `SynchronizerIsNotAvailable`.
* New participant reassignment metrics: `daml.participant.sync.reassignments.submitted`,
  `daml.participant.sync.reassignments.requests`, `daml.participant.sync.reassignments.finalized`,
  `daml.participant.sync.reassignments.batch-size` and `daml.participant.sync.reassignments.unassignment.local-target-timestamp-lag`.
* `repair.purge` rejects contracts that are reassigned away from the synchronizer, or skips them when `ignoreAlreadyPurged` is set.
* To maintain ledger consistency when importing repair events, repair events are now rejected if the last persisted event was a topology event. If this happens, reconnect to the synchronizer to move the record time. If you cannot reconnect, use the `forceRepairWhenTopologyTransactionAtLedgerEnd` flag. Using the force flag can corrupt the data in the system.
* Participants reconnect to a synchronizer faster. On reconnect, the participant looks up its latest request before a
  given time. This lookup could scan the whole request journal and now uses its index.

### All node operators

* New cache configuration `canton.<node>.parameters.caching.transparency-check-cache` (default `maximum-size = 10000`,
  `expire-after-timeout = 5m`) for the results of transparency checks, used if the static synchronizer parameter
  `enable_transparency_checks` is set. It previously shared the session key receiver cache configuration.
* Topology:
  * When a topology transaction submission loses the race against a concurrent topology transaction submission for the same serial, a `TOPOLOGY_SERIAL_MISMATCH` is reported instead of a semantic error related to the content of the transaction.
  * The submitting node now logs an INFO when a topology transaction sent through the queue-based or store-based topology outbox is sequenced but rejected during topology validation.
  * The topology and offline root key scripts can build topology transactions of proto version `v31`, used from
    protocol version 37. They take the protocol version of the synchronizer: `--protocol-version` for
    `prepare-cert.sh`, `interactive_submission.py`, `interactive_topology_example.py` and
    `interactive_topology_example.sh`, an optional last argument for the functions of `topology_util.sh`, and the
    keyword argument `protocol_version` for the Python helpers.
    * **The protocol version defaults to 36**, i.e. to `v30` topology transactions as in earlier releases.
      Synchronizers on protocol versions 36 and 37 accept them.
    * Pass 37 to build `v31` topology transactions for a synchronizer on protocol version 37. Such synchronizers
      accept `v30` only to ease the transition, so switch to 37 once your synchronizers run protocol version 37.
    * `prepare-cert.sh`: keep 36 while the node connects to any synchronizer running protocol version 36, and switch
      to 37 once all of them run it. A node can't convert a certificate signed with the offline root key, so a
      certificate of the wrong version must be prepared again.
    * An unsupported protocol version fails with an explanation of the choices.
  * `prepare-cert.sh` rejects `--intermediate-delegation` combined with `--root-delegation` or `--delegation-restrictions`.
* KMS:
  * Added AWS KMS support for `Ed25519` signing keys like GCP KMS.
  * Fixed creation of Ed25519 keys in GCP KMS to use only the software protection level, because they are not available with HSM protection level.
* Improved error reporting of various admin API endpoints in case of the server being shut down: `ABORTED_DUE_TO_SHUTDOWN` is now reported in some cases instead of internal errors.
* gRPC server handler logs now carry the request's trace id when a client calls with an empty `TraceContext`, for example the sequencer connection pool's `Authenticate`, `Subscribe` and `DownloadTopologyStateForInit`. The client interceptor uses a default trace id when the caller supplied none, instead of sending no `traceparent`.
* Dependency updates to address security vulnerabilities: Bouncy Castle 1.86, gRPC 1.85, jackson 2.22.4, and
  OpenTelemetry and its instrumentation.
* The sequencer aggregator no longer fails on old messages delivered by a lagging sequencer.
* Fixed a regression where the Canton console printed party IDs, synchronizer IDs and other identifiers as raw case
  classes (e.g. `PartyId(uid = UniqueIdentifier(...))`) instead of their compact form.
* The Docker images use da-base-image 1.0.18, whose JDK no longer trusts the eMudhra root CA. TLS certificates that
  chain to it are rejected.

### Daml

* Fixed the transaction trace shown for unhandled exceptions: when the exception passed through
  a try-catch that did not handle it, the trace started at the choice enclosing the try-catch
  instead of the choice where the exception was thrown.

## Compatibility

The following Canton protocol versions are supported:

| Dependency | Version |
| - | - |
| Canton protocol versions | 36, 37 |

Protocol versions 34 and 35 are no longer supported. Upgrade synchronizers on protocol version 34 or 35 to a
supported protocol version with a Canton 3.6 release before upgrading the nodes to this release.

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

| Dependency | Version |
| - | - |
| Java Runtime | OpenJDK 64-Bit Server VM (build 21.0.12+2-nixos, mixed mode, sharing) |
| Postgres | Recommended: PostgreSQL 17.11 (Debian 17.11-1.pgdg13+2) – Also tested: PostgreSQL 14.24 (Debian 14.24-1.pgdg13+2), PostgreSQL 15.19 (Debian 15.19-1.pgdg13+2), PostgreSQL 16.15 (Debian 16.15-1.pgdg13+2), PostgreSQL 17.11 (Debian 17.11-1.pgdg13+2), PostgreSQL 18.6 (Debian 18.6-1.pgdg13+2) |
