From d666f76fbbf24cd70d67ad40e67c7094b8567b46 Mon Sep 17 00:00:00 2001 From: Samir Talwar Date: Wed, 28 Jul 2021 16:59:23 +0200 Subject: [PATCH] participant-integration-api: Switch to the v2 participant state API. [KVL-1002] (#10398) * participant-state: Give `ChangeId` its own file. * participant-state: Introduce `v1.CompletionInfo` for a while. `CompletionInfo` is identical to `SubmitterInfo`. Its purpose is to make the migration to v2 easier. It should not make it into the final version. * participant-integration-api: Switch to the v2 participant state API. This means that: - the API server and indexer expect v2 API traits - adapters are provided if you need to elevate your v1 API usage - the indexer internally uses v2 Updates - rejections are switched over to use the v2 format - Sandbox Classic uses v2 as the internal representation too (because it interacts directly with the underlying indexer representation, and is therefore tightly coupled) _kvutils_ and other users of the `StandaloneApiServer` and `StandaloneIndexerServer` use the adapters. CHANGELOG_BEGIN - [Integration Kit] The API server and indexer have switched over to v2 of the participant-state API. You can continue to use the v1 API, but you will need to wrap your ``ReadService`` and ``WriteService`` objects in the ``AdaptedV1ReadService`` and ``AdaptedV1WriteSerivce`` classes. CHANGELOG_END * participant-state: Remove v1.CompletionInfo. It's served its purpose. * kvutils: Remove an unnecessary line from `Runner`. * ledger-api-common: Delete a TODO; we'll track it elsewhere. * participant-integration-api: Use full words in `JdbcLedgerDao`. Just a little bit of cleanup. * ledger-api-common: Extract out the random submission ID generator. And introduce a trait, because, well, this is still the JVM. --- .../indexerbenchmark/IndexerBenchmark.scala | 5 +- .../ledger/api/SubmissionIdGenerator.scala | 20 ++ .../api/validation/CommandsValidator.scala | 14 +- .../services/grpc/GrpcCommandService.scala | 4 +- .../grpc/GrpcCommandSubmissionService.scala | 8 +- .../api/validation/ErrorFactories.scala | 17 +- .../digitalasset/ledger/api/DomainMocks.scala | 2 + .../SubmitRequestValidatorTest.scala | 41 +++- .../GrpcCommandSubmissionServiceSpec.scala | 26 +- .../com/digitalasset/ledger/api/domain.scala | 14 +- .../postgres/V2_1__Rebuild_Acs.scala | 40 +-- .../platform/apiserver/ApiServices.scala | 2 +- .../apiserver/StandaloneApiServer.scala | 2 +- .../execution/CommandExecutionResult.scala | 2 +- .../apiserver/execution/CommandExecutor.scala | 2 + .../LedgerTimeAwareCommandExecutor.scala | 14 +- .../StoreBackedCommandExecutor.scala | 8 +- .../execution/TimedCommandExecutor.scala | 4 +- .../services/ApiCommandService.scala | 2 + .../services/ApiSubmissionService.scala | 24 +- .../services/LedgerConfigProvider.scala | 8 +- .../admin/ApiConfigManagementService.scala | 2 +- .../admin/ApiPackageManagementService.scala | 2 +- .../admin/ApiParticipantPruningService.scala | 2 +- .../admin/ApiPartyManagementService.scala | 2 +- .../services/admin/SynchronousResponse.scala | 12 +- .../platform/indexer/ExecuteUpdate.scala | 52 ++-- .../main/scala/platform/indexer/Indexer.scala | 2 +- .../scala/platform/indexer/JdbcIndexer.scala | 4 +- .../scala/platform/indexer/OffsetUpdate.scala | 2 +- .../indexer/StandaloneIndexerServer.scala | 2 +- .../parallel/IndexerLoggingContext.scala | 23 +- .../parallel/ParallelIndexerFactory.scala | 2 +- .../store/CompletionFromTransaction.scala | 6 +- .../scala/platform/store/Conversions.scala | 33 ++- .../store/appendonlydao/JdbcLedgerDao.scala | 57 +++-- .../appendonlydao/SequentialWriteDao.scala | 2 +- .../events/PostCommitValidation.scala | 23 +- .../store/backend/UpdateToDbDto.scala | 42 ++-- .../platform/store/dao/JdbcLedgerDao.scala | 105 ++++---- .../scala/platform/store/dao/LedgerDao.scala | 14 +- .../platform/store/dao/MeteredLedgerDao.scala | 24 +- .../store/dao/events/ContractsTableH2.scala | 2 +- .../dao/events/ContractsTableOracle.scala | 2 +- .../dao/events/ContractsTablePostgres.scala | 2 +- .../dao/events/EventsTableH2Database.scala | 12 +- .../store/dao/events/EventsTableOracle.scala | 12 +- .../dao/events/EventsTablePostgresql.scala | 6 +- .../dao/events/PostCommitValidation.scala | 24 +- .../dao/events/TransactionIndexing.scala | 12 +- .../store/dao/events/TransactionsWriter.scala | 6 +- .../platform/store/entries/LedgerEntry.scala | 2 + .../JdbcAppendOnlyTransactionInsertion.scala | 8 +- .../dao/JdbcAtomicTransactionInsertion.scala | 10 +- .../dao/JdbcLedgerDaoCompletionsSpec.scala | 116 ++++----- .../dao/JdbcLedgerDaoDivulgenceSpec.scala | 17 +- .../store/dao/JdbcLedgerDaoSuite.scala | 80 +++--- .../dao/JdbcPipelinedInsertionsSpec.scala | 6 +- .../JdbcPipelinedTransactionInsertion.scala | 10 +- .../ApiConfigManagementServiceSpec.scala | 2 +- .../ApiPackageManagementServiceSpec.scala | 2 +- .../admin/ApiPartyManagementServiceSpec.scala | 2 +- .../StoreBackedCommandExecutorSpec.scala | 43 +++- .../services/ApiSubmissionServiceSpec.scala | 30 ++- .../services/LedgerConfigProviderSpec.scala | 2 +- .../index/TransactionConversionSpec.scala | 5 +- .../platform/indexer/ExecuteUpdateSpec.scala | 71 ++---- .../platform/indexer/JdbcIndexerSpec.scala | 4 +- .../parallel/ParallelIndexerFactorySpec.scala | 2 +- .../platform/store/ConversionsSpec.scala | 20 +- .../SequentialWriteDaoSpec.scala | 2 +- .../store/backend/UpdateToDbDtoSpec.scala | 227 +++++++++--------- .../dao/events/TransactionIndexingSpec.scala | 10 +- ledger/participant-state/BUILD.bazel | 1 + .../state/kvutils/app/Runner.scala | 14 +- .../integritycheck/IntegrityChecker.scala | 11 +- .../integritycheck/ReplayingReadService.scala | 2 +- .../participant/state/v2/ChangeId.scala | 16 ++ .../state/v2/DeduplicationPeriod.scala | 8 + .../state/v2/SubmissionResult.scala | 6 + .../participant/state/v2/SubmitterInfo.scala | 18 +- .../ledger/participant/state/v2/Update.scala | 33 ++- .../RecoveringIndexerIntegrationSpec.scala | 3 +- .../platform/sandbox/SandboxServer.scala | 2 +- .../stores/LedgerBackedWriteService.scala | 4 +- .../stores/SandboxIndexAndWriteService.scala | 2 +- .../sandbox/stores/ledger/Ledger.scala | 2 +- .../sandbox/stores/ledger/MeteredLedger.scala | 2 +- .../sandbox/stores/ledger/Rejection.scala | 18 +- .../stores/ledger/ScenarioLoader.scala | 9 +- .../ledger/inmemory/InMemoryLedger.scala | 4 +- .../sandbox/stores/ledger/sql/SqlLedger.scala | 24 +- .../TransactionTimeModelComplianceIT.scala | 93 +++++-- .../scala/platform/sandboxnext/Runner.scala | 14 +- 94 files changed, 1013 insertions(+), 694 deletions(-) create mode 100644 ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/SubmissionIdGenerator.scala create mode 100644 ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/ChangeId.scala diff --git a/ledger/indexer-benchmark/src/main/scala/ledger/indexerbenchmark/IndexerBenchmark.scala b/ledger/indexer-benchmark/src/main/scala/ledger/indexerbenchmark/IndexerBenchmark.scala index c5253140ba51..35391895609d 100644 --- a/ledger/indexer-benchmark/src/main/scala/ledger/indexerbenchmark/IndexerBenchmark.scala +++ b/ledger/indexer-benchmark/src/main/scala/ledger/indexerbenchmark/IndexerBenchmark.scala @@ -15,6 +15,7 @@ import com.daml.ledger.api.health.HealthStatus import com.daml.ledger.configuration.{Configuration, LedgerInitialConditions, LedgerTimeModel} import com.daml.ledger.offset.Offset import com.daml.ledger.participant.state.v1.{ReadService, Update} +import com.daml.ledger.participant.state.v2.AdaptedV1ReadService import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner} import com.daml.lf.data.Time import com.daml.logging.LoggingContext.newLoggingContext @@ -67,7 +68,7 @@ class IndexerBenchmark() { val updates = Await.result(createUpdates(config), Duration(10, "minute")) println("Creating read service and indexer...") - val readService = createReadService(updates) + val readService = new AdaptedV1ReadService(createReadService(updates)) val indexerFactory = new JdbcIndexer.Factory( ServerRole.Indexer, config.indexerConfig, @@ -87,7 +88,7 @@ class IndexerBenchmark() { _ = println("Setting up the index database...") indexer <- Await - .result(indexerFactory.migrateSchema(false), Duration(5, "minute")) + .result(indexerFactory.migrateSchema(allowExistingSchema = false), Duration(5, "minute")) .acquire() _ = println("Starting the indexing...") diff --git a/ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/SubmissionIdGenerator.scala b/ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/SubmissionIdGenerator.scala new file mode 100644 index 000000000000..d9cfe51f7b79 --- /dev/null +++ b/ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/SubmissionIdGenerator.scala @@ -0,0 +1,20 @@ +// Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.daml.ledger.api + +import java.util.UUID + +import com.daml.lf.data.Ref +import com.daml.lf.data.Ref.SubmissionId + +trait SubmissionIdGenerator { + def generate(): Ref.SubmissionId +} + +object SubmissionIdGenerator { + object Random extends SubmissionIdGenerator { + override def generate(): SubmissionId = + Ref.SubmissionId.assertFromString(UUID.randomUUID().toString) + } +} diff --git a/ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/validation/CommandsValidator.scala b/ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/validation/CommandsValidator.scala index 1389651cbaf7..fc5c9ee3a8a9 100644 --- a/ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/validation/CommandsValidator.scala +++ b/ledger/ledger-api-common/src/main/scala/com/digitalasset/ledger/api/validation/CommandsValidator.scala @@ -6,9 +6,7 @@ package com.daml.ledger.api.validation import java.time.{Duration, Instant} import com.daml.api.util.{DurationConversion, TimestampConversion} -import com.daml.lf.command._ -import com.daml.lf.data._ -import com.daml.ledger.api.domain +import com.daml.ledger.api.domain.LedgerId import com.daml.ledger.api.v1.commands.Command.Command.{ Create => ProtoCreate, CreateAndExercise => ProtoCreateAndExercise, @@ -17,17 +15,19 @@ import com.daml.ledger.api.v1.commands.Command.Command.{ ExerciseByKey => ProtoExerciseByKey, } import com.daml.ledger.api.v1.commands.{Command => ProtoCommand, Commands => ProtoCommands} +import com.daml.ledger.api.{SubmissionIdGenerator, domain} +import com.daml.lf.command._ +import com.daml.lf.data._ import com.daml.lf.value.{Value => Lf} -import com.daml.ledger.api.domain.LedgerId import com.daml.platform.server.api.validation.ErrorFactories._ import com.daml.platform.server.api.validation.FieldValidations.{requirePresence, _} import io.grpc.StatusRuntimeException import scalaz.syntax.tag._ -import scala.collection.immutable import scala.Ordering.Implicits.infixOrderingOps +import scala.collection.immutable -final class CommandsValidator(ledgerId: LedgerId) { +final class CommandsValidator(ledgerId: LedgerId, submissionIdGenerator: SubmissionIdGenerator) { import ValueValidator._ @@ -46,6 +46,7 @@ final class CommandsValidator(ledgerId: LedgerId) { appId <- requireLedgerString(commands.applicationId, "application_id") .map(domain.ApplicationId(_)) commandId <- requireLedgerString(commands.commandId, "command_id").map(domain.CommandId(_)) + submissionId = domain.SubmissionId(submissionIdGenerator.generate()) submitters <- CommandsValidator.validateSubmitters(commands) commandz <- requireNonEmpty(commands.commands, "commands") validatedCommands <- validateInnerCommands(commandz) @@ -68,6 +69,7 @@ final class CommandsValidator(ledgerId: LedgerId) { workflowId = workflowId, applicationId = appId, commandId = commandId, + submissionId = submissionId, actAs = submitters.actAs, readAs = submitters.readAs, submittedAt = currentUtcTime, diff --git a/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandService.scala b/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandService.scala index f86fe44a769b..d8cde4127d8c 100644 --- a/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandService.scala +++ b/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandService.scala @@ -5,6 +5,7 @@ package com.daml.platform.server.api.services.grpc import java.time.{Duration, Instant} +import com.daml.ledger.api.SubmissionIdGenerator import com.daml.ledger.api.domain.LedgerId import com.daml.ledger.api.v1.command_service.CommandServiceGrpc.CommandService import com.daml.ledger.api.v1.command_service._ @@ -23,6 +24,7 @@ class GrpcCommandService( currentLedgerTime: () => Instant, currentUtcTime: () => Instant, maxDeduplicationTime: () => Option[Duration], + generateSubmissionId: SubmissionIdGenerator, )(implicit executionContext: ExecutionContext) extends CommandService with GrpcApiService @@ -31,7 +33,7 @@ class GrpcCommandService( protected implicit val logger: Logger = LoggerFactory.getLogger(service.getClass) private[this] val validator = - new SubmitAndWaitRequestValidator(new CommandsValidator(ledgerId)) + new SubmitAndWaitRequestValidator(new CommandsValidator(ledgerId, generateSubmissionId)) override def submitAndWait(request: SubmitAndWaitRequest): Future[Empty] = validator diff --git a/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandSubmissionService.scala b/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandSubmissionService.scala index d4262c194460..c6d7de08449a 100644 --- a/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandSubmissionService.scala +++ b/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandSubmissionService.scala @@ -5,6 +5,7 @@ package com.daml.platform.server.api.services.grpc import java.time.{Duration, Instant} +import com.daml.ledger.api.SubmissionIdGenerator import com.daml.ledger.api.domain.LedgerId import com.daml.ledger.api.v1.command_submission_service.CommandSubmissionServiceGrpc.{ CommandSubmissionService => ApiCommandSubmissionService @@ -16,8 +17,8 @@ import com.daml.ledger.api.v1.command_submission_service.{ import com.daml.ledger.api.validation.{CommandsValidator, SubmitRequestValidator} import com.daml.metrics.{Metrics, Timed} import com.daml.platform.api.grpc.GrpcApiService -import com.daml.platform.server.api.{ProxyCloseable, ValidationLogger} import com.daml.platform.server.api.services.domain.CommandSubmissionService +import com.daml.platform.server.api.{ProxyCloseable, ValidationLogger} import com.daml.telemetry.{DefaultTelemetry, SpanAttribute, TelemetryContext} import com.google.protobuf.empty.Empty import io.grpc.ServerServiceDefinition @@ -31,6 +32,7 @@ class GrpcCommandSubmissionService( currentLedgerTime: () => Instant, currentUtcTime: () => Instant, maxDeduplicationTime: () => Option[Duration], + submissionIdGenerator: SubmissionIdGenerator, metrics: Metrics, )(implicit executionContext: ExecutionContext) extends ApiCommandSubmissionService @@ -39,7 +41,9 @@ class GrpcCommandSubmissionService( protected implicit val logger: Logger = LoggerFactory.getLogger(service.getClass) - private val validator = new SubmitRequestValidator(new CommandsValidator(ledgerId)) + private val validator = new SubmitRequestValidator( + new CommandsValidator(ledgerId, submissionIdGenerator) + ) override def submit(request: ApiSubmitRequest): Future[Empty] = { implicit val telemetryContext: TelemetryContext = diff --git a/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/validation/ErrorFactories.scala b/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/validation/ErrorFactories.scala index 14c30ce8a98b..13707435f159 100644 --- a/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/validation/ErrorFactories.scala +++ b/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/validation/ErrorFactories.scala @@ -24,24 +24,15 @@ trait ErrorFactories { def invalidArgument(errorMsg: String): StatusRuntimeException = grpcError(Status.INVALID_ARGUMENT.withDescription(s"Invalid argument: $errorMsg")) - def invalidField(fieldName: String, message: String) = + def invalidField(fieldName: String, message: String): StatusRuntimeException = grpcError(Status.INVALID_ARGUMENT.withDescription(s"Invalid field $fieldName: $message")) def outOfRange(description: String): StatusRuntimeException = grpcError(Status.OUT_OF_RANGE.withDescription(description)) - def notFound(target: String): StatusRuntimeException = - grpcError(Status.NOT_FOUND.withDescription(s"$target not found.")) - - def internal(description: String): StatusRuntimeException = - grpcError(Status.INTERNAL.withDescription(description)) - def aborted(description: String): StatusRuntimeException = grpcError(Status.ABORTED.withDescription(description)) - def unimplemented(description: String): StatusRuntimeException = - grpcError(Status.UNIMPLEMENTED.withDescription(description)) - // permission denied is intentionally without description to ensure we don't leak security relevant information by accident def permissionDenied(): StatusRuntimeException = grpcError(Status.PERMISSION_DENIED) @@ -52,13 +43,11 @@ trait ErrorFactories { def missingLedgerConfig(): StatusRuntimeException = grpcError(Status.UNAVAILABLE.withDescription("The ledger configuration is not available.")) - def resourceExhausted(description: String): StatusRuntimeException = - grpcError(Status.RESOURCE_EXHAUSTED.withDescription(description)) - def participantPrunedDataAccessed(message: String): StatusRuntimeException = grpcError(Status.NOT_FOUND.withDescription(message)) - def grpcError(status: Status) = new ApiException(status) + def grpcError(status: Status): StatusRuntimeException = + new ApiException(status) } diff --git a/ledger/ledger-api-common/src/test/lib/scala/com/digitalasset/ledger/api/DomainMocks.scala b/ledger/ledger-api-common/src/test/lib/scala/com/digitalasset/ledger/api/DomainMocks.scala index b5d66fa3f6c9..0ae8416bf0ac 100644 --- a/ledger/ledger-api-common/src/test/lib/scala/com/digitalasset/ledger/api/DomainMocks.scala +++ b/ledger/ledger-api-common/src/test/lib/scala/com/digitalasset/ledger/api/DomainMocks.scala @@ -20,6 +20,8 @@ object DomainMocks { val commandId = CommandId(Ref.LedgerString.assertFromString("commandId")) + val submissionId = SubmissionId(Ref.LedgerString.assertFromString("submissionId")) + val transactionId = TransactionId(Ref.LedgerString.assertFromString("deadbeef")) val applicationId = ApplicationId(Ref.LedgerString.assertFromString("applicationId")) diff --git a/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/ledger/api/validation/SubmitRequestValidatorTest.scala b/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/ledger/api/validation/SubmitRequestValidatorTest.scala index 1e6dc5cdf4be..8453680ccfff 100644 --- a/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/ledger/api/validation/SubmitRequestValidatorTest.scala +++ b/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/ledger/api/validation/SubmitRequestValidatorTest.scala @@ -4,10 +4,11 @@ package com.daml.ledger.api.validation import java.time.Instant +import java.util.UUID import com.daml.api.util.{DurationConversion, TimestampConversion} -import com.daml.ledger.api.DomainMocks -import com.daml.ledger.api.DomainMocks.{applicationId, commandId, workflowId} +import com.daml.ledger.api.{DomainMocks, SubmissionIdGenerator} +import com.daml.ledger.api.DomainMocks.{applicationId, commandId, submissionId, workflowId} import com.daml.ledger.api.domain.{LedgerId, Commands => ApiCommands} import com.daml.ledger.api.v1.commands.{Command, Commands, CreateCommand} import com.daml.ledger.api.v1.value.Value.Sum @@ -35,9 +36,6 @@ class SubmitRequestValidatorTest val int64 = Sum.Int64(1) val label = "label" val constructor = "constructor" - val workflowId = "workflowId" - val applicationId = "applicationId" - val commandId = "commandId" val submitter = "party" val deduplicationTime = new Duration().withSeconds(10) val command = Command.of( @@ -56,9 +54,9 @@ class SubmitRequestValidatorTest val commands = Commands( ledgerId = ledgerId.unwrap, - workflowId = workflowId, - applicationId = applicationId, - commandId = commandId, + workflowId = workflowId.unwrap, + applicationId = applicationId.unwrap, + commandId = commandId.unwrap, party = submitter, commands = Seq(command), deduplicationTime = Some(deduplicationTime), @@ -82,6 +80,7 @@ class SubmitRequestValidatorTest workflowId = Some(workflowId), applicationId = applicationId, commandId = commandId, + submissionId = submissionId, actAs = Set(DomainMocks.party), readAs = Set.empty, submittedAt = submittedAt, @@ -123,14 +122,17 @@ class SubmitRequestValidatorTest ) ) - val commandsValidator = new CommandsValidator(ledgerId) import ValueValidator.validateValue private def unexpectedError = sys.error("unexpected error") + private val generateRandomSubmissionId: SubmissionIdGenerator = + () => Ref.SubmissionId.assertFromString(UUID.randomUUID().toString) + "CommandSubmissionRequestValidator" when { "validating command submission requests" should { "reject requests with empty commands" in { + val commandsValidator = new CommandsValidator(ledgerId, generateRandomSubmissionId) requestMustFailWith( commandsValidator.validateCommands( api.commands.withCommands(Seq.empty), @@ -144,6 +146,7 @@ class SubmitRequestValidatorTest } "not allow missing ledgerId" in { + val commandsValidator = new CommandsValidator(ledgerId, generateRandomSubmissionId) requestMustFailWith( commandsValidator .validateCommands( @@ -158,6 +161,8 @@ class SubmitRequestValidatorTest } "tolerate a missing workflowId" in { + val generateSubmissionId: SubmissionIdGenerator = () => submissionId.unwrap + val commandsValidator = new CommandsValidator(ledgerId, generateSubmissionId) commandsValidator.validateCommands( api.commands.withWorkflowId(""), internal.ledgerTime, @@ -172,6 +177,7 @@ class SubmitRequestValidatorTest } "not allow missing applicationId" in { + val commandsValidator = new CommandsValidator(ledgerId, generateRandomSubmissionId) requestMustFailWith( commandsValidator.validateCommands( api.commands.withApplicationId(""), @@ -185,6 +191,7 @@ class SubmitRequestValidatorTest } "not allow missing commandId" in { + val commandsValidator = new CommandsValidator(ledgerId, generateRandomSubmissionId) requestMustFailWith( commandsValidator.validateCommands( api.commands.withCommandId(""), @@ -198,6 +205,7 @@ class SubmitRequestValidatorTest } "not allow missing submitter" in { + val commandsValidator = new CommandsValidator(ledgerId, generateRandomSubmissionId) requestMustFailWith( commandsValidator .validateCommands( @@ -212,6 +220,7 @@ class SubmitRequestValidatorTest } "correctly read and deduplicate multiple submitters" in { + val commandsValidator = new CommandsValidator(ledgerId, generateRandomSubmissionId) val result = commandsValidator .validateCommands( api.commands @@ -233,6 +242,8 @@ class SubmitRequestValidatorTest } "tolerate a single submitter specified in the actAs fields" in { + val generateSubmissionId: SubmissionIdGenerator = () => submissionId.unwrap + val commandsValidator = new CommandsValidator(ledgerId, generateSubmissionId) commandsValidator .validateCommands( api.commands.withParty("").addActAs(api.submitter), @@ -243,6 +254,8 @@ class SubmitRequestValidatorTest } "tolerate a single submitter specified in party, actAs, and readAs fields" in { + val generateSubmissionId: SubmissionIdGenerator = () => submissionId.unwrap + val commandsValidator = new CommandsValidator(ledgerId, generateSubmissionId) commandsValidator .validateCommands( api.commands.withParty(api.submitter).addActAs(api.submitter).addReadAs(api.submitter), @@ -254,6 +267,8 @@ class SubmitRequestValidatorTest "advance ledger time if minLedgerTimeAbs is set" in { val minLedgerTimeAbs = internal.ledgerTime.plus(internal.timeDelta) + val generateSubmissionId: SubmissionIdGenerator = () => submissionId.unwrap + val commandsValidator = new CommandsValidator(ledgerId, generateSubmissionId) commandsValidator.validateCommands( api.commands.copy( minLedgerTimeAbs = Some(TimestampConversion.fromInstant(minLedgerTimeAbs)) @@ -266,6 +281,8 @@ class SubmitRequestValidatorTest "advance ledger time if minLedgerTimeRel is set" in { val minLedgerTimeAbs = internal.ledgerTime.plus(internal.timeDelta) + val generateSubmissionId: SubmissionIdGenerator = () => submissionId.unwrap + val commandsValidator = new CommandsValidator(ledgerId, generateSubmissionId) commandsValidator.validateCommands( api.commands.copy( minLedgerTimeRel = Some(DurationConversion.toProto(internal.timeDelta)) @@ -277,6 +294,7 @@ class SubmitRequestValidatorTest } "not allow negative deduplication time" in { + val commandsValidator = new CommandsValidator(ledgerId, generateRandomSubmissionId) requestMustFailWith( commandsValidator.validateCommands( api.commands.copy(deduplicationTime = Some(Duration.of(-1, 0))), @@ -291,6 +309,7 @@ class SubmitRequestValidatorTest "not allow deduplication time exceeding maximum deduplication time" in { val manySeconds = 100000L + val commandsValidator = new CommandsValidator(ledgerId, generateRandomSubmissionId) requestMustFailWith( commandsValidator.validateCommands( api.commands.copy(deduplicationTime = Some(Duration.of(manySeconds, 0))), @@ -305,6 +324,8 @@ class SubmitRequestValidatorTest } "default to maximum deduplication time if deduplication time is missing" in { + val generateSubmissionId: SubmissionIdGenerator = () => submissionId.unwrap + val commandsValidator = new CommandsValidator(ledgerId, generateSubmissionId) commandsValidator.validateCommands( api.commands.copy(deduplicationTime = None), internal.ledgerTime, @@ -318,6 +339,7 @@ class SubmitRequestValidatorTest } "not allow missing ledger configuration" in { + val commandsValidator = new CommandsValidator(ledgerId, generateRandomSubmissionId) requestMustFailWith( commandsValidator .validateCommands(api.commands, internal.ledgerTime, internal.submittedAt, None), @@ -325,7 +347,6 @@ class SubmitRequestValidatorTest "The ledger configuration is not available.", ) } - } "validating contractId values" should { diff --git a/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandSubmissionServiceSpec.scala b/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandSubmissionServiceSpec.scala index 0c363861ae37..f679f8bb8848 100644 --- a/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandSubmissionServiceSpec.scala +++ b/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/platform/server/api/services/grpc/GrpcCommandSubmissionServiceSpec.scala @@ -19,6 +19,7 @@ import com.daml.ledger.api.testing.utils.MockMessages.{ } import com.daml.ledger.api.v1.commands.{Command, CreateCommand} import com.daml.ledger.api.v1.value.{Identifier, Record, RecordField, Value} +import com.daml.lf.data.Ref import com.daml.metrics.Metrics import com.daml.platform.server.api.services.domain.CommandSubmissionService import com.daml.telemetry.{SpanAttribute, TelemetryContext, TelemetrySpecBase} @@ -48,6 +49,7 @@ class GrpcCommandSubmissionServiceSpec currentLedgerTime = () => Instant.EPOCH, currentUtcTime = () => Instant.EPOCH, maxDeduplicationTime = () => Some(Duration.ZERO), + submissionIdGenerator = () => Ref.SubmissionId.assertFromString("submissionId"), metrics = new Metrics(new MetricRegistry), ) @@ -72,21 +74,19 @@ class GrpcCommandSubmissionServiceSpec } object GrpcCommandSubmissionServiceSpec { - private val aCommand = { - Command( - Command.Command.Create( - CreateCommand( - Some(Identifier("package", moduleName = "module", entityName = "entity")), - Some( - Record( - Some(Identifier("package", moduleName = "module", entityName = "entity")), - Seq(RecordField("something", Some(Value(Value.Sum.Bool(true))))), - ) - ), - ) + private val aCommand = Command.of( + Command.Command.Create( + CreateCommand( + Some(Identifier("package", moduleName = "module", entityName = "entity")), + Some( + Record( + Some(Identifier("package", moduleName = "module", entityName = "entity")), + Seq(RecordField("something", Some(Value(Value.Sum.Bool(true))))), + ) + ), ) ) - } + ) private val aSubmitRequest = submitRequest.copy( commands = Some(commands.copy(commands = Seq(aCommand))) diff --git a/ledger/ledger-api-domain/src/main/scala/com/digitalasset/ledger/api/domain.scala b/ledger/ledger-api-domain/src/main/scala/com/digitalasset/ledger/api/domain.scala index 2db6943fb4a0..95cb41380b3f 100644 --- a/ledger/ledger-api-domain/src/main/scala/com/digitalasset/ledger/api/domain.scala +++ b/ledger/ledger-api-domain/src/main/scala/com/digitalasset/ledger/api/domain.scala @@ -228,17 +228,17 @@ object domain { sealed trait WorkflowIdTag - type WorkflowId = Ref.LedgerString @@ WorkflowIdTag + type WorkflowId = Ref.WorkflowId @@ WorkflowIdTag val WorkflowId: Tag.TagOf[WorkflowIdTag] = Tag.of[WorkflowIdTag] sealed trait CommandIdTag - type CommandId = Ref.LedgerString @@ CommandIdTag + type CommandId = Ref.CommandId @@ CommandIdTag val CommandId: Tag.TagOf[CommandIdTag] = Tag.of[CommandIdTag] sealed trait TransactionIdTag - type TransactionId = Ref.LedgerString @@ TransactionIdTag + type TransactionId = Ref.TransactionId @@ TransactionIdTag val TransactionId: Tag.TagOf[TransactionIdTag] = Tag.of[TransactionIdTag] sealed trait ContractIdTag @@ -265,14 +265,20 @@ object domain { sealed trait ApplicationIdTag - type ApplicationId = Ref.LedgerString @@ ApplicationIdTag + type ApplicationId = Ref.ApplicationId @@ ApplicationIdTag val ApplicationId: Tag.TagOf[ApplicationIdTag] = Tag.of[ApplicationIdTag] + sealed trait SubmissionIdTag + + type SubmissionId = Ref.SubmissionId @@ SubmissionIdTag + val SubmissionId: Tag.TagOf[SubmissionIdTag] = Tag.of[SubmissionIdTag] + case class Commands( ledgerId: LedgerId, workflowId: Option[WorkflowId], applicationId: ApplicationId, commandId: CommandId, + submissionId: SubmissionId, actAs: Set[Ref.Party], readAs: Set[Ref.Party], submittedAt: Instant, diff --git a/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V2_1__Rebuild_Acs.scala b/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V2_1__Rebuild_Acs.scala index b97f76293e52..66cb3783beba 100644 --- a/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V2_1__Rebuild_Acs.scala +++ b/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V2_1__Rebuild_Acs.scala @@ -7,7 +7,7 @@ package com.daml.platform.db.migration.postgres import java.io.InputStream import java.sql.Connection -import java.util.Date +import java.util.{Date, UUID} import akka.NotUsed import akka.stream.scaladsl.Source @@ -287,6 +287,7 @@ private[migration] class V2_1__Rebuild_Acs extends BaseJavaMigration { transactionId, _, _, + _, workflowId, ledgerEffectiveTime, _, @@ -429,7 +430,7 @@ private[migration] class V2_1__Rebuild_Acs extends BaseJavaMigration { "ledger_offset", ) - private val DisclosureParser = (eventId("event_id") ~ party("party") map (flatten)) + private val DisclosureParser = eventId("event_id") ~ party("party") map flatten private def toLedgerEntry( parsedEntry: ParsedEntry @@ -455,17 +456,18 @@ private[migration] class V2_1__Rebuild_Acs extends BaseJavaMigration { .transform((_, v) => v.map(_._2).toSet) offset -> LedgerEntry.Transaction( - Some(commandId), - transactionId, - Some(applicationId), - List(submitter), - workflowId, - effectiveAt.toInstant, - recordedAt.toInstant, - transactionSerializer + commandId = Some(commandId), + transactionId = transactionId, + applicationId = Some(applicationId), + submissionId = None, + actAs = List(submitter), + workflowId = workflowId, + ledgerEffectiveTime = effectiveAt.toInstant, + recordedAt = recordedAt.toInstant, + transaction = transactionSerializer .deserializeTransaction(transactionId, transactionStream) .getOrElse(sys.error(s"failed to deserialize transaction! trId: $transactionId")), - Relation.mapKeys(disclosure)(_.nodeId), + explicitDisclosure = Relation.mapKeys(disclosure)(_.nodeId), ) case ParsedEntry( "rejection", @@ -481,9 +483,17 @@ private[migration] class V2_1__Rebuild_Acs extends BaseJavaMigration { Some(rejectionDescription), offset, ) => + // We don't have a submission ID, so we need to generate one. + val submissionId = Ref.SubmissionId.assertFromString(UUID.randomUUID().toString) val rejectionReason = readRejectionReason(rejectionType, rejectionDescription) - offset -> LedgerEntry - .Rejection(recordedAt.toInstant, commandId, applicationId, List(submitter), rejectionReason) + offset -> LedgerEntry.Rejection( + recordTime = recordedAt.toInstant, + commandId = commandId, + applicationId = applicationId, + submissionId = submissionId, + actAs = List(submitter), + rejectionReason = rejectionReason, + ) case invalidRow => sys.error(s"invalid ledger entry for offset: ${invalidRow.offset}. database row: $invalidRow") } @@ -501,7 +511,7 @@ private[migration] class V2_1__Rebuild_Acs extends BaseJavaMigration { ~ date("recorded_at") ~ binaryStream("contract") ~ binaryStream("key").? - ~ binaryStream("transaction") map (flatten)) + ~ binaryStream("transaction") map flatten) private val SQL_SELECT_CONTRACT_LET = SQL( @@ -544,7 +554,7 @@ private[migration] class V2_1__Rebuild_Acs extends BaseJavaMigration { private def executeBatchSql(query: String, params: Iterable[Seq[NamedParameter]])(implicit con: Connection ) = { - require(params.size > 0, "batch sql statement must have at least one set of name parameters") + require(params.nonEmpty, "batch sql statement must have at least one set of name parameters") BatchSql(query, params.head, params.drop(1).toSeq: _*).execute() } diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/ApiServices.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/ApiServices.scala index 48946eda4809..94099028e252 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/ApiServices.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/ApiServices.scala @@ -15,7 +15,7 @@ import com.daml.ledger.api.health.HealthChecks import com.daml.ledger.api.v1.command_completion_service.CompletionEndRequest import com.daml.ledger.client.services.commands.CommandSubmissionFlow import com.daml.ledger.participant.state.index.v2._ -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner} import com.daml.lf.data.Ref import com.daml.lf.engine._ diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/StandaloneApiServer.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/StandaloneApiServer.scala index 249ace16e179..5ca534e95c1a 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/StandaloneApiServer.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/StandaloneApiServer.scala @@ -15,7 +15,7 @@ import com.daml.ledger.api.auth.{AuthService, Authorizer} import com.daml.ledger.api.domain import com.daml.ledger.api.health.HealthChecks import com.daml.ledger.configuration.LedgerId -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner} import com.daml.lf.data.Ref import com.daml.lf.engine.{Engine, ValueEnricher} diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/CommandExecutionResult.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/CommandExecutionResult.scala index 308f6bbc5c81..1dff59255bf0 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/CommandExecutionResult.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/CommandExecutionResult.scala @@ -3,7 +3,7 @@ package com.daml.platform.apiserver.execution -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.transaction.SubmittedTransaction /** The result of command execution. diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/CommandExecutor.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/CommandExecutor.scala index a523af57c9b9..bc72eb63f901 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/CommandExecutor.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/CommandExecutor.scala @@ -4,6 +4,7 @@ package com.daml.platform.apiserver.execution import com.daml.ledger.api.domain.{Commands => ApiCommands} +import com.daml.ledger.configuration.Configuration import com.daml.lf.crypto import com.daml.logging.LoggingContext import com.daml.platform.store.ErrorCause @@ -14,6 +15,7 @@ private[apiserver] trait CommandExecutor { def execute( commands: ApiCommands, submissionSeed: crypto.Hash, + ledgerConfiguration: Configuration, )(implicit ec: ExecutionContext, loggingContext: LoggingContext, diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/LedgerTimeAwareCommandExecutor.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/LedgerTimeAwareCommandExecutor.scala index 081f40e1bc5a..04fd8fbc16ae 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/LedgerTimeAwareCommandExecutor.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/LedgerTimeAwareCommandExecutor.scala @@ -4,6 +4,7 @@ package com.daml.platform.apiserver.execution import com.daml.ledger.api.domain.Commands +import com.daml.ledger.configuration.Configuration import com.daml.ledger.participant.state.index.v2.ContractStore import com.daml.lf.crypto import com.daml.lf.data.Time @@ -31,22 +32,24 @@ private[apiserver] final class LedgerTimeAwareCommandExecutor( override def execute( commands: Commands, submissionSeed: crypto.Hash, + ledgerConfiguration: Configuration, )(implicit ec: ExecutionContext, loggingContext: LoggingContext, ): Future[Either[ErrorCause, CommandExecutionResult]] = - loop(commands, submissionSeed, maxRetries) + loop(commands, submissionSeed, ledgerConfiguration, maxRetries) private[this] def loop( commands: Commands, submissionSeed: crypto.Hash, + ledgerConfiguration: Configuration, retriesLeft: Int, )(implicit ec: ExecutionContext, loggingContext: LoggingContext, ): Future[Either[ErrorCause, CommandExecutionResult]] = { delegate - .execute(commands, submissionSeed) + .execute(commands, submissionSeed, ledgerConfiguration) .flatMap { case e @ Left(_) => // Permanently failed @@ -79,7 +82,12 @@ private[apiserver] final class LedgerTimeAwareCommandExecutor( logger.debug( s"Restarting the computation with new ledger effective time $maxUsedTime" ) - loop(advanceInputTime(commands, maxUsedTime), submissionSeed, retriesLeft - 1) + loop( + advanceInputTime(commands, maxUsedTime), + submissionSeed, + ledgerConfiguration, + retriesLeft - 1, + ) } else { Future.successful(Left(ErrorCause.LedgerTime(maxRetries))) } diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/StoreBackedCommandExecutor.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/StoreBackedCommandExecutor.scala index ce60bef542c8..a4620cc2757c 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/StoreBackedCommandExecutor.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/StoreBackedCommandExecutor.scala @@ -7,8 +7,9 @@ import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicLong import com.daml.ledger.api.domain.{Commands => ApiCommands} +import com.daml.ledger.configuration.Configuration import com.daml.ledger.participant.state.index.v2.{ContractStore, IndexPackagesService} -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.crypto import com.daml.lf.data.{ImmArray, Ref} import com.daml.lf.engine.{ @@ -43,6 +44,7 @@ private[apiserver] final class StoreBackedCommandExecutor( override def execute( commands: ApiCommands, submissionSeed: crypto.Hash, + ledgerConfiguration: Configuration, )(implicit ec: ExecutionContext, loggingContext: LoggingContext, @@ -77,7 +79,9 @@ private[apiserver] final class StoreBackedCommandExecutor( commands.actAs.toList, commands.applicationId.unwrap, commands.commandId.unwrap, - commands.deduplicateUntil, + state.DeduplicationPeriod.DeduplicationDuration(commands.deduplicationDuration), + commands.submissionId.unwrap, + ledgerConfiguration, ), transactionMeta = state.TransactionMeta( commands.commands.ledgerEffectiveTime, diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/TimedCommandExecutor.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/TimedCommandExecutor.scala index 3553e796f48d..0fc31ef528f0 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/TimedCommandExecutor.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/execution/TimedCommandExecutor.scala @@ -4,6 +4,7 @@ package com.daml.platform.apiserver.execution import com.daml.ledger.api.domain +import com.daml.ledger.configuration.Configuration import com.daml.lf.crypto import com.daml.logging.LoggingContext import com.daml.metrics.{Metrics, Timed} @@ -19,6 +20,7 @@ private[apiserver] class TimedCommandExecutor( override def execute( commands: domain.Commands, submissionSeed: crypto.Hash, + ledgerConfiguration: Configuration, )(implicit ec: ExecutionContext, loggingContext: LoggingContext, @@ -26,7 +28,7 @@ private[apiserver] class TimedCommandExecutor( Timed.timedAndTrackedFuture( metrics.daml.execution.total, metrics.daml.execution.totalRunning, - delegate.execute(commands, submissionSeed), + delegate.execute(commands, submissionSeed, ledgerConfiguration), ) } diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/ApiCommandService.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/ApiCommandService.scala index c615e77d38f7..c0f8f832b204 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/ApiCommandService.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/ApiCommandService.scala @@ -10,6 +10,7 @@ import akka.actor.Cancellable import akka.stream.Materializer import akka.stream.scaladsl.{Flow, Keep, Source} import com.daml.api.util.TimeProvider +import com.daml.ledger.api.SubmissionIdGenerator import com.daml.ledger.api.domain.LedgerId import com.daml.ledger.api.v1.command_completion_service.{ CompletionEndResponse, @@ -209,6 +210,7 @@ private[apiserver] object ApiCommandService { currentUtcTime = () => Instant.now, maxDeduplicationTime = () => ledgerConfigProvider.latestConfiguration.map(_.maxDeduplicationTime), + generateSubmissionId = SubmissionIdGenerator.Random, ) final case class Configuration( diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/ApiSubmissionService.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/ApiSubmissionService.scala index 93f876d68fe9..2476fb475051 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/ApiSubmissionService.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/ApiSubmissionService.scala @@ -7,11 +7,12 @@ import java.time.{Duration, Instant} import java.util.UUID import com.daml.api.util.TimeProvider +import com.daml.ledger.api.SubmissionIdGenerator import com.daml.ledger.api.domain.{LedgerId, Commands => ApiCommands} import com.daml.ledger.api.messages.command.submission.SubmitRequest import com.daml.ledger.configuration.Configuration import com.daml.ledger.participant.state.index.v2._ -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.crypto import com.daml.lf.data.Ref import com.daml.lf.engine.{Error => LfError} @@ -73,6 +74,7 @@ private[apiserver] object ApiSubmissionService { currentUtcTime = () => Instant.now, maxDeduplicationTime = () => ledgerConfigProvider.latestConfiguration.map(_.maxDeduplicationTime), + submissionIdGenerator = SubmissionIdGenerator.Random, metrics = metrics, ) @@ -150,21 +152,9 @@ private[apiserver] final class ApiSubmissionService private[services] ( logger.debug("Success") Success(()) - case Success(Overloaded) => - logger.info("Back-pressure") - Failure(Status.RESOURCE_EXHAUSTED.asRuntimeException) - - case Success(NotSupported) => - logger.warn("Not supported") - Failure(Status.INVALID_ARGUMENT.asRuntimeException) - - case Success(InternalError(reason)) => - logger.error(s"Internal error: $reason") - Failure(Status.INTERNAL.augmentDescription(reason).asRuntimeException) - - case Success(SynchronousReject(failure)) => - logger.info(s"Rejected: ${failure.getStatus}") - Failure(failure) + case Success(result: SynchronousError) => + logger.info(s"Rejected: ${result.description}") + Failure(result.exception) case Failure(error) => logger.info(s"Rejected: ${error.getMessage}") @@ -192,7 +182,7 @@ private[apiserver] final class ApiSubmissionService private[services] ( telemetryContext: TelemetryContext, ): Future[state.SubmissionResult] = for { - result <- commandExecutor.execute(commands, submissionSeed) + result <- commandExecutor.execute(commands, submissionSeed, ledgerConfig) transactionInfo <- handleCommandExecutionResult(result) partyAllocationResults <- allocateMissingInformees(transactionInfo.transaction) submissionResult <- submitTransaction(transactionInfo, partyAllocationResults, ledgerConfig) diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/LedgerConfigProvider.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/LedgerConfigProvider.scala index 7318892f6792..55fa6c1ee412 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/LedgerConfigProvider.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/LedgerConfigProvider.scala @@ -14,7 +14,7 @@ import com.daml.ledger.api.domain import com.daml.ledger.api.domain.LedgerOffset import com.daml.ledger.configuration.Configuration import com.daml.ledger.participant.state.index.v2.IndexConfigManagementService -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.ResourceOwner import com.daml.lf.data.Ref import com.daml.lf.data.Time.Timestamp @@ -164,11 +164,9 @@ private[apiserver] final class LedgerConfigProvider private ( .map { case state.SubmissionResult.Acknowledged => logger.info(s"Initial configuration submission $submissionId was successful") - case state.SubmissionResult.NotSupported => - logger.info("Setting an initial ledger configuration is not supported") - case result => + case result: state.SubmissionResult.SynchronousError => logger.warn( - s"Initial configuration submission $submissionId failed. Reason: ${result.description}" + s"Initial configuration submission $submissionId failed. Code: ${result.status.getCode}, Reason: ${result.description}" ) } } diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiConfigManagementService.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiConfigManagementService.scala index 3d6a090d448f..83bb6efaec66 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiConfigManagementService.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiConfigManagementService.scala @@ -14,7 +14,7 @@ import com.daml.ledger.api.v1.admin.config_management_service.ConfigManagementSe import com.daml.ledger.api.v1.admin.config_management_service._ import com.daml.ledger.configuration.{Configuration, LedgerTimeModel} import com.daml.ledger.participant.state.index.v2.IndexConfigManagementService -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.{Ref, Time} import com.daml.logging.LoggingContext.withEnrichedLoggingContext import com.daml.logging.{ContextualizedLogger, LoggingContext} diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiPackageManagementService.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiPackageManagementService.scala index aa1a5b13e0a0..c21668fd8b0b 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiPackageManagementService.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiPackageManagementService.scala @@ -17,7 +17,7 @@ import com.daml.ledger.participant.state.index.v2.{ IndexTransactionsService, LedgerEndService, } -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.archive.{Dar, DarParser, Decode, GenDarReader} import com.daml.lf.data.Ref import com.daml.lf.engine.Engine diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiParticipantPruningService.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiParticipantPruningService.scala index e17dc2bcc2e8..baaa2e8b48d9 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiParticipantPruningService.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiParticipantPruningService.scala @@ -12,7 +12,7 @@ import com.daml.ledger.api.v1.admin.participant_pruning_service.{ } import com.daml.ledger.offset.Offset import com.daml.ledger.participant.state.index.v2.{IndexParticipantPruningService, LedgerEndService} -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref import com.daml.logging.{ContextualizedLogger, LoggingContext} import com.daml.platform.ApiOffset diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiPartyManagementService.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiPartyManagementService.scala index 6be4673f19bb..42ab50071b60 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiPartyManagementService.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/ApiPartyManagementService.scala @@ -16,7 +16,7 @@ import com.daml.ledger.participant.state.index.v2.{ IndexTransactionsService, LedgerEndService, } -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref import com.daml.logging.LoggingContext.withEnrichedLoggingContext import com.daml.logging.{ContextualizedLogger, LoggingContext} diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/SynchronousResponse.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/SynchronousResponse.scala index 0d2e4e2a5ee1..5888a57c7642 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/SynchronousResponse.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/admin/SynchronousResponse.scala @@ -9,8 +9,8 @@ import java.util.concurrent.TimeUnit import akka.stream.Materializer import akka.stream.scaladsl.{Sink, Source} import com.daml.ledger.api.domain.LedgerOffset +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref -import com.daml.ledger.participant.state.{v1 => state} import com.daml.platform.apiserver.services.admin.SynchronousResponse.{Accepted, Rejected} import com.daml.platform.server.api.validation.ErrorFactories import com.daml.telemetry.TelemetryContext @@ -54,14 +54,8 @@ class SynchronousResponse[Input, Entry, AcceptedEntry]( Future.failed(ErrorFactories.aborted("Request timed out")) } .flatten - case r @ SubmissionResult.SynchronousReject(_) => - Future.failed(r.failure) - case r @ SubmissionResult.Overloaded => - Future.failed(ErrorFactories.resourceExhausted(r.description)) - case r @ SubmissionResult.InternalError(_) => - Future.failed(ErrorFactories.internal(r.reason)) - case r @ SubmissionResult.NotSupported => - Future.failed(ErrorFactories.unimplemented(r.description)) + case r: SubmissionResult.SynchronousError => + Future.failed(r.exception) } } yield entry } diff --git a/ledger/participant-integration-api/src/main/scala/platform/indexer/ExecuteUpdate.scala b/ledger/participant-integration-api/src/main/scala/platform/indexer/ExecuteUpdate.scala index dab20db0ebe1..e6ec4faded3a 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/indexer/ExecuteUpdate.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/indexer/ExecuteUpdate.scala @@ -3,7 +3,7 @@ package com.daml.platform.indexer -import java.time.{Duration, Instant} +import java.time.Duration import akka.NotUsed import akka.stream.scaladsl.Flow @@ -12,7 +12,7 @@ import com.daml.daml_lf_dev.DamlLf import com.daml.ledger.api.domain import com.daml.ledger.offset.Offset import com.daml.ledger.participant.state.index.v2 -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.ResourceOwner import com.daml.lf.data.Ref import com.daml.lf.data.Time.Timestamp @@ -101,7 +101,7 @@ trait ExecuteUpdate { metrics.daml.index.db.storeTransactionDbMetrics.prepareBatches, Future { val preparedInsert = ledgerDao.prepareTransactionInsert( - submitterInfo = tx.optSubmitterInfo, + completionInfo = tx.optCompletionInfo, workflowId = tx.transactionMeta.workflowId, transactionId = tx.transactionId, ledgerEffectiveTime = tx.transactionMeta.ledgerEffectiveTime.toInstant, @@ -194,8 +194,13 @@ trait ExecuteUpdate { Some(configRejection.rejectionReason), ) - case CommandRejected(recordTime, submitterInfo, reason) => - ledgerDao.storeRejection(Some(submitterInfo), recordTime.toInstant, offsetStep, reason) + case CommandRejected(recordTime, completionInfo, reason) => + ledgerDao.storeRejection( + Some(completionInfo), + recordTime.toInstant, + offsetStep, + reason, + ) case update: TransactionAccepted => import update._ logger.warn( @@ -204,7 +209,7 @@ trait ExecuteUpdate { ) ledgerDao.storeTransaction( preparedInsert = ledgerDao.prepareTransactionInsert( - submitterInfo = optSubmitterInfo, + completionInfo = optCompletionInfo, workflowId = transactionMeta.workflowId, transactionId = transactionId, ledgerEffectiveTime = transactionMeta.ledgerEffectiveTime.toInstant, @@ -213,7 +218,7 @@ trait ExecuteUpdate { divulgedContracts = divulgedContracts, blindingInfo = blindingInfo, ), - submitterInfo = optSubmitterInfo, + completionInfo = optCompletionInfo, transactionId = transactionId, recordTime = recordTime.toInstant, ledgerEffectiveTime = transactionMeta.ledgerEffectiveTime.toInstant, @@ -290,17 +295,17 @@ trait ExecuteUpdate { Logging.submitter(info.actAs), Logging.applicationId(info.applicationId), Logging.commandId(info.commandId), - Logging.deduplicateUntil(info.deduplicateUntil), + Logging.deduplicationPeriod(info.optDeduplicationPeriod), ) ) .getOrElse(LoggingEntries.empty) - case CommandRejected(_, submitterInfo, reason) => + case CommandRejected(_, completionInfo, reason) => LoggingEntries( - Logging.submitter(submitterInfo.actAs), - Logging.applicationId(submitterInfo.applicationId), - Logging.commandId(submitterInfo.commandId), - Logging.deduplicateUntil(submitterInfo.deduplicateUntil), - Logging.rejectionReason(reason.description), + Logging.submitter(completionInfo.actAs), + Logging.applicationId(completionInfo.applicationId), + Logging.commandId(completionInfo.commandId), + Logging.deduplicationPeriod(completionInfo.optDeduplicationPeriod), + Logging.rejectionReason(reason), ) } @@ -343,11 +348,16 @@ trait ExecuteUpdate { def maxDeduplicationTime(time: Duration): LoggingEntry = "maxDeduplicationTime" -> time - def deduplicateUntil(time: Instant): LoggingEntry = - "deduplicateUntil" -> time + def deduplicationPeriod(period: Option[state.DeduplicationPeriod]): LoggingEntry = + "deduplicationPeriod" -> period + + def rejectionReason(rejectionReason: String): LoggingEntry = + "rejectionReason" -> rejectionReason - def rejectionReason(reason: String): LoggingEntry = - "rejectionReason" -> reason + def rejectionReason( + rejectionReasonTemplate: state.Update.CommandRejected.RejectionReasonTemplate + ): LoggingEntry = + "rejectionReason" -> rejectionReasonTemplate def displayName(name: String): LoggingEntry = "displayName" -> name @@ -426,7 +436,7 @@ class PipelinedExecuteUpdate( .future( metrics.daml.index.db.storeTransactionCompletion, ledgerDao.completeTransaction( - submitterInfo = tx.optSubmitterInfo, + completionInfo = tx.optCompletionInfo, transactionId = tx.transactionId, recordTime = tx.recordTime.toInstant, offsetStep = offsetStep, @@ -506,7 +516,7 @@ class AtomicExecuteUpdate( case PreparedTransactionInsert( offsetStep, TransactionAccepted( - optSubmitterInfo, + optCompletionInfo, transactionMeta, transaction, transactionId, @@ -520,7 +530,7 @@ class AtomicExecuteUpdate( metrics.daml.index.db.storeTransaction, ledgerDao.storeTransaction( preparedInsert, - submitterInfo = optSubmitterInfo, + completionInfo = optCompletionInfo, transactionId = transactionId, recordTime = recordTime.toInstant, ledgerEffectiveTime = transactionMeta.ledgerEffectiveTime.toInstant, diff --git a/ledger/participant-integration-api/src/main/scala/platform/indexer/Indexer.scala b/ledger/participant-integration-api/src/main/scala/platform/indexer/Indexer.scala index b1c183cc41cd..5dbbbfe643b4 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/indexer/Indexer.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/indexer/Indexer.scala @@ -3,7 +3,7 @@ package com.daml.platform.indexer -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.ResourceOwner import scala.concurrent.Future diff --git a/ledger/participant-integration-api/src/main/scala/platform/indexer/JdbcIndexer.scala b/ledger/participant-integration-api/src/main/scala/platform/indexer/JdbcIndexer.scala index 8f501b2639f3..b0b46a0acb4f 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/indexer/JdbcIndexer.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/indexer/JdbcIndexer.scala @@ -11,7 +11,7 @@ import akka.stream.scaladsl.{Flow, Keep, Sink} import com.daml.ledger.api.domain import com.daml.ledger.api.domain.ParticipantId import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner} import com.daml.lf.data.Ref import com.daml.logging.{ContextualizedLogger, LoggingContext} @@ -209,7 +209,7 @@ object JdbcIndexer { dao: LedgerDao )(implicit ec: ExecutionContext): Future[Option[Offset]] = for { - initialConditions <- readService.getLedgerInitialConditions().runWith(Sink.head) + initialConditions <- readService.ledgerInitialConditions().runWith(Sink.head) existingLedgerId <- dao.lookupLedgerId() providedLedgerId = domain.LedgerId(initialConditions.ledgerId) _ <- existingLedgerId.fold(initializeLedgerData(providedLedgerId, dao))( diff --git a/ledger/participant-integration-api/src/main/scala/platform/indexer/OffsetUpdate.scala b/ledger/participant-integration-api/src/main/scala/platform/indexer/OffsetUpdate.scala index f7ea68e328aa..204aea5d5338 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/indexer/OffsetUpdate.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/indexer/OffsetUpdate.scala @@ -4,7 +4,7 @@ package com.daml.platform.indexer import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.platform.store.dao.events.TransactionsWriter.PreparedInsert sealed trait OffsetUpdate extends Product with Serializable { diff --git a/ledger/participant-integration-api/src/main/scala/platform/indexer/StandaloneIndexerServer.scala b/ledger/participant-integration-api/src/main/scala/platform/indexer/StandaloneIndexerServer.scala index 96022b052ae3..de40e1c878e0 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/indexer/StandaloneIndexerServer.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/indexer/StandaloneIndexerServer.scala @@ -5,7 +5,7 @@ package com.daml.platform.indexer import akka.stream.Materializer import com.daml.ledger.api.health.{HealthStatus, ReportsHealth} -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner} import com.daml.logging.{ContextualizedLogger, LoggingContext} import com.daml.metrics.Metrics diff --git a/ledger/participant-integration-api/src/main/scala/platform/indexer/parallel/IndexerLoggingContext.scala b/ledger/participant-integration-api/src/main/scala/platform/indexer/parallel/IndexerLoggingContext.scala index 8b7498ff7199..4abd6ed830f6 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/indexer/parallel/IndexerLoggingContext.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/indexer/parallel/IndexerLoggingContext.scala @@ -3,10 +3,10 @@ package com.daml.platform.indexer.parallel -import java.time.{Duration, Instant} +import java.time.Duration import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref import com.daml.lf.data.Time.Timestamp import com.daml.logging.entries.{LoggingEntries, LoggingEntry} @@ -81,7 +81,7 @@ object IndexerLoggingContext { Logging.submitter(info.actAs), Logging.applicationId(info.applicationId), Logging.commandId(info.commandId), - Logging.deduplicateUntil(info.deduplicateUntil), + Logging.deduplicationPeriod(info.optDeduplicationPeriod), ) ) .getOrElse(LoggingEntries.empty) @@ -90,8 +90,8 @@ object IndexerLoggingContext { Logging.submitter(submitterInfo.actAs), Logging.applicationId(submitterInfo.applicationId), Logging.commandId(submitterInfo.commandId), - Logging.deduplicateUntil(submitterInfo.deduplicateUntil), - Logging.rejectionReason(reason.description), + Logging.deduplicationPeriod(submitterInfo.optDeduplicationPeriod), + Logging.rejectionReason(reason), ) } @@ -132,11 +132,16 @@ object IndexerLoggingContext { def maxDeduplicationTime(time: Duration): LoggingEntry = "maxDeduplicationTime" -> time - def deduplicateUntil(time: Instant): LoggingEntry = - "deduplicateUntil" -> time + def deduplicationPeriod(period: Option[state.DeduplicationPeriod]): LoggingEntry = + "deduplicationPeriod" -> period - def rejectionReason(reason: String): LoggingEntry = - "rejectionReason" -> reason + def rejectionReason(rejectionReason: String): LoggingEntry = + "rejectionReason" -> rejectionReason + + def rejectionReason( + rejectionReasonTemplate: state.Update.CommandRejected.RejectionReasonTemplate + ): LoggingEntry = + "rejectionReason" -> rejectionReasonTemplate def displayName(name: String): LoggingEntry = "displayName" -> name diff --git a/ledger/participant-integration-api/src/main/scala/platform/indexer/parallel/ParallelIndexerFactory.scala b/ledger/participant-integration-api/src/main/scala/platform/indexer/parallel/ParallelIndexerFactory.scala index 6a3ed36ced99..ceff56bd842b 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/indexer/parallel/ParallelIndexerFactory.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/indexer/parallel/ParallelIndexerFactory.scala @@ -11,7 +11,7 @@ import akka.stream.scaladsl.{Keep, Sink, Source} import akka.stream.{KillSwitch, KillSwitches, Materializer, UniqueKillSwitch} import com.daml.ledger.api.health.HealthStatus import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner} import com.daml.lf.data.Ref import com.daml.logging.LoggingContext.{withEnrichedLoggingContext, withEnrichedLoggingContextFrom} diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/CompletionFromTransaction.scala b/ledger/participant-integration-api/src/main/scala/platform/store/CompletionFromTransaction.scala index 0dfc24f37d0a..b2250d5ea409 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/CompletionFromTransaction.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/CompletionFromTransaction.scala @@ -44,6 +44,7 @@ private[platform] object CompletionFromTransaction { Some(commandId), transactionId, Some(`appId`), + _, actAs, _, _, @@ -57,10 +58,9 @@ private[platform] object CompletionFromTransaction { Seq(Completion(commandId, Some(Status()), transactionId)), ) - case (offset, LedgerEntry.Rejection(recordTime, commandId, `appId`, actAs, reason)) + case (offset, LedgerEntry.Rejection(recordTime, commandId, `appId`, _, actAs, reason)) if actAs.exists(parties) => - val stateReason = reason.toParticipantStateRejectionReason - val status = Status(stateReason.code.value, stateReason.description) + val status = reason.toParticipantStateRejectionReason.status offset -> CompletionStreamResponse( checkpoint = toApiCheckpoint(recordTime, offset), Seq(Completion(commandId, Some(status))), diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/Conversions.scala b/ledger/participant-integration-api/src/main/scala/platform/store/Conversions.scala index 292aab8ab1e1..a0adb2ca9d73 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/Conversions.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/Conversions.scala @@ -13,12 +13,15 @@ import anorm.Column.nonNull import anorm._ import com.daml.ledger.api.domain import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.v2.Update.CommandRejected +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.crypto.Hash import com.daml.lf.data.Ref import com.daml.lf.ledger.EventId import com.daml.lf.value.Value import spray.json.DefaultJsonProtocol._ +import com.google.rpc.status.{Status => RpcStatus} +import io.grpc.Status import spray.json._ // TODO append-only: split this file on cleanup, and move anorm/db conversion related stuff to the right place @@ -337,20 +340,34 @@ private[platform] object Conversions { } implicit class RejectionReasonOps(rejectionReason: domain.RejectionReason) { - def toParticipantStateRejectionReason: state.RejectionReason = + + import RejectionReasonOps._ + + def toParticipantStateRejectionReason: state.Update.CommandRejected.RejectionReasonTemplate = rejectionReason match { case domain.RejectionReason.Inconsistent(reason) => - state.RejectionReasonV0.Inconsistent(reason) + newRejectionReason(Status.Code.ABORTED, s"Inconsistent: $reason") case domain.RejectionReason.Disputed(reason) => - state.RejectionReasonV0.Disputed(reason) + newRejectionReason(Status.Code.INVALID_ARGUMENT, s"Disputed: $reason") case domain.RejectionReason.OutOfQuota(reason) => - state.RejectionReasonV0.ResourcesExhausted(reason) + newRejectionReason(Status.Code.ABORTED, s"Resources exhausted: $reason") case domain.RejectionReason.PartyNotKnownOnLedger(reason) => - state.RejectionReasonV0.PartyNotKnownOnLedger(reason) + newRejectionReason(Status.Code.INVALID_ARGUMENT, s"Party not known on ledger: $reason") case domain.RejectionReason.SubmitterCannotActViaParticipant(reason) => - state.RejectionReasonV0.SubmitterCannotActViaParticipant(reason) + newRejectionReason( + Status.Code.PERMISSION_DENIED, + s"Submitted cannot act via participant: $reason", + ) case domain.RejectionReason.InvalidLedgerTime(reason) => - state.RejectionReasonV0.InvalidLedgerTime(reason) + newRejectionReason(Status.Code.ABORTED, s"Invalid ledger time: $reason") } } + + object RejectionReasonOps { + private def newRejectionReason( + code: Status.Code, + message: String, + ): state.Update.CommandRejected.RejectionReasonTemplate = + new CommandRejected.FinalReason(RpcStatus.of(code.value(), message, Seq.empty)) + } } diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/JdbcLedgerDao.scala b/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/JdbcLedgerDao.scala index c42262b4eb0e..27708f0e6428 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/JdbcLedgerDao.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/JdbcLedgerDao.scala @@ -19,7 +19,7 @@ import com.daml.ledger.participant.state.index.v2.{ CommandDeduplicationResult, PackageDetails, } -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.ResourceOwner import com.daml.lf.archive.ArchiveParser import com.daml.lf.data.{Ref, Time} @@ -283,7 +283,7 @@ private class JdbcLedgerDao( } override def prepareTransactionInsert( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[Ref.WorkflowId], transactionId: Ref.TransactionId, ledgerEffectiveTime: Instant, @@ -312,7 +312,7 @@ private class JdbcLedgerDao( ) // TODO append-only: cleanup override def completeTransaction( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], transactionId: Ref.TransactionId, recordTime: Instant, offsetStep: OffsetStep, @@ -323,7 +323,7 @@ private class JdbcLedgerDao( override def storeTransaction( preparedInsert: PreparedInsert, - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], transactionId: Ref.TransactionId, recordTime: Instant, ledgerEffectiveTime: Instant, @@ -350,10 +350,10 @@ private class JdbcLedgerDao( ) override def storeRejection( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], recordTime: Instant, offsetStep: OffsetStep, - reason: state.RejectionReason, + reason: state.Update.CommandRejected.RejectionReasonTemplate, )(implicit loggingContext: LoggingContext): Future[PersistenceResponse] = dbDispatcher .executeSql(metrics.daml.index.db.storeRejectionDbMetrics) { implicit conn => @@ -361,11 +361,11 @@ private class JdbcLedgerDao( sequentialIndexer.store( conn, offset, - submitterInfo.map(someSubmitterInfo => + completionInfo.map(info => state.Update.CommandRejected( recordTime = Time.Timestamp.assertFromInstant(recordTime), - submitterInfo = someSubmitterInfo, - reason = reason, + completionInfo = info, + reasonTemplate = reason, ) ), ) @@ -382,19 +382,19 @@ private class JdbcLedgerDao( ledgerEntries.foreach { case (offset, entry) => entry match { case tx: LedgerEntry.Transaction => - val submitterInfo = - for ( - appId <- tx.applicationId; - actAs <- if (tx.actAs.isEmpty) None else Some(tx.actAs); - cmdId <- tx.commandId - ) yield state.SubmitterInfo(actAs, appId, cmdId, Instant.EPOCH) + val completionInfo = for { + actAs <- if (tx.actAs.isEmpty) None else Some(tx.actAs) + applicationId <- tx.applicationId + commandId <- tx.commandId + submissionId <- tx.submissionId + } yield state.CompletionInfo(actAs, applicationId, commandId, None, submissionId) sequentialIndexer.store( connection, offset, Some( state.Update.TransactionAccepted( - optSubmitterInfo = submitterInfo, + optCompletionInfo = completionInfo, transactionMeta = state.TransactionMeta( ledgerEffectiveTime = Time.Timestamp.assertFromInstant(tx.ledgerEffectiveTime), @@ -413,16 +413,23 @@ private class JdbcLedgerDao( ) ), ) - case LedgerEntry.Rejection(recordTime, commandId, applicationId, actAs, reason) => + case LedgerEntry.Rejection( + recordTime, + commandId, + applicationId, + submissionId, + actAs, + reason, + ) => sequentialIndexer.store( connection, offset, Some( state.Update.CommandRejected( recordTime = Time.Timestamp.assertFromInstant(recordTime), - submitterInfo = - state.SubmitterInfo(actAs, applicationId, commandId, Instant.EPOCH), - reason = reason.toParticipantStateRejectionReason, + completionInfo = + state.CompletionInfo(actAs, applicationId, commandId, None, submissionId), + reasonTemplate = reason.toParticipantStateRejectionReason, ) ), ) @@ -643,7 +650,7 @@ private class JdbcLedgerDao( * !!! Usage of this is discouraged, with the removal of sandbox-classic this will be removed */ override def storeTransaction( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[Ref.WorkflowId], transactionId: Ref.TransactionId, ledgerEffectiveTime: Instant, @@ -663,7 +670,7 @@ private class JdbcLedgerDao( case None => Some( state.Update.TransactionAccepted( - optSubmitterInfo = submitterInfo, + optCompletionInfo = completionInfo, transactionMeta = state.TransactionMeta( ledgerEffectiveTime = Time.Timestamp.assertFromInstant(ledgerEffectiveTime), workflowId = workflowId, @@ -682,11 +689,11 @@ private class JdbcLedgerDao( ) case Some(reason) => - submitterInfo.map(someSubmitterInfo => + completionInfo.map(info => state.Update.CommandRejected( recordTime = Time.Timestamp.assertFromInstant(recordTime), - submitterInfo = someSubmitterInfo, - reason = reason.toStateV1RejectionReason, + completionInfo = info, + reasonTemplate = reason.toStateV2RejectionReason, ) ) }, diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/SequentialWriteDao.scala b/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/SequentialWriteDao.scala index 821ba5386beb..5bef604ce5b2 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/SequentialWriteDao.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/SequentialWriteDao.scala @@ -6,7 +6,7 @@ package com.daml.platform.store.appendonlydao import java.sql.Connection import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.platform.store.backend.{ DbDto, IngestionStorageBackend, diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/events/PostCommitValidation.scala b/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/events/PostCommitValidation.scala index 506278fa7af9..61e8af9d4db8 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/events/PostCommitValidation.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/appendonlydao/events/PostCommitValidation.scala @@ -6,7 +6,8 @@ package com.daml.platform.store.appendonlydao.events import java.sql.Connection import java.time.Instant -import com.daml.ledger.participant.state.v1 +import com.daml.ledger.api.domain +import com.daml.ledger.participant.state.{v1, v2} import com.daml.lf.transaction.CommittedTransaction import com.daml.platform.store.appendonlydao.events.PostCommitValidation._ import com.daml.platform.store.backend.{ContractStorageBackend, PartyStorageBackend} @@ -278,15 +279,23 @@ private[appendonlydao] object PostCommitValidation { def description: String def toStateV1RejectionReason: v1.RejectionReason + + def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate } object Rejection { + + import com.daml.platform.store.Conversions.RejectionReasonOps + object UnknownContract extends Rejection { override val description = "Unknown contract" override def toStateV1RejectionReason: v1.RejectionReason = v1.RejectionReasonV0.Inconsistent(description) + + override def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate = + domain.RejectionReason.Inconsistent(description).toParticipantStateRejectionReason } object DuplicateKey extends Rejection { @@ -295,6 +304,9 @@ private[appendonlydao] object PostCommitValidation { override def toStateV1RejectionReason: v1.RejectionReason = v1.RejectionReasonV0.Inconsistent(description) + + override def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate = + domain.RejectionReason.Inconsistent(description).toParticipantStateRejectionReason } final case class MismatchingLookup( @@ -306,6 +318,9 @@ private[appendonlydao] object PostCommitValidation { override def toStateV1RejectionReason: v1.RejectionReason = v1.RejectionReasonV0.Inconsistent(description) + + override def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate = + domain.RejectionReason.Inconsistent(description).toParticipantStateRejectionReason } final case class CausalMonotonicityViolation( @@ -317,6 +332,9 @@ private[appendonlydao] object PostCommitValidation { override def toStateV1RejectionReason: v1.RejectionReason = v1.RejectionReasonV0.InvalidLedgerTime(description) + + override def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate = + domain.RejectionReason.InvalidLedgerTime(description).toParticipantStateRejectionReason } object UnallocatedParties extends Rejection { @@ -325,6 +343,9 @@ private[appendonlydao] object PostCommitValidation { override def toStateV1RejectionReason: v1.RejectionReason = v1.RejectionReasonV0.PartyNotKnownOnLedger(description) + + override def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate = + domain.RejectionReason.PartyNotKnownOnLedger(description).toParticipantStateRejectionReason } } } diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/backend/UpdateToDbDto.scala b/ledger/participant-integration-api/src/main/scala/platform/store/backend/UpdateToDbDto.scala index 8625432d1cc0..005a7f68b5d5 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/backend/UpdateToDbDto.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/backend/UpdateToDbDto.scala @@ -8,7 +8,7 @@ import java.util.UUID import com.daml.ledger.api.domain import com.daml.ledger.configuration.Configuration import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref import com.daml.lf.engine.Blinding import com.daml.lf.ledger.EventId @@ -30,17 +30,17 @@ object UpdateToDbDto { DbDto.CommandCompletion( completion_offset = offset.toHexString, record_time = u.recordTime.toInstant, - application_id = u.submitterInfo.applicationId, - submitters = u.submitterInfo.actAs.toSet, - command_id = u.submitterInfo.commandId, + application_id = u.completionInfo.applicationId, + submitters = u.completionInfo.actAs.toSet, + command_id = u.completionInfo.commandId, transaction_id = None, - status_code = Some(u.reason.code.value()), - status_message = Some(u.reason.description), + status_code = Some(u.reasonTemplate.code), + status_message = Some(u.reasonTemplate.message), ), DbDto.CommandDeduplication( DeduplicationKeyMaker.make( - domain.CommandId(u.submitterInfo.commandId), - u.submitterInfo.actAs, + domain.CommandId(u.completionInfo.commandId), + u.completionInfo.actAs, ) ), ) @@ -165,10 +165,10 @@ object UpdateToDbDto { event_offset = Some(offset.toHexString), transaction_id = Some(u.transactionId), ledger_effective_time = Some(u.transactionMeta.ledgerEffectiveTime.toInstant), - command_id = u.optSubmitterInfo.map(_.commandId), + command_id = u.optCompletionInfo.map(_.commandId), workflow_id = u.transactionMeta.workflowId, - application_id = u.optSubmitterInfo.map(_.applicationId), - submitters = u.optSubmitterInfo.map(_.actAs.toSet), + application_id = u.optCompletionInfo.map(_.applicationId), + submitters = u.optCompletionInfo.map(_.actAs.toSet), node_index = Some(nodeId.index), event_id = Some(eventId.toLedgerString), contract_id = create.coid.coid, @@ -204,10 +204,10 @@ object UpdateToDbDto { event_offset = Some(offset.toHexString), transaction_id = Some(u.transactionId), ledger_effective_time = Some(u.transactionMeta.ledgerEffectiveTime.toInstant), - command_id = u.optSubmitterInfo.map(_.commandId), + command_id = u.optCompletionInfo.map(_.commandId), workflow_id = u.transactionMeta.workflowId, - application_id = u.optSubmitterInfo.map(_.applicationId), - submitters = u.optSubmitterInfo.map(_.actAs.toSet), + application_id = u.optCompletionInfo.map(_.applicationId), + submitters = u.optCompletionInfo.map(_.actAs.toSet), node_index = Some(nodeId.index), event_id = Some(EventId(u.transactionId, nodeId).toLedgerString), contract_id = exercise.targetCoid.coid, @@ -245,10 +245,10 @@ object UpdateToDbDto { val contractInst = divulgedContractIndex.get(contractId).map(_.contractInst) DbDto.EventDivulgence( event_offset = Some(offset.toHexString), - command_id = u.optSubmitterInfo.map(_.commandId), + command_id = u.optCompletionInfo.map(_.commandId), workflow_id = u.transactionMeta.workflowId, - application_id = u.optSubmitterInfo.map(_.applicationId), - submitters = u.optSubmitterInfo.map(_.actAs.toSet), + application_id = u.optCompletionInfo.map(_.applicationId), + submitters = u.optCompletionInfo.map(_.actAs.toSet), contract_id = contractId.coid, template_id = contractInst.map(_.template.toString), tree_event_witnesses = visibleToParties.map(_.toString), @@ -261,13 +261,13 @@ object UpdateToDbDto { ) } - val completions = u.optSubmitterInfo.iterator.map { submitterInfo => + val completions = u.optCompletionInfo.iterator.map { completionInfo => DbDto.CommandCompletion( completion_offset = offset.toHexString, record_time = u.recordTime.toInstant, - application_id = submitterInfo.applicationId, - submitters = submitterInfo.actAs.toSet, - command_id = submitterInfo.commandId, + application_id = completionInfo.applicationId, + submitters = completionInfo.actAs.toSet, + command_id = completionInfo.commandId, transaction_id = Some(u.transactionId), status_code = None, status_message = None, diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/JdbcLedgerDao.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/JdbcLedgerDao.scala index 290dc889b805..ebea592eee3e 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/JdbcLedgerDao.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/JdbcLedgerDao.scala @@ -33,7 +33,7 @@ import com.daml.ledger.participant.state.index.v2.{ CommandDeduplicationResult, PackageDetails, } -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.ResourceOwner import com.daml.lf.archive.ArchiveParser import com.daml.lf.data.Ref @@ -429,7 +429,7 @@ private class JdbcLedgerDao( } override def prepareTransactionInsert( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[Ref.WorkflowId], transactionId: Ref.TransactionId, ledgerEffectiveTime: Instant, @@ -439,7 +439,7 @@ private class JdbcLedgerDao( blindingInfo: Option[BlindingInfo], ): PreparedInsert = transactionsWriter.prepare( - submitterInfo, + completionInfo, workflowId, transactionId, ledgerEffectiveTime, @@ -451,12 +451,12 @@ private class JdbcLedgerDao( private def handleError( offset: Offset, - info: state.SubmitterInfo, + completionInfo: state.CompletionInfo, recordTime: Instant, - rejectionReason: state.RejectionReason, + rejectionReason: state.Update.CommandRejected.RejectionReasonTemplate, )(implicit connection: Connection): Unit = { - stopDeduplicatingCommandSync(domain.CommandId(info.commandId), info.actAs) - queries.prepareRejectionInsert(info, offset, recordTime, rejectionReason).execute() + stopDeduplicatingCommandSync(domain.CommandId(completionInfo.commandId), completionInfo.actAs) + queries.prepareRejectionInsert(completionInfo, offset, recordTime, rejectionReason).execute() () } @@ -479,21 +479,21 @@ private class JdbcLedgerDao( .map(_ => Ok)(servicesExecutionContext) override def completeTransaction( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], transactionId: Ref.TransactionId, recordTime: Instant, offsetStep: OffsetStep, )(implicit loggingContext: LoggingContext): Future[PersistenceResponse] = dbDispatcher .executeSql(metrics.daml.index.db.storeTransactionDbMetrics) { implicit conn => - insertCompletions(submitterInfo, transactionId, recordTime, offsetStep) + insertCompletions(completionInfo, transactionId, recordTime, offsetStep) updateLedgerEnd(offsetStep) Ok } override def storeTransaction( preparedInsert: PreparedInsert, - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], transactionId: Ref.TransactionId, recordTime: Instant, ledgerEffectiveTime: Instant, @@ -508,10 +508,10 @@ private class JdbcLedgerDao( case None => preparedInsert.writeState(metrics) preparedInsert.writeEvents(metrics) - insertCompletions(submitterInfo, transactionId, recordTime, offsetStep) + insertCompletions(completionInfo, transactionId, recordTime, offsetStep) case Some(error) => - submitterInfo.foreach( - handleError(offsetStep.offset, _, recordTime, error.toStateV1RejectionReason) + completionInfo.foreach( + handleError(offsetStep.offset, _, recordTime, error.toStateV2RejectionReason) ) } @@ -535,14 +535,14 @@ private class JdbcLedgerDao( ) private def insertCompletions( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], transactionId: Ref.TransactionId, recordTime: Instant, offsetStep: OffsetStep, )(implicit connection: Connection): Unit = Timed.value( metrics.daml.index.db.storeTransactionDbMetrics.insertCompletion, - submitterInfo + completionInfo .map(queries.prepareCompletionInsert(_, offsetStep.offset, transactionId, recordTime)) .foreach(_.execute()), ) @@ -554,14 +554,14 @@ private class JdbcLedgerDao( ) override def storeRejection( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], recordTime: Instant, offsetStep: OffsetStep, - reason: state.RejectionReason, + reason: state.Update.CommandRejected.RejectionReasonTemplate, )(implicit loggingContext: LoggingContext): Future[PersistenceResponse] = { logger.info("Storing rejection") dbDispatcher.executeSql(metrics.daml.index.db.storeRejectionDbMetrics) { implicit conn => - for (info <- submitterInfo) { + for (info <- completionInfo) { handleError(offsetStep.offset, info, recordTime, reason) } ParametersTable.updateLedgerEnd(offsetStep) @@ -580,15 +580,15 @@ private class JdbcLedgerDao( ledgerEntries.foreach { case (offset, entry) => entry match { case tx: LedgerEntry.Transaction => - val submitterInfo = - for ( - appId <- tx.applicationId; - actAs <- if (tx.actAs.isEmpty) None else Some(tx.actAs); - cmdId <- tx.commandId - ) - yield state.SubmitterInfo(actAs, appId, cmdId, Instant.EPOCH) + val completionInfo = for { + actAs <- if (tx.actAs.isEmpty) None else Some(tx.actAs) + applicationId <- tx.applicationId + commandId <- tx.commandId + submissionId <- tx.submissionId + } yield state.CompletionInfo(actAs, applicationId, commandId, None, submissionId) + prepareTransactionInsert( - submitterInfo = submitterInfo, + completionInfo = completionInfo, workflowId = tx.workflowId, transactionId = tx.transactionId, ledgerEffectiveTime = tx.ledgerEffectiveTime, @@ -597,19 +597,27 @@ private class JdbcLedgerDao( divulgedContracts = Nil, blindingInfo = None, ).write(metrics) - submitterInfo + completionInfo .map(queries.prepareCompletionInsert(_, offset, tx.transactionId, tx.recordedAt)) .foreach(_.execute()) - case LedgerEntry.Rejection(recordTime, commandId, applicationId, actAs, reason) => - val _ = queries + case LedgerEntry.Rejection( + recordTime, + commandId, + applicationId, + submissionId, + actAs, + reason, + ) => + queries .prepareRejectionInsert( - submitterInfo = - state.SubmitterInfo(actAs, applicationId, commandId, Instant.EPOCH), + completionInfo = + state.CompletionInfo(actAs, applicationId, commandId, None, submissionId), offset = offset, recordTime = recordTime, reason = reason.toParticipantStateRejectionReason, ) .execute() + () } } ParametersTable.updateLedgerEnd(CurrentOffset(newLedgerEnd)) @@ -970,7 +978,7 @@ private class JdbcLedgerDao( * !!! Usage of this is discouraged, with the removal of sandbox-classic this will be removed */ override def storeTransaction( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[Ref.WorkflowId], transactionId: Ref.TransactionId, ledgerEffectiveTime: Instant, @@ -981,7 +989,7 @@ private class JdbcLedgerDao( recordTime: Instant, )(implicit loggingContext: LoggingContext): Future[PersistenceResponse] = { val preparedInsert = prepareTransactionInsert( - submitterInfo = submitterInfo, + completionInfo = completionInfo, workflowId = workflowId, transactionId = transactionId, ledgerEffectiveTime = ledgerEffectiveTime, @@ -992,7 +1000,7 @@ private class JdbcLedgerDao( ) storeTransaction( preparedInsert, - submitterInfo, + completionInfo, transactionId, recordTime, ledgerEffectiveTime, @@ -1179,7 +1187,7 @@ private[platform] object JdbcLedgerDao { |where ledger_offset>{startExclusive} and ledger_offset<={endInclusive} |order by ledger_offset asc limit {pageSize} offset {queryOffset}""".stripMargin - protected[JdbcLedgerDao] def SQL_GET_CONFIGURATION_ENTRIES = + protected[JdbcLedgerDao] def SQL_GET_CONFIGURATION_ENTRIES: String = """select * from configuration_entries where |ledger_offset > {startExclusive} and ledger_offset <= {endInclusive} |order by ledger_offset asc limit {pageSize} offset {queryOffset}""".stripMargin @@ -1191,23 +1199,23 @@ private[platform] object JdbcLedgerDao { def limit(numberOfItems: Int): String protected[JdbcLedgerDao] def prepareCompletionInsert( - submitterInfo: state.SubmitterInfo, + completionInfo: state.CompletionInfo, offset: Offset, transactionId: Ref.TransactionId, recordTime: Instant, ): SimpleSql[Row] = { - SQL"insert into participant_command_completions(completion_offset, record_time, application_id, submitters, command_id, transaction_id) values ($offset, $recordTime, ${submitterInfo.applicationId}, ${submitterInfo.actAs - .toArray[String]}, ${submitterInfo.commandId}, $transactionId)" + SQL"insert into participant_command_completions(completion_offset, record_time, application_id, submitters, command_id, transaction_id) values ($offset, $recordTime, ${completionInfo.applicationId}, ${completionInfo.actAs + .toArray[String]}, ${completionInfo.commandId}, $transactionId)" } protected[JdbcLedgerDao] def prepareRejectionInsert( - submitterInfo: state.SubmitterInfo, + completionInfo: state.CompletionInfo, offset: Offset, recordTime: Instant, - reason: state.RejectionReason, + reason: state.Update.CommandRejected.RejectionReasonTemplate, ): SimpleSql[Row] = { - SQL"insert into participant_command_completions(completion_offset, record_time, application_id, submitters, command_id, status_code, status_message) values ($offset, $recordTime, ${submitterInfo.applicationId}, ${submitterInfo.actAs - .toArray[String]}, ${submitterInfo.commandId}, ${reason.code.value}, ${reason.description})" + SQL"insert into participant_command_completions(completion_offset, record_time, application_id, submitters, command_id, status_code, status_message) values ($offset, $recordTime, ${completionInfo.applicationId}, ${completionInfo.actAs + .toArray[String]}, ${completionInfo.commandId}, ${reason.code}, ${reason.message})" } protected[JdbcLedgerDao] def escapeReservedWord(word: String): String @@ -1363,7 +1371,7 @@ private[platform] object JdbcLedgerDao { |order by ledger_offset asc |offset {queryOffset} rows fetch next {pageSize} rows only""".stripMargin - override protected[JdbcLedgerDao] val SQL_GET_CONFIGURATION_ENTRIES = + override protected[JdbcLedgerDao] val SQL_GET_CONFIGURATION_ENTRIES: String = """select * from configuration_entries where |({startExclusive} is null or ledger_offset>{startExclusive}) and ledger_offset<={endInclusive} |order by ledger_offset asc @@ -1379,24 +1387,23 @@ private[platform] object JdbcLedgerDao { } override protected[JdbcLedgerDao] def prepareCompletionInsert( - submitterInfo: state.SubmitterInfo, + completionInfo: state.CompletionInfo, offset: Offset, transactionId: Ref.TransactionId, recordTime: Instant, ): SimpleSql[Row] = { import com.daml.platform.store.OracleArrayConversions._ - SQL"insert into participant_command_completions(completion_offset, record_time, application_id, submitters, command_id, transaction_id) values ($offset, $recordTime, ${submitterInfo.applicationId}, ${submitterInfo.actAs.toJson.compactPrint}, ${submitterInfo.commandId}, $transactionId)" + SQL"insert into participant_command_completions(completion_offset, record_time, application_id, submitters, command_id, transaction_id) values ($offset, $recordTime, ${completionInfo.applicationId}, ${completionInfo.actAs.toJson.compactPrint}, ${completionInfo.commandId}, $transactionId)" } override protected[JdbcLedgerDao] def prepareRejectionInsert( - submitterInfo: state.SubmitterInfo, + completionInfo: state.CompletionInfo, offset: Offset, recordTime: Instant, - reason: state.RejectionReason, + reason: state.Update.CommandRejected.RejectionReasonTemplate, ): SimpleSql[Row] = { import com.daml.platform.store.OracleArrayConversions._ - SQL"insert into participant_command_completions(completion_offset, record_time, application_id, submitters, command_id, status_code, status_message) values ($offset, $recordTime, ${submitterInfo.applicationId}, ${submitterInfo.actAs.toJson.compactPrint}, ${submitterInfo.commandId}, ${reason.code - .value()}, ${reason.description})" + SQL"insert into participant_command_completions(completion_offset, record_time, application_id, submitters, command_id, status_code, status_message) values ($offset, $recordTime, ${completionInfo.applicationId}, ${completionInfo.actAs.toJson.compactPrint}, ${completionInfo.commandId}, ${reason.code}, ${reason.message})" } // spaces which are subsequently trimmed left only for readability diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/LedgerDao.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/LedgerDao.scala index 415a34fcbeb8..38dab1d61129 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/LedgerDao.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/LedgerDao.scala @@ -21,7 +21,7 @@ import com.daml.ledger.api.v1.transaction_service.{ import com.daml.ledger.configuration.Configuration import com.daml.ledger.offset.Offset import com.daml.ledger.participant.state.index.v2.{CommandDeduplicationResult, PackageDetails} -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref import com.daml.lf.transaction.{BlindingInfo, CommittedTransaction} import com.daml.logging.LoggingContext @@ -244,7 +244,7 @@ private[platform] trait LedgerWriteDao extends ReportsHealth { // TODO append-only: cleanup def prepareTransactionInsert( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[Ref.WorkflowId], transactionId: Ref.TransactionId, ledgerEffectiveTime: Instant, @@ -257,7 +257,7 @@ private[platform] trait LedgerWriteDao extends ReportsHealth { // TODO append-only: cleanup def storeTransaction( preparedInsert: PreparedInsert, - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], transactionId: Ref.TransactionId, recordTime: Instant, ledgerEffectiveTime: Instant, @@ -278,17 +278,17 @@ private[platform] trait LedgerWriteDao extends ReportsHealth { // TODO append-only: cleanup def completeTransaction( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], transactionId: Ref.TransactionId, recordTime: Instant, offsetStep: OffsetStep, )(implicit loggingContext: LoggingContext): Future[PersistenceResponse] def storeRejection( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], recordTime: Instant, offsetStep: OffsetStep, - reason: state.RejectionReason, + reason: state.Update.CommandRejected.RejectionReasonTemplate, )(implicit loggingContext: LoggingContext): Future[PersistenceResponse] /** !!! Please kindly not use this. @@ -339,7 +339,7 @@ private[platform] trait LedgerWriteDao extends ReportsHealth { * !!! Usage of this is discouraged, with the removal of sandbox-classic this will be removed */ def storeTransaction( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[Ref.WorkflowId], transactionId: Ref.TransactionId, ledgerEffectiveTime: Instant, diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/MeteredLedgerDao.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/MeteredLedgerDao.scala index d13f08812dc5..53eee0fa4d19 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/MeteredLedgerDao.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/MeteredLedgerDao.scala @@ -13,7 +13,7 @@ import com.daml.ledger.api.health.HealthStatus import com.daml.ledger.configuration.Configuration import com.daml.ledger.offset.Offset import com.daml.ledger.participant.state.index.v2.{CommandDeduplicationResult, PackageDetails} -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref import com.daml.lf.transaction.{BlindingInfo, CommittedTransaction} import com.daml.logging.LoggingContext @@ -155,7 +155,7 @@ private[platform] class MeteredLedgerDao(ledgerDao: LedgerDao, metrics: Metrics) override def storeTransaction( preparedInsert: PreparedInsert, - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], transactionId: Ref.TransactionId, recordTime: Instant, ledgerEffectiveTime: Instant, @@ -167,7 +167,7 @@ private[platform] class MeteredLedgerDao(ledgerDao: LedgerDao, metrics: Metrics) metrics.daml.index.db.storeTransaction, ledgerDao.storeTransaction( preparedInsert, - submitterInfo, + completionInfo, transactionId, recordTime, ledgerEffectiveTime, @@ -178,7 +178,7 @@ private[platform] class MeteredLedgerDao(ledgerDao: LedgerDao, metrics: Metrics) ) def prepareTransactionInsert( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[Ref.WorkflowId], transactionId: Ref.TransactionId, ledgerEffectiveTime: Instant, @@ -188,7 +188,7 @@ private[platform] class MeteredLedgerDao(ledgerDao: LedgerDao, metrics: Metrics) blindingInfo: Option[BlindingInfo], ): TransactionsWriter.PreparedInsert = ledgerDao.prepareTransactionInsert( - submitterInfo, + completionInfo, workflowId, transactionId, ledgerEffectiveTime, @@ -199,14 +199,14 @@ private[platform] class MeteredLedgerDao(ledgerDao: LedgerDao, metrics: Metrics) ) override def storeRejection( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], recordTime: Instant, offsetStep: OffsetStep, - reason: state.RejectionReason, + reason: state.Update.CommandRejected.RejectionReasonTemplate, )(implicit loggingContext: LoggingContext): Future[PersistenceResponse] = Timed.future( metrics.daml.index.db.storeRejection, - ledgerDao.storeRejection(submitterInfo, recordTime, offsetStep, reason), + ledgerDao.storeRejection(completionInfo, recordTime, offsetStep, reason), ) override def storeInitialState( @@ -279,18 +279,18 @@ private[platform] class MeteredLedgerDao(ledgerDao: LedgerDao, metrics: Metrics) ledgerDao.storeTransactionEvents(preparedInsert) override def completeTransaction( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], transactionId: Ref.TransactionId, recordTime: Instant, offsetStep: OffsetStep, )(implicit loggingContext: LoggingContext): Future[PersistenceResponse] = - ledgerDao.completeTransaction(submitterInfo, transactionId, recordTime, offsetStep) + ledgerDao.completeTransaction(completionInfo, transactionId, recordTime, offsetStep) /** This is a combined store transaction method to support sandbox-classic and tests * !!! Usage of this is discouraged, with the removal of sandbox-classic this will be removed */ override def storeTransaction( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[Ref.WorkflowId], transactionId: Ref.TransactionId, ledgerEffectiveTime: Instant, @@ -303,7 +303,7 @@ private[platform] class MeteredLedgerDao(ledgerDao: LedgerDao, metrics: Metrics) Timed.future( metrics.daml.index.db.storeTransactionCombined, ledgerDao.storeTransaction( - submitterInfo, + completionInfo, workflowId, transactionId, ledgerEffectiveTime, diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTableH2.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTableH2.scala index 51ff0a756ee1..b8b0cc063a77 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTableH2.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTableH2.scala @@ -7,7 +7,7 @@ import java.sql.Connection import java.time.Instant import anorm.{BatchSql, NamedParameter} -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.platform.store.Conversions._ import com.daml.platform.store.dao.events.ContractsTable.Executable import com.daml.platform.store.serialization.Compression diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTableOracle.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTableOracle.scala index 0f4d6636b463..780423b13cce 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTableOracle.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTableOracle.scala @@ -7,7 +7,7 @@ import java.sql.Connection import java.time.Instant import anorm.{BatchSql, NamedParameter} -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.platform.store.Conversions._ import com.daml.platform.store.dao.events.ContractsTable.Executable import com.daml.platform.store.serialization.Compression diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTablePostgres.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTablePostgres.scala index c660a6e386b4..2e7eb3753852 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTablePostgres.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/ContractsTablePostgres.scala @@ -6,7 +6,7 @@ package com.daml.platform.store.dao.events import java.sql.{Connection, Timestamp} import anorm.{Row, SimpleSql, SqlQuery} -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.platform.store.dao.events.ContractsTable.Executable object ContractsTablePostgres extends ContractsTable { diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTableH2Database.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTableH2Database.scala index 71b692de31e3..8e0f10255965 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTableH2Database.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTableH2Database.scala @@ -8,7 +8,7 @@ import java.time.Instant import anorm.{BatchSql, NamedParameter} import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.ledger.EventId import com.daml.platform.store.Conversions._ import com.daml.platform.store.JdbcArrayConversions.StringArrayParameterMetadata @@ -63,7 +63,7 @@ object EventsTableH2Database extends EventsTable { transactionId: TransactionId, workflowId: Option[WorkflowId], ledgerEffectiveTime: Instant, - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], events: Vector[(NodeId, Node)], stakeholders: WitnessRelation[NodeId], disclosure: WitnessRelation[NodeId], @@ -75,9 +75,9 @@ object EventsTableH2Database extends EventsTable { "transaction_id" -> transactionId, "workflow_id" -> workflowId, "ledger_effective_time" -> ledgerEffectiveTime, - "command_id" -> submitterInfo.map(_.commandId), - "application_id" -> submitterInfo.map(_.applicationId), - "submitters" -> Party.Array(submitterInfo.map(_.actAs).getOrElse(List.empty): _*), + "command_id" -> completionInfo.map(_.commandId), + "application_id" -> completionInfo.map(_.applicationId), + "submitters" -> Party.Array(completionInfo.map(_.actAs).getOrElse(List.empty): _*), ) for ((nodeId, node) <- events) yield { @@ -201,7 +201,7 @@ object EventsTableH2Database extends EventsTable { transactionId = tx.transactionId, workflowId = tx.workflowId, ledgerEffectiveTime = tx.ledgerEffectiveTime, - submitterInfo = tx.submitterInfo, + completionInfo = tx.completionInfo, events = info.events, stakeholders = info.stakeholders, disclosure = info.disclosure, diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTableOracle.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTableOracle.scala index d1fa0f36a71e..ca49fb12c894 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTableOracle.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTableOracle.scala @@ -8,7 +8,7 @@ import java.time.Instant import anorm.{BatchSql, NamedParameter} import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.ledger.EventId import com.daml.platform.store.Conversions._ import com.daml.platform.store.OracleArrayConversions._ @@ -69,7 +69,7 @@ object EventsTableOracle extends EventsTable { transactionId: TransactionId, workflowId: Option[WorkflowId], ledgerEffectiveTime: Instant, - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], events: Vector[(NodeId, Node)], stakeholders: WitnessRelation[NodeId], disclosure: WitnessRelation[NodeId], @@ -81,9 +81,9 @@ object EventsTableOracle extends EventsTable { "transaction_id" -> transactionId, "workflow_id" -> workflowId, "ledger_effective_time" -> ledgerEffectiveTime, - "command_id" -> submitterInfo.map(_.commandId), - "application_id" -> submitterInfo.map(_.applicationId), - "submitters" -> submitterInfo.map(_.actAs).getOrElse(List.empty).toJson.compactPrint, + "command_id" -> completionInfo.map(_.commandId), + "application_id" -> completionInfo.map(_.applicationId), + "submitters" -> completionInfo.map(_.actAs).getOrElse(List.empty).toJson.compactPrint, ) for ((nodeId, node) <- events) @@ -210,7 +210,7 @@ object EventsTableOracle extends EventsTable { transactionId = tx.transactionId, workflowId = tx.workflowId, ledgerEffectiveTime = tx.ledgerEffectiveTime, - submitterInfo = tx.submitterInfo, + completionInfo = tx.completionInfo, events = info.events, stakeholders = info.stakeholders, disclosure = info.disclosure, diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTablePostgresql.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTablePostgresql.scala index 53dae9fa75e2..bd5847f17bb0 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTablePostgresql.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/EventsTablePostgresql.scala @@ -53,9 +53,9 @@ case class EventsTablePostgresql(idempotentEventInsertions: Boolean) extends Eve val templateIds = Array.ofDim[String](batchSize) val nodeIndexes = Array.ofDim[java.lang.Integer](batchSize) val commandIds = - Array.fill(batchSize)(tx.submitterInfo.map(_.commandId.asInstanceOf[String]).orNull) + Array.fill(batchSize)(tx.completionInfo.map(_.commandId.asInstanceOf[String]).orNull) val applicationIds = - Array.fill(batchSize)(tx.submitterInfo.map(_.applicationId.asInstanceOf[String]).orNull) + Array.fill(batchSize)(tx.completionInfo.map(_.applicationId.asInstanceOf[String]).orNull) val submitters = Array.ofDim[String](batchSize) val flatEventWitnesses = Array.ofDim[String](batchSize) val treeEventWitnesses = Array.ofDim[String](batchSize) @@ -72,7 +72,7 @@ case class EventsTablePostgresql(idempotentEventInsertions: Boolean) extends Eve val exerciseActors = Array.ofDim[String](batchSize) val exerciseChildEventIds = Array.ofDim[String](batchSize) - val submittersValue = tx.submitterInfo.map(_.actAs.mkString("|")).orNull + val submittersValue = tx.completionInfo.map(_.actAs.mkString("|")).orNull for (((nodeId, node), i) <- info.events.zipWithIndex) { node match { diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/PostCommitValidation.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/PostCommitValidation.scala index 9c6c335e4608..aa34809d2fd9 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/PostCommitValidation.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/PostCommitValidation.scala @@ -6,7 +6,8 @@ package com.daml.platform.store.dao.events import java.sql.Connection import java.time.Instant -import com.daml.ledger.participant.state.v1 +import com.daml.ledger.api.domain +import com.daml.ledger.participant.state.{v1, v2} import com.daml.lf.transaction.CommittedTransaction import com.daml.platform.store.dao.events.PostCommitValidation._ @@ -271,15 +272,23 @@ private[dao] object PostCommitValidation { def description: String def toStateV1RejectionReason: v1.RejectionReason + + def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate } object Rejection { + + import com.daml.platform.store.Conversions.RejectionReasonOps + object UnknownContract extends Rejection { override val description = "Unknown contract" override def toStateV1RejectionReason: v1.RejectionReason = v1.RejectionReasonV0.Inconsistent(description) + + override def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate = + domain.RejectionReason.Inconsistent(description).toParticipantStateRejectionReason } object DuplicateKey extends Rejection { @@ -288,6 +297,9 @@ private[dao] object PostCommitValidation { override def toStateV1RejectionReason: v1.RejectionReason = v1.RejectionReasonV0.Inconsistent(description) + + override def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate = + domain.RejectionReason.Inconsistent(description).toParticipantStateRejectionReason } final case class MismatchingLookup( @@ -299,6 +311,9 @@ private[dao] object PostCommitValidation { override def toStateV1RejectionReason: v1.RejectionReason = v1.RejectionReasonV0.Inconsistent(description) + + override def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate = + domain.RejectionReason.Inconsistent(description).toParticipantStateRejectionReason } final case class CausalMonotonicityViolation( @@ -310,6 +325,9 @@ private[dao] object PostCommitValidation { override def toStateV1RejectionReason: v1.RejectionReason = v1.RejectionReasonV0.InvalidLedgerTime(description) + + override def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate = + domain.RejectionReason.InvalidLedgerTime(description).toParticipantStateRejectionReason } object UnallocatedParties extends Rejection { @@ -318,7 +336,9 @@ private[dao] object PostCommitValidation { override def toStateV1RejectionReason: v1.RejectionReason = v1.RejectionReasonV0.PartyNotKnownOnLedger(description) + + override def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate = + domain.RejectionReason.PartyNotKnownOnLedger(description).toParticipantStateRejectionReason } } - } diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/TransactionIndexing.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/TransactionIndexing.scala index e919588f6167..c84926027c5e 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/TransactionIndexing.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/TransactionIndexing.scala @@ -6,7 +6,7 @@ package com.daml.platform.store.dao.events import java.time.Instant import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.ledger.EventId import com.daml.lf.transaction.{BlindingInfo, CommittedTransaction} import com.daml.platform.store.serialization.Compression @@ -193,7 +193,7 @@ object TransactionIndexing { ) def build( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[WorkflowId], transactionId: TransactionId, ledgerEffectiveTime: Instant, @@ -223,7 +223,7 @@ object TransactionIndexing { val netVisibility = Relation.union(netTransactionVisibility, visibility(netDivulgedContracts)) TransactionIndexing( transaction = TransactionInfo( - submitterInfo = submitterInfo, + completionInfo = completionInfo, workflowId = workflowId, transactionId = transactionId, ledgerEffectiveTime = ledgerEffectiveTime, @@ -249,7 +249,7 @@ object TransactionIndexing { } final case class TransactionInfo( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[WorkflowId], transactionId: TransactionId, ledgerEffectiveTime: Instant, @@ -323,7 +323,7 @@ object TransactionIndexing { def from( blindingInfo: BlindingInfo, - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[WorkflowId], transactionId: TransactionId, ledgerEffectiveTime: Instant, @@ -341,7 +341,7 @@ object TransactionIndexing { rollbackEnd = (acc, _, _) => acc, ) .build( - submitterInfo = submitterInfo, + completionInfo = completionInfo, workflowId = workflowId, transactionId = transactionId, ledgerEffectiveTime = ledgerEffectiveTime, diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/TransactionsWriter.scala b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/TransactionsWriter.scala index 7654968c8454..b3682ca7d6d2 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/TransactionsWriter.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/dao/events/TransactionsWriter.scala @@ -8,7 +8,7 @@ import java.time.Instant import anorm.{Row, SimpleSql} import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.engine.Blinding import com.daml.lf.transaction.{BlindingInfo, CommittedTransaction} import com.daml.metrics.{Metrics, Timed} @@ -76,7 +76,7 @@ private[platform] final class TransactionsWriter( private val contractWitnessesTable = ContractWitnessesTable(dbType) def prepare( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], workflowId: Option[WorkflowId], transactionId: TransactionId, ledgerEffectiveTime: Instant, @@ -94,7 +94,7 @@ private[platform] final class TransactionsWriter( val indexing = TransactionIndexing.from( blinding, - submitterInfo, + completionInfo, workflowId, transactionId, ledgerEffectiveTime, diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/entries/LedgerEntry.scala b/ledger/participant-integration-api/src/main/scala/platform/store/entries/LedgerEntry.scala index 51b2944c7970..45f21fe2ad9b 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/entries/LedgerEntry.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/entries/LedgerEntry.scala @@ -18,6 +18,7 @@ private[platform] object LedgerEntry { recordTime: Instant, commandId: Ref.CommandId, applicationId: Ref.ApplicationId, + submissionId: Ref.SubmissionId, actAs: List[Ref.Party], rejectionReason: RejectionReason, ) extends LedgerEntry @@ -26,6 +27,7 @@ private[platform] object LedgerEntry { commandId: Option[Ref.CommandId], transactionId: Ref.TransactionId, applicationId: Option[Ref.ApplicationId], + submissionId: Option[Ref.SubmissionId], actAs: List[Ref.Party], workflowId: Option[Ref.WorkflowId], ledgerEffectiveTime: Instant, diff --git a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcAppendOnlyTransactionInsertion.scala b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcAppendOnlyTransactionInsertion.scala index 152ba6e574b5..fb4e26f31b24 100644 --- a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcAppendOnlyTransactionInsertion.scala +++ b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcAppendOnlyTransactionInsertion.scala @@ -4,7 +4,7 @@ package com.daml.platform.store.dao import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.transaction.BlindingInfo import com.daml.platform.indexer.OffsetStep import com.daml.platform.store.entries.LedgerEntry @@ -15,8 +15,8 @@ import scala.concurrent.Future trait JdbcAppendOnlyTransactionInsertion { self: JdbcLedgerDaoSuite with AsyncTestSuite => - private[dao] def store( - submitterInfo: Option[state.SubmitterInfo], + private[dao] override def store( + completionInfo: Option[state.CompletionInfo], tx: LedgerEntry.Transaction, offsetStep: OffsetStep, divulgedContracts: List[state.DivulgedContract], @@ -24,7 +24,7 @@ trait JdbcAppendOnlyTransactionInsertion { ): Future[(Offset, LedgerEntry.Transaction)] = { for { _ <- ledgerDao.storeTransaction( - submitterInfo = submitterInfo, + completionInfo = completionInfo, workflowId = tx.workflowId, transactionId = tx.transactionId, ledgerEffectiveTime = tx.ledgerEffectiveTime, diff --git a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcAtomicTransactionInsertion.scala b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcAtomicTransactionInsertion.scala index c78a88502aca..f80b2e34d646 100644 --- a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcAtomicTransactionInsertion.scala +++ b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcAtomicTransactionInsertion.scala @@ -4,7 +4,7 @@ package com.daml.platform.store.dao import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.transaction.BlindingInfo import com.daml.platform.indexer.OffsetStep import com.daml.platform.store.entries.LedgerEntry @@ -15,15 +15,15 @@ import scala.concurrent.Future trait JdbcAtomicTransactionInsertion { self: JdbcLedgerDaoSuite with AsyncTestSuite => - private[dao] def store( - submitterInfo: Option[state.SubmitterInfo], + private[dao] override def store( + completionInfo: Option[state.CompletionInfo], tx: LedgerEntry.Transaction, offsetStep: OffsetStep, divulgedContracts: List[state.DivulgedContract], blindingInfo: Option[BlindingInfo], ): Future[(Offset, LedgerEntry.Transaction)] = { val preparedTransactionInsert = ledgerDao.prepareTransactionInsert( - submitterInfo, + completionInfo, tx.workflowId, tx.transactionId, tx.ledgerEffectiveTime, @@ -35,7 +35,7 @@ trait JdbcAtomicTransactionInsertion { for { _ <- ledgerDao.storeTransaction( preparedTransactionInsert, - submitterInfo = submitterInfo, + completionInfo = completionInfo, transactionId = tx.transactionId, transaction = tx.transaction, recordTime = tx.recordedAt, diff --git a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoCompletionsSpec.scala b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoCompletionsSpec.scala index d08237d28daa..bdf7e7d12fbe 100644 --- a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoCompletionsSpec.scala +++ b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoCompletionsSpec.scala @@ -8,11 +8,12 @@ import java.util.UUID import akka.stream.scaladsl.Sink import com.daml.ledger.api.v1.command_completion_service.CompletionStreamResponse import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.v1.RejectionReasonV0 -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref import com.daml.platform.ApiOffset import com.daml.platform.store.dao.JdbcLedgerDaoCompletionsSpec._ +import com.google.rpc.status.{Status => RpcStatus} +import io.grpc.Status import org.scalatest.flatspec.AsyncFlatSpec import org.scalatest.matchers.should.Matchers import org.scalatest.{LoneElement, OptionValues} @@ -22,8 +23,6 @@ import scala.concurrent.Future private[dao] trait JdbcLedgerDaoCompletionsSpec extends OptionValues with LoneElement { this: AsyncFlatSpec with Matchers with JdbcLedgerDaoSuite => - import state.RejectionReasonV0._ - behavior of "JdbcLedgerDao (completions)" it should "return the expected completion for an accepted transaction" in { @@ -71,9 +70,12 @@ private[dao] trait JdbcLedgerDaoCompletionsSpec extends OptionValues with LoneEl it should "return the expected completion for a rejection" in { val expectedCmdId = UUID.randomUUID.toString + val rejection = new state.Update.CommandRejected.FinalReason( + RpcStatus.of(Status.Code.ABORTED.value(), "Stop.", Seq.empty) + ) for { from <- ledgerDao.lookupLedgerEnd() - offset <- storeRejection(Inconsistent(""), expectedCmdId) + offset <- storeRejection(rejection, expectedCmdId) to <- ledgerDao.lookupLedgerEnd() (_, response) <- ledgerDao.completions .getCommandCompletions(from, to, applicationId, parties) @@ -85,15 +87,18 @@ private[dao] trait JdbcLedgerDaoCompletionsSpec extends OptionValues with LoneEl completion.transactionId shouldBe empty completion.commandId shouldBe expectedCmdId - completion.status.value.code shouldNot be(io.grpc.Status.Code.OK.value()) + completion.status shouldBe Some(rejection.status) } } it should "return the expected completion for a multi-party rejection" in { val expectedCmdId = UUID.randomUUID.toString + val rejection = new state.Update.CommandRejected.FinalReason( + RpcStatus.of(Status.Code.ALREADY_EXISTS.value(), "No thanks.", Seq.empty) + ) for { from <- ledgerDao.lookupLedgerEnd() - _ <- storeMultiPartyRejection(Inconsistent(""), expectedCmdId) + _ <- storeMultiPartyRejection(rejection, expectedCmdId) to <- ledgerDao.lookupLedgerEnd() // Response 1: querying as all submitters (_, response1) <- ledgerDao.completions @@ -115,9 +120,12 @@ private[dao] trait JdbcLedgerDaoCompletionsSpec extends OptionValues with LoneEl } it should "not return completions if the application id is wrong" in { + val rejection = new state.Update.CommandRejected.FinalReason( + RpcStatus.of(Status.Code.INTERNAL.value(), "Internal error.", Seq.empty) + ) for { from <- ledgerDao.lookupLedgerEnd() - _ <- storeRejection(Inconsistent("")) + _ <- storeRejection(rejection) to <- ledgerDao.lookupLedgerEnd() response <- ledgerDao.completions .getCommandCompletions(from, to, applicationId = "WRONG", parties) @@ -128,9 +136,12 @@ private[dao] trait JdbcLedgerDaoCompletionsSpec extends OptionValues with LoneEl } it should "not return completions if the parties do not match" in { + val rejection = new state.Update.CommandRejected.FinalReason( + RpcStatus.of(Status.Code.OUT_OF_RANGE.value(), "Too far.", Seq.empty) + ) for { from <- ledgerDao.lookupLedgerEnd() - _ <- storeRejection(Inconsistent("")) + _ <- storeRejection(rejection) to <- ledgerDao.lookupLedgerEnd() response1 <- ledgerDao.completions .getCommandCompletions(from, to, applicationId, Set("WRONG")) @@ -145,9 +156,12 @@ private[dao] trait JdbcLedgerDaoCompletionsSpec extends OptionValues with LoneEl } it should "not return completions if the parties do not match (multi-party submission)" in { + val rejection = new state.Update.CommandRejected.FinalReason( + RpcStatus.of(Status.Code.PERMISSION_DENIED.value(), "Forbidden.", Seq.empty) + ) for { from <- ledgerDao.lookupLedgerEnd() - _ <- storeMultiPartyRejection(Inconsistent("")) + _ <- storeMultiPartyRejection(rejection) to <- ledgerDao.lookupLedgerEnd() response1 <- ledgerDao.completions .getCommandCompletions(from, to, applicationId, Set("WRONG")) @@ -161,40 +175,13 @@ private[dao] trait JdbcLedgerDaoCompletionsSpec extends OptionValues with LoneEl } } - it should "return the expected status for each rejection reason" in { - val reasons = List[state.RejectionReasonV0]( - Disputed(""), - Inconsistent(""), - InvalidLedgerTime(""), - ResourcesExhausted(""), - PartyNotKnownOnLedger(""), - SubmitterCannotActViaParticipant(""), - InvalidLedgerTime(""), - ) - - for { - from <- ledgerDao.lookupLedgerEnd() - _ <- seq(reasons.map(reason => prepareStoreRejection(reason))) - to <- ledgerDao.lookupLedgerEnd() - responses <- ledgerDao.completions - .getCommandCompletions(from, to, applicationId, parties) - .map(_._2) - .runWith(Sink.seq) - } yield { - responses should have length reasons.length.toLong - val returnedCodes = responses.flatMap(_.completions.map(_.status.get.code)) - for ((reason, code) <- reasons.zip(returnedCodes)) { - code shouldBe reason.code.value - } - succeed - } - } it should "allow arbitrarily large rejection reasons" in { + val rejection = new state.Update.CommandRejected.FinalReason( + RpcStatus.of(Status.Code.ABORTED.value(), (0 to 10000).map(_ => " ").mkString(""), Seq.empty) + ) for { from <- ledgerDao.lookupLedgerEnd() - _ <- storeMultiPartyRejection( - RejectionReasonV0.Inconsistent((0 to 10000).map(_ => " ").mkString("")) - ) + _ <- storeMultiPartyRejection(rejection) to <- ledgerDao.lookupLedgerEnd() response1 <- ledgerDao.completions .getCommandCompletions(from, to, applicationId, Set("WRONG")) @@ -204,15 +191,23 @@ private[dao] trait JdbcLedgerDaoCompletionsSpec extends OptionValues with LoneEl } } - private def prepareStoreRejection( - reason: state.RejectionReasonV0, - commandId: String = UUID.randomUUID().toString, - ): () => Future[Offset] = () => { + private def storeRejection( + reason: state.Update.CommandRejected.RejectionReasonTemplate, + commandId: Ref.CommandId = UUID.randomUUID().toString, + submissionId: Ref.SubmissionId = UUID.randomUUID().toString, + ): Future[Offset] = { val offset = nextOffset() ledgerDao .storeRejection( - submitterInfo = - Some(state.SubmitterInfo(List(party1), applicationId, commandId, Instant.EPOCH)), + completionInfo = Some( + state.CompletionInfo( + actAs = List(party1), + applicationId = applicationId, + commandId = commandId, + optDeduplicationPeriod = None, + submissionId = submissionId, + ) + ), recordTime = Instant.now, offsetStep = nextOffsetStep(offset), reason = reason, @@ -221,14 +216,21 @@ private[dao] trait JdbcLedgerDaoCompletionsSpec extends OptionValues with LoneEl } private def storeMultiPartyRejection( - reason: state.RejectionReasonV0, - commandId: String = UUID.randomUUID().toString, + reason: state.Update.CommandRejected.RejectionReasonTemplate, + commandId: Ref.CommandId = UUID.randomUUID().toString, + submissionId: Ref.SubmissionId = UUID.randomUUID().toString, ): Future[Offset] = { lazy val offset = nextOffset() ledgerDao .storeRejection( - submitterInfo = Some( - state.SubmitterInfo(List(party1, party2, party3), applicationId, commandId, Instant.EPOCH) + completionInfo = Some( + state.CompletionInfo( + actAs = List(party1, party2, party3), + applicationId = applicationId, + commandId = commandId, + optDeduplicationPeriod = None, + submissionId = submissionId, + ) ), recordTime = Instant.now, offsetStep = nextOffsetStep(offset), @@ -236,18 +238,6 @@ private[dao] trait JdbcLedgerDaoCompletionsSpec extends OptionValues with LoneEl ) .map(_ => offset) } - - private def storeRejection( - reason: state.RejectionReasonV0, - commandId: String = UUID.randomUUID().toString, - ): Future[Offset] = prepareStoreRejection(reason, commandId)() - - /** Starts and executes futures sequentially */ - private def seq(s: List[() => Future[Offset]]): Future[Seq[Offset]] = - s match { - case Nil => Future(Seq.empty) - case hd :: tail => hd().flatMap(offset => seq(tail).map(offset +: _)) - } } private[dao] object JdbcLedgerDaoCompletionsSpec { diff --git a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoDivulgenceSpec.scala b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoDivulgenceSpec.scala index 9ab34d7cfd5c..1e4b09350fe1 100644 --- a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoDivulgenceSpec.scala +++ b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoDivulgenceSpec.scala @@ -147,13 +147,14 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside { val t1 = Instant.now() val t2 = t1.plusMillis(1) val t3 = t2.plusMillis(1) - val appId = UUID.randomUUID.toString + val appId = UUID.randomUUID().toString for { _ <- store( nextOffset() -> LedgerEntry.Transaction( - commandId = Some(UUID.randomUUID.toString), - transactionId = UUID.randomUUID.toString, + commandId = Some(UUID.randomUUID().toString), + transactionId = UUID.randomUUID().toString, applicationId = Some(appId), + submissionId = Some(UUID.randomUUID().toString), actAs = List(alice), workflowId = None, ledgerEffectiveTime = t1, @@ -164,9 +165,10 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside { ) _ <- store( nextOffset() -> LedgerEntry.Transaction( - commandId = Some(UUID.randomUUID.toString), - transactionId = UUID.randomUUID.toString, + commandId = Some(UUID.randomUUID().toString), + transactionId = UUID.randomUUID().toString, applicationId = Some(appId), + submissionId = Some(UUID.randomUUID().toString), actAs = List(bob), workflowId = None, ledgerEffectiveTime = t2, @@ -179,9 +181,10 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside { divulgedContracts = Map((create2, someVersionedContractInstance) -> Set(alice)), blindingInfo = None, offsetAndTx = nextOffset() -> LedgerEntry.Transaction( - commandId = Some(UUID.randomUUID.toString), - transactionId = UUID.randomUUID.toString, + commandId = Some(UUID.randomUUID().toString), + transactionId = UUID.randomUUID().toString, applicationId = Some(appId), + submissionId = Some(UUID.randomUUID().toString), actAs = List(bob), workflowId = None, ledgerEffectiveTime = t3, diff --git a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoSuite.scala b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoSuite.scala index 754c0f2f3d34..87e4073c047f 100644 --- a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoSuite.scala +++ b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoSuite.scala @@ -14,7 +14,7 @@ import com.daml.daml_lf_dev.DamlLf import com.daml.ledger.configuration.{Configuration, LedgerTimeModel} import com.daml.ledger.offset.Offset import com.daml.ledger.participant.state.index.v2 -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.test.ModelTestDar import com.daml.lf.archive.DarParser import com.daml.lf.data.Ref.{Identifier, Party} @@ -88,7 +88,10 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { Ref.DottedName.assertFromString(name), ), ) - protected def recordFieldName(name: String) = Some(Ref.Name.assertFromString(name)) + + protected def recordFieldName(name: String): Option[Ref.Name] = + Some(Ref.Name.assertFromString(name)) + protected final val someTemplateId = testIdentifier("ParameterShowcase") protected final val someValueText = LfValue.ValueText("some text") protected final val someValueInt = LfValue.ValueInt64(1) @@ -134,13 +137,16 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { ) protected final val someChoiceResult = LfValue.ValueContractId[ContractId](ContractId.V0.assertFromString("#1")) - protected final def someContractKey(party: Party, value: String) = LfValue.ValueRecord( - None, - ImmArray( - None -> LfValue.ValueParty(party), - None -> LfValue.ValueText(value), - ), - ) + + protected final def someContractKey(party: Party, value: String): LfValue.ValueRecord[Nothing] = + LfValue.ValueRecord( + None, + ImmArray( + None -> LfValue.ValueParty(party), + None -> LfValue.ValueText(value), + ), + ) + protected final val someContractInstance = ContractInst( someTemplateId, someContractArgument, @@ -164,7 +170,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { ) private[dao] def store( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], tx: LedgerEntry.Transaction, offsetStep: OffsetStep, divulgedContracts: List[state.DivulgedContract], @@ -280,6 +286,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(s"commandId$id"), transactionId = s"trId$id", applicationId = Some("appID1"), + submissionId = Some(s"submissionId$id"), actAs = actAs, workflowId = Some("workflowId"), ledgerEffectiveTime = let, @@ -305,6 +312,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(s"commandId$id"), transactionId = s"trId$id", applicationId = Some("appID1"), + submissionId = Some(s"submissionId$id"), actAs = actAs, workflowId = Some("workflowId"), ledgerEffectiveTime = let, @@ -396,6 +404,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(s"just-divulged-${id.coid}"), transactionId = s"trId${id.coid}", applicationId = Some("appID1"), + submissionId = Some(s"submissionId${id.coid}"), actAs = List(divulgees.head), workflowId = None, ledgerEffectiveTime = Instant.now, @@ -418,6 +427,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(s"commandId$id"), transactionId = s"trId$id", applicationId = Some("appID1"), + submissionId = Some(s"submissionId$id"), actAs = List("Alice"), workflowId = Some("workflowId"), ledgerEffectiveTime = let, @@ -439,6 +449,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(s"commandId$id"), transactionId = s"trId$id", applicationId = Some("appID1"), + submissionId = Some(s"submissionId$id"), actAs = List(alice, bob, charlie), workflowId = Some("workflowId"), ledgerEffectiveTime = let, @@ -460,6 +471,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(s"commandId$id"), transactionId = s"trId$id", applicationId = Some("appID1"), + submissionId = Some(s"submissionId$id"), actAs = List("Alice"), workflowId = Some("workflowId"), ledgerEffectiveTime = let, @@ -481,15 +493,16 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { val txId = s"trId$id" val let = Instant.now offset -> LedgerEntry.Transaction( - Some(s"commandId$id"), - txId, - Some("appID1"), - List("Alice"), - Some("workflowId"), - let, - let, - CommittedTransaction(tx), - Map(exerciseId -> Set("Alice", "Bob"), childId -> Set("Alice", "Bob")), + commandId = Some(s"commandId$id"), + transactionId = txId, + applicationId = Some("appID1"), + submissionId = Some(s"submissionId$id"), + actAs = List("Alice"), + workflowId = Some("workflowId"), + ledgerEffectiveTime = let, + recordedAt = let, + transaction = CommittedTransaction(tx), + explicitDisclosure = Map(exerciseId -> Set("Alice", "Bob"), childId -> Set("Alice", "Bob")), ) } @@ -505,6 +518,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(UUID.randomUUID().toString), transactionId = UUID.randomUUID().toString, applicationId = Some("appID1"), + submissionId = Some(UUID.randomUUID.toString), actAs = List(alice), workflowId = Some("workflowId"), ledgerEffectiveTime = let, @@ -532,6 +546,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(UUID.randomUUID.toString), transactionId = UUID.randomUUID().toString, applicationId = Some("appID1"), + submissionId = Some(UUID.randomUUID.toString), actAs = List(alice), workflowId = Some("workflowId"), ledgerEffectiveTime = let, @@ -586,6 +601,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(UUID.randomUUID().toString), transactionId = UUID.randomUUID().toString, applicationId = Some("appID1"), + submissionId = Some(UUID.randomUUID().toString), actAs = List(charlie), workflowId = Some("workflowId"), ledgerEffectiveTime = let, @@ -624,6 +640,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(UUID.randomUUID().toString), transactionId = UUID.randomUUID.toString, applicationId = Some("appID1"), + submissionId = Some(UUID.randomUUID.toString), actAs = List(operator), workflowId = Some("workflowId"), ledgerEffectiveTime = Instant.now, @@ -634,14 +651,14 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { } protected final def prepareInsert( - submitterInfo: Option[state.SubmitterInfo], + completionInfo: Option[state.CompletionInfo], tx: LedgerEntry.Transaction, offsetStep: OffsetStep, divulgedContracts: List[state.DivulgedContract] = List.empty, blindingInfo: Option[BlindingInfo] = None, ): TransactionsWriter.PreparedInsert = ledgerDao.prepareTransactionInsert( - submitterInfo, + completionInfo, tx.workflowId, tx.transactionId, tx.ledgerEffectiveTime, @@ -668,18 +685,20 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { offsetStepAndTx: (OffsetStep, LedgerEntry.Transaction), ): Future[(Offset, LedgerEntry.Transaction)] = { val (offsetStep, entry) = offsetStepAndTx - val maybeSubmitterInfo = submitterInfo(entry) + val info = completionInfoFrom(entry) val divulged = divulgedContracts.keysIterator.map(c => state.DivulgedContract(c._1, c._2)).toList - store(maybeSubmitterInfo, entry, offsetStep, divulged, blindingInfo) + store(info, entry, offsetStep, divulged, blindingInfo) } - protected def submitterInfo(entry: LedgerEntry.Transaction) = - for ( - actAs <- if (entry.actAs.isEmpty) None else Some(entry.actAs); app <- entry.applicationId; - cmd <- entry.commandId - ) yield state.SubmitterInfo(actAs, app, cmd, Instant.EPOCH) + protected def completionInfoFrom(entry: LedgerEntry.Transaction): Option[state.CompletionInfo] = + for { + actAs <- if (entry.actAs.isEmpty) None else Some(entry.actAs) + applicationId <- entry.applicationId + commandId <- entry.commandId + submissionId <- entry.submissionId + } yield state.CompletionInfo(actAs, applicationId, commandId, None, submissionId) protected final def store( offsetAndTx: (Offset, LedgerEntry.Transaction) @@ -727,6 +746,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(UUID.randomUUID().toString), transactionId = txUuid.getOrElse(UUID.randomUUID.toString), applicationId = Some(defaultAppId), + submissionId = Some(UUID.randomUUID().toString), actAs = List(party), workflowId = Some(defaultWorkflowId), ledgerEffectiveTime = Instant.now, @@ -765,6 +785,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(UUID.randomUUID().toString), transactionId = UUID.randomUUID.toString, applicationId = Some(defaultAppId), + submissionId = Some(UUID.randomUUID().toString), actAs = List(party), workflowId = Some(defaultWorkflowId), ledgerEffectiveTime = Instant.now, @@ -793,6 +814,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(UUID.randomUUID().toString), transactionId = UUID.randomUUID.toString, applicationId = Some(defaultAppId), + submissionId = Some(UUID.randomUUID().toString), actAs = List(party), workflowId = Some(defaultWorkflowId), ledgerEffectiveTime = Instant.now(), @@ -823,6 +845,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(UUID.randomUUID().toString), transactionId = UUID.randomUUID.toString, applicationId = Some(defaultAppId), + submissionId = Some(UUID.randomUUID().toString), actAs = List(party), workflowId = Some(defaultWorkflowId), ledgerEffectiveTime = Instant.now(), @@ -837,6 +860,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { commandId = Some(UUID.randomUUID().toString), transactionId = UUID.randomUUID.toString, applicationId = Some(defaultAppId), + submissionId = Some(UUID.randomUUID().toString), actAs = List(party), workflowId = Some(defaultWorkflowId), ledgerEffectiveTime = Instant.now(), diff --git a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcPipelinedInsertionsSpec.scala b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcPipelinedInsertionsSpec.scala index 75ecd60264b4..62bc3bfbcfce 100644 --- a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcPipelinedInsertionsSpec.scala +++ b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcPipelinedInsertionsSpec.scala @@ -24,8 +24,8 @@ trait JdbcPipelinedInsertionsSpec extends Inside with OptionValues with Matchers it should "allow idempotent transaction insertions" in { val key = "some-key" val create @ (offset, tx) = txCreateContractWithKey(alice, key, Some("1337")) - val maybeSubmitterInfo = submitterInfo(tx) - val preparedInsert = prepareInsert(maybeSubmitterInfo, tx, CurrentOffset(offset)) + val info = completionInfoFrom(tx) + val preparedInsert = prepareInsert(info, tx, CurrentOffset(offset)) for { _ <- ledgerDao.storeTransactionEvents(preparedInsert) // Assume the indexer restarts after events insertion @@ -73,7 +73,7 @@ trait JdbcPipelinedInsertionsSpec extends Inside with OptionValues with Matchers offsetTx: (Offset, LedgerEntry.Transaction) ): Future[Assertion] = { val (offset, tx) = offsetTx - val maybeSubmitterInfo = submitterInfo(tx) + val maybeSubmitterInfo = completionInfoFrom(tx) val preparedInsert = prepareInsert(maybeSubmitterInfo, tx, CurrentOffset(offset)) for { _ <- ledgerDao.storeTransactionEvents(preparedInsert) diff --git a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcPipelinedTransactionInsertion.scala b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcPipelinedTransactionInsertion.scala index f5850e517a0f..9b4e4d84a543 100644 --- a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcPipelinedTransactionInsertion.scala +++ b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcPipelinedTransactionInsertion.scala @@ -4,7 +4,7 @@ package com.daml.platform.store.dao import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.transaction.BlindingInfo import com.daml.platform.indexer.OffsetStep import com.daml.platform.store.entries.LedgerEntry @@ -15,20 +15,20 @@ import scala.concurrent.Future trait JdbcPipelinedTransactionInsertion { self: JdbcLedgerDaoSuite with AsyncTestSuite => - private[dao] def store( - submitterInfo: Option[state.SubmitterInfo], + private[dao] override def store( + completionInfo: Option[state.CompletionInfo], tx: LedgerEntry.Transaction, offsetStep: OffsetStep, divulgedContracts: List[state.DivulgedContract], blindingInfo: Option[BlindingInfo], ): Future[(Offset, LedgerEntry.Transaction)] = { val preparedTransactionInsert = - prepareInsert(submitterInfo, tx, offsetStep, divulgedContracts, blindingInfo) + prepareInsert(completionInfo, tx, offsetStep, divulgedContracts, blindingInfo) for { _ <- ledgerDao.storeTransactionState(preparedTransactionInsert) _ <- ledgerDao.storeTransactionEvents(preparedTransactionInsert) _ <- ledgerDao.completeTransaction( - submitterInfo = submitterInfo, + completionInfo = completionInfo, transactionId = tx.transactionId, recordTime = tx.recordedAt, offsetStep = offsetStep, diff --git a/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiConfigManagementServiceSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiConfigManagementServiceSpec.scala index 630dfa3ea250..b683c01dbfe9 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiConfigManagementServiceSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiConfigManagementServiceSpec.scala @@ -14,7 +14,7 @@ import com.daml.ledger.api.testing.utils.AkkaBeforeAndAfterAll import com.daml.ledger.api.v1.admin.config_management_service.{SetTimeModelRequest, TimeModel} import com.daml.ledger.configuration.{Configuration, LedgerTimeModel} import com.daml.ledger.participant.state.index.v2.IndexConfigManagementService -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.{Ref, Time} import com.daml.logging.LoggingContext import com.daml.platform.configuration.LedgerConfiguration diff --git a/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiPackageManagementServiceSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiPackageManagementServiceSpec.scala index 4ac77e8ab87b..f0f33cb705d5 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiPackageManagementServiceSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiPackageManagementServiceSpec.scala @@ -18,7 +18,7 @@ import com.daml.ledger.api.v1.admin.package_management_service.{ UploadDarFileRequest, } import com.daml.ledger.participant.state.index.v2.{IndexPackagesService, IndexTransactionsService} -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.archive.testing.Encode import com.daml.lf.archive.{Dar, GenDarReader} import com.daml.lf.data.Ref diff --git a/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiPartyManagementServiceSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiPartyManagementServiceSpec.scala index 374888e32d0d..1890066b598b 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiPartyManagementServiceSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/db/migration/translation/apiserver/services/admin/ApiPartyManagementServiceSpec.scala @@ -15,7 +15,7 @@ import com.daml.ledger.participant.state.index.v2.{ IndexPartyManagementService, IndexTransactionsService, } -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref import com.daml.logging.LoggingContext import com.daml.telemetry.{TelemetryContext, TelemetrySpecBase} diff --git a/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/execution/StoreBackedCommandExecutorSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/execution/StoreBackedCommandExecutorSpec.scala index 97d650a3a93f..079d5dacbead 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/execution/StoreBackedCommandExecutorSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/execution/StoreBackedCommandExecutorSpec.scala @@ -3,8 +3,11 @@ package com.daml.platform.apiserver.execution +import java.time.{Duration, Instant} + import com.codahale.metrics.MetricRegistry -import com.daml.ledger.api.domain.Commands +import com.daml.ledger.api.domain.{ApplicationId, CommandId, Commands, LedgerId, SubmissionId} +import com.daml.ledger.configuration.{Configuration, LedgerTimeModel} import com.daml.ledger.participant.state.index.v2.{ContractStore, IndexPackagesService} import com.daml.lf.crypto.Hash import com.daml.lf.data.Ref.ParticipantId @@ -17,6 +20,7 @@ import com.daml.metrics.Metrics import org.mockito.{ArgumentMatchersSugar, MockitoSugar} import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AsyncWordSpec +import com.daml.lf.command.{Commands => LfCommands} class StoreBackedCommandExecutorSpec extends AsyncWordSpec @@ -49,6 +53,34 @@ class StoreBackedCommandExecutorSpec (TransactionBuilder.EmptySubmitted, emptyTransactionMetadata) ) ) + + val commands = Commands( + ledgerId = LedgerId("ledgerId"), + workflowId = None, + applicationId = ApplicationId(Ref.ApplicationId.assertFromString("applicationId")), + commandId = CommandId(Ref.CommandId.assertFromString("commandId")), + submissionId = SubmissionId(Ref.SubmissionId.assertFromString("submissionId")), + actAs = Set.empty, + readAs = Set.empty, + submittedAt = Instant.EPOCH, + deduplicationDuration = Duration.ZERO, + commands = LfCommands( + commands = ImmArray.empty, + ledgerEffectiveTime = Time.Timestamp.Epoch, + commandsReference = "", + ), + ) + val submissionSeed = Hash.hashPrivateKey("a key") + val configuration = Configuration( + generation = 1, + timeModel = LedgerTimeModel( + avgTransactionLatency = Duration.ZERO, + minSkew = Duration.ZERO, + maxSkew = Duration.ZERO, + ).get, + maxDeduplicationTime = Duration.ZERO, + ) + val instance = new StoreBackedCommandExecutor( mockEngine, Ref.ParticipantId.assertFromString("anId"), @@ -56,16 +88,9 @@ class StoreBackedCommandExecutorSpec mock[ContractStore], new Metrics(new MetricRegistry), ) - val mockDomainCommands = mock[Commands] - val mockLfCommands = mock[com.daml.lf.command.Commands] - when(mockLfCommands.ledgerEffectiveTime).thenReturn(Time.Timestamp.now()) - when(mockDomainCommands.workflowId).thenReturn(None) - when(mockDomainCommands.commands).thenReturn(mockLfCommands) - when(mockDomainCommands.actAs).thenReturn(Set.empty[Ref.Party]) - when(mockDomainCommands.readAs).thenReturn(Set.empty[Ref.Party]) LoggingContext.newLoggingContext { implicit context => - instance.execute(mockDomainCommands, Hash.hashPrivateKey("a key")).map { actual => + instance.execute(commands, submissionSeed, configuration).map { actual => actual.foreach { actualResult => actualResult.interpretationTimeNanos should be > 0L } diff --git a/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/services/ApiSubmissionServiceSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/services/ApiSubmissionServiceSpec.scala index 616896d52b96..80af9ee13232 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/services/ApiSubmissionServiceSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/services/ApiSubmissionServiceSpec.scala @@ -4,6 +4,7 @@ package com.daml.platform.apiserver.services import java.time.{Duration, Instant} +import java.util.UUID import java.util.concurrent.CompletableFuture.completedFuture import java.util.concurrent.atomic.AtomicInteger @@ -12,7 +13,15 @@ import akka.stream.scaladsl.Source import com.codahale.metrics.MetricRegistry import com.daml.api.util.TimeProvider import com.daml.ledger.api.DomainMocks -import com.daml.ledger.api.domain.{CommandId, Commands, LedgerId, LedgerOffset, PartyDetails} +import com.google.rpc.status.{Status => RpcStatus} +import com.daml.ledger.api.domain.{ + CommandId, + Commands, + LedgerId, + LedgerOffset, + PartyDetails, + SubmissionId, +} import com.daml.ledger.api.messages.command.submission.SubmitRequest import com.daml.ledger.api.testing.utils.AkkaBeforeAndAfterAll import com.daml.ledger.configuration.{Configuration, LedgerTimeModel} @@ -22,7 +31,7 @@ import com.daml.ledger.participant.state.index.v2.{ IndexPartyManagementService, IndexSubmissionService, } -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.{ResourceOwner, TestResourceContext} import com.daml.lf import com.daml.lf.command.{Commands => LfCommands} @@ -197,7 +206,9 @@ class ApiSubmissionServiceSpec val party = "party-1" val typedParty = Ref.Party.assertFromString(party) - val submissionFailure = state.SubmissionResult.InternalError(s"failed to allocate $party") + val submissionFailure = state.SubmissionResult.SynchronousError( + RpcStatus.of(Status.Code.INTERNAL.value(), s"Failed to allocate $party.", Seq.empty) + ) when( writeService.allocateParty( eqTo(Some(typedParty)), @@ -305,8 +316,10 @@ class ApiSubmissionServiceSpec workflowId = None, applicationId = DomainMocks.applicationId, commandId = CommandId( - Ref.LedgerString.assertFromString(s"commandId-${commandId.incrementAndGet()}") + Ref.CommandId.assertFromString(s"commandId-${commandId.incrementAndGet()}") ), + submissionId = + SubmissionId(Ref.SubmissionId.assertFromString(UUID.randomUUID().toString)), actAs = Set.empty, readAs = Set.empty, submittedAt = Instant.MIN, @@ -315,10 +328,11 @@ class ApiSubmissionServiceSpec ) ) when( - mockCommandExecutor.execute(eqTo(submitRequest.commands), any[Hash])( - any[ExecutionContext], - any[LoggingContext], - ) + mockCommandExecutor.execute( + eqTo(submitRequest.commands), + any[Hash], + any[Configuration], + )(any[ExecutionContext], any[LoggingContext]) ).thenReturn(Future.successful(Left(error))) service.submit(submitRequest).transform(result => Success(code -> result)) diff --git a/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/services/LedgerConfigProviderSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/services/LedgerConfigProviderSpec.scala index 5fcaab58bae7..1b1265d9d83f 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/services/LedgerConfigProviderSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/platform/apiserver/services/LedgerConfigProviderSpec.scala @@ -14,7 +14,7 @@ import com.daml.ledger.api.domain.{ConfigurationEntry, LedgerOffset} import com.daml.ledger.api.testing.utils.AkkaBeforeAndAfterAll import com.daml.ledger.configuration.{Configuration, LedgerTimeModel} import com.daml.ledger.participant.state.index.v2.IndexConfigManagementService -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.ResourceContext import com.daml.lf.data.Ref import com.daml.lf.data.Time.Timestamp diff --git a/ledger/participant-integration-api/src/test/suite/scala/platform/index/TransactionConversionSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/platform/index/TransactionConversionSpec.scala index 84946e3e8127..8b0cde433954 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/platform/index/TransactionConversionSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/platform/index/TransactionConversionSpec.scala @@ -24,7 +24,7 @@ final class TransactionConversionSpec extends AnyWordSpec with Matchers { private val contractId1 = Value.ContractId.assertFromString("#contractId") private val contractId2 = Value.ContractId.assertFromString("#contractId2") private def create(contractId: Value.ContractId): Event = - Event( + Event.of( Event.Event.Created( CreatedEvent("", contractId.coid, None, None, None, Seq.empty, Seq.empty, Seq.empty, None) ) @@ -32,7 +32,7 @@ final class TransactionConversionSpec extends AnyWordSpec with Matchers { private val create1 = create(contractId1) private val create2 = create(contractId2) - private val archive1 = Event( + private val archive1 = Event.of( Event.Event.Archived(ArchivedEvent("", contractId1.coid, None, Seq.empty)) ) @@ -119,6 +119,7 @@ final class TransactionConversionSpec extends AnyWordSpec with Matchers { commandId = None, transactionId = Ref.TransactionId.assertFromString("transactionId"), applicationId = None, + submissionId = Some(Ref.SubmissionId.assertFromString("submissionId")), actAs = List(party), workflowId = None, ledgerEffectiveTime = Instant.EPOCH, diff --git a/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/ExecuteUpdateSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/ExecuteUpdateSpec.scala index d25e73a492e8..d4f7bef88e32 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/ExecuteUpdateSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/ExecuteUpdateSpec.scala @@ -9,16 +9,10 @@ import akka.stream.scaladsl.{Flow, Source} import com.codahale.metrics.MetricRegistry import com.daml.ledger.api.testing.utils.AkkaBeforeAndAfterAll import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.TestResourceContext import com.daml.lf.data.{Bytes, ImmArray, Ref, Time} -import com.daml.lf.transaction.{ - BlindingInfo, - CommittedTransaction, - NodeId, - TransactionVersion, - VersionedTransaction, -} +import com.daml.lf.transaction.{NodeId, TransactionVersion, VersionedTransaction} import com.daml.lf.value.Value.ContractId import com.daml.lf.{crypto, transaction} import com.daml.logging.LoggingContext @@ -67,12 +61,20 @@ final class ExecuteUpdateSpec packageUploadRejectionReason, ) - private val txAccepted = transactionAccepted( - submitterInfo = None, - workflowId = None, - transactionId = txId, - ledgerEffectiveTime = Instant.EPOCH, + private val txAccepted = state.Update.TransactionAccepted( + optCompletionInfo = None, + transactionMeta = state.TransactionMeta( + ledgerEffectiveTime = Time.Timestamp.Epoch, + workflowId = None, + submissionTime = Time.Timestamp.Epoch, + submissionSeed = crypto.Hash.hashPrivateKey("dummy"), + optUsedPackages = None, + optNodeSeeds = None, + optByKeyNodes = None, + ), transaction = txMock, + transactionId = txId, + recordTime = Time.Timestamp.Epoch, divulgedContracts = List.empty, blindingInfo = None, ) @@ -91,7 +93,7 @@ final class ExecuteUpdateSpec when( dao.prepareTransactionInsert( - submitterInfo = None, + completionInfo = None, workflowId = None, transactionId = txId, ledgerEffectiveTime = ledgerEffectiveTime, @@ -108,7 +110,7 @@ final class ExecuteUpdateSpec .thenReturn(Future.successful(PersistenceResponse.Ok)) when( dao.completeTransaction( - eqTo(Option.empty[state.SubmitterInfo]), + eqTo(None), eqTo(txId), eqTo(ledgerEffectiveTime), eqTo(CurrentOffset(offset)), @@ -125,7 +127,7 @@ final class ExecuteUpdateSpec when( dao.storeTransaction( preparedInsert = eqTo(mockedPreparedInsert), - submitterInfo = eqTo(Option.empty[state.SubmitterInfo]), + completionInfo = eqTo(None), transactionId = eqTo(txId), recordTime = eqTo(ledgerEffectiveTime), ledgerEffectiveTime = eqTo(ledgerEffectiveTime), @@ -246,7 +248,7 @@ final class ExecuteUpdateSpec orderedEvents .verify(ledgerDaoMock) .prepareTransactionInsert( - submitterInfo = None, + completionInfo = None, workflowId = None, transactionId = txId, ledgerEffectiveTime = ledgerEffectiveTime, @@ -264,7 +266,7 @@ final class ExecuteUpdateSpec orderedEvents .verify(ledgerDaoMock) .completeTransaction( - eqTo(Option.empty[state.SubmitterInfo]), + eqTo(None), eqTo(txId), eqTo(ledgerEffectiveTime), eqTo(CurrentOffset(offset)), @@ -309,7 +311,7 @@ final class ExecuteUpdateSpec orderedEvents .verify(ledgerDaoMock) .prepareTransactionInsert( - submitterInfo = None, + completionInfo = None, workflowId = None, transactionId = txId, ledgerEffectiveTime = ledgerEffectiveTime, @@ -322,7 +324,7 @@ final class ExecuteUpdateSpec .verify(ledgerDaoMock) .storeTransaction( preparedInsert = eqTo(mockedPreparedInsert), - submitterInfo = eqTo(Option.empty[state.SubmitterInfo]), + completionInfo = eqTo(None), transactionId = eqTo(txId), recordTime = eqTo(ledgerEffectiveTime), ledgerEffectiveTime = eqTo(ledgerEffectiveTime), @@ -346,33 +348,4 @@ final class ExecuteUpdateSpec } } } - - private def transactionAccepted( - submitterInfo: Option[state.SubmitterInfo], - workflowId: Option[Ref.WorkflowId], - transactionId: Ref.TransactionId, - ledgerEffectiveTime: Instant, - transaction: CommittedTransaction, - divulgedContracts: List[state.DivulgedContract], - blindingInfo: Option[BlindingInfo], - ): state.Update.TransactionAccepted = { - val ledgerTimestamp = Time.Timestamp(ledgerEffectiveTime.toEpochMilli) - state.Update.TransactionAccepted( - optSubmitterInfo = submitterInfo, - transactionMeta = state.TransactionMeta( - ledgerEffectiveTime = ledgerTimestamp, - workflowId = workflowId, - submissionTime = ledgerTimestamp, - submissionSeed = crypto.Hash.hashPrivateKey("dummy"), - optUsedPackages = None, - optNodeSeeds = None, - optByKeyNodes = None, - ), - transaction = transaction, - transactionId = transactionId, - recordTime = ledgerTimestamp, - divulgedContracts = divulgedContracts, - blindingInfo = blindingInfo, - ) - } } diff --git a/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/JdbcIndexerSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/JdbcIndexerSpec.scala index 490947031fed..3b3a0dc62601 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/JdbcIndexerSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/JdbcIndexerSpec.scala @@ -12,7 +12,7 @@ import com.codahale.metrics.MetricRegistry import com.daml.ledger.api.testing.utils.AkkaBeforeAndAfterAll import com.daml.ledger.configuration.{Configuration, LedgerInitialConditions, LedgerTimeModel} import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.{ResourceOwner, TestResourceContext} import com.daml.lf.data.Time.Timestamp import com.daml.lf.data.{Bytes, Ref} @@ -48,7 +48,7 @@ final class JdbcIndexerSpec updates: Seq[(Offset, state.Update)] = Seq.empty ): state.ReadService = { val readService = mock[state.ReadService] - when(readService.getLedgerInitialConditions()) + when(readService.ledgerInitialConditions()) .thenAnswer( Source.single( LedgerInitialConditions( diff --git a/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/parallel/ParallelIndexerFactorySpec.scala b/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/parallel/ParallelIndexerFactorySpec.scala index f7b9ec658c3e..6c653720b5f2 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/parallel/ParallelIndexerFactorySpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/platform/indexer/parallel/ParallelIndexerFactorySpec.scala @@ -7,7 +7,7 @@ import java.time.Instant import com.codahale.metrics.MetricRegistry import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref import com.daml.lf.data.Time.Timestamp import com.daml.logging.LoggingContext diff --git a/ledger/participant-integration-api/src/test/suite/scala/platform/store/ConversionsSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/platform/store/ConversionsSpec.scala index d8a8ae46fd36..cb7be742c85b 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/platform/store/ConversionsSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/platform/store/ConversionsSpec.scala @@ -4,8 +4,8 @@ package com.daml.platform.store import com.daml.ledger.api.domain -import com.daml.ledger.participant.state.{v1 => state} import com.daml.platform.store.Conversions._ +import io.grpc.Status import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AsyncWordSpec @@ -14,37 +14,43 @@ class ConversionsSpec extends AsyncWordSpec with Matchers { "convert an 'Inconsistent' rejection reason" in { val reason = domain.RejectionReason.Inconsistent("This was not very consistent.") val converted = reason.toParticipantStateRejectionReason - converted should be(state.RejectionReasonV0.Inconsistent("This was not very consistent.")) + converted.code should be(Status.Code.ABORTED.value()) + converted.message should be("Inconsistent: This was not very consistent.") } "convert an 'Disputed' rejection reason" in { val reason = domain.RejectionReason.Disputed("I dispute that.") val converted = reason.toParticipantStateRejectionReason - converted should be(state.RejectionReasonV0.Disputed("I dispute that.")) + converted.code should be(Status.Code.INVALID_ARGUMENT.value()) + converted.message should be("Disputed: I dispute that.") } "convert an 'OutOfQuota' rejection reason" in { val reason = domain.RejectionReason.OutOfQuota("Insert coins to continue.") val converted = reason.toParticipantStateRejectionReason - converted should be(state.RejectionReasonV0.ResourcesExhausted("Insert coins to continue.")) + converted.code should be(Status.Code.ABORTED.value()) + converted.message should be("Resources exhausted: Insert coins to continue.") } "convert an 'PartyNotKnownOnLedger' rejection reason" in { val reason = domain.RejectionReason.PartyNotKnownOnLedger("Who on earth is Alice?") val converted = reason.toParticipantStateRejectionReason - converted should be(state.RejectionReasonV0.PartyNotKnownOnLedger("Who on earth is Alice?")) + converted.code should be(Status.Code.INVALID_ARGUMENT.value()) + converted.message should be("Party not known on ledger: Who on earth is Alice?") } "convert an 'SubmitterCannotActViaParticipant' rejection reason" in { val reason = domain.RejectionReason.SubmitterCannotActViaParticipant("Wrong box.") val converted = reason.toParticipantStateRejectionReason - converted should be(state.RejectionReasonV0.SubmitterCannotActViaParticipant("Wrong box.")) + converted.code should be(Status.Code.PERMISSION_DENIED.value()) + converted.message should be("Submitted cannot act via participant: Wrong box.") } "convert an 'InvalidLedgerTime' rejection reason" in { val reason = domain.RejectionReason.InvalidLedgerTime("Too late.") val converted = reason.toParticipantStateRejectionReason - converted should be(state.RejectionReasonV0.InvalidLedgerTime("Too late.")) + converted.code should be(Status.Code.ABORTED.value()) + converted.message should be("Invalid ledger time: Too late.") } } } diff --git a/ledger/participant-integration-api/src/test/suite/scala/platform/store/appendonlydao/SequentialWriteDaoSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/platform/store/appendonlydao/SequentialWriteDaoSpec.scala index d9f478c74c35..7c16166eb352 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/platform/store/appendonlydao/SequentialWriteDaoSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/platform/store/appendonlydao/SequentialWriteDaoSpec.scala @@ -8,7 +8,7 @@ import java.time.Instant import com.daml.ledger.api.domain.{LedgerId, ParticipantId} import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref import com.daml.lf.data.Time.Timestamp import com.daml.platform.store.appendonlydao.SequentialWriteDaoSpec._ diff --git a/ledger/participant-integration-api/src/test/suite/scala/platform/store/backend/UpdateToDbDtoSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/platform/store/backend/UpdateToDbDtoSpec.scala index b88997b9bad6..9edeb5afa20f 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/platform/store/backend/UpdateToDbDtoSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/platform/store/backend/UpdateToDbDtoSpec.scala @@ -3,14 +3,14 @@ package com.daml.platform.store.backend -import java.time.{Duration, Instant} +import java.time.Duration import com.daml.daml_lf_dev.DamlLf import com.daml.ledger.api.domain import com.daml.ledger.api.v1.event.{CreatedEvent, ExercisedEvent} import com.daml.ledger.configuration.{Configuration, LedgerTimeModel} import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.crypto import com.daml.lf.data.{Ref, Time} import com.daml.lf.ledger.EventId @@ -31,6 +31,8 @@ import com.daml.platform.store.appendonlydao.events.{ } import com.daml.platform.store.dao.DeduplicationKeyMaker import com.google.protobuf.ByteString +import com.google.rpc.status.{Status => RpcStatus} +import io.grpc.Status import org.scalactic.TripleEquals._ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec @@ -38,6 +40,7 @@ import org.scalatest.wordspec.AnyWordSpec import scala.concurrent.{ExecutionContext, Future} class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { + import UpdateToDbDtoSpec._ "UpdateToDbDto" should { @@ -248,16 +251,19 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { } "handle CommandRejected" in { - val submitterInfo = state.SubmitterInfo( + val completionInfo = state.CompletionInfo( actAs = List(someParty), - someApplicationId, - someCommandId, - Instant.EPOCH, + applicationId = someApplicationId, + commandId = someCommandId, + optDeduplicationPeriod = None, + submissionId = someSubmissionId, ) val update = state.Update.CommandRejected( someRecordTime, - submitterInfo, - state.RejectionReasonV0.Inconsistent("test reason"), + completionInfo, + new state.Update.CommandRejected.FinalReason( + RpcStatus.of(Status.Code.ABORTED.value(), "test reason", Seq.empty) + ), ) val dtos = UpdateToDbDto(someParticipantId, valueSerialization, compressionStrategy)( someOffset @@ -267,24 +273,24 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { DbDto.CommandCompletion( completion_offset = someOffset.toHexString, record_time = someRecordTime.toInstant, - application_id = submitterInfo.applicationId, - submitters = submitterInfo.actAs.toSet, - command_id = submitterInfo.commandId, + application_id = someApplicationId, + submitters = Set(someParty), + command_id = someCommandId, transaction_id = None, - status_code = Some(update.reason.code.value()), - status_message = Some(update.reason.description), + status_code = Some(Status.Code.ABORTED.value()), + status_message = Some("test reason"), ), DbDto.CommandDeduplication( DeduplicationKeyMaker.make( - domain.CommandId(submitterInfo.commandId), - submitterInfo.actAs, + domain.CommandId(completionInfo.commandId), + completionInfo.actAs, ) ), ) } "handle TransactionAccepted (single create node)" in { - val submitterInfo = someSubmitterInfo + val completionInfo = someCompletionInfo val transactionMeta = someTransactionMeta val builder = new TransactionBuilder() val createNode = builder.create( @@ -298,7 +304,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { val createNodeId = builder.add(createNode) val transaction = builder.buildCommitted() val update = state.Update.TransactionAccepted( - optSubmitterInfo = Some(submitterInfo), + optCompletionInfo = Some(completionInfo), transactionMeta = transactionMeta, transaction = transaction, transactionId = Ref.TransactionId.assertFromString("TransactionId"), @@ -315,10 +321,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { event_offset = Some(someOffset.toHexString), transaction_id = Some(update.transactionId), ledger_effective_time = Some(transactionMeta.ledgerEffectiveTime.toInstant), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), node_index = Some(createNodeId.index), event_id = Some(EventId(update.transactionId, createNodeId).toLedgerString), contract_id = createNode.coid.coid, @@ -338,9 +344,9 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { DbDto.CommandCompletion( completion_offset = someOffset.toHexString, record_time = update.recordTime.toInstant, - application_id = submitterInfo.applicationId, - submitters = submitterInfo.actAs.toSet, - command_id = submitterInfo.commandId, + application_id = completionInfo.applicationId, + submitters = completionInfo.actAs.toSet, + command_id = completionInfo.commandId, transaction_id = Some(update.transactionId), status_code = None, status_message = None, @@ -349,7 +355,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { } "handle TransactionAccepted (single create node with agreement text)" in { - val submitterInfo = someSubmitterInfo + val completionInfo = someCompletionInfo val transactionMeta = someTransactionMeta val builder = new TransactionBuilder() val createNode = builder @@ -365,7 +371,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { val createNodeId = builder.add(createNode) val transaction = builder.buildCommitted() val update = state.Update.TransactionAccepted( - optSubmitterInfo = Some(submitterInfo), + optCompletionInfo = Some(completionInfo), transactionMeta = transactionMeta, transaction = transaction, transactionId = Ref.TransactionId.assertFromString("TransactionId"), @@ -382,10 +388,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { event_offset = Some(someOffset.toHexString), transaction_id = Some(update.transactionId), ledger_effective_time = Some(transactionMeta.ledgerEffectiveTime.toInstant), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), node_index = Some(createNodeId.index), event_id = Some(EventId(update.transactionId, createNodeId).toLedgerString), contract_id = createNode.coid.coid, @@ -405,9 +411,9 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { DbDto.CommandCompletion( completion_offset = someOffset.toHexString, record_time = update.recordTime.toInstant, - application_id = submitterInfo.applicationId, - submitters = submitterInfo.actAs.toSet, - command_id = submitterInfo.commandId, + application_id = completionInfo.applicationId, + submitters = completionInfo.actAs.toSet, + command_id = completionInfo.commandId, transaction_id = Some(update.transactionId), status_code = None, status_message = None, @@ -416,7 +422,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { } "handle TransactionAccepted (single consuming exercise node)" in { - val submitterInfo = someSubmitterInfo + val completionInfo = someCompletionInfo val transactionMeta = someTransactionMeta val builder = new TransactionBuilder() val exerciseNode = { @@ -442,7 +448,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { val exerciseNodeId = builder.add(exerciseNode) val transaction = builder.buildCommitted() val update = state.Update.TransactionAccepted( - optSubmitterInfo = Some(submitterInfo), + optCompletionInfo = Some(completionInfo), transactionMeta = transactionMeta, transaction = transaction, transactionId = Ref.TransactionId.assertFromString("TransactionId"), @@ -460,10 +466,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { event_offset = Some(someOffset.toHexString), transaction_id = Some(update.transactionId), ledger_effective_time = Some(transactionMeta.ledgerEffectiveTime.toInstant), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), node_index = Some(exerciseNodeId.index), event_id = Some(EventId(update.transactionId, exerciseNodeId).toLedgerString), contract_id = exerciseNode.targetCoid.coid, @@ -484,9 +490,9 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { DbDto.CommandCompletion( completion_offset = someOffset.toHexString, record_time = update.recordTime.toInstant, - application_id = submitterInfo.applicationId, - submitters = submitterInfo.actAs.toSet, - command_id = submitterInfo.commandId, + application_id = completionInfo.applicationId, + submitters = completionInfo.actAs.toSet, + command_id = completionInfo.commandId, transaction_id = Some(update.transactionId), status_code = None, status_message = None, @@ -495,7 +501,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { } "handle TransactionAccepted (single non-consuming exercise node)" in { - val submitterInfo = someSubmitterInfo + val completionInfo = someCompletionInfo val transactionMeta = someTransactionMeta val builder = new TransactionBuilder() val exerciseNode = { @@ -521,7 +527,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { val exerciseNodeId = builder.add(exerciseNode) val transaction = builder.buildCommitted() val update = state.Update.TransactionAccepted( - optSubmitterInfo = Some(submitterInfo), + optCompletionInfo = Some(completionInfo), transactionMeta = transactionMeta, transaction = transaction, transactionId = Ref.TransactionId.assertFromString("TransactionId"), @@ -539,10 +545,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { event_offset = Some(someOffset.toHexString), transaction_id = Some(update.transactionId), ledger_effective_time = Some(transactionMeta.ledgerEffectiveTime.toInstant), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), node_index = Some(exerciseNodeId.index), event_id = Some(EventId(update.transactionId, exerciseNodeId).toLedgerString), contract_id = exerciseNode.targetCoid.coid, @@ -563,9 +569,9 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { DbDto.CommandCompletion( completion_offset = someOffset.toHexString, record_time = update.recordTime.toInstant, - application_id = submitterInfo.applicationId, - submitters = submitterInfo.actAs.toSet, - command_id = submitterInfo.commandId, + application_id = completionInfo.applicationId, + submitters = completionInfo.actAs.toSet, + command_id = completionInfo.commandId, transaction_id = Some(update.transactionId), status_code = None, status_message = None, @@ -580,7 +586,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { // └─ #2 Exercise (choice A) // ├─ #3 Exercise (choice B) // └─ #4 Exercise (choice C) - val submitterInfo = someSubmitterInfo + val completionInfo = someCompletionInfo val transactionMeta = someTransactionMeta val builder = new TransactionBuilder() val createNode = builder.create( @@ -626,7 +632,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { val exerciseNodeCId = builder.add(exerciseNodeC, exerciseNodeAId) val transaction = builder.buildCommitted() val update = state.Update.TransactionAccepted( - optSubmitterInfo = Some(submitterInfo), + optCompletionInfo = Some(completionInfo), transactionMeta = transactionMeta, transaction = transaction, transactionId = Ref.TransactionId.assertFromString("TransactionId"), @@ -644,10 +650,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { event_offset = Some(someOffset.toHexString), transaction_id = Some(update.transactionId), ledger_effective_time = Some(transactionMeta.ledgerEffectiveTime.toInstant), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), node_index = Some(exerciseNodeAId.index), event_id = Some(EventId(update.transactionId, exerciseNodeAId).toLedgerString), contract_id = exerciseNodeA.targetCoid.coid, @@ -675,10 +681,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { event_offset = Some(someOffset.toHexString), transaction_id = Some(update.transactionId), ledger_effective_time = Some(transactionMeta.ledgerEffectiveTime.toInstant), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), node_index = Some(exerciseNodeBId.index), event_id = Some(EventId(update.transactionId, exerciseNodeBId).toLedgerString), contract_id = exerciseNodeB.targetCoid.coid, @@ -701,10 +707,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { event_offset = Some(someOffset.toHexString), transaction_id = Some(update.transactionId), ledger_effective_time = Some(transactionMeta.ledgerEffectiveTime.toInstant), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), node_index = Some(exerciseNodeCId.index), event_id = Some(EventId(update.transactionId, exerciseNodeCId).toLedgerString), contract_id = exerciseNodeC.targetCoid.coid, @@ -725,9 +731,9 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { DbDto.CommandCompletion( completion_offset = someOffset.toHexString, record_time = update.recordTime.toInstant, - application_id = submitterInfo.applicationId, - submitters = submitterInfo.actAs.toSet, - command_id = submitterInfo.commandId, + application_id = completionInfo.applicationId, + submitters = completionInfo.actAs.toSet, + command_id = completionInfo.commandId, transaction_id = Some(update.transactionId), status_code = None, status_message = None, @@ -740,7 +746,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { // └─ #1 Create // Transaction // └─ #2 Exercise (divulges #1 to 'divulgee') - val submitterInfo = someSubmitterInfo + val completionInfo = someCompletionInfo val transactionMeta = someTransactionMeta val builder = new TransactionBuilder() val createNode = builder.create( @@ -764,7 +770,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { val exerciseNodeId = builder.add(exerciseNode) val transaction = builder.buildCommitted() val update = state.Update.TransactionAccepted( - optSubmitterInfo = Some(submitterInfo), + optCompletionInfo = Some(completionInfo), transactionMeta = transactionMeta, transaction = transaction, transactionId = Ref.TransactionId.assertFromString("TransactionId"), @@ -782,10 +788,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { event_offset = Some(someOffset.toHexString), transaction_id = Some(update.transactionId), ledger_effective_time = Some(transactionMeta.ledgerEffectiveTime.toInstant), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), node_index = Some(exerciseNodeId.index), event_id = Some(EventId(update.transactionId, exerciseNodeId).toLedgerString), contract_id = exerciseNode.targetCoid.coid, @@ -805,10 +811,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { ), DbDto.EventDivulgence( event_offset = Some(someOffset.toHexString), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), contract_id = exerciseNode.targetCoid.coid, template_id = None, // No contract details stored. That's ok because the participant sees the create event. @@ -821,9 +827,9 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { DbDto.CommandCompletion( completion_offset = someOffset.toHexString, record_time = update.recordTime.toInstant, - application_id = submitterInfo.applicationId, - submitters = submitterInfo.actAs.toSet, - command_id = submitterInfo.commandId, + application_id = completionInfo.applicationId, + submitters = completionInfo.actAs.toSet, + command_id = completionInfo.commandId, transaction_id = Some(update.transactionId), status_code = None, status_message = None, @@ -835,7 +841,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { // Transaction // ├─ #1 Create // └─ #2 Exercise (divulges #1 to 'divulgee') - val submitterInfo = someSubmitterInfo + val completionInfo = someCompletionInfo val transactionMeta = someTransactionMeta val builder = new TransactionBuilder() val createNode = builder.create( @@ -860,7 +866,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { val exerciseNodeId = builder.add(exerciseNode) val transaction = builder.buildCommitted() val update = state.Update.TransactionAccepted( - optSubmitterInfo = Some(submitterInfo), + optCompletionInfo = Some(completionInfo), transactionMeta = transactionMeta, transaction = transaction, transactionId = Ref.TransactionId.assertFromString("TransactionId"), @@ -877,10 +883,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { event_offset = Some(someOffset.toHexString), transaction_id = Some(update.transactionId), ledger_effective_time = Some(transactionMeta.ledgerEffectiveTime.toInstant), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), node_index = Some(createNodeId.index), event_id = Some(EventId(update.transactionId, createNodeId).toLedgerString), contract_id = createNode.coid.coid, @@ -902,10 +908,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { event_offset = Some(someOffset.toHexString), transaction_id = Some(update.transactionId), ledger_effective_time = Some(transactionMeta.ledgerEffectiveTime.toInstant), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), node_index = Some(exerciseNodeId.index), event_id = Some(EventId(update.transactionId, exerciseNodeId).toLedgerString), contract_id = exerciseNode.targetCoid.coid, @@ -925,10 +931,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { ), DbDto.EventDivulgence( event_offset = Some(someOffset.toHexString), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), contract_id = exerciseNode.targetCoid.coid, template_id = None, // No contract details stored. That's ok because the participant sees the create event. @@ -941,9 +947,9 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { DbDto.CommandCompletion( completion_offset = someOffset.toHexString, record_time = update.recordTime.toInstant, - application_id = submitterInfo.applicationId, - submitters = submitterInfo.actAs.toSet, - command_id = submitterInfo.commandId, + application_id = completionInfo.applicationId, + submitters = completionInfo.actAs.toSet, + command_id = completionInfo.commandId, transaction_id = Some(update.transactionId), status_code = None, status_message = None, @@ -952,7 +958,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { } "handle TransactionAccepted (explicit blinding info)" in { - val submitterInfo = someSubmitterInfo + val completionInfo = someCompletionInfo val transactionMeta = someTransactionMeta val builder = new TransactionBuilder() val createNode = builder.create( @@ -976,7 +982,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { val exerciseNodeId = builder.add(exerciseNode) val transaction = builder.buildCommitted() val update = state.Update.TransactionAccepted( - optSubmitterInfo = Some(submitterInfo), + optCompletionInfo = Some(completionInfo), transactionMeta = transactionMeta, transaction = transaction, transactionId = Ref.TransactionId.assertFromString("TransactionId"), @@ -1000,10 +1006,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { event_offset = Some(someOffset.toHexString), transaction_id = Some(update.transactionId), ledger_effective_time = Some(transactionMeta.ledgerEffectiveTime.toInstant), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), node_index = Some(exerciseNodeId.index), event_id = Some(EventId(update.transactionId, exerciseNodeId).toLedgerString), contract_id = exerciseNode.targetCoid.coid, @@ -1023,10 +1029,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { ), DbDto.EventDivulgence( event_offset = Some(someOffset.toHexString), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), contract_id = exerciseNode.targetCoid.coid, template_id = Some(createNode.templateId.toString), // taken from explicit divulgedContracts @@ -1038,9 +1044,9 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { DbDto.CommandCompletion( completion_offset = someOffset.toHexString, record_time = update.recordTime.toInstant, - application_id = submitterInfo.applicationId, - submitters = submitterInfo.actAs.toSet, - command_id = submitterInfo.commandId, + application_id = completionInfo.applicationId, + submitters = completionInfo.actAs.toSet, + command_id = completionInfo.commandId, transaction_id = Some(update.transactionId), status_code = None, status_message = None, @@ -1055,7 +1061,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { // └─ #3 Exercise (divulges #2 to divulgee) // - Create and Exercise events must not be visible // - Divulgence events from rolled back Exercise/Fetch nodes must be visible - val submitterInfo = someSubmitterInfo + val completionInfo = someCompletionInfo val transactionMeta = someTransactionMeta val builder = new TransactionBuilder() val rollbackNode = builder.rollback() @@ -1082,7 +1088,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { builder.add(exerciseNode, rollbackNodeId) val transaction = builder.buildCommitted() val update = state.Update.TransactionAccepted( - optSubmitterInfo = Some(submitterInfo), + optCompletionInfo = Some(completionInfo), transactionMeta = transactionMeta, transaction = transaction, transactionId = Ref.TransactionId.assertFromString("TransactionId"), @@ -1098,10 +1104,10 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { // TODO append-only: Why is there a divulgence event? The divulged contract doesn't exist because it was rolled back. DbDto.EventDivulgence( event_offset = Some(someOffset.toHexString), - command_id = Some(submitterInfo.commandId), + command_id = Some(completionInfo.commandId), workflow_id = transactionMeta.workflowId, - application_id = Some(submitterInfo.applicationId), - submitters = Some(submitterInfo.actAs.toSet), + application_id = Some(completionInfo.applicationId), + submitters = Some(completionInfo.actAs.toSet), contract_id = exerciseNode.targetCoid.coid, template_id = None, tree_event_witnesses = Set("divulgee"), @@ -1112,9 +1118,9 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { DbDto.CommandCompletion( completion_offset = someOffset.toHexString, record_time = update.recordTime.toInstant, - application_id = submitterInfo.applicationId, - submitters = submitterInfo.actAs.toSet, - command_id = submitterInfo.commandId, + application_id = completionInfo.applicationId, + submitters = completionInfo.actAs.toSet, + command_id = completionInfo.commandId, transaction_id = Some(update.transactionId), status_code = None, status_message = None, @@ -1138,7 +1144,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { val createNodeId = builder.add(createNode) val transaction = builder.buildCommitted() val update = state.Update.TransactionAccepted( - optSubmitterInfo = None, + optCompletionInfo = None, transactionMeta = transactionMeta, transaction = transaction, transactionId = Ref.TransactionId.assertFromString("TransactionId"), @@ -1248,11 +1254,12 @@ object UpdateToDbDtoSpec { .setHashFunction(DamlLf.HashFunction.SHA256) .setPayload(ByteString.copyFromUtf8("payload 2 (longer than the other payload)")) .build - private val someSubmitterInfo = state.SubmitterInfo( + private val someCompletionInfo = state.CompletionInfo( actAs = List(someParty), - someApplicationId, - someCommandId, - Instant.ofEpochMilli(1), + applicationId = someApplicationId, + commandId = someCommandId, + optDeduplicationPeriod = None, + submissionId = someSubmissionId, ) private val someTransactionMeta = state.TransactionMeta( ledgerEffectiveTime = Time.Timestamp.assertFromLong(2), diff --git a/ledger/participant-integration-api/src/test/suite/scala/platform/store/dao/events/TransactionIndexingSpec.scala b/ledger/participant-integration-api/src/test/suite/scala/platform/store/dao/events/TransactionIndexingSpec.scala index 7798c953226f..d4e71ea04a70 100644 --- a/ledger/participant-integration-api/src/test/suite/scala/platform/store/dao/events/TransactionIndexingSpec.scala +++ b/ledger/participant-integration-api/src/test/suite/scala/platform/store/dao/events/TransactionIndexingSpec.scala @@ -15,9 +15,9 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec final class TransactionIndexingSpec extends AnyWordSpec with Matchers { - val anOffset = Offset.fromByteArray(Array.emptyByteArray) - val aTransactionId = Ref.TransactionId.assertFromString("0") - val anInstant = Instant.EPOCH + private val anOffset = Offset.fromByteArray(Array.emptyByteArray) + private val aTransactionId = Ref.TransactionId.assertFromString("0") + private val anInstant = Instant.EPOCH "TransactionIndexing" should { "apply blindingInfo divulgence upon construction" in { @@ -30,7 +30,7 @@ final class TransactionIndexingSpec extends AnyWordSpec with Matchers { TransactionIndexing .from( blindingInfo = BlindingInfo(Map.empty, aDivulgence), - submitterInfo = None, + completionInfo = None, workflowId = None, aTransactionId, anInstant, @@ -104,7 +104,7 @@ final class TransactionIndexingSpec extends AnyWordSpec with Matchers { val result = TransactionIndexing .from( blindingInfo = blindingInfo, - submitterInfo = None, + completionInfo = None, workflowId = None, aTransactionId, anInstant, diff --git a/ledger/participant-state/BUILD.bazel b/ledger/participant-state/BUILD.bazel index f93b5c85260a..7ca31b133fe1 100644 --- a/ledger/participant-state/BUILD.bazel +++ b/ledger/participant-state/BUILD.bazel @@ -34,6 +34,7 @@ da_scala_library( "//ledger/ledger-configuration/protobuf:ledger_configuration_proto_java", "//ledger/ledger-offset", "//ledger/metrics", + "//libs-scala/logging-entries", "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/ledger/participant-state/kvutils/app/src/main/scala/com/daml/ledger/participant/state/kvutils/app/Runner.scala b/ledger/participant-state/kvutils/app/src/main/scala/com/daml/ledger/participant/state/kvutils/app/Runner.scala index 33afb7bfd50c..2f537f4be3e4 100644 --- a/ledger/participant-state/kvutils/app/src/main/scala/com/daml/ledger/participant/state/kvutils/app/Runner.scala +++ b/ledger/participant-state/kvutils/app/src/main/scala/com/daml/ledger/participant/state/kvutils/app/Runner.scala @@ -11,12 +11,16 @@ import akka.actor.ActorSystem import akka.stream.Materializer import com.codahale.metrics.InstrumentedExecutorService import com.daml.ledger.api.health.HealthChecks -import com.daml.ledger.participant.state.v1.WritePackagesService -import com.daml.ledger.participant.state.v1.metrics.{TimedReadService, TimedWriteService} +import com.daml.ledger.participant.state.v2.metrics.{TimedReadService, TimedWriteService} +import com.daml.ledger.participant.state.v2.{ + AdaptedV1ReadService, + AdaptedV1WriteService, + WritePackagesService, +} import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner} import com.daml.lf.archive.DarParser import com.daml.lf.data.Ref -import com.daml.lf.engine._ +import com.daml.lf.engine.{Engine, EngineConfig} import com.daml.logging.LoggingContext.newLoggingContext import com.daml.logging.{ContextualizedLogger, LoggingContext} import com.daml.metrics.JvmMetricSet @@ -110,8 +114,8 @@ final class Runner[T <: ReadWriteService, Extra]( ledger <- factory .readWriteServiceOwner(config, participantConfig, sharedEngine) .acquire() - readService = new TimedReadService(ledger, metrics) - writeService = new TimedWriteService(ledger, metrics) + readService = new TimedReadService(new AdaptedV1ReadService(ledger), metrics) + writeService = new TimedWriteService(new AdaptedV1WriteService(ledger), metrics) healthChecks = new HealthChecks( "read" -> readService, "write" -> writeService, diff --git a/ledger/participant-state/kvutils/tools/src/main/scala/ledger/participant/state/kvutils/tools/integritycheck/IntegrityChecker.scala b/ledger/participant-state/kvutils/tools/src/main/scala/ledger/participant/state/kvutils/tools/integritycheck/IntegrityChecker.scala index 5cecd2fdb085..eed3fc91c0e8 100644 --- a/ledger/participant-state/kvutils/tools/src/main/scala/ledger/participant/state/kvutils/tools/integritycheck/IntegrityChecker.scala +++ b/ledger/participant-state/kvutils/tools/src/main/scala/ledger/participant/state/kvutils/tools/integritycheck/IntegrityChecker.scala @@ -15,7 +15,7 @@ import com.daml.ledger.participant.state.kvutils.export.{ LedgerDataImporter, ProtobufBasedLedgerDataImporter, } -import com.daml.ledger.participant.state.v1.ReadService +import com.daml.ledger.participant.state.v2.{AdaptedV1ReadService, ReadService} import com.daml.ledger.resources.{ResourceContext, ResourceOwner} import com.daml.lf.data.Ref import com.daml.logging.LoggingContext @@ -104,7 +104,7 @@ class IntegrityChecker[LogResult]( _ <- indexStateUpdates( config = config, metrics = metrics, - readService = + replayingReadService = if (config.indexOnly) expectedReadServiceFactory.createReadService else @@ -124,12 +124,13 @@ class IntegrityChecker[LogResult]( private def indexStateUpdates( config: Config, metrics: Metrics, - readService: ReplayingReadService, + replayingReadService: ReplayingReadService, )(implicit materializer: Materializer, executionContext: ExecutionContext): Future[Unit] = { implicit val resourceContext: ResourceContext = ResourceContext(executionContext) + val readService = new AdaptedV1ReadService(replayingReadService) // Start the indexer consuming the recorded state updates - println(s"Starting to index ${readService.updateCount()} updates.".white) + println(s"Starting to index ${replayingReadService.updateCount()} updates.".white) newLoggingContext { implicit loggingContext => val feedHandleResourceOwner = for { indexer <- migrateAndStartIndexer( @@ -158,7 +159,7 @@ class IntegrityChecker[LogResult]( .fromNanos(System.nanoTime() - startTime) .toMillis .toDouble / 1000.0 - val updatesPerSecond = readService.updateCount() / durationSeconds + val updatesPerSecond = replayingReadService.updateCount() / durationSeconds println() println(s"Indexing duration: $durationSeconds seconds ($updatesPerSecond updates/second)") } diff --git a/ledger/participant-state/kvutils/tools/src/main/scala/ledger/participant/state/kvutils/tools/integritycheck/ReplayingReadService.scala b/ledger/participant-state/kvutils/tools/src/main/scala/ledger/participant/state/kvutils/tools/integritycheck/ReplayingReadService.scala index 903058a2a562..0a5392cf8c85 100644 --- a/ledger/participant-state/kvutils/tools/src/main/scala/ledger/participant/state/kvutils/tools/integritycheck/ReplayingReadService.scala +++ b/ledger/participant-state/kvutils/tools/src/main/scala/ledger/participant/state/kvutils/tools/integritycheck/ReplayingReadService.scala @@ -4,7 +4,7 @@ package com.daml.ledger.participant.state.kvutils.tools.integritycheck import akka.stream.Materializer -import com.daml.ledger.participant.state.kvutils.`export`.WriteSet +import com.daml.ledger.participant.state.kvutils.export.WriteSet import com.daml.ledger.participant.state.v1.ReadService /** A ReadService that streams back previously recorded state updates */ diff --git a/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/ChangeId.scala b/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/ChangeId.scala new file mode 100644 index 000000000000..b2feb9453c6b --- /dev/null +++ b/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/ChangeId.scala @@ -0,0 +1,16 @@ +// Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.daml.ledger.participant.state.v2 + +import com.daml.lf.data.Ref + +/** Identifier for ledger changes used by command deduplication + * + * @see ReadService.stateUpdates for the command deduplication guarantee + */ +final case class ChangeId( + private val applicationId: Ref.ApplicationId, + private val commandId: Ref.CommandId, + private val actAs: Set[Ref.Party], +) diff --git a/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/DeduplicationPeriod.scala b/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/DeduplicationPeriod.scala index 20c1c70eca17..a81359e1f4a4 100644 --- a/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/DeduplicationPeriod.scala +++ b/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/DeduplicationPeriod.scala @@ -6,6 +6,7 @@ package com.daml.ledger.participant.state.v2 import java.time.Duration import com.daml.ledger.offset.Offset +import com.daml.logging.entries.{LoggingValue, ToLoggingValue} /** Specifies the deduplication period for a command submission. * Note that we would like to keep this easily extensible to support offsets and absolute @@ -31,4 +32,11 @@ object DeduplicationPeriod { /** The `offset` defines the start of the deduplication period. */ final case class DeduplicationOffset(offset: Offset) extends DeduplicationPeriod + + implicit val `DeduplicationPeriod to LoggingValue`: ToLoggingValue[DeduplicationPeriod] = { + case DeduplicationDuration(duration) => + LoggingValue.Nested.fromEntries("duration" -> duration) + case DeduplicationOffset(offset) => + LoggingValue.Nested.fromEntries("offset" -> offset) + } } diff --git a/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/SubmissionResult.scala b/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/SubmissionResult.scala index 97a9e72c08f4..1c031f0dab23 100644 --- a/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/SubmissionResult.scala +++ b/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/SubmissionResult.scala @@ -3,6 +3,8 @@ package com.daml.ledger.participant.state.v2 +import io.grpc.{Status, StatusRuntimeException} + sealed abstract class SubmissionResult extends Product with Serializable { def description: String } @@ -23,5 +25,9 @@ object SubmissionResult { final case class SynchronousError(grpcError: com.google.rpc.status.Status) extends SubmissionResult { override val description: String = s"Submission failed with error ${grpcError.message}" + + def status: Status = Status.fromCodeValue(grpcError.code).withDescription(grpcError.message) + + def exception: StatusRuntimeException = status.asRuntimeException } } diff --git a/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/SubmitterInfo.scala b/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/SubmitterInfo.scala index 8cff8613892f..70acc2972404 100644 --- a/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/SubmitterInfo.scala +++ b/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/SubmitterInfo.scala @@ -36,14 +36,12 @@ final case class SubmitterInfo( /** The ID for the ledger change */ val changeId: ChangeId = ChangeId(applicationId, commandId, actAs.toSet) -} -/** Identifier for ledger changes used by command deduplication - * - * @see ReadService.stateUpdates for the command deduplication guarantee - */ -final case class ChangeId( - private val applicationId: Ref.ApplicationId, - private val commandId: Ref.CommandId, - private val actAs: Set[Ref.Party], -) + def toCompletionInfo: CompletionInfo = CompletionInfo( + actAs, + applicationId, + commandId, + Some(deduplicationPeriod), + submissionId, + ) +} diff --git a/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/Update.scala b/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/Update.scala index aa171b1e98e1..5e17bc5e8078 100644 --- a/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/Update.scala +++ b/ledger/participant-state/src/main/scala/com/daml/ledger/participant/state/v2/Update.scala @@ -8,6 +8,8 @@ import com.daml.ledger.configuration.Configuration import com.daml.lf.data.Ref import com.daml.lf.data.Time.Timestamp import com.daml.lf.transaction.{BlindingInfo, CommittedTransaction} +import com.daml.logging.entries.{LoggingValue, ToLoggingValue} +import com.google.rpc.status.{Status => RpcStatus} /** An update to the (abstract) participant state. * @@ -222,22 +224,39 @@ object Update { */ sealed trait RejectionReasonTemplate { + /** A human-readable description of the error */ + def message: String + + /** A gRPC status code representing the error. */ + def code: Int + + /** A protobuf gRPC status representing the error. */ + def status: RpcStatus + /** Whether the rejection is a definite answer for the deduplication guarantees * specified for [[ReadService.stateUpdates]]. */ def definiteAnswer: Boolean + } - /** A human-readable description of the error */ - def message: String + object RejectionReasonTemplate { + implicit val `RejectionReasonTemplate to LoggingValue` + : ToLoggingValue[RejectionReasonTemplate] = + reason => + LoggingValue.Nested.fromEntries( + "code" -> reason.code, + "message" -> reason.message, + "definiteAnswer" -> reason.definiteAnswer, + ) } /** The status code for the command rejection. */ - final class FinalReason(val status: com.google.rpc.status.Status) - extends RejectionReasonTemplate { - + final class FinalReason(override val status: RpcStatus) extends RejectionReasonTemplate { override def message: String = status.message - override def definiteAnswer: Boolean = - GrpcStatuses.isDefiniteAnswer(status) + + override def code: Int = status.code + + override def definiteAnswer: Boolean = GrpcStatuses.isDefiniteAnswer(status) } } } diff --git a/ledger/recovering-indexer-integration-tests/src/test/suite/scala/com/digitalasset/platform/indexer/RecoveringIndexerIntegrationSpec.scala b/ledger/recovering-indexer-integration-tests/src/test/suite/scala/com/digitalasset/platform/indexer/RecoveringIndexerIntegrationSpec.scala index 7fa4aaffba1b..18e08e54398c 100644 --- a/ledger/recovering-indexer-integration-tests/src/test/suite/scala/com/digitalasset/platform/indexer/RecoveringIndexerIntegrationSpec.scala +++ b/ledger/recovering-indexer-integration-tests/src/test/suite/scala/com/digitalasset/platform/indexer/RecoveringIndexerIntegrationSpec.scala @@ -18,6 +18,7 @@ import com.daml.ledger.offset.Offset import com.daml.ledger.on.memory import com.daml.ledger.participant.state.kvutils.api.KeyValueParticipantState import com.daml.ledger.participant.state.v1.{ReadService, WriteService} +import com.daml.ledger.participant.state.v2.AdaptedV1ReadService import com.daml.ledger.resources.{ResourceOwner, TestResourceContext} import com.daml.ledger.validator.StateKeySerializationStrategy import com.daml.lf.data.Ref @@ -206,7 +207,7 @@ class RecoveringIndexerIntegrationSpec .map(ExecutionContext.fromExecutorService) participantState <- newParticipantState(ledgerId, participantId)(materializer, loggingContext) _ <- new StandaloneIndexerServer( - readService = participantState, + readService = new AdaptedV1ReadService(participantState), config = IndexerConfig( participantId = participantId, jdbcUrl = jdbcUrl, diff --git a/ledger/sandbox-classic/src/main/scala/platform/sandbox/SandboxServer.scala b/ledger/sandbox-classic/src/main/scala/platform/sandbox/SandboxServer.scala index 17b675cdd93f..aafa53def4a7 100644 --- a/ledger/sandbox-classic/src/main/scala/platform/sandbox/SandboxServer.scala +++ b/ledger/sandbox-classic/src/main/scala/platform/sandbox/SandboxServer.scala @@ -18,7 +18,7 @@ import com.daml.ledger.api.auth.interceptor.AuthorizationInterceptor import com.daml.ledger.api.auth.{AuthService, AuthServiceWildcard, Authorizer} import com.daml.ledger.api.domain.LedgerId import com.daml.ledger.api.health.HealthChecks -import com.daml.ledger.participant.state.v1.metrics.TimedWriteService +import com.daml.ledger.participant.state.v2.metrics.TimedWriteService import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner} import com.daml.lf.data.ImmArray import com.daml.lf.engine.{Engine, EngineConfig} diff --git a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/LedgerBackedWriteService.scala b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/LedgerBackedWriteService.scala index 2a453eca5b2b..dc48fdfe84e7 100644 --- a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/LedgerBackedWriteService.scala +++ b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/LedgerBackedWriteService.scala @@ -10,7 +10,7 @@ import com.daml.daml_lf_dev.DamlLf import com.daml.ledger.api.health.HealthStatus import com.daml.ledger.configuration.Configuration import com.daml.ledger.offset.Offset -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.{Ref, Time} import com.daml.lf.transaction.SubmittedTransaction import com.daml.logging.LoggingContext @@ -37,7 +37,7 @@ private[stores] final class LedgerBackedWriteService(ledger: Ledger, timeProvide "actAs" -> submitterInfo.actAs, "applicationId" -> submitterInfo.applicationId, "commandId" -> submitterInfo.commandId, - "deduplicateUntil" -> submitterInfo.deduplicateUntil, + "deduplicationPeriod" -> submitterInfo.deduplicationPeriod, "submissionTime" -> transactionMeta.submissionTime.toInstant, "workflowId" -> transactionMeta.workflowId, "ledgerTime" -> transactionMeta.ledgerEffectiveTime.toInstant, diff --git a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/SandboxIndexAndWriteService.scala b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/SandboxIndexAndWriteService.scala index babb4c3f9525..d6ea7d85e605 100644 --- a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/SandboxIndexAndWriteService.scala +++ b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/SandboxIndexAndWriteService.scala @@ -10,7 +10,7 @@ import akka.stream.scaladsl.{Sink, Source} import com.daml.api.util.TimeProvider import com.daml.ledger.api.domain import com.daml.ledger.participant.state.index.v2.IndexService -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner} import com.daml.lf.data.{ImmArray, Ref} import com.daml.lf.engine.Engine diff --git a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/Ledger.scala b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/Ledger.scala index 7077138d7de1..653a05caca96 100644 --- a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/Ledger.scala +++ b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/Ledger.scala @@ -7,7 +7,7 @@ import java.time.Instant import com.daml.daml_lf_dev.DamlLf.Archive import com.daml.ledger.configuration.Configuration -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref import com.daml.lf.data.Ref.Party import com.daml.lf.data.Relation.Relation diff --git a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/MeteredLedger.scala b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/MeteredLedger.scala index 2354d883a72c..a761125e3610 100644 --- a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/MeteredLedger.scala +++ b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/MeteredLedger.scala @@ -7,7 +7,7 @@ import java.time.Instant import com.daml.daml_lf_dev.DamlLf.Archive import com.daml.ledger.configuration.Configuration -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.Ref.Party import com.daml.lf.data.{Ref, Time} import com.daml.lf.transaction.SubmittedTransaction diff --git a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/Rejection.scala b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/Rejection.scala index e34d38838653..0fc7ed0eec68 100644 --- a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/Rejection.scala +++ b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/Rejection.scala @@ -5,9 +5,9 @@ package com.daml.platform.sandbox.stores.ledger import com.daml.ledger.api.domain import com.daml.ledger.configuration.LedgerTimeModel -import com.daml.ledger.participant.state.v1 -import com.daml.platform.store.Conversions.RejectionReasonOps +import com.daml.ledger.participant.state.{v1, v2} import io.grpc.Status +import com.google.rpc.status.{Status => RpcStatus} sealed trait Rejection { val reason: String @@ -18,8 +18,12 @@ sealed trait Rejection { def toDomainRejectionReason: domain.RejectionReason - def toStateV1RejectionReason: v1.RejectionReason = - toDomainRejectionReason.toParticipantStateRejectionReason + def toStateV1RejectionReason: v1.RejectionReason + + def toStateV2RejectionReason: v2.Update.CommandRejected.RejectionReasonTemplate = + new v2.Update.CommandRejected.FinalReason( + RpcStatus.of(code.value(), description, Seq.empty) + ) } object Rejection { @@ -33,6 +37,9 @@ object Rejection { override lazy val toDomainRejectionReason: domain.RejectionReason = domain.RejectionReason.InvalidLedgerTime(description) + + override lazy val toStateV1RejectionReason: v1.RejectionReason = + v1.RejectionReasonV0.InvalidLedgerTime(description) } final case class InvalidLedgerTime(outOfRange: LedgerTimeModel.OutOfRange) extends Rejection { @@ -44,5 +51,8 @@ object Rejection { override lazy val toDomainRejectionReason: domain.RejectionReason = domain.RejectionReason.InvalidLedgerTime(description) + + override lazy val toStateV1RejectionReason: v1.RejectionReason = + v1.RejectionReasonV0.InvalidLedgerTime(description) } } diff --git a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/ScenarioLoader.scala b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/ScenarioLoader.scala index 2fc441fc59a2..f16923cd75f7 100644 --- a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/ScenarioLoader.scala +++ b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/ScenarioLoader.scala @@ -181,7 +181,8 @@ private[sandbox] object ScenarioLoader { } } - private val workflowIdPrefix = Ref.LedgerString.assertFromString(s"scenario-workflow-") + private val submissionIdPrefix = Ref.LedgerString.assertFromString("scenario-submission-") + private val workflowIdPrefix = Ref.LedgerString.assertFromString("scenario-workflow-") private val scenarioLoader = Ref.LedgerString.assertFromString("scenario-loader") private def executeScenarioStep( @@ -209,8 +210,9 @@ private[sandbox] object ScenarioLoader { } val transactionId = txId.id - val workflowId = - Some(Ref.LedgerString.assertConcat(workflowIdPrefix, Ref.LedgerString.fromInt(stepId))) + val stepIdString = Ref.LedgerString.fromInt(stepId) + val submissionId = Some(Ref.SubmissionId.assertConcat(submissionIdPrefix, stepIdString)) + val workflowId = Some(Ref.WorkflowId.assertConcat(workflowIdPrefix, stepIdString)) val tx = richTransaction.transaction // copies non-absolute-able node IDs, but IDs that don't match // get intersected away later @@ -233,6 +235,7 @@ private[sandbox] object ScenarioLoader { Some(transactionId), transactionId, Some(scenarioLoader), + submissionId, richTransaction.actAs.toList, workflowId, time.toInstant, diff --git a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/inmemory/InMemoryLedger.scala b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/inmemory/InMemoryLedger.scala index de6754092acc..a88abd9c8de5 100644 --- a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/inmemory/InMemoryLedger.scala +++ b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/inmemory/InMemoryLedger.scala @@ -39,7 +39,7 @@ import com.daml.ledger.participant.state.index.v2.{ CommandDeduplicationResult, PackageDetails, } -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.lf.data.{ImmArray, Ref, Time} import com.daml.lf.language.Ast import com.daml.lf.ledger.EventId @@ -338,6 +338,7 @@ private[sandbox] final class InMemoryLedger( Some(submitterInfo.commandId), transactionId, Some(submitterInfo.applicationId), + Some(submitterInfo.submissionId), submitterInfo.actAs, transactionMeta.workflowId, transactionMeta.ledgerEffectiveTime.toInstant, @@ -364,6 +365,7 @@ private[sandbox] final class InMemoryLedger( timeProvider.getCurrentTime, submitterInfo.commandId, submitterInfo.applicationId, + submitterInfo.submissionId, submitterInfo.actAs, reason, ) diff --git a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/sql/SqlLedger.scala b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/sql/SqlLedger.scala index 9e94f5dc4c25..fffc70d126a6 100644 --- a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/sql/SqlLedger.scala +++ b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/sql/SqlLedger.scala @@ -19,7 +19,7 @@ import com.daml.ledger.api.health.HealthStatus import com.daml.ledger.configuration.Configuration import com.daml.ledger.offset.Offset import com.daml.ledger.participant.state.index.v2.{ContractStore, PackageDetails} -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner} import com.daml.lf.data.{ImmArray, Ref, Time} import com.daml.lf.engine.{Engine, ValueEnricher} @@ -44,6 +44,8 @@ import com.daml.platform.store.dao.{LedgerDao, LedgerWriteDao} import com.daml.platform.store.entries.{LedgerEntry, PackageLedgerEntry, PartyLedgerEntry} import com.daml.platform.store.{BaseLedger, FlywayMigrations, LfValueTranslationCache} import com.daml.resources.ProgramResource.StartupException +import com.google.rpc.status.{Status => RpcStatus} +import io.grpc.Status import scalaz.Tag import scala.collection.immutable.Queue @@ -413,10 +415,10 @@ private final class SqlLedger( .fold( reason => ledgerDao.storeRejection( - Some(submitterInfo), - recordTime, - CurrentOffset(offset), - reason.toStateV1RejectionReason, + completionInfo = Some(submitterInfo.toCompletionInfo), + recordTime = recordTime, + offsetStep = CurrentOffset(offset), + reason = reason.toStateV2RejectionReason, ), _ => { val divulgedContracts = Nil @@ -425,7 +427,7 @@ private final class SqlLedger( val blindingInfo = None ledgerDao.storeTransaction( - submitterInfo = Some(submitterInfo), + completionInfo = Some(submitterInfo.toCompletionInfo), workflowId = transactionMeta.workflowId, transactionId = transactionId, ledgerEffectiveTime = transactionMeta.ledgerEffectiveTime.toInstant, @@ -452,7 +454,15 @@ private final class SqlLedger( case Success(Enqueued) => Success(state.SubmissionResult.Acknowledged) case Success(Dropped) => - Success(state.SubmissionResult.Overloaded) + Success( + state.SubmissionResult.SynchronousError( + RpcStatus.of( + Status.Code.RESOURCE_EXHAUSTED.value(), + "System is overloaded, please try again later", + Seq.empty, + ) + ) + ) case Success(QueueClosed) => Failure(new IllegalStateException("queue closed")) case Success(QueueOfferResult.Failure(e)) => Failure(e) diff --git a/ledger/sandbox-classic/src/test/suite/scala/platform/sandbox/stores/ledger/TransactionTimeModelComplianceIT.scala b/ledger/sandbox-classic/src/test/suite/scala/platform/sandbox/stores/ledger/TransactionTimeModelComplianceIT.scala index fb47f2918128..81dc44bdad7f 100644 --- a/ledger/sandbox-classic/src/test/suite/scala/platform/sandbox/stores/ledger/TransactionTimeModelComplianceIT.scala +++ b/ledger/sandbox-classic/src/test/suite/scala/platform/sandbox/stores/ledger/TransactionTimeModelComplianceIT.scala @@ -17,7 +17,7 @@ import com.daml.ledger.api.testing.utils.{ } import com.daml.ledger.api.v1.completion.Completion import com.daml.ledger.configuration.{Configuration, LedgerTimeModel} -import com.daml.ledger.participant.state.{v1 => state} +import com.daml.ledger.participant.state.{v2 => state} import com.daml.ledger.resources.ResourceContext import com.daml.lf.crypto import com.daml.lf.data.{Ref, Time} @@ -30,6 +30,7 @@ import org.scalatest.time.Span import org.scalatest.wordspec.AsyncWordSpec import org.scalatest.{Assertion, OptionValues} +import scala.concurrent.Future import scala.concurrent.duration._ class TransactionTimeModelComplianceIT @@ -67,31 +68,41 @@ class TransactionTimeModelComplianceIT generation: Long, minSkew: JDuration, maxSkew: JDuration, - ) = { + ): Future[Configuration] = { val config = Configuration( generation = generation, timeModel = LedgerTimeModel(JDuration.ZERO, minSkew, maxSkew).get, maxDeduplicationTime = JDuration.ofSeconds(10), ) - ledger.publishConfiguration( - Time.Timestamp.assertFromInstant(recordTime.plusSeconds(3600)), - UUID.randomUUID().toString, - config, - ) + ledger + .publishConfiguration( + Time.Timestamp.assertFromInstant(recordTime.plusSeconds(3600)), + UUID.randomUUID().toString, + config, + ) + .map(_ => config) } - private[this] def publishTxAt(ledger: Ledger, ledgerTime: Instant, commandId: String) = { + private[this] def publishTxAt( + ledger: Ledger, + ledgerTime: Instant, + commandId: String, + submissionId: String = UUID.randomUUID().toString, + configuration: Configuration, + ) = { val dummyTransaction = TransactionBuilder.EmptySubmitted val submitterInfo = state.SubmitterInfo( actAs = List(Ref.Party.assertFromString("submitter")), - applicationId = Ref.LedgerString.assertFromString("appId"), - commandId = Ref.LedgerString.assertFromString(commandId + UUID.randomUUID().toString), - deduplicateUntil = Instant.EPOCH, + applicationId = Ref.ApplicationId.assertFromString("appId"), + commandId = Ref.CommandId.assertFromString(commandId + UUID.randomUUID().toString), + deduplicationPeriod = state.DeduplicationPeriod.DeduplicationDuration(JDuration.ZERO), + submissionId = Ref.SubmissionId.assertFromString(submissionId), + ledgerConfiguration = configuration, ) val transactionMeta = state.TransactionMeta( ledgerEffectiveTime = Time.Timestamp.assertFromInstant(ledgerTime), - workflowId = Some(Ref.LedgerString.assertFromString("wfid")), + workflowId = Some(Ref.WorkflowId.assertFromString("wfid")), submissionTime = Time.Timestamp.assertFromInstant(ledgerTime.plusNanos(3)), submissionSeed = submissionSeed, optUsedPackages = None, @@ -134,7 +145,12 @@ class TransactionTimeModelComplianceIT val ledgerTime = recordTime for { - r1 <- publishTxAt(ledger, ledgerTime, "lt-valid") + r1 <- publishTxAt( + ledger = ledger, + ledgerTime = ledgerTime, + commandId = "lt-valid", + configuration = null, + ) } yield { expectInvalidLedgerTime(r1) } @@ -143,8 +159,19 @@ class TransactionTimeModelComplianceIT val ledgerTime = recordTime for { - _ <- publishConfig(ledger, recordTime, 1, JDuration.ofSeconds(1), JDuration.ofSeconds(1)) - r1 <- publishTxAt(ledger, ledgerTime, "lt-valid") + config <- publishConfig( + ledger, + recordTime, + 1, + JDuration.ofSeconds(1), + JDuration.ofSeconds(1), + ) + r1 <- publishTxAt( + ledger = ledger, + ledgerTime = ledgerTime, + commandId = "lt-valid", + configuration = config, + ) } yield { expectValidTx(r1) } @@ -155,8 +182,13 @@ class TransactionTimeModelComplianceIT val ledgerTime = recordTime.minus(minSkew).minusSeconds(1) for { - _ <- publishConfig(ledger, recordTime, 1, minSkew, maxSkew) - r1 <- publishTxAt(ledger, ledgerTime, "lt-low") + config <- publishConfig(ledger, recordTime, 1, minSkew, maxSkew) + r1 <- publishTxAt( + ledger = ledger, + ledgerTime = ledgerTime, + commandId = "lt-low", + configuration = config, + ) } yield { expectInvalidLedgerTime(r1) } @@ -167,8 +199,13 @@ class TransactionTimeModelComplianceIT val ledgerTime = recordTime.plus(maxSkew).plusSeconds(1) for { - _ <- publishConfig(ledger, recordTime, 1, minSkew, maxSkew) - r1 <- publishTxAt(ledger, ledgerTime, "lt-high") + config <- publishConfig(ledger, recordTime, 1, minSkew, maxSkew) + r1 <- publishTxAt( + ledger = ledger, + ledgerTime = ledgerTime, + commandId = "lt-high", + configuration = config, + ) } yield { expectInvalidLedgerTime(r1) } @@ -179,10 +216,20 @@ class TransactionTimeModelComplianceIT val ledgerTime = recordTime.plus(largeSkew) for { - _ <- publishConfig(ledger, recordTime, 1, largeSkew, largeSkew) - r1 <- publishTxAt(ledger, ledgerTime, "lt-before") - _ <- publishConfig(ledger, recordTime, 2, smallSkew, smallSkew) - r2 <- publishTxAt(ledger, ledgerTime, "lt-after") + config1 <- publishConfig(ledger, recordTime, 1, largeSkew, largeSkew) + r1 <- publishTxAt( + ledger = ledger, + ledgerTime = ledgerTime, + commandId = "lt-before", + configuration = config1, + ) + config2 <- publishConfig(ledger, recordTime, 2, smallSkew, smallSkew) + r2 <- publishTxAt( + ledger = ledger, + ledgerTime = ledgerTime, + commandId = "lt-after", + configuration = config2, + ) } yield { expectValidTx(r1) expectInvalidLedgerTime(r2) diff --git a/ledger/sandbox/src/main/scala/platform/sandboxnext/Runner.scala b/ledger/sandbox/src/main/scala/platform/sandboxnext/Runner.scala index a8d197499c44..1c7a1b1dab72 100644 --- a/ledger/sandbox/src/main/scala/platform/sandboxnext/Runner.scala +++ b/ledger/sandbox/src/main/scala/platform/sandboxnext/Runner.scala @@ -22,8 +22,12 @@ import com.daml.ledger.on.sql.Database.InvalidDatabaseException import com.daml.ledger.on.sql.SqlLedgerReaderWriter import com.daml.ledger.participant.state.kvutils.api.KeyValueParticipantState import com.daml.ledger.participant.state.kvutils.caching._ -import com.daml.ledger.participant.state.v1.WritePackagesService -import com.daml.ledger.participant.state.v1.metrics.{TimedReadService, TimedWriteService} +import com.daml.ledger.participant.state.v2.metrics.{TimedReadService, TimedWriteService} +import com.daml.ledger.participant.state.v2.{ + AdaptedV1ReadService, + AdaptedV1WriteService, + WritePackagesService, +} import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner} import com.daml.lf.archive.DarParser import com.daml.lf.data.Ref @@ -161,14 +165,14 @@ class Runner(config: SandboxConfig) extends ResourceOwner[Port] { timeProvider = timeServiceBackend.getOrElse(TimeProvider.UTC), ) ledger = new KeyValueParticipantState(readerWriter, readerWriter, metrics) - readService = new TimedReadService(ledger, metrics) - writeService = new TimedWriteService(ledger, metrics) + readService = new TimedReadService(new AdaptedV1ReadService(ledger), metrics) + writeService = new TimedWriteService(new AdaptedV1WriteService(ledger), metrics) healthChecks = new HealthChecks( "read" -> readService, "write" -> writeService, ) ledgerId <- ResourceOwner.forFuture(() => - readService.getLedgerInitialConditions().runWith(Sink.head).map(_.ledgerId) + readService.ledgerInitialConditions().runWith(Sink.head).map(_.ledgerId) ) _ <- if (isReset) {