mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-19 16:57:40 +03:00
LF: Add version directly in GenNode (#8154)
CHANGELOG_BEGIN CHANGELOG_END
This commit is contained in:
parent
38455e8ca9
commit
8f3c6a4494
@ -9,11 +9,11 @@ abstract class LfVersions[V](versionsAscending: NonEmptyList[V])(protoValue: V =
|
|||||||
|
|
||||||
protected val maxVersion: V = versionsAscending.last
|
protected val maxVersion: V = versionsAscending.last
|
||||||
|
|
||||||
val acceptedVersions: List[V] = versionsAscending.list.toList
|
private[lf] val acceptedVersions: List[V] = versionsAscending.list.toList
|
||||||
|
|
||||||
private val acceptedVersionsMap: Map[String, V] =
|
private val acceptedVersionsMap: Map[String, V] =
|
||||||
acceptedVersions.iterator.map(v => (protoValue(v), v)).toMap
|
acceptedVersions.iterator.map(v => (protoValue(v), v)).toMap
|
||||||
|
|
||||||
def isAcceptedVersion(version: String): Option[V] = acceptedVersionsMap.get(version)
|
private[lf] def isAcceptedVersion(version: String): Option[V] = acceptedVersionsMap.get(version)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -352,9 +352,7 @@ class Engine(val config: EngineConfig = EngineConfig.Stable) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onLedger.ptx.finish(
|
onLedger.ptx.finish match {
|
||||||
compiledPackages.packageLanguageVersion,
|
|
||||||
) match {
|
|
||||||
case PartialTransaction.CompleteTransaction(tx) =>
|
case PartialTransaction.CompleteTransaction(tx) =>
|
||||||
val meta = Tx.Metadata(
|
val meta = Tx.Metadata(
|
||||||
submissionSeed = None,
|
submissionSeed = None,
|
||||||
|
@ -143,7 +143,14 @@ private[engine] final class Preprocessor(compiledPackages: MutableCompiledPackag
|
|||||||
|
|
||||||
private def getTemplateId(node: Node.GenNode.WithTxValue[NodeId, _]) =
|
private def getTemplateId(node: Node.GenNode.WithTxValue[NodeId, _]) =
|
||||||
node match {
|
node match {
|
||||||
case Node.NodeCreate(coid @ _, coinst, optLoc @ _, sigs @ _, stks @ _, key @ _) =>
|
case Node.NodeCreate(
|
||||||
|
coid @ _,
|
||||||
|
coinst,
|
||||||
|
optLoc @ _,
|
||||||
|
sigs @ _,
|
||||||
|
stks @ _,
|
||||||
|
key @ _,
|
||||||
|
version @ _) =>
|
||||||
coinst.template
|
coinst.template
|
||||||
case Node.NodeExercises(
|
case Node.NodeExercises(
|
||||||
coid @ _,
|
coid @ _,
|
||||||
@ -160,11 +167,12 @@ private[engine] final class Preprocessor(compiledPackages: MutableCompiledPackag
|
|||||||
exerciseResult @ _,
|
exerciseResult @ _,
|
||||||
key @ _,
|
key @ _,
|
||||||
byKey @ _,
|
byKey @ _,
|
||||||
|
version @ _,
|
||||||
) =>
|
) =>
|
||||||
templateId
|
templateId
|
||||||
case Node.NodeFetch(coid @ _, templateId, _, _, _, _, _, _) =>
|
case Node.NodeFetch(coid @ _, templateId, _, _, _, _, _, _, _) =>
|
||||||
templateId
|
templateId
|
||||||
case Node.NodeLookupByKey(templateId, _, key @ _, _) =>
|
case Node.NodeLookupByKey(templateId, _, key @ _, _, _) =>
|
||||||
templateId
|
templateId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,14 @@ private[preprocessing] final class TransactionPreprocessor(
|
|||||||
val (localCids, globalCids) = acc
|
val (localCids, globalCids) = acc
|
||||||
|
|
||||||
node match {
|
node match {
|
||||||
case Node.NodeCreate(coid @ _, coinst, optLoc @ _, sigs @ _, stks @ _, key @ _) =>
|
case Node.NodeCreate(
|
||||||
|
coid @ _,
|
||||||
|
coinst,
|
||||||
|
optLoc @ _,
|
||||||
|
sigs @ _,
|
||||||
|
stks @ _,
|
||||||
|
key @ _,
|
||||||
|
version @ _) =>
|
||||||
val identifier = coinst.template
|
val identifier = coinst.template
|
||||||
if (globalCids(coid))
|
if (globalCids(coid))
|
||||||
fail("Conflicting discriminators between a global and local contract ID.")
|
fail("Conflicting discriminators between a global and local contract ID.")
|
||||||
@ -59,15 +66,17 @@ private[preprocessing] final class TransactionPreprocessor(
|
|||||||
children @ _,
|
children @ _,
|
||||||
exerciseResult @ _,
|
exerciseResult @ _,
|
||||||
key @ _,
|
key @ _,
|
||||||
byKey @ _) =>
|
byKey @ _,
|
||||||
|
version @ _,
|
||||||
|
) =>
|
||||||
val templateId = template
|
val templateId = template
|
||||||
val (cmd, newCids) =
|
val (cmd, newCids) =
|
||||||
commandPreprocessor.unsafePreprocessExercise(templateId, coid, choice, chosenVal.value)
|
commandPreprocessor.unsafePreprocessExercise(templateId, coid, choice, chosenVal.value)
|
||||||
(cmd, (localCids | newCids.filterNot(globalCids), globalCids))
|
(cmd, (localCids | newCids.filterNot(globalCids), globalCids))
|
||||||
case Node.NodeFetch(coid, templateId, _, _, _, _, _, _) =>
|
case Node.NodeFetch(coid, templateId, _, _, _, _, _, _, _) =>
|
||||||
val cmd = commandPreprocessor.unsafePreprocessFetch(templateId, coid)
|
val cmd = commandPreprocessor.unsafePreprocessFetch(templateId, coid)
|
||||||
(cmd, acc)
|
(cmd, acc)
|
||||||
case Node.NodeLookupByKey(templateId, _, key, _) =>
|
case Node.NodeLookupByKey(templateId, _, key, _, _) =>
|
||||||
val keyValue = unsafeAsValueWithNoContractIds(key.key.value)
|
val keyValue = unsafeAsValueWithNoContractIds(key.key.value)
|
||||||
val cmd = commandPreprocessor.unsafePreprocessLookupByKey(templateId, keyValue)
|
val cmd = commandPreprocessor.unsafePreprocessLookupByKey(templateId, keyValue)
|
||||||
(cmd, acc)
|
(cmd, acc)
|
||||||
@ -89,9 +98,9 @@ private[preprocessing] final class TransactionPreprocessor(
|
|||||||
fail(s"invalid transaction, root refers to non-existing node $id")
|
fail(s"invalid transaction, root refers to non-existing node $id")
|
||||||
case Some(node) =>
|
case Some(node) =>
|
||||||
node match {
|
node match {
|
||||||
case Node.NodeFetch(_, _, _, _, _, _, _, _) =>
|
case _: Node.NodeFetch[_, _] =>
|
||||||
fail(s"Transaction contains a fetch root node $id")
|
fail(s"Transaction contains a fetch root node $id")
|
||||||
case Node.NodeLookupByKey(_, _, _, _) =>
|
case _: Node.NodeLookupByKey[_, _] =>
|
||||||
fail(s"Transaction contains a lookup by key root node $id")
|
fail(s"Transaction contains a lookup by key root node $id")
|
||||||
case _ =>
|
case _ =>
|
||||||
val (cmd, acc) = unsafeTranslateNode(cids, node)
|
val (cmd, acc) = unsafeTranslateNode(cids, node)
|
||||||
|
@ -29,7 +29,6 @@ import Value._
|
|||||||
import com.daml.lf.speedy.{InitialSeeding, SValue, svalue}
|
import com.daml.lf.speedy.{InitialSeeding, SValue, svalue}
|
||||||
import com.daml.lf.speedy.SValue._
|
import com.daml.lf.speedy.SValue._
|
||||||
import com.daml.lf.command._
|
import com.daml.lf.command._
|
||||||
import com.daml.lf.transaction.Node.VersionedNode
|
|
||||||
import com.daml.lf.transaction.TransactionVersions.UnversionedNode
|
import com.daml.lf.transaction.TransactionVersions.UnversionedNode
|
||||||
import com.daml.lf.value.ValueVersions.assertAsVersionedValue
|
import com.daml.lf.value.ValueVersions.assertAsVersionedValue
|
||||||
import org.scalactic.Equality
|
import org.scalactic.Equality
|
||||||
@ -1220,6 +1219,7 @@ class EngineTest
|
|||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
|
_,
|
||||||
) =>
|
) =>
|
||||||
coid shouldBe originalCoid
|
coid shouldBe originalCoid
|
||||||
consuming shouldBe true
|
consuming shouldBe true
|
||||||
@ -1230,7 +1230,7 @@ class EngineTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
findNodeByIdx(bobView.nodes, 1).getOrElse(fail("node not found")) match {
|
findNodeByIdx(bobView.nodes, 1).getOrElse(fail("node not found")) match {
|
||||||
case Node.NodeCreate(_, coins, _, _, stakeholders, _) =>
|
case Node.NodeCreate(_, coins, _, _, stakeholders, _, _) =>
|
||||||
coins.template shouldBe templateId
|
coins.template shouldBe templateId
|
||||||
stakeholders shouldBe Set(alice, clara)
|
stakeholders shouldBe Set(alice, clara)
|
||||||
case _ => fail("create event is expected")
|
case _ => fail("create event is expected")
|
||||||
@ -1242,7 +1242,7 @@ class EngineTest
|
|||||||
|
|
||||||
claraView.nodes.size shouldBe 1
|
claraView.nodes.size shouldBe 1
|
||||||
findNodeByIdx(claraView.nodes, 1).getOrElse(fail("node not found")) match {
|
findNodeByIdx(claraView.nodes, 1).getOrElse(fail("node not found")) match {
|
||||||
case Node.NodeCreate(_, coins, _, _, stakeholders, _) =>
|
case Node.NodeCreate(_, coins, _, _, stakeholders, _, _) =>
|
||||||
coins.template shouldBe templateId
|
coins.template shouldBe templateId
|
||||||
stakeholders shouldBe Set(alice, clara)
|
stakeholders shouldBe Set(alice, clara)
|
||||||
case _ => fail("create event is expected")
|
case _ => fail("create event is expected")
|
||||||
@ -1367,7 +1367,7 @@ class EngineTest
|
|||||||
|
|
||||||
def actFetchActors[Nid, Cid, Val](n: Node.GenNode[Nid, Cid, Val]): Set[Party] = {
|
def actFetchActors[Nid, Cid, Val](n: Node.GenNode[Nid, Cid, Val]): Set[Party] = {
|
||||||
n match {
|
n match {
|
||||||
case Node.NodeFetch(_, _, _, actingParties, _, _, _, _) => actingParties
|
case Node.NodeFetch(_, _, _, actingParties, _, _, _, _, _) => actingParties
|
||||||
case _ => Set()
|
case _ => Set()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1420,8 +1420,8 @@ class EngineTest
|
|||||||
|
|
||||||
"be retained when reinterpreting single fetch nodes" in {
|
"be retained when reinterpreting single fetch nodes" in {
|
||||||
val Right((tx, txMeta)) = runExample(fetcher1Cid, clara)
|
val Right((tx, txMeta)) = runExample(fetcher1Cid, clara)
|
||||||
val fetchNodes = tx.versionedNodes.iterator.collect {
|
val fetchNodes = tx.nodes.iterator.collect {
|
||||||
case entry @ (_, VersionedNode(_, Node.NodeFetch(_, _, _, _, _, _, _, _))) => entry
|
case entry @ (_, Node.NodeFetch(_, _, _, _, _, _, _, _, _)) => entry
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchNodes.foreach {
|
fetchNodes.foreach {
|
||||||
@ -1429,7 +1429,7 @@ class EngineTest
|
|||||||
val fetchTx = VersionedTransaction(n.version, Map(nid -> n), ImmArray(nid))
|
val fetchTx = VersionedTransaction(n.version, Map(nid -> n), ImmArray(nid))
|
||||||
val Right((reinterpreted, _)) =
|
val Right((reinterpreted, _)) =
|
||||||
engine
|
engine
|
||||||
.reinterpret(n.node.requiredAuthorizers, n.node, txMeta.nodeSeeds.toSeq.collectFirst {
|
.reinterpret(n.requiredAuthorizers, n, txMeta.nodeSeeds.toSeq.collectFirst {
|
||||||
case (`nid`, seed) => seed
|
case (`nid`, seed) => seed
|
||||||
}, txMeta.submissionTime, let)
|
}, txMeta.submissionTime, let)
|
||||||
.consume(lookupContract, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
@ -1481,6 +1481,7 @@ class EngineTest
|
|||||||
stakeholders = Set.empty,
|
stakeholders = Set.empty,
|
||||||
key = None,
|
key = None,
|
||||||
byKey = false,
|
byKey = false,
|
||||||
|
version = TxVersions.minVersion,
|
||||||
)
|
)
|
||||||
|
|
||||||
val let = Time.Timestamp.now()
|
val let = Time.Timestamp.now()
|
||||||
@ -1531,7 +1532,7 @@ class EngineTest
|
|||||||
tx: GenTx[Nid, Cid, Val],
|
tx: GenTx[Nid, Cid, Val],
|
||||||
): Option[(Nid, Node.NodeLookupByKey[Cid, Val])] =
|
): Option[(Nid, Node.NodeLookupByKey[Cid, Val])] =
|
||||||
tx.nodes.collectFirst {
|
tx.nodes.collectFirst {
|
||||||
case (nid, nl @ Node.NodeLookupByKey(_, _, _, _)) => nid -> nl
|
case (nid, nl @ Node.NodeLookupByKey(_, _, _, _, _)) => nid -> nl
|
||||||
}
|
}
|
||||||
|
|
||||||
val now = Time.Timestamp.now()
|
val now = Time.Timestamp.now()
|
||||||
@ -1686,7 +1687,7 @@ class EngineTest
|
|||||||
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
||||||
|
|
||||||
tx.transaction.nodes.values.headOption match {
|
tx.transaction.nodes.values.headOption match {
|
||||||
case Some(Node.NodeFetch(_, _, _, _, _, _, key, _)) =>
|
case Some(Node.NodeFetch(_, _, _, _, _, _, key, _, _)) =>
|
||||||
key match {
|
key match {
|
||||||
// just test that the maintainers match here, getting the key out is a bit hairier
|
// just test that the maintainers match here, getting the key out is a bit hairier
|
||||||
case Some(Node.KeyWithMaintainers(_, maintainers)) =>
|
case Some(Node.KeyWithMaintainers(_, maintainers)) =>
|
||||||
@ -1811,7 +1812,7 @@ class EngineTest
|
|||||||
"be partially reinterpretable" in {
|
"be partially reinterpretable" in {
|
||||||
val Right((tx, txMeta)) = run(3)
|
val Right((tx, txMeta)) = run(3)
|
||||||
val ImmArray(_, exeNode1) = tx.transaction.roots
|
val ImmArray(_, exeNode1) = tx.transaction.roots
|
||||||
val Node.NodeExercises(_, _, _, _, _, _, _, _, _, _, children, _, _, _) =
|
val Node.NodeExercises(_, _, _, _, _, _, _, _, _, _, children, _, _, _, _) =
|
||||||
tx.transaction.nodes(exeNode1)
|
tx.transaction.nodes(exeNode1)
|
||||||
val nids = children.toSeq.take(2).toImmArray
|
val nids = children.toSeq.take(2).toImmArray
|
||||||
|
|
||||||
@ -2062,11 +2063,13 @@ object EngineTest {
|
|||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
_))) =>
|
_,
|
||||||
|
_,
|
||||||
|
))) =>
|
||||||
(contracts - targetCoid, keys)
|
(contracts - targetCoid, keys)
|
||||||
case (
|
case (
|
||||||
(contracts, keys),
|
(contracts, keys),
|
||||||
(_, Node.NodeCreate(cid: ContractId, coinst, _, _, _, key))) =>
|
(_, Node.NodeCreate(cid: ContractId, coinst, _, _, _, key, _))) =>
|
||||||
(
|
(
|
||||||
contracts.updated(
|
contracts.updated(
|
||||||
cid,
|
cid,
|
||||||
@ -2106,7 +2109,6 @@ object EngineTest {
|
|||||||
case (nodes, roots, dependsOnTime, nodeSeeds, _, _) =>
|
case (nodes, roots, dependsOnTime, nodeSeeds, _, _) =>
|
||||||
(
|
(
|
||||||
TxVersions.asVersionedTransaction(
|
TxVersions.asVersionedTransaction(
|
||||||
engine.compiledPackages().packageLanguageVersion,
|
|
||||||
roots.toImmArray,
|
roots.toImmArray,
|
||||||
nodes,
|
nodes,
|
||||||
),
|
),
|
||||||
|
@ -95,7 +95,7 @@ class LargeTransactionTest extends AnyWordSpec with Matchers with BazelRunfiles
|
|||||||
cmdReference = "create RangeOfInts",
|
cmdReference = "create RangeOfInts",
|
||||||
seed = hash("testLargeTransactionOneContract:create", txSize))
|
seed = hash("testLargeTransactionOneContract:create", txSize))
|
||||||
val contractId = firstRootNode(createCmdTx) match {
|
val contractId = firstRootNode(createCmdTx) match {
|
||||||
case N.NodeCreate(coid, _, _, _, _, _) => coid
|
case N.NodeCreate(coid, _, _, _, _, _, _) => coid
|
||||||
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
||||||
}
|
}
|
||||||
val exerciseCmd = toListContainerExerciseCmd(rangeOfIntsTemplateId, contractId)
|
val exerciseCmd = toListContainerExerciseCmd(rangeOfIntsTemplateId, contractId)
|
||||||
@ -122,7 +122,7 @@ class LargeTransactionTest extends AnyWordSpec with Matchers with BazelRunfiles
|
|||||||
cmdReference = "create RangeOfInts",
|
cmdReference = "create RangeOfInts",
|
||||||
seed = hash("testLargeTransactionManySmallContracts:create", num))
|
seed = hash("testLargeTransactionManySmallContracts:create", num))
|
||||||
val contractId = firstRootNode(createCmdTx) match {
|
val contractId = firstRootNode(createCmdTx) match {
|
||||||
case N.NodeCreate(coid, _, _, _, _, _) => coid
|
case N.NodeCreate(coid, _, _, _, _, _, _) => coid
|
||||||
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
||||||
}
|
}
|
||||||
val exerciseCmd = toListOfIntContainers(rangeOfIntsTemplateId, contractId)
|
val exerciseCmd = toListOfIntContainers(rangeOfIntsTemplateId, contractId)
|
||||||
@ -149,7 +149,7 @@ class LargeTransactionTest extends AnyWordSpec with Matchers with BazelRunfiles
|
|||||||
cmdReference = "create ListUtil",
|
cmdReference = "create ListUtil",
|
||||||
seed = hash("testLargeChoiceArgument:create", size))
|
seed = hash("testLargeChoiceArgument:create", size))
|
||||||
val contractId = firstRootNode(createCmdTx) match {
|
val contractId = firstRootNode(createCmdTx) match {
|
||||||
case N.NodeCreate(coid, _, _, _, _, _) => coid
|
case N.NodeCreate(coid, _, _, _, _, _, _) => coid
|
||||||
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
||||||
}
|
}
|
||||||
val exerciseCmd = sizeExerciseCmd(listUtilTemplateId, contractId)(size)
|
val exerciseCmd = sizeExerciseCmd(listUtilTemplateId, contractId)(size)
|
||||||
@ -192,7 +192,7 @@ class LargeTransactionTest extends AnyWordSpec with Matchers with BazelRunfiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
newContracts.count {
|
newContracts.count {
|
||||||
case N.NodeCreate(_, _, _, _, _, _) => true
|
case N.NodeCreate(_, _, _, _, _, _, _) => true
|
||||||
case n @ _ => fail(s"Unexpected match: $n")
|
case n @ _ => fail(s"Unexpected match: $n")
|
||||||
} shouldBe expectedNumberOfContracts
|
} shouldBe expectedNumberOfContracts
|
||||||
}
|
}
|
||||||
@ -317,7 +317,7 @@ class LargeTransactionTest extends AnyWordSpec with Matchers with BazelRunfiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
createNode match {
|
createNode match {
|
||||||
case N.NodeCreate(_, x: ContractInst[_], _, _, _, _) => x
|
case N.NodeCreate(_, x: ContractInst[_], _, _, _, _, _) => x
|
||||||
case n @ _ => fail(s"Unexpected match: $n")
|
case n @ _ => fail(s"Unexpected match: $n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,7 +448,7 @@ object ScenarioLedger {
|
|||||||
}
|
}
|
||||||
processNodes(mbNewCache2, idsToProcess)
|
processNodes(mbNewCache2, idsToProcess)
|
||||||
|
|
||||||
case NodeFetch(referencedCoid, templateId @ _, optLoc @ _, _, _, _, _, _) =>
|
case NodeFetch(referencedCoid, templateId @ _, optLoc @ _, _, _, _, _, _, _) =>
|
||||||
val newCacheP =
|
val newCacheP =
|
||||||
newCache.updateLedgerNodeInfo(referencedCoid)(info =>
|
newCache.updateLedgerNodeInfo(referencedCoid)(info =>
|
||||||
info.copy(referencedBy = info.referencedBy + eventId))
|
info.copy(referencedBy = info.referencedBy + eventId))
|
||||||
|
@ -15,7 +15,7 @@ import com.daml.lf.data.Ref._
|
|||||||
import com.daml.lf.data.Time
|
import com.daml.lf.data.Time
|
||||||
import com.daml.lf.scenario.ScenarioLedger.TransactionId
|
import com.daml.lf.scenario.ScenarioLedger.TransactionId
|
||||||
import com.daml.lf.scenario._
|
import com.daml.lf.scenario._
|
||||||
import com.daml.lf.transaction.{NodeId, Transaction => Tx}
|
import com.daml.lf.transaction.{NodeId, TransactionVersions, Transaction => Tx}
|
||||||
import com.daml.lf.speedy.SError._
|
import com.daml.lf.speedy.SError._
|
||||||
import com.daml.lf.speedy.SValue._
|
import com.daml.lf.speedy.SValue._
|
||||||
import com.daml.lf.speedy.SBuiltin._
|
import com.daml.lf.speedy.SBuiltin._
|
||||||
@ -41,6 +41,7 @@ private[lf] object Pretty {
|
|||||||
|
|
||||||
def prettyError(err: SError): Doc = {
|
def prettyError(err: SError): Doc = {
|
||||||
val ptx = PartialTransaction.initial(
|
val ptx = PartialTransaction.initial(
|
||||||
|
(_ => TransactionVersions.minVersion),
|
||||||
submissionTime = Time.Timestamp.MinValue,
|
submissionTime = Time.Timestamp.MinValue,
|
||||||
initialSeeds = InitialSeeding.NoSeed
|
initialSeeds = InitialSeeding.NoSeed
|
||||||
)
|
)
|
||||||
|
@ -1266,9 +1266,7 @@ private[lf] object SBuiltin {
|
|||||||
throw SpeedyHungry(SResultScenarioInsertMustFail(committerOld, commitLocationOld))
|
throw SpeedyHungry(SResultScenarioInsertMustFail(committerOld, commitLocationOld))
|
||||||
|
|
||||||
case SBool(false) =>
|
case SBool(false) =>
|
||||||
ptxOld.finish(
|
ptxOld.finish match {
|
||||||
machine.compiledPackages.packageLanguageVersion,
|
|
||||||
) match {
|
|
||||||
case PartialTransaction.CompleteTransaction(tx) =>
|
case PartialTransaction.CompleteTransaction(tx) =>
|
||||||
// Transaction finished successfully. It might still
|
// Transaction finished successfully. It might still
|
||||||
// fail when committed, so tell the scenario runner to
|
// fail when committed, so tell the scenario runner to
|
||||||
@ -1289,10 +1287,7 @@ private[lf] object SBuiltin {
|
|||||||
args: util.ArrayList[SValue],
|
args: util.ArrayList[SValue],
|
||||||
machine: Machine,
|
machine: Machine,
|
||||||
onLedger: OnLedger): Unit =
|
onLedger: OnLedger): Unit =
|
||||||
onLedger.ptx
|
onLedger.ptx.finish match {
|
||||||
.finish(
|
|
||||||
machine.compiledPackages.packageLanguageVersion,
|
|
||||||
) match {
|
|
||||||
case PartialTransaction.CompleteTransaction(tx) =>
|
case PartialTransaction.CompleteTransaction(tx) =>
|
||||||
throw SpeedyHungry(
|
throw SpeedyHungry(
|
||||||
SResultScenarioCommit(
|
SResultScenarioCommit(
|
||||||
|
@ -15,6 +15,7 @@ import com.daml.lf.speedy.SError._
|
|||||||
import com.daml.lf.speedy.SExpr._
|
import com.daml.lf.speedy.SExpr._
|
||||||
import com.daml.lf.speedy.SResult._
|
import com.daml.lf.speedy.SResult._
|
||||||
import com.daml.lf.speedy.SValue._
|
import com.daml.lf.speedy.SValue._
|
||||||
|
import com.daml.lf.transaction.TransactionVersions
|
||||||
import com.daml.lf.value.{Value => V}
|
import com.daml.lf.value.{Value => V}
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
@ -629,7 +630,8 @@ private[lf] object Speedy {
|
|||||||
onLedger.committers = Set.empty
|
onLedger.committers = Set.empty
|
||||||
onLedger.commitLocation = None
|
onLedger.commitLocation = None
|
||||||
onLedger.ptx = PartialTransaction.initial(
|
onLedger.ptx = PartialTransaction.initial(
|
||||||
submissionTime = onLedger.ptx.submissionTime,
|
onLedger.ptx.packageToTransactionVersion,
|
||||||
|
onLedger.ptx.submissionTime,
|
||||||
InitialSeeding.TransactionSeed(freshSeed),
|
InitialSeeding.TransactionSeed(freshSeed),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -738,7 +740,9 @@ private[lf] object Speedy {
|
|||||||
validating: Boolean = false,
|
validating: Boolean = false,
|
||||||
checkAuthorization: CheckAuthorizationMode = CheckAuthorizationMode.On,
|
checkAuthorization: CheckAuthorizationMode = CheckAuthorizationMode.On,
|
||||||
traceLog: TraceLog = RingBufferTraceLog(damlTraceLog, 100),
|
traceLog: TraceLog = RingBufferTraceLog(damlTraceLog, 100),
|
||||||
): Machine =
|
): Machine = {
|
||||||
|
val pkg2TxVersion =
|
||||||
|
compiledPackages.packageLanguageVersion.andThen(TransactionVersions.assignNodeVersion)
|
||||||
new Machine(
|
new Machine(
|
||||||
ctrl = expr,
|
ctrl = expr,
|
||||||
returnValue = null,
|
returnValue = null,
|
||||||
@ -751,7 +755,7 @@ private[lf] object Speedy {
|
|||||||
ledgerMode = OnLedger(
|
ledgerMode = OnLedger(
|
||||||
validating = validating,
|
validating = validating,
|
||||||
checkAuthorization = checkAuthorization,
|
checkAuthorization = checkAuthorization,
|
||||||
ptx = PartialTransaction.initial(submissionTime, initialSeeding),
|
ptx = PartialTransaction.initial(pkg2TxVersion, submissionTime, initialSeeding),
|
||||||
committers = committers,
|
committers = committers,
|
||||||
commitLocation = None,
|
commitLocation = None,
|
||||||
dependsOnTime = false,
|
dependsOnTime = false,
|
||||||
@ -766,6 +770,7 @@ private[lf] object Speedy {
|
|||||||
track = Instrumentation(),
|
track = Instrumentation(),
|
||||||
profile = new Profile(),
|
profile = new Profile(),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@throws[PackageNotFound]
|
@throws[PackageNotFound]
|
||||||
@throws[CompilationError]
|
@throws[CompilationError]
|
||||||
|
@ -6,16 +6,15 @@ package speedy
|
|||||||
|
|
||||||
import com.daml.lf.data.Ref.{ChoiceName, Location, Party, TypeConName}
|
import com.daml.lf.data.Ref.{ChoiceName, Location, Party, TypeConName}
|
||||||
import com.daml.lf.data.{BackStack, ImmArray, Ref, Time}
|
import com.daml.lf.data.{BackStack, ImmArray, Ref, Time}
|
||||||
import com.daml.lf.language.LanguageVersion
|
|
||||||
import com.daml.lf.ledger.Authorize
|
import com.daml.lf.ledger.Authorize
|
||||||
import com.daml.lf.ledger.FailedAuthorization
|
import com.daml.lf.ledger.FailedAuthorization
|
||||||
|
|
||||||
import com.daml.lf.transaction.{
|
import com.daml.lf.transaction.{
|
||||||
GenTransaction,
|
GenTransaction,
|
||||||
GlobalKey,
|
GlobalKey,
|
||||||
Node,
|
Node,
|
||||||
NodeId,
|
NodeId,
|
||||||
SubmittedTransaction,
|
SubmittedTransaction,
|
||||||
|
TransactionVersion,
|
||||||
TransactionVersions,
|
TransactionVersions,
|
||||||
Transaction => Tx
|
Transaction => Tx
|
||||||
}
|
}
|
||||||
@ -115,9 +114,11 @@ private[lf] object PartialTransaction {
|
|||||||
)
|
)
|
||||||
|
|
||||||
def initial(
|
def initial(
|
||||||
|
pkg2TxVersion: Ref.PackageId => TransactionVersion,
|
||||||
submissionTime: Time.Timestamp,
|
submissionTime: Time.Timestamp,
|
||||||
initialSeeds: InitialSeeding,
|
initialSeeds: InitialSeeding,
|
||||||
) = PartialTransaction(
|
) = PartialTransaction(
|
||||||
|
pkg2TxVersion,
|
||||||
submissionTime = submissionTime,
|
submissionTime = submissionTime,
|
||||||
nextNodeIdx = 0,
|
nextNodeIdx = 0,
|
||||||
nodes = HashMap.empty,
|
nodes = HashMap.empty,
|
||||||
@ -160,6 +161,7 @@ private[lf] object PartialTransaction {
|
|||||||
* locally archived contract ids will succeed wrongly.
|
* locally archived contract ids will succeed wrongly.
|
||||||
*/
|
*/
|
||||||
private[lf] case class PartialTransaction(
|
private[lf] case class PartialTransaction(
|
||||||
|
packageToTransactionVersion: Ref.PackageId => TransactionVersion,
|
||||||
submissionTime: Time.Timestamp,
|
submissionTime: Time.Timestamp,
|
||||||
nextNodeIdx: Int,
|
nextNodeIdx: Int,
|
||||||
nodes: HashMap[NodeId, PartialTransaction.Node],
|
nodes: HashMap[NodeId, PartialTransaction.Node],
|
||||||
@ -224,21 +226,14 @@ private[lf] case class PartialTransaction(
|
|||||||
* - an error in case the transaction cannot be serialized using
|
* - an error in case the transaction cannot be serialized using
|
||||||
* the `outputTransactionVersions`.
|
* the `outputTransactionVersions`.
|
||||||
*/
|
*/
|
||||||
def finish(
|
def finish: PartialTransaction.Result =
|
||||||
packageLanguageVersion: Ref.PackageId => LanguageVersion,
|
if (context.exeContext.isEmpty && aborted.isEmpty) {
|
||||||
): PartialTransaction.Result =
|
|
||||||
if (context.exeContext.isEmpty && aborted.isEmpty)
|
|
||||||
CompleteTransaction(
|
CompleteTransaction(
|
||||||
SubmittedTransaction(
|
SubmittedTransaction(
|
||||||
TransactionVersions
|
TransactionVersions.asVersionedTransaction(context.children.toImmArray, nodes)
|
||||||
.asVersionedTransaction(
|
|
||||||
packageLanguageVersion,
|
|
||||||
context.children.toImmArray,
|
|
||||||
nodes
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else
|
} else
|
||||||
IncompleteTransaction(this)
|
IncompleteTransaction(this)
|
||||||
|
|
||||||
/** Extend the 'PartialTransaction' with a node for creating a
|
/** Extend the 'PartialTransaction' with a node for creating a
|
||||||
@ -270,6 +265,7 @@ private[lf] case class PartialTransaction(
|
|||||||
signatories,
|
signatories,
|
||||||
stakeholders,
|
stakeholders,
|
||||||
key,
|
key,
|
||||||
|
packageToTransactionVersion(coinst.template.packageId)
|
||||||
)
|
)
|
||||||
val nid = NodeId(nextNodeIdx)
|
val nid = NodeId(nextNodeIdx)
|
||||||
val ptx = copy(
|
val ptx = copy(
|
||||||
@ -312,7 +308,8 @@ private[lf] case class PartialTransaction(
|
|||||||
signatories,
|
signatories,
|
||||||
stakeholders,
|
stakeholders,
|
||||||
key,
|
key,
|
||||||
byKey
|
byKey,
|
||||||
|
packageToTransactionVersion(templateId.packageId),
|
||||||
)
|
)
|
||||||
mustBeActive(
|
mustBeActive(
|
||||||
coid,
|
coid,
|
||||||
@ -329,7 +326,13 @@ private[lf] case class PartialTransaction(
|
|||||||
result: Option[Value.ContractId],
|
result: Option[Value.ContractId],
|
||||||
): PartialTransaction = {
|
): PartialTransaction = {
|
||||||
val nid = NodeId(nextNodeIdx)
|
val nid = NodeId(nextNodeIdx)
|
||||||
val node = Node.NodeLookupByKey(templateId, optLocation, key, result)
|
val node = Node.NodeLookupByKey(
|
||||||
|
templateId,
|
||||||
|
optLocation,
|
||||||
|
key,
|
||||||
|
result,
|
||||||
|
packageToTransactionVersion(templateId.packageId),
|
||||||
|
)
|
||||||
insertLeafNode(node)
|
insertLeafNode(node)
|
||||||
.noteAuthFails(nid, CheckAuthorization.authorizeLookupByKey(node), auth)
|
.noteAuthFails(nid, CheckAuthorization.authorizeLookupByKey(node), auth)
|
||||||
}
|
}
|
||||||
@ -414,6 +417,7 @@ private[lf] case class PartialTransaction(
|
|||||||
exerciseResult = Some(value),
|
exerciseResult = Some(value),
|
||||||
key = ec.contractKey,
|
key = ec.contractKey,
|
||||||
byKey = ec.byKey,
|
byKey = ec.byKey,
|
||||||
|
version = packageToTransactionVersion(ec.templateId.packageId),
|
||||||
)
|
)
|
||||||
val nodeId = ec.nodeId
|
val nodeId = ec.nodeId
|
||||||
val nodeSeed = ec.parent.nextChildrenSeed
|
val nodeSeed = ec.parent.nextChildrenSeed
|
||||||
|
@ -6,14 +6,15 @@ package transaction
|
|||||||
package test
|
package test
|
||||||
|
|
||||||
import com.daml.lf.data.{BackStack, ImmArray, Ref}
|
import com.daml.lf.data.{BackStack, ImmArray, Ref}
|
||||||
import com.daml.lf.transaction.Node.{GenNode, VersionedNode}
|
import com.daml.lf.transaction.Node.GenNode
|
||||||
import com.daml.lf.transaction.{Transaction => Tx}
|
import com.daml.lf.transaction.{Transaction => Tx}
|
||||||
import com.daml.lf.value.Value.{ContractId, ContractInst}
|
import com.daml.lf.value.Value.{ContractId, ContractInst}
|
||||||
import com.daml.lf.value.{ValueVersions, Value => LfValue}
|
import com.daml.lf.value.{ValueVersions, Value => LfValue}
|
||||||
|
|
||||||
import scala.collection.immutable.HashMap
|
import scala.collection.immutable.HashMap
|
||||||
|
|
||||||
final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion) {
|
final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion = _ =>
|
||||||
|
TransactionVersions.minVersion) {
|
||||||
|
|
||||||
import TransactionBuilder._
|
import TransactionBuilder._
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion
|
|||||||
def add(node: Node, parentId: NodeId): NodeId = ids.synchronized {
|
def add(node: Node, parentId: NodeId): NodeId = ids.synchronized {
|
||||||
lazy val nodeId = newNode(node) // lazy to avoid getting the next id if the method later throws
|
lazy val nodeId = newNode(node) // lazy to avoid getting the next id if the method later throws
|
||||||
nodes(parentId) match {
|
nodes(parentId) match {
|
||||||
case VersionedNode(_, _: TxExercise) =>
|
case _: TxExercise =>
|
||||||
children += parentId -> (children(parentId) :+ nodeId)
|
children += parentId -> (children(parentId) :+ nodeId)
|
||||||
case _ =>
|
case _ =>
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
@ -57,9 +58,9 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion
|
|||||||
import VersionTimeline.Implicits._
|
import VersionTimeline.Implicits._
|
||||||
|
|
||||||
val finalNodes = nodes.transform {
|
val finalNodes = nodes.transform {
|
||||||
case (nid, VersionedNode(version, exe: TxExercise)) =>
|
case (nid, exe: TxExercise) =>
|
||||||
VersionedNode[NodeId, ContractId](version, exe.copy(children = children(nid).toImmArray))
|
exe.copy(children = children(nid).toImmArray)
|
||||||
case (_, node @ VersionedNode(_, _: Node.LeafOnlyNode[_, _])) =>
|
case (_, node: Node.LeafOnlyNode[ContractId, TxValue]) =>
|
||||||
node
|
node
|
||||||
}
|
}
|
||||||
val finalRoots = roots.toImmArray
|
val finalRoots = roots.toImmArray
|
||||||
@ -93,17 +94,100 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion
|
|||||||
value.Value.VersionedValue(pkgValVersion(templateId.packageId), _)
|
value.Value.VersionedValue(pkgValVersion(templateId.packageId), _)
|
||||||
|
|
||||||
private[this] def versionN(node: Node): TxNode =
|
private[this] def versionN(node: Node): TxNode =
|
||||||
VersionedNode(
|
GenNode.map3(identity[NodeId], identity[ContractId], versionValue(node.templateId))(node)
|
||||||
pkgTxVersion(node.templateId.packageId),
|
|
||||||
GenNode.map3(identity[NodeId], identity[ContractId], versionValue(node.templateId))(node)
|
def create(
|
||||||
|
id: String,
|
||||||
|
template: String,
|
||||||
|
argument: Value,
|
||||||
|
signatories: Seq[String],
|
||||||
|
observers: Seq[String],
|
||||||
|
key: Option[String],
|
||||||
|
): Create = {
|
||||||
|
val templateId = Ref.Identifier.assertFromString(template)
|
||||||
|
Create(
|
||||||
|
coid = ContractId.assertFromString(id),
|
||||||
|
coinst = ContractInst(
|
||||||
|
template = templateId,
|
||||||
|
arg = argument,
|
||||||
|
agreementText = "",
|
||||||
|
),
|
||||||
|
optLocation = None,
|
||||||
|
signatories = signatories.map(Ref.Party.assertFromString).toSet,
|
||||||
|
stakeholders = signatories.union(observers).map(Ref.Party.assertFromString).toSet,
|
||||||
|
key = key.map(keyWithMaintainers(maintainers = signatories, _)),
|
||||||
|
version = pkgTxVersion(templateId.packageId),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def exercise(
|
||||||
|
contract: Create,
|
||||||
|
choice: String,
|
||||||
|
consuming: Boolean,
|
||||||
|
actingParties: Set[String],
|
||||||
|
argument: Value,
|
||||||
|
byKey: Boolean = true,
|
||||||
|
): Exercise =
|
||||||
|
Exercise(
|
||||||
|
choiceObservers = Set.empty, //FIXME #7709: take observers as argument (pref no default value)
|
||||||
|
targetCoid = contract.coid,
|
||||||
|
templateId = contract.coinst.template,
|
||||||
|
choiceId = Ref.ChoiceName.assertFromString(choice),
|
||||||
|
optLocation = None,
|
||||||
|
consuming = consuming,
|
||||||
|
actingParties = actingParties.map(Ref.Party.assertFromString),
|
||||||
|
chosenValue = argument,
|
||||||
|
stakeholders = contract.stakeholders,
|
||||||
|
signatories = contract.signatories,
|
||||||
|
children = ImmArray.empty,
|
||||||
|
exerciseResult = None,
|
||||||
|
key = contract.key,
|
||||||
|
byKey = byKey,
|
||||||
|
version = pkgTxVersion(contract.coinst.template.packageId),
|
||||||
|
)
|
||||||
|
|
||||||
|
def exerciseByKey(
|
||||||
|
contract: Create,
|
||||||
|
choice: String,
|
||||||
|
consuming: Boolean,
|
||||||
|
actingParties: Set[String],
|
||||||
|
argument: Value,
|
||||||
|
): Exercise =
|
||||||
|
exercise(contract, choice, consuming, actingParties, argument, byKey = true)
|
||||||
|
|
||||||
|
def fetch(contract: Create, byKey: Boolean = true): Fetch =
|
||||||
|
Fetch(
|
||||||
|
coid = contract.coid,
|
||||||
|
templateId = contract.coinst.template,
|
||||||
|
optLocation = None,
|
||||||
|
actingParties = contract.signatories.map(Ref.Party.assertFromString),
|
||||||
|
signatories = contract.signatories,
|
||||||
|
stakeholders = contract.stakeholders,
|
||||||
|
key = contract.key,
|
||||||
|
byKey = byKey,
|
||||||
|
version = pkgTxVersion(contract.coinst.template.packageId),
|
||||||
|
)
|
||||||
|
|
||||||
|
def fetchByKey(contract: Create): Fetch =
|
||||||
|
fetch(contract, byKey = true)
|
||||||
|
|
||||||
|
def lookupByKey(contract: Create, found: Boolean): LookupByKey =
|
||||||
|
LookupByKey(
|
||||||
|
templateId = contract.coinst.template,
|
||||||
|
optLocation = None,
|
||||||
|
key = contract.key.get,
|
||||||
|
result = if (found) Some(contract.coid) else None,
|
||||||
|
version = pkgTxVersion(contract.coinst.template.packageId),
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object TransactionBuilder {
|
object TransactionBuilder {
|
||||||
|
|
||||||
type Value = value.Value[ContractId]
|
type Value = value.Value[ContractId]
|
||||||
type TxValue = value.Value.VersionedValue[ContractId]
|
type TxValue = value.Value.VersionedValue[ContractId]
|
||||||
type Node = Node.GenNode[NodeId, ContractId, Value]
|
type Node = Node.GenNode[NodeId, ContractId, Value]
|
||||||
type TxNode = VersionedNode[NodeId, ContractId]
|
type TxNode = Node.GenNode.WithTxValue[NodeId, ContractId]
|
||||||
|
|
||||||
type Create = Node.NodeCreate[ContractId, Value]
|
type Create = Node.NodeCreate[ContractId, Value]
|
||||||
type Exercise = Node.NodeExercises[NodeId, ContractId, Value]
|
type Exercise = Node.NodeExercises[NodeId, ContractId, Value]
|
||||||
@ -157,84 +241,6 @@ object TransactionBuilder {
|
|||||||
maintainers = maintainers.map(Ref.Party.assertFromString).toSet,
|
maintainers = maintainers.map(Ref.Party.assertFromString).toSet,
|
||||||
)
|
)
|
||||||
|
|
||||||
def create(
|
|
||||||
id: String,
|
|
||||||
template: String,
|
|
||||||
argument: Value,
|
|
||||||
signatories: Seq[String],
|
|
||||||
observers: Seq[String],
|
|
||||||
key: Option[String],
|
|
||||||
): Create =
|
|
||||||
Create(
|
|
||||||
coid = ContractId.assertFromString(id),
|
|
||||||
coinst = ContractInst(
|
|
||||||
template = Ref.Identifier.assertFromString(template),
|
|
||||||
arg = argument,
|
|
||||||
agreementText = "",
|
|
||||||
),
|
|
||||||
optLocation = None,
|
|
||||||
signatories = signatories.map(Ref.Party.assertFromString).toSet,
|
|
||||||
stakeholders = signatories.union(observers).map(Ref.Party.assertFromString).toSet,
|
|
||||||
key = key.map(keyWithMaintainers(maintainers = signatories, _)),
|
|
||||||
)
|
|
||||||
|
|
||||||
def exercise(
|
|
||||||
contract: Create,
|
|
||||||
choice: String,
|
|
||||||
consuming: Boolean,
|
|
||||||
actingParties: Set[String],
|
|
||||||
argument: Value,
|
|
||||||
byKey: Boolean = true,
|
|
||||||
): Exercise =
|
|
||||||
Exercise(
|
|
||||||
choiceObservers = Set.empty, //FIXME #7709: take observers as argument (pref no default value)
|
|
||||||
targetCoid = contract.coid,
|
|
||||||
templateId = contract.coinst.template,
|
|
||||||
choiceId = Ref.ChoiceName.assertFromString(choice),
|
|
||||||
optLocation = None,
|
|
||||||
consuming = consuming,
|
|
||||||
actingParties = actingParties.map(Ref.Party.assertFromString),
|
|
||||||
chosenValue = argument,
|
|
||||||
stakeholders = contract.stakeholders,
|
|
||||||
signatories = contract.signatories,
|
|
||||||
children = ImmArray.empty,
|
|
||||||
exerciseResult = None,
|
|
||||||
key = contract.key,
|
|
||||||
byKey = byKey
|
|
||||||
)
|
|
||||||
|
|
||||||
def exerciseByKey(
|
|
||||||
contract: Create,
|
|
||||||
choice: String,
|
|
||||||
consuming: Boolean,
|
|
||||||
actingParties: Set[String],
|
|
||||||
argument: Value,
|
|
||||||
): Exercise =
|
|
||||||
exercise(contract, choice, consuming, actingParties, argument, byKey = true)
|
|
||||||
|
|
||||||
def fetch(contract: Create, byKey: Boolean = true): Fetch =
|
|
||||||
Fetch(
|
|
||||||
coid = contract.coid,
|
|
||||||
templateId = contract.coinst.template,
|
|
||||||
optLocation = None,
|
|
||||||
actingParties = contract.signatories.map(Ref.Party.assertFromString),
|
|
||||||
signatories = contract.signatories,
|
|
||||||
stakeholders = contract.stakeholders,
|
|
||||||
key = contract.key,
|
|
||||||
byKey = byKey,
|
|
||||||
)
|
|
||||||
|
|
||||||
def fetchByKey(contract: Create): Fetch =
|
|
||||||
fetch(contract, byKey = true)
|
|
||||||
|
|
||||||
def lookupByKey(contract: Create, found: Boolean): LookupByKey =
|
|
||||||
LookupByKey(
|
|
||||||
templateId = contract.coinst.template,
|
|
||||||
optLocation = None,
|
|
||||||
key = contract.key.get,
|
|
||||||
result = if (found) Some(contract.coid) else None
|
|
||||||
)
|
|
||||||
|
|
||||||
def just(node: Node, nodes: Node*): Tx.Transaction = {
|
def just(node: Node, nodes: Node*): Tx.Transaction = {
|
||||||
val builder = TransactionBuilder()
|
val builder = TransactionBuilder()
|
||||||
val _ = builder.add(node)
|
val _ = builder.add(node)
|
||||||
|
@ -8,11 +8,11 @@ package test
|
|||||||
import com.daml.lf.data.Ref._
|
import com.daml.lf.data.Ref._
|
||||||
import com.daml.lf.data._
|
import com.daml.lf.data._
|
||||||
import com.daml.lf.transaction.Node.{
|
import com.daml.lf.transaction.Node.{
|
||||||
|
GenNode,
|
||||||
KeyWithMaintainers,
|
KeyWithMaintainers,
|
||||||
NodeCreate,
|
NodeCreate,
|
||||||
NodeExercises,
|
NodeExercises,
|
||||||
NodeFetch,
|
NodeFetch
|
||||||
VersionedNode
|
|
||||||
}
|
}
|
||||||
import com.daml.lf.transaction.VersionTimeline.Implicits._
|
import com.daml.lf.transaction.VersionTimeline.Implicits._
|
||||||
import com.daml.lf.transaction.{
|
import com.daml.lf.transaction.{
|
||||||
@ -284,16 +284,18 @@ object ValueGenerators {
|
|||||||
*/
|
*/
|
||||||
val malformedCreateNodeGen: Gen[NodeCreate.WithTxValue[Value.ContractId]] = {
|
val malformedCreateNodeGen: Gen[NodeCreate.WithTxValue[Value.ContractId]] = {
|
||||||
for {
|
for {
|
||||||
|
version <- transactionVersionGen
|
||||||
coid <- coidGen
|
coid <- coidGen
|
||||||
coinst <- contractInstanceGen
|
coinst <- contractInstanceGen
|
||||||
signatories <- genNonEmptyParties
|
signatories <- genNonEmptyParties
|
||||||
stakeholders <- genNonEmptyParties
|
stakeholders <- genNonEmptyParties
|
||||||
key <- Gen.option(keyWithMaintainersGen)
|
key <- Gen.option(keyWithMaintainersGen)
|
||||||
} yield NodeCreate(coid, coinst, None, signatories, stakeholders, key)
|
} yield NodeCreate(coid, coinst, None, signatories, stakeholders, key, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
val fetchNodeGen: Gen[NodeFetch.WithTxValue[ContractId]] = {
|
val fetchNodeGen: Gen[NodeFetch.WithTxValue[ContractId]] = {
|
||||||
for {
|
for {
|
||||||
|
version <- transactionVersionGen
|
||||||
coid <- coidGen
|
coid <- coidGen
|
||||||
templateId <- idGen
|
templateId <- idGen
|
||||||
actingParties <- genNonEmptyParties
|
actingParties <- genNonEmptyParties
|
||||||
@ -301,13 +303,24 @@ object ValueGenerators {
|
|||||||
stakeholders <- genNonEmptyParties
|
stakeholders <- genNonEmptyParties
|
||||||
key <- Gen.option(keyWithMaintainersGen)
|
key <- Gen.option(keyWithMaintainersGen)
|
||||||
byKey <- Gen.oneOf(true, false)
|
byKey <- Gen.oneOf(true, false)
|
||||||
} yield NodeFetch(coid, templateId, None, actingParties, signatories, stakeholders, key, byKey)
|
} yield
|
||||||
|
NodeFetch(
|
||||||
|
coid,
|
||||||
|
templateId,
|
||||||
|
None,
|
||||||
|
actingParties,
|
||||||
|
signatories,
|
||||||
|
stakeholders,
|
||||||
|
key,
|
||||||
|
byKey,
|
||||||
|
version)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Makes exercise nodes with some random child IDs. */
|
/** Makes exercise nodes with some random child IDs. */
|
||||||
val danglingRefExerciseNodeGen
|
val danglingRefExerciseNodeGen
|
||||||
: Gen[NodeExercises[NodeId, Value.ContractId, Tx.Value[Value.ContractId]]] = {
|
: Gen[NodeExercises[NodeId, Value.ContractId, Tx.Value[Value.ContractId]]] = {
|
||||||
for {
|
for {
|
||||||
|
version <- transactionVersionGen
|
||||||
targetCoid <- coidGen
|
targetCoid <- coidGen
|
||||||
templateId <- idGen
|
templateId <- idGen
|
||||||
choiceId <- nameGen
|
choiceId <- nameGen
|
||||||
@ -340,7 +353,8 @@ object ValueGenerators {
|
|||||||
children,
|
children,
|
||||||
Some(exerciseResultValue),
|
Some(exerciseResultValue),
|
||||||
Some(KeyWithMaintainers(key, maintainers)),
|
Some(KeyWithMaintainers(key, maintainers)),
|
||||||
byKey = byKey,
|
byKey,
|
||||||
|
version,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,12 +464,12 @@ object ValueGenerators {
|
|||||||
tx <- noDanglingRefGenTransaction
|
tx <- noDanglingRefGenTransaction
|
||||||
txVer <- transactionVersionGen
|
txVer <- transactionVersionGen
|
||||||
nodeVersionGen = transactionVersionGen.filter(v => !(txVer precedes v))
|
nodeVersionGen = transactionVersionGen.filter(v => !(txVer precedes v))
|
||||||
nodes <- tx.fold(Gen.const(HashMap.empty[NodeId, VersionedNode[NodeId, ContractId]])) {
|
nodes <- tx.fold(Gen.const(HashMap.empty[NodeId, GenNode.WithTxValue[NodeId, ContractId]])) {
|
||||||
case (acc, (nodeId, node)) =>
|
case (acc, (nodeId, node)) =>
|
||||||
for {
|
for {
|
||||||
hashMap <- acc
|
hashMap <- acc
|
||||||
version <- nodeVersionGen
|
version <- nodeVersionGen
|
||||||
} yield hashMap.updated(nodeId, VersionedNode(version, node))
|
} yield hashMap.updated(nodeId, node.updateVersion(version))
|
||||||
}
|
}
|
||||||
} yield VersionedTransaction(txVer, nodes, tx.roots)
|
} yield VersionedTransaction(txVer, nodes, tx.roots)
|
||||||
|
|
||||||
|
@ -6,15 +6,7 @@ package transaction
|
|||||||
|
|
||||||
import com.daml.lf.data.Ref._
|
import com.daml.lf.data.Ref._
|
||||||
import com.daml.lf.data.{ImmArray, ScalazEqual}
|
import com.daml.lf.data.{ImmArray, ScalazEqual}
|
||||||
import com.daml.lf.value.Value.VersionedValue
|
import com.daml.lf.value._
|
||||||
import com.daml.lf.value.{
|
|
||||||
CidContainer,
|
|
||||||
CidContainer1,
|
|
||||||
CidContainer2,
|
|
||||||
CidContainer3,
|
|
||||||
CidMapper,
|
|
||||||
Value
|
|
||||||
}
|
|
||||||
import scalaz.Equal
|
import scalaz.Equal
|
||||||
import scalaz.std.option._
|
import scalaz.std.option._
|
||||||
import scalaz.syntax.equal._
|
import scalaz.syntax.equal._
|
||||||
@ -35,6 +27,7 @@ object Node {
|
|||||||
with CidContainer[GenNode[Nid, Cid, Val]] {
|
with CidContainer[GenNode[Nid, Cid, Val]] {
|
||||||
|
|
||||||
def templateId: TypeConName
|
def templateId: TypeConName
|
||||||
|
def version: TransactionVersion
|
||||||
|
|
||||||
final override protected def self: this.type = this
|
final override protected def self: this.type = this
|
||||||
|
|
||||||
@ -62,6 +55,8 @@ object Node {
|
|||||||
|
|
||||||
def foreach3(fNid: Nid => Unit, fCid: Cid => Unit, fVal: Val => Unit) =
|
def foreach3(fNid: Nid => Unit, fCid: Cid => Unit, fVal: Val => Unit) =
|
||||||
GenNode.foreach3(fNid, fCid, fVal)(this)
|
GenNode.foreach3(fNid, fCid, fVal)(this)
|
||||||
|
|
||||||
|
private[lf] def updateVersion(version: TransactionVersion): GenNode[Nid, Cid, Val]
|
||||||
}
|
}
|
||||||
|
|
||||||
object GenNode extends WithTxValue3[GenNode] with CidContainer3[GenNode] {
|
object GenNode extends WithTxValue3[GenNode] with CidContainer3[GenNode] {
|
||||||
@ -78,6 +73,7 @@ object Node {
|
|||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
key,
|
key,
|
||||||
|
_,
|
||||||
) =>
|
) =>
|
||||||
self copy (
|
self copy (
|
||||||
coid = f2(coid),
|
coid = f2(coid),
|
||||||
@ -93,6 +89,7 @@ object Node {
|
|||||||
_,
|
_,
|
||||||
key,
|
key,
|
||||||
_,
|
_,
|
||||||
|
_,
|
||||||
) =>
|
) =>
|
||||||
self copy (
|
self copy (
|
||||||
coid = f2(coid),
|
coid = f2(coid),
|
||||||
@ -113,6 +110,7 @@ object Node {
|
|||||||
exerciseResult,
|
exerciseResult,
|
||||||
key,
|
key,
|
||||||
_,
|
_,
|
||||||
|
_,
|
||||||
) =>
|
) =>
|
||||||
self copy (
|
self copy (
|
||||||
targetCoid = f2(targetCoid),
|
targetCoid = f2(targetCoid),
|
||||||
@ -126,6 +124,7 @@ object Node {
|
|||||||
_,
|
_,
|
||||||
key,
|
key,
|
||||||
result,
|
result,
|
||||||
|
_,
|
||||||
) =>
|
) =>
|
||||||
self copy (
|
self copy (
|
||||||
key = KeyWithMaintainers.map1(f3)(key),
|
key = KeyWithMaintainers.map1(f3)(key),
|
||||||
@ -145,6 +144,7 @@ object Node {
|
|||||||
signatories @ _,
|
signatories @ _,
|
||||||
stakeholders @ _,
|
stakeholders @ _,
|
||||||
key,
|
key,
|
||||||
|
_,
|
||||||
) =>
|
) =>
|
||||||
f2(coid)
|
f2(coid)
|
||||||
Value.ContractInst.foreach1(f3)(coinst)
|
Value.ContractInst.foreach1(f3)(coinst)
|
||||||
@ -158,6 +158,7 @@ object Node {
|
|||||||
stakeholdersd @ _,
|
stakeholdersd @ _,
|
||||||
key,
|
key,
|
||||||
_,
|
_,
|
||||||
|
_,
|
||||||
) =>
|
) =>
|
||||||
f2(coid)
|
f2(coid)
|
||||||
key.foreach(KeyWithMaintainers.foreach1(f3))
|
key.foreach(KeyWithMaintainers.foreach1(f3))
|
||||||
@ -176,6 +177,7 @@ object Node {
|
|||||||
exerciseResult,
|
exerciseResult,
|
||||||
key,
|
key,
|
||||||
_,
|
_,
|
||||||
|
_,
|
||||||
) =>
|
) =>
|
||||||
f2(targetCoid)
|
f2(targetCoid)
|
||||||
f3(chosenValue)
|
f3(chosenValue)
|
||||||
@ -187,6 +189,7 @@ object Node {
|
|||||||
optLocation @ _,
|
optLocation @ _,
|
||||||
key,
|
key,
|
||||||
result,
|
result,
|
||||||
|
_,
|
||||||
) =>
|
) =>
|
||||||
KeyWithMaintainers.foreach1(f3)(key)
|
KeyWithMaintainers.foreach1(f3)(key)
|
||||||
result.foreach(f2)
|
result.foreach(f2)
|
||||||
@ -206,11 +209,16 @@ object Node {
|
|||||||
signatories: Set[Party],
|
signatories: Set[Party],
|
||||||
stakeholders: Set[Party],
|
stakeholders: Set[Party],
|
||||||
key: Option[KeyWithMaintainers[Val]],
|
key: Option[KeyWithMaintainers[Val]],
|
||||||
|
// For the sake of consistency between types with a version field, keep this field the last.
|
||||||
|
override val version: TransactionVersion,
|
||||||
) extends LeafOnlyNode[Cid, Val]
|
) extends LeafOnlyNode[Cid, Val]
|
||||||
with NodeInfo.Create {
|
with NodeInfo.Create {
|
||||||
|
|
||||||
override def templateId: TypeConName = coinst.template
|
override def templateId: TypeConName = coinst.template
|
||||||
override def byKey: Boolean = false
|
override def byKey: Boolean = false
|
||||||
|
|
||||||
|
override private[lf] def updateVersion(version: TransactionVersion): NodeCreate[Cid, Val] =
|
||||||
|
copy(version = version)
|
||||||
}
|
}
|
||||||
|
|
||||||
object NodeCreate extends WithTxValue2[NodeCreate]
|
object NodeCreate extends WithTxValue2[NodeCreate]
|
||||||
@ -224,9 +232,15 @@ object Node {
|
|||||||
signatories: Set[Party],
|
signatories: Set[Party],
|
||||||
stakeholders: Set[Party],
|
stakeholders: Set[Party],
|
||||||
key: Option[KeyWithMaintainers[Val]],
|
key: Option[KeyWithMaintainers[Val]],
|
||||||
override val byKey: Boolean // invariant (!byKey || exerciseResult.isDefined)
|
override val byKey: Boolean, // invariant (!byKey || exerciseResult.isDefined)
|
||||||
|
// For the sake of consistency between types with a version field, keep this field the last.
|
||||||
|
override val version: TransactionVersion,
|
||||||
) extends LeafOnlyNode[Cid, Val]
|
) extends LeafOnlyNode[Cid, Val]
|
||||||
with NodeInfo.Fetch
|
with NodeInfo.Fetch {
|
||||||
|
|
||||||
|
override private[lf] def updateVersion(version: TransactionVersion): NodeFetch[Cid, Val] =
|
||||||
|
copy(version = version)
|
||||||
|
}
|
||||||
|
|
||||||
object NodeFetch extends WithTxValue2[NodeFetch]
|
object NodeFetch extends WithTxValue2[NodeFetch]
|
||||||
|
|
||||||
@ -249,11 +263,18 @@ object Node {
|
|||||||
children: ImmArray[Nid],
|
children: ImmArray[Nid],
|
||||||
exerciseResult: Option[Val],
|
exerciseResult: Option[Val],
|
||||||
key: Option[KeyWithMaintainers[Val]],
|
key: Option[KeyWithMaintainers[Val]],
|
||||||
override val byKey: Boolean // invariant (!byKey || exerciseResult.isDefined)
|
override val byKey: Boolean, // invariant (!byKey || exerciseResult.isDefined)
|
||||||
|
// For the sake of consistency between types with a version field, keep this field the last.
|
||||||
|
override val version: TransactionVersion,
|
||||||
) extends GenNode[Nid, Cid, Val]
|
) extends GenNode[Nid, Cid, Val]
|
||||||
with NodeInfo.Exercise {
|
with NodeInfo.Exercise {
|
||||||
@deprecated("use actingParties instead", since = "1.1.2")
|
@deprecated("use actingParties instead", since = "1.1.2")
|
||||||
private[daml] def controllers: actingParties.type = actingParties
|
private[daml] def controllers: actingParties.type = actingParties
|
||||||
|
|
||||||
|
override private[lf] def updateVersion(
|
||||||
|
version: TransactionVersion,
|
||||||
|
): NodeExercises[Nid, Cid, Val] =
|
||||||
|
copy(version = version)
|
||||||
}
|
}
|
||||||
|
|
||||||
object NodeExercises extends WithTxValue3[NodeExercises]
|
object NodeExercises extends WithTxValue3[NodeExercises]
|
||||||
@ -263,12 +284,17 @@ object Node {
|
|||||||
optLocation: Option[Location],
|
optLocation: Option[Location],
|
||||||
key: KeyWithMaintainers[Val],
|
key: KeyWithMaintainers[Val],
|
||||||
result: Option[Cid],
|
result: Option[Cid],
|
||||||
|
// For the sake of consistency between types with a version field, keep this field the last.
|
||||||
|
override val version: TransactionVersion,
|
||||||
) extends LeafOnlyNode[Cid, Val]
|
) extends LeafOnlyNode[Cid, Val]
|
||||||
with NodeInfo.LookupByKey {
|
with NodeInfo.LookupByKey {
|
||||||
|
|
||||||
override def keyMaintainers: Set[Party] = key.maintainers
|
override def keyMaintainers: Set[Party] = key.maintainers
|
||||||
override def hasResult: Boolean = result.isDefined
|
override def hasResult: Boolean = result.isDefined
|
||||||
override def byKey: Boolean = true
|
override def byKey: Boolean = true
|
||||||
|
|
||||||
|
override private[lf] def updateVersion(version: TransactionVersion): NodeLookupByKey[Cid, Val] =
|
||||||
|
copy(version = version)
|
||||||
}
|
}
|
||||||
|
|
||||||
object NodeLookupByKey extends WithTxValue2[NodeLookupByKey]
|
object NodeLookupByKey extends WithTxValue2[NodeLookupByKey]
|
||||||
@ -311,10 +337,18 @@ object Node {
|
|||||||
): Boolean =
|
): Boolean =
|
||||||
ScalazEqual.match2[recorded.type, isReplayedBy.type, Boolean](fallback = false) {
|
ScalazEqual.match2[recorded.type, isReplayedBy.type, Boolean](fallback = false) {
|
||||||
case nc: NodeCreate[Cid, Val] => {
|
case nc: NodeCreate[Cid, Val] => {
|
||||||
case NodeCreate(coid2, coinst2, optLocation2 @ _, signatories2, stakeholders2, key2) =>
|
case NodeCreate(
|
||||||
|
coid2,
|
||||||
|
coinst2,
|
||||||
|
optLocation2 @ _,
|
||||||
|
signatories2,
|
||||||
|
stakeholders2,
|
||||||
|
key2,
|
||||||
|
version2) =>
|
||||||
import nc._
|
import nc._
|
||||||
// NOTE(JM): Do not compare location annotations as they may differ due to
|
// NOTE(JM): Do not compare location annotations as they may differ due to
|
||||||
// differing update expression constructed from the root node.
|
// differing update expression constructed from the root node.
|
||||||
|
version == version2 &&
|
||||||
coid === coid2 && coinst === coinst2 &&
|
coid === coid2 && coinst === coinst2 &&
|
||||||
signatories == signatories2 && stakeholders == stakeholders2 && key === key2
|
signatories == signatories2 && stakeholders == stakeholders2 && key === key2
|
||||||
case _ => false
|
case _ => false
|
||||||
@ -329,8 +363,10 @@ object Node {
|
|||||||
stakeholders2,
|
stakeholders2,
|
||||||
key2,
|
key2,
|
||||||
_,
|
_,
|
||||||
|
version2,
|
||||||
) =>
|
) =>
|
||||||
import nf._
|
import nf._
|
||||||
|
version == version2 &&
|
||||||
coid === coid2 && templateId == templateId2 &&
|
coid === coid2 && templateId == templateId2 &&
|
||||||
actingParties.forall(_ => actingParties == actingParties2) &&
|
actingParties.forall(_ => actingParties == actingParties2) &&
|
||||||
signatories == signatories2 && stakeholders == stakeholders2 &&
|
signatories == signatories2 && stakeholders == stakeholders2 &&
|
||||||
@ -352,8 +388,10 @@ object Node {
|
|||||||
exerciseResult2,
|
exerciseResult2,
|
||||||
key2,
|
key2,
|
||||||
_,
|
_,
|
||||||
|
version2,
|
||||||
) =>
|
) =>
|
||||||
import ne._
|
import ne._
|
||||||
|
version == version2 &&
|
||||||
targetCoid === targetCoid2 && templateId == templateId2 && choiceId == choiceId2 &&
|
targetCoid === targetCoid2 && templateId == templateId2 && choiceId == choiceId2 &&
|
||||||
consuming == consuming2 && actingParties == actingParties2 && chosenValue === chosenValue2 &&
|
consuming == consuming2 && actingParties == actingParties2 && chosenValue === chosenValue2 &&
|
||||||
stakeholders == stakeholders2 && signatories == signatories2 && choiceObservers == choiceObservers2 &&
|
stakeholders == stakeholders2 && signatories == signatories2 && choiceObservers == choiceObservers2 &&
|
||||||
@ -361,8 +399,9 @@ object Node {
|
|||||||
key.fold(true)(_ => key === key2)
|
key.fold(true)(_ => key === key2)
|
||||||
}
|
}
|
||||||
case nl: NodeLookupByKey[Cid, Val] => {
|
case nl: NodeLookupByKey[Cid, Val] => {
|
||||||
case NodeLookupByKey(templateId2, optLocation2 @ _, key2, result2) =>
|
case NodeLookupByKey(templateId2, optLocation2 @ _, key2, result2, version2) =>
|
||||||
import nl._
|
import nl._
|
||||||
|
version == version2 &&
|
||||||
templateId == templateId2 &&
|
templateId == templateId2 &&
|
||||||
key === key2 && result === result2
|
key === key2 && result === result2
|
||||||
}
|
}
|
||||||
@ -376,31 +415,6 @@ object Node {
|
|||||||
type WithTxValue[+Nid, +Cid] = F[Nid, Cid, Transaction.Value[Cid]]
|
type WithTxValue[+Nid, +Cid] = F[Nid, Cid, Transaction.Value[Cid]]
|
||||||
}
|
}
|
||||||
|
|
||||||
case class VersionedNode[+Nid, +Cid](
|
|
||||||
version: TransactionVersion,
|
|
||||||
node: Node.GenNode.WithTxValue[Nid, Cid],
|
|
||||||
) extends CidContainer[VersionedNode[Nid, Cid]] {
|
|
||||||
override protected def self: this.type = this
|
|
||||||
}
|
|
||||||
|
|
||||||
object VersionedNode extends CidContainer2[VersionedNode] {
|
|
||||||
override private[lf] def map2[A1, B1, A2, B2](
|
|
||||||
f1: A1 => A2,
|
|
||||||
f2: B1 => B2,
|
|
||||||
): VersionedNode[A1, B1] => VersionedNode[A2, B2] = {
|
|
||||||
case VersionedNode(version, node) =>
|
|
||||||
VersionedNode(version, GenNode.map3(f1, f2, VersionedValue.map1(f2))(node))
|
|
||||||
}
|
|
||||||
|
|
||||||
override private[lf] def foreach2[A, B](
|
|
||||||
f1: A => Unit,
|
|
||||||
f2: B => Unit,
|
|
||||||
): VersionedNode[A, B] => Unit = {
|
|
||||||
case VersionedNode(_, node) =>
|
|
||||||
GenNode.foreach3(f1, f2, VersionedValue.foreach1(f2))(node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class NodeId(index: Int)
|
final case class NodeId(index: Int)
|
||||||
|
@ -7,7 +7,7 @@ package transaction
|
|||||||
import com.daml.lf.data.Ref._
|
import com.daml.lf.data.Ref._
|
||||||
import com.daml.lf.data._
|
import com.daml.lf.data._
|
||||||
import com.daml.lf.ledger.FailedAuthorization
|
import com.daml.lf.ledger.FailedAuthorization
|
||||||
import com.daml.lf.transaction.Node.VersionedNode
|
import com.daml.lf.transaction.Node.GenNode
|
||||||
import com.daml.lf.value.Value
|
import com.daml.lf.value.Value
|
||||||
import scalaz.Equal
|
import scalaz.Equal
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ import scala.collection.immutable.HashMap
|
|||||||
|
|
||||||
final case class VersionedTransaction[Nid, +Cid] private[lf] (
|
final case class VersionedTransaction[Nid, +Cid] private[lf] (
|
||||||
version: TransactionVersion,
|
version: TransactionVersion,
|
||||||
versionedNodes: Map[Nid, Node.VersionedNode[Nid, Cid]],
|
nodes: Map[Nid, GenNode.WithTxValue[Nid, Cid]],
|
||||||
override val roots: ImmArray[Nid],
|
override val roots: ImmArray[Nid],
|
||||||
) extends HasTxNodes[Nid, Cid, Transaction.Value[Cid]]
|
) extends HasTxNodes[Nid, Cid, Transaction.Value[Cid]]
|
||||||
with value.CidContainer[VersionedTransaction[Nid, Cid]]
|
with value.CidContainer[VersionedTransaction[Nid, Cid]]
|
||||||
@ -26,20 +26,14 @@ final case class VersionedTransaction[Nid, +Cid] private[lf] (
|
|||||||
|
|
||||||
@deprecated("use resolveRelCid/ensureNoCid/ensureNoRelCid", since = "0.13.52")
|
@deprecated("use resolveRelCid/ensureNoCid/ensureNoRelCid", since = "0.13.52")
|
||||||
def mapContractId[Cid2](f: Cid => Cid2): VersionedTransaction[Nid, Cid2] = {
|
def mapContractId[Cid2](f: Cid => Cid2): VersionedTransaction[Nid, Cid2] = {
|
||||||
val versionNode = Node.VersionedNode.map2(identity[Nid], f)
|
val versionNode = GenNode.map3(identity[Nid], f, Value.VersionedValue.map1(f))
|
||||||
VersionedTransaction(
|
VersionedTransaction(
|
||||||
version,
|
version,
|
||||||
versionedNodes = versionedNodes.transform((_, node) => versionNode(node)),
|
nodes = nodes.transform((_, node) => versionNode(node)),
|
||||||
roots,
|
roots,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// O(1)
|
|
||||||
override def nodes: Map[Nid, Node.GenNode.WithTxValue[Nid, Cid]] =
|
|
||||||
// Here we use intentionally `mapValues` to get the time/memory complexity of the method constant.
|
|
||||||
// It is fine since the function `_.node` is very cheap.
|
|
||||||
versionedNodes.mapValues(_.node)
|
|
||||||
|
|
||||||
// O(1)
|
// O(1)
|
||||||
def transaction: GenTransaction[Nid, Cid, Transaction.Value[Cid]] =
|
def transaction: GenTransaction[Nid, Cid, Transaction.Value[Cid]] =
|
||||||
GenTransaction(nodes, roots)
|
GenTransaction(nodes, roots)
|
||||||
@ -53,7 +47,7 @@ object VersionedTransaction extends value.CidContainer2[VersionedTransaction] {
|
|||||||
f2: B1 => B2,
|
f2: B1 => B2,
|
||||||
): VersionedTransaction[A1, B1] => VersionedTransaction[A2, B2] = {
|
): VersionedTransaction[A1, B1] => VersionedTransaction[A2, B2] = {
|
||||||
case VersionedTransaction(version, versionedNodes, roots) =>
|
case VersionedTransaction(version, versionedNodes, roots) =>
|
||||||
val mapNode = Node.VersionedNode.map2(f1, f2)
|
val mapNode = GenNode.map3(f1, f2, Value.VersionedValue.map1(f2))
|
||||||
VersionedTransaction(
|
VersionedTransaction(
|
||||||
version,
|
version,
|
||||||
versionedNodes.map {
|
versionedNodes.map {
|
||||||
@ -68,7 +62,7 @@ object VersionedTransaction extends value.CidContainer2[VersionedTransaction] {
|
|||||||
f2: B => Unit,
|
f2: B => Unit,
|
||||||
): VersionedTransaction[A, B] => Unit = {
|
): VersionedTransaction[A, B] => Unit = {
|
||||||
case VersionedTransaction(_, versionedNodes, _) =>
|
case VersionedTransaction(_, versionedNodes, _) =>
|
||||||
val foreachNode = Node.VersionedNode.foreach2(f1, f2)
|
val foreachNode = GenNode.foreach3(f1, f2, Value.VersionedValue.foreach1(f2))
|
||||||
versionedNodes.foreach {
|
versionedNodes.foreach {
|
||||||
case (nid, node) =>
|
case (nid, node) =>
|
||||||
f1(nid)
|
f1(nid)
|
||||||
@ -331,7 +325,7 @@ sealed abstract class HasTxNodes[Nid, +Cid, +Val] {
|
|||||||
|
|
||||||
final def localContracts[Cid2 >: Cid]: Map[Cid2, Nid] =
|
final def localContracts[Cid2 >: Cid]: Map[Cid2, Nid] =
|
||||||
fold(Map.empty[Cid2, Nid]) {
|
fold(Map.empty[Cid2, Nid]) {
|
||||||
case (acc, (nid, create @ Node.NodeCreate(_, _, _, _, _, _))) =>
|
case (acc, (nid, create @ Node.NodeCreate(_, _, _, _, _, _, _))) =>
|
||||||
acc.updated(create.coid, nid)
|
acc.updated(create.coid, nid)
|
||||||
case (acc, _) => acc
|
case (acc, _) => acc
|
||||||
}
|
}
|
||||||
@ -341,11 +335,11 @@ sealed abstract class HasTxNodes[Nid, +Cid, +Val] {
|
|||||||
*/
|
*/
|
||||||
final def inputContracts[Cid2 >: Cid]: Set[Cid2] =
|
final def inputContracts[Cid2 >: Cid]: Set[Cid2] =
|
||||||
fold(Set.empty[Cid2]) {
|
fold(Set.empty[Cid2]) {
|
||||||
case (acc, (_, Node.NodeExercises(coid, _, _, _, _, _, _, _, _, _, _, _, _, _))) =>
|
case (acc, (_, Node.NodeExercises(coid, _, _, _, _, _, _, _, _, _, _, _, _, _, _))) =>
|
||||||
acc + coid
|
acc + coid
|
||||||
case (acc, (_, Node.NodeFetch(coid, _, _, _, _, _, _, _))) =>
|
case (acc, (_, Node.NodeFetch(coid, _, _, _, _, _, _, _, _))) =>
|
||||||
acc + coid
|
acc + coid
|
||||||
case (acc, (_, Node.NodeLookupByKey(_, _, _, Some(coid)))) =>
|
case (acc, (_, Node.NodeLookupByKey(_, _, _, Some(coid), _))) =>
|
||||||
acc + coid
|
acc + coid
|
||||||
case (acc, _) => acc
|
case (acc, _) => acc
|
||||||
} -- localContracts.keySet
|
} -- localContracts.keySet
|
||||||
@ -478,15 +472,15 @@ object GenTransaction extends value.CidContainer3[GenTransaction] {
|
|||||||
tx.fold(State(Set.empty, Set.empty)) {
|
tx.fold(State(Set.empty, Set.empty)) {
|
||||||
case (state, (_, node)) =>
|
case (state, (_, node)) =>
|
||||||
node match {
|
node match {
|
||||||
case Node.NodeCreate(_, c, _, _, _, Some(key)) =>
|
case Node.NodeCreate(_, c, _, _, _, Some(key), _) =>
|
||||||
state.created(globalKey(c.template, key.key.value))
|
state.created(globalKey(c.template, key.key.value))
|
||||||
case Node.NodeExercises(_, tmplId, _, _, true, _, _, _, _, _, _, _, Some(key), _) =>
|
case Node.NodeExercises(_, tmplId, _, _, true, _, _, _, _, _, _, _, Some(key), _, _) =>
|
||||||
state.consumed(globalKey(tmplId, key.key.value))
|
state.consumed(globalKey(tmplId, key.key.value))
|
||||||
case Node.NodeExercises(_, tmplId, _, _, false, _, _, _, _, _, _, _, Some(key), _) =>
|
case Node.NodeExercises(_, tmplId, _, _, false, _, _, _, _, _, _, _, Some(key), _, _) =>
|
||||||
state.referenced(globalKey(tmplId, key.key.value))
|
state.referenced(globalKey(tmplId, key.key.value))
|
||||||
case Node.NodeFetch(_, tmplId, _, _, _, _, Some(key), _) =>
|
case Node.NodeFetch(_, tmplId, _, _, _, _, Some(key), _, _) =>
|
||||||
state.referenced(globalKey(tmplId, key.key.value))
|
state.referenced(globalKey(tmplId, key.key.value))
|
||||||
case Node.NodeLookupByKey(tmplId, _, key, Some(_)) =>
|
case Node.NodeLookupByKey(tmplId, _, key, Some(_), _) =>
|
||||||
state.referenced(globalKey(tmplId, key.key.value))
|
state.referenced(globalKey(tmplId, key.key.value))
|
||||||
case _ =>
|
case _ =>
|
||||||
state
|
state
|
||||||
@ -598,123 +592,128 @@ object Transaction {
|
|||||||
): Either[ReplayMismatch[Nid, Cid], Unit] =
|
): Either[ReplayMismatch[Nid, Cid], Unit] =
|
||||||
(nids1, nids2) match {
|
(nids1, nids2) match {
|
||||||
case (nid1 #:: rest1, nid2 #:: rest2) =>
|
case (nid1 #:: rest1, nid2 #:: rest2) =>
|
||||||
val VersionedNode(version1, node1) = recorded.versionedNodes(nid1)
|
(recorded.nodes(nid1), replayed.nodes(nid2)) match {
|
||||||
val VersionedNode(version2, node2) = replayed.versionedNodes(nid2)
|
case (
|
||||||
if (version1 != version2)
|
Node.NodeCreate(
|
||||||
Left(ReplayNodeMismatch(recorded, nid1, replayed, nid2))
|
coid1,
|
||||||
else
|
coinst1,
|
||||||
(node1, node2) match {
|
optLocation1 @ _,
|
||||||
case (
|
signatories1,
|
||||||
Node.NodeCreate(
|
stakeholders1,
|
||||||
coid1,
|
key1,
|
||||||
coinst1,
|
version1,
|
||||||
optLocation1 @ _,
|
),
|
||||||
signatories1,
|
Node.NodeCreate(
|
||||||
stakeholders1,
|
coid2,
|
||||||
key1
|
coinst2,
|
||||||
),
|
optLocation2 @ _,
|
||||||
Node.NodeCreate(
|
signatories2,
|
||||||
coid2,
|
stakeholders2,
|
||||||
coinst2,
|
key2,
|
||||||
optLocation2 @ _,
|
version2,
|
||||||
signatories2,
|
))
|
||||||
stakeholders2,
|
if version1 == version2 &&
|
||||||
key2
|
coid1 === coid2 &&
|
||||||
))
|
coinst1 === coinst2 &&
|
||||||
if coid1 === coid2 &&
|
signatories1 == signatories2 &&
|
||||||
coinst1 === coinst2 &&
|
stakeholders1 == stakeholders2 &&
|
||||||
signatories1 == signatories2 &&
|
key1 === key2 =>
|
||||||
stakeholders1 == stakeholders2 &&
|
loop(rest1, rest2, stack)
|
||||||
key1 === key2 =>
|
case (
|
||||||
loop(rest1, rest2, stack)
|
Node.NodeFetch(
|
||||||
case (
|
coid1,
|
||||||
Node.NodeFetch(
|
templateId1,
|
||||||
coid1,
|
optLocation1 @ _,
|
||||||
templateId1,
|
actingParties1,
|
||||||
optLocation1 @ _,
|
signatories1,
|
||||||
actingParties1,
|
stakeholders1,
|
||||||
signatories1,
|
key1,
|
||||||
stakeholders1,
|
byKey1 @ _,
|
||||||
key1,
|
version1,
|
||||||
byKey1 @ _,
|
),
|
||||||
),
|
Node.NodeFetch(
|
||||||
Node.NodeFetch(
|
coid2,
|
||||||
coid2,
|
templateId2,
|
||||||
templateId2,
|
optLocation2 @ _,
|
||||||
optLocation2 @ _,
|
actingParties2,
|
||||||
actingParties2,
|
signatories2,
|
||||||
signatories2,
|
stakeholders2,
|
||||||
stakeholders2,
|
key2,
|
||||||
key2,
|
byKey2 @ _,
|
||||||
byKey2 @ _,
|
version2,
|
||||||
))
|
))
|
||||||
if coid1 === coid2 &&
|
if version1 == version2 &&
|
||||||
templateId1 == templateId2 &&
|
coid1 === coid2 &&
|
||||||
(actingParties1.isEmpty || actingParties1 == actingParties2) &&
|
templateId1 == templateId2 &&
|
||||||
signatories1 == signatories2 &&
|
(actingParties1.isEmpty || actingParties1 == actingParties2) &&
|
||||||
stakeholders1 == stakeholders2 &&
|
signatories1 == signatories2 &&
|
||||||
(key1.isEmpty || key1 === key2) =>
|
stakeholders1 == stakeholders2 &&
|
||||||
loop(rest1, rest2, stack)
|
(key1.isEmpty || key1 === key2) =>
|
||||||
case (
|
loop(rest1, rest2, stack)
|
||||||
exe1 @ Node.NodeExercises(
|
case (
|
||||||
targetCoid1,
|
exe1 @ Node.NodeExercises(
|
||||||
templateId1,
|
targetCoid1,
|
||||||
choiceId1,
|
templateId1,
|
||||||
optLocation1 @ _,
|
choiceId1,
|
||||||
consuming1,
|
optLocation1 @ _,
|
||||||
actingParties1,
|
consuming1,
|
||||||
chosenValue1,
|
actingParties1,
|
||||||
stakeholders1,
|
chosenValue1,
|
||||||
signatories1,
|
stakeholders1,
|
||||||
choiceObservers1,
|
signatories1,
|
||||||
children1 @ _,
|
choiceObservers1,
|
||||||
exerciseResult1 @ _,
|
children1 @ _,
|
||||||
key1,
|
exerciseResult1 @ _,
|
||||||
byKey1 @ _,
|
key1,
|
||||||
),
|
byKey1 @ _,
|
||||||
exe2 @ Node.NodeExercises(
|
version1,
|
||||||
targetCoid2,
|
),
|
||||||
templateId2,
|
exe2 @ Node.NodeExercises(
|
||||||
choiceId2,
|
targetCoid2,
|
||||||
optLocation2 @ _,
|
templateId2,
|
||||||
consuming2,
|
choiceId2,
|
||||||
actingParties2,
|
optLocation2 @ _,
|
||||||
chosenValue2,
|
consuming2,
|
||||||
stakeholders2,
|
actingParties2,
|
||||||
signatories2,
|
chosenValue2,
|
||||||
choiceObservers2,
|
stakeholders2,
|
||||||
children2 @ _,
|
signatories2,
|
||||||
exerciseResult2 @ _,
|
choiceObservers2,
|
||||||
key2,
|
children2 @ _,
|
||||||
byKey2 @ _,
|
exerciseResult2 @ _,
|
||||||
))
|
key2,
|
||||||
// results are checked after the children
|
byKey2 @ _,
|
||||||
if targetCoid1 === targetCoid2 &&
|
version2,
|
||||||
templateId1 == templateId2 &&
|
))
|
||||||
choiceId1 == choiceId2 &&
|
// results are checked after the children
|
||||||
consuming1 == consuming2 &&
|
if version1 == version2 &&
|
||||||
actingParties1 == actingParties2 &&
|
targetCoid1 === targetCoid2 &&
|
||||||
chosenValue1 === chosenValue2 &&
|
templateId1 == templateId2 &&
|
||||||
stakeholders1 == stakeholders2 &&
|
choiceId1 == choiceId2 &&
|
||||||
signatories1 == signatories2 &&
|
consuming1 == consuming2 &&
|
||||||
choiceObservers1 == choiceObservers2 &&
|
actingParties1 == actingParties2 &&
|
||||||
(key1.isEmpty || key1 === key2) =>
|
chosenValue1 === chosenValue2 &&
|
||||||
loop(
|
stakeholders1 == stakeholders2 &&
|
||||||
children1.iterator.toStream,
|
signatories1 == signatories2 &&
|
||||||
children2.iterator.toStream,
|
choiceObservers1 == choiceObservers2 &&
|
||||||
(nid1, exe1, rest1, nid2, exe2, rest2) :: stack
|
(key1.isEmpty || key1 === key2) =>
|
||||||
|
loop(
|
||||||
|
children1.iterator.toStream,
|
||||||
|
children2.iterator.toStream,
|
||||||
|
(nid1, exe1, rest1, nid2, exe2, rest2) :: stack
|
||||||
|
)
|
||||||
|
case (
|
||||||
|
Node.NodeLookupByKey(templateId1, optLocation1 @ _, key1, result1, version1),
|
||||||
|
Node.NodeLookupByKey(templateId2, optLocation2 @ _, key2, result2, version2)
|
||||||
)
|
)
|
||||||
case (
|
if version1 == version2 &&
|
||||||
Node.NodeLookupByKey(templateId1, optLocation1 @ _, key1, result1),
|
templateId1 == templateId2 &&
|
||||||
Node.NodeLookupByKey(templateId2, optLocation2 @ _, key2, result2)
|
key1 === key2 &&
|
||||||
)
|
result1 === result2 =>
|
||||||
if templateId1 == templateId2 &&
|
loop(rest1, rest2, stack)
|
||||||
key1 === key2 &&
|
case _ =>
|
||||||
result1 === result2 =>
|
Left(ReplayNodeMismatch(recorded, nid1, replayed, nid2))
|
||||||
loop(rest1, rest2, stack)
|
}
|
||||||
case _ =>
|
|
||||||
Left(ReplayNodeMismatch(recorded, nid1, replayed, nid2))
|
|
||||||
}
|
|
||||||
|
|
||||||
case (Stream.Empty, Stream.Empty) =>
|
case (Stream.Empty, Stream.Empty) =>
|
||||||
stack match {
|
stack match {
|
||||||
|
@ -118,19 +118,6 @@ object TransactionCoder {
|
|||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
|
|
||||||
private[lf] def encodeVersionedNode[Nid, Cid](
|
|
||||||
encodeNid: EncodeNid[Nid],
|
|
||||||
encodeCid: ValueCoder.EncodeCid[Cid],
|
|
||||||
enclosingVersion: TransactionVersion,
|
|
||||||
nodeId: Nid,
|
|
||||||
versionedNode: VersionedNode[Nid, Cid],
|
|
||||||
): Either[EncodeError, TransactionOuterClass.Node] =
|
|
||||||
if (enclosingVersion precedes versionedNode.version)
|
|
||||||
Left(EncodeError(
|
|
||||||
s"A transaction of version $enclosingVersion cannot contain nodes of newer version (${versionedNode.version}"))
|
|
||||||
else
|
|
||||||
encodeNode(encodeNid, encodeCid, versionedNode.version, nodeId, versionedNode.node)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* encodes a [[GenNode[Nid, Cid]] to protocol buffer
|
* encodes a [[GenNode[Nid, Cid]] to protocol buffer
|
||||||
* @param nodeId node id of the node to be encoded
|
* @param nodeId node id of the node to be encoded
|
||||||
@ -144,109 +131,116 @@ object TransactionCoder {
|
|||||||
private[lf] def encodeNode[Nid, Cid](
|
private[lf] def encodeNode[Nid, Cid](
|
||||||
encodeNid: EncodeNid[Nid],
|
encodeNid: EncodeNid[Nid],
|
||||||
encodeCid: ValueCoder.EncodeCid[Cid],
|
encodeCid: ValueCoder.EncodeCid[Cid],
|
||||||
version: TransactionVersion,
|
enclosingVersion: TransactionVersion,
|
||||||
nodeId: Nid,
|
nodeId: Nid,
|
||||||
node: GenNode[Nid, Cid, Value.VersionedValue[Cid]],
|
node: GenNode[Nid, Cid, Value.VersionedValue[Cid]],
|
||||||
): Either[EncodeError, TransactionOuterClass.Node] = {
|
): Either[EncodeError, TransactionOuterClass.Node] =
|
||||||
val nodeBuilder = TransactionOuterClass.Node.newBuilder().setNodeId(encodeNid.asString(nodeId))
|
if (enclosingVersion precedes node.version)
|
||||||
nodeBuilder.setVersion(version.protoValue)
|
Left(EncodeError(
|
||||||
|
s"A transaction of version $enclosingVersion cannot contain nodes of newer version (${node.version}"))
|
||||||
|
else {
|
||||||
|
|
||||||
node match {
|
val nodeBuilder =
|
||||||
case nc @ NodeCreate(_, _, _, _, _, _) =>
|
TransactionOuterClass.Node.newBuilder().setNodeId(encodeNid.asString(nodeId))
|
||||||
val createBuilder =
|
nodeBuilder.setVersion(node.version.protoValue)
|
||||||
TransactionOuterClass.NodeCreate
|
|
||||||
|
node match {
|
||||||
|
case nc @ NodeCreate(_, _, _, _, _, _, _) =>
|
||||||
|
val createBuilder =
|
||||||
|
TransactionOuterClass.NodeCreate
|
||||||
|
.newBuilder()
|
||||||
|
.addAllStakeholders(nc.stakeholders.toSet[String].asJava)
|
||||||
|
.addAllSignatories(nc.signatories.toSet[String].asJava)
|
||||||
|
for {
|
||||||
|
inst <- encodeContractInstance(encodeCid, nc.coinst)
|
||||||
|
optKey <- nc.key match {
|
||||||
|
case None => Right(None)
|
||||||
|
case Some(key) => encodeKeyWithMaintainers(encodeCid, key).map(Some(_))
|
||||||
|
}
|
||||||
|
encodedCid = encodeCid.encode(nc.coid)
|
||||||
|
} yield {
|
||||||
|
createBuilder.setContractIdStruct(encodedCid)
|
||||||
|
createBuilder.setContractInstance(inst)
|
||||||
|
optKey.foreach(createBuilder.setKeyWithMaintainers)
|
||||||
|
nodeBuilder.setCreate(createBuilder).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
case nf @ NodeFetch(_, _, _, _, _, _, _, _, _) =>
|
||||||
|
val fetchBuilder = TransactionOuterClass.NodeFetch
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.addAllStakeholders(nc.stakeholders.toSet[String].asJava)
|
.setTemplateId(ValueCoder.encodeIdentifier(nf.templateId))
|
||||||
.addAllSignatories(nc.signatories.toSet[String].asJava)
|
.addAllStakeholders(nf.stakeholders.toSet[String].asJava)
|
||||||
for {
|
.addAllSignatories(nf.signatories.toSet[String].asJava)
|
||||||
inst <- encodeContractInstance(encodeCid, nc.coinst)
|
|
||||||
optKey <- nc.key match {
|
|
||||||
case None => Right(None)
|
|
||||||
case Some(key) => encodeKeyWithMaintainers(encodeCid, key).map(Some(_))
|
|
||||||
}
|
|
||||||
encodedCid = encodeCid.encode(nc.coid)
|
|
||||||
} yield {
|
|
||||||
createBuilder.setContractIdStruct(encodedCid)
|
|
||||||
createBuilder.setContractInstance(inst)
|
|
||||||
optKey.foreach(createBuilder.setKeyWithMaintainers)
|
|
||||||
nodeBuilder.setCreate(createBuilder).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
case nf @ NodeFetch(_, _, _, _, _, _, _, _) =>
|
for {
|
||||||
val fetchBuilder = TransactionOuterClass.NodeFetch
|
optKey <- nf.key match {
|
||||||
.newBuilder()
|
case None => Right(None)
|
||||||
.setTemplateId(ValueCoder.encodeIdentifier(nf.templateId))
|
case Some(key) => encodeKeyWithMaintainers(encodeCid, key).map(Some(_))
|
||||||
.addAllStakeholders(nf.stakeholders.toSet[String].asJava)
|
}
|
||||||
.addAllSignatories(nf.signatories.toSet[String].asJava)
|
encodedCid = encodeCid.encode(nf.coid)
|
||||||
|
} yield {
|
||||||
for {
|
fetchBuilder.setContractIdStruct(encodedCid)
|
||||||
optKey <- nf.key match {
|
nf.actingParties.foreach(fetchBuilder.addActors)
|
||||||
case None => Right(None)
|
optKey.foreach(fetchBuilder.setKeyWithMaintainers)
|
||||||
case Some(key) => encodeKeyWithMaintainers(encodeCid, key).map(Some(_))
|
nodeBuilder.setFetch(fetchBuilder).build()
|
||||||
}
|
}
|
||||||
encodedCid = encodeCid.encode(nf.coid)
|
|
||||||
} yield {
|
|
||||||
fetchBuilder.setContractIdStruct(encodedCid)
|
|
||||||
nf.actingParties.foreach(fetchBuilder.addActors)
|
|
||||||
optKey.foreach(fetchBuilder.setKeyWithMaintainers)
|
|
||||||
nodeBuilder.setFetch(fetchBuilder).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
case ne @ NodeExercises(_, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
|
case ne @ NodeExercises(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
|
||||||
for {
|
for {
|
||||||
_ <- Either.cond(
|
_ <- Either.cond(
|
||||||
test =
|
test =
|
||||||
!((version precedes TransactionVersions.minChoiceObservers) && ne.choiceObservers.nonEmpty),
|
!((node.version precedes TransactionVersions.minChoiceObservers) && ne.choiceObservers.nonEmpty),
|
||||||
right = (),
|
right = (),
|
||||||
left = EncodeError(version, isTooOldFor = "non-empty choice-observers")
|
left = EncodeError(node.version, isTooOldFor = "non-empty choice-observers")
|
||||||
)
|
)
|
||||||
argValue <- encodeValue(encodeCid, ne.chosenValue)
|
argValue <- encodeValue(encodeCid, ne.chosenValue)
|
||||||
retValue <- ne.exerciseResult match {
|
retValue <- ne.exerciseResult match {
|
||||||
case Some(value) => encodeValue(encodeCid, value)
|
case Some(value) => encodeValue(encodeCid, value)
|
||||||
case None => Left(EncodeError("NodeExercises without result"))
|
case None => Left(EncodeError("NodeExercises without result"))
|
||||||
|
}
|
||||||
|
exBuilder = TransactionOuterClass.NodeExercise
|
||||||
|
.newBuilder()
|
||||||
|
.setChoice(ne.choiceId)
|
||||||
|
.setTemplateId(ValueCoder.encodeIdentifier(ne.templateId))
|
||||||
|
.setChosenValue(argValue)
|
||||||
|
.setConsuming(ne.consuming)
|
||||||
|
.addAllActors(ne.actingParties.toSet[String].asJava)
|
||||||
|
.addAllChildren(ne.children.map(encodeNid.asString).toList.asJava)
|
||||||
|
.addAllSignatories(ne.signatories.toSet[String].asJava)
|
||||||
|
.addAllStakeholders(ne.stakeholders.toSet[String].asJava)
|
||||||
|
.addAllObservers(ne.choiceObservers.toSet[String].asJava)
|
||||||
|
encodedCid = encodeCid.encode(ne.targetCoid)
|
||||||
|
_ <- Right(
|
||||||
|
ne.key
|
||||||
|
.map { kWithM =>
|
||||||
|
encodeKeyWithMaintainers(encodeCid, kWithM).foreach(
|
||||||
|
exBuilder.setKeyWithMaintainers)
|
||||||
|
}
|
||||||
|
.getOrElse(()),
|
||||||
|
)
|
||||||
|
} yield {
|
||||||
|
exBuilder.setContractIdStruct(encodedCid)
|
||||||
|
exBuilder.setReturnValue(retValue)
|
||||||
|
nodeBuilder.setExercise(exBuilder).build()
|
||||||
}
|
}
|
||||||
exBuilder = TransactionOuterClass.NodeExercise
|
|
||||||
.newBuilder()
|
|
||||||
.setChoice(ne.choiceId)
|
|
||||||
.setTemplateId(ValueCoder.encodeIdentifier(ne.templateId))
|
|
||||||
.setChosenValue(argValue)
|
|
||||||
.setConsuming(ne.consuming)
|
|
||||||
.addAllActors(ne.actingParties.toSet[String].asJava)
|
|
||||||
.addAllChildren(ne.children.map(encodeNid.asString).toList.asJava)
|
|
||||||
.addAllSignatories(ne.signatories.toSet[String].asJava)
|
|
||||||
.addAllStakeholders(ne.stakeholders.toSet[String].asJava)
|
|
||||||
.addAllObservers(ne.choiceObservers.toSet[String].asJava)
|
|
||||||
encodedCid = encodeCid.encode(ne.targetCoid)
|
|
||||||
_ <- Right(
|
|
||||||
ne.key
|
|
||||||
.map { kWithM =>
|
|
||||||
encodeKeyWithMaintainers(encodeCid, kWithM).foreach(exBuilder.setKeyWithMaintainers)
|
|
||||||
}
|
|
||||||
.getOrElse(()),
|
|
||||||
)
|
|
||||||
} yield {
|
|
||||||
exBuilder.setContractIdStruct(encodedCid)
|
|
||||||
exBuilder.setReturnValue(retValue)
|
|
||||||
nodeBuilder.setExercise(exBuilder).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
case nlbk @ NodeLookupByKey(_, _, _, _) =>
|
case nlbk @ NodeLookupByKey(_, _, _, _, _) =>
|
||||||
val nlbkBuilder = TransactionOuterClass.NodeLookupByKey.newBuilder()
|
val nlbkBuilder = TransactionOuterClass.NodeLookupByKey.newBuilder()
|
||||||
for {
|
for {
|
||||||
encodedKey <- encodeKeyWithMaintainers(encodeCid, nlbk.key)
|
encodedKey <- encodeKeyWithMaintainers(encodeCid, nlbk.key)
|
||||||
encodedCid = nlbk.result match {
|
encodedCid = nlbk.result match {
|
||||||
case Some(cid) => Some(encodeCid.encode(cid))
|
case Some(cid) => Some(encodeCid.encode(cid))
|
||||||
case None => None
|
case None => None
|
||||||
|
}
|
||||||
|
} yield {
|
||||||
|
nlbkBuilder
|
||||||
|
.setTemplateId(ValueCoder.encodeIdentifier(nlbk.templateId))
|
||||||
|
.setKeyWithMaintainers(encodedKey)
|
||||||
|
encodedCid.foreach(nlbkBuilder.setContractIdStruct)
|
||||||
|
nodeBuilder.setLookupByKey(nlbkBuilder).build()
|
||||||
}
|
}
|
||||||
} yield {
|
}
|
||||||
nlbkBuilder
|
|
||||||
.setTemplateId(ValueCoder.encodeIdentifier(nlbk.templateId))
|
|
||||||
.setKeyWithMaintainers(encodedKey)
|
|
||||||
encodedCid.foreach(nlbkBuilder.setContractIdStruct)
|
|
||||||
nodeBuilder.setLookupByKey(nlbkBuilder).build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
private def decodeKeyWithMaintainers[Cid](
|
private def decodeKeyWithMaintainers[Cid](
|
||||||
decodeCid: ValueCoder.DecodeCid[Cid],
|
decodeCid: ValueCoder.DecodeCid[Cid],
|
||||||
keyWithMaintainers: TransactionOuterClass.KeyWithMaintainers,
|
keyWithMaintainers: TransactionOuterClass.KeyWithMaintainers,
|
||||||
@ -270,7 +264,7 @@ object TransactionCoder {
|
|||||||
decodeCid: ValueCoder.DecodeCid[Cid],
|
decodeCid: ValueCoder.DecodeCid[Cid],
|
||||||
enclosingVersion: TransactionVersion,
|
enclosingVersion: TransactionVersion,
|
||||||
protoNode: TransactionOuterClass.Node,
|
protoNode: TransactionOuterClass.Node,
|
||||||
): Either[DecodeError, (Nid, VersionedNode[Nid, Cid])] =
|
): Either[DecodeError, (Nid, GenNode.WithTxValue[Nid, Cid])] =
|
||||||
for {
|
for {
|
||||||
version <- if (enclosingVersion precedes TransactionVersions.minNodeVersion) {
|
version <- if (enclosingVersion precedes TransactionVersions.minNodeVersion) {
|
||||||
Right(enclosingVersion)
|
Right(enclosingVersion)
|
||||||
@ -293,7 +287,7 @@ object TransactionCoder {
|
|||||||
decodeCid: ValueCoder.DecodeCid[Cid],
|
decodeCid: ValueCoder.DecodeCid[Cid],
|
||||||
version: TransactionVersion,
|
version: TransactionVersion,
|
||||||
protoNode: TransactionOuterClass.Node,
|
protoNode: TransactionOuterClass.Node,
|
||||||
): Either[DecodeError, (Nid, VersionedNode[Nid, Cid])] = {
|
): Either[DecodeError, (Nid, GenNode.WithTxValue[Nid, Cid])] = {
|
||||||
val nodeId = decodeNid.fromString(protoNode.getNodeId)
|
val nodeId = decodeNid.fromString(protoNode.getNodeId)
|
||||||
|
|
||||||
protoNode.getNodeTypeCase match {
|
protoNode.getNodeTypeCase match {
|
||||||
@ -308,8 +302,7 @@ object TransactionCoder {
|
|||||||
key <- if (protoCreate.getKeyWithMaintainers == TransactionOuterClass.KeyWithMaintainers.getDefaultInstance)
|
key <- if (protoCreate.getKeyWithMaintainers == TransactionOuterClass.KeyWithMaintainers.getDefaultInstance)
|
||||||
Right(None)
|
Right(None)
|
||||||
else decodeKeyWithMaintainers(decodeCid, protoCreate.getKeyWithMaintainers).map(Some(_))
|
else decodeKeyWithMaintainers(decodeCid, protoCreate.getKeyWithMaintainers).map(Some(_))
|
||||||
} yield
|
} yield ni -> NodeCreate(c, ci, None, signatories, stakeholders, key, version)
|
||||||
(ni, VersionedNode(version, NodeCreate(c, ci, None, signatories, stakeholders, key)))
|
|
||||||
case NodeTypeCase.FETCH =>
|
case NodeTypeCase.FETCH =>
|
||||||
val protoFetch = protoNode.getFetch
|
val protoFetch = protoNode.getFetch
|
||||||
for {
|
for {
|
||||||
@ -324,12 +317,16 @@ object TransactionCoder {
|
|||||||
else
|
else
|
||||||
decodeKeyWithMaintainers(decodeCid, protoFetch.getKeyWithMaintainers).map(Some(_))
|
decodeKeyWithMaintainers(decodeCid, protoFetch.getKeyWithMaintainers).map(Some(_))
|
||||||
} yield
|
} yield
|
||||||
(
|
ni -> NodeFetch(
|
||||||
ni,
|
c,
|
||||||
VersionedNode(
|
templateId,
|
||||||
version,
|
None,
|
||||||
NodeFetch(c, templateId, None, actingParties, signatories, stakeholders, key, false),
|
actingParties,
|
||||||
)
|
signatories,
|
||||||
|
stakeholders,
|
||||||
|
key,
|
||||||
|
false,
|
||||||
|
version,
|
||||||
)
|
)
|
||||||
|
|
||||||
case NodeTypeCase.EXERCISE =>
|
case NodeTypeCase.EXERCISE =>
|
||||||
@ -364,27 +361,22 @@ object TransactionCoder {
|
|||||||
}
|
}
|
||||||
choiceName <- toIdentifier(protoExe.getChoice)
|
choiceName <- toIdentifier(protoExe.getChoice)
|
||||||
} yield
|
} yield
|
||||||
(
|
ni -> NodeExercises(
|
||||||
ni,
|
targetCoid = targetCoid,
|
||||||
VersionedNode(
|
templateId = templateId,
|
||||||
version,
|
choiceId = choiceName,
|
||||||
NodeExercises(
|
optLocation = None,
|
||||||
targetCoid = targetCoid,
|
consuming = protoExe.getConsuming,
|
||||||
templateId = templateId,
|
actingParties = actingParties,
|
||||||
choiceId = choiceName,
|
chosenValue = cv,
|
||||||
optLocation = None,
|
stakeholders = stakeholders,
|
||||||
consuming = protoExe.getConsuming,
|
signatories = signatories,
|
||||||
actingParties = actingParties,
|
choiceObservers = choiceObservers,
|
||||||
chosenValue = cv,
|
children = children,
|
||||||
stakeholders = stakeholders,
|
exerciseResult = Some(rv),
|
||||||
signatories = signatories,
|
key = keyWithMaintainers,
|
||||||
choiceObservers = choiceObservers,
|
byKey = false,
|
||||||
children = children,
|
version = version,
|
||||||
exerciseResult = Some(rv),
|
|
||||||
key = keyWithMaintainers,
|
|
||||||
byKey = false,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
case NodeTypeCase.LOOKUP_BY_KEY =>
|
case NodeTypeCase.LOOKUP_BY_KEY =>
|
||||||
val protoLookupByKey = protoNode.getLookupByKey
|
val protoLookupByKey = protoNode.getLookupByKey
|
||||||
@ -394,13 +386,7 @@ object TransactionCoder {
|
|||||||
key <- decodeKeyWithMaintainers(decodeCid, protoLookupByKey.getKeyWithMaintainers)
|
key <- decodeKeyWithMaintainers(decodeCid, protoLookupByKey.getKeyWithMaintainers)
|
||||||
cid <- decodeCid.decodeOptional(protoLookupByKey.getContractIdStruct)
|
cid <- decodeCid.decodeOptional(protoLookupByKey.getContractIdStruct)
|
||||||
} yield
|
} yield
|
||||||
(
|
ni -> NodeLookupByKey[Cid, Value.VersionedValue[Cid]](templateId, None, key, cid, version)
|
||||||
ni,
|
|
||||||
VersionedNode(
|
|
||||||
version,
|
|
||||||
NodeLookupByKey[Cid, Value.VersionedValue[Cid]](templateId, None, key, cid)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
case NodeTypeCase.NODETYPE_NOT_SET => Left(DecodeError("Unset Node type"))
|
case NodeTypeCase.NODETYPE_NOT_SET => Left(DecodeError("Unset Node type"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -456,12 +442,12 @@ object TransactionCoder {
|
|||||||
case (builderOrError, (nid, _)) =>
|
case (builderOrError, (nid, _)) =>
|
||||||
for {
|
for {
|
||||||
builder <- builderOrError
|
builder <- builderOrError
|
||||||
encodedNode <- encodeVersionedNode(
|
encodedNode <- encodeNode(
|
||||||
encodeNid,
|
encodeNid,
|
||||||
encodeCid,
|
encodeCid,
|
||||||
transaction.version,
|
transaction.version,
|
||||||
nid,
|
nid,
|
||||||
transaction.versionedNodes(nid),
|
transaction.nodes(nid),
|
||||||
)
|
)
|
||||||
} yield builder.addNodes(encodedNode)
|
} yield builder.addNodes(encodedNode)
|
||||||
}
|
}
|
||||||
@ -529,7 +515,8 @@ object TransactionCoder {
|
|||||||
.map(_.toImmArray)
|
.map(_.toImmArray)
|
||||||
|
|
||||||
val nodes = protoTx.getNodesList.asScala
|
val nodes = protoTx.getNodesList.asScala
|
||||||
.foldLeft[Either[DecodeError, HashMap[Nid, VersionedNode[Nid, Cid]]]](Right(HashMap.empty)) {
|
.foldLeft[Either[DecodeError, HashMap[Nid, GenNode.WithTxValue[Nid, Cid]]]](
|
||||||
|
Right(HashMap.empty)) {
|
||||||
case (Left(e), _) => Left(e)
|
case (Left(e), _) => Left(e)
|
||||||
case (Right(acc), s) =>
|
case (Right(acc), s) =>
|
||||||
decodeVersionedNode(decodeNid, decodeCid, txVersion, s).map(acc + _)
|
decodeVersionedNode(decodeNid, decodeCid, txVersion, s).map(acc + _)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
package com.daml.lf
|
package com.daml.lf
|
||||||
package transaction
|
package transaction
|
||||||
|
|
||||||
import com.daml.lf.data.{ImmArray, Ref}
|
import com.daml.lf.data.ImmArray
|
||||||
import com.daml.lf.language.LanguageVersion
|
import com.daml.lf.language.LanguageVersion
|
||||||
import com.daml.lf.value.Value.{ContractId, VersionedValue}
|
import com.daml.lf.value.Value.{ContractId, VersionedValue}
|
||||||
import com.daml.lf.value.{Value, ValueVersion, ValueVersions}
|
import com.daml.lf.value.{Value, ValueVersion, ValueVersions}
|
||||||
@ -16,7 +16,7 @@ final case class TransactionVersion(protoValue: String)
|
|||||||
/**
|
/**
|
||||||
* Currently supported versions of the DAML-LF transaction specification.
|
* Currently supported versions of the DAML-LF transaction specification.
|
||||||
*/
|
*/
|
||||||
private[lf] object TransactionVersions
|
object TransactionVersions
|
||||||
extends LfVersions(versionsAscending = VersionTimeline.ascendingVersions[TransactionVersion])(
|
extends LfVersions(versionsAscending = VersionTimeline.ascendingVersions[TransactionVersion])(
|
||||||
_.protoValue,
|
_.protoValue,
|
||||||
) {
|
) {
|
||||||
@ -24,18 +24,18 @@ private[lf] object TransactionVersions
|
|||||||
import VersionTimeline._
|
import VersionTimeline._
|
||||||
import VersionTimeline.Implicits._
|
import VersionTimeline.Implicits._
|
||||||
|
|
||||||
private[transaction] val minVersion = TransactionVersion("10")
|
val minVersion = TransactionVersion("10")
|
||||||
private[transaction] val minChoiceObservers = TransactionVersion("dev")
|
private[transaction] val minChoiceObservers = TransactionVersion("dev")
|
||||||
private[transaction] val minNodeVersion = TransactionVersion("dev")
|
private[transaction] val minNodeVersion = TransactionVersion("dev")
|
||||||
|
|
||||||
// Older versions are deprecated https://github.com/digital-asset/daml/issues/5220
|
// Older versions are deprecated https://github.com/digital-asset/daml/issues/5220
|
||||||
val StableOutputVersions: VersionRange[TransactionVersion] =
|
private[lf] val StableOutputVersions: VersionRange[TransactionVersion] =
|
||||||
VersionRange(TransactionVersion("10"), TransactionVersion("10"))
|
VersionRange(TransactionVersion("10"), TransactionVersion("10"))
|
||||||
|
|
||||||
val DevOutputVersions: VersionRange[TransactionVersion] =
|
private[lf] val DevOutputVersions: VersionRange[TransactionVersion] =
|
||||||
StableOutputVersions.copy(max = acceptedVersions.last)
|
StableOutputVersions.copy(max = acceptedVersions.last)
|
||||||
|
|
||||||
val Empty: VersionRange[TransactionVersion] =
|
private[lf] val Empty: VersionRange[TransactionVersion] =
|
||||||
VersionRange(acceptedVersions.last, acceptedVersions.head)
|
VersionRange(acceptedVersions.last, acceptedVersions.head)
|
||||||
|
|
||||||
private[lf] def assignValueVersion(nodeVersion: TransactionVersion): ValueVersion =
|
private[lf] def assignValueVersion(nodeVersion: TransactionVersion): ValueVersion =
|
||||||
@ -44,25 +44,21 @@ private[lf] object TransactionVersions
|
|||||||
private[lf] def assignNodeVersion(langVersion: LanguageVersion): TransactionVersion =
|
private[lf] def assignNodeVersion(langVersion: LanguageVersion): TransactionVersion =
|
||||||
VersionTimeline.latestWhenAllPresent(TransactionVersions.minVersion, langVersion)
|
VersionTimeline.latestWhenAllPresent(TransactionVersions.minVersion, langVersion)
|
||||||
|
|
||||||
type UnversionedNode = Node.GenNode[NodeId, Value.ContractId, Value[Value.ContractId]]
|
private[lf] type UnversionedNode = Node.GenNode[NodeId, Value.ContractId, Value[Value.ContractId]]
|
||||||
type VersionedNode = Node.GenNode[NodeId, Value.ContractId, VersionedValue[Value.ContractId]]
|
private[lf] type VersionedNode =
|
||||||
|
Node.GenNode[NodeId, Value.ContractId, VersionedValue[Value.ContractId]]
|
||||||
|
|
||||||
def asVersionedTransaction(
|
private[lf] def asVersionedTransaction(
|
||||||
pkgLangVersions: Ref.PackageId => LanguageVersion,
|
|
||||||
roots: ImmArray[NodeId],
|
roots: ImmArray[NodeId],
|
||||||
nodes: HashMap[NodeId, UnversionedNode],
|
nodes: HashMap[NodeId, UnversionedNode],
|
||||||
): VersionedTransaction[NodeId, Value.ContractId] = {
|
): VersionedTransaction[NodeId, Value.ContractId] = {
|
||||||
|
|
||||||
val versionedNodes = nodes.transform { (_, node) =>
|
val versionedNodes = nodes.transform { (_, node) =>
|
||||||
val nodeVersion = assignNodeVersion(pkgLangVersions(node.templateId.packageId))
|
val valueVersion = assignValueVersion(node.version)
|
||||||
val valueVersion = assignValueVersion(nodeVersion)
|
Node.GenNode.map3(
|
||||||
Node.VersionedNode(
|
identity[NodeId],
|
||||||
nodeVersion,
|
identity[ContractId],
|
||||||
Node.GenNode.map3(
|
VersionedValue[ContractId](valueVersion, _))(node)
|
||||||
identity[NodeId],
|
|
||||||
identity[ContractId],
|
|
||||||
VersionedValue[ContractId](valueVersion, _))(node),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val txVersion = roots.iterator.foldLeft(TransactionVersions.minVersion)((acc, nodeId) =>
|
val txVersion = roots.iterator.foldLeft(TransactionVersions.minVersion)((acc, nodeId) =>
|
||||||
|
@ -57,9 +57,9 @@ class TransactionCoderSpec
|
|||||||
forAll(malformedCreateNodeGen, transactionVersionGen, transactionVersionGen) {
|
forAll(malformedCreateNodeGen, transactionVersionGen, transactionVersionGen) {
|
||||||
(createNode, version1, version2) =>
|
(createNode, version1, version2) =>
|
||||||
val (nodeVersion, txVersion) = inIncreasingOrder(version1, version2)
|
val (nodeVersion, txVersion) = inIncreasingOrder(version1, version2)
|
||||||
val versionedNode = VersionedNode(nodeVersion, createNode)
|
val versionedNode = createNode.updateVersion(nodeVersion)
|
||||||
val Right(encodedNode) = TransactionCoder
|
val Right(encodedNode) = TransactionCoder
|
||||||
.encodeVersionedNode(
|
.encodeNode(
|
||||||
TransactionCoder.NidEncoder,
|
TransactionCoder.NidEncoder,
|
||||||
ValueCoder.CidEncoder,
|
ValueCoder.CidEncoder,
|
||||||
txVersion,
|
txVersion,
|
||||||
@ -86,10 +86,10 @@ class TransactionCoderSpec
|
|||||||
(fetchNode, version1, version2) =>
|
(fetchNode, version1, version2) =>
|
||||||
val (nodeVersion, txVersion) = inIncreasingOrder(version1, version2)
|
val (nodeVersion, txVersion) = inIncreasingOrder(version1, version2)
|
||||||
|
|
||||||
val versionedNode = VersionedNode(nodeVersion, withoutByKeyFlag(fetchNode))
|
val versionedNode = withoutByKeyFlag(fetchNode).updateVersion(nodeVersion)
|
||||||
val encodedNode =
|
val encodedNode =
|
||||||
TransactionCoder
|
TransactionCoder
|
||||||
.encodeVersionedNode(
|
.encodeNode(
|
||||||
TransactionCoder.NidEncoder,
|
TransactionCoder.NidEncoder,
|
||||||
ValueCoder.CidEncoder,
|
ValueCoder.CidEncoder,
|
||||||
txVersion,
|
txVersion,
|
||||||
@ -118,10 +118,10 @@ class TransactionCoderSpec
|
|||||||
val (nodeVersion, txVersion) = inIncreasingOrder(version1, version2)
|
val (nodeVersion, txVersion) = inIncreasingOrder(version1, version2)
|
||||||
|
|
||||||
val normalizedNode = minimalistNode(nodeVersion)(exerciseNode)
|
val normalizedNode = minimalistNode(nodeVersion)(exerciseNode)
|
||||||
val versionedNode = VersionedNode(nodeVersion, normalizedNode)
|
val versionedNode = normalizedNode.updateVersion(nodeVersion)
|
||||||
val Right(encodedNode) =
|
val Right(encodedNode) =
|
||||||
TransactionCoder
|
TransactionCoder
|
||||||
.encodeVersionedNode(
|
.encodeNode(
|
||||||
TransactionCoder.NidEncoder,
|
TransactionCoder.NidEncoder,
|
||||||
ValueCoder.CidEncoder,
|
ValueCoder.CidEncoder,
|
||||||
txVersion,
|
txVersion,
|
||||||
@ -147,8 +147,8 @@ class TransactionCoderSpec
|
|||||||
forAll(noDanglingRefGenVersionedTransaction, minSuccessful(50)) { tx =>
|
forAll(noDanglingRefGenVersionedTransaction, minSuccessful(50)) { tx =>
|
||||||
val tx2 = VersionedTransaction(
|
val tx2 = VersionedTransaction(
|
||||||
tx.version,
|
tx.version,
|
||||||
tx.versionedNodes.transform((_, node) =>
|
tx.nodes.transform((_, node) =>
|
||||||
VersionedNode(node.version, minimalistNode(node.version)(node.node))),
|
minimalistNode(node.version)(node.updateVersion(node.version))),
|
||||||
tx.roots,
|
tx.roots,
|
||||||
)
|
)
|
||||||
inside(
|
inside(
|
||||||
@ -175,7 +175,12 @@ class TransactionCoderSpec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"succeed with encoding under later version if succeeded under earlier version" in
|
"succeed with encoding under later version if succeeded under earlier version" in {
|
||||||
|
def overrideNodeVersions[Nid, Cid](tx: GenTransaction.WithTxValue[Nid, Cid]) = {
|
||||||
|
tx.copy(nodes = tx.nodes.transform((_, node) =>
|
||||||
|
node.updateVersion(TransactionVersions.minVersion)))
|
||||||
|
}
|
||||||
|
|
||||||
forAll(noDanglingRefGenTransaction, minSuccessful(50)) { tx =>
|
forAll(noDanglingRefGenTransaction, minSuccessful(50)) { tx =>
|
||||||
forAll(transactionVersionGen, transactionVersionGen, minSuccessful(20)) {
|
forAll(transactionVersionGen, transactionVersionGen, minSuccessful(20)) {
|
||||||
(txVer1, txVer2) =>
|
(txVer1, txVer2) =>
|
||||||
@ -210,14 +215,16 @@ class TransactionCoderSpec
|
|||||||
)),
|
)),
|
||||||
) {
|
) {
|
||||||
case (Right(decWithMin), Right(decWithMax)) =>
|
case (Right(decWithMin), Right(decWithMax)) =>
|
||||||
decWithMin.transaction shouldBe minimalistTx(txvMin, tx)
|
overrideNodeVersions(decWithMin.transaction) shouldBe
|
||||||
decWithMin.transaction shouldBe
|
overrideNodeVersions(minimalistTx(txvMin, tx))
|
||||||
minimalistTx(txvMin, decWithMax.transaction)
|
overrideNodeVersions(decWithMin.transaction) shouldBe
|
||||||
|
overrideNodeVersions(minimalistTx(txvMin, decWithMax.transaction))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
"transactions decoding should fail when unsupported value version received" in
|
"transactions decoding should fail when unsupported value version received" in
|
||||||
forAll(noDanglingRefGenTransaction, minSuccessful(50)) { tx =>
|
forAll(noDanglingRefGenTransaction, minSuccessful(50)) { tx =>
|
||||||
@ -260,7 +267,7 @@ class TransactionCoderSpec
|
|||||||
ValueCoder.CidEncoder,
|
ValueCoder.CidEncoder,
|
||||||
VersionedTransaction(
|
VersionedTransaction(
|
||||||
badTxVer,
|
badTxVer,
|
||||||
tx.nodes.mapValues(VersionedNode(badTxVer, _)),
|
tx.nodes.mapValues(_.updateVersion(badTxVer)),
|
||||||
tx.roots),
|
tx.roots),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -296,15 +303,16 @@ class TransactionCoderSpec
|
|||||||
signatories = Set(Party.assertFromString("alice")),
|
signatories = Set(Party.assertFromString("alice")),
|
||||||
stakeholders = Set(Party.assertFromString("alice"), Party.assertFromString("bob")),
|
stakeholders = Set(Party.assertFromString("alice"), Party.assertFromString("bob")),
|
||||||
key = None,
|
key = None,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
|
|
||||||
forEvery(transactionVersions) { version =>
|
forEvery(transactionVersions) { version =>
|
||||||
val versionedNode = VersionedNode(version, node)
|
val versionedNode = node.updateVersion(version)
|
||||||
val roots = ImmArray.ImmArraySeq.range(0, 10000).map(NodeId(_)).toImmArray
|
val roots = ImmArray.ImmArraySeq.range(0, 10000).map(NodeId(_)).toImmArray
|
||||||
val nodes = roots.iterator.map(nid => nid -> versionedNode).toMap
|
val nodes = roots.iterator.map(nid => nid -> versionedNode).toMap
|
||||||
val tx = VersionedTransaction(
|
val tx = VersionedTransaction(
|
||||||
version,
|
version,
|
||||||
versionedNodes = nodes,
|
nodes = nodes.mapValues(_.copy(version = version)),
|
||||||
roots = roots
|
roots = roots
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -346,12 +354,12 @@ class TransactionCoderSpec
|
|||||||
|
|
||||||
forEvery(transactionVersions) { txVersion =>
|
forEvery(transactionVersions) { txVersion =>
|
||||||
val result = TransactionCoder
|
val result = TransactionCoder
|
||||||
.encodeVersionedNode(
|
.encodeNode(
|
||||||
TransactionCoder.NidEncoder,
|
TransactionCoder.NidEncoder,
|
||||||
ValueCoder.CidEncoder,
|
ValueCoder.CidEncoder,
|
||||||
txVersion,
|
txVersion,
|
||||||
NodeId(0),
|
NodeId(0),
|
||||||
VersionedNode(v10, normalized)
|
normalized.updateVersion(v10),
|
||||||
)
|
)
|
||||||
|
|
||||||
result.isLeft shouldBe shouldFail
|
result.isLeft shouldBe shouldFail
|
||||||
@ -369,12 +377,12 @@ class TransactionCoderSpec
|
|||||||
val normalizedNode = minimalistNode(nodeVersion)(node)
|
val normalizedNode = minimalistNode(nodeVersion)(node)
|
||||||
|
|
||||||
TransactionCoder
|
TransactionCoder
|
||||||
.encodeVersionedNode(
|
.encodeNode(
|
||||||
TransactionCoder.NidEncoder,
|
TransactionCoder.NidEncoder,
|
||||||
ValueCoder.CidEncoder,
|
ValueCoder.CidEncoder,
|
||||||
txVersion,
|
txVersion,
|
||||||
nodeId,
|
nodeId,
|
||||||
VersionedNode(nodeVersion, normalizedNode)
|
normalizedNode.updateVersion(nodeVersion),
|
||||||
) shouldBe 'left
|
) shouldBe 'left
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -389,11 +397,11 @@ class TransactionCoderSpec
|
|||||||
|
|
||||||
forAll(danglingRefGenNode, Gen.asciiStr, minSuccessful(10)) {
|
forAll(danglingRefGenNode, Gen.asciiStr, minSuccessful(10)) {
|
||||||
case ((nodeId, node), str) =>
|
case ((nodeId, node), str) =>
|
||||||
val normalizedNode = VersionedNode(v10, normalize(node))
|
val normalizedNode = normalize(node.updateVersion(v10))
|
||||||
|
|
||||||
val Right(encoded) = for {
|
val Right(encoded) = for {
|
||||||
encoded <- TransactionCoder
|
encoded <- TransactionCoder
|
||||||
.encodeVersionedNode(
|
.encodeNode(
|
||||||
TransactionCoder.NidEncoder,
|
TransactionCoder.NidEncoder,
|
||||||
ValueCoder.CidEncoder,
|
ValueCoder.CidEncoder,
|
||||||
v10,
|
v10,
|
||||||
@ -424,10 +432,10 @@ class TransactionCoderSpec
|
|||||||
whenever(version1 != version2) {
|
whenever(version1 != version2) {
|
||||||
val (txVersion, nodeVersion) = inIncreasingOrder(version1, version2)
|
val (txVersion, nodeVersion) = inIncreasingOrder(version1, version2)
|
||||||
|
|
||||||
val normalizedNode = VersionedNode(nodeVersion, minimalistNode(nodeVersion)(node))
|
val normalizedNode = minimalistNode(nodeVersion)(node).updateVersion(nodeVersion)
|
||||||
|
|
||||||
val Right(encoded) = TransactionCoder
|
val Right(encoded) = TransactionCoder
|
||||||
.encodeVersionedNode(
|
.encodeNode(
|
||||||
TransactionCoder.NidEncoder,
|
TransactionCoder.NidEncoder,
|
||||||
ValueCoder.CidEncoder,
|
ValueCoder.CidEncoder,
|
||||||
nodeVersion,
|
nodeVersion,
|
||||||
@ -457,12 +465,12 @@ class TransactionCoderSpec
|
|||||||
minSuccessful(50),
|
minSuccessful(50),
|
||||||
) { (nodeIdx, node, strings) =>
|
) { (nodeIdx, node, strings) =>
|
||||||
val nodeId = NodeId(nodeIdx)
|
val nodeId = NodeId(nodeIdx)
|
||||||
val normalizedNode = VersionedNode(v10, normalize(node))
|
val normalizedNode = normalize(node).updateVersion(v10)
|
||||||
|
|
||||||
val Right(encoded) =
|
val Right(encoded) =
|
||||||
for {
|
for {
|
||||||
encoded <- TransactionCoder
|
encoded <- TransactionCoder
|
||||||
.encodeVersionedNode(
|
.encodeNode(
|
||||||
TransactionCoder.NidEncoder,
|
TransactionCoder.NidEncoder,
|
||||||
ValueCoder.CidEncoder,
|
ValueCoder.CidEncoder,
|
||||||
v10,
|
v10,
|
||||||
@ -607,8 +615,8 @@ class TransactionCoderSpec
|
|||||||
private def versionNodes[Nid, Cid](
|
private def versionNodes[Nid, Cid](
|
||||||
version: TransactionVersion,
|
version: TransactionVersion,
|
||||||
nodes: Map[Nid, GenNode[Nid, Cid, Tx.Value[Cid]]],
|
nodes: Map[Nid, GenNode[Nid, Cid, Tx.Value[Cid]]],
|
||||||
): Map[Nid, VersionedNode[Nid, Cid]] =
|
): Map[Nid, GenNode.WithTxValue[Nid, Cid]] =
|
||||||
nodes.mapValues(VersionedNode(version, _))
|
nodes.mapValues(_.updateVersion(version))
|
||||||
|
|
||||||
private[this] def inIncreasingOrder(version1: TransactionVersion, version2: TransactionVersion) =
|
private[this] def inIncreasingOrder(version1: TransactionVersion, version2: TransactionVersion) =
|
||||||
if (version1 precedes version2)
|
if (version1 precedes version2)
|
||||||
|
@ -12,10 +12,10 @@ import com.daml.lf.transaction.GenTransaction.{
|
|||||||
NotWellFormedError,
|
NotWellFormedError,
|
||||||
OrphanedNode
|
OrphanedNode
|
||||||
}
|
}
|
||||||
import com.daml.lf.transaction.Node.{GenNode, NodeCreate, NodeExercises, VersionedNode}
|
import com.daml.lf.transaction.Node.{GenNode, NodeCreate, NodeExercises}
|
||||||
import com.daml.lf.value.Value.ContractId
|
import com.daml.lf.value.Value.ContractId
|
||||||
import com.daml.lf.value.{Value => V}
|
import com.daml.lf.value.{Value => V}
|
||||||
import com.daml.lf.value.test.ValueGenerators.{danglingRefGenNode, transactionVersionGen}
|
import com.daml.lf.value.test.ValueGenerators.danglingRefGenNode
|
||||||
import org.scalacheck.Gen
|
import org.scalacheck.Gen
|
||||||
import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks
|
import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks
|
||||||
import org.scalatest.matchers.should.Matchers
|
import org.scalatest.matchers.should.Matchers
|
||||||
@ -133,19 +133,19 @@ class TransactionSpec extends AnyFreeSpec with Matchers with ScalaCheckDrivenPro
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
"isReplayedBy" - {
|
"isReplayedBy" - {
|
||||||
def genTrans(node: VersionedNode[NodeId, ContractId]) = {
|
def genTrans(node: GenNode.WithTxValue[NodeId, ContractId]) = {
|
||||||
val nid = NodeId(1)
|
val nid = NodeId(1)
|
||||||
VersionedTransaction(node.version, HashMap(nid -> node), ImmArray(nid))
|
VersionedTransaction(node.version, HashMap(nid -> node), ImmArray(nid))
|
||||||
}
|
}
|
||||||
|
|
||||||
def isReplayedBy(
|
def isReplayedBy(
|
||||||
n1: VersionedNode[NodeId, ContractId],
|
n1: GenNode.WithTxValue[NodeId, ContractId],
|
||||||
n2: VersionedNode[NodeId, ContractId],
|
n2: GenNode.WithTxValue[NodeId, ContractId],
|
||||||
) = Transaction.isReplayedBy(genTrans(n1), genTrans(n2))
|
) = Transaction.isReplayedBy(genTrans(n1), genTrans(n2))
|
||||||
|
|
||||||
// the whole-transaction-relevant parts are handled by equalForest testing
|
// the whole-transaction-relevant parts are handled by equalForest testing
|
||||||
type CidVal[F[_, _]] = F[V.ContractId, V.VersionedValue[V.ContractId]]
|
type CidVal[F[_, _]] = F[V.ContractId, V.VersionedValue[V.ContractId]]
|
||||||
val genEmptyNode: Gen[VersionedNode[Nothing, V.ContractId]] =
|
val genEmptyNode: Gen[GenNode.WithTxValue[Nothing, V.ContractId]] =
|
||||||
for {
|
for {
|
||||||
entry <- danglingRefGenNode
|
entry <- danglingRefGenNode
|
||||||
node = entry match {
|
node = entry match {
|
||||||
@ -153,8 +153,7 @@ class TransactionSpec extends AnyFreeSpec with Matchers with ScalaCheckDrivenPro
|
|||||||
case (_, ne: Node.NodeExercises.WithTxValue[_, V.ContractId]) =>
|
case (_, ne: Node.NodeExercises.WithTxValue[_, V.ContractId]) =>
|
||||||
ne.copy(children = ImmArray.empty)
|
ne.copy(children = ImmArray.empty)
|
||||||
}
|
}
|
||||||
version <- transactionVersionGen
|
} yield node
|
||||||
} yield VersionedNode(version, node)
|
|
||||||
|
|
||||||
"is reflexive" in forAll(genEmptyNode) { n =>
|
"is reflexive" in forAll(genEmptyNode) { n =>
|
||||||
isReplayedBy(n, n) shouldBe Right(())
|
isReplayedBy(n, n) shouldBe Right(())
|
||||||
@ -167,7 +166,7 @@ class TransactionSpec extends AnyFreeSpec with Matchers with ScalaCheckDrivenPro
|
|||||||
if (randomVersion != v) randomVersion else versions.last
|
if (randomVersion != v) randomVersion else versions.last
|
||||||
}
|
}
|
||||||
forAll(genEmptyNode, minSuccessful(10)) { n =>
|
forAll(genEmptyNode, minSuccessful(10)) { n =>
|
||||||
val m = n.copy(version = diffVersion(n.version))
|
val m = n.updateVersion(diffVersion(n.version))
|
||||||
isReplayedBy(n, m) shouldBe 'left
|
isReplayedBy(n, m) shouldBe 'left
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,15 +179,14 @@ class TransactionSpec extends AnyFreeSpec with Matchers with ScalaCheckDrivenPro
|
|||||||
|
|
||||||
"ignores location" in forAll(genEmptyNode) { n =>
|
"ignores location" in forAll(genEmptyNode) { n =>
|
||||||
val withoutLocation = {
|
val withoutLocation = {
|
||||||
val VersionedNode(version, node) = n
|
val nodeWithoutLocation = n match {
|
||||||
val nodeWithoutLocation = node match {
|
|
||||||
case nc: CidVal[Node.NodeCreate] => nc copy (optLocation = None)
|
case nc: CidVal[Node.NodeCreate] => nc copy (optLocation = None)
|
||||||
case nf: Node.NodeFetch.WithTxValue[V.ContractId] => nf copy (optLocation = None)
|
case nf: Node.NodeFetch.WithTxValue[V.ContractId] => nf copy (optLocation = None)
|
||||||
case ne: Node.NodeExercises.WithTxValue[Nothing, V.ContractId] =>
|
case ne: Node.NodeExercises.WithTxValue[Nothing, V.ContractId] =>
|
||||||
ne copy (optLocation = None)
|
ne copy (optLocation = None)
|
||||||
case nl: CidVal[Node.NodeLookupByKey] => nl copy (optLocation = None)
|
case nl: CidVal[Node.NodeLookupByKey] => nl copy (optLocation = None)
|
||||||
}
|
}
|
||||||
VersionedNode(version, nodeWithoutLocation)
|
nodeWithoutLocation
|
||||||
}
|
}
|
||||||
isReplayedBy(withoutLocation, n) shouldBe Right(())
|
isReplayedBy(withoutLocation, n) shouldBe Right(())
|
||||||
isReplayedBy(n, withoutLocation) shouldBe Right(())
|
isReplayedBy(n, withoutLocation) shouldBe Right(())
|
||||||
@ -266,7 +264,8 @@ object TransactionSpec {
|
|||||||
children = children,
|
children = children,
|
||||||
exerciseResult = if (hasExerciseResult) Some(V.ValueUnit) else None,
|
exerciseResult = if (hasExerciseResult) Some(V.ValueUnit) else None,
|
||||||
key = None,
|
key = None,
|
||||||
byKey = false
|
byKey = false,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
|
|
||||||
val dummyCid = V.ContractId.V1.assertBuild(
|
val dummyCid = V.ContractId.V1.assertBuild(
|
||||||
@ -289,6 +288,7 @@ object TransactionSpec {
|
|||||||
signatories = Set.empty,
|
signatories = Set.empty,
|
||||||
stakeholders = Set.empty,
|
stakeholders = Set.empty,
|
||||||
key = None,
|
key = None,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
|
|
||||||
implicit def toChoiceName(s: String): Ref.Name = Ref.Name.assertFromString(s)
|
implicit def toChoiceName(s: String): Ref.Name = Ref.Name.assertFromString(s)
|
||||||
|
@ -488,7 +488,7 @@ class IdeClient(val compiledPackages: CompiledPackages) extends ScriptLedgerClie
|
|||||||
case SResultNeedKey(keyWithMaintainers, committers, cb) =>
|
case SResultNeedKey(keyWithMaintainers, committers, cb) =>
|
||||||
scenarioRunner.lookupKey(keyWithMaintainers.globalKey, committers, cb).toTry.get
|
scenarioRunner.lookupKey(keyWithMaintainers.globalKey, committers, cb).toTry.get
|
||||||
case SResultFinalValue(SUnit) =>
|
case SResultFinalValue(SUnit) =>
|
||||||
onLedger.ptx.finish(machine.compiledPackages.packageLanguageVersion) match {
|
onLedger.ptx.finish match {
|
||||||
case PartialTransaction.CompleteTransaction(tx) =>
|
case PartialTransaction.CompleteTransaction(tx) =>
|
||||||
val results: ImmArray[ScriptLedgerClient.CommandResult] = tx.roots.map { n =>
|
val results: ImmArray[ScriptLedgerClient.CommandResult] = tx.roots.map { n =>
|
||||||
tx.nodes(n) match {
|
tx.nodes(n) match {
|
||||||
|
@ -53,7 +53,7 @@ private[migration] class V5_1__Populate_Event_Data extends BaseJavaMigration {
|
|||||||
val data = txs.flatMap {
|
val data = txs.flatMap {
|
||||||
case (txId, tx) =>
|
case (txId, tx) =>
|
||||||
tx.nodes.collect {
|
tx.nodes.collect {
|
||||||
case (nodeId, NodeCreate(cid, _, _, signatories, stakeholders, _)) =>
|
case (nodeId, NodeCreate(cid, _, _, signatories, stakeholders, _, _)) =>
|
||||||
(cid, EventId(txId, nodeId), signatories, stakeholders -- signatories)
|
(cid, EventId(txId, nodeId), signatories, stakeholders -- signatories)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ private[migration] class V10_1__Populate_Event_Data extends BaseJavaMigration {
|
|||||||
val data = txs.flatMap {
|
val data = txs.flatMap {
|
||||||
case (txId, tx) =>
|
case (txId, tx) =>
|
||||||
tx.nodes.collect {
|
tx.nodes.collect {
|
||||||
case (nodeId, NodeCreate(cid, _, _, signatories, stakeholders, _)) =>
|
case (nodeId, NodeCreate(cid, _, _, signatories, stakeholders, _, _)) =>
|
||||||
(cid, EventId(txId, nodeId), signatories, stakeholders -- signatories)
|
(cid, EventId(txId, nodeId), signatories, stakeholders -- signatories)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import java.util.UUID
|
|||||||
|
|
||||||
import com.daml.lf.data.{ImmArray, Ref}
|
import com.daml.lf.data.{ImmArray, Ref}
|
||||||
import com.daml.lf.transaction.Node.{KeyWithMaintainers, NodeCreate, NodeExercises, NodeFetch}
|
import com.daml.lf.transaction.Node.{KeyWithMaintainers, NodeCreate, NodeExercises, NodeFetch}
|
||||||
|
import com.daml.lf.transaction.TransactionVersions
|
||||||
import com.daml.lf.transaction.test.TransactionBuilder
|
import com.daml.lf.transaction.test.TransactionBuilder
|
||||||
import com.daml.lf.value.Value.{ContractInst, ValueParty, VersionedValue}
|
import com.daml.lf.value.Value.{ContractInst, ValueParty, VersionedValue}
|
||||||
import com.daml.lf.value.ValueVersion
|
import com.daml.lf.value.ValueVersion
|
||||||
@ -32,7 +33,8 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
|
|||||||
optLocation = None,
|
optLocation = None,
|
||||||
signatories = Set(alice),
|
signatories = Set(alice),
|
||||||
stakeholders = Set(alice),
|
stakeholders = Set(alice),
|
||||||
key = None
|
key = None,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
contractId -> builder.buildCommitted()
|
contractId -> builder.buildCommitted()
|
||||||
@ -49,7 +51,8 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
|
|||||||
stakeholders = Set(bob),
|
stakeholders = Set(bob),
|
||||||
key = Some(
|
key = Some(
|
||||||
KeyWithMaintainers(ValueParty(bob), Set(bob))
|
KeyWithMaintainers(ValueParty(bob), Set(bob))
|
||||||
)
|
),
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
contractId -> builder.buildCommitted()
|
contractId -> builder.buildCommitted()
|
||||||
@ -72,6 +75,7 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
|
|||||||
exerciseResult = None,
|
exerciseResult = None,
|
||||||
key = None,
|
key = None,
|
||||||
byKey = false,
|
byKey = false,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
builder.add(
|
builder.add(
|
||||||
@ -85,7 +89,8 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
|
|||||||
key = Some(
|
key = Some(
|
||||||
KeyWithMaintainers(ValueParty(bob), Set(bob))
|
KeyWithMaintainers(ValueParty(bob), Set(bob))
|
||||||
),
|
),
|
||||||
byKey = false
|
byKey = false,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
),
|
),
|
||||||
parentId = rootExercise,
|
parentId = rootExercise,
|
||||||
)
|
)
|
||||||
@ -107,6 +112,7 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
|
|||||||
KeyWithMaintainers(ValueParty(bob), Set(bob))
|
KeyWithMaintainers(ValueParty(bob), Set(bob))
|
||||||
),
|
),
|
||||||
byKey = false,
|
byKey = false,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
),
|
),
|
||||||
parentId = rootExercise,
|
parentId = rootExercise,
|
||||||
)
|
)
|
||||||
@ -119,7 +125,8 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
|
|||||||
stakeholders = Set(alice, bob),
|
stakeholders = Set(alice, bob),
|
||||||
key = Some(
|
key = Some(
|
||||||
KeyWithMaintainers(ValueParty(bob), Set(bob))
|
KeyWithMaintainers(ValueParty(bob), Set(bob))
|
||||||
)
|
),
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
),
|
),
|
||||||
parentId = nestedExercise,
|
parentId = nestedExercise,
|
||||||
)
|
)
|
||||||
|
@ -19,7 +19,13 @@ import com.daml.lf.data.Ref.{Identifier, Party}
|
|||||||
import com.daml.lf.data.{ImmArray, Ref}
|
import com.daml.lf.data.{ImmArray, Ref}
|
||||||
import com.daml.lf.transaction.Node._
|
import com.daml.lf.transaction.Node._
|
||||||
import com.daml.lf.transaction.test.TransactionBuilder
|
import com.daml.lf.transaction.test.TransactionBuilder
|
||||||
import com.daml.lf.transaction.{BlindingInfo, CommittedTransaction, Node, NodeId}
|
import com.daml.lf.transaction.{
|
||||||
|
BlindingInfo,
|
||||||
|
CommittedTransaction,
|
||||||
|
Node,
|
||||||
|
NodeId,
|
||||||
|
TransactionVersions
|
||||||
|
}
|
||||||
import com.daml.lf.value.Value
|
import com.daml.lf.value.Value
|
||||||
import com.daml.lf.value.Value.{ContractId, ContractInst, ValueRecord, ValueText, ValueUnit}
|
import com.daml.lf.value.Value.{ContractId, ContractInst, ValueRecord, ValueText, ValueUnit}
|
||||||
import com.daml.logging.LoggingContext
|
import com.daml.logging.LoggingContext
|
||||||
@ -110,7 +116,8 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
|
|||||||
optLocation = None,
|
optLocation = None,
|
||||||
signatories = signatories,
|
signatories = signatories,
|
||||||
stakeholders = signatories,
|
stakeholders = signatories,
|
||||||
key = None
|
key = None,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
|
|
||||||
protected final def createWithStakeholders(
|
protected final def createWithStakeholders(
|
||||||
@ -124,7 +131,8 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
|
|||||||
optLocation = None,
|
optLocation = None,
|
||||||
signatories = signatories,
|
signatories = signatories,
|
||||||
stakeholders = stakeholders,
|
stakeholders = stakeholders,
|
||||||
key = None
|
key = None,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
|
|
||||||
private def exercise(
|
private def exercise(
|
||||||
@ -145,6 +153,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
|
|||||||
exerciseResult = Some(ValueText("some exercise result")),
|
exerciseResult = Some(ValueText("some exercise result")),
|
||||||
key = None,
|
key = None,
|
||||||
byKey = false,
|
byKey = false,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
|
|
||||||
// All non-transient contracts created in a transaction
|
// All non-transient contracts created in a transaction
|
||||||
@ -232,6 +241,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
|
|||||||
exerciseResult = Some(ValueUnit),
|
exerciseResult = Some(ValueUnit),
|
||||||
key = None,
|
key = None,
|
||||||
byKey = false,
|
byKey = false,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
txBuilder.add(
|
txBuilder.add(
|
||||||
@ -244,6 +254,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
|
|||||||
stakeholders = Set(alice),
|
stakeholders = Set(alice),
|
||||||
None,
|
None,
|
||||||
byKey = false,
|
byKey = false,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
),
|
),
|
||||||
exerciseId,
|
exerciseId,
|
||||||
)
|
)
|
||||||
@ -561,7 +572,8 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
|
|||||||
optLocation = None,
|
optLocation = None,
|
||||||
signatories = Set(party),
|
signatories = Set(party),
|
||||||
stakeholders = Set(party),
|
stakeholders = Set(party),
|
||||||
key = Some(KeyWithMaintainers(ValueText(key), Set(party)))
|
key = Some(KeyWithMaintainers(ValueText(key), Set(party))),
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
))
|
))
|
||||||
nextOffset() ->
|
nextOffset() ->
|
||||||
LedgerEntry.Transaction(
|
LedgerEntry.Transaction(
|
||||||
@ -600,6 +612,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
|
|||||||
exerciseResult = Some(ValueUnit),
|
exerciseResult = Some(ValueUnit),
|
||||||
key = maybeKey.map(k => KeyWithMaintainers(ValueText(k), Set(party))),
|
key = maybeKey.map(k => KeyWithMaintainers(ValueText(k), Set(party))),
|
||||||
byKey = false,
|
byKey = false,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
))
|
))
|
||||||
nextOffset() -> LedgerEntry.Transaction(
|
nextOffset() -> LedgerEntry.Transaction(
|
||||||
commandId = Some(UUID.randomUUID().toString),
|
commandId = Some(UUID.randomUUID().toString),
|
||||||
@ -627,6 +640,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
|
|||||||
None,
|
None,
|
||||||
KeyWithMaintainers(ValueText(key), Set(party)),
|
KeyWithMaintainers(ValueText(key), Set(party)),
|
||||||
result,
|
result,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
))
|
))
|
||||||
nextOffset() -> LedgerEntry.Transaction(
|
nextOffset() -> LedgerEntry.Transaction(
|
||||||
commandId = Some(UUID.randomUUID().toString),
|
commandId = Some(UUID.randomUUID().toString),
|
||||||
@ -656,6 +670,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
|
|||||||
stakeholders = Set(party),
|
stakeholders = Set(party),
|
||||||
None,
|
None,
|
||||||
byKey = false,
|
byKey = false,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
))
|
))
|
||||||
nextOffset() -> LedgerEntry.Transaction(
|
nextOffset() -> LedgerEntry.Transaction(
|
||||||
commandId = Some(UUID.randomUUID().toString),
|
commandId = Some(UUID.randomUUID().toString),
|
||||||
|
@ -115,7 +115,7 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
|
|
||||||
val error =
|
val error =
|
||||||
store.validate(
|
store.validate(
|
||||||
transaction = TxBuilder.justCommitted(createContract, TxBuilder.fetch(createContract)),
|
transaction = TxBuilder.justCommitted(createContract, txBuilder.fetch(createContract)),
|
||||||
transactionLedgerEffectiveTime = Instant.now(),
|
transactionLedgerEffectiveTime = Instant.now(),
|
||||||
divulged = Set.empty,
|
divulged = Set.empty,
|
||||||
)
|
)
|
||||||
@ -130,7 +130,7 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
|
|
||||||
val error =
|
val error =
|
||||||
store.validate(
|
store.validate(
|
||||||
transaction = TxBuilder.justCommitted(TxBuilder.fetch(divulgedContract)),
|
transaction = TxBuilder.justCommitted(txBuilder.fetch(divulgedContract)),
|
||||||
transactionLedgerEffectiveTime = Instant.now(),
|
transactionLedgerEffectiveTime = Instant.now(),
|
||||||
divulged = Set(divulgedContract.coid),
|
divulged = Set(divulgedContract.coid),
|
||||||
)
|
)
|
||||||
@ -145,7 +145,7 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
|
|
||||||
val error =
|
val error =
|
||||||
store.validate(
|
store.validate(
|
||||||
transaction = TxBuilder.justCommitted(TxBuilder.fetch(missingCreate)),
|
transaction = TxBuilder.justCommitted(txBuilder.fetch(missingCreate)),
|
||||||
transactionLedgerEffectiveTime = Instant.now(),
|
transactionLedgerEffectiveTime = Instant.now(),
|
||||||
divulged = Set.empty,
|
divulged = Set.empty,
|
||||||
)
|
)
|
||||||
@ -161,7 +161,7 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
val error =
|
val error =
|
||||||
store.validate(
|
store.validate(
|
||||||
transaction = TxBuilder
|
transaction = TxBuilder
|
||||||
.justCommitted(createContract, TxBuilder.lookupByKey(createContract, found = true)),
|
.justCommitted(createContract, txBuilder.lookupByKey(createContract, found = true)),
|
||||||
transactionLedgerEffectiveTime = Instant.now(),
|
transactionLedgerEffectiveTime = Instant.now(),
|
||||||
divulged = Set.empty,
|
divulged = Set.empty,
|
||||||
)
|
)
|
||||||
@ -177,7 +177,7 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
val error =
|
val error =
|
||||||
store.validate(
|
store.validate(
|
||||||
transaction =
|
transaction =
|
||||||
TxBuilder.justCommitted(TxBuilder.lookupByKey(missingCreate, found = true)),
|
TxBuilder.justCommitted(txBuilder.lookupByKey(missingCreate, found = true)),
|
||||||
transactionLedgerEffectiveTime = Instant.now(),
|
transactionLedgerEffectiveTime = Instant.now(),
|
||||||
divulged = Set.empty,
|
divulged = Set.empty,
|
||||||
)
|
)
|
||||||
@ -198,7 +198,7 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
val error =
|
val error =
|
||||||
store.validate(
|
store.validate(
|
||||||
transaction =
|
transaction =
|
||||||
TxBuilder.justCommitted(TxBuilder.lookupByKey(missingContract, found = false)),
|
TxBuilder.justCommitted(txBuilder.lookupByKey(missingContract, found = false)),
|
||||||
transactionLedgerEffectiveTime = Instant.now(),
|
transactionLedgerEffectiveTime = Instant.now(),
|
||||||
divulged = Set.empty,
|
divulged = Set.empty,
|
||||||
)
|
)
|
||||||
@ -276,7 +276,7 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
|
|
||||||
val error =
|
val error =
|
||||||
store.validate(
|
store.validate(
|
||||||
transaction = TxBuilder.justCommitted(TxBuilder.fetch(committedContract)),
|
transaction = TxBuilder.justCommitted(txBuilder.fetch(committedContract)),
|
||||||
transactionLedgerEffectiveTime = committedContractLedgerEffectiveTime,
|
transactionLedgerEffectiveTime = committedContractLedgerEffectiveTime,
|
||||||
divulged = Set.empty,
|
divulged = Set.empty,
|
||||||
)
|
)
|
||||||
@ -289,7 +289,7 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
|
|
||||||
val error =
|
val error =
|
||||||
store.validate(
|
store.validate(
|
||||||
transaction = TxBuilder.justCommitted(TxBuilder.fetch(committedContract)),
|
transaction = TxBuilder.justCommitted(txBuilder.fetch(committedContract)),
|
||||||
transactionLedgerEffectiveTime = committedContractLedgerEffectiveTime.minusNanos(1),
|
transactionLedgerEffectiveTime = committedContractLedgerEffectiveTime.minusNanos(1),
|
||||||
divulged = Set.empty,
|
divulged = Set.empty,
|
||||||
)
|
)
|
||||||
@ -308,7 +308,7 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
val error =
|
val error =
|
||||||
store.validate(
|
store.validate(
|
||||||
transaction =
|
transaction =
|
||||||
TxBuilder.justCommitted(TxBuilder.lookupByKey(committedContract, found = true)),
|
TxBuilder.justCommitted(txBuilder.lookupByKey(committedContract, found = true)),
|
||||||
transactionLedgerEffectiveTime = committedContractLedgerEffectiveTime,
|
transactionLedgerEffectiveTime = committedContractLedgerEffectiveTime,
|
||||||
divulged = Set.empty,
|
divulged = Set.empty,
|
||||||
)
|
)
|
||||||
@ -322,7 +322,7 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
val error =
|
val error =
|
||||||
store.validate(
|
store.validate(
|
||||||
transaction =
|
transaction =
|
||||||
TxBuilder.justCommitted(TxBuilder.lookupByKey(committedContract, found = false)),
|
TxBuilder.justCommitted(txBuilder.lookupByKey(committedContract, found = false)),
|
||||||
transactionLedgerEffectiveTime = committedContractLedgerEffectiveTime,
|
transactionLedgerEffectiveTime = committedContractLedgerEffectiveTime,
|
||||||
divulged = Set.empty,
|
divulged = Set.empty,
|
||||||
)
|
)
|
||||||
@ -368,7 +368,7 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
|
|
||||||
val error =
|
val error =
|
||||||
store.validate(
|
store.validate(
|
||||||
transaction = TxBuilder.justCommitted(TxBuilder.fetch(divulgedContract)),
|
transaction = TxBuilder.justCommitted(txBuilder.fetch(divulgedContract)),
|
||||||
transactionLedgerEffectiveTime = Instant.now(),
|
transactionLedgerEffectiveTime = Instant.now(),
|
||||||
divulged = Set.empty,
|
divulged = Set.empty,
|
||||||
)
|
)
|
||||||
@ -402,8 +402,10 @@ final class PostCommitValidationSpec extends AnyWordSpec with Matchers {
|
|||||||
|
|
||||||
object PostCommitValidationSpec {
|
object PostCommitValidationSpec {
|
||||||
|
|
||||||
|
val txBuilder = new TxBuilder()
|
||||||
|
|
||||||
private def genTestCreate(): TxBuilder.Create =
|
private def genTestCreate(): TxBuilder.Create =
|
||||||
TxBuilder.create(
|
txBuilder.create(
|
||||||
id = s"#${UUID.randomUUID}",
|
id = s"#${UUID.randomUUID}",
|
||||||
template = "foo:bar:baz",
|
template = "foo:bar:baz",
|
||||||
argument = TxBuilder.record("field" -> "value"),
|
argument = TxBuilder.record("field" -> "value"),
|
||||||
@ -413,7 +415,7 @@ object PostCommitValidationSpec {
|
|||||||
)
|
)
|
||||||
|
|
||||||
private def genTestExercise(create: TxBuilder.Create): TxBuilder.Exercise =
|
private def genTestExercise(create: TxBuilder.Create): TxBuilder.Exercise =
|
||||||
TxBuilder.exercise(
|
txBuilder.exercise(
|
||||||
contract = create,
|
contract = create,
|
||||||
choice = "SomeChoice",
|
choice = "SomeChoice",
|
||||||
consuming = true,
|
consuming = true,
|
||||||
|
@ -272,13 +272,18 @@ private[kvutils] class TransactionCommitter(
|
|||||||
recordedTemplateId,
|
recordedTemplateId,
|
||||||
recordedOptLocation @ _,
|
recordedOptLocation @ _,
|
||||||
recordedKey,
|
recordedKey,
|
||||||
recordedResult),
|
recordedResult,
|
||||||
|
recordedVersion,
|
||||||
|
),
|
||||||
Node.NodeLookupByKey(
|
Node.NodeLookupByKey(
|
||||||
replayedTemplateId,
|
replayedTemplateId,
|
||||||
replayedOptLocation @ _,
|
replayedOptLocation @ _,
|
||||||
replayedKey,
|
replayedKey,
|
||||||
replayedResult))
|
replayedResult,
|
||||||
if recordedTemplateId == replayedTemplateId && recordedKey == replayedKey
|
replayedVersion,
|
||||||
|
))
|
||||||
|
if recordedVersion == replayedVersion &&
|
||||||
|
recordedTemplateId == replayedTemplateId && recordedKey == replayedKey
|
||||||
&& !resultIsCreatedInTx(recordedTx, recordedResult)
|
&& !resultIsCreatedInTx(recordedTx, recordedResult)
|
||||||
&& !resultIsCreatedInTx(replayedTx, replayedResult) =>
|
&& !resultIsCreatedInTx(replayedTx, replayedResult) =>
|
||||||
RejectionReason.Inconsistent(validationError.msg)
|
RejectionReason.Inconsistent(validationError.msg)
|
||||||
|
@ -8,7 +8,7 @@ import com.daml.lf.data.{BackStack, ImmArray}
|
|||||||
import com.daml.lf.engine.Blinding
|
import com.daml.lf.engine.Blinding
|
||||||
import com.daml.lf.transaction.Transaction.Transaction
|
import com.daml.lf.transaction.Transaction.Transaction
|
||||||
import com.daml.lf.transaction.test.TransactionBuilder
|
import com.daml.lf.transaction.test.TransactionBuilder
|
||||||
import com.daml.lf.transaction.Node
|
import com.daml.lf.transaction.{Node, TransactionVersions}
|
||||||
import com.daml.lf.value.Value.{ContractId, ContractInst, ValueText}
|
import com.daml.lf.value.Value.{ContractId, ContractInst, ValueText}
|
||||||
import org.scalatest.matchers.should.Matchers
|
import org.scalatest.matchers.should.Matchers
|
||||||
import org.scalatest.wordspec.AnyWordSpec
|
import org.scalatest.wordspec.AnyWordSpec
|
||||||
@ -28,7 +28,8 @@ class ProjectionsSpec extends AnyWordSpec with Matchers {
|
|||||||
optLocation = None,
|
optLocation = None,
|
||||||
signatories = signatories,
|
signatories = signatories,
|
||||||
stakeholders = stakeholders,
|
stakeholders = stakeholders,
|
||||||
key = None
|
key = None,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
|
|
||||||
def makeExeNode(
|
def makeExeNode(
|
||||||
@ -54,6 +55,7 @@ class ProjectionsSpec extends AnyWordSpec with Matchers {
|
|||||||
exerciseResult = None,
|
exerciseResult = None,
|
||||||
key = None,
|
key = None,
|
||||||
byKey = false,
|
byKey = false,
|
||||||
|
version = TransactionVersions.minVersion,
|
||||||
)
|
)
|
||||||
|
|
||||||
def project(tx: Transaction) = {
|
def project(tx: Transaction) = {
|
||||||
|
@ -36,6 +36,7 @@ import org.scalatest.Inspectors.forEvery
|
|||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
class TransactionCommitterSpec extends AnyWordSpec with Matchers with MockitoSugar {
|
class TransactionCommitterSpec extends AnyWordSpec with Matchers with MockitoSugar {
|
||||||
|
private[this] val txBuilder = TransactionBuilder()
|
||||||
private val metrics = new Metrics(new MetricRegistry)
|
private val metrics = new Metrics(new MetricRegistry)
|
||||||
private val aDamlTransactionEntry = DamlTransactionEntry.newBuilder
|
private val aDamlTransactionEntry = DamlTransactionEntry.newBuilder
|
||||||
.setTransaction(Conversions.encodeTransaction(TransactionBuilder.Empty))
|
.setTransaction(Conversions.encodeTransaction(TransactionBuilder.Empty))
|
||||||
@ -352,7 +353,7 @@ class TransactionCommitterSpec extends AnyWordSpec with Matchers with MockitoSug
|
|||||||
val dummyValue = TransactionBuilder.record("field" -> "value")
|
val dummyValue = TransactionBuilder.record("field" -> "value")
|
||||||
|
|
||||||
def create(contractId: String, key: String = "key"): TransactionBuilder.Create =
|
def create(contractId: String, key: String = "key"): TransactionBuilder.Create =
|
||||||
TransactionBuilder.create(
|
txBuilder.create(
|
||||||
id = contractId,
|
id = contractId,
|
||||||
template = "dummyPackage:DummyModule:DummyTemplate",
|
template = "dummyPackage:DummyModule:DummyTemplate",
|
||||||
argument = dummyValue,
|
argument = dummyValue,
|
||||||
@ -386,7 +387,7 @@ class TransactionCommitterSpec extends AnyWordSpec with Matchers with MockitoSug
|
|||||||
val create1 = create("#someContractId")
|
val create1 = create("#someContractId")
|
||||||
val create2 = create("#otherContractId")
|
val create2 = create("#otherContractId")
|
||||||
|
|
||||||
val exercise = TransactionBuilder.exercise(
|
val exercise = txBuilder.exercise(
|
||||||
contract = createInput,
|
contract = createInput,
|
||||||
choice = "DummyChoice",
|
choice = "DummyChoice",
|
||||||
consuming = false,
|
consuming = false,
|
||||||
@ -398,7 +399,7 @@ class TransactionCommitterSpec extends AnyWordSpec with Matchers with MockitoSug
|
|||||||
|
|
||||||
val lookupNodes @ Seq(lookup1, lookup2, lookupNone, lookupOther @ _) =
|
val lookupNodes @ Seq(lookup1, lookup2, lookupNone, lookupOther @ _) =
|
||||||
Seq(create1 -> true, create2 -> true, create1 -> false, otherKeyCreate -> true) map {
|
Seq(create1 -> true, create2 -> true, create1 -> false, otherKeyCreate -> true) map {
|
||||||
case (create, found) => TransactionBuilder.lookupByKey(create, found)
|
case (create, found) => txBuilder.lookupByKey(create, found)
|
||||||
}
|
}
|
||||||
val Seq(tx1, tx2, txNone, txOther) = lookupNodes map { node =>
|
val Seq(tx1, tx2, txNone, txOther) = lookupNodes map { node =>
|
||||||
val builder = TransactionBuilder()
|
val builder = TransactionBuilder()
|
||||||
|
Loading…
Reference in New Issue
Block a user