diff --git a/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala b/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala index d182052565..f71dbec0d7 100644 --- a/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala +++ b/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala @@ -37,6 +37,7 @@ class AuthorizationSpec extends AnyFreeSpec with Matchers with Inside { observers = Seq("Carl"), key = Some(Value.ValueUnit), maintainers = maintainers, + byInterface = None, ) "create" - { diff --git a/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala b/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala index 0bb3ba8281..01af1e449f 100644 --- a/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala +++ b/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala @@ -103,6 +103,7 @@ class BlindingSpec extends AnyFreeSpec with Matchers { observers = Seq("Carl"), key = Some(ValueRecord(None, ImmArray.empty)), maintainers = Seq("Alice"), + byInterface = None, ) val lookup = builder.lookupByKey(create, true) val nodeId = builder.add(lookup) @@ -124,6 +125,7 @@ class BlindingSpec extends AnyFreeSpec with Matchers { observers = Seq("Carl"), key = Some(ValueRecord(None, ImmArray.empty)), maintainers = Seq("Alice"), + byInterface = None, ) val lookup = builder.lookupByKey(create, false) val nodeId = builder.add(lookup) diff --git a/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala b/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala index c4820fc577..f8da5140bd 100644 --- a/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala +++ b/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala @@ -1104,6 +1104,7 @@ class EngineTest _, _, _, + _, ) => coid shouldBe originalCoid consuming shouldBe true @@ -1190,7 +1191,7 @@ class EngineTest def actFetchActors(n: Node): Set[Party] = { n match { - case Node.Fetch(_, _, actingParties, _, _, _, _, _) => actingParties + case Node.Fetch(_, _, actingParties, _, _, _, _, _, _) => actingParties case _ => Set() } } @@ -1576,7 +1577,7 @@ class EngineTest ) tx.transaction.nodes.values.headOption match { - case Some(Node.Fetch(_, _, _, _, _, key, _, _)) => + case Some(Node.Fetch(_, _, _, _, _, key, _, _, _)) => key match { // just test that the maintainers match here, getting the key out is a bit hairier case Some(Node.KeyWithMaintainers(_, maintainers)) => @@ -1800,7 +1801,7 @@ class EngineTest val stx = suffix(tx) val ImmArray(_, exeNode1) = tx.transaction.roots - val Node.Exercise(_, _, _, _, _, _, _, _, _, children, _, _, _, _) = + val Node.Exercise(_, _, _, _, _, _, _, _, _, children, _, _, _, _, _) = tx.transaction.nodes(exeNode1) val nids = children.toSeq.take(2).toImmArray diff --git a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/scenario/ScenarioLedger.scala b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/scenario/ScenarioLedger.scala index da77de6e9a..d6177a3cce 100644 --- a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/scenario/ScenarioLedger.scala +++ b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/scenario/ScenarioLedger.scala @@ -485,7 +485,7 @@ object ScenarioLedger { } processNodes(mbNewCache2, idsToProcess) - case Node.Fetch(referencedCoid, templateId @ _, _, _, _, _, _, _) => + case Node.Fetch(referencedCoid, templateId @ _, _, _, _, _, _, _, _) => val newCacheP = newCache.updateLedgerNodeInfo(referencedCoid)(info => info.copy(referencedBy = info.referencedBy + eventId) diff --git a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltin.scala b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltin.scala index 99ab4deca6..25676e6ac9 100644 --- a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltin.scala +++ b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltin.scala @@ -945,6 +945,7 @@ private[lf] object SBuiltin { signatories = sigs, stakeholders = sigs union obs, key = mbKey, + byInterface = None, // TODO https://github.com/digital-asset/daml/issues/10915 ) machine.addLocalContract(coid, templateId, createArg, sigs, obs, mbKey) @@ -1007,6 +1008,7 @@ private[lf] object SBuiltin { mbKey = mbKey, byKey = byKey, chosenValue = chosenValue, + byInterface = None, // TODO https://github.com/digital-asset/daml/issues/10915 ) checkAborted(onLedger.ptx) machine.returnValue = SUnit @@ -1217,6 +1219,7 @@ private[lf] object SBuiltin { stakeholders, key, byKey, + None, // TODO https://github.com/digital-asset/daml/issues/10915 ) checkAborted(onLedger.ptx) machine.returnValue = SUnit diff --git a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/transaction/PartialTransaction.scala b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/transaction/PartialTransaction.scala index 8fa9732d9e..22a61a873c 100644 --- a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/transaction/PartialTransaction.scala +++ b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/transaction/PartialTransaction.scala @@ -136,6 +136,8 @@ private[lf] object PartialTransaction { * @param parent The context in which the exercises is * happening. * @param byKey True if the exercise is done "by key" + * @param byInterface The interface through which this exercise + * was invoked, if any. */ final case class ExercisesContextInfo( targetId: Value.ContractId, @@ -151,6 +153,7 @@ private[lf] object PartialTransaction { nodeId: NodeId, parent: Context, byKey: Boolean, + byInterface: Option[TypeConName], ) extends ContextInfo { val actionNodeSeed = parent.nextActionChildSeed val actionChildSeed = crypto.Hash.deriveNodeSeed(actionNodeSeed, _) @@ -406,6 +409,7 @@ private[speedy] case class PartialTransaction( signatories: Set[Party], stakeholders: Set[Party], key: Option[Node.KeyWithMaintainers[Value]], + byInterface: Option[TypeConName], ): (Value.ContractId, PartialTransaction) = { val actionNodeSeed = context.nextActionChildSeed val discriminator = @@ -420,6 +424,7 @@ private[speedy] case class PartialTransaction( signatories, stakeholders, key, + byInterface, version, ) val nid = NodeId(nextNodeIdx) @@ -498,6 +503,7 @@ private[speedy] case class PartialTransaction( stakeholders: Set[Party], key: Option[Node.KeyWithMaintainers[Value]], byKey: Boolean, + byInterface: Option[TypeConName], ): PartialTransaction = { val nid = NodeId(nextNodeIdx) val version = packageToTransactionVersion(templateId.packageId) @@ -509,6 +515,7 @@ private[speedy] case class PartialTransaction( stakeholders, key, normByKey(version, byKey), + byInterface, version, ) mustBeActive( @@ -554,6 +561,7 @@ private[speedy] case class PartialTransaction( mbKey: Option[Node.KeyWithMaintainers[Value]], byKey: Boolean, chosenValue: Value, + byInterface: Option[TypeConName], ): PartialTransaction = { val nid = NodeId(nextNodeIdx) val ec = @@ -571,6 +579,7 @@ private[speedy] case class PartialTransaction( nodeId = nid, parent = context, byKey = byKey, + byInterface = byInterface, ) mustBeActive( @@ -663,6 +672,7 @@ private[speedy] case class PartialTransaction( exerciseResult = None, key = ec.contractKey, byKey = normByKey(version, ec.byKey), + byInterface = ec.byInterface, version = version, ) } diff --git a/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/NormalizeRollbacksSpec.scala b/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/NormalizeRollbacksSpec.scala index 6a6a729309..619f58a626 100644 --- a/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/NormalizeRollbacksSpec.scala +++ b/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/NormalizeRollbacksSpec.scala @@ -301,6 +301,7 @@ object NormalizeRollbackSpec { signatories = Set.empty, stakeholders = Set.empty, key = None, + byInterface = None, version = TransactionVersion.minVersion, ) @@ -324,6 +325,7 @@ object NormalizeRollbackSpec { exerciseResult = None, key = None, byKey = false, + byInterface = None, version = TransactionVersion.minVersion, ) } diff --git a/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/PartialTransactionSpec.scala b/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/PartialTransactionSpec.scala index c3b4444b4a..ab8339b78e 100644 --- a/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/PartialTransactionSpec.scala +++ b/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/PartialTransactionSpec.scala @@ -53,6 +53,7 @@ class PartialTransactionSpec extends AnyWordSpec with Matchers with Inside { Set(party), Set.empty, None, + None, ) ._2 @@ -70,6 +71,7 @@ class PartialTransactionSpec extends AnyWordSpec with Matchers with Inside { choiceObservers = Set.empty, mbKey = None, byKey = false, + byInterface = None, chosenValue = Value.ValueUnit, ) diff --git a/daml-lf/transaction-test-lib/src/main/scala/lf/transaction/test/TransactionBuilder.scala b/daml-lf/transaction-test-lib/src/main/scala/lf/transaction/test/TransactionBuilder.scala index aed0f92b46..4cd3617607 100644 --- a/daml-lf/transaction-test-lib/src/main/scala/lf/transaction/test/TransactionBuilder.scala +++ b/daml-lf/transaction-test-lib/src/main/scala/lf/transaction/test/TransactionBuilder.scala @@ -84,8 +84,9 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion signatories: Set[Ref.Party], observers: Set[Ref.Party], key: Option[Value] = None, + byInterface: Option[Ref.Identifier] = None, ): Node.Create = - create(id, templateId, argument, signatories, observers, key, signatories) + create(id, templateId, argument, signatories, observers, key, signatories, byInterface) def create( id: ContractId, @@ -95,6 +96,7 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion observers: Set[Ref.Party], key: Option[Value], maintainers: Set[Ref.Party], + byInterface: Option[Ref.Identifier], ): Node.Create = { Node.Create( coid = id, @@ -104,6 +106,7 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion signatories = signatories, stakeholders = signatories | observers, key = key.map(Node.KeyWithMaintainers(_, maintainers)), + byInterface = byInterface, version = pkgTxVersion(templateId.packageId), ) } @@ -117,6 +120,7 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion result: Option[Value] = None, choiceObservers: Set[Ref.Party] = Set.empty, byKey: Boolean = true, + byInterface: Option[Ref.Identifier] = None, ): Node.Exercise = Node.Exercise( choiceObservers = choiceObservers, @@ -132,6 +136,7 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion exerciseResult = result, key = contract.key, byKey = byKey, + byInterface = byInterface, version = pkgTxVersion(contract.templateId.packageId), ) @@ -144,7 +149,11 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion ): Node.Exercise = exercise(contract, choice, consuming, actingParties, argument, byKey = true) - def fetch(contract: Node.Create, byKey: Boolean = false): Node.Fetch = + def fetch( + contract: Node.Create, + byKey: Boolean = false, + byInterface: Option[Ref.Identifier] = None, + ): Node.Fetch = Node.Fetch( coid = contract.coid, templateId = contract.templateId, @@ -153,6 +162,7 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion stakeholders = contract.stakeholders, key = contract.key, byKey = byKey, + byInterface = byInterface, version = pkgTxVersion(contract.templateId.packageId), ) diff --git a/daml-lf/transaction-test-lib/src/main/scala/lf/value/test/ValueGenerators.scala b/daml-lf/transaction-test-lib/src/main/scala/lf/value/test/ValueGenerators.scala index 76e0eaff61..ba51f3240e 100644 --- a/daml-lf/transaction-test-lib/src/main/scala/lf/value/test/ValueGenerators.scala +++ b/daml-lf/transaction-test-lib/src/main/scala/lf/value/test/ValueGenerators.scala @@ -316,6 +316,7 @@ object ValueGenerators { signatories, stakeholders, key, + None, // TODO https://github.com/digital-asset/daml/issues/10915 version, ) } @@ -343,6 +344,7 @@ object ValueGenerators { stakeholders, key, byKey, + None, // TODO https://github.com/digital-asset/daml/issues/10915 version, ) } @@ -399,6 +401,7 @@ object ValueGenerators { exerciseResult, key, byKey, + None, // TODO https://github.com/digital-asset/daml/issues/10915 version, ) } diff --git a/daml-lf/transaction/src/main/protobuf/com/daml/lf/transaction.proto b/daml-lf/transaction/src/main/protobuf/com/daml/lf/transaction.proto index 085261ee8e..be1933cbdc 100644 --- a/daml-lf/transaction/src/main/protobuf/com/daml/lf/transaction.proto +++ b/daml-lf/transaction/src/main/protobuf/com/daml/lf/transaction.proto @@ -10,8 +10,9 @@ // * 12 -- drop value version in profit of node version // * 13 -- no change w.r.t. 12 // * 14 -- add rollback nodes -// add byKey flag to fetch and exercise node +// add by_key flag to fetch and exercise node // * dev -- special staging area for the next version to be released +// add by_interface to fetch and exercise node syntax = "proto3"; package com.daml.lf.transaction; @@ -72,6 +73,7 @@ message NodeCreate { repeated string signatories = 4; KeyWithMaintainers key_with_maintainers = 5; com.daml.lf.value.ContractId contract_id_struct = 6; + optional com.daml.lf.value.Identifier by_interface = 10; // *since version dev* } message NodeFetch { @@ -83,7 +85,8 @@ message NodeFetch { reserved 5; // was value_version com.daml.lf.value.ContractId contract_id_struct = 6; KeyWithMaintainers key_with_maintainers = 8; - bool byKey = 9; // *since version 1.14* + bool by_key = 9; // *since version 1.14* + optional com.daml.lf.value.Identifier by_interface = 10; // *since version dev* } message NodeExercise { @@ -108,7 +111,8 @@ message NodeExercise { reserved 13; // was contract_key KeyWithMaintainers key_with_maintainers = 14; // optional repeated string observers = 15; // *since version 11* - bool byKey = 18; // *since version 14* + bool by_key = 18; // *since version 14* + optional com.daml.lf.value.Identifier by_interface = 19; // *since version dev* } message NodeLookupByKey { diff --git a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala index 4d4ca3f7fd..0e147f768a 100644 --- a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala +++ b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala @@ -56,6 +56,8 @@ object Node { def byKey: Boolean + def byInterface: Option[TypeConName] + protected def versionValue[Cid2 >: ContractId](v: Value): VersionedValue = VersionedValue(version, v) } @@ -82,6 +84,7 @@ object Node { signatories: Set[Party], stakeholders: Set[Party], key: Option[KeyWithMaintainers[Value]], + override val byInterface: Option[TypeConName], // For the sake of consistency between types with a version field, keep this field the last. override val version: TransactionVersion, ) extends LeafOnlyAction @@ -121,6 +124,7 @@ object Node { stakeholders: Set[Party], key: Option[KeyWithMaintainers[Value]], override val byKey: Boolean, // invariant (!byKey || exerciseResult.isDefined) + override val byInterface: Option[TypeConName], // For the sake of consistency between types with a version field, keep this field the last. override val version: TransactionVersion, ) extends LeafOnlyAction @@ -160,6 +164,7 @@ object Node { exerciseResult: Option[Value], key: Option[KeyWithMaintainers[Value]], override val byKey: Boolean, // invariant (!byKey || exerciseResult.isDefined) + override val byInterface: Option[TypeConName], // For the sake of consistency between types with a version field, keep this field the last. override val version: TransactionVersion, ) extends Action @@ -210,6 +215,7 @@ object Node { override def keyMaintainers: Set[Party] = key.maintainers override def hasResult: Boolean = result.isDefined override def byKey: Boolean = true + override def byInterface: Option[TypeConName] = None override private[lf] def updateVersion(version: TransactionVersion): Node.LookupByKey = copy(version = version) 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 48e42a11c3..55a98ac3fb 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 @@ -437,9 +437,9 @@ sealed abstract class HasTxNodes { */ final def inputContracts[Cid2 >: ContractId]: Set[Cid2] = fold(Set.empty[Cid2]) { - case (acc, (_, Node.Exercise(coid, _, _, _, _, _, _, _, _, _, _, _, _, _))) => + case (acc, (_, Node.Exercise(coid, _, _, _, _, _, _, _, _, _, _, _, _, _, _))) => acc + coid - case (acc, (_, Node.Fetch(coid, _, _, _, _, _, _, _))) => + case (acc, (_, Node.Fetch(coid, _, _, _, _, _, _, _, _))) => acc + coid case (acc, (_, Node.LookupByKey(_, _, Some(coid), _))) => acc + coid @@ -763,13 +763,13 @@ object GenTransaction { tx.fold(State(Set.empty, Set.empty)) { case (state, (_, node)) => node match { - case Node.Create(_, tmplId, _, _, _, _, Some(key), _) => + case Node.Create(_, tmplId, _, _, _, _, Some(key), _, _) => state.created(globalKey(tmplId, key.key)) - case Node.Exercise(_, tmplId, _, true, _, _, _, _, _, _, _, Some(key), _, _) => + case Node.Exercise(_, tmplId, _, true, _, _, _, _, _, _, _, Some(key), _, _, _) => state.consumed(globalKey(tmplId, key.key)) - case Node.Exercise(_, tmplId, _, false, _, _, _, _, _, _, _, Some(key), _, _) => + case Node.Exercise(_, tmplId, _, false, _, _, _, _, _, _, _, Some(key), _, _, _) => state.referenced(globalKey(tmplId, key.key)) - case Node.Fetch(_, tmplId, _, _, _, Some(key), _, _) => + case Node.Fetch(_, tmplId, _, _, _, Some(key), _, _, _) => state.referenced(globalKey(tmplId, key.key)) case Node.LookupByKey(tmplId, key, Some(_), _) => state.referenced(globalKey(tmplId, key.key)) diff --git a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala index 7c97f09b50..7678270ce4 100644 --- a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala +++ b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala @@ -277,11 +277,16 @@ object TransactionCoder { node match { - case nc @ Node.Create(_, _, _, _, _, _, _, _) => + case nc @ Node.Create(_, _, _, _, _, _, _, _, _) => val builder = TransactionOuterClass.NodeCreate.newBuilder() nc.stakeholders.foreach(builder.addStakeholders) nc.signatories.foreach(builder.addSignatories) discard(builder.setContractIdStruct(encodeCid.encode(nc.coid))) + if (nodeVersion >= TransactionVersion.minInterfaces) { + nc.byInterface.foreach(iface => + builder.setByInterface(ValueCoder.encodeIdentifier(iface)) + ) + } for { _ <- if (nodeVersion < TransactionVersion.minNoVersionValue) { @@ -309,7 +314,7 @@ object TransactionCoder { ) } yield nodeBuilder.setCreate(builder).build() - case nf @ Node.Fetch(_, _, _, _, _, _, _, _) => + case nf @ Node.Fetch(_, _, _, _, _, _, _, _, _) => val builder = TransactionOuterClass.NodeFetch.newBuilder() discard(builder.setTemplateId(ValueCoder.encodeIdentifier(nf.templateId))) nf.stakeholders.foreach(builder.addStakeholders) @@ -319,6 +324,11 @@ object TransactionCoder { discard(builder.setByKey(nf.byKey)) } nf.actingParties.foreach(builder.addActors) + if (nodeVersion >= TransactionVersion.minInterfaces) { + nf.byInterface.foreach(iface => + builder.setByInterface(ValueCoder.encodeIdentifier(iface)) + ) + } for { _ <- encodeAndSetContractKey( encodeCid, @@ -328,7 +338,7 @@ object TransactionCoder { ) } yield nodeBuilder.setFetch(builder).build() - case ne @ Node.Exercise(_, _, _, _, _, _, _, _, _, _, _, _, _, _) => + case ne @ Node.Exercise(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _) => val builder = TransactionOuterClass.NodeExercise.newBuilder() discard( builder @@ -345,6 +355,11 @@ object TransactionCoder { if (nodeVersion >= TransactionVersion.minByKey) { discard(builder.setByKey(ne.byKey)) } + if (nodeVersion >= TransactionVersion.minInterfaces) { + ne.byInterface.foreach(iface => + builder.setByInterface(ValueCoder.encodeIdentifier(iface)) + ) + } for { _ <- Either.cond( test = ne.version >= TransactionVersion.minChoiceObservers || @@ -515,6 +530,12 @@ object TransactionCoder { nodeVersion, protoCreate.getKeyWithMaintainers, ) + byInterface <- + if (nodeVersion >= TransactionVersion.minInterfaces && protoCreate.hasByInterface) { + ValueCoder.decodeIdentifier(protoCreate.getByInterface).map(Some(_)) + } else { + Right(None) + } } yield ni -> Node.Create( c, ci.template, @@ -523,6 +544,7 @@ object TransactionCoder { signatories, stakeholders, key, + byInterface, nodeVersion, ) case NodeTypeCase.FETCH => @@ -543,6 +565,12 @@ object TransactionCoder { if (nodeVersion >= TransactionVersion.minByKey) protoFetch.getByKey else false + byInterface <- + if (nodeVersion >= TransactionVersion.minInterfaces && protoFetch.hasByInterface) { + ValueCoder.decodeIdentifier(protoFetch.getByInterface).map(Some(_)) + } else { + Right(None) + } } yield ni -> Node.Fetch( coid = c, templateId = templateId, @@ -551,6 +579,7 @@ object TransactionCoder { stakeholders = stakeholders, key = key, byKey = byKey, + byInterface = byInterface, version = nodeVersion, ) @@ -600,6 +629,12 @@ object TransactionCoder { if (nodeVersion >= TransactionVersion.minByKey) protoExe.getByKey else false + byInterface <- + if (nodeVersion >= TransactionVersion.minInterfaces && protoExe.hasByInterface) { + ValueCoder.decodeIdentifier(protoExe.getByInterface).map(Some(_)) + } else { + Right(None) + } } yield ni -> Node.Exercise( targetCoid = targetCoid, templateId = templateId, @@ -614,6 +649,7 @@ object TransactionCoder { exerciseResult = rvOpt, key = keyWithMaintainers, byKey = byKey, + byInterface = byInterface, version = nodeVersion, ) case NodeTypeCase.LOOKUP_BY_KEY => diff --git a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionVersion.scala b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionVersion.scala index e69f3aff7f..ab8702e1ae 100644 --- a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionVersion.scala +++ b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionVersion.scala @@ -49,6 +49,7 @@ object TransactionVersion { //nothing was added in V13, so there are no vals: "minSomething = V13" private[lf] val minExceptions = V14 private[lf] val minByKey = V14 + private[lf] val minInterfaces = VDev private[lf] val assignNodeVersion: LanguageVersion => TransactionVersion = { import LanguageVersion._ diff --git a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala index 5dc4b09d09..2128bab499 100644 --- a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala +++ b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala @@ -230,6 +230,7 @@ class TransactionCoderSpec signatories = Set(Party.assertFromString("alice")), stakeholders = Set(Party.assertFromString("alice"), Party.assertFromString("bob")), key = None, + byInterface = None, version = TransactionVersion.minVersion, ) 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 0c48afaf5f..f29879fb4e 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 @@ -679,6 +679,7 @@ object TransactionSpec { exerciseResult = if (hasExerciseResult) Some(V.ValueUnit) else None, key = None, byKey = false, + byInterface = None, version = TransactionVersion.minVersion, ) @@ -691,6 +692,7 @@ object TransactionSpec { signatories = Set.empty, stakeholders = Set.empty, key = None, + byInterface = None, version = TransactionVersion.minVersion, ) diff --git a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/validation/ValidationSpec.scala b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/validation/ValidationSpec.scala index 754b4e9211..bea539ec6d 100644 --- a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/validation/ValidationSpec.scala +++ b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/validation/ValidationSpec.scala @@ -96,6 +96,7 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC signatories = samParties1, stakeholders = samParties2, key = key, + byInterface = None, // TODO https://github.com/digital-asset/daml/issues/10915 version = version, ) @@ -112,6 +113,7 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC stakeholders = samParties3, key = key, byKey = samBool1, + byInterface = None, // TODO https://github.com/digital-asset/daml/issues/10915 version = version, ) @@ -145,6 +147,7 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC exerciseResult = exerciseResult, key = key, byKey = samBool2, + byInterface = None, // TODO https://github.com/digital-asset/daml/issues/10915 version = version, ) diff --git a/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V10_1__Populate_Event_Data.scala b/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V10_1__Populate_Event_Data.scala index 38bb3dc6e0..b0c266a0d9 100644 --- a/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V10_1__Populate_Event_Data.scala +++ b/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V10_1__Populate_Event_Data.scala @@ -52,7 +52,7 @@ private[migration] class V10_1__Populate_Event_Data extends BaseJavaMigration { val txs = loadTransactions(conn) val data = txs.flatMap { case (txId, tx) => tx.nodes.collect { - case (nodeId, Node.Create(cid, _, _, _, signatories, stakeholders, _, _)) => + case (nodeId, Node.Create(cid, _, _, _, signatories, stakeholders, _, _, _)) => (cid, EventId(txId, nodeId), signatories, stakeholders -- signatories) } } 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 1fd03f59e8..92eda78d1d 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 @@ -34,6 +34,7 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside { signatories = Set(alice), stakeholders = Set(alice), key = None, + byInterface = None, version = TransactionVersion.minVersion, ) ) @@ -53,6 +54,7 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside { key = Some( Node.KeyWithMaintainers(someContractKey(bob, "some key"), Set(bob)) ), + byInterface = None, version = TransactionVersion.minVersion, ) ) @@ -77,6 +79,7 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside { exerciseResult = Some(someChoiceResult), key = None, byKey = false, + byInterface = None, version = TransactionVersion.minVersion, ) ) @@ -91,6 +94,7 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside { Node.KeyWithMaintainers(ValueParty(bob), Set(bob)) ), byKey = false, + byInterface = None, version = TransactionVersion.minVersion, ), parentId = rootExercise, @@ -112,6 +116,7 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside { Node.KeyWithMaintainers(someContractKey(bob, "some key"), Set(bob)) ), byKey = false, + byInterface = None, version = TransactionVersion.minVersion, ), parentId = rootExercise, @@ -127,6 +132,7 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside { key = Some( Node.KeyWithMaintainers(someContractKey(bob, "some key"), Set(bob)) ), + byInterface = None, version = TransactionVersion.minVersion, ), parentId = nestedExercise, 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 a0f3b539f6..7c2f59e5d6 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 @@ -207,6 +207,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { signatories = signatories, stakeholders = stakeholders, key = key, + byInterface = None, version = txVersion, ) @@ -228,6 +229,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { exerciseResult = Some(someChoiceResult), key = key, byKey = false, + byInterface = None, version = txVersion, ) @@ -243,6 +245,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { stakeholders = Set(party), None, byKey = false, + byInterface = None, version = txVersion, ) @@ -384,6 +387,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { exerciseResult = Some(someChoiceResult), key = None, byKey = false, + byInterface = None, version = txVersion, ) ) @@ -396,6 +400,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { stakeholders = Set(alice), None, byKey = false, + byInterface = None, version = txVersion, ), exerciseId, @@ -710,6 +715,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { signatories = Set(party), stakeholders = Set(party), key = Some(Node.KeyWithMaintainers(someContractKey(party, key), Set(party))), + byInterface = None, version = txVersion, ) ) @@ -750,6 +756,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { exerciseResult = Some(LfValue.ValueUnit), key = maybeKey.map(k => Node.KeyWithMaintainers(someContractKey(party, k), Set(party))), byKey = false, + byInterface = None, version = txVersion, ) ) @@ -810,6 +817,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend { stakeholders = Set(party), None, byKey = false, + byInterface = None, version = txVersion, ) ) diff --git a/ledger/participant-state/kvutils/src/test/suite/scala/com/daml/ledger/participant/state/kvutils/ProjectionsSpec.scala b/ledger/participant-state/kvutils/src/test/suite/scala/com/daml/ledger/participant/state/kvutils/ProjectionsSpec.scala index 37748d2780..5f666d10b0 100644 --- a/ledger/participant-state/kvutils/src/test/suite/scala/com/daml/ledger/participant/state/kvutils/ProjectionsSpec.scala +++ b/ledger/participant-state/kvutils/src/test/suite/scala/com/daml/ledger/participant/state/kvutils/ProjectionsSpec.scala @@ -23,6 +23,7 @@ class ProjectionsSpec extends AnyWordSpec with Matchers { signatories = signatories, stakeholders = stakeholders, key = None, + byInterface = None, version = TransactionVersion.minVersion, ) @@ -49,6 +50,7 @@ class ProjectionsSpec extends AnyWordSpec with Matchers { exerciseResult = None, key = None, byKey = false, + byInterface = None, version = TransactionVersion.minVersion, ) diff --git a/security-evidence.md b/security-evidence.md index f976fb736c..64a9f58478 100644 --- a/security-evidence.md +++ b/security-evidence.md @@ -1,32 +1,32 @@ # Security tests, by category ## Authorization: -- badly-authorized create is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L60) -- badly-authorized exercise is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L158) +- badly-authorized create is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L61) +- badly-authorized exercise is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L159) - badly-authorized exercise/create (create is unauthorized) is rejected: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L265) - badly-authorized exercise/create (exercise is unauthorized) is rejected: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L233) - badly-authorized exercise/exercise (no implicit authority from outer exercise) is rejected: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L324) -- badly-authorized fetch is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L95) -- badly-authorized lookup is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L117) -- create with no signatories is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L50) -- create with non-signatory maintainers is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L72) -- exercise with no controllers is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L148) -- well-authorized create is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L43) -- well-authorized exercise is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L141) +- badly-authorized fetch is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L96) +- badly-authorized lookup is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L118) +- create with no signatories is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L51) +- create with non-signatory maintainers is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L73) +- exercise with no controllers is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L149) +- well-authorized create is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L44) +- well-authorized exercise is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L142) - well-authorized exercise/create is accepted: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L211) - well-authorized exercise/exercise is accepted: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L367) -- well-authorized fetch is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L89) -- well-authorized lookup is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L111) +- well-authorized fetch is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L90) +- well-authorized lookup is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L112) ## Privacy: - ensure correct privacy for create node: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L32) - ensure correct privacy for exercise node (consuming): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L43) - ensure correct privacy for exercise node (non-consuming): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L62) -- ensure correct privacy for exercise subtree: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L137) +- ensure correct privacy for exercise subtree: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L139) - ensure correct privacy for fetch node: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L82) - ensure correct privacy for lookup-by-key node (found): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L94) -- ensure correct privacy for lookup-by-key node (not-found): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L115) -- ensure correct privacy for rollback subtree: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L199) +- ensure correct privacy for lookup-by-key node (not-found): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L116) +- ensure correct privacy for rollback subtree: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L201) ## Semantics: - Exceptions, throw/catch.: [ExceptionTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExceptionTest.scala#L24)