update canton to 20240709.13636.vd03d4972 (#19547)

Co-authored-by: Azure Pipelines Daml Build <support@digitalasset.com>
Co-authored-by: Remy Haemmerle <Remy.Haemmerle@daml.com>
This commit is contained in:
azure-pipelines[bot] 2024-07-10 09:23:38 +00:00 committed by GitHub
parent 2d6b7f87bc
commit 5078d1e043
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
89 changed files with 656 additions and 596 deletions

View File

@ -11,7 +11,7 @@ import "scalapb/scalapb.proto";
// Schema definition for the exported ACS snapshot // Schema definition for the exported ACS snapshot
message ActiveContract { message ActiveContract {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// The ID of the domain where the contract was assigned at the time of the export // The ID of the domain where the contract was assigned at the time of the export
// Required // Required

View File

@ -5,8 +5,8 @@ object ProtocolVersionAnnotation {
/** Type-level marker for whether a protocol version is stable */ /** Type-level marker for whether a protocol version is stable */
sealed trait Status sealed trait Status
/** Marker for unstable protocol versions */ /** Marker for alpha protocol versions */
sealed trait Unstable extends Status sealed trait Alpha extends Status
/** Marker for stable protocol versions */ /** Marker for stable protocol versions */
sealed trait Stable extends Status sealed trait Stable extends Status
@ -19,17 +19,17 @@ object ProtocolVersionAnnotation {
* that are used in some stable protocol versions * that are used in some stable protocol versions
* *
* Implements both [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Stable]] and * Implements both [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Stable]] and
* [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Unstable]] means that [[StableProtoVersion]] * [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Alpha]] means that [[StableProtoVersion]]
* messages can be used in stable and unstable protocol versions. * messages can be used in stable and alpha protocol versions.
*/ */
trait StableProtoVersion trait StableProtoVersion
extends ProtocolVersionAnnotation.Stable extends ProtocolVersionAnnotation.Stable
with ProtocolVersionAnnotation.Unstable with ProtocolVersionAnnotation.Alpha
/** Marker trait for Protobuf messages generated by scalapb /** Marker trait for Protobuf messages generated by scalapb
* that are used only unstable protocol versions * that are used only alpha protocol versions
*/ */
trait UnstableProtoVersion extends ProtocolVersionAnnotation.Unstable trait AlphaProtoVersion extends ProtocolVersionAnnotation.Alpha
/** Marker trait for Protobuf messages generated by scalapb /** Marker trait for Protobuf messages generated by scalapb
* that are used only to persist data in node storage. * that are used only to persist data in node storage.

View File

@ -4,12 +4,23 @@
package com.digitalasset.canton.admin.api.client.commands package com.digitalasset.canton.admin.api.client.commands
import com.digitalasset.canton.domain.sequencing.sequencer.block.bftordering.admin.EnterpriseSequencerBftAdminData.{ import com.digitalasset.canton.domain.sequencing.sequencer.block.bftordering.admin.EnterpriseSequencerBftAdminData.{
OrderingTopology,
PeerNetworkStatus, PeerNetworkStatus,
endpointToProto, endpointToProto,
} }
import com.digitalasset.canton.networking.Endpoint import com.digitalasset.canton.networking.Endpoint
import com.digitalasset.canton.sequencer.admin.v30 import com.digitalasset.canton.sequencer.admin.v30.SequencerBftAdministrationServiceGrpc.SequencerBftAdministrationServiceStub
import com.digitalasset.canton.sequencer.admin.v30.* import com.digitalasset.canton.sequencer.admin.v30.{
AddPeerEndpointRequest,
AddPeerEndpointResponse,
GetOrderingTopologyRequest,
GetOrderingTopologyResponse,
GetPeerNetworkStatusRequest,
GetPeerNetworkStatusResponse,
RemovePeerEndpointRequest,
RemovePeerEndpointResponse,
SequencerBftAdministrationServiceGrpc,
}
import io.grpc.ManagedChannel import io.grpc.ManagedChannel
import scala.concurrent.Future import scala.concurrent.Future
@ -19,11 +30,11 @@ object EnterpriseSequencerBftAdminCommands {
abstract class BaseSequencerBftAdministrationCommand[Req, Rep, Res] abstract class BaseSequencerBftAdministrationCommand[Req, Rep, Res]
extends GrpcAdminCommand[Req, Rep, Res] { extends GrpcAdminCommand[Req, Rep, Res] {
override type Svc = override type Svc =
v30.SequencerBftAdministrationServiceGrpc.SequencerBftAdministrationServiceStub SequencerBftAdministrationServiceStub
override def createService( override def createService(
channel: ManagedChannel channel: ManagedChannel
): v30.SequencerBftAdministrationServiceGrpc.SequencerBftAdministrationServiceStub = ): SequencerBftAdministrationServiceStub =
v30.SequencerBftAdministrationServiceGrpc.stub(channel) SequencerBftAdministrationServiceGrpc.stub(channel)
} }
final case class AddPeerEndpoint(endpoint: Endpoint) final case class AddPeerEndpoint(endpoint: Endpoint)
@ -38,7 +49,7 @@ object EnterpriseSequencerBftAdminCommands {
) )
override def submitRequest( override def submitRequest(
service: v30.SequencerBftAdministrationServiceGrpc.SequencerBftAdministrationServiceStub, service: SequencerBftAdministrationServiceStub,
request: AddPeerEndpointRequest, request: AddPeerEndpointRequest,
): Future[AddPeerEndpointResponse] = ): Future[AddPeerEndpointResponse] =
service.addPeerEndpoint(request) service.addPeerEndpoint(request)
@ -61,7 +72,7 @@ object EnterpriseSequencerBftAdminCommands {
) )
override def submitRequest( override def submitRequest(
service: v30.SequencerBftAdministrationServiceGrpc.SequencerBftAdministrationServiceStub, service: SequencerBftAdministrationServiceStub,
request: RemovePeerEndpointRequest, request: RemovePeerEndpointRequest,
): Future[RemovePeerEndpointResponse] = ): Future[RemovePeerEndpointResponse] =
service.removePeerEndpoint(request) service.removePeerEndpoint(request)
@ -84,7 +95,7 @@ object EnterpriseSequencerBftAdminCommands {
) )
override def submitRequest( override def submitRequest(
service: v30.SequencerBftAdministrationServiceGrpc.SequencerBftAdministrationServiceStub, service: SequencerBftAdministrationServiceStub,
request: GetPeerNetworkStatusRequest, request: GetPeerNetworkStatusRequest,
): Future[GetPeerNetworkStatusResponse] = ): Future[GetPeerNetworkStatusResponse] =
service.getPeerNetworkStatus(request) service.getPeerNetworkStatus(request)
@ -94,4 +105,27 @@ object EnterpriseSequencerBftAdminCommands {
): Either[String, PeerNetworkStatus] = ): Either[String, PeerNetworkStatus] =
PeerNetworkStatus.fromProto(response) PeerNetworkStatus.fromProto(response)
} }
final case class GetOrderingTopology()
extends BaseSequencerBftAdministrationCommand[
GetOrderingTopologyRequest,
GetOrderingTopologyResponse,
OrderingTopology,
] {
override def createRequest(): Either[String, GetOrderingTopologyRequest] = Right(
GetOrderingTopologyRequest.of()
)
override def submitRequest(
service: SequencerBftAdministrationServiceStub,
request: GetOrderingTopologyRequest,
): Future[GetOrderingTopologyResponse] =
service.getOrderingTopology(request)
override def handleResponse(
response: GetOrderingTopologyResponse
): Either[String, OrderingTopology] =
OrderingTopology.fromProto(response)
}
} }

View File

@ -238,7 +238,7 @@ final case class RetentionPeriodDefaults(
* @param manualStart If set to true, the nodes have to be manually started via console (default false) * @param manualStart If set to true, the nodes have to be manually started via console (default false)
* @param startupParallelism Start up to N nodes in parallel (default is num-threads) * @param startupParallelism Start up to N nodes in parallel (default is num-threads)
* @param nonStandardConfig don't fail config validation on non-standard configuration settings * @param nonStandardConfig don't fail config validation on non-standard configuration settings
* @param devVersionSupport If true, allow domain nodes to use unstable protocol versions and participant nodes to connect to such domains * @param alphaVersionSupport If true, allow domain nodes to use alpha protocol versions and participant nodes to connect to such domains
* @param betaVersionSupport If true, allow domain nodes to use beta protocol versions and participant nodes to connect to such domains * @param betaVersionSupport If true, allow domain nodes to use beta protocol versions and participant nodes to connect to such domains
* @param timeouts Sets the timeouts used for processing and console * @param timeouts Sets the timeouts used for processing and console
* @param portsFile A ports file name, where the ports of all participants will be written to after startup * @param portsFile A ports file name, where the ports of all participants will be written to after startup
@ -252,7 +252,7 @@ final case class CantonParameters(
// TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version // TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version
nonStandardConfig: Boolean = true, nonStandardConfig: Boolean = true,
// TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version // TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version
devVersionSupport: Boolean = true, alphaVersionSupport: Boolean = true,
betaVersionSupport: Boolean = false, betaVersionSupport: Boolean = false,
portsFile: Option[String] = None, portsFile: Option[String] = None,
timeouts: TimeoutSettings = TimeoutSettings(), timeouts: TimeoutSettings = TimeoutSettings(),
@ -380,7 +380,7 @@ trait CantonConfig {
participantParameters.transferTimeProofFreshnessProportion, participantParameters.transferTimeProofFreshnessProportion,
protocolConfig = ParticipantProtocolConfig( protocolConfig = ParticipantProtocolConfig(
minimumProtocolVersion = participantParameters.minimumProtocolVersion.map(_.unwrap), minimumProtocolVersion = participantParameters.minimumProtocolVersion.map(_.unwrap),
devVersionSupport = participantParameters.devVersionSupport, alphaVersionSupport = participantParameters.alphaVersionSupport,
betaVersionSupport = participantParameters.BetaVersionSupport, betaVersionSupport = participantParameters.BetaVersionSupport,
dontWarnOnDeprecatedPV = participantParameters.dontWarnOnDeprecatedPV, dontWarnOnDeprecatedPV = participantParameters.dontWarnOnDeprecatedPV,
), ),
@ -523,7 +523,7 @@ private[canton] object CantonNodeParameterConverter {
def protocol(parent: CantonConfig, config: ProtocolConfig): CantonNodeParameters.Protocol = def protocol(parent: CantonConfig, config: ProtocolConfig): CantonNodeParameters.Protocol =
CantonNodeParameters.Protocol.Impl( CantonNodeParameters.Protocol.Impl(
devVersionSupport = parent.parameters.devVersionSupport || config.devVersionSupport, alphaVersionSupport = parent.parameters.alphaVersionSupport || config.alphaVersionSupport,
betaVersionSupport = parent.parameters.betaVersionSupport || config.betaVersionSupport, betaVersionSupport = parent.parameters.betaVersionSupport || config.betaVersionSupport,
dontWarnOnDeprecatedPV = config.dontWarnOnDeprecatedPV, dontWarnOnDeprecatedPV = config.dontWarnOnDeprecatedPV,
) )

View File

@ -184,14 +184,14 @@ object CommunityConfigValidations
name: String, name: String,
nodeTypeName: String, nodeTypeName: String,
nonStandardConfig: Boolean, nonStandardConfig: Boolean,
devVersionSupport: Boolean, alphaVersionSupport: Boolean,
): Validated[NonEmpty[Seq[String]], Unit] = { ): Validated[NonEmpty[Seq[String]], Unit] = {
Validated.cond( Validated.cond(
nonStandardConfig || !devVersionSupport, nonStandardConfig || !alphaVersionSupport,
(), (),
NonEmpty( NonEmpty(
Seq, Seq,
s"Enabling dev-version-support for $nodeTypeName $name requires you to explicitly set canton.parameters.non-standard-config = yes", s"Enabling alpha-version-support for $nodeTypeName $name requires you to explicitly set canton.parameters.non-standard-config = yes",
), ),
) )
} }
@ -201,7 +201,7 @@ object CommunityConfigValidations
name = name.unwrap, name = name.unwrap,
nodeTypeName = nodeConfig.nodeTypeName, nodeTypeName = nodeConfig.nodeTypeName,
nonStandardConfig = config.parameters.nonStandardConfig, nonStandardConfig = config.parameters.nonStandardConfig,
devVersionSupport = nodeConfig.parameters.devVersionSupport, alphaVersionSupport = nodeConfig.parameters.alphaVersionSupport,
) )
} }

View File

@ -23,7 +23,10 @@ import com.digitalasset.canton.domain.sequencing.config.{
RemoteSequencerConfig, RemoteSequencerConfig,
SequencerNodeConfigCommon, SequencerNodeConfigCommon,
} }
import com.digitalasset.canton.domain.sequencing.sequencer.block.bftordering.admin.EnterpriseSequencerBftAdminData.PeerNetworkStatus import com.digitalasset.canton.domain.sequencing.sequencer.block.bftordering.admin.EnterpriseSequencerBftAdminData.{
OrderingTopology,
PeerNetworkStatus,
}
import com.digitalasset.canton.domain.sequencing.sequencer.{ import com.digitalasset.canton.domain.sequencing.sequencer.{
SequencerClients, SequencerClients,
SequencerPruningStatus, SequencerPruningStatus,
@ -1162,6 +1165,12 @@ abstract class SequencerReference(
consoleEnvironment.run { consoleEnvironment.run {
runner.adminCommand(EnterpriseSequencerBftAdminCommands.GetPeerNetworkStatus(endpoints)) runner.adminCommand(EnterpriseSequencerBftAdminCommands.GetPeerNetworkStatus(endpoints))
} }
@Help.Summary("Get the currently active ordering topology")
def get_ordering_topology(): OrderingTopology =
consoleEnvironment.run {
runner.adminCommand(EnterpriseSequencerBftAdminCommands.GetOrderingTopology())
}
} }
} }

View File

@ -562,9 +562,7 @@ class LocalSecretKeyAdministration(
.leftMap(err => s"Error retrieving private key [$fingerprint] $err") .leftMap(err => s"Error retrieving private key [$fingerprint] $err")
publicKey <- crypto.cryptoPublicStore publicKey <- crypto.cryptoPublicStore
.publicKey(fingerprint) .publicKey(fingerprint)
.leftMap(_.toString) .toRight(s"Error retrieving public key [$fingerprint]: no public key found")
.subflatMap(_.toRight(s"no public key found for [$fingerprint]"))
.leftMap(err => s"Error retrieving public key [$fingerprint] $err")
keyPair: CryptoKeyPair[PublicKey, PrivateKey] = (publicKey, privateKey) match { keyPair: CryptoKeyPair[PublicKey, PrivateKey] = (publicKey, privateKey) match {
case (pub: SigningPublicKey, pkey: SigningPrivateKey) => case (pub: SigningPublicKey, pkey: SigningPrivateKey) =>
new SigningKeyPair(pub, pkey) new SigningKeyPair(pub, pkey)

View File

@ -206,7 +206,7 @@ class ManagedNodes[
for { for {
cAndP <- configAndParams(name) cAndP <- configAndParams(name)
(config, params) = cAndP (config, params) = cAndP
_ <- runMigration(name, config.storage, params.devVersionSupport) _ <- runMigration(name, config.storage, params.alphaVersionSupport)
} yield () } yield ()
} }
) )
@ -216,7 +216,7 @@ class ManagedNodes[
for { for {
cAndP <- configAndParams(name) cAndP <- configAndParams(name)
(config, params) = cAndP (config, params) = cAndP
_ <- runRepairMigration(name, config.storage, params.devVersionSupport) _ <- runRepairMigration(name, config.storage, params.alphaVersionSupport)
} yield () } yield ()
} }
) )
@ -299,7 +299,7 @@ class ManagedNodes[
params: CantonNodeParameters, params: CantonNodeParameters,
): Either[StartupError, Unit] = ): Either[StartupError, Unit] =
runIfUsingDatabase[Id](storageConfig) { dbConfig => runIfUsingDatabase[Id](storageConfig) { dbConfig =>
val migrations = migrationsFactory.create(dbConfig, name, params.devVersionSupport) val migrations = migrationsFactory.create(dbConfig, name, params.alphaVersionSupport)
import TraceContext.Implicits.Empty.* import TraceContext.Implicits.Empty.*
logger.info(s"Setting up database schemas for $name") logger.info(s"Setting up database schemas for $name")
@ -332,11 +332,11 @@ class ManagedNodes[
private def runMigration( private def runMigration(
name: InstanceName, name: InstanceName,
storageConfig: StorageConfig, storageConfig: StorageConfig,
devVersionSupport: Boolean, alphaVersionSupport: Boolean,
): Either[StartupError, Unit] = ): Either[StartupError, Unit] =
runIfUsingDatabase[Id](storageConfig) { dbConfig => runIfUsingDatabase[Id](storageConfig) { dbConfig =>
migrationsFactory migrationsFactory
.create(dbConfig, name, devVersionSupport) .create(dbConfig, name, alphaVersionSupport)
.migrateDatabase() .migrateDatabase()
.leftMap(FailedDatabaseMigration(name, _)) .leftMap(FailedDatabaseMigration(name, _))
.value .value
@ -346,11 +346,11 @@ class ManagedNodes[
private def runRepairMigration( private def runRepairMigration(
name: InstanceName, name: InstanceName,
storageConfig: StorageConfig, storageConfig: StorageConfig,
devVersionSupport: Boolean, alphaVersionSupport: Boolean,
): Either[StartupError, Unit] = ): Either[StartupError, Unit] =
runIfUsingDatabase[Id](storageConfig) { dbConfig => runIfUsingDatabase[Id](storageConfig) { dbConfig =>
migrationsFactory migrationsFactory
.create(dbConfig, name, devVersionSupport) .create(dbConfig, name, alphaVersionSupport)
.repairFlywayMigration() .repairFlywayMigration()
.leftMap(FailedDatabaseRepairMigration(name, _)) .leftMap(FailedDatabaseRepairMigration(name, _))
.value .value

View File

@ -3,15 +3,15 @@
// anymore. // anymore.
_shared { _shared {
participant-dev-params = { participant-dev-params = {
dev-version-support = true alpha-version-support = true
} }
// domain parameters config // domain parameters config
domain-dev-params = { domain-dev-params = {
dev-version-support = true alpha-version-support = true
protocol-version = dev protocol-version = dev
} }
} }
canton.parameters { canton.parameters {
non-standard-config = yes non-standard-config = yes
dev-version-support = yes alpha-version-support = yes
} }

View File

@ -0,0 +1,14 @@
canton.parameters {
# turn on non-standard configuration support
non-standard-config = yes
# turn on support of alpha version support for domain nodes
alpha-version-support = yes
}
canton.participants.participant1.parameters = {
# enable alpha version support on the participant (this will allow the participant to connect to a domain running protocol version dev or any other alpha protocol)
# and it will turn on support for unsafe daml lf dev versions
# not to be used in production and requires you to define non-standard-config = yes
alpha-version-support = yes
}

View File

@ -2,13 +2,13 @@ canton.parameters {
# turn on non-standard configuration support # turn on non-standard configuration support
non-standard-config = yes non-standard-config = yes
# turn on support of development version support for domain nodes # turn on support of alpha version support for domain nodes
dev-version-support = yes alpha-version-support = yes
} }
canton.participants.participant1.parameters = { canton.participants.participant1.parameters = {
# enable dev version on the participant (this will allow the participant to connect to a domain with dev protocol version) # enable alpha version support on the participant (this will allow the participant to connect to a domain with dev protocol version)
# and it will turn on support for unsafe daml lf dev versions # and it will turn on support for unsafe daml lf dev versions
# not to be used in production and requires you to define non-standard-config = yes # not to be used in production and requires you to define non-standard-config = yes
dev-version-support = yes alpha-version-support = yes
} }

View File

@ -78,7 +78,7 @@ class NodesTest extends FixtureAnyWordSpec with BaseTest with HasExecutionContex
override def batching: BatchingConfig = BatchingConfig() override def batching: BatchingConfig = BatchingConfig()
override def caching: CachingConfigs = CachingConfigs() override def caching: CachingConfigs = CachingConfigs()
override def useUnifiedSequencer: Boolean = false override def useUnifiedSequencer: Boolean = false
override def devVersionSupport: Boolean = false override def alphaVersionSupport: Boolean = false
override def watchdog: Option[WatchdogConfig] = None override def watchdog: Option[WatchdogConfig] = None
} }
} }
@ -97,7 +97,7 @@ class NodesTest extends FixtureAnyWordSpec with BaseTest with HasExecutionContex
nonStandardConfig: Boolean = false, nonStandardConfig: Boolean = false,
dbMigrateAndStart: Boolean = false, dbMigrateAndStart: Boolean = false,
disableUpgradeValidation: Boolean = false, disableUpgradeValidation: Boolean = false,
devVersionSupport: Boolean = false, alphaVersionSupport: Boolean = false,
betaVersionSupport: Boolean = false, betaVersionSupport: Boolean = false,
dontWarnOnDeprecatedPV: Boolean = false, dontWarnOnDeprecatedPV: Boolean = false,
initialProtocolVersion: ProtocolVersion = testedProtocolVersion, initialProtocolVersion: ProtocolVersion = testedProtocolVersion,

View File

@ -202,7 +202,7 @@ message AcknowledgeSignedRequest {
message AcknowledgeSignedResponse {} message AcknowledgeSignedResponse {}
message DownloadTopologyStateForInitRequest { message DownloadTopologyStateForInitRequest {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
string member = 1; string member = 1;
} }
@ -212,7 +212,7 @@ message DownloadTopologyStateForInitResponse {
} }
message GetTrafficStateForMemberRequest { message GetTrafficStateForMemberRequest {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// Member for which to get the traffic state // Member for which to get the traffic state
string member = 1; string member = 1;
@ -221,7 +221,7 @@ message GetTrafficStateForMemberRequest {
} }
message GetTrafficStateForMemberResponse { message GetTrafficStateForMemberResponse {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
com.digitalasset.canton.protocol.v30.TrafficState traffic_state = 1; com.digitalasset.canton.protocol.v30.TrafficState traffic_state = 1;
} }

View File

@ -30,7 +30,7 @@ message GlobalKey {
} }
message AggregationRule { message AggregationRule {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// Members who are allowed to send a request for the underlying aggregation. // Members who are allowed to send a request for the underlying aggregation.
// Must contain SubmissionRequest.sender, otherwise the request is rejected. // Must contain SubmissionRequest.sender, otherwise the request is rejected.

View File

@ -11,7 +11,7 @@ import "scalapb/scalapb.proto";
// Definition of the ConfirmationResponse message which is shared between the transaction and transfer protocol // Definition of the ConfirmationResponse message which is shared between the transaction and transfer protocol
message LocalVerdict { message LocalVerdict {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
VerdictCode code = 1; VerdictCode code = 1;
google.rpc.Status reason = 2; // ok iff code is approve google.rpc.Status reason = 2; // ok iff code is approve
@ -25,7 +25,7 @@ message LocalVerdict {
} }
message ConfirmationResponse { message ConfirmationResponse {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
int64 request_id = 1; // in microseconds of UTC time since Unix epoch int64 request_id = 1; // in microseconds of UTC time since Unix epoch
string sender = 2; string sender = 2;

View File

@ -47,7 +47,7 @@ enum OnboardingRestriction {
} }
message DynamicDomainParameters { message DynamicDomainParameters {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
google.protobuf.Duration confirmation_response_timeout = 1; google.protobuf.Duration confirmation_response_timeout = 1;
google.protobuf.Duration mediator_reaction_timeout = 2; google.protobuf.Duration mediator_reaction_timeout = 2;

View File

@ -35,7 +35,7 @@ message MediatorReject {
} }
message Verdict { message Verdict {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
oneof some_verdict { oneof some_verdict {
google.protobuf.Empty approve = 1; google.protobuf.Empty approve = 1;
@ -46,7 +46,7 @@ message Verdict {
// This covers transactions and transfers // This covers transactions and transfers
message ConfirmationResultMessage { message ConfirmationResultMessage {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
string domain_id = 1; string domain_id = 1;
com.digitalasset.canton.protocol.v30.ViewType view_type = 2; com.digitalasset.canton.protocol.v30.ViewType view_type = 2;

View File

@ -9,7 +9,7 @@ import "google/protobuf/wrappers.proto";
import "scalapb/scalapb.proto"; import "scalapb/scalapb.proto";
message OrderingRequest { message OrderingRequest {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
string sequencer_uid = 1; // UID of the sequencer requesting ordering of the request string sequencer_uid = 1; // UID of the sequencer requesting ordering of the request
google.protobuf.BytesValue content = 2; // Content of the request to be ordered google.protobuf.BytesValue content = 2; // Content of the request to be ordered

View File

@ -63,7 +63,7 @@ message ViewCommonData {
} }
message Informee { message Informee {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
string party = 1; string party = 1;
int32 weight = 2; // optional: only set if party is confirming int32 weight = 2; // optional: only set if party is confirming
@ -87,14 +87,14 @@ message ViewParticipantMessage {
// InformeeMessage // InformeeMessage
message InformeeMessage { message InformeeMessage {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
FullInformeeTree full_informee_tree = 1; FullInformeeTree full_informee_tree = 1;
com.digitalasset.canton.crypto.v30.Signature submitting_participant_signature = 2; com.digitalasset.canton.crypto.v30.Signature submitting_participant_signature = 2;
} }
message LightTransactionViewTree { message LightTransactionViewTree {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
GenTransactionTree tree = 1; GenTransactionTree tree = 1;
repeated bytes subview_hashes = 2; repeated bytes subview_hashes = 2;
@ -118,7 +118,7 @@ message InputContract {
} }
message CommonMetadata { message CommonMetadata {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
com.digitalasset.canton.crypto.v30.Salt salt = 1; com.digitalasset.canton.crypto.v30.Salt salt = 1;
// this used to contain a confirmation policy (Signatory or VIP) that no longer exists // this used to contain a confirmation policy (Signatory or VIP) that no longer exists
@ -129,7 +129,7 @@ message CommonMetadata {
} }
message SubmitterMetadata { message SubmitterMetadata {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
com.digitalasset.canton.crypto.v30.Salt salt = 1; com.digitalasset.canton.crypto.v30.Salt salt = 1;
repeated string act_as = 2; repeated string act_as = 2;
@ -153,7 +153,7 @@ message SessionKeyLookup {
} }
message EncryptedViewMessage { message EncryptedViewMessage {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
bytes view_tree = 1; bytes view_tree = 1;

View File

@ -21,7 +21,7 @@ message TransferId {
// Messages sent by a participant as part of the transfer protocol // Messages sent by a participant as part of the transfer protocol
message TransferOutCommonData { message TransferOutCommonData {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
com.digitalasset.canton.crypto.v30.Salt salt = 1; com.digitalasset.canton.crypto.v30.Salt salt = 1;
string source_domain = 2; string source_domain = 2;
@ -33,7 +33,7 @@ message TransferOutCommonData {
} }
message TransferViewTree { message TransferViewTree {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
bytes common_data = 1; bytes common_data = 1;
BlindableNode participant_data = 2; BlindableNode participant_data = 2;
@ -47,14 +47,14 @@ message TransferInMediatorMessage {
} }
message TransferOutMediatorMessage { message TransferOutMediatorMessage {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
TransferViewTree tree = 1; TransferViewTree tree = 1;
com.digitalasset.canton.crypto.v30.Signature submitting_participant_signature = 2; com.digitalasset.canton.crypto.v30.Signature submitting_participant_signature = 2;
} }
message TransferInCommonData { message TransferInCommonData {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
com.digitalasset.canton.crypto.v30.Salt salt = 1; com.digitalasset.canton.crypto.v30.Salt salt = 1;
string target_domain = 2; string target_domain = 2;
@ -65,7 +65,7 @@ message TransferInCommonData {
} }
message TransferSubmitterMetadata { message TransferSubmitterMetadata {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
string submitter = 1; string submitter = 1;
string submitting_participant_uid = 2; string submitting_participant_uid = 2;
@ -76,7 +76,7 @@ message TransferSubmitterMetadata {
} }
message TransferOutView { message TransferOutView {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
com.digitalasset.canton.crypto.v30.Salt salt = 1; com.digitalasset.canton.crypto.v30.Salt salt = 1;
string target_domain = 3; string target_domain = 3;
@ -88,7 +88,7 @@ message TransferOutView {
} }
message TransferInView { message TransferInView {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
com.digitalasset.canton.crypto.v30.Salt salt = 1; com.digitalasset.canton.crypto.v30.Salt salt = 1;
v30.SerializableContract contract = 3; v30.SerializableContract contract = 3;

View File

@ -73,7 +73,7 @@ message Handshake {
// Submission cost computed by the sender for a SubmissionRequest // Submission cost computed by the sender for a SubmissionRequest
message SequencingSubmissionCost { message SequencingSubmissionCost {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// Computed cost // Computed cost
int64 cost = 1; int64 cost = 1;
} }
@ -90,7 +90,7 @@ message StaticDomainParameters {
} }
message Envelope { message Envelope {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// Contains a v30.EnvelopeContent if signatures are empty and a v30.TypedSignedProtocolMessageContent otherwise // Contains a v30.EnvelopeContent if signatures are empty and a v30.TypedSignedProtocolMessageContent otherwise
bytes content = 1; bytes content = 1;
@ -102,13 +102,13 @@ message Envelope {
} }
message Batch { message Batch {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
repeated Envelope envelopes = 1; repeated Envelope envelopes = 1;
} }
message CompressedBatch { message CompressedBatch {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
enum CompressionAlgorithm { enum CompressionAlgorithm {
COMPRESSION_ALGORITHM_UNSPECIFIED = 0; COMPRESSION_ALGORITHM_UNSPECIFIED = 0;
@ -121,7 +121,7 @@ message CompressedBatch {
} }
message SequencedEvent { message SequencedEvent {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// A sequence number for all events emitted to a subscriber. Starting at 0. // A sequence number for all events emitted to a subscriber. Starting at 0.
// The same event may have different counter values for different recipients. // The same event may have different counter values for different recipients.
@ -158,7 +158,7 @@ message SequencedEvent {
// Messages used for synchronization between sequencer nodes // Messages used for synchronization between sequencer nodes
message SubmissionRequest { message SubmissionRequest {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// Sender of the request. // Sender of the request.
// This request must be wrapped in a SignedContent and // This request must be wrapped in a SignedContent and

View File

@ -8,7 +8,7 @@ package com.digitalasset.canton.protocol.v30;
import "scalapb/scalapb.proto"; import "scalapb/scalapb.proto";
message DynamicSequencingParameters { message DynamicSequencingParameters {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// Sequencing dynamic domain parameters can only be interpreted by a sequencer implementation // Sequencing dynamic domain parameters can only be interpreted by a sequencer implementation
// and are opaque to the rest of the domain. // and are opaque to the rest of the domain.

View File

@ -10,7 +10,7 @@ import "google/protobuf/wrappers.proto";
import "scalapb/scalapb.proto"; import "scalapb/scalapb.proto";
message SignedContent { message SignedContent {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
google.protobuf.BytesValue content = 1; google.protobuf.BytesValue content = 1;
repeated com.digitalasset.canton.crypto.v30.Signature signatures = 2; repeated com.digitalasset.canton.crypto.v30.Signature signatures = 2;

View File

@ -14,7 +14,7 @@ import "scalapb/scalapb.proto";
// Messages depending on both participant_transaction.proto and participant_transfer.proto. // Messages depending on both participant_transaction.proto and participant_transfer.proto.
message TypedSignedProtocolMessageContent { message TypedSignedProtocolMessageContent {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
oneof some_signed_protocol_message { oneof some_signed_protocol_message {
bytes confirmation_response = 2; bytes confirmation_response = 2;
@ -25,14 +25,14 @@ message TypedSignedProtocolMessageContent {
} }
message SignedProtocolMessage { message SignedProtocolMessage {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
repeated com.digitalasset.canton.crypto.v30.Signature signature = 1; repeated com.digitalasset.canton.crypto.v30.Signature signature = 1;
bytes typed_signed_protocol_message_content = 2; bytes typed_signed_protocol_message_content = 2;
} }
message EnvelopeContent { message EnvelopeContent {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
oneof some_envelope_content { oneof some_envelope_content {
v30.InformeeMessage informee_message = 1; v30.InformeeMessage informee_message = 1;

View File

@ -323,7 +323,7 @@ message TopologyMapping {
} }
message TopologyTransaction { message TopologyTransaction {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
Enums.TopologyChangeOp operation = 1; Enums.TopologyChangeOp operation = 1;
@ -337,7 +337,7 @@ message TopologyTransaction {
} }
message SignedTopologyTransaction { message SignedTopologyTransaction {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// serialized topology transaction (protobuf bytestring) // serialized topology transaction (protobuf bytestring)
bytes transaction = 1; bytes transaction = 1;
@ -359,7 +359,7 @@ message SignedTopologyTransaction {
* including the member the submitted the broadcast. * including the member the submitted the broadcast.
*/ */
message TopologyTransactionsBroadcast { message TopologyTransactionsBroadcast {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
message Broadcast { message Broadcast {
string broadcast_id = 1; string broadcast_id = 1;

View File

@ -10,7 +10,7 @@ import "google/protobuf/wrappers.proto";
import "scalapb/scalapb.proto"; import "scalapb/scalapb.proto";
message TrafficControlParameters { message TrafficControlParameters {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// In bytes, the maximum amount of base traffic that can be accumulated // In bytes, the maximum amount of base traffic that can be accumulated
uint64 max_base_traffic_amount = 1; uint64 max_base_traffic_amount = 1;
@ -34,7 +34,7 @@ message TrafficControlParameters {
// Message representing a traffic receipt included in SequencedEvent receipts to update sender about // Message representing a traffic receipt included in SequencedEvent receipts to update sender about
// the traffic consumed state after sequencing of the event // the traffic consumed state after sequencing of the event
message TrafficReceipt { message TrafficReceipt {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// Cost effectively consumed by this specific event // Cost effectively consumed by this specific event
uint64 consumed_cost = 1; uint64 consumed_cost = 1;
// Total amount of extra traffic consumed // Total amount of extra traffic consumed
@ -45,7 +45,7 @@ message TrafficReceipt {
// Message representing traffic consumed by a member at a given point in time // Message representing traffic consumed by a member at a given point in time
message TrafficConsumed { message TrafficConsumed {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// Member consuming the traffic // Member consuming the traffic
string member = 1; string member = 1;
// Total extra traffic consumed // Total extra traffic consumed
@ -60,7 +60,7 @@ message TrafficConsumed {
// Message representing a traffic purchase made on behalf of a member // Message representing a traffic purchase made on behalf of a member
message TrafficPurchased { message TrafficPurchased {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// Member receiving the traffic // Member receiving the traffic
string member = 1; string member = 1;
// Serial of the update // Serial of the update
@ -88,7 +88,7 @@ message TrafficState {
} }
message SetTrafficPurchasedMessage { message SetTrafficPurchasedMessage {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
// Member to update the balance for // Member to update the balance for
string member = 1; string member = 1;

View File

@ -242,10 +242,10 @@ object CommunityStorageConfig {
trait DbConfig extends StorageConfig with PrettyPrinting { trait DbConfig extends StorageConfig with PrettyPrinting {
/** Function to combine the defined migration path together with dev version changes */ /** Function to combine the defined migration path together with dev version changes */
final def buildMigrationsPaths(devVersionSupport: Boolean): Seq[String] = { final def buildMigrationsPaths(alphaVersionSupport: Boolean): Seq[String] = {
if (parameters.migrationsPaths.nonEmpty) if (parameters.migrationsPaths.nonEmpty)
parameters.migrationsPaths parameters.migrationsPaths
else if (devVersionSupport) else if (alphaVersionSupport)
Seq(stableMigrationPath, devMigrationPath) Seq(stableMigrationPath, devMigrationPath)
else Seq(stableMigrationPath) else Seq(stableMigrationPath)
} }

View File

@ -46,9 +46,7 @@ class Crypto(
): EitherT[FutureUnlessShutdown, SigningKeyGenerationError, SigningPublicKey] = ): EitherT[FutureUnlessShutdown, SigningKeyGenerationError, SigningPublicKey] =
for { for {
publicKey <- privateCrypto.generateSigningKey(scheme, name) publicKey <- privateCrypto.generateSigningKey(scheme, name)
_ <- cryptoPublicStore _ <- EitherT.right(cryptoPublicStore.storeSigningKey(publicKey, name))
.storeSigningKey(publicKey, name)
.leftMap[SigningKeyGenerationError](SigningKeyGenerationError.SigningPublicStoreError)
} yield publicKey } yield publicKey
/** Helper method to generate a new encryption key pair and store the public key in the public store as well. */ /** Helper method to generate a new encryption key pair and store the public key in the public store as well. */
@ -60,11 +58,7 @@ class Crypto(
): EitherT[FutureUnlessShutdown, EncryptionKeyGenerationError, EncryptionPublicKey] = ): EitherT[FutureUnlessShutdown, EncryptionKeyGenerationError, EncryptionPublicKey] =
for { for {
publicKey <- privateCrypto.generateEncryptionKey(scheme, name) publicKey <- privateCrypto.generateEncryptionKey(scheme, name)
_ <- cryptoPublicStore _ <- EitherT.right(cryptoPublicStore.storeEncryptionKey(publicKey, name))
.storeEncryptionKey(publicKey, name)
.leftMap[EncryptionKeyGenerationError](
EncryptionKeyGenerationError.EncryptionPublicStoreError
)
} yield publicKey } yield publicKey
override def onClosed(): Unit = override def onClosed(): Unit =

View File

@ -457,9 +457,15 @@ object EncryptionPublicKey
final case class EncryptionPublicKeyWithName( final case class EncryptionPublicKeyWithName(
override val publicKey: EncryptionPublicKey, override val publicKey: EncryptionPublicKey,
override val name: Option[KeyName], override val name: Option[KeyName],
) extends PublicKeyWithName { ) extends PublicKeyWithName
with PrettyPrinting {
type K = EncryptionPublicKey type K = EncryptionPublicKey
override val id: Fingerprint = publicKey.id override val id: Fingerprint = publicKey.id
override def pretty: Pretty[EncryptionPublicKeyWithName] =
prettyOfClass(param("publicKey", _.publicKey), param("name", _.name))
} }
object EncryptionPublicKeyWithName { object EncryptionPublicKeyWithName {

View File

@ -387,9 +387,15 @@ object SigningPublicKey
final case class SigningPublicKeyWithName( final case class SigningPublicKeyWithName(
override val publicKey: SigningPublicKey, override val publicKey: SigningPublicKey,
override val name: Option[KeyName], override val name: Option[KeyName],
) extends PublicKeyWithName { ) extends PublicKeyWithName
with PrettyPrinting {
type K = SigningPublicKey type K = SigningPublicKey
override val id: Fingerprint = publicKey.id override val id: Fingerprint = publicKey.id
override def pretty: Pretty[SigningPublicKeyWithName] =
prettyOfClass(param("publicKey", _.publicKey), param("name", _.name))
} }
object SigningPublicKeyWithName { object SigningPublicKeyWithName {

View File

@ -3,13 +3,14 @@
package com.digitalasset.canton.crypto.store package com.digitalasset.canton.crypto.store
import cats.data.EitherT import cats.data.OptionT
import cats.syntax.functor.* import cats.syntax.functor.*
import com.daml.error.{ErrorCategory, ErrorCode, Explanation, Resolution} import com.daml.error.{ErrorCategory, ErrorCode, Explanation, Resolution}
import com.digitalasset.canton.config.ProcessingTimeout import com.digitalasset.canton.config.ProcessingTimeout
import com.digitalasset.canton.crypto.store.db.DbCryptoPublicStore import com.digitalasset.canton.crypto.store.db.DbCryptoPublicStore
import com.digitalasset.canton.crypto.store.memory.InMemoryCryptoPublicStore import com.digitalasset.canton.crypto.store.memory.InMemoryCryptoPublicStore
import com.digitalasset.canton.crypto.{KeyName, *} import com.digitalasset.canton.crypto.{KeyName, *}
import com.digitalasset.canton.discard.Implicits.DiscardOps
import com.digitalasset.canton.error.{BaseCantonError, CantonErrorGroups} import com.digitalasset.canton.error.{BaseCantonError, CantonErrorGroups}
import com.digitalasset.canton.lifecycle.FutureUnlessShutdown import com.digitalasset.canton.lifecycle.FutureUnlessShutdown
import com.digitalasset.canton.logging.NamedLoggerFactory import com.digitalasset.canton.logging.NamedLoggerFactory
@ -34,31 +35,25 @@ trait CryptoPublicStore extends AutoCloseable {
// Write methods that the underlying store has to implement for the caching // Write methods that the underlying store has to implement for the caching
protected def writeSigningKey(key: SigningPublicKey, name: Option[KeyName])(implicit protected def writeSigningKey(key: SigningPublicKey, name: Option[KeyName])(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Unit] ): FutureUnlessShutdown[Unit]
protected def writeEncryptionKey(key: EncryptionPublicKey, name: Option[KeyName])(implicit protected def writeEncryptionKey(key: EncryptionPublicKey, name: Option[KeyName])(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Unit] ): FutureUnlessShutdown[Unit]
protected[crypto] def listAllKeyFingerprints(implicit
traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[Fingerprint]] =
for {
signingKeys <- listSigningKeys
encryptionKeys <- listEncryptionKeys
} yield signingKeys.map(_.publicKey.id) ++ encryptionKeys.map(_.publicKey.id)
@VisibleForTesting @VisibleForTesting
private[store] def listSigningKeys(implicit private[store] def listSigningKeys(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[SigningPublicKeyWithName]] ): FutureUnlessShutdown[Set[SigningPublicKeyWithName]]
@VisibleForTesting @VisibleForTesting
private[store] def listEncryptionKeys(implicit private[store] def listEncryptionKeys(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[EncryptionPublicKeyWithName]] ): FutureUnlessShutdown[Set[EncryptionPublicKeyWithName]]
def storePublicKey(publicKey: PublicKey, name: Option[KeyName])(implicit def storePublicKey(publicKey: PublicKey, name: Option[KeyName])(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Unit] = ): FutureUnlessShutdown[Unit] =
(publicKey: @unchecked) match { (publicKey: @unchecked) match {
case sigKey: SigningPublicKey => storeSigningKey(sigKey, name) case sigKey: SigningPublicKey => storeSigningKey(sigKey, name)
case encKey: EncryptionPublicKey => storeEncryptionKey(encKey, name) case encKey: EncryptionPublicKey => storeEncryptionKey(encKey, name)
@ -66,50 +61,35 @@ trait CryptoPublicStore extends AutoCloseable {
def publicKey(keyId: Fingerprint)(implicit def publicKey(keyId: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[PublicKey]] = ): OptionT[FutureUnlessShutdown, PublicKey] =
publicKeyWithName(keyId).map(_.map(_.publicKey)) readSigningKey(keyId)
.widen[PublicKeyWithName]
def publicKeyWithName(keyId: Fingerprint)(implicit .orElse(readEncryptionKey(keyId).widen[PublicKeyWithName])
traceContext: TraceContext .map(_.publicKey)
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[PublicKeyWithName]] =
for {
sigKeyOption <- readSigningKey(keyId)
pubKeyOption <- sigKeyOption.fold(readEncryptionKey(keyId).widen[Option[PublicKeyWithName]])(
key => EitherT.rightT(Some(key))
)
} yield pubKeyOption
def existsPublicKey(keyId: Fingerprint, purpose: KeyPurpose)(implicit
traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Boolean] =
purpose match {
case KeyPurpose.Signing => signingKey(keyId).map(_.nonEmpty)
case KeyPurpose.Encryption => encryptionKey(keyId).map(_.nonEmpty)
}
def findSigningKeyIdByName(keyName: KeyName)(implicit def findSigningKeyIdByName(keyName: KeyName)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[SigningPublicKey]] = ): OptionT[FutureUnlessShutdown, SigningPublicKey] =
listSigningKeys.map(_.find(_.name.contains(keyName)).map(_.publicKey)) OptionT(listSigningKeys.map(_.find(_.name.contains(keyName)).map(_.publicKey)))
def findSigningKeyIdByFingerprint(fingerprint: Fingerprint)(implicit def findSigningKeyIdByFingerprint(fingerprint: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[SigningPublicKey]] = ): OptionT[FutureUnlessShutdown, SigningPublicKey] =
listSigningKeys.map(_.find(_.publicKey.fingerprint == fingerprint).map(_.publicKey)) OptionT(listSigningKeys.map(_.find(_.publicKey.fingerprint == fingerprint).map(_.publicKey)))
def findEncryptionKeyIdByName(keyName: KeyName)(implicit def findEncryptionKeyIdByName(keyName: KeyName)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[EncryptionPublicKey]] = ): OptionT[FutureUnlessShutdown, EncryptionPublicKey] =
listEncryptionKeys.map(_.find(_.name.contains(keyName)).map(_.publicKey)) OptionT(listEncryptionKeys.map(_.find(_.name.contains(keyName)).map(_.publicKey)))
def findEncryptionKeyIdByFingerprint(fingerprint: Fingerprint)(implicit def findEncryptionKeyIdByFingerprint(fingerprint: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[EncryptionPublicKey]] = ): OptionT[FutureUnlessShutdown, EncryptionPublicKey] =
listEncryptionKeys.map(_.find(_.publicKey.fingerprint == fingerprint).map(_.publicKey)) OptionT(listEncryptionKeys.map(_.find(_.publicKey.fingerprint == fingerprint).map(_.publicKey)))
def publicKeysWithName(implicit def publicKeysWithName(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[PublicKeyWithName]] = ): FutureUnlessShutdown[Set[PublicKeyWithName]] =
for { for {
sigKeys <- listSigningKeys sigKeys <- listSigningKeys
encKeys <- listEncryptionKeys encKeys <- listEncryptionKeys
@ -117,64 +97,68 @@ trait CryptoPublicStore extends AutoCloseable {
def signingKey(signingKeyId: Fingerprint)(implicit def signingKey(signingKeyId: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[SigningPublicKey]] = ): OptionT[FutureUnlessShutdown, SigningPublicKey] =
retrieveKeyAndUpdateCache(signingKeyMap, readSigningKey(_))(signingKeyId) retrieveKeyAndUpdateCache(signingKeyMap, readSigningKey(_))(signingKeyId)
protected def readSigningKey(signingKeyId: Fingerprint)(implicit protected def readSigningKey(signingKeyId: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[SigningPublicKeyWithName]] ): OptionT[FutureUnlessShutdown, SigningPublicKeyWithName]
def signingKeys(implicit def signingKeys(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[SigningPublicKey]] = ): FutureUnlessShutdown[Set[SigningPublicKey]] =
retrieveKeysAndUpdateCache(listSigningKeys, signingKeyMap) retrieveKeysAndUpdateCache(listSigningKeys, signingKeyMap)
def storeSigningKey(key: SigningPublicKey, name: Option[KeyName] = None)(implicit def storeSigningKey(key: SigningPublicKey, name: Option[KeyName] = None)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Unit] = ): FutureUnlessShutdown[Unit] =
writeSigningKey(key, name).map { _ => writeSigningKey(key, name).map { _ =>
val _ = signingKeyMap.put(key.id, SigningPublicKeyWithName(key, name)) signingKeyMap.put(key.id, SigningPublicKeyWithName(key, name)).discard
} }
def encryptionKey(encryptionKeyId: Fingerprint)(implicit def encryptionKey(encryptionKeyId: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[EncryptionPublicKey]] = ): OptionT[FutureUnlessShutdown, EncryptionPublicKey] =
retrieveKeyAndUpdateCache(encryptionKeyMap, readEncryptionKey(_))(encryptionKeyId) retrieveKeyAndUpdateCache(encryptionKeyMap, readEncryptionKey(_))(encryptionKeyId)
protected def readEncryptionKey(encryptionKeyId: Fingerprint)(implicit protected def readEncryptionKey(encryptionKeyId: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[EncryptionPublicKeyWithName]] ): OptionT[FutureUnlessShutdown, EncryptionPublicKeyWithName]
def encryptionKeys(implicit def encryptionKeys(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[EncryptionPublicKey]] = ): FutureUnlessShutdown[Set[EncryptionPublicKey]] =
retrieveKeysAndUpdateCache(listEncryptionKeys, encryptionKeyMap) retrieveKeysAndUpdateCache(listEncryptionKeys, encryptionKeyMap)
def storeEncryptionKey(key: EncryptionPublicKey, name: Option[KeyName] = None)(implicit def storeEncryptionKey(key: EncryptionPublicKey, name: Option[KeyName] = None)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Unit] = ): FutureUnlessShutdown[Unit] =
writeEncryptionKey(key, name) writeEncryptionKey(key, name)
.map { _ => .map { _ =>
val _ = encryptionKeyMap.put(key.id, EncryptionPublicKeyWithName(key, name)) encryptionKeyMap.put(key.id, EncryptionPublicKeyWithName(key, name)).discard
} }
private[crypto] def deleteKey(keyId: Fingerprint)(implicit
traceContext: TraceContext
): FutureUnlessShutdown[Unit]
private def retrieveKeyAndUpdateCache[KN <: PublicKeyWithName]( private def retrieveKeyAndUpdateCache[KN <: PublicKeyWithName](
cache: TrieMap[Fingerprint, KN], cache: TrieMap[Fingerprint, KN],
readKey: Fingerprint => EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[KN]], readKey: Fingerprint => OptionT[FutureUnlessShutdown, KN],
)(keyId: Fingerprint): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[KN#K]] = )(keyId: Fingerprint): OptionT[FutureUnlessShutdown, KN#K] =
cache.get(keyId) match { cache.get(keyId) match {
case Some(value) => EitherT.rightT(Some(value.publicKey)) case Some(key) => OptionT.some(key.publicKey)
case None => case None =>
readKey(keyId).map { keyOption => readKey(keyId).map { key =>
keyOption.foreach(key => cache.putIfAbsent(keyId, key)) cache.putIfAbsent(keyId, key).discard
keyOption.map(_.publicKey) key.publicKey
} }
} }
private def retrieveKeysAndUpdateCache[KN <: PublicKeyWithName]( private def retrieveKeysAndUpdateCache[KN <: PublicKeyWithName](
keysFromDb: EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[KN]], keysFromDb: FutureUnlessShutdown[Set[KN]],
cache: TrieMap[Fingerprint, KN], cache: TrieMap[Fingerprint, KN],
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[KN#K]] = ): FutureUnlessShutdown[Set[KN#K]] =
for { for {
// we always rebuild the cache here just in case new keys have been added by another process // we always rebuild the cache here just in case new keys have been added by another process
// this should not be a problem since these operations to get all keys are infrequent and typically // this should not be a problem since these operations to get all keys are infrequent and typically
@ -194,7 +178,7 @@ object CryptoPublicStore {
ec: ExecutionContext ec: ExecutionContext
): CryptoPublicStore = { ): CryptoPublicStore = {
storage match { storage match {
case _: MemoryStorage => new InMemoryCryptoPublicStore case _: MemoryStorage => new InMemoryCryptoPublicStore(loggerFactory)
case dbStorage: DbStorage => case dbStorage: DbStorage =>
new DbCryptoPublicStore(dbStorage, releaseProtocolVersion, timeouts, loggerFactory) new DbCryptoPublicStore(dbStorage, releaseProtocolVersion, timeouts, loggerFactory)
} }
@ -218,27 +202,22 @@ object CryptoPublicStoreError extends CantonErrorGroups.CommandErrorGroup {
extends BaseCantonError.Impl(cause = "An error occurred with the public crypto store") extends BaseCantonError.Impl(cause = "An error occurred with the public crypto store")
} }
final case class FailedToListKeys(reason: String) extends CryptoPublicStoreError {
override def pretty: Pretty[FailedToListKeys] = prettyOfClass(unnamedParam(_.reason.unquoted))
}
final case class FailedToReadKey(keyId: Fingerprint, reason: String)
extends CryptoPublicStoreError {
override def pretty: Pretty[FailedToReadKey] = prettyOfClass(unnamedParam(_.reason.unquoted))
}
final case class FailedToInsertKey(keyId: Fingerprint, reason: String) final case class FailedToInsertKey(keyId: Fingerprint, reason: String)
extends CryptoPublicStoreError { extends CryptoPublicStoreError {
override def pretty: Pretty[FailedToInsertKey] = override def pretty: Pretty[FailedToInsertKey] =
prettyOfClass(param("keyId", _.keyId), param("reason", _.reason.unquoted)) prettyOfClass(param("keyId", _.keyId), param("reason", _.reason.unquoted))
} }
final case class KeyAlreadyExists(keyId: Fingerprint, existingKeyName: Option[String]) final case class KeyAlreadyExists[K <: PublicKeyWithName: Pretty](
extends CryptoPublicStoreError { keyId: Fingerprint,
override def pretty: Pretty[KeyAlreadyExists] = existingPublicKey: K,
newPublicKey: K,
) extends CryptoPublicStoreError {
override def pretty: Pretty[KeyAlreadyExists[K]] =
prettyOfClass( prettyOfClass(
param("keyId", _.keyId), param("keyId", _.keyId),
param("existingKeyName", _.existingKeyName.getOrElse("").unquoted), param("existingPublicKey", _.existingPublicKey),
param("newPublicKey", _.newPublicKey),
) )
} }

View File

@ -17,7 +17,6 @@ import com.digitalasset.canton.resource.DbStorage.DbAction
import com.digitalasset.canton.resource.DbStorage.Implicits.* import com.digitalasset.canton.resource.DbStorage.Implicits.*
import com.digitalasset.canton.resource.{DbStorage, DbStore} import com.digitalasset.canton.resource.{DbStorage, DbStore}
import com.digitalasset.canton.tracing.TraceContext import com.digitalasset.canton.tracing.TraceContext
import com.digitalasset.canton.util.EitherTUtil
import com.digitalasset.canton.version.ReleaseProtocolVersion import com.digitalasset.canton.version.ReleaseProtocolVersion
import com.google.common.annotations.VisibleForTesting import com.google.common.annotations.VisibleForTesting
import com.google.protobuf.ByteString import com.google.protobuf.ByteString
@ -149,18 +148,16 @@ class DbCryptoPrivateStore(
purpose: KeyPurpose, purpose: KeyPurpose,
)(implicit )(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPrivateStoreError, Option[StoredPrivateKey]] = ): EitherT[FutureUnlessShutdown, CryptoPrivateStoreError, Option[StoredPrivateKey]] = {
EitherTUtil EitherT.right(
.fromFuture[CryptoPrivateStoreError, Option[StoredPrivateKey]]( storage
storage .querySingleUnlessShutdown(
.querySingle( queryKey(keyId, purpose),
queryKey(keyId, purpose), functionFullName,
functionFullName, )
) .value
.value, )
err => CryptoPrivateStoreError.FailedToReadKey(keyId, err.toString), }
)
.mapK(FutureUnlessShutdown.outcomeK)
private[crypto] def writePrivateKey( private[crypto] def writePrivateKey(
key: StoredPrivateKey key: StoredPrivateKey
@ -172,15 +169,13 @@ class DbCryptoPrivateStore(
@VisibleForTesting @VisibleForTesting
private[canton] def listPrivateKeys(purpose: KeyPurpose, encrypted: Boolean)(implicit private[canton] def listPrivateKeys(purpose: KeyPurpose, encrypted: Boolean)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPrivateStoreError, Set[StoredPrivateKey]] = ): EitherT[FutureUnlessShutdown, CryptoPrivateStoreError, Set[StoredPrivateKey]] = {
EitherTUtil EitherT.right(
.fromFuture[CryptoPrivateStoreError, Set[StoredPrivateKey]]( storage
storage .queryUnlessShutdown(queryKeys(purpose), functionFullName)
.query(queryKeys(purpose), functionFullName) .map(keys => keys.filter(_.isEncrypted == encrypted))
.map(keys => keys.filter(_.isEncrypted == encrypted)), )
err => CryptoPrivateStoreError.FailedToListKeys(err.toString), }
)
.mapK(FutureUnlessShutdown.outcomeK)
private def deleteKey(keyId: Fingerprint): SqlAction[Int, NoStream, Effect.Write] = private def deleteKey(keyId: Fingerprint): SqlAction[Int, NoStream, Effect.Write] =
sqlu"delete from common_crypto_private_keys where key_id = $keyId" sqlu"delete from common_crypto_private_keys where key_id = $keyId"
@ -191,28 +186,24 @@ class DbCryptoPrivateStore(
private[crypto] def replaceStoredPrivateKeys(newKeys: Seq[StoredPrivateKey])(implicit private[crypto] def replaceStoredPrivateKeys(newKeys: Seq[StoredPrivateKey])(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPrivateStoreError, Unit] = ): EitherT[FutureUnlessShutdown, CryptoPrivateStoreError, Unit] =
EitherTUtil EitherT.right(
.fromFuture[CryptoPrivateStoreError, Unit]( storage
storage .updateUnlessShutdown_(
.update_( DBIOAction
DBIOAction .sequence(
.sequence( newKeys.map(key => deleteKey(key.id).andThen(insertKeyUpdate(key)))
newKeys.map(key => deleteKey(key.id).andThen(insertKeyUpdate(key))) )
) .transactionally,
.transactionally, functionFullName,
functionFullName, )
), )
err => CryptoPrivateStoreError.FailedToReplaceKeys(newKeys.map(_.id), err.toString),
)
.mapK(FutureUnlessShutdown.outcomeK)
private[crypto] def deletePrivateKey(keyId: Fingerprint)(implicit private[crypto] def deletePrivateKey(keyId: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPrivateStoreError, Unit] = ): EitherT[FutureUnlessShutdown, CryptoPrivateStoreError, Unit] =
EitherTUtil.fromFuture( EitherT.right(
storage storage
.updateUnlessShutdown_(deleteKey(keyId), functionFullName), .updateUnlessShutdown_(deleteKey(keyId), functionFullName)
err => CryptoPrivateStoreError.FailedToDeleteKey(keyId, err.toString),
) )
private[crypto] def encrypted( private[crypto] def encrypted(
@ -235,27 +226,23 @@ class DbCryptoPrivateStore(
private[crypto] def getWrapperKeyId()(implicit private[crypto] def getWrapperKeyId()(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPrivateStoreError, Option[String300]] = ): EitherT[FutureUnlessShutdown, CryptoPrivateStoreError, Option[String300]] =
EitherTUtil EitherT
.fromFuture( .right(
storage.queryUnlessShutdown( storage
{ .queryUnlessShutdown(
sql"select distinct wrapper_key_id from common_crypto_private_keys" sql"select distinct wrapper_key_id from common_crypto_private_keys"
.as[Option[String300]] .as[Option[String300]]
.map(_.toSeq) .map(_.toSeq),
}, functionFullName,
functionFullName, )
),
err => CryptoPrivateStoreError.FailedToGetWrapperKeyId(err.toString),
) )
.transform { .subflatMap { wrapperKeys =>
case Left(err) => Left(err) if (wrapperKeys.size > 1)
case Right(wrapper_keys) => Left(
if (wrapper_keys.size > 1) CryptoPrivateStoreError
Left( .FailedToGetWrapperKeyId("Found more than one distinct wrapper_key_id")
CryptoPrivateStoreError )
.FailedToGetWrapperKeyId("Found more than one distinct wrapper_key_id") else
) Right(wrapperKeys.flatten.headOption)
else
Right(wrapper_keys.flatten.headOption)
} }
} }

View File

@ -3,8 +3,7 @@
package com.digitalasset.canton.crypto.store.db package com.digitalasset.canton.crypto.store.db
import cats.data.EitherT import cats.data.OptionT
import cats.syntax.bifunctor.*
import com.daml.nameof.NameOf.functionFullName import com.daml.nameof.NameOf.functionFullName
import com.digitalasset.canton.config.ProcessingTimeout import com.digitalasset.canton.config.ProcessingTimeout
import com.digitalasset.canton.crypto.* import com.digitalasset.canton.crypto.*
@ -12,9 +11,8 @@ import com.digitalasset.canton.crypto.store.*
import com.digitalasset.canton.lifecycle.FutureUnlessShutdown import com.digitalasset.canton.lifecycle.FutureUnlessShutdown
import com.digitalasset.canton.logging.NamedLoggerFactory import com.digitalasset.canton.logging.NamedLoggerFactory
import com.digitalasset.canton.resource.DbStorage.DbAction import com.digitalasset.canton.resource.DbStorage.DbAction
import com.digitalasset.canton.resource.{DbStorage, DbStore} import com.digitalasset.canton.resource.{DbStorage, DbStore, IdempotentInsert}
import com.digitalasset.canton.tracing.TraceContext import com.digitalasset.canton.tracing.TraceContext
import com.digitalasset.canton.util.EitherTUtil
import com.digitalasset.canton.version.ReleaseProtocolVersion import com.digitalasset.canton.version.ReleaseProtocolVersion
import slick.jdbc.{GetResult, SetParameter} import slick.jdbc.{GetResult, SetParameter}
@ -42,7 +40,7 @@ class DbCryptoPublicStore(
.as[K] .as[K]
.map(_.toSet) .map(_.toSet)
private def queryKey[K <: PublicKeyWithName: GetResult]( private def queryKeyO[K <: PublicKeyWithName: GetResult](
keyId: Fingerprint, keyId: Fingerprint,
purpose: KeyPurpose, purpose: KeyPurpose,
): DbAction.ReadOnly[Option[K]] = ): DbAction.ReadOnly[Option[K]] =
@ -50,109 +48,86 @@ class DbCryptoPublicStore(
.as[K] .as[K]
.headOption .headOption
private def insertKeyUpdate[K <: PublicKey: SetParameter, KN <: PublicKeyWithName: GetResult]( private def queryKey[K <: PublicKeyWithName: GetResult](
key: K, keyId: Fingerprint,
name: Option[KeyName], purpose: KeyPurpose,
): DbAction.WriteOnly[Int] = ): DbAction.ReadOnly[K] =
storage.profile match { sql"select data, name from common_crypto_public_keys where key_id = $keyId and purpose = $purpose"
case _: DbStorage.Profile.Oracle => .as[K]
sqlu"""insert .head
/*+ IGNORE_ROW_ON_DUPKEY_INDEX ( common_crypto_public_keys ( key_id ) ) */
into common_crypto_public_keys (key_id, purpose, data, name)
values (${key.id}, ${key.purpose}, $key, $name)"""
case _ =>
sqlu"""insert into common_crypto_public_keys (key_id, purpose, data, name)
values (${key.id}, ${key.purpose}, $key, $name)
on conflict do nothing"""
}
private def insertKey[K <: PublicKey: SetParameter, KN <: PublicKeyWithName: GetResult]( private def insertKey[K <: PublicKey: SetParameter, KN <: PublicKeyWithName: GetResult](
key: K, key: K,
name: Option[KeyName], name: Option[KeyName],
)(implicit )(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Unit] = ): FutureUnlessShutdown[Unit] = {
for { storage.queryAndUpdateUnlessShutdown(
inserted <- EitherT.right( IdempotentInsert.insertVerifyingConflicts(
storage.updateUnlessShutdown(insertKeyUpdate(key, name), functionFullName) storage,
) "common_crypto_public_keys ( key_id )",
res <- sql"common_crypto_public_keys (key_id, purpose, data, name) values (${key.id}, ${key.purpose}, $key, $name)",
if (inserted == 0) { queryKey(key.id, key.purpose),
// If no key was inserted by the insert query, check that the existing value matches )(
storage existingKey => existingKey.publicKey == key && existingKey.name == name,
.querySingleUnlessShutdown(queryKey(key.id, key.purpose), functionFullName) _ => s"Existing public key for ${key.id} is different than inserted key",
.toRight( ),
CryptoPublicStoreError.FailedToInsertKey(key.id, "No key inserted and no key found") functionFullName,
) )
.flatMap { existingKey => }
EitherT
.cond[FutureUnlessShutdown](
existingKey.publicKey == key && existingKey.name == name,
(),
CryptoPublicStoreError.KeyAlreadyExists(key.id, existingKey.name.map(_.unwrap)),
)
.leftWiden[CryptoPublicStoreError]
}
} else EitherT.rightT[FutureUnlessShutdown, CryptoPublicStoreError](())
} yield res
override def readSigningKey(signingKeyId: Fingerprint)(implicit override def readSigningKey(signingKeyId: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[SigningPublicKeyWithName]] = ): OptionT[FutureUnlessShutdown, SigningPublicKeyWithName] =
EitherTUtil.fromFuture( storage
storage .querySingleUnlessShutdown(
.querySingleUnlessShutdown( queryKeyO[SigningPublicKeyWithName](signingKeyId, KeyPurpose.Signing),
queryKey[SigningPublicKeyWithName](signingKeyId, KeyPurpose.Signing), functionFullName,
functionFullName, )
)
.value,
err => CryptoPublicStoreError.FailedToReadKey(signingKeyId, err.toString),
)
override def readEncryptionKey(encryptionKeyId: Fingerprint)(implicit override def readEncryptionKey(encryptionKeyId: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[EncryptionPublicKeyWithName]] = ): OptionT[FutureUnlessShutdown, EncryptionPublicKeyWithName] =
EitherTUtil.fromFuture( storage
storage .querySingleUnlessShutdown(
.querySingleUnlessShutdown( queryKeyO[EncryptionPublicKeyWithName](encryptionKeyId, KeyPurpose.Encryption),
queryKey[EncryptionPublicKeyWithName](encryptionKeyId, KeyPurpose.Encryption), functionFullName,
functionFullName, )
)
.value,
err => CryptoPublicStoreError.FailedToReadKey(encryptionKeyId, err.toString),
)
override protected def writeSigningKey(key: SigningPublicKey, name: Option[KeyName])(implicit override protected def writeSigningKey(key: SigningPublicKey, name: Option[KeyName])(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Unit] = ): FutureUnlessShutdown[Unit] =
insertKey[SigningPublicKey, SigningPublicKeyWithName](key, name) insertKey[SigningPublicKey, SigningPublicKeyWithName](key, name)
override protected def writeEncryptionKey(key: EncryptionPublicKey, name: Option[KeyName])( override protected def writeEncryptionKey(key: EncryptionPublicKey, name: Option[KeyName])(
implicit traceContext: TraceContext implicit traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Unit] = ): FutureUnlessShutdown[Unit] =
insertKey[EncryptionPublicKey, EncryptionPublicKeyWithName](key, name) insertKey[EncryptionPublicKey, EncryptionPublicKeyWithName](key, name)
override private[store] def listSigningKeys(implicit override private[store] def listSigningKeys(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[SigningPublicKeyWithName]] = ): FutureUnlessShutdown[Set[SigningPublicKeyWithName]] =
EitherTUtil.fromFuture( storage.queryUnlessShutdown(
storage.queryUnlessShutdown( queryKeys[SigningPublicKeyWithName](KeyPurpose.Signing),
queryKeys[SigningPublicKeyWithName](KeyPurpose.Signing), functionFullName,
functionFullName,
),
err => CryptoPublicStoreError.FailedToListKeys(err.toString),
) )
override private[store] def listEncryptionKeys(implicit override private[store] def listEncryptionKeys(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[EncryptionPublicKeyWithName]] = ): FutureUnlessShutdown[Set[EncryptionPublicKeyWithName]] =
EitherTUtil storage
.fromFuture( .queryUnlessShutdown(
storage queryKeys[EncryptionPublicKeyWithName](KeyPurpose.Encryption),
.queryUnlessShutdown( functionFullName,
queryKeys[EncryptionPublicKeyWithName](KeyPurpose.Encryption),
functionFullName,
),
err => CryptoPublicStoreError.FailedToListKeys(err.toString),
) )
override private[crypto] def deleteKey(
keyId: Fingerprint
)(implicit traceContext: TraceContext): FutureUnlessShutdown[Unit] = {
storage
.updateUnlessShutdown_(
sqlu"delete from common_crypto_public_keys where key_id = $keyId",
functionFullName,
)
}
} }

View File

@ -3,76 +3,102 @@
package com.digitalasset.canton.crypto.store.memory package com.digitalasset.canton.crypto.store.memory
import cats.data.EitherT import cats.data.OptionT
import cats.syntax.either.* import cats.syntax.either.*
import com.digitalasset.canton.crypto.store.{CryptoPublicStore, CryptoPublicStoreError} import com.digitalasset.canton.crypto.store.{CryptoPublicStore, CryptoPublicStoreError}
import com.digitalasset.canton.crypto.{KeyName, *} import com.digitalasset.canton.crypto.{KeyName, *}
import com.digitalasset.canton.discard.Implicits.DiscardOps
import com.digitalasset.canton.lifecycle.FutureUnlessShutdown import com.digitalasset.canton.lifecycle.FutureUnlessShutdown
import com.digitalasset.canton.logging.pretty.Pretty
import com.digitalasset.canton.logging.{NamedLoggerFactory, NamedLogging}
import com.digitalasset.canton.tracing.TraceContext import com.digitalasset.canton.tracing.TraceContext
import com.digitalasset.canton.util.TrieMapUtil import com.digitalasset.canton.util.{ErrorUtil, TrieMapUtil}
import scala.collection.concurrent.TrieMap import scala.collection.concurrent.TrieMap
import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContext
class InMemoryCryptoPublicStore(override implicit val ec: ExecutionContext) class InMemoryCryptoPublicStore(override protected val loggerFactory: NamedLoggerFactory)(
extends CryptoPublicStore { override implicit val ec: ExecutionContext
) extends CryptoPublicStore
with NamedLogging {
private val storedSigningKeyMap: TrieMap[Fingerprint, SigningPublicKeyWithName] = TrieMap.empty private val storedSigningKeyMap: TrieMap[Fingerprint, SigningPublicKeyWithName] = TrieMap.empty
private val storedEncryptionKeyMap: TrieMap[Fingerprint, EncryptionPublicKeyWithName] = private val storedEncryptionKeyMap: TrieMap[Fingerprint, EncryptionPublicKeyWithName] =
TrieMap.empty TrieMap.empty
private def errorKeyDuplicate[K <: PublicKeyWithName]( private def errorKeyDuplicate[K <: PublicKeyWithName: Pretty](
keyId: Fingerprint, keyId: Fingerprint,
oldKey: K, oldKey: K,
newKey: K, newKey: K,
): CryptoPublicStoreError = ): CryptoPublicStoreError =
CryptoPublicStoreError.KeyAlreadyExists(keyId, oldKey.name.map(_.unwrap)) CryptoPublicStoreError.KeyAlreadyExists(keyId, oldKey, newKey)
override protected def writeSigningKey(key: SigningPublicKey, name: Option[KeyName])(implicit override protected def writeSigningKey(key: SigningPublicKey, name: Option[KeyName])(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Unit] = { ): FutureUnlessShutdown[Unit] = {
TrieMapUtil FutureUnlessShutdown.wrap {
.insertIfAbsent( TrieMapUtil
storedSigningKeyMap, .insertIfAbsent(
key.id, storedSigningKeyMap,
SigningPublicKeyWithName(key, name), key.id,
errorKeyDuplicate[SigningPublicKeyWithName] _, SigningPublicKeyWithName(key, name),
) errorKeyDuplicate[SigningPublicKeyWithName] _,
.toEitherT )
.valueOr { err =>
ErrorUtil.invalidState(
s"Existing public key for ${key.id} is different than inserted key: $err"
)
}
}
} }
override def readSigningKey(signingKeyId: Fingerprint)(implicit override def readSigningKey(signingKeyId: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[SigningPublicKeyWithName]] = ): OptionT[FutureUnlessShutdown, SigningPublicKeyWithName] =
EitherT.rightT(storedSigningKeyMap.get(signingKeyId)) OptionT.fromOption(storedSigningKeyMap.get(signingKeyId))
override def readEncryptionKey(encryptionKeyId: Fingerprint)(implicit override def readEncryptionKey(encryptionKeyId: Fingerprint)(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[EncryptionPublicKeyWithName]] = ): OptionT[FutureUnlessShutdown, EncryptionPublicKeyWithName] =
EitherT.rightT(storedEncryptionKeyMap.get(encryptionKeyId)) OptionT.fromOption(storedEncryptionKeyMap.get(encryptionKeyId))
override protected def writeEncryptionKey(key: EncryptionPublicKey, name: Option[KeyName])( override protected def writeEncryptionKey(key: EncryptionPublicKey, name: Option[KeyName])(
implicit traceContext: TraceContext implicit traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Unit] = { ): FutureUnlessShutdown[Unit] = {
TrieMapUtil FutureUnlessShutdown.wrap {
.insertIfAbsent( TrieMapUtil
storedEncryptionKeyMap, .insertIfAbsent(
key.id, storedEncryptionKeyMap,
EncryptionPublicKeyWithName(key, name), key.id,
errorKeyDuplicate[EncryptionPublicKeyWithName] _, EncryptionPublicKeyWithName(key, name),
) errorKeyDuplicate[EncryptionPublicKeyWithName] _,
.toEitherT )
.valueOr { _ =>
ErrorUtil.invalidState(
s"Existing public key for ${key.id} is different than inserted key"
)
}
}
} }
override private[store] def listSigningKeys(implicit override private[store] def listSigningKeys(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[SigningPublicKeyWithName]] = ): FutureUnlessShutdown[Set[SigningPublicKeyWithName]] =
EitherT.rightT(storedSigningKeyMap.values.toSet) FutureUnlessShutdown.pure(storedSigningKeyMap.values.toSet)
override private[store] def listEncryptionKeys(implicit override private[store] def listEncryptionKeys(implicit
traceContext: TraceContext traceContext: TraceContext
): EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Set[EncryptionPublicKeyWithName]] = ): FutureUnlessShutdown[Set[EncryptionPublicKeyWithName]] =
EitherT.rightT(storedEncryptionKeyMap.values.toSet) FutureUnlessShutdown.pure(storedEncryptionKeyMap.values.toSet)
override private[crypto] def deleteKey(
keyId: Fingerprint
)(implicit traceContext: TraceContext): FutureUnlessShutdown[Unit] = {
storedSigningKeyMap.remove(keyId).discard
storedEncryptionKeyMap.remove(keyId).discard
FutureUnlessShutdown.unit
}
override def close(): Unit = () override def close(): Unit = ()
} }

View File

@ -55,14 +55,14 @@ object CantonNodeParameters {
) extends CantonNodeParameters.General ) extends CantonNodeParameters.General
} }
trait Protocol { trait Protocol {
def devVersionSupport: Boolean def alphaVersionSupport: Boolean
def betaVersionSupport: Boolean def betaVersionSupport: Boolean
def dontWarnOnDeprecatedPV: Boolean def dontWarnOnDeprecatedPV: Boolean
} }
object Protocol { object Protocol {
final case class Impl( final case class Impl(
devVersionSupport: Boolean, alphaVersionSupport: Boolean,
betaVersionSupport: Boolean, betaVersionSupport: Boolean,
dontWarnOnDeprecatedPV: Boolean, dontWarnOnDeprecatedPV: Boolean,
) extends CantonNodeParameters.Protocol ) extends CantonNodeParameters.Protocol
@ -95,7 +95,7 @@ trait HasProtocolCantonNodeParameters extends CantonNodeParameters.Protocol {
protected def protocol: CantonNodeParameters.Protocol protected def protocol: CantonNodeParameters.Protocol
def devVersionSupport: Boolean = protocol.devVersionSupport def alphaVersionSupport: Boolean = protocol.alphaVersionSupport
def betaVersionSupport: Boolean = protocol.betaVersionSupport def betaVersionSupport: Boolean = protocol.betaVersionSupport
def dontWarnOnDeprecatedPV: Boolean = protocol.dontWarnOnDeprecatedPV def dontWarnOnDeprecatedPV: Boolean = protocol.dontWarnOnDeprecatedPV
} }

View File

@ -47,6 +47,10 @@ object FutureUnlessShutdown {
Future.successful(x) Future.successful(x)
) )
/** Analog to Future.apply that handles an exception of `x` as a failed future. */
def wrap[A](x: => A)(implicit ec: ExecutionContext): FutureUnlessShutdown[A] =
FutureUnlessShutdown.outcomeF(Future(x))
/** Wraps the result of a [[scala.concurrent.Future]] into an [[UnlessShutdown.Outcome]] */ /** Wraps the result of a [[scala.concurrent.Future]] into an [[UnlessShutdown.Outcome]] */
def outcomeF[A](f: Future[A])(implicit ec: ExecutionContext): FutureUnlessShutdown[A] = def outcomeF[A](f: Future[A])(implicit ec: ExecutionContext): FutureUnlessShutdown[A] =
FutureUnlessShutdown(f.map(UnlessShutdown.Outcome(_))) FutureUnlessShutdown(f.map(UnlessShutdown.Outcome(_)))

View File

@ -154,9 +154,11 @@ object EncryptedView {
traceContext: TraceContext, traceContext: TraceContext,
): EitherT[FutureUnlessShutdown, InvalidEncryptionKey, Unit] = ): EitherT[FutureUnlessShutdown, InvalidEncryptionKey, Unit] =
for { for {
encryptionKey <- cryptoPublicStore encryptionKey <- EitherT.right(
.findEncryptionKeyIdByFingerprint(keyId) cryptoPublicStore
.leftMap(err => DecryptionError.InvalidEncryptionKey(err.show)) .findEncryptionKeyIdByFingerprint(keyId)
.value
)
_ <- encryptionKey match { _ <- encryptionKey match {
case Some(encPubKey) => case Some(encPubKey) =>
EitherT.cond[FutureUnlessShutdown]( EitherT.cond[FutureUnlessShutdown](

View File

@ -49,14 +49,14 @@ trait DbMigrations { this: NamedLogging =>
* A user that does that, won't be able to upgrade to new Canton versions, as we reserve our right to just * A user that does that, won't be able to upgrade to new Canton versions, as we reserve our right to just
* modify the dev version files in any way we like. * modify the dev version files in any way we like.
*/ */
protected def devVersionSupport: Boolean protected def alphaVersionSupport: Boolean
/** Database is migrated using Flyway, which looks at the migration files at /** Database is migrated using Flyway, which looks at the migration files at
* src/main/resources/db/migration/canton as explained at https://flywaydb.org/documentation/getstarted/firststeps/api * src/main/resources/db/migration/canton as explained at https://flywaydb.org/documentation/getstarted/firststeps/api
*/ */
protected def createFlyway(dataSource: DataSource): Flyway = { protected def createFlyway(dataSource: DataSource): Flyway = {
Flyway.configure Flyway.configure
.locations(dbConfig.buildMigrationsPaths(devVersionSupport)*) .locations(dbConfig.buildMigrationsPaths(alphaVersionSupport)*)
.dataSource(dataSource) .dataSource(dataSource)
.cleanDisabled(!dbConfig.parameters.unsafeCleanOnValidationError) .cleanDisabled(!dbConfig.parameters.unsafeCleanOnValidationError)
.cleanOnValidationError(dbConfig.parameters.unsafeCleanOnValidationError) .cleanOnValidationError(dbConfig.parameters.unsafeCleanOnValidationError)
@ -298,7 +298,7 @@ class CommunityDbMigrationsFactory(loggerFactory: NamedLoggerFactory) extends Db
class CommunityDbMigrations( class CommunityDbMigrations(
protected val dbConfig: DbConfig, protected val dbConfig: DbConfig,
protected val devVersionSupport: Boolean, protected val alphaVersionSupport: Boolean,
protected val loggerFactory: NamedLoggerFactory, protected val loggerFactory: NamedLoggerFactory,
)(implicit override protected val closeContext: CloseContext) )(implicit override protected val closeContext: CloseContext)
extends DbMigrations extends DbMigrations

View File

@ -10,12 +10,12 @@ import com.digitalasset.canton.buildinfo.BuildInfo
import com.digitalasset.canton.logging.pretty.{Pretty, PrettyPrinting} import com.digitalasset.canton.logging.pretty.{Pretty, PrettyPrinting}
import com.digitalasset.canton.serialization.ProtoConverter.ParsingResult import com.digitalasset.canton.serialization.ProtoConverter.ParsingResult
import com.digitalasset.canton.version.ProtocolVersion.{ import com.digitalasset.canton.version.ProtocolVersion.{
alpha,
beta, beta,
deleted, deleted,
deprecated, deprecated,
stable, stable,
supported, supported,
unstable,
} }
import pureconfig.error.FailureReason import pureconfig.error.FailureReason
import pureconfig.{ConfigReader, ConfigWriter} import pureconfig.{ConfigReader, ConfigWriter}
@ -38,11 +38,11 @@ import slick.jdbc.{GetResult, PositionedParameters, SetParameter}
* *
* How to add a new protocol version `N`: * How to add a new protocol version `N`:
* - Define a new constant `v<N>` in the [[ProtocolVersion$]] object via * - Define a new constant `v<N>` in the [[ProtocolVersion$]] object via
* {{{lazy val v<N>: ProtocolVersionWithStatus[Unstable] = ProtocolVersion.unstable(<N>)}}} * {{{lazy val v<N>: ProtocolVersionWithStatus[Alpha] = ProtocolVersion.alpha(<N>)}}}
* *
* - The new protocol version should be declared as unstable until it is released: * - The new protocol version should be declared as alpha until it is released:
* Define it with type argument [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Unstable]] * Define it with type argument [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Alpha]]
* and add it to the list in [[com.digitalasset.canton.version.ProtocolVersion.unstable]]. * and add it to the list in [[com.digitalasset.canton.version.ProtocolVersion.alpha]].
* *
* - Add a new test job for the protocol version `N` to the canton_build workflow. * - Add a new test job for the protocol version `N` to the canton_build workflow.
* Make a sensible decision how often it should run. * Make a sensible decision how often it should run.
@ -51,16 +51,16 @@ import slick.jdbc.{GetResult, PositionedParameters, SetParameter}
* *
* How to release a protocol version `N`: * How to release a protocol version `N`:
* - Switch the type parameter of the protocol version constant `v<N>` from * - Switch the type parameter of the protocol version constant `v<N>` from
* [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Unstable]] to [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Stable]] * [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Alpha]] to [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Stable]]
* As a result, you may have to modify a couple of protobuf definitions and mark them as stable as well. * As a result, you may have to modify a couple of protobuf definitions and mark them as stable as well.
* *
* - Remove `v<N>` from [[com.digitalasset.canton.version.ProtocolVersion.unstable]] * - Remove `v<N>` from [[com.digitalasset.canton.version.ProtocolVersion.alpha]]
* and add it to [[com.digitalasset.canton.buildinfo.BuildInfo.stableProtocolVersions]]. * and add it to [[com.digitalasset.canton.buildinfo.BuildInfo.stableProtocolVersions]].
* *
* How to release a protocol version `N` as Beta: * How to release a protocol version `N` as Beta:
* - Switch the type parameter of the protocol version constant `v<N>` from * - Switch the type parameter of the protocol version constant `v<N>` from
* [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Unstable]] to [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Beta]] * [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Alpha]] to [[com.digitalasset.canton.version.ProtocolVersionAnnotation.Beta]]
* - Remove `v<N>` from [[com.digitalasset.canton.version.ProtocolVersion.unstable]] * - Remove `v<N>` from [[com.digitalasset.canton.version.ProtocolVersion.alpha]]
* and add it to [[com.digitalasset.canton.buildinfo.BuildInfo.betaProtocolVersions]]. * and add it to [[com.digitalasset.canton.buildinfo.BuildInfo.betaProtocolVersions]].
* *
* - Check the test jobs for protocol versions: * - Check the test jobs for protocol versions:
@ -79,7 +79,7 @@ sealed case class ProtocolVersion private[version] (v: Int)
def isDeprecated: Boolean = deprecated.contains(this) def isDeprecated: Boolean = deprecated.contains(this)
def isUnstable: Boolean = unstable.contains(this) def isUnstable: Boolean = alpha.contains(this)
def isBeta: Boolean = beta.contains(this) def isBeta: Boolean = beta.contains(this)
@ -110,10 +110,11 @@ object ProtocolVersion {
v: Int v: Int
): ProtocolVersionWithStatus[ProtocolVersionAnnotation.Stable] = ): ProtocolVersionWithStatus[ProtocolVersionAnnotation.Stable] =
createWithStatus[ProtocolVersionAnnotation.Stable](v) createWithStatus[ProtocolVersionAnnotation.Stable](v)
private[version] def createUnstable(
private[version] def createAlpha(
v: Int v: Int
): ProtocolVersionWithStatus[ProtocolVersionAnnotation.Unstable] = ): ProtocolVersionWithStatus[ProtocolVersionAnnotation.Alpha] =
createWithStatus[ProtocolVersionAnnotation.Unstable](v) createWithStatus[ProtocolVersionAnnotation.Alpha](v)
private[version] def createBeta( private[version] def createBeta(
v: Int v: Int
): ProtocolVersionWithStatus[ProtocolVersionAnnotation.Beta] = ): ProtocolVersionWithStatus[ProtocolVersionAnnotation.Beta] =
@ -236,31 +237,31 @@ object ProtocolVersion {
ProtocolVersion(30), ProtocolVersion(30),
) )
val unstable: NonEmpty[List[ProtocolVersionWithStatus[ProtocolVersionAnnotation.Unstable]]] = val alpha: NonEmpty[List[ProtocolVersionWithStatus[ProtocolVersionAnnotation.Alpha]]] =
NonEmpty.mk(List, ProtocolVersion.v31, ProtocolVersion.dev) NonEmpty.mk(List, ProtocolVersion.v31, ProtocolVersion.dev)
val beta: List[ProtocolVersionWithStatus[ProtocolVersionAnnotation.Beta]] = val beta: List[ProtocolVersionWithStatus[ProtocolVersionAnnotation.Beta]] =
parseFromBuildInfo(BuildInfo.betaProtocolVersions.toSeq) parseFromBuildInfo(BuildInfo.betaProtocolVersions.toSeq)
.map(pv => ProtocolVersion.createBeta(pv.v)) .map(pv => ProtocolVersion.createBeta(pv.v))
val supported: NonEmpty[List[ProtocolVersion]] = (unstable ++ beta ++ stable).sorted val supported: NonEmpty[List[ProtocolVersion]] = (alpha ++ beta ++ stable).sorted
private val allProtocolVersions = deprecated ++ deleted ++ unstable ++ beta ++ stable private val allProtocolVersions = deprecated ++ deleted ++ alpha ++ beta ++ stable
require( require(
allProtocolVersions.sizeCompare(allProtocolVersions.distinct) == 0, allProtocolVersions.sizeCompare(allProtocolVersions.distinct) == 0,
s"All the protocol versions should be distinct." + s"All the protocol versions should be distinct." +
s"Found: ${Map("deprecated" -> deprecated, "deleted" -> deleted, "unstable" -> unstable, "stable" -> stable)}", s"Found: ${Map("deprecated" -> deprecated, "deleted" -> deleted, "alpha" -> alpha, "stable" -> stable)}",
) )
// TODO(i15561): change back to `stableAndSupported.max1` once there is a stable Daml 3 protocol version // TODO(i15561): change back to `stableAndSupported.max1` once there is a stable Daml 3 protocol version
val latest: ProtocolVersion = stable.lastOption.getOrElse(unstable.head1) val latest: ProtocolVersion = stable.lastOption.getOrElse(alpha.head1)
lazy val dev: ProtocolVersionWithStatus[ProtocolVersionAnnotation.Unstable] = lazy val dev: ProtocolVersionWithStatus[ProtocolVersionAnnotation.Alpha] =
ProtocolVersion.createUnstable(Int.MaxValue) ProtocolVersion.createAlpha(Int.MaxValue)
lazy val v31: ProtocolVersionWithStatus[ProtocolVersionAnnotation.Unstable] = lazy val v31: ProtocolVersionWithStatus[ProtocolVersionAnnotation.Alpha] =
ProtocolVersion.createUnstable(31) ProtocolVersion.createAlpha(31)
// Minimum stable protocol version introduced // Minimum stable protocol version introduced
lazy val minimum: ProtocolVersion = v31 lazy val minimum: ProtocolVersion = v31

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --target=2.1 - --target=2.1
name: CantonExamples name: CantonExamples

View File

@ -32,7 +32,7 @@ trait LocalNodeParametersConfig {
/** Various cache sizes */ /** Various cache sizes */
def caching: CachingConfigs def caching: CachingConfigs
def useUnifiedSequencer: Boolean def useUnifiedSequencer: Boolean
def devVersionSupport: Boolean def alphaVersionSupport: Boolean
def watchdog: Option[WatchdogConfig] def watchdog: Option[WatchdogConfig]
} }

View File

@ -4,7 +4,7 @@
package com.digitalasset.canton.config package com.digitalasset.canton.config
trait ProtocolConfig { trait ProtocolConfig {
def devVersionSupport: Boolean def alphaVersionSupport: Boolean
def betaVersionSupport: Boolean def betaVersionSupport: Boolean
def dontWarnOnDeprecatedPV: Boolean def dontWarnOnDeprecatedPV: Boolean
} }

View File

@ -11,7 +11,7 @@ import com.digitalasset.canton.ProtoDeserializationError.ProtoDeserializationFai
import com.digitalasset.canton.config.CantonRequireTypes.String300 import com.digitalasset.canton.config.CantonRequireTypes.String300
import com.digitalasset.canton.config.ProcessingTimeout import com.digitalasset.canton.config.ProcessingTimeout
import com.digitalasset.canton.crypto.admin.v30 import com.digitalasset.canton.crypto.admin.v30
import com.digitalasset.canton.crypto.store.{CryptoPrivateStoreError, CryptoPublicStoreError} import com.digitalasset.canton.crypto.store.CryptoPrivateStoreError
import com.digitalasset.canton.crypto.{v30 as cryptoproto, *} import com.digitalasset.canton.crypto.{v30 as cryptoproto, *}
import com.digitalasset.canton.error.BaseCantonError import com.digitalasset.canton.error.BaseCantonError
import com.digitalasset.canton.lifecycle.FutureUnlessShutdown import com.digitalasset.canton.lifecycle.FutureUnlessShutdown
@ -59,11 +59,7 @@ class GrpcVaultService(
override def listMyKeys(request: v30.ListMyKeysRequest): Future[v30.ListMyKeysResponse] = { override def listMyKeys(request: v30.ListMyKeysRequest): Future[v30.ListMyKeysResponse] = {
implicit val traceContext: TraceContext = TraceContextGrpc.fromGrpcContext implicit val traceContext: TraceContext = TraceContextGrpc.fromGrpcContext
val result = for { val result = for {
keys <- crypto.cryptoPublicStore.publicKeysWithName keys <- EitherT.right(crypto.cryptoPublicStore.publicKeysWithName)
.leftMap[BaseCantonError] { err =>
CryptoPublicStoreError.ErrorCode
.WrapStr(s"Failed to retrieve public keys: $err")
}
publicKeys <- publicKeys <-
keys.toList.parFilterA(pk => keys.toList.parFilterA(pk =>
crypto.cryptoPrivateStore crypto.cryptoPrivateStore
@ -100,7 +96,7 @@ class GrpcVaultService(
implicit val traceContext: TraceContext = TraceContextGrpc.fromGrpcContext implicit val traceContext: TraceContext = TraceContextGrpc.fromGrpcContext
for { for {
publicKey <- publicKey <-
FutureUnlessShutdown.pure( FutureUnlessShutdown.wrap(
ProtoConverter ProtoConverter
.parse( .parse(
cryptoproto.PublicKey.parseFrom, cryptoproto.PublicKey.parseFrom,
@ -109,14 +105,12 @@ class GrpcVaultService(
) )
.valueOr(err => throw ProtoDeserializationFailure.WrapNoLogging(err).asGrpcError) .valueOr(err => throw ProtoDeserializationFailure.WrapNoLogging(err).asGrpcError)
) )
name <- FutureUnlessShutdown.pure( name <- FutureUnlessShutdown.wrap(
KeyName KeyName
.fromProtoPrimitive(request.name) .fromProtoPrimitive(request.name)
.valueOr(err => throw ProtoDeserializationFailure.WrapNoLogging(err).asGrpcError) .valueOr(err => throw ProtoDeserializationFailure.WrapNoLogging(err).asGrpcError)
) )
_ <- crypto.cryptoPublicStore _ <- crypto.cryptoPublicStore.storePublicKey(publicKey, name.emptyStringAsNone)
.storePublicKey(publicKey, name.emptyStringAsNone)
.valueOr(err => throw CryptoPublicStoreError.ErrorCode.Wrap(err).asGrpcError)
} yield v30.ImportPublicKeyResponse(fingerprint = publicKey.fingerprint.unwrap) } yield v30.ImportPublicKeyResponse(fingerprint = publicKey.fingerprint.unwrap)
}.failOnShutdownTo(AbortedDueToShutdown.Error().asGrpcError) }.failOnShutdownTo(AbortedDueToShutdown.Error().asGrpcError)
@ -125,15 +119,11 @@ class GrpcVaultService(
): Future[v30.ListPublicKeysResponse] = { ): Future[v30.ListPublicKeysResponse] = {
implicit val traceContext: TraceContext = TraceContextGrpc.fromGrpcContext implicit val traceContext: TraceContext = TraceContextGrpc.fromGrpcContext
crypto.cryptoPublicStore.publicKeysWithName crypto.cryptoPublicStore.publicKeysWithName
.map(keys => .map { keys =>
v30.ListPublicKeysResponse(listPublicKeys(request.filters, keys).map(_.toProtoV30)) v30.ListPublicKeysResponse(listPublicKeys(request.filters, keys).map(_.toProtoV30))
) }
.valueOr(err => .failOnShutdownTo(AbortedDueToShutdown.Error().asGrpcError)
throw CryptoPublicStoreError.ErrorCode }
.WrapStr(s"Failed to retrieve public keys: $err")
.asGrpcError
)
}.failOnShutdownTo(AbortedDueToShutdown.Error().asGrpcError)
override def generateSigningKey( override def generateSigningKey(
request: v30.GenerateSigningKeyRequest request: v30.GenerateSigningKeyRequest
@ -232,7 +222,7 @@ class GrpcVaultService(
.asRuntimeException() .asRuntimeException()
) )
cryptoPrivateStore <- cryptoPrivateStore <-
FutureUnlessShutdown.pure( FutureUnlessShutdown.wrap(
crypto.cryptoPrivateStore.toExtended.getOrElse( crypto.cryptoPrivateStore.toExtended.getOrElse(
throw Status.FAILED_PRECONDITION throw Status.FAILED_PRECONDITION
.withDescription( .withDescription(
@ -242,7 +232,7 @@ class GrpcVaultService(
) )
) )
fingerprint <- fingerprint <-
FutureUnlessShutdown.pure( FutureUnlessShutdown.wrap(
Fingerprint Fingerprint
.fromProtoPrimitive(request.fingerprint) .fromProtoPrimitive(request.fingerprint)
.valueOr(err => .valueOr(err =>
@ -252,7 +242,7 @@ class GrpcVaultService(
) )
) )
protocolVersion <- protocolVersion <-
FutureUnlessShutdown.pure( FutureUnlessShutdown.wrap(
ProtocolVersion ProtocolVersion
.fromProtoPrimitive(request.protocolVersion) .fromProtoPrimitive(request.protocolVersion)
.valueOr(err => .valueOr(err =>
@ -276,8 +266,7 @@ class GrpcVaultService(
publicKey <- EitherTUtil.toFutureUnlessShutdown( publicKey <- EitherTUtil.toFutureUnlessShutdown(
crypto.cryptoPublicStore crypto.cryptoPublicStore
.publicKey(fingerprint) .publicKey(fingerprint)
.leftMap(_.toString) .toRight(s"no public key found for [$fingerprint]")
.subflatMap(_.toRight(s"no public key found for [$fingerprint]"))
.leftMap(err => .leftMap(err =>
Status.FAILED_PRECONDITION Status.FAILED_PRECONDITION
.withDescription(s"Error retrieving public key [$fingerprint] $err") .withDescription(s"Error retrieving public key [$fingerprint] $err")
@ -351,7 +340,7 @@ class GrpcVaultService(
keyPair: CryptoKeyPair[PublicKey, PrivateKey], keyPair: CryptoKeyPair[PublicKey, PrivateKey],
)(implicit traceContext: TraceContext): FutureUnlessShutdown[Unit] = )(implicit traceContext: TraceContext): FutureUnlessShutdown[Unit] =
for { for {
cryptoPrivateStore <- FutureUnlessShutdown.pure( cryptoPrivateStore <- FutureUnlessShutdown.wrap(
crypto.cryptoPrivateStore.toExtended.getOrElse( crypto.cryptoPrivateStore.toExtended.getOrElse(
throw Status.FAILED_PRECONDITION throw Status.FAILED_PRECONDITION
.withDescription( .withDescription(
@ -360,20 +349,7 @@ class GrpcVaultService(
.asRuntimeException() .asRuntimeException()
) )
) )
_ <- crypto.cryptoPublicStore _ <- crypto.cryptoPublicStore.storePublicKey(keyPair.publicKey, validatedName)
.storePublicKey(keyPair.publicKey, validatedName)
.recoverWith {
// if the existing key is the same, then ignore error
case error: CryptoPublicStoreError.KeyAlreadyExists =>
for {
existing <- crypto.cryptoPublicStore.publicKey(keyPair.publicKey.fingerprint)
_ <-
if (existing.contains(keyPair.publicKey))
EitherT.rightT[FutureUnlessShutdown, CryptoPublicStoreError](())
else EitherT.leftT[FutureUnlessShutdown, Unit](error: CryptoPublicStoreError)
} yield ()
}
.valueOr(err => throw CryptoPublicStoreError.ErrorCode.Wrap(err).asGrpcError)
_ = logger.info(s"Uploading key ${validatedName}") _ = logger.info(s"Uploading key ${validatedName}")
_ <- cryptoPrivateStore _ <- cryptoPrivateStore
.storePrivateKey(keyPair.privateKey, validatedName) .storePrivateKey(keyPair.privateKey, validatedName)
@ -381,7 +357,7 @@ class GrpcVaultService(
} yield () } yield ()
for { for {
validatedName <- FutureUnlessShutdown.pure( validatedName <- FutureUnlessShutdown.wrap(
OptionUtil OptionUtil
.emptyStringAsNone(request.name) .emptyStringAsNone(request.name)
.traverse(KeyName.create) .traverse(KeyName.create)
@ -423,24 +399,25 @@ class GrpcVaultService(
): Future[v30.DeleteKeyPairResponse] = { ): Future[v30.DeleteKeyPairResponse] = {
implicit val traceContext: TraceContext = TraceContextGrpc.fromGrpcContext implicit val traceContext: TraceContext = TraceContextGrpc.fromGrpcContext
for { for {
fingerprint <- Future( fingerprint <- FutureUnlessShutdown.wrap(
Fingerprint Fingerprint
.fromProtoPrimitive(request.fingerprint) .fromProtoPrimitive(request.fingerprint)
.valueOr(err => .valueOr { err =>
throw ProtoDeserializationFailure throw ProtoDeserializationFailure
.WrapNoLoggingStr(s"Failed to parse key fingerprint: $err") .WrapNoLoggingStr(s"Failed to parse key fingerprint: $err")
.asGrpcError .asGrpcError
) }
) )
_ <- CantonGrpcUtil.mapErrNewEUS { _ <- crypto.cryptoPrivateStore
crypto.cryptoPrivateStore .removePrivateKey(fingerprint)
.removePrivateKey(fingerprint) .valueOr { err =>
.leftMap(err => throw Status.FAILED_PRECONDITION
ProtoDeserializationFailure.WrapNoLoggingStr(s"Failed to remove private key: $err") .withDescription(s"Failed to remove private key: $err")
) .asRuntimeException()
} }
_ <- crypto.cryptoPublicStore.deleteKey(fingerprint)
} yield v30.DeleteKeyPairResponse() } yield v30.DeleteKeyPairResponse()
} }.failOnShutdownTo(AbortedDueToShutdown.Error().asGrpcError)
} }
object GrpcVaultService { object GrpcVaultService {

View File

@ -4,7 +4,7 @@
package com.digitalasset.canton.environment package com.digitalasset.canton.environment
import better.files.File import better.files.File
import cats.data.EitherT import cats.data.{EitherT, OptionT}
import cats.syntax.functorFilter.* import cats.syntax.functorFilter.*
import com.daml.metrics.HealthMetrics import com.daml.metrics.HealthMetrics
import com.daml.metrics.api.MetricHandle.LabeledMetricsFactory import com.daml.metrics.api.MetricHandle.LabeledMetricsFactory
@ -29,7 +29,7 @@ import com.digitalasset.canton.crypto.*
import com.digitalasset.canton.crypto.admin.grpc.GrpcVaultService.GrpcVaultServiceFactory import com.digitalasset.canton.crypto.admin.grpc.GrpcVaultService.GrpcVaultServiceFactory
import com.digitalasset.canton.crypto.admin.v30.VaultServiceGrpc import com.digitalasset.canton.crypto.admin.v30.VaultServiceGrpc
import com.digitalasset.canton.crypto.store.CryptoPrivateStore.CryptoPrivateStoreFactory import com.digitalasset.canton.crypto.store.CryptoPrivateStore.CryptoPrivateStoreFactory
import com.digitalasset.canton.crypto.store.{CryptoPrivateStoreError, CryptoPublicStoreError} import com.digitalasset.canton.crypto.store.CryptoPrivateStoreError
import com.digitalasset.canton.data.CantonTimestamp import com.digitalasset.canton.data.CantonTimestamp
import com.digitalasset.canton.discard.Implicits.DiscardOps import com.digitalasset.canton.discard.Implicits.DiscardOps
import com.digitalasset.canton.environment.CantonNodeBootstrap.HealthDumpFunction import com.digitalasset.canton.environment.CantonNodeBootstrap.HealthDumpFunction
@ -697,14 +697,11 @@ abstract class CantonNodeBootstrapImpl[
override protected def autoCompleteStage() override protected def autoCompleteStage()
: EitherT[FutureUnlessShutdown, String, Option[Unit]] = { : EitherT[FutureUnlessShutdown, String, Option[Unit]] = {
for { for {
namespaceKeyO <- crypto.cryptoPublicStore namespaceKey <- crypto.cryptoPublicStore
.signingKey(nodeId.fingerprint) .signingKey(nodeId.fingerprint)
.leftMap(_.toString) .toRight(
namespaceKey <- EitherT.fromEither[FutureUnlessShutdown](
namespaceKeyO.toRight(
s"Performing auto-init but can't find key ${nodeId.fingerprint} from previous step" s"Performing auto-init but can't find key ${nodeId.fingerprint} from previous step"
) )
)
// init topology manager // init topology manager
nsd <- EitherT.fromEither[FutureUnlessShutdown]( nsd <- EitherT.fromEither[FutureUnlessShutdown](
NamespaceDelegation.create( NamespaceDelegation.create(
@ -820,46 +817,34 @@ object CantonNodeBootstrapImpl {
private def getKeyByFingerprint[P <: PublicKey]( private def getKeyByFingerprint[P <: PublicKey](
typ: String, typ: String,
findPubKeyIdByFingerprint: Fingerprint => EitherT[ findPubKeyIdByFingerprint: Fingerprint => OptionT[FutureUnlessShutdown, P],
FutureUnlessShutdown,
CryptoPublicStoreError,
Option[P],
],
existPrivateKeyByFp: Fingerprint => EitherT[ existPrivateKeyByFp: Fingerprint => EitherT[
FutureUnlessShutdown, FutureUnlessShutdown,
CryptoPrivateStoreError, CryptoPrivateStoreError,
Boolean, Boolean,
], ],
fingerprint: Fingerprint, fingerprint: Fingerprint,
)(implicit ec: ExecutionContext): EitherT[FutureUnlessShutdown, String, P] = for { )(implicit ec: ExecutionContext): EitherT[FutureUnlessShutdown, String, P] = {
keyIdO <- findPubKeyIdByFingerprint(fingerprint) findPubKeyIdByFingerprint(fingerprint)
.leftMap(err => .toRight(s"$typ key with fingerprint $fingerprint does not exist")
s"Failure while looking for $typ fingerprint $fingerprint in public store: $err" .flatMap { keyWithFingerprint =>
) val fingerprint = keyWithFingerprint.fingerprint
pubKey <- keyIdO.fold( existPrivateKeyByFp(fingerprint)
EitherT.leftT[FutureUnlessShutdown, P]( .leftMap(err =>
s"$typ key with fingerprint $fingerprint does not exist" s"Failure while looking for $typ key $fingerprint in private key store: $err"
) )
) { keyWithFingerprint => .transform {
val fingerprint = keyWithFingerprint.fingerprint case Right(true) => Right(keyWithFingerprint)
existPrivateKeyByFp(fingerprint) case Right(false) =>
.leftMap(err => Left(s"Broken private key store: Could not find $typ key $fingerprint")
s"Failure while looking for $typ key $fingerprint in private key store: $err" case Left(err) => Left(err)
) }
.transform { }
case Right(true) => Right(keyWithFingerprint) }
case Right(false) =>
Left(s"Broken private key store: Could not find $typ key $fingerprint")
case Left(err) => Left(err)
}
}
} yield pubKey
private def getOrCreateKey[P <: PublicKey]( private def getOrCreateKey[P <: PublicKey](
typ: String, typ: String,
findPubKeyIdByName: KeyName => EitherT[FutureUnlessShutdown, CryptoPublicStoreError, Option[ findPubKeyIdByName: KeyName => OptionT[FutureUnlessShutdown, P],
P
]],
generateKey: Option[KeyName] => EitherT[FutureUnlessShutdown, String, P], generateKey: Option[KeyName] => EitherT[FutureUnlessShutdown, String, P],
existPrivateKeyByFp: Fingerprint => EitherT[ existPrivateKeyByFp: Fingerprint => EitherT[
FutureUnlessShutdown, FutureUnlessShutdown,
@ -869,8 +854,7 @@ object CantonNodeBootstrapImpl {
name: String, name: String,
)(implicit ec: ExecutionContext): EitherT[FutureUnlessShutdown, String, P] = for { )(implicit ec: ExecutionContext): EitherT[FutureUnlessShutdown, String, P] = for {
keyName <- EitherT.fromEither[FutureUnlessShutdown](KeyName.create(name)) keyName <- EitherT.fromEither[FutureUnlessShutdown](KeyName.create(name))
keyIdO <- findPubKeyIdByName(keyName) keyIdO <- EitherT.right(findPubKeyIdByName(keyName).value)
.leftMap(err => s"Failure while looking for $typ key $name in public store: $err")
pubKey <- keyIdO.fold( pubKey <- keyIdO.fold(
generateKey(Some(keyName)) generateKey(Some(keyName))
.leftMap(err => s"Failure while generating $typ key for $name: $err") .leftMap(err => s"Failure while generating $typ key for $name: $err")

View File

@ -27,8 +27,8 @@ object ProtocolVersionCompatibility {
release: ReleaseVersion = ReleaseVersion.current, release: ReleaseVersion = ReleaseVersion.current,
): NonEmpty[List[ProtocolVersion]] = { ): NonEmpty[List[ProtocolVersion]] = {
val unstableAndBeta = val unstableAndBeta =
if (cantonNodeParameters.devVersionSupport && cantonNodeParameters.nonStandardConfig) if (cantonNodeParameters.alphaVersionSupport && cantonNodeParameters.nonStandardConfig)
ProtocolVersion.unstable.forgetNE ++ ReleaseVersionToProtocolVersions ProtocolVersion.alpha.forgetNE ++ ReleaseVersionToProtocolVersions
.getBetaProtocolVersions(release) .getBetaProtocolVersions(release)
else if (cantonNodeParameters.betaVersionSupport) else if (cantonNodeParameters.betaVersionSupport)
ReleaseVersionToProtocolVersions.getBetaProtocolVersions(release) ReleaseVersionToProtocolVersions.getBetaProtocolVersions(release)
@ -58,7 +58,7 @@ object ProtocolVersionCompatibility {
val unstable = val unstable =
if (includeUnstableVersions) if (includeUnstableVersions)
ProtocolVersion.unstable.forgetNE ProtocolVersion.alpha.forgetNE
else List.empty else List.empty
ReleaseVersionToProtocolVersions.getOrElse( ReleaseVersionToProtocolVersions.getOrElse(
@ -77,8 +77,8 @@ object ProtocolVersionCompatibility {
release: ReleaseVersion = ReleaseVersion.current, release: ReleaseVersion = ReleaseVersion.current,
): NonEmpty[List[ProtocolVersion]] = { ): NonEmpty[List[ProtocolVersion]] = {
val unstableAndBeta = val unstableAndBeta =
if (cantonNodeParameters.devVersionSupport && cantonNodeParameters.nonStandardConfig) if (cantonNodeParameters.alphaVersionSupport && cantonNodeParameters.nonStandardConfig)
ProtocolVersion.unstable.forgetNE ++ ReleaseVersionToProtocolVersions ProtocolVersion.alpha.forgetNE ++ ReleaseVersionToProtocolVersions
.getBetaProtocolVersions(release) .getBetaProtocolVersions(release)
else if (cantonNodeParameters.betaVersionSupport) else if (cantonNodeParameters.betaVersionSupport)
ReleaseVersionToProtocolVersions.getBetaProtocolVersions(release) ReleaseVersionToProtocolVersions.getBetaProtocolVersions(release)
@ -108,7 +108,7 @@ object ProtocolVersionCompatibility {
val unstable = val unstable =
if (includeUnstableVersions) if (includeUnstableVersions)
ProtocolVersion.unstable.forgetNE ProtocolVersion.alpha.forgetNE
else List.empty else List.empty
ReleaseVersionToProtocolVersions.getOrElse( ReleaseVersionToProtocolVersions.getOrElse(

View File

@ -19,7 +19,7 @@ message VersionedMessageV1 {
} }
message VersionedMessageV2 { message VersionedMessageV2 {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
string msg = 1; string msg = 1;
int32 iValue = 2; int32 iValue = 2;
double dValue = 3; double dValue = 3;

View File

@ -29,10 +29,10 @@ trait CryptoPublicStoreTest extends BaseTest { this: AsyncWordSpec =>
"save encryption keys correctly when added incrementally" in { "save encryption keys correctly when added incrementally" in {
val store = newStore val store = newStore
for { for {
_ <- store.storeEncryptionKey(encKey1, encKey1WithName.name).valueOrFail("store encKey1") _ <- store.storeEncryptionKey(encKey1, encKey1WithName.name)
_ <- store.storeEncryptionKey(encKey2, None).valueOrFail("store encKey2") _ <- store.storeEncryptionKey(encKey2, None)
result <- store.encryptionKeys.valueOrFail("get encryption keys") result <- store.encryptionKeys
result2 <- store.listEncryptionKeys.valueOrFail("list keys") result2 <- store.listEncryptionKeys
} yield { } yield {
result shouldEqual Set(encKey1, encKey2) result shouldEqual Set(encKey1, encKey2)
result2 shouldEqual Set(encKey1WithName, encKey2WithName) result2 shouldEqual Set(encKey1WithName, encKey2WithName)
@ -44,15 +44,15 @@ trait CryptoPublicStoreTest extends BaseTest { this: AsyncWordSpec =>
val store = newStore val store = newStore
val separateStore = newStore val separateStore = newStore
for { for {
_ <- store.storeEncryptionKey(encKey1, encKey1WithName.name).valueOrFail("store encKey1") _ <- store.storeEncryptionKey(encKey1, encKey1WithName.name)
_ <- store.storeEncryptionKey(encKey2, None).valueOrFail("store encKey2") _ <- store.storeEncryptionKey(encKey2, None)
result1 <- separateStore.encryptionKey(encKey1.fingerprint).valueOrFail("read encKey1") result1 <- separateStore.encryptionKey(encKey1.fingerprint).value
result2 <- separateStore.encryptionKey(encKey2.fingerprint).valueOrFail("read encKey2") result2 <- separateStore.encryptionKey(encKey2.fingerprint).value
_ <- store.storeSigningKey(sigKey1, sigKey1WithName.name).valueOrFail("store sigKey1") _ <- store.storeSigningKey(sigKey1, sigKey1WithName.name)
_ <- store.storeSigningKey(sigKey2, None).valueOrFail("store sigKey2") _ <- store.storeSigningKey(sigKey2, None)
result3 <- separateStore.signingKey(sigKey1.fingerprint).valueOrFail("read sigKey1") result3 <- separateStore.signingKey(sigKey1.fingerprint).value
result4 <- separateStore.signingKey(sigKey2.fingerprint).valueOrFail("read sigKey2") result4 <- separateStore.signingKey(sigKey2.fingerprint).value
} yield { } yield {
result1 shouldEqual Some(encKey1) result1 shouldEqual Some(encKey1)
result2 shouldEqual Some(encKey2) result2 shouldEqual Some(encKey2)
@ -66,34 +66,46 @@ trait CryptoPublicStoreTest extends BaseTest { this: AsyncWordSpec =>
"save signing keys correctly when added incrementally" in { "save signing keys correctly when added incrementally" in {
val store = newStore val store = newStore
for { for {
_ <- store.storeSigningKey(sigKey1, sigKey1WithName.name).valueOrFail("store sigKey1") _ <- store.storeSigningKey(sigKey1, sigKey1WithName.name)
_ <- store.storeSigningKey(sigKey2, None).valueOrFail("store sigKey2") _ <- store.storeSigningKey(sigKey2, None)
result <- store.signingKeys.valueOrFail("list keys") result <- store.signingKeys
result2 <- store.listSigningKeys.valueOrFail("list keys") result2 <- store.listSigningKeys
} yield { } yield {
result shouldEqual Set(sigKey1, sigKey2) result shouldEqual Set(sigKey1, sigKey2)
result2 shouldEqual Set(sigKey1WithName, sigKey2WithName) result2 shouldEqual Set(sigKey1WithName, sigKey2WithName)
} }
}.failOnShutdown }.failOnShutdown
"delete public keys" in {
val store = newStore
for {
_ <- store.storeSigningKey(sigKey1, sigKey1WithName.name)
result1 <- store.signingKeys
_ <- store.deleteKey(sigKey1.id)
result2 <- store.signingKeys
_ <- store.storeSigningKey(sigKey1, None)
} yield {
result1 shouldEqual Set(sigKey1)
result2 shouldEqual Set()
}
}.failOnShutdown
"idempotent store of encryption keys" in { "idempotent store of encryption keys" in {
val store = newStore val store = newStore
for { for {
_ <- store _ <- store.storeEncryptionKey(encKey1, encKey1WithName.name)
.storeEncryptionKey(encKey1, encKey1WithName.name)
.valueOrFail("store key 1 with name")
// Should succeed // Should succeed
_ <- store _ <- store.storeEncryptionKey(encKey1, encKey1WithName.name)
.storeEncryptionKey(encKey1, encKey1WithName.name)
.valueOrFail("store key 1 with name again")
// Should fail due to different name // Should fail due to different name
failedInsert <- store.storeEncryptionKey(encKey1, None).value _failedInsert <- loggerFactory.assertInternalErrorAsyncUS[IllegalStateException](
store.storeEncryptionKey(encKey1, None),
_.getMessage shouldBe s"Existing public key for ${encKey1.id} is different than inserted key",
)
result <- store.listEncryptionKeys.valueOrFail("listing encryption keys") result <- store.listEncryptionKeys
} yield { } yield {
failedInsert.left.value shouldBe a[CryptoPublicStoreError]
result shouldEqual Set(encKey1WithName) result shouldEqual Set(encKey1WithName)
} }
}.failOnShutdown }.failOnShutdown
@ -103,19 +115,21 @@ trait CryptoPublicStoreTest extends BaseTest { this: AsyncWordSpec =>
for { for {
_ <- store _ <- store
.storeSigningKey(sigKey1, sigKey1WithName.name) .storeSigningKey(sigKey1, sigKey1WithName.name)
.valueOrFail("store key 1 with name")
// Should succeed // Should succeed
_ <- store _ <- store
.storeSigningKey(sigKey1, sigKey1WithName.name) .storeSigningKey(sigKey1, sigKey1WithName.name)
.valueOrFail("store key 1 with name again")
// Should fail due to different name // Should fail due to different name
failedInsert <- store.storeSigningKey(sigKey1, None).value _failedInsert <- loggerFactory.assertInternalErrorAsyncUS[IllegalStateException](
store.storeSigningKey(sigKey1, None),
_.getMessage should startWith(
s"Existing public key for ${sigKey1.id} is different than inserted key"
),
)
result <- store.listSigningKeys.valueOrFail("listing encryption keys") result <- store.listSigningKeys
} yield { } yield {
failedInsert.left.value shouldBe a[CryptoPublicStoreError]
result shouldEqual Set(sigKey1WithName) result shouldEqual Set(sigKey1WithName)
} }
}.failOnShutdown }.failOnShutdown

View File

@ -8,6 +8,9 @@ import org.scalatest.wordspec.AsyncWordSpec
class CryptoPublicStoreTestInMemory extends AsyncWordSpec with CryptoPublicStoreTest { class CryptoPublicStoreTestInMemory extends AsyncWordSpec with CryptoPublicStoreTest {
"InMemoryCryptoPublicStore" should { "InMemoryCryptoPublicStore" should {
behave like cryptoPublicStore(new InMemoryCryptoPublicStore, backedByDatabase = false) behave like cryptoPublicStore(
new InMemoryCryptoPublicStore(loggerFactory),
backedByDatabase = false,
)
} }
} }

View File

@ -123,7 +123,7 @@ class HasProtocolVersionedWrapperTest extends AnyWordSpec with BaseTest {
// Used by the compiled string below // Used by the compiled string below
val stablePV = ProtocolVersion.createStable(10) val stablePV = ProtocolVersion.createStable(10)
val unstablePV = ProtocolVersion.createUnstable(11) val alphaPV = ProtocolVersion.createAlpha(11)
def name: String = "message" def name: String = "message"
@ -139,27 +139,27 @@ class HasProtocolVersionedWrapperTest extends AnyWordSpec with BaseTest {
): Assertion ): Assertion
} }
clue("can use a stable proto message in an unstable protocol version") { clue("can use a stable proto message in an alpha protocol version") {
assertCompiles( assertCompiles(
""" """
val _ = VersionedProtoConverter(unstablePV)(VersionedMessageV1)( val _ = VersionedProtoConverter(alphaPV)(VersionedMessageV1)(
supportedProtoVersionMemoized(_)(fromProtoV1), supportedProtoVersionMemoized(_)(fromProtoV1),
_.toProtoV1.toByteString _.toProtoV1.toByteString
)""" )"""
): Assertion ): Assertion
} }
clue("can use an unstable proto message in an unstable protocol version") { clue("can use an alpha proto message in an alpha protocol version") {
assertCompiles( assertCompiles(
""" """
val _ = VersionedProtoConverter(unstablePV)(VersionedMessageV2)( val _ = VersionedProtoConverter(alphaPV)(VersionedMessageV2)(
supportedProtoVersionMemoized(_)(fromProtoV2), supportedProtoVersionMemoized(_)(fromProtoV2),
_.toProtoV2.toByteString _.toProtoV2.toByteString
)""" )"""
): Assertion ): Assertion
} }
clue("can not use an unstable proto message in a stable protocol version") { clue("can not use an alpha proto message in a stable protocol version") {
assertTypeError( assertTypeError(
""" """
val _ = VersionedProtoConverter(stablePV)(VersionedMessageV2)( val _ = VersionedProtoConverter(stablePV)(VersionedMessageV2)(
@ -213,7 +213,7 @@ object HasProtocolVersionedWrapperTest {
protocolVersion 30 31 32 33 34 ... protocolVersion 30 31 32 33 34 ...
*/ */
override val supportedProtoVersions = SupportedProtoVersions( override val supportedProtoVersions = SupportedProtoVersions(
ProtoVersion(1) -> VersionedProtoConverter(ProtocolVersion.createUnstable((basePV + 2).v))( ProtoVersion(1) -> VersionedProtoConverter(ProtocolVersion.createAlpha((basePV + 2).v))(
VersionedMessageV1 VersionedMessageV1
)( )(
supportedProtoVersionMemoized(_)(fromProtoV1), supportedProtoVersionMemoized(_)(fromProtoV1),
@ -226,9 +226,9 @@ object HasProtocolVersionedWrapperTest {
supportedProtoVersionMemoized(_)(fromProtoV0), supportedProtoVersionMemoized(_)(fromProtoV0),
_.toProtoV0.toByteString, _.toProtoV0.toByteString,
), ),
// Can use an unstable Protobuf message in an unstable protocol version // Can use an alpha Protobuf message in an alpha protocol version
ProtoVersion(2) -> VersionedProtoConverter( ProtoVersion(2) -> VersionedProtoConverter(
ProtocolVersion.createUnstable((basePV + 3).v) ProtocolVersion.createAlpha((basePV + 3).v)
)(VersionedMessageV2)( )(VersionedMessageV2)(
supportedProtoVersionMemoized(_)(fromProtoV2), supportedProtoVersionMemoized(_)(fromProtoV2),
_.toProtoV2.toByteString, _.toProtoV2.toByteString,

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --target=2.1 - --target=2.1
name: ai-analysis name: ai-analysis

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --target=2.1 - --target=2.1
name: bank name: bank

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --target=2.1 - --target=2.1
name: doctor name: doctor

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --target=2.1 - --target=2.1
name: health-insurance name: health-insurance

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --target=2.1 - --target=2.1
name: medical-records name: medical-records

View File

@ -122,7 +122,7 @@ message OnboardingStateResponse {
} }
message OnboardingStateForSequencer { message OnboardingStateForSequencer {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
com.digitalasset.canton.topology.admin.v30.TopologyTransactions topology_snapshot = 1; com.digitalasset.canton.topology.admin.v30.TopologyTransactions topology_snapshot = 1;
com.digitalasset.canton.protocol.v30.StaticDomainParameters static_domain_parameters = 2; com.digitalasset.canton.protocol.v30.StaticDomainParameters static_domain_parameters = 2;

View File

@ -11,6 +11,7 @@ service SequencerBftAdministrationService {
rpc AddPeerEndpoint(AddPeerEndpointRequest) returns (AddPeerEndpointResponse); rpc AddPeerEndpoint(AddPeerEndpointRequest) returns (AddPeerEndpointResponse);
rpc RemovePeerEndpoint(RemovePeerEndpointRequest) returns (RemovePeerEndpointResponse); rpc RemovePeerEndpoint(RemovePeerEndpointRequest) returns (RemovePeerEndpointResponse);
rpc GetPeerNetworkStatus(GetPeerNetworkStatusRequest) returns (GetPeerNetworkStatusResponse); rpc GetPeerNetworkStatus(GetPeerNetworkStatusRequest) returns (GetPeerNetworkStatusResponse);
rpc GetOrderingTopology(GetOrderingTopologyRequest) returns (GetOrderingTopologyResponse);
} }
message AddPeerEndpointRequest { message AddPeerEndpointRequest {
@ -60,3 +61,12 @@ message GetPeerNetworkStatusRequest {
message GetPeerNetworkStatusResponse { message GetPeerNetworkStatusResponse {
repeated PeerEndpointStatus statuses = 1; repeated PeerEndpointStatus statuses = 1;
} }
message GetOrderingTopologyRequest {}
message GetOrderingTopologyResponse {
// The current epoch, through which the topology is valid.
int64 current_epoch = 1;
// The sequencer IDs of the active BFT ordering nodes in the network.
repeated string sequencer_ids = 2;
}

View File

@ -12,7 +12,7 @@ import "google/protobuf/wrappers.proto";
import "scalapb/scalapb.proto"; import "scalapb/scalapb.proto";
message SequencerSnapshot { message SequencerSnapshot {
option (scalapb.message).companion_extends = "com.digitalasset.canton.version.UnstableProtoVersion"; option (scalapb.message).companion_extends = "com.digitalasset.canton.version.AlphaProtoVersion";
int64 latest_timestamp = 1; // in microseconds of UTC time since Unix epoch int64 latest_timestamp = 1; // in microseconds of UTC time since Unix epoch
uint64 last_block_height = 2; uint64 last_block_height = 2;

View File

@ -36,7 +36,7 @@ final case class DomainParametersConfig(
requiredHashAlgorithms: Option[NonEmpty[Set[HashAlgorithm]]] = None, requiredHashAlgorithms: Option[NonEmpty[Set[HashAlgorithm]]] = None,
requiredCryptoKeyFormats: Option[NonEmpty[Set[CryptoKeyFormat]]] = None, requiredCryptoKeyFormats: Option[NonEmpty[Set[CryptoKeyFormat]]] = None,
// TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version // TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version
override val devVersionSupport: Boolean = true, override val alphaVersionSupport: Boolean = true,
override val betaVersionSupport: Boolean = false, override val betaVersionSupport: Boolean = false,
override val dontWarnOnDeprecatedPV: Boolean = false, override val dontWarnOnDeprecatedPV: Boolean = false,
) extends ProtocolConfig ) extends ProtocolConfig
@ -48,7 +48,8 @@ final case class DomainParametersConfig(
param("requiredSymmetricKeySchemes", _.requiredSymmetricKeySchemes), param("requiredSymmetricKeySchemes", _.requiredSymmetricKeySchemes),
param("requiredHashAlgorithms", _.requiredHashAlgorithms), param("requiredHashAlgorithms", _.requiredHashAlgorithms),
param("requiredCryptoKeyFormats", _.requiredCryptoKeyFormats), param("requiredCryptoKeyFormats", _.requiredCryptoKeyFormats),
param("devVersionSupport", _.devVersionSupport), param("alphaVersionSupport", _.alphaVersionSupport),
param("betaVersionSupport", _.betaVersionSupport),
param("dontWarnOnDeprecatedPV", _.dontWarnOnDeprecatedPV), param("dontWarnOnDeprecatedPV", _.dontWarnOnDeprecatedPV),
) )

View File

@ -90,7 +90,7 @@ abstract class MediatorNodeConfigCommon(
*/ */
final case class MediatorNodeParameterConfig( final case class MediatorNodeParameterConfig(
// TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version // TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version
override val devVersionSupport: Boolean = true, override val alphaVersionSupport: Boolean = true,
override val betaVersionSupport: Boolean = false, override val betaVersionSupport: Boolean = false,
override val dontWarnOnDeprecatedPV: Boolean = false, override val dontWarnOnDeprecatedPV: Boolean = false,
override val batching: BatchingConfig = BatchingConfig(), override val batching: BatchingConfig = BatchingConfig(),
@ -488,7 +488,7 @@ class MediatorNodeBootstrap(
timeouts = timeouts, timeouts = timeouts,
traceContextPropagation = parameters.tracing.propagation, traceContextPropagation = parameters.tracing.propagation,
clientProtocolVersions = clientProtocolVersions =
if (parameterConfig.devVersionSupport) ProtocolVersion.supported if (parameterConfig.alphaVersionSupport) ProtocolVersion.supported
else else
// TODO(#15561) Remove NonEmpty construct once stableAndSupported is NonEmpty again // TODO(#15561) Remove NonEmpty construct once stableAndSupported is NonEmpty again
NonEmpty NonEmpty

View File

@ -125,7 +125,7 @@ class BftOrderingMetrics(
val batchesOrdered: Meter = openTelemetryMetricsFactory.meter( val batchesOrdered: Meter = openTelemetryMetricsFactory.meter(
MetricInfo( MetricInfo(
prefix :+ s"ordered-batches", prefix :+ "ordered-batches",
summary = "Batches ordered", summary = "Batches ordered",
description = "Measures the total batches ordered.", description = "Measures the total batches ordered.",
qualification = MetricQualification.Traffic, qualification = MetricQualification.Traffic,
@ -134,7 +134,7 @@ class BftOrderingMetrics(
val blocksOrdered: Meter = openTelemetryMetricsFactory.meter( val blocksOrdered: Meter = openTelemetryMetricsFactory.meter(
MetricInfo( MetricInfo(
prefix :+ s"ordered-blocks", prefix :+ "ordered-blocks",
summary = "Blocks ordered", summary = "Blocks ordered",
description = "Measures the total blocks ordered.", description = "Measures the total blocks ordered.",
qualification = MetricQualification.Traffic, qualification = MetricQualification.Traffic,

View File

@ -14,13 +14,13 @@ import com.digitalasset.canton.config.{
/** Various parameters for non-standard sequencer settings /** Various parameters for non-standard sequencer settings
* *
* @param devVersionSupport if true, then dev version will be turned on, but we will brick this sequencer node if it is used for production. * @param alphaVersionSupport if true, then dev version will be turned on, but we will brick this sequencer node if it is used for production.
* @param dontWarnOnDeprecatedPV if true, then this sequencer will not emit a warning when configured to use protocol version 2.0.0. * @param dontWarnOnDeprecatedPV if true, then this sequencer will not emit a warning when configured to use protocol version 2.0.0.
* @param maxConfirmationRequestsBurstFactor how forgiving the rate limit is in case of bursts (so rate limit starts after observing an initial burst of factor * max_rate commands) * @param maxConfirmationRequestsBurstFactor how forgiving the rate limit is in case of bursts (so rate limit starts after observing an initial burst of factor * max_rate commands)
*/ */
final case class SequencerNodeParameterConfig( final case class SequencerNodeParameterConfig(
// TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version // TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version
override val devVersionSupport: Boolean = true, override val alphaVersionSupport: Boolean = true,
override val betaVersionSupport: Boolean = false, override val betaVersionSupport: Boolean = false,
override val dontWarnOnDeprecatedPV: Boolean = false, override val dontWarnOnDeprecatedPV: Boolean = false,
maxConfirmationRequestsBurstFactor: PositiveDouble = PositiveDouble.tryCreate(0.5), maxConfirmationRequestsBurstFactor: PositiveDouble = PositiveDouble.tryCreate(0.5),

View File

@ -7,12 +7,14 @@ import cats.implicits.*
import com.digitalasset.canton.config.RequireTypes.Port import com.digitalasset.canton.config.RequireTypes.Port
import com.digitalasset.canton.networking.Endpoint import com.digitalasset.canton.networking.Endpoint
import com.digitalasset.canton.sequencer.admin.v30.{ import com.digitalasset.canton.sequencer.admin.v30.{
GetOrderingTopologyResponse,
GetPeerNetworkStatusResponse, GetPeerNetworkStatusResponse,
PeerEndpoint, PeerEndpoint,
PeerEndpointHealth as ProtoPeerEndpointHealth, PeerEndpointHealth as ProtoPeerEndpointHealth,
PeerEndpointHealthStatus as ProtoPeerEndpointHealthStatus, PeerEndpointHealthStatus as ProtoPeerEndpointHealthStatus,
PeerEndpointStatus as ProtoPeerEndpointStatus, PeerEndpointStatus as ProtoPeerEndpointStatus,
} }
import com.digitalasset.canton.topology.SequencerId
object EnterpriseSequencerBftAdminData { object EnterpriseSequencerBftAdminData {
@ -89,4 +91,24 @@ object EnterpriseSequencerBftAdminData {
.sequence .sequence
.map(PeerNetworkStatus(_)) .map(PeerNetworkStatus(_))
} }
final case class OrderingTopology(currentEpoch: Long, sequencerIds: Seq[SequencerId]) {
def toProto: GetOrderingTopologyResponse =
GetOrderingTopologyResponse.of(currentEpoch, sequencerIds.map(_.toProtoPrimitive))
}
object OrderingTopology {
def fromProto(response: GetOrderingTopologyResponse): Either[String, OrderingTopology] =
response.sequencerIds
.map { sequencerIdString =>
for {
sequencerId <- SequencerId
.fromProtoPrimitive(sequencerIdString, "sequencerId")
.leftMap(_.toString)
} yield sequencerId
}
.sequence
.map(OrderingTopology(response.currentEpoch, _))
}
} }

View File

@ -7,7 +7,6 @@ import cats.Order.*
import cats.data.EitherT import cats.data.EitherT
import cats.kernel.Order import cats.kernel.Order
import cats.syntax.either.* import cats.syntax.either.*
import cats.syntax.functor.*
import cats.syntax.parallel.* import cats.syntax.parallel.*
import cats.{Functor, Show} import cats.{Functor, Show}
import com.daml.nonempty.NonEmpty import com.daml.nonempty.NonEmpty
@ -29,7 +28,7 @@ import com.digitalasset.canton.tracing.{HasTraceContext, TraceContext, Traced}
import com.digitalasset.canton.util.EitherTUtil.condUnitET import com.digitalasset.canton.util.EitherTUtil.condUnitET
import com.digitalasset.canton.util.FutureInstances.* import com.digitalasset.canton.util.FutureInstances.*
import com.digitalasset.canton.util.ShowUtil.* import com.digitalasset.canton.util.ShowUtil.*
import com.digitalasset.canton.util.retry import com.digitalasset.canton.util.{ErrorUtil, retry}
import com.digitalasset.canton.version.ProtocolVersion import com.digitalasset.canton.version.ProtocolVersion
import com.digitalasset.canton.{ProtoDeserializationError, SequencerCounter} import com.digitalasset.canton.{ProtoDeserializationError, SequencerCounter}
import com.google.common.annotations.VisibleForTesting import com.google.common.annotations.VisibleForTesting
@ -668,14 +667,15 @@ trait SequencerStore extends SequencerMemberValidator with NamedLogging with Aut
def saveRecentCheckpoints(): Future[Unit] = for { def saveRecentCheckpoints(): Future[Unit] = for {
checkpoints <- checkpointsAtTimestamp(requestedTimestamp.immediatePredecessor) checkpoints <- checkpointsAtTimestamp(requestedTimestamp.immediatePredecessor)
_ <- checkpoints.toList.parTraverse { case (member, checkpoint) => _ <- checkpoints.toList.parTraverse { case (member, checkpoint) =>
lookupMember(member).map { for {
case Some(RegisteredMember(memberId, _)) => memberId <- lookupMember(member).map(
saveCounterCheckpoint( _.fold(ErrorUtil.invalidState(s"Member $member should be registered"))(_.memberId)
memberId, )
checkpoint, _ <- saveCounterCheckpoint(
).value memberId,
case _ => Right(()) checkpoint,
} ).value
} yield ()
} }
} yield () } yield ()

View File

@ -17,13 +17,7 @@ import com.digitalasset.canton.lifecycle.{FlagCloseable, HasCloseContext}
import com.digitalasset.canton.sequencing.protocol.{MessageId, SequencerErrors} import com.digitalasset.canton.sequencing.protocol.{MessageId, SequencerErrors}
import com.digitalasset.canton.store.db.DbTest import com.digitalasset.canton.store.db.DbTest
import com.digitalasset.canton.time.NonNegativeFiniteDuration import com.digitalasset.canton.time.NonNegativeFiniteDuration
import com.digitalasset.canton.topology.{ import com.digitalasset.canton.topology.{DefaultTestIdentities, Member, ParticipantId}
DefaultTestIdentities,
Member,
ParticipantId,
SequencerId,
UniqueIdentifier,
}
import com.digitalasset.canton.util.FutureInstances.* import com.digitalasset.canton.util.FutureInstances.*
import com.digitalasset.canton.{BaseTest, ProtocolVersionChecksAsyncWordSpec, SequencerCounter} import com.digitalasset.canton.{BaseTest, ProtocolVersionChecksAsyncWordSpec, SequencerCounter}
import com.google.protobuf.ByteString import com.google.protobuf.ByteString
@ -43,9 +37,7 @@ trait SequencerStoreTest
with FlagCloseable with FlagCloseable
with ProtocolVersionChecksAsyncWordSpec { with ProtocolVersionChecksAsyncWordSpec {
lazy val sequencerMember: Member = SequencerId( lazy val sequencerMember: Member = DefaultTestIdentities.sequencerId
UniqueIdentifier.tryFromProtoPrimitive("sequencer::namespace")
)
def sequencerStore(mk: () => SequencerStore): Unit = { def sequencerStore(mk: () => SequencerStore): Unit = {

View File

@ -13,5 +13,5 @@ object TestProtocolVersions {
/** A valid, supported protocol version that is not part of the released protocol versions. /** A valid, supported protocol version that is not part of the released protocol versions.
*/ */
val UnreleasedValidPV: ProtocolVersion = ProtocolVersion.unstable.head val UnreleasedValidPV: ProtocolVersion = ProtocolVersion.alpha.head
} }

View File

@ -4,13 +4,13 @@
package com.digitalasset.canton.platform.apiserver.services.admin package com.digitalasset.canton.platform.apiserver.services.admin
import cats.data.EitherT import cats.data.EitherT
import com.digitalasset.daml.lf.archive.DamlLf.Archive
import com.daml.error.DamlError import com.daml.error.DamlError
import com.daml.logging.entries.LoggingValue.OfString import com.daml.logging.entries.LoggingValue.OfString
import com.digitalasset.canton.ledger.error.PackageServiceErrors.{InternalError, Validation} import com.digitalasset.canton.ledger.error.PackageServiceErrors.{InternalError, Validation}
import com.digitalasset.canton.logging.LoggingContextWithTrace.implicitExtractTraceContext import com.digitalasset.canton.logging.LoggingContextWithTrace.implicitExtractTraceContext
import com.digitalasset.canton.logging.{LoggingContextWithTrace, NamedLoggerFactory, NamedLogging} import com.digitalasset.canton.logging.{LoggingContextWithTrace, NamedLoggerFactory, NamedLogging}
import com.digitalasset.canton.platform.apiserver.services.admin.ApiPackageManagementService.ErrorValidations import com.digitalasset.canton.platform.apiserver.services.admin.ApiPackageManagementService.ErrorValidations
import com.digitalasset.daml.lf.archive.DamlLf.Archive
import com.digitalasset.daml.lf.archive.Decode import com.digitalasset.daml.lf.archive.Decode
import com.digitalasset.daml.lf.data.Ref import com.digitalasset.daml.lf.data.Ref
import com.digitalasset.daml.lf.language.Ast import com.digitalasset.daml.lf.language.Ast

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --enable-interfaces=yes - --enable-interfaces=yes
name: carbonv1-tests name: carbonv1-tests

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --enable-interfaces=yes - --enable-interfaces=yes
name: carbonv2-tests name: carbonv2-tests

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
name: experimental-tests name: experimental-tests
source: . source: .
version: 3.1.0 version: 3.1.0

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --enable-interfaces=yes - --enable-interfaces=yes
name: model-tests name: model-tests

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
name: package-management-tests name: package-management-tests
source: . source: .
version: 3.1.0 version: 3.1.0

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --enable-interfaces=yes - --enable-interfaces=yes
name: semantic-tests name: semantic-tests

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
name: upgrade-tests name: upgrade-tests
source: . source: .
version: 1.0.0 version: 1.0.0

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
name: upgrade-tests name: upgrade-tests
source: . source: .
version: 2.0.0 version: 2.0.0

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
name: upgrade-tests name: upgrade-tests
source: . source: .
version: 3.0.0 version: 3.0.0

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --target=2.1 - --target=2.1
name: JsonEncodingTest name: JsonEncodingTest

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --target=2.dev - --target=2.dev
name: JsonEncodingTestDev name: JsonEncodingTestDev

View File

@ -1,4 +1,4 @@
sdk-version: 3.1.0-snapshot.20240705.13166.0.v801ce9b3 sdk-version: 3.1.0-snapshot.20240708.13168.0.v7ed18470
build-options: build-options:
- --target=2.1 - --target=2.1
name: AdminWorkflows name: AdminWorkflows

View File

@ -882,7 +882,7 @@ object ParticipantNodeBootstrap {
override protected def createEngine(arguments: Arguments): Engine = override protected def createEngine(arguments: Arguments): Engine =
DAMLe.newEngine( DAMLe.newEngine(
enableLfDev = arguments.parameterConfig.devVersionSupport, enableLfDev = arguments.parameterConfig.alphaVersionSupport,
enableLfBeta = arguments.parameterConfig.betaVersionSupport, enableLfBeta = arguments.parameterConfig.betaVersionSupport,
enableStackTraces = arguments.parameterConfig.engine.enableEngineStackTraces, enableStackTraces = arguments.parameterConfig.engine.enableEngineStackTraces,
iterationsBetweenInterruptions = iterationsBetweenInterruptions =

View File

@ -45,7 +45,7 @@ final case class ParticipantNodeParameters(
) extends CantonNodeParameters ) extends CantonNodeParameters
with HasGeneralCantonNodeParameters { with HasGeneralCantonNodeParameters {
override def dontWarnOnDeprecatedPV: Boolean = protocolConfig.dontWarnOnDeprecatedPV override def dontWarnOnDeprecatedPV: Boolean = protocolConfig.dontWarnOnDeprecatedPV
override def devVersionSupport: Boolean = protocolConfig.devVersionSupport override def alphaVersionSupport: Boolean = protocolConfig.alphaVersionSupport
override def betaVersionSupport: Boolean = protocolConfig.betaVersionSupport override def betaVersionSupport: Boolean = protocolConfig.betaVersionSupport
} }
@ -82,7 +82,7 @@ object ParticipantNodeParameters {
protocolConfig = ParticipantProtocolConfig( protocolConfig = ParticipantProtocolConfig(
Some(testedProtocolVersion), Some(testedProtocolVersion),
// TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version // TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version
devVersionSupport = true, alphaVersionSupport = true,
betaVersionSupport = true, betaVersionSupport = true,
dontWarnOnDeprecatedPV = false, dontWarnOnDeprecatedPV = false,
), ),

View File

@ -95,7 +95,7 @@ object PartyNotificationConfig {
final case class ParticipantProtocolConfig( final case class ParticipantProtocolConfig(
minimumProtocolVersion: Option[ProtocolVersion], minimumProtocolVersion: Option[ProtocolVersion],
override val devVersionSupport: Boolean, override val alphaVersionSupport: Boolean,
override val betaVersionSupport: Boolean, override val betaVersionSupport: Boolean,
override val dontWarnOnDeprecatedPV: Boolean, override val dontWarnOnDeprecatedPV: Boolean,
) extends ProtocolConfig ) extends ProtocolConfig
@ -331,7 +331,7 @@ object TestingTimeServiceConfig {
* Setting to zero will disable reusing recent time proofs and will instead always fetch a new proof. * Setting to zero will disable reusing recent time proofs and will instead always fetch a new proof.
* @param minimumProtocolVersion The minimum protocol version that this participant will speak when connecting to a domain * @param minimumProtocolVersion The minimum protocol version that this participant will speak when connecting to a domain
* @param initialProtocolVersion The initial protocol version used by the participant (default latest), e.g., used to create the initial topology transactions. * @param initialProtocolVersion The initial protocol version used by the participant (default latest), e.g., used to create the initial topology transactions.
* @param devVersionSupport If set to true, will allow the participant to connect to a domain with dev protocol version and will turn on unsafe Daml LF versions. * @param alphaVersionSupport If set to true, will allow the participant to connect to a domain with dev protocol version and will turn on unsafe Daml LF versions.
* @param dontWarnOnDeprecatedPV If true, then this participant will not emit a warning when connecting to a sequencer using a deprecated protocol version (such as 2.0.0). * @param dontWarnOnDeprecatedPV If true, then this participant will not emit a warning when connecting to a sequencer using a deprecated protocol version (such as 2.0.0).
* @param warnIfOverloadedFor If all incoming commands have been rejected due to PARTICIPANT_BACKPRESSURE during this interval, the participant will log a warning. * @param warnIfOverloadedFor If all incoming commands have been rejected due to PARTICIPANT_BACKPRESSURE during this interval, the participant will log a warning.
* @param excludeInfrastructureTransactions If set, infrastructure transactions (i.e. ping, bong and dar distribution) will be excluded from participant metering. * @param excludeInfrastructureTransactions If set, infrastructure transactions (i.e. ping, bong and dar distribution) will be excluded from participant metering.
@ -357,7 +357,7 @@ final case class ParticipantNodeParameterConfig(
ProtocolVersion.latest ProtocolVersion.latest
), ),
// TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version // TODO(i15561): Revert back to `false` once there is a stable Daml 3 protocol version
devVersionSupport: Boolean = true, alphaVersionSupport: Boolean = true,
BetaVersionSupport: Boolean = false, BetaVersionSupport: Boolean = false,
dontWarnOnDeprecatedPV: Boolean = false, dontWarnOnDeprecatedPV: Boolean = false,
warnIfOverloadedFor: Option[config.NonNegativeFiniteDuration] = Some( warnIfOverloadedFor: Option[config.NonNegativeFiniteDuration] = Some(

View File

@ -41,7 +41,7 @@ object MockedNodeParameters {
override def loggingConfig: LoggingConfig = _loggingConfig override def loggingConfig: LoggingConfig = _loggingConfig
override def devVersionSupport: Boolean = ??? override def alphaVersionSupport: Boolean = ???
override def betaVersionSupport: Boolean = ??? override def betaVersionSupport: Boolean = ???

View File

@ -3,7 +3,7 @@
package com.digitalasset.canton.crypto.provider.symbolic package com.digitalasset.canton.crypto.provider.symbolic
import cats.data.EitherT import cats.data.{EitherT, OptionT}
import com.digitalasset.canton.concurrent.DirectExecutionContext import com.digitalasset.canton.concurrent.DirectExecutionContext
import com.digitalasset.canton.config.ProcessingTimeout import com.digitalasset.canton.config.ProcessingTimeout
import com.digitalasset.canton.crypto.* import com.digitalasset.canton.crypto.*
@ -37,27 +37,34 @@ class SymbolicCrypto(
loggerFactory, loggerFactory,
) { ) {
private def process[E, A]( private def processE[E, A](
description: String description: String
)(fn: TraceContext => EitherT[FutureUnlessShutdown, E, A]): A = { )(fn: TraceContext => EitherT[FutureUnlessShutdown, E, A]): A =
process(description)(fn(_).valueOr(err => sys.error(s"Failed operation $description: $err")))
private def processO[A](
description: String
)(fn: TraceContext => OptionT[FutureUnlessShutdown, A]): Option[A] =
process(description)(fn(_).value)
private def process[A](description: String)(fn: TraceContext => FutureUnlessShutdown[A]): A = {
TraceContext.withNewTraceContext { implicit traceContext => TraceContext.withNewTraceContext { implicit traceContext =>
timeouts.default.await(description) { timeouts.default.await(description) {
fn(traceContext) fn(traceContext)
.valueOr(err => sys.error(s"Failed operation $description: $err"))
.onShutdown(sys.error("aborted due to shutdown")) .onShutdown(sys.error("aborted due to shutdown"))
} }
} }
} }
def getOrGenerateSymbolicSigningKey(name: String): SigningPublicKey = { def getOrGenerateSymbolicSigningKey(name: String): SigningPublicKey = {
process("get or generate symbolic signing key") { implicit traceContext => processO("get or generate symbolic signing key") { implicit traceContext =>
cryptoPublicStore cryptoPublicStore
.findSigningKeyIdByName(KeyName.tryCreate(name)) .findSigningKeyIdByName(KeyName.tryCreate(name))
}.getOrElse(generateSymbolicSigningKey(Some(name))) }.getOrElse(generateSymbolicSigningKey(Some(name)))
} }
def getOrGenerateSymbolicEncryptionKey(name: String): EncryptionPublicKey = { def getOrGenerateSymbolicEncryptionKey(name: String): EncryptionPublicKey = {
process("get or generate symbolic encryption key") { implicit traceContext => processO("get or generate symbolic encryption key") { implicit traceContext =>
cryptoPublicStore cryptoPublicStore
.findEncryptionKeyIdByName(KeyName.tryCreate(name)) .findEncryptionKeyIdByName(KeyName.tryCreate(name))
}.getOrElse(generateSymbolicEncryptionKey(Some(name))) }.getOrElse(generateSymbolicEncryptionKey(Some(name)))
@ -67,7 +74,7 @@ class SymbolicCrypto(
def generateSymbolicSigningKey( def generateSymbolicSigningKey(
name: Option[String] = None name: Option[String] = None
): SigningPublicKey = { ): SigningPublicKey = {
process("generate symbolic signing key") { implicit traceContext => processE("generate symbolic signing key") { implicit traceContext =>
// We don't care about the signing key scheme in symbolic crypto // We don't care about the signing key scheme in symbolic crypto
generateSigningKey(SigningKeyScheme.Ed25519, name.map(KeyName.tryCreate)) generateSigningKey(SigningKeyScheme.Ed25519, name.map(KeyName.tryCreate))
} }
@ -75,7 +82,7 @@ class SymbolicCrypto(
/** Generates a new symbolic signing keypair but does not store it in the public store */ /** Generates a new symbolic signing keypair but does not store it in the public store */
def newSymbolicSigningKeyPair(): SigningKeyPair = { def newSymbolicSigningKeyPair(): SigningKeyPair = {
process("generate symbolic signing keypair") { implicit traceContext => processE("generate symbolic signing keypair") { implicit traceContext =>
// We don't care about the signing key scheme in symbolic crypto // We don't care about the signing key scheme in symbolic crypto
privateCrypto privateCrypto
.generateSigningKeypair(SigningKeyScheme.Ed25519) .generateSigningKeypair(SigningKeyScheme.Ed25519)
@ -85,7 +92,7 @@ class SymbolicCrypto(
def generateSymbolicEncryptionKey( def generateSymbolicEncryptionKey(
name: Option[String] = None name: Option[String] = None
): EncryptionPublicKey = ): EncryptionPublicKey =
process("generate symbolic encryption key") { implicit traceContext => processE("generate symbolic encryption key") { implicit traceContext =>
// We don't care about the encryption key scheme in symbolic crypto // We don't care about the encryption key scheme in symbolic crypto
generateEncryptionKey( generateEncryptionKey(
EncryptionKeyScheme.EciesP256HkdfHmacSha256Aes128Gcm, EncryptionKeyScheme.EciesP256HkdfHmacSha256Aes128Gcm,
@ -94,7 +101,7 @@ class SymbolicCrypto(
} }
def newSymbolicEncryptionKeyPair(): EncryptionKeyPair = { def newSymbolicEncryptionKeyPair(): EncryptionKeyPair = {
process("generate symbolic encryption keypair") { implicit traceContext => processE("generate symbolic encryption keypair") { implicit traceContext =>
// We don't care about the encryption key scheme in symbolic crypto // We don't care about the encryption key scheme in symbolic crypto
privateCrypto privateCrypto
.generateEncryptionKeypair(EncryptionKeyScheme.EciesP256HkdfHmacSha256Aes128Gcm) .generateEncryptionKeypair(EncryptionKeyScheme.EciesP256HkdfHmacSha256Aes128Gcm)
@ -102,7 +109,7 @@ class SymbolicCrypto(
} }
def sign(hash: Hash, signingKeyId: Fingerprint): Signature = def sign(hash: Hash, signingKeyId: Fingerprint): Signature =
process("symbolic signing") { implicit traceContext => processE("symbolic signing") { implicit traceContext =>
privateCrypto.sign(hash, signingKeyId) privateCrypto.sign(hash, signingKeyId)
} }
@ -128,7 +135,7 @@ object SymbolicCrypto {
DirectExecutionContext(loggerFactory.getLogger(this.getClass)) DirectExecutionContext(loggerFactory.getLogger(this.getClass))
val pureCrypto = new SymbolicPureCrypto() val pureCrypto = new SymbolicPureCrypto()
val cryptoPublicStore = new InMemoryCryptoPublicStore val cryptoPublicStore = new InMemoryCryptoPublicStore(loggerFactory)
val cryptoPrivateStore = new InMemoryCryptoPrivateStore(releaseProtocolVersion, loggerFactory) val cryptoPrivateStore = new InMemoryCryptoPrivateStore(releaseProtocolVersion, loggerFactory)
val privateCrypto = new SymbolicPrivateCrypto(pureCrypto, cryptoPrivateStore) val privateCrypto = new SymbolicPrivateCrypto(pureCrypto, cryptoPrivateStore)

View File

@ -7,6 +7,7 @@ import cats.data.{EitherT, OptionT}
import com.digitalasset.canton.BaseTest import com.digitalasset.canton.BaseTest
import com.digitalasset.canton.concurrent.{DirectExecutionContext, ExecutionContextMonitor} import com.digitalasset.canton.concurrent.{DirectExecutionContext, ExecutionContextMonitor}
import com.digitalasset.canton.discard.Implicits.DiscardOps import com.digitalasset.canton.discard.Implicits.DiscardOps
import com.digitalasset.canton.lifecycle.{FutureUnlessShutdown, UnlessShutdown}
import com.digitalasset.canton.logging.SuppressingLogger.LogEntryOptionality import com.digitalasset.canton.logging.SuppressingLogger.LogEntryOptionality
import com.digitalasset.canton.util.ErrorUtil import com.digitalasset.canton.util.ErrorUtil
import com.digitalasset.canton.util.Thereafter.syntax.* import com.digitalasset.canton.util.Thereafter.syntax.*
@ -195,6 +196,20 @@ class SuppressingLogger private[logging] (
checkLogsInternalError(assertion), checkLogsInternalError(assertion),
) )
def assertInternalErrorAsyncUS[T <: Throwable](
within: => FutureUnlessShutdown[_],
assertion: T => Assertion,
)(implicit c: ClassTag[T], pos: source.Position): FutureUnlessShutdown[Assertion] =
assertLogs(
within.transform {
case Success(_) =>
fail(s"An exception of type $c was expected, but no exception was thrown.")
case Failure(c(t)) => Success(UnlessShutdown.Outcome(assertion(t)))
case Failure(t) => fail(s"Exception has wrong type. Expected type: $c.", t)
}(directExecutionContext),
checkLogsInternalError(assertion),
)
/** Asserts that the sequence of logged warnings/errors meets a given sequence of assertions. /** Asserts that the sequence of logged warnings/errors meets a given sequence of assertions.
* Use this if the expected sequence of logged warnings/errors is deterministic. * Use this if the expected sequence of logged warnings/errors is deterministic.
* *

View File

@ -1 +1 @@
20240708.13628.v22bd0def 20240709.13636.vd03d4972

View File

@ -1,7 +1,7 @@
canton { canton {
parameters { parameters {
non-standard-config = yes non-standard-config = yes
dev-version-support = yes alpha-version-support = yes
} }
participants { participants {
build-and-lint-test { build-and-lint-test {
@ -10,7 +10,7 @@ canton {
# This test is run in exclusive mode to avoid clashes. # This test is run in exclusive mode to avoid clashes.
ledger-api.port = 5011 ledger-api.port = 5011
admin-api.port = 5012 admin-api.port = 5012
parameters.dev-version-support = yes parameters.alpha-version-support = yes
http-ledger-api-experimental { http-ledger-api-experimental {
allow-insecure-tokens = true allow-insecure-tokens = true
server { server {

View File

@ -185,9 +185,9 @@ getCantonConfig conf@SandboxConfig{..} portFile mCerts (ledgerPort, adminPort, s
[ "type" Aeson..= ("sim-clock" :: T.Text) ] [ "type" Aeson..= ("sim-clock" :: T.Text) ]
| Static <- [timeMode] ] | Static <- [timeMode] ]
-- TODO(https://github.com/DACH-NY/canton/issues/16458): once ProtocolVersion.latest -- TODO(https://github.com/DACH-NY/canton/issues/16458): once ProtocolVersion.latest
-- is stable, revert dev-version-support and non-standard-config to -- is stable, revert alpha-version-support and non-standard-config to
-- devVersionSupport here and below. -- devVersionSupport here and below.
, [ "dev-version-support" Aeson..= True] , [ "alpha-version-support" Aeson..= True]
, [ "non-standard-config" Aeson..= True] , [ "non-standard-config" Aeson..= True]
] ) ] )
, "participants" Aeson..= Aeson.object , "participants" Aeson..= Aeson.object
@ -207,7 +207,7 @@ getCantonConfig conf@SandboxConfig{..} portFile mCerts (ledgerPort, adminPort, s
] ] ] ]
| Just secret <- [mbSharedSecret] ] | Just secret <- [mbSharedSecret] ]
) )
, "parameters" Aeson..= Aeson.object [ "dev-version-support" Aeson..= True ] , "parameters" Aeson..= Aeson.object [ "alpha-version-support" Aeson..= True ]
] <> ] <>
[ "testing-time" Aeson..= Aeson.object [ "type" Aeson..= ("monotonic-time" :: T.Text) ] [ "testing-time" Aeson..= Aeson.object [ "type" Aeson..= ("monotonic-time" :: T.Text) ]
| Static <- [timeMode] | Static <- [timeMode]
@ -223,13 +223,13 @@ getCantonConfig conf@SandboxConfig{..} portFile mCerts (ledgerPort, adminPort, s
, storage , storage
, "public-api" Aeson..= port sequencerPublicPort , "public-api" Aeson..= port sequencerPublicPort
, "admin-api" Aeson..= port sequencerAdminPort , "admin-api" Aeson..= port sequencerAdminPort
, "parameters" Aeson..= Aeson.object [ "dev-version-support" Aeson..= True ] , "parameters" Aeson..= Aeson.object [ "alpha-version-support" Aeson..= True ]
] ]
] ]
, "mediators" Aeson..= Aeson.object , "mediators" Aeson..= Aeson.object
[ "mediator1" Aeson..= Aeson.object [ "mediator1" Aeson..= Aeson.object
[ "admin-api" Aeson..= port mediatorAdminPort [ "admin-api" Aeson..= port mediatorAdminPort
, "parameters" Aeson..= Aeson.object [ "dev-version-support" Aeson..= True ] , "parameters" Aeson..= Aeson.object [ "alpha-version-support" Aeson..= True ]
] ]
] ]
] ]

View File

@ -89,7 +89,7 @@ object CantonRunner {
val (adminPort, ledgerApiPort) = ports(i) val (adminPort, ledgerApiPort) = ports(i)
val participantId = config.participantIds(i) val participantId = config.participantIds(i)
// TODO(https://github.com/DACH-NY/canton/issues/16458): once ProtocolVersion.latest // TODO(https://github.com/DACH-NY/canton/issues/16458): once ProtocolVersion.latest
// is stable, revert dev-version-support and non-standard-config to // is stable, revert alpha-version-support and non-standard-config to
// devMode here and below. // devMode here and below.
s"""${participantId} { s"""${participantId} {
| admin-api.port = ${adminPort.port} | admin-api.port = ${adminPort.port}
@ -102,7 +102,7 @@ object CantonRunner {
| storage.type = memory | storage.type = memory
| parameters = { | parameters = {
| engine.enable-engine-stack-traces = true | engine.enable-engine-stack-traces = true
| dev-version-support = yes | alpha-version-support = yes
| disable-upgrade-validation = ${config.disableUpgradeValidation} | disable-upgrade-validation = ${config.disableUpgradeValidation}
| } | }
| ${timeType.fold("")(x => "testing-time.type = " + x)} | ${timeType.fold("")(x => "testing-time.type = " + x)}
@ -114,7 +114,7 @@ object CantonRunner {
s"""canton { s"""canton {
| parameters { | parameters {
| non-standard-config = yes | non-standard-config = yes
| dev-version-support = yes | alpha-version-support = yes
| ports-file = ${toJson(files.portsFile)} | ports-file = ${toJson(files.portsFile)}
| ${clockType.fold("")(x => "clock.type = " + x)} | ${clockType.fold("")(x => "clock.type = " + x)}
| } | }