Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions UNRELEASED.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# Release of Canton CANTON_VERSION

## Until 2025-04-23 (Exclusive)
- The error code `ABORTED_DUE_TO_SHUTDOWN` is now used instead of the (duplicate) error code `SERVER_IS_SHUTTING_DOWN` that was previously used.

Canton CANTON_VERSION has been released on RELEASE_DATE. You can download the Daml Open Source edition from the Daml Connect [Github Release Section](https://github.com/digital-asset/daml/releases/tag/vCANTON_VERSION). The Enterprise edition is available on [Artifactory](https://digitalasset.jfrog.io/artifactory/canton-enterprise/canton-enterprise-CANTON_VERSION.zip).
Please also consult the [full documentation of this release](https://docs.daml.com/CANTON_VERSION/canton/about.html).

Expand All @@ -12,8 +9,30 @@ schedule, i.e. if you add an entry effective at or after the first
header, prepend the new date header that corresponds to the
Wednesday after your change.

## Until 2025-04-23 (Exclusive)
## Until 2025-04-30 (Exclusive)

### BREAKING CHANGE: Per-synchronizer party allocation
Console commands and API endpoints for allocating/enabling and removing/disabling parties now operate on a per-synchronizer basis.
This means that party allocations must be done explicitly for each synchronizer, and that the participant
must be connected to each synchronizer at the time of enabling or disabling the party.

The console commands `participant.parties.enable` and `participant.parties.disable` have a new parameter `synchronizer: Option[SynchronizerAlias]`
that specifies on which synchronizer the party should be enabled or disabled. The parameter can be "omitted" or set to `None`, if the participant
is connected to only one synchronizer. The parameter `waitForSynchronizer: SynchronizerChoice` has been removed.

The console command `participant.ledger_api.parties.allocate` has a new parameter `synchronizer_id` for specifying the target synchronizer for the party allocation.
Similar to the parameter for the other console commands, this parameter can be omitted if the participant is connected to only one synchronizer.

The Ledger API request `PartyManagementService.AllocatePartyRequest` now has a new field `string synchronizer_id` for specifying the target synchronizer of the party allocation.
Similar to the parameter for the console commands, this parameter can be omitted if the participant is connected to only a one synchronizer.

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

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

## Until 2025-04-23 (Exclusive)
- The error code `ABORTED_DUE_TO_SHUTDOWN` is now used instead of the (duplicate) error code `SERVER_IS_SHUTTING_DOWN` that was previously used.

- JSON API - changed encoding for protobuf based enums.
Following types are now encoded as strings:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,15 @@ object LedgerApiCommands {
partyIdHint: String,
annotations: Map[String, String],
identityProviderId: String,
synchronizerId: String,
) extends BaseCommand[AllocatePartyRequest, AllocatePartyResponse, PartyDetails] {
override protected def createRequest(): Either[String, AllocatePartyRequest] =
Right(
AllocatePartyRequest(
partyIdHint = partyIdHint,
localMetadata = Some(ObjectMeta(resourceVersion = "", annotations = annotations)),
identityProviderId = identityProviderId,
synchronizerId = synchronizerId,
)
)
override protected def submitRequest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import com.digitalasset.canton.topology.*
import com.digitalasset.canton.topology.admin.grpc.{BaseQuery, TopologyStoreId}
import com.digitalasset.canton.topology.admin.v30
import com.digitalasset.canton.topology.admin.v30.*
import com.digitalasset.canton.topology.admin.v30.AuthorizeRequest.Type.{Proposal, TransactionHash}
import com.digitalasset.canton.topology.admin.v30.AuthorizeRequest.Type.{
Proposal,
TransactionHashBytes,
}
import com.digitalasset.canton.topology.admin.v30.IdentityInitializationServiceGrpc.IdentityInitializationServiceStub
import com.digitalasset.canton.topology.admin.v30.TopologyAggregationServiceGrpc.TopologyAggregationServiceStub
import com.digitalasset.canton.topology.admin.v30.TopologyManagerReadServiceGrpc.TopologyManagerReadServiceStub
Expand Down Expand Up @@ -912,7 +915,7 @@ object TopologyAdminCommands {
}

final case class Authorize[M <: TopologyMapping: ClassTag](
transactionHash: String,
transactionHash: ByteString,
mustFullyAuthorize: Boolean,
signedBy: Seq[Fingerprint],
store: TopologyStoreId,
Expand All @@ -925,7 +928,7 @@ object TopologyAdminCommands {

override protected def createRequest(): Either[String, AuthorizeRequest] = Right(
AuthorizeRequest(
TransactionHash(transactionHash),
TransactionHashBytes(transactionHash),
mustFullyAuthorize = mustFullyAuthorize,
forceChanges = Seq.empty,
signedBy = signedBy.map(_.toProtoPrimitive),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,8 @@ object ConsoleEnvironment {
SynchronizerAlias.tryCreate(alias)
implicit def toSynchronizerAliases(aliases: Seq[String]): Seq[SynchronizerAlias] =
aliases.map(SynchronizerAlias.tryCreate)
implicit def toSomeSynchronizerAlias(alias: SynchronizerAlias): Option[SynchronizerAlias] =
Some(alias)

implicit def toInstanceName(name: String): InstanceName = InstanceName.tryCreate(name)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class GrpcAdminCommandRunner(
case _ => awaitTimeout
}

logger.debug(s"Running command $command on $instanceName against $clientConfig")
val resultET = for {
_ <- {
channels.get((instanceName, clientConfig.address, clientConfig.port)) match {
Expand All @@ -104,7 +105,6 @@ class GrpcAdminCommandRunner(
}
}
channel = getOrCreateChannel(instanceName, clientConfig)
_ = logger.debug(s"Running command $command on $instanceName against $clientConfig")
result <- grpcRunner.run(
instanceName,
command,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,14 +486,17 @@ class RepairMacros(override val loggerFactory: NamedLoggerFactory)
partyId: PartyId,
synchronize: Boolean,
)(implicit env: ConsoleEnvironment): Unit = {
// remove any topology transaction that points to source participant
sourceParticipant.topology.party_to_participant_mappings
.propose_delta(
partyId,
removes = List(sourceParticipant.id),
forceFlags = ForceFlags(DisablePartyWithActiveContracts),
)
.discard
sourceParticipant.synchronizers.list_connected().foreach { synchronizer =>
// remove any topology transaction that points to source participant
sourceParticipant.topology.party_to_participant_mappings
.propose_delta(
partyId,
removes = List(sourceParticipant.id),
forceFlags = ForceFlags(DisablePartyWithActiveContracts),
store = synchronizer.synchronizerId,
)
.discard
}
if (synchronize) {
// there's a gap between having received the transaction, but it hasn't been fully processed yet,
// so the node status will return that the node is idle, when that's not really the case.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1542,19 +1542,24 @@ trait BaseLedgerApiAdministration extends NoTracing with StreamingCommandHelper
"""Allocates a new party on the ledger.
party: a hint for generating the party identifier
annotations: key-value pairs associated with this party and stored locally on this Ledger API server
identityProviderId: identity provider id"""
identityProviderId: identity provider id
synchronizerId: The synchronizer on which the party should be allocated.
The participant must be connected to the synchronizer.
The parameter may be omitted if the participant is connected to only one synchronizer."""
)
def allocate(
party: String,
annotations: Map[String, String] = Map.empty,
identityProviderId: String = "",
synchronizerId: String = "",
): PartyDetails = {
val proto = check(FeatureFlag.Testing)(consoleEnvironment.run {
ledgerApiCommand(
LedgerApiCommands.PartyManagementService.AllocateParty(
partyIdHint = party,
annotations = annotations,
identityProviderId = identityProviderId,
synchronizerId = synchronizerId,
)
)
})
Expand Down
Loading
Loading