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