diff --git a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Transaction.scala b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Transaction.scala index adb46950a289..902e575dbcd9 100644 --- a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Transaction.scala +++ b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Transaction.scala @@ -364,13 +364,29 @@ sealed abstract class HasTxNodes[Nid, +Cid] { globalState } - final def localContracts[Cid2 >: Cid]: Map[Cid2, Nid] = - fold(Map.empty[Cid2, Nid]) { + final def localContracts[Cid2 >: Cid]: Map[Cid2, (Nid, Node.NodeCreate[Cid2])] = + fold(Map.empty[Cid2, (Nid, Node.NodeCreate[Cid2])]) { case (acc, (nid, create: Node.NodeCreate[Cid])) => - acc.updated(create.coid, nid) + acc.updated(create.coid, nid -> create) case (acc, _) => acc } + /** Returns the IDs of all the consumed contracts. + * This includes transient contracts but it does not include contracts + * consumed in rollback nodes. + */ + final def consumedContracts[Cid2 >: Cid]: Set[Cid2] = + foldInExecutionOrder(Set.empty[Cid2])( + exerciseBegin = (acc, _, exe) => { + if (exe.consuming) { (acc + exe.targetCoid, true) } + else { (acc, true) } + }, + rollbackBegin = (acc, _, _) => (acc, false), + leaf = (acc, _, _) => acc, + exerciseEnd = (acc, _, _) => acc, + rollbackEnd = (acc, _, _) => acc, + ) + /** Returns the IDs of all input contracts that are used by this transaction. */ final def inputContracts[Cid2 >: Cid]: Set[Cid2] = @@ -405,6 +421,37 @@ sealed abstract class HasTxNodes[Nid, +Cid] { } } + /** The contract keys created or updated as part of the transaction. + * This includes updates to transient contracts (by mapping them to None) + * but it does not include any updates under rollback nodes. + */ + final def updatedContractKeys(implicit + ev: HasTxNodes[Nid, Cid] <:< HasTxNodes[_, Value.ContractId] + ): Map[GlobalKey, Option[Value.ContractId]] = { + ev(this).foldInExecutionOrder(Map.empty[GlobalKey, Option[Value.ContractId]])( + exerciseBegin = { + case (acc, _, exec) if exec.consuming => + ( + exec.key.fold(acc)(key => + acc.updated(GlobalKey.assertBuild(exec.templateId, key.key), None) + ), + true, + ) + case (acc, _, _) => (acc, true) + }, + rollbackBegin = (acc, _, _) => (acc, false), + leaf = { + case (acc, _, create: Node.NodeCreate[Value.ContractId]) => + create.key.fold(acc)(key => + acc.updated(GlobalKey.assertBuild(create.templateId, key.key), Some(create.coid)) + ) + case (acc, _, _: Node.NodeFetch[_] | _: Node.NodeLookupByKey[_]) => acc + }, + exerciseEnd = (acc, _, _) => acc, + rollbackEnd = (acc, _, _) => acc, + ) + } + // This method visits to all nodes of the transaction in execution order. // Exercise/rollback nodes are visited twice: when execution reaches them and when execution leaves their body. // On the first visit of an execution/rollback node, the caller can prevent traversal of the children diff --git a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala index 6aefce81dcdd..39e89813d347 100644 --- a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala +++ b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala @@ -374,6 +374,82 @@ class TransactionSpec extends AnyFreeSpec with Matchers with ScalaCheckDrivenPro builder.build().contractKeys shouldBe expectedResults } } + + def create(builder: TransactionBuilder, parties: Seq[String], key: Option[String] = None) = { + val cid: ContractId = builder.newCid + val node = builder.create( + id = cid, + template = "-pkg-:Mod:T", + argument = V.ValueUnit, + signatories = parties, + observers = Seq(), + key = key.map(V.ValueText(_)), + ) + (cid, node) + } + def exercise( + builder: TransactionBuilder, + create: Node.NodeCreate[ContractId], + parties: Seq[String], + consuming: Boolean, + ) = + builder.exercise( + contract = create, + choice = "C", + actingParties = parties.toSet, + consuming = consuming, + argument = V.ValueUnit, + byKey = false, + ) + + "consumedContract" - { + "return the IDs of consumed contracts" in { + val builder = TransactionBuilder() + val parties = Seq("Alice") + val (cid0, create0) = create(builder, parties) + val (_, create1) = create(builder, parties) + val (cid2, create2) = create(builder, parties) + val (_, create3) = create(builder, parties) + builder.add(exercise(builder, create0, parties, true)) + builder.add(create1) + builder.add(create2) + val exeNid1 = builder.add(exercise(builder, create1, parties, false)) + val exeNid2 = builder.add(exercise(builder, create2, parties, true), exeNid1) + builder.add(exercise(builder, create3, parties, false), exeNid2) + val rollback = builder.add(builder.rollback(), exeNid2) + builder.add(exercise(builder, create3, parties, true), rollback) + builder.build().consumedContracts shouldBe Set(cid0, cid2) + } + } + + "updatedContractKeys" - { + "return all the updated contract keys" in { + val builder = TransactionBuilder() + val parties = Seq("Alice") + val (cid0, create0) = create(builder, parties, Some("key0")) + val (_, create1) = create(builder, parties, Some("key1")) + val (_, create2) = create(builder, parties, Some("key2")) + val (cid3, create3) = create(builder, parties, Some("key2")) + val (_, create4) = create(builder, parties, Some("key2")) + val (_, create5) = create(builder, parties, Some("key3")) + builder.add(create0) + builder.add(exercise(builder, create0, parties, false)) + builder.add(create1) + val ex = builder.add(exercise(builder, create1, parties, true)) + builder.add(create2, ex) + builder.add(exercise(builder, create2, parties, true), ex) + builder.add(create3, ex) + val rollback = builder.add(builder.rollback()) + builder.add(exercise(builder, create0, parties, true), rollback) + builder.add(create5, rollback) + builder.add(exercise(builder, create3, parties, true), rollback) + builder.add(create4, rollback) + def key(s: String) = + GlobalKey.assertBuild(Ref.Identifier.assertFromString("-pkg-:Mod:T"), V.ValueText(s)) + builder.build().updatedContractKeys shouldBe + Map(key("key0") -> Some(cid0), key("key1") -> None, key("key2") -> Some(cid3)) + } + } } object TransactionSpec { diff --git a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/Conversions.scala b/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/Conversions.scala index 673f2b261a9e..777b5fd6a030 100644 --- a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/Conversions.scala +++ b/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/Conversions.scala @@ -14,7 +14,14 @@ import com.daml.ledger.participant.state.v1.{PackageId, SubmitterInfo} import com.daml.lf.data.Ref.{Identifier, LedgerString, Party} import com.daml.lf.data.Relation.Relation import com.daml.lf.data.Time -import com.daml.lf.transaction.{GlobalKey, _} +import com.daml.lf.transaction.{ + BlindingInfo, + GlobalKey, + NodeId, + Transaction, + TransactionCoder, + TransactionOuterClass, +} import com.daml.lf.value.Value.{ContractId, VersionedValue} import com.daml.lf.value.{Value, ValueCoder, ValueOuterClass} import com.daml.lf.{crypto, data} diff --git a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/InputsAndEffects.scala b/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/InputsAndEffects.scala deleted file mode 100644 index 08b4a8a1af3f..000000000000 --- a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/InputsAndEffects.scala +++ /dev/null @@ -1,169 +0,0 @@ -// 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.kvutils - -import com.daml.ledger.participant.state.kvutils.Conversions._ -import com.daml.ledger.participant.state.kvutils.DamlKvutils._ -import com.daml.ledger.participant.state.v1.TransactionMeta -import com.daml.lf.data.Ref._ -import com.daml.lf.transaction.{GlobalKey, Node, NodeId, Transaction} -import com.daml.lf.value.Value -import com.daml.lf.value.Value.ContractId - -import scala.collection.mutable - -/** Internal utilities to compute the inputs and effects of a DAML transaction */ -private[kvutils] object InputsAndEffects { - - /** The effects of the transaction, that is what contracts - * were consumed and created, and what contract keys were updated. - */ - /** @param consumedContracts - * The contracts consumed by this transaction. - * When committing the transaction these contracts must be marked consumed. - * A contract should be marked consumed when the transaction is committed, - * regardless of the ledger effective time of the transaction (e.g. a transaction - * with an earlier ledger effective time that gets committed later would find the - * contract inactive). - * @param createdContracts - * The contracts created by this transaction. - * When the transaction is committed, keys marking the activeness of these - * contracts should be created. The key should be a combination of the transaction - * id and the relative contract id (that is, the node index). - * @param updatedContractKeys - * The contract keys created or updated as part of the transaction. - */ - final case class Effects( - consumedContracts: List[DamlStateKey], - createdContracts: List[(DamlStateKey, Node.NodeCreate[ContractId])], - updatedContractKeys: Map[DamlStateKey, Option[ContractId]], - ) - - object Effects { - val empty = Effects(List.empty, List.empty, Map.empty) - } - - /** Compute the inputs to a DAML transaction, that is, the referenced contracts, keys - * and packages. - */ - def computeInputs( - tx: Transaction.Transaction, - meta: TransactionMeta, - ): List[DamlStateKey] = { - val inputs = mutable.LinkedHashSet[DamlStateKey]() - - { - import PackageId.ordering - inputs ++= - meta.optUsedPackages - .getOrElse( - throw new InternalError("Transaction was not annotated with used packages") - ) - .toList - .sorted - .map(DamlStateKey.newBuilder.setPackageId(_).build) - } - - val localContract = tx.localContracts - - def addContractInput(coid: ContractId): Unit = - if (!localContract.isDefinedAt(coid)) - inputs += contractIdToStateKey(coid) - - def partyInputs(parties: Set[Party]): List[DamlStateKey] = { - import Party.ordering - parties.toList.sorted.map(partyStateKey) - } - - tx.foreach { case (_, node) => - node match { - case action: Node.GenActionNode[NodeId, Value.ContractId] => - action match { - case fetch: Node.NodeFetch[Value.ContractId] => - addContractInput(fetch.coid) - fetch.key.foreach { keyWithMaintainers => - inputs += contractKeyToStateKey(fetch.templateId, keyWithMaintainers.key) - } - - case create: Node.NodeCreate[Value.ContractId] => - create.key.foreach { keyWithMaintainers => - inputs += contractKeyToStateKey(create.coinst.template, keyWithMaintainers.key) - } - - case exe: Node.NodeExercises[NodeId, Value.ContractId] => - addContractInput(exe.targetCoid) - exe.key.foreach { keyWithMaintainers => - inputs += contractKeyToStateKey(exe.templateId, keyWithMaintainers.key) - } - - case lookup: Node.NodeLookupByKey[Value.ContractId] => - // We need both the contract key state and the contract state. The latter is used to verify - // that the submitter can access the contract. - lookup.result.foreach(addContractInput) - inputs += contractKeyToStateKey(lookup.templateId, lookup.key.key) - } - - inputs ++= partyInputs(action.informeesOfNode) - - case _: Node.NodeRollback[_] => - // TODO https://github.com/digital-asset/daml/issues/8020 - sys.error("rollback nodes are not supported") - } - } - - inputs.toList - } - - /** Compute the effects of a DAML transaction, that is, the created and consumed contracts. */ - def computeEffects(tx: Transaction.Transaction): Effects = { - // TODO(JM): Skip transient contracts in createdContracts/updateContractKeys. E.g. rewrite this to - // fold bottom up (with reversed roots!) and skip creates of archived contracts. - tx.fold(Effects.empty) { case (effects, (_, node)) => - node match { - case _: Node.NodeRollback[_] => - // TODO https://github.com/digital-asset/daml/issues/8020 - sys.error("rollback nodes are not supported") - case _: Node.NodeFetch[Value.ContractId] => - effects - case create: Node.NodeCreate[Value.ContractId] => - effects.copy( - createdContracts = - contractIdToStateKey(create.coid) -> create :: effects.createdContracts, - updatedContractKeys = create.key - .fold(effects.updatedContractKeys)(keyWithMaintainers => - effects.updatedContractKeys.updated( - contractKeyToStateKey(create.coinst.template, keyWithMaintainers.key), - Some(create.coid), - ) - ), - ) - - case exe: Node.NodeExercises[NodeId, Value.ContractId] => - if (exe.consuming) { - effects.copy( - consumedContracts = contractIdToStateKey(exe.targetCoid) :: effects.consumedContracts, - updatedContractKeys = exe.key - .fold(effects.updatedContractKeys)(key => - effects.updatedContractKeys.updated( - contractKeyToStateKey(exe.templateId, key.key), - None, - ) - ), - ) - } else { - effects - } - case _: Node.NodeLookupByKey[Value.ContractId] => - effects - } - } - } - - private[this] def contractKeyToStateKey(tmplId: Identifier, key: Value[ContractId]) = - globalKeyToStateKey( - GlobalKey - .build(tmplId, key) - .fold(msg => throw Err.InvalidSubmission(msg), identity) - ) -} diff --git a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/KeyValueSubmission.scala b/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/KeyValueSubmission.scala index ac5792d5a61d..15710e2992e6 100644 --- a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/KeyValueSubmission.scala +++ b/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/KeyValueSubmission.scala @@ -35,8 +35,7 @@ class KeyValueSubmission(metrics: Metrics) { */ def transactionOutputs(tx: SubmittedTransaction): List[DamlStateKey] = metrics.daml.kvutils.submission.conversion.transactionOutputs.time { () => - val effects = InputsAndEffects.computeEffects(tx) - effects.createdContracts.map(_._1) ++ effects.consumedContracts + (tx.localContracts.keys ++ tx.consumedContracts).map(Conversions.contractIdToStateKey).toList } private def submissionParties( diff --git a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/TransactionCommitter.scala b/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/TransactionCommitter.scala index b0e88541f8bd..cdfb4df62df7 100644 --- a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/TransactionCommitter.scala +++ b/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/TransactionCommitter.scala @@ -12,18 +12,17 @@ import com.daml.ledger.participant.state.kvutils.committer.Committer._ import com.daml.ledger.participant.state.kvutils.committer._ import com.daml.ledger.participant.state.kvutils.committer.transaction.TransactionCommitter.DamlTransactionEntrySummary import com.daml.ledger.participant.state.kvutils.committer.transaction.keys.ContractKeysValidation.validateKeys -import com.daml.ledger.participant.state.kvutils.{Conversions, Err, InputsAndEffects} +import com.daml.ledger.participant.state.kvutils.{Conversions, Err} import com.daml.ledger.participant.state.v1.{Configuration, RejectionReason, TimeModel} import com.daml.lf.archive.Decode import com.daml.lf.archive.Reader.ParseError import com.daml.lf.crypto -import com.daml.lf.data.Ref.{Identifier, PackageId, Party, TypeConName} +import com.daml.lf.data.Ref.{PackageId, Party} import com.daml.lf.data.Time.Timestamp import com.daml.lf.engine.{Blinding, Engine, ReplayMismatch} import com.daml.lf.language.Ast import com.daml.lf.transaction.{ BlindingInfo, - GlobalKey, GlobalKeyWithMaintainers, Node, NodeId, @@ -448,30 +447,31 @@ private[kvutils] class TransactionCommitter( blindingInfo: BlindingInfo, commitContext: CommitContext, ): Unit = { - val effects = InputsAndEffects.computeEffects(transactionEntry.transaction) - val cid2nid: Value.ContractId => NodeId = - transactionEntry.transaction.localContracts + val localContracts = transactionEntry.transaction.localContracts + val consumedContracts = transactionEntry.transaction.consumedContracts + val contractKeys = transactionEntry.transaction.updatedContractKeys // Add contract state entries to mark contract activeness (checked by 'validateModelConformance'). - for ((key, createNode) <- effects.createdContracts) { + for ((cid, (nid, createNode)) <- localContracts) { val cs = DamlContractState.newBuilder cs.setActiveAt(buildTimestamp(transactionEntry.ledgerEffectiveTime)) - val localDisclosure = - blindingInfo.disclosure(cid2nid(decodeContractId(key.getContractId))) + val localDisclosure = blindingInfo.disclosure(nid) cs.addAllLocallyDisclosedTo((localDisclosure: Iterable[String]).asJava) cs.setContractInstance( Conversions.encodeContractInstance(createNode.versionedCoinst) ) createNode.key.foreach { keyWithMaintainers => cs.setContractKey( - Conversions.encodeGlobalKey( - globalKey(createNode.coinst.template, keyWithMaintainers.key) - ) + Conversions.encodeContractKey(createNode.coinst.template, keyWithMaintainers.key) ) } - commitContext.set(key, DamlStateValue.newBuilder.setContractState(cs).build) + commitContext.set( + Conversions.contractIdToStateKey(cid), + DamlStateValue.newBuilder.setContractState(cs).build, + ) } // Update contract state entries to mark contracts as consumed (checked by 'validateModelConformance'). - for (key <- effects.consumedContracts) { + consumedContracts.foreach { cid => + val key = Conversions.contractIdToStateKey(cid) val cs = getContractState(commitContext, key) commitContext.set( key, @@ -497,9 +497,10 @@ private[kvutils] class TransactionCommitter( } // Update contract keys. val ledgerEffectiveTime = transactionEntry.submission.getLedgerEffectiveTime - for ((key, contractKeyState) <- effects.updatedContractKeys) { + for ((contractKey, contractKeyState) <- contractKeys) { + val stateKey = Conversions.globalKeyToStateKey(contractKey) val (k, v) = - updateContractKeyWithContractKeyState(ledgerEffectiveTime, key, contractKeyState) + updateContractKeyWithContractKeyState(ledgerEffectiveTime, stateKey, contractKeyState) commitContext.set(k, v) } } @@ -769,14 +770,4 @@ private[kvutils] object TransactionCommitter { } } yield parseTimestamp(dedupTimestamp).toInstant - private[committer] def damlContractKey( - templateId: TypeConName, - keyValue: Value[ContractId], - ): DamlContractKey = - encodeGlobalKey(globalKey(templateId, keyValue)) - - private[transaction] def globalKey(tmplId: Identifier, key: Value[ContractId]) = - GlobalKey - .build(tmplId, key) - .fold(msg => throw Err.InternalError(msg), identity) } diff --git a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/keys/KeyConsistencyValidation.scala b/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/keys/KeyConsistencyValidation.scala index f29af16215be..bc23b8435eee 100644 --- a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/keys/KeyConsistencyValidation.scala +++ b/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/keys/KeyConsistencyValidation.scala @@ -3,8 +3,8 @@ package com.daml.ledger.participant.state.kvutils.committer.transaction.keys +import com.daml.ledger.participant.state.kvutils.Conversions import com.daml.ledger.participant.state.kvutils.DamlKvutils.DamlContractKey -import com.daml.ledger.participant.state.kvutils.committer.transaction.TransactionCommitter.damlContractKey import com.daml.ledger.participant.state.kvutils.committer.transaction.keys.ContractKeysValidation.{ Inconsistent, KeyValidationState, @@ -74,7 +74,7 @@ private[keys] object KeyConsistencyValidation { case None => Right(keyValidationState) case Some(submittedKeyWithMaintainers) => val submittedDamlContractKey = - damlContractKey(templateId, submittedKeyWithMaintainers.key) + Conversions.encodeContractKey(templateId, submittedKeyWithMaintainers.key) val newKeyValidationState = keyValidationState + ConsistencyKeyValidationState( submittedContractKeysToContractIds = Map( diff --git a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/keys/KeyUniquenessValidation.scala b/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/keys/KeyUniquenessValidation.scala index bf64fb458542..65f11bdca7ba 100644 --- a/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/keys/KeyUniquenessValidation.scala +++ b/ledger/participant-state/kvutils/src/main/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/keys/KeyUniquenessValidation.scala @@ -5,7 +5,6 @@ package com.daml.ledger.participant.state.kvutils.committer.transaction.keys import com.daml.ledger.participant.state.kvutils.Conversions import com.daml.ledger.participant.state.kvutils.DamlKvutils.DamlStateKey -import com.daml.ledger.participant.state.kvutils.committer.transaction.TransactionCommitter.globalKey import com.daml.ledger.participant.state.kvutils.committer.transaction.keys.ContractKeysValidation.{ Duplicate, KeyValidationState, @@ -24,9 +23,8 @@ private[keys] object KeyUniquenessValidation { node match { case exercise: Node.NodeExercises[NodeId, ContractId] if exercise.key.isDefined && exercise.consuming => - val stateKey = Conversions.globalKeyToStateKey( - globalKey(exercise.templateId, exercise.key.get.key) - ) + val stateKey = + Conversions.contractKeyToStateKey(exercise.templateId, exercise.key.get.key) Right( keyValidationState + KeyValidationState( activeStateKeys = activeStateKeys - stateKey @@ -35,9 +33,7 @@ private[keys] object KeyUniquenessValidation { case create: Node.NodeCreate[ContractId] if create.key.isDefined => val stateKey = - Conversions.globalKeyToStateKey( - globalKey(create.coinst.template, create.key.get.key) - ) + Conversions.contractKeyToStateKey(create.coinst.template, create.key.get.key) if (activeStateKeys.contains(stateKey)) Left(Duplicate) diff --git a/ledger/participant-state/kvutils/src/test/suite/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/TransactionCommitterSpec.scala b/ledger/participant-state/kvutils/src/test/suite/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/TransactionCommitterSpec.scala index ed6d72ade63f..4fb3bb3bec04 100644 --- a/ledger/participant-state/kvutils/src/test/suite/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/TransactionCommitterSpec.scala +++ b/ledger/participant-state/kvutils/src/test/suite/scala/com/daml/ledger/participant/state/kvutils/committer/transaction/TransactionCommitterSpec.scala @@ -11,10 +11,7 @@ import com.daml.ledger.participant.state.kvutils.Conversions.{buildTimestamp, co import com.daml.ledger.participant.state.kvutils.DamlKvutils._ import com.daml.ledger.participant.state.kvutils.Err.MissingInputState import com.daml.ledger.participant.state.kvutils.TestHelpers._ -import com.daml.ledger.participant.state.kvutils.committer.transaction.TransactionCommitter.{ - DamlTransactionEntrySummary, - damlContractKey, -} +import com.daml.ledger.participant.state.kvutils.committer.transaction.TransactionCommitter.DamlTransactionEntrySummary import com.daml.ledger.participant.state.kvutils.committer.transaction.keys.ContractKeysValidation import com.daml.ledger.participant.state.kvutils.committer.{ CommitContext, @@ -621,7 +618,7 @@ class TransactionCommitterSpec extends AnyWordSpec with Matchers with MockitoSug val key = { val aCreateNode = createNode("#dummy") - damlContractKey(aCreateNode.templateId, aCreateNode.key.get.key) + Conversions.encodeContractKey(aCreateNode.templateId, aCreateNode.key.get.key) } forAll(cases) { (transaction: SubmittedTransaction, contractIdAtCommitter: Option[String]) => val context = commitContextWithContractStateKeys( diff --git a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/TransactionCommitter.scala b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/TransactionCommitter.scala index b675350764ef..5fac78604f23 100644 --- a/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/TransactionCommitter.scala +++ b/ledger/sandbox-classic/src/main/scala/platform/sandbox/stores/ledger/TransactionCommitter.scala @@ -36,9 +36,9 @@ object LegacyTransactionCommitter extends TransactionCommitter { val contractMapping = transaction .localContracts[Value.ContractId] - .transform((_, nid) => + .transform { case (_, (nid, _)) => Value.ContractId.V0(Ref.ContractIdString.assertFromString(prefix + nid.index.toString)) - ) + } .withDefault(identity) CommittedTransaction(VersionedTransaction.map2(identity[NodeId], contractMapping)(transaction))