mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 09:17:43 +03:00
DAML-LF: remove seed from node, move it to transaction meta data. (#5570)
* DAML-LF: remove seed from node, move it to transaction meta data. + redesign seeding to validate partial transaction. CHANGELOG_BEGIN CHANGELOG_END
This commit is contained in:
parent
7067fa432e
commit
a178e3e3e9
@ -8,14 +8,13 @@ import com.daml.lf.command._
|
|||||||
import com.daml.lf.data._
|
import com.daml.lf.data._
|
||||||
import com.daml.lf.data.Ref.{PackageId, ParticipantId, Party}
|
import com.daml.lf.data.Ref.{PackageId, ParticipantId, Party}
|
||||||
import com.daml.lf.language.Ast._
|
import com.daml.lf.language.Ast._
|
||||||
import com.daml.lf.speedy.Compiler
|
import com.daml.lf.speedy.{Compiler, InitialSeeding, Pretty, Command => SpeedyCommand}
|
||||||
import com.daml.lf.speedy.Pretty
|
|
||||||
import com.daml.lf.speedy.Speedy.Machine
|
import com.daml.lf.speedy.Speedy.Machine
|
||||||
import com.daml.lf.speedy.SResult._
|
import com.daml.lf.speedy.SResult._
|
||||||
import com.daml.lf.transaction.Transaction
|
import com.daml.lf.transaction.{Transaction => Tx}
|
||||||
import com.daml.lf.transaction.Node._
|
import com.daml.lf.transaction.Node._
|
||||||
|
import com.daml.lf.transaction.Transaction.{NodeId, Transaction}
|
||||||
import com.daml.lf.value.Value
|
import com.daml.lf.value.Value
|
||||||
import com.daml.lf.speedy.{Command => SpeedyCommand}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows for evaluating [[Commands]] and validating [[Transaction]]s.
|
* Allows for evaluating [[Commands]] and validating [[Transaction]]s.
|
||||||
@ -48,8 +47,8 @@ import com.daml.lf.speedy.{Command => SpeedyCommand}
|
|||||||
* This class is thread safe as long `nextRandomInt` is.
|
* This class is thread safe as long `nextRandomInt` is.
|
||||||
*/
|
*/
|
||||||
final class Engine {
|
final class Engine {
|
||||||
private[this] val _compiledPackages = ConcurrentCompiledPackages()
|
private[this] val compiledPackages = ConcurrentCompiledPackages()
|
||||||
private[this] val _preprocessor = new preprocessing.Preprocessor(_compiledPackages)
|
private[this] val preprocessor = new preprocessing.Preprocessor(compiledPackages)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes commands `cmds` under the authority of `cmds.submitter` and returns one of the following:
|
* Executes commands `cmds` under the authority of `cmds.submitter` and returns one of the following:
|
||||||
@ -82,12 +81,12 @@ final class Engine {
|
|||||||
cmds: Commands,
|
cmds: Commands,
|
||||||
participantId: ParticipantId,
|
participantId: ParticipantId,
|
||||||
submissionSeed: Option[crypto.Hash],
|
submissionSeed: Option[crypto.Hash],
|
||||||
): Result[(Transaction.Transaction, Transaction.Metadata)] = {
|
): Result[(Tx.Transaction, Tx.Metadata)] = {
|
||||||
val submissionTime = cmds.ledgerEffectiveTime
|
val submissionTime = cmds.ledgerEffectiveTime
|
||||||
_preprocessor
|
preprocessor
|
||||||
.preprocessCommands(cmds.commands)
|
.preprocessCommands(cmds.commands)
|
||||||
.flatMap { processedCmds =>
|
.flatMap { processedCmds =>
|
||||||
ShouldCheckSubmitterInMaintainers(_compiledPackages, cmds).flatMap {
|
ShouldCheckSubmitterInMaintainers(compiledPackages, cmds).flatMap {
|
||||||
checkSubmitterInMaintainers =>
|
checkSubmitterInMaintainers =>
|
||||||
interpretCommands(
|
interpretCommands(
|
||||||
validating = false,
|
validating = false,
|
||||||
@ -96,10 +95,9 @@ final class Engine {
|
|||||||
commands = processedCmds,
|
commands = processedCmds,
|
||||||
ledgerTime = cmds.ledgerEffectiveTime,
|
ledgerTime = cmds.ledgerEffectiveTime,
|
||||||
submissionTime = submissionTime,
|
submissionTime = submissionTime,
|
||||||
transactionSeed = submissionSeed.map(
|
seeding = Engine.initialSeeding(submissionSeed, participantId, submissionTime),
|
||||||
crypto.Hash.deriveTransactionSeed(_, participantId, submissionTime)),
|
|
||||||
) map {
|
) map {
|
||||||
case (tx, dependsOnTime) =>
|
case (tx, dependsOnTime, nodeSeeds) =>
|
||||||
// Annotate the transaction with the package dependencies. Since
|
// Annotate the transaction with the package dependencies. Since
|
||||||
// all commands are actions on a contract template, with a fully typed
|
// all commands are actions on a contract template, with a fully typed
|
||||||
// argument, we only need to consider the templates mentioned in the command
|
// argument, we only need to consider the templates mentioned in the command
|
||||||
@ -107,16 +105,18 @@ final class Engine {
|
|||||||
val deps = processedCmds.foldLeft(Set.empty[PackageId]) { (pkgIds, cmd) =>
|
val deps = processedCmds.foldLeft(Set.empty[PackageId]) { (pkgIds, cmd) =>
|
||||||
val pkgId = cmd.templateId.packageId
|
val pkgId = cmd.templateId.packageId
|
||||||
val transitiveDeps =
|
val transitiveDeps =
|
||||||
_compiledPackages
|
compiledPackages
|
||||||
.getPackageDependencies(pkgId)
|
.getPackageDependencies(pkgId)
|
||||||
.getOrElse(
|
.getOrElse(
|
||||||
sys.error(s"INTERNAL ERROR: Missing dependencies of package $pkgId"))
|
sys.error(s"INTERNAL ERROR: Missing dependencies of package $pkgId"))
|
||||||
(pkgIds + pkgId) union transitiveDeps
|
(pkgIds + pkgId) union transitiveDeps
|
||||||
}
|
}
|
||||||
tx -> Transaction.Metadata(
|
tx -> Tx.Metadata(
|
||||||
submissionTime = submissionTime,
|
submissionSeed,
|
||||||
usedPackages = deps,
|
submissionTime,
|
||||||
dependsOnTime = dependsOnTime,
|
deps,
|
||||||
|
dependsOnTime,
|
||||||
|
nodeSeeds,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,47 +124,35 @@ final class Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Behaves like `submit`, but it takes GenNode arguments instead of a Commands argument.
|
* Behaves like `submit`, but it takes a GenNode argument instead of a Commands argument.
|
||||||
* That is, it can be used to reinterpret an already interpreted transaction (since it consists of GenNodes).
|
* That is, it can be used to reinterpret partially an already interpreted transaction (since it consists of GenNodes).
|
||||||
* Formally, the following is guaranteed to hold for all pcs, pkgs, and keys, when evaluated on the same Engine:
|
|
||||||
* evaluate(submit(cmds)) = ResultDone(tx) ==> evaluate(reinterpret(cmds.submitters, txRoots, cmds.ledgerEffectiveTime)) === ResultDone(tx)
|
|
||||||
* where:
|
|
||||||
* evaluate(result) = result.consume(pcs, pkgs, keys)
|
|
||||||
* txRoots = tx.roots.map(id => tx.nodes.get(id).get).toSeq
|
|
||||||
* tx === tx' if tx and tx' are equivalent modulo a renaming of node and relative contract IDs
|
|
||||||
*
|
*
|
||||||
* Moreover, if the transaction tx is valid at time leTime, n belongs to tx.nodes, and subtx is the subtransaction of
|
|
||||||
* tx rooted at n, the following holds:
|
|
||||||
* evaluate(reinterpret(n.requiredAuthorizers, Seq(n), leTime) === subtx
|
|
||||||
*
|
*
|
||||||
* In addition to the errors returned by `submit`, reinterpretation fails with a `ValidationError` whenever `nodes`
|
* [[nodeSeed]] is the seed of the Create and Exercise node as generated during submission.
|
||||||
* contain a relative contract ID, either as the target contract of a fetch, or as an argument to a
|
* If undefined the contract IDs are derive using V0 scheme.
|
||||||
* create or an exercise choice.
|
* The value of [[nodeSeed]] does not matter for other kind of nodes.
|
||||||
*
|
|
||||||
* [[transactionSeed]] is the master hash te be used to derive node and contractId discriminator.
|
|
||||||
* If let undefined, no discriminator will be generated.
|
|
||||||
*/
|
*/
|
||||||
def reinterpret(
|
def reinterpret(
|
||||||
submissionTime: Time.Timestamp,
|
|
||||||
transactionSeed: Option[crypto.Hash],
|
|
||||||
submitters: Set[Party],
|
submitters: Set[Party],
|
||||||
nodes: Seq[GenNode.WithTxValue[Value.NodeId, Value.ContractId]],
|
node: GenNode.WithTxValue[Value.NodeId, Value.ContractId],
|
||||||
|
nodeSeed: Option[crypto.Hash],
|
||||||
|
submissionTime: Time.Timestamp,
|
||||||
ledgerEffectiveTime: Time.Timestamp,
|
ledgerEffectiveTime: Time.Timestamp,
|
||||||
): Result[(Transaction.Transaction, Boolean)] =
|
): Result[(Tx.Transaction, Boolean, ImmArray[(NodeId, crypto.Hash)])] =
|
||||||
for {
|
for {
|
||||||
commands <- Result.sequence(ImmArray(nodes).map(_preprocessor.translateNode))
|
command <- preprocessor.translateNode(node)
|
||||||
checkSubmitterInMaintainers <- ShouldCheckSubmitterInMaintainers(
|
checkSubmitterInMaintainers <- ShouldCheckSubmitterInMaintainers(
|
||||||
_compiledPackages,
|
compiledPackages,
|
||||||
commands.map(_.templateId))
|
ImmArray(command.templateId))
|
||||||
// reinterpret is never used for submission, only for validation.
|
// reinterpret is never used for submission, only for validation.
|
||||||
result <- interpretCommands(
|
result <- interpretCommands(
|
||||||
validating = true,
|
validating = true,
|
||||||
checkSubmitterInMaintainers = checkSubmitterInMaintainers,
|
checkSubmitterInMaintainers = checkSubmitterInMaintainers,
|
||||||
submitters = submitters,
|
submitters = submitters,
|
||||||
commands = commands,
|
commands = ImmArray(command),
|
||||||
ledgerTime = ledgerEffectiveTime,
|
ledgerTime = ledgerEffectiveTime,
|
||||||
submissionTime,
|
submissionTime = submissionTime,
|
||||||
transactionSeed,
|
seeding = InitialSeeding.RootNodeSeeds(ImmArray(nodeSeed)),
|
||||||
)
|
)
|
||||||
} yield result
|
} yield result
|
||||||
|
|
||||||
@ -184,7 +172,7 @@ final class Engine {
|
|||||||
* @param ledgerEffectiveTime time when the transaction is claimed to be submitted
|
* @param ledgerEffectiveTime time when the transaction is claimed to be submitted
|
||||||
*/
|
*/
|
||||||
def validate(
|
def validate(
|
||||||
tx: Transaction.Transaction,
|
tx: Tx.Transaction,
|
||||||
ledgerEffectiveTime: Time.Timestamp,
|
ledgerEffectiveTime: Time.Timestamp,
|
||||||
participantId: Ref.ParticipantId,
|
participantId: Ref.ParticipantId,
|
||||||
submissionTime: Time.Timestamp,
|
submissionTime: Time.Timestamp,
|
||||||
@ -217,9 +205,9 @@ final class Engine {
|
|||||||
// For empty transactions, use an empty set of submitters
|
// For empty transactions, use an empty set of submitters
|
||||||
submitters = submittersOpt.getOrElse(Set.empty)
|
submitters = submittersOpt.getOrElse(Set.empty)
|
||||||
|
|
||||||
commands <- _preprocessor.translateTransactionRoots(tx)
|
commands <- preprocessor.translateTransactionRoots(tx)
|
||||||
checkSubmitterInMaintainers <- ShouldCheckSubmitterInMaintainers(
|
checkSubmitterInMaintainers <- ShouldCheckSubmitterInMaintainers(
|
||||||
_compiledPackages,
|
compiledPackages,
|
||||||
commands.map(_._2.templateId))
|
commands.map(_._2.templateId))
|
||||||
result <- interpretCommands(
|
result <- interpretCommands(
|
||||||
validating = true,
|
validating = true,
|
||||||
@ -227,10 +215,10 @@ final class Engine {
|
|||||||
submitters = submitters,
|
submitters = submitters,
|
||||||
commands = commands.map(_._2),
|
commands = commands.map(_._2),
|
||||||
ledgerTime = ledgerEffectiveTime,
|
ledgerTime = ledgerEffectiveTime,
|
||||||
submissionTime,
|
submissionTime = submissionTime,
|
||||||
submissionSeed.map(crypto.Hash.deriveTransactionSeed(_, participantId, submissionTime))
|
seeding = Engine.initialSeeding(submissionSeed, participantId, submissionTime),
|
||||||
)
|
)
|
||||||
(rtx, _) = result
|
(rtx, _, _) = result
|
||||||
validationResult <- if (tx isReplayedBy rtx) {
|
validationResult <- if (tx isReplayedBy rtx) {
|
||||||
ResultDone(())
|
ResultDone(())
|
||||||
} else {
|
} else {
|
||||||
@ -246,8 +234,7 @@ final class Engine {
|
|||||||
* Submitters are a set, in order to support interpreting subtransactions
|
* Submitters are a set, in order to support interpreting subtransactions
|
||||||
* (a subtransaction can be authorized by multiple parties).
|
* (a subtransaction can be authorized by multiple parties).
|
||||||
*
|
*
|
||||||
* [[transactionSeed]] is the master hash used to derive node and contractId discriminator.
|
* [[seeding]] is seeding used to derive node seed and contractId discriminator.
|
||||||
* If let undefined, no discriminator will be generated.
|
|
||||||
*/
|
*/
|
||||||
private[engine] def interpretCommands(
|
private[engine] def interpretCommands(
|
||||||
validating: Boolean,
|
validating: Boolean,
|
||||||
@ -257,15 +244,15 @@ final class Engine {
|
|||||||
commands: ImmArray[SpeedyCommand],
|
commands: ImmArray[SpeedyCommand],
|
||||||
ledgerTime: Time.Timestamp,
|
ledgerTime: Time.Timestamp,
|
||||||
submissionTime: Time.Timestamp,
|
submissionTime: Time.Timestamp,
|
||||||
transactionSeed: Option[crypto.Hash],
|
seeding: speedy.InitialSeeding,
|
||||||
): Result[(Transaction.Transaction, Boolean)] = {
|
): Result[(Transaction, Boolean, ImmArray[(Tx.NodeId, crypto.Hash)])] = {
|
||||||
val machine = Machine
|
val machine = Machine
|
||||||
.build(
|
.build(
|
||||||
checkSubmitterInMaintainers = checkSubmitterInMaintainers,
|
checkSubmitterInMaintainers = checkSubmitterInMaintainers,
|
||||||
sexpr = Compiler(compiledPackages.packages).compile(commands),
|
sexpr = Compiler(compiledPackages.packages).compile(commands),
|
||||||
compiledPackages = _compiledPackages,
|
compiledPackages = compiledPackages,
|
||||||
submissionTime,
|
submissionTime = submissionTime,
|
||||||
speedy.InitialSeeding(transactionSeed)
|
seeds = seeding,
|
||||||
)
|
)
|
||||||
.copy(validating = validating, committers = submitters)
|
.copy(validating = validating, committers = submitters)
|
||||||
interpretLoop(machine, ledgerTime)
|
interpretLoop(machine, ledgerTime)
|
||||||
@ -276,7 +263,7 @@ final class Engine {
|
|||||||
private[engine] def interpretLoop(
|
private[engine] def interpretLoop(
|
||||||
machine: Machine,
|
machine: Machine,
|
||||||
time: Time.Timestamp
|
time: Time.Timestamp
|
||||||
): Result[(Transaction.Transaction, Boolean)] = {
|
): Result[(Tx.Transaction, Boolean, ImmArray[(Tx.NodeId, crypto.Hash)])] = {
|
||||||
while (!machine.isFinal) {
|
while (!machine.isFinal) {
|
||||||
machine.step() match {
|
machine.step() match {
|
||||||
case SResultContinue =>
|
case SResultContinue =>
|
||||||
@ -293,9 +280,9 @@ final class Engine {
|
|||||||
return Result.needPackage(
|
return Result.needPackage(
|
||||||
pkgId,
|
pkgId,
|
||||||
pkg => {
|
pkg => {
|
||||||
_compiledPackages.addPackage(pkgId, pkg).flatMap {
|
compiledPackages.addPackage(pkgId, pkg).flatMap {
|
||||||
case _ =>
|
case _ =>
|
||||||
callback(_compiledPackages)
|
callback(compiledPackages)
|
||||||
interpretLoop(machine, time)
|
interpretLoop(machine, time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,17 +332,17 @@ final class Engine {
|
|||||||
machine.ptx.finish match {
|
machine.ptx.finish match {
|
||||||
case Left(p) =>
|
case Left(p) =>
|
||||||
ResultError(Error(s"Interpretation error: ended with partial result: $p"))
|
ResultError(Error(s"Interpretation error: ended with partial result: $p"))
|
||||||
case Right(t) => ResultDone(t -> machine.dependsOnTime)
|
case Right(t) => ResultDone((t, machine.dependsOnTime, machine.ptx.nodeSeeds.toImmArray))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def clearPackages(): Unit = _compiledPackages.clear()
|
def clearPackages(): Unit = compiledPackages.clear()
|
||||||
|
|
||||||
/** Note: it's important we return a [[com.daml.lf.CompiledPackages]],
|
/** Note: it's important we return a [[com.daml.lf.CompiledPackages]],
|
||||||
* and not a [[ConcurrentCompiledPackages]], otherwise people would be able
|
* and not a [[ConcurrentCompiledPackages]], otherwise people would be able
|
||||||
* to modify them.
|
* to modify them.
|
||||||
*/
|
*/
|
||||||
def compiledPackages(): CompiledPackages = _compiledPackages
|
def compiledPackages(): CompiledPackages = compiledPackages
|
||||||
|
|
||||||
/** This function can be used to give a package to the engine pre-emptively,
|
/** This function can be used to give a package to the engine pre-emptively,
|
||||||
* rather than having the engine to ask about it through
|
* rather than having the engine to ask about it through
|
||||||
@ -365,9 +352,22 @@ final class Engine {
|
|||||||
* be loaded.
|
* be loaded.
|
||||||
*/
|
*/
|
||||||
def preloadPackage(pkgId: PackageId, pkg: Package): Result[Unit] =
|
def preloadPackage(pkgId: PackageId, pkg: Package): Result[Unit] =
|
||||||
_compiledPackages.addPackage(pkgId, pkg)
|
compiledPackages.addPackage(pkgId, pkg)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Engine {
|
object Engine {
|
||||||
def apply(): Engine = new Engine()
|
def apply(): Engine = new Engine()
|
||||||
|
|
||||||
|
def initialSeeding(
|
||||||
|
submissionSeed: Option[crypto.Hash],
|
||||||
|
participant: Ref.ParticipantId,
|
||||||
|
submissionTime: Time.Timestamp,
|
||||||
|
): InitialSeeding =
|
||||||
|
submissionSeed match {
|
||||||
|
case None =>
|
||||||
|
InitialSeeding.NoSeed
|
||||||
|
case Some(seed) =>
|
||||||
|
InitialSeeding.TransactionSeed(
|
||||||
|
crypto.Hash.deriveTransactionSeed(seed, participant, submissionTime))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,17 +145,9 @@ private[engine] final class Preprocessor(compiledPackages: MutableCompiledPackag
|
|||||||
|
|
||||||
private def getTemplateId(node: Node.GenNode.WithTxValue[Transaction.NodeId, _]) =
|
private def getTemplateId(node: Node.GenNode.WithTxValue[Transaction.NodeId, _]) =
|
||||||
node match {
|
node match {
|
||||||
case Node.NodeCreate(
|
case Node.NodeCreate(coid @ _, coinst, optLoc @ _, sigs @ _, stks @ _, key @ _) =>
|
||||||
nodeSeed @ _,
|
|
||||||
coid @ _,
|
|
||||||
coinst,
|
|
||||||
optLoc @ _,
|
|
||||||
sigs @ _,
|
|
||||||
stks @ _,
|
|
||||||
key @ _) =>
|
|
||||||
coinst.template
|
coinst.template
|
||||||
case Node.NodeExercises(
|
case Node.NodeExercises(
|
||||||
nodeSeed @ _,
|
|
||||||
coid @ _,
|
coid @ _,
|
||||||
templateId,
|
templateId,
|
||||||
choice @ _,
|
choice @ _,
|
||||||
|
@ -48,20 +48,12 @@ private[preprocessing] final class TransactionPreprocessor(
|
|||||||
): speedy.Command = {
|
): speedy.Command = {
|
||||||
|
|
||||||
node match {
|
node match {
|
||||||
case Node.NodeCreate(
|
case Node.NodeCreate(coid @ _, coinst, optLoc @ _, sigs @ _, stks @ _, key @ _) =>
|
||||||
nodeSeed @ _,
|
|
||||||
coid @ _,
|
|
||||||
coinst,
|
|
||||||
optLoc @ _,
|
|
||||||
sigs @ _,
|
|
||||||
stks @ _,
|
|
||||||
key @ _) =>
|
|
||||||
val identifier = coinst.template
|
val identifier = coinst.template
|
||||||
val arg = unsafeAsValueWithAbsoluteContractIds(coinst.arg.value)
|
val arg = unsafeAsValueWithAbsoluteContractIds(coinst.arg.value)
|
||||||
commandPreprocessor.unsafePreprocessCreate(identifier, arg)
|
commandPreprocessor.unsafePreprocessCreate(identifier, arg)
|
||||||
|
|
||||||
case Node.NodeExercises(
|
case Node.NodeExercises(
|
||||||
nodeSeed @ _,
|
|
||||||
coid,
|
coid,
|
||||||
template,
|
template,
|
||||||
choice,
|
choice,
|
||||||
|
@ -17,7 +17,7 @@ import com.daml.lf.transaction.Node._
|
|||||||
import com.daml.lf.transaction.{GenTransaction => GenTx, Transaction => Tx}
|
import com.daml.lf.transaction.{GenTransaction => GenTx, Transaction => Tx}
|
||||||
import com.daml.lf.value.Value
|
import com.daml.lf.value.Value
|
||||||
import Value._
|
import Value._
|
||||||
import com.daml.lf.speedy.{SValue, svalue}
|
import com.daml.lf.speedy.{InitialSeeding, SValue, svalue}
|
||||||
import com.daml.lf.speedy.SValue._
|
import com.daml.lf.speedy.SValue._
|
||||||
import com.daml.lf.command._
|
import com.daml.lf.command._
|
||||||
import com.daml.lf.value.ValueVersions.assertAsVersionedValue
|
import com.daml.lf.value.ValueVersions.assertAsVersionedValue
|
||||||
@ -61,36 +61,6 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
private val (basicTestsPkgId, basicTestsPkg, allPackages) = loadPackage(
|
private val (basicTestsPkgId, basicTestsPkg, allPackages) = loadPackage(
|
||||||
"daml-lf/tests/BasicTests.dar")
|
"daml-lf/tests/BasicTests.dar")
|
||||||
|
|
||||||
def lookupContract(@deprecated("shut up unused arguments warning", "blah") id: AbsoluteContractId)
|
|
||||||
: Option[ContractInst[Tx.Value[AbsoluteContractId]]] = {
|
|
||||||
Some(
|
|
||||||
ContractInst(
|
|
||||||
TypeConName(basicTestsPkgId, "BasicTests:Simple"),
|
|
||||||
assertAsVersionedValue(
|
|
||||||
ValueRecord(
|
|
||||||
Some(Identifier(basicTestsPkgId, "BasicTests:Simple")),
|
|
||||||
ImmArray((Some[Name]("p"), ValueParty(party))))),
|
|
||||||
""
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
def lookupContractForPayout(
|
|
||||||
@deprecated("shut up unused arguments warning", "blah") id: AbsoluteContractId)
|
|
||||||
: Option[ContractInst[Tx.Value[AbsoluteContractId]]] = {
|
|
||||||
Some(
|
|
||||||
ContractInst(
|
|
||||||
TypeConName(basicTestsPkgId, "BasicTests:CallablePayout"),
|
|
||||||
assertAsVersionedValue(
|
|
||||||
ValueRecord(
|
|
||||||
Some(Identifier(basicTestsPkgId, "BasicTests:CallablePayout")),
|
|
||||||
ImmArray(
|
|
||||||
(Some("giver"), ValueParty(alice)),
|
|
||||||
(Some("receiver"), ValueParty(bob))
|
|
||||||
))),
|
|
||||||
""
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
val withKeyTemplate = "BasicTests:WithKey"
|
val withKeyTemplate = "BasicTests:WithKey"
|
||||||
val BasicTests_WithKey = Identifier(basicTestsPkgId, withKeyTemplate)
|
val BasicTests_WithKey = Identifier(basicTestsPkgId, withKeyTemplate)
|
||||||
val withKeyContractInst: ContractInst[Tx.Value[AbsoluteContractId]] =
|
val withKeyContractInst: ContractInst[Tx.Value[AbsoluteContractId]] =
|
||||||
@ -106,11 +76,35 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
""
|
""
|
||||||
)
|
)
|
||||||
|
|
||||||
def lookupContractWithKey(
|
val defaultContracts =
|
||||||
@deprecated("shut up unused arguments warning", "blah") id: AbsoluteContractId)
|
Map(
|
||||||
: Option[ContractInst[Tx.Value[AbsoluteContractId]]] = {
|
toContractId("#BasicTests:Simple:1") ->
|
||||||
Some(withKeyContractInst)
|
ContractInst(
|
||||||
}
|
TypeConName(basicTestsPkgId, "BasicTests:Simple"),
|
||||||
|
assertAsVersionedValue(
|
||||||
|
ValueRecord(
|
||||||
|
Some(Identifier(basicTestsPkgId, "BasicTests:Simple")),
|
||||||
|
ImmArray((Some[Name]("p"), ValueParty(party))))),
|
||||||
|
""
|
||||||
|
),
|
||||||
|
toContractId("#BasicTests:CallablePayout:1") ->
|
||||||
|
ContractInst(
|
||||||
|
TypeConName(basicTestsPkgId, "BasicTests:CallablePayout"),
|
||||||
|
assertAsVersionedValue(
|
||||||
|
ValueRecord(
|
||||||
|
Some(Identifier(basicTestsPkgId, "BasicTests:CallablePayout")),
|
||||||
|
ImmArray(
|
||||||
|
(Some[Ref.Name]("giver"), ValueParty(alice)),
|
||||||
|
(Some[Ref.Name]("receiver"), ValueParty(bob))
|
||||||
|
)
|
||||||
|
)),
|
||||||
|
""
|
||||||
|
),
|
||||||
|
toContractId("#BasicTests:WithKey:1") ->
|
||||||
|
withKeyContractInst
|
||||||
|
)
|
||||||
|
|
||||||
|
val lookupContract = defaultContracts.get(_)
|
||||||
|
|
||||||
def lookupPackage(pkgId: PackageId): Option[Package] = {
|
def lookupPackage(pkgId: PackageId): Option[Package] = {
|
||||||
allPackages.get(pkgId)
|
allPackages.get(pkgId)
|
||||||
@ -122,7 +116,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
BasicTests_WithKey,
|
BasicTests_WithKey,
|
||||||
ValueRecord(_, ImmArray((_, ValueParty(`alice`)), (_, ValueInt64(42)))),
|
ValueRecord(_, ImmArray((_, ValueParty(`alice`)), (_, ValueInt64(42)))),
|
||||||
) =>
|
) =>
|
||||||
Some(toContractId("#1"))
|
Some(toContractId("#BasicTests:WithKey:1"))
|
||||||
case _ =>
|
case _ =>
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -198,7 +192,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
}
|
}
|
||||||
|
|
||||||
"translate exercise commands argument including labels" in {
|
"translate exercise commands argument including labels" in {
|
||||||
val originalCoid = toContractId("#1")
|
val originalCoid = toContractId("#BasicTests:CallablePayout:1")
|
||||||
val templateId = Identifier(basicTestsPkgId, "BasicTests:CallablePayout")
|
val templateId = Identifier(basicTestsPkgId, "BasicTests:CallablePayout")
|
||||||
val command = ExerciseCommand(
|
val command = ExerciseCommand(
|
||||||
templateId,
|
templateId,
|
||||||
@ -208,12 +202,12 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
val res = preprocessor
|
val res = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
res shouldBe 'right
|
res shouldBe 'right
|
||||||
}
|
}
|
||||||
|
|
||||||
"translate exercise commands argument without labels" in {
|
"translate exercise commands argument without labels" in {
|
||||||
val originalCoid = toContractId("#1")
|
val originalCoid = toContractId("#BasicTests:CallablePayout:1")
|
||||||
val templateId = Identifier(basicTestsPkgId, "BasicTests:CallablePayout")
|
val templateId = Identifier(basicTestsPkgId, "BasicTests:CallablePayout")
|
||||||
val command = ExerciseCommand(
|
val command = ExerciseCommand(
|
||||||
templateId,
|
templateId,
|
||||||
@ -223,7 +217,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
val res = preprocessor
|
val res = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
res shouldBe 'right
|
res shouldBe 'right
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +232,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
val res = preprocessor
|
val res = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
res shouldBe 'right
|
res shouldBe 'right
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +247,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
val res = preprocessor
|
val res = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
res shouldBe 'right
|
res shouldBe 'right
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +262,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
val res = preprocessor
|
val res = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
res.left.value.msg should startWith("Missing record label n for record")
|
res.left.value.msg should startWith("Missing record label n for record")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +277,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
val res = preprocessor
|
val res = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
res.left.value.msg should startWith(
|
res.left.value.msg should startWith(
|
||||||
"Impossible to exercise by key, no key is defined for template")
|
"Impossible to exercise by key, no key is defined for template")
|
||||||
}
|
}
|
||||||
@ -299,7 +293,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
val res = preprocessor
|
val res = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
res.left.value.msg should startWith("mismatching type")
|
res.left.value.msg should startWith("mismatching type")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +312,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
val res = preprocessor
|
val res = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
res shouldBe 'right
|
res shouldBe 'right
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -439,14 +433,19 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
"reinterpret to the same result" in {
|
"reinterpret to the same result" in {
|
||||||
val Right((tx, txMeta)) = interpretResult
|
val Right((tx, txMeta)) = interpretResult
|
||||||
val txRoots = tx.roots.map(id => tx.nodes(id)).toSeq
|
val txRoots = tx.roots.map(id => tx.nodes(id))
|
||||||
val txSeed =
|
val nodeSeedMap = txMeta.nodeSeeds.toSeq.toMap
|
||||||
Some(crypto.Hash.deriveTransactionSeed(submissionSeed, participant, txMeta.submissionTime))
|
|
||||||
|
|
||||||
val Right((rtx, _)) =
|
val Right((rtx, _, _)) =
|
||||||
engine
|
reinterpret(
|
||||||
.reinterpret(txMeta.submissionTime, txSeed, Set(party), txRoots, let)
|
engine,
|
||||||
.consume(lookupContract, lookupPackage, lookupKey)
|
Set(party),
|
||||||
|
txRoots,
|
||||||
|
tx.roots.map(nodeSeedMap.get),
|
||||||
|
txMeta.submissionTime,
|
||||||
|
let,
|
||||||
|
lookupPackage
|
||||||
|
)
|
||||||
(tx isReplayedBy rtx) shouldBe true
|
(tx isReplayedBy rtx) shouldBe true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,13 +473,10 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
val templateId = Identifier(basicTestsPkgId, "BasicTests:Simple")
|
val templateId = Identifier(basicTestsPkgId, "BasicTests:Simple")
|
||||||
val hello = Identifier(basicTestsPkgId, "BasicTests:Hello")
|
val hello = Identifier(basicTestsPkgId, "BasicTests:Hello")
|
||||||
val let = Time.Timestamp.now()
|
val let = Time.Timestamp.now()
|
||||||
val txSeed = crypto.Hash.deriveTransactionSeed(submissionSeed, participant, let)
|
val seeding = Engine.initialSeeding(Some(submissionSeed), participant, let)
|
||||||
|
val cid = toContractId("#BasicTests:Simple:1")
|
||||||
val command =
|
val command =
|
||||||
ExerciseCommand(
|
ExerciseCommand(templateId, cid, "Hello", ValueRecord(Some(hello), ImmArray.empty))
|
||||||
templateId,
|
|
||||||
toContractId("#1"),
|
|
||||||
"Hello",
|
|
||||||
ValueRecord(Some(hello), ImmArray.empty))
|
|
||||||
|
|
||||||
val res = preprocessor
|
val res = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
@ -498,10 +494,10 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
commands = r,
|
commands = r,
|
||||||
ledgerTime = let,
|
ledgerTime = let,
|
||||||
submissionTime = let,
|
submissionTime = let,
|
||||||
transactionSeed = Some(txSeed)
|
seeding = seeding,
|
||||||
)
|
)
|
||||||
.consume(lookupContract, lookupPackage, lookupKey))
|
.consume(lookupContract, lookupPackage, lookupKey))
|
||||||
val Right((tx, _)) = interpretResult
|
val Right((tx, _, nodeSeeds)) = interpretResult
|
||||||
|
|
||||||
"be translated" in {
|
"be translated" in {
|
||||||
val Right((rtx, _)) = engine
|
val Right((rtx, _)) = engine
|
||||||
@ -511,11 +507,21 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
}
|
}
|
||||||
|
|
||||||
"reinterpret to the same result" in {
|
"reinterpret to the same result" in {
|
||||||
val txRoots = tx.roots.map(id => tx.nodes(id)).toSeq
|
val nodeSeedMap = HashMap(nodeSeeds.toSeq: _*)
|
||||||
|
val roots = tx.roots.map(tx.nodes)
|
||||||
|
val rootSeeds = tx.roots.map(nodeSeedMap.get)
|
||||||
|
|
||||||
val Right((rtx, _)) = engine
|
val Right((rtx, _, _)) =
|
||||||
.reinterpret(let, Some(txSeed), Set(party), txRoots, let)
|
reinterpret(
|
||||||
.consume(lookupContract, lookupPackage, lookupKey)
|
engine,
|
||||||
|
Set(party),
|
||||||
|
roots,
|
||||||
|
rootSeeds,
|
||||||
|
let,
|
||||||
|
let,
|
||||||
|
lookupPackage,
|
||||||
|
defaultContracts
|
||||||
|
)
|
||||||
(tx isReplayedBy rtx) shouldBe true
|
(tx isReplayedBy rtx) shouldBe true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,13 +562,13 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
val res = preprocessor
|
val res = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
.consume(lookupContractWithKey, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
res shouldBe 'right
|
res shouldBe 'right
|
||||||
|
|
||||||
"fail at submission" in {
|
"fail at submission" in {
|
||||||
val submitResult = engine
|
val submitResult = engine
|
||||||
.submit(Commands(alice, ImmArray(command), let, "test"), participant, Some(submissionSeed))
|
.submit(Commands(alice, ImmArray(command), let, "test"), participant, Some(submissionSeed))
|
||||||
.consume(lookupContractWithKey, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
submitResult.left.value.msg should startWith("dependency error: couldn't find key")
|
submitResult.left.value.msg should startWith("dependency error: couldn't find key")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -571,7 +577,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
val submissionSeed = hash("exercise-by-key command with existing key")
|
val submissionSeed = hash("exercise-by-key command with existing key")
|
||||||
val templateId = Identifier(basicTestsPkgId, "BasicTests:WithKey")
|
val templateId = Identifier(basicTestsPkgId, "BasicTests:WithKey")
|
||||||
val let = Time.Timestamp.now()
|
val let = Time.Timestamp.now()
|
||||||
val txSeed = crypto.Hash.deriveTransactionSeed(submissionSeed, participant, let)
|
val seeding = Engine.initialSeeding(Some(submissionSeed), participant, let)
|
||||||
val command = ExerciseByKeyCommand(
|
val command = ExerciseByKeyCommand(
|
||||||
templateId,
|
templateId,
|
||||||
ValueRecord(None, ImmArray((None, ValueParty(alice)), (None, ValueInt64(42)))),
|
ValueRecord(None, ImmArray((None, ValueParty(alice)), (None, ValueInt64(42)))),
|
||||||
@ -581,7 +587,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
val res = preprocessor
|
val res = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
.consume(lookupContractWithKey, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
res shouldBe 'right
|
res shouldBe 'right
|
||||||
val result =
|
val result =
|
||||||
res
|
res
|
||||||
@ -595,34 +601,34 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
commands = r,
|
commands = r,
|
||||||
ledgerTime = let,
|
ledgerTime = let,
|
||||||
submissionTime = let,
|
submissionTime = let,
|
||||||
transactionSeed = Some(txSeed)
|
seeding = seeding,
|
||||||
)
|
)
|
||||||
.consume(lookupContractWithKey, lookupPackage, lookupKey))
|
.consume(lookupContract, lookupPackage, lookupKey))
|
||||||
.map(_._1)
|
val Right((tx, _, nodeSeeds)) = result
|
||||||
val tx = result.right.value
|
|
||||||
|
|
||||||
"be translated" in {
|
"be translated" in {
|
||||||
val submitResult = engine
|
val submitResult = engine
|
||||||
.submit(Commands(alice, ImmArray(command), let, "test"), participant, Some(submissionSeed))
|
.submit(Commands(alice, ImmArray(command), let, "test"), participant, Some(submissionSeed))
|
||||||
.consume(lookupContractWithKey, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
.map(_._1)
|
.map(_._1)
|
||||||
(result |@| submitResult)(_ isReplayedBy _) shouldBe Right(true)
|
(result.map(_._1) |@| submitResult)(_ isReplayedBy _) shouldBe Right(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
"reinterpret to the same result" in {
|
"reinterpret to the same result" in {
|
||||||
val txRoots = tx.roots.map(id => tx.nodes(id)).toSeq
|
val roots = tx.roots.map(id => tx.nodes(id))
|
||||||
|
val nodeSeedMap = HashMap(nodeSeeds.toSeq: _*)
|
||||||
|
val rootSeeds = tx.roots.map(nodeSeedMap.get)
|
||||||
|
|
||||||
val reinterpretResult =
|
val reinterpretResult =
|
||||||
engine
|
reinterpret(engine, Set(alice), roots, rootSeeds, let, let, lookupPackage, defaultContracts)
|
||||||
.reinterpret(let, Some(txSeed), Set(alice), txRoots, let)
|
|
||||||
.consume(lookupContractWithKey, lookupPackage, lookupKey)
|
|
||||||
.map(_._1)
|
.map(_._1)
|
||||||
(result |@| reinterpretResult)(_ isReplayedBy _) shouldBe Right(true)
|
(result.map(_._1) |@| reinterpretResult)(_ isReplayedBy _) shouldBe Right(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
"be validated" in {
|
"be validated" in {
|
||||||
val validated = engine
|
val validated = engine
|
||||||
.validate(tx, let, participant, let, Some(submissionSeed))
|
.validate(tx, let, participant, let, Some(submissionSeed))
|
||||||
.consume(lookupContractWithKey, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
validated match {
|
validated match {
|
||||||
case Left(e) =>
|
case Left(e) =>
|
||||||
fail(e.msg)
|
fail(e.msg)
|
||||||
@ -673,11 +679,11 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
commands = r,
|
commands = r,
|
||||||
ledgerTime = let,
|
ledgerTime = let,
|
||||||
submissionTime = let,
|
submissionTime = let,
|
||||||
transactionSeed = Some(txSeed),
|
seeding = InitialSeeding.TransactionSeed(txSeed),
|
||||||
)
|
)
|
||||||
.consume(lookupContract, lookupPackage, lookupKey))
|
.consume(lookupContract, lookupPackage, lookupKey))
|
||||||
.map(_._1)
|
|
||||||
val Right(tx) = interpretResult
|
val Right((tx, _, nodeSeeds)) = interpretResult
|
||||||
|
|
||||||
"be translated" in {
|
"be translated" in {
|
||||||
tx.roots should have length 2
|
tx.roots should have length 2
|
||||||
@ -688,13 +694,14 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
}
|
}
|
||||||
|
|
||||||
"reinterpret to the same result" in {
|
"reinterpret to the same result" in {
|
||||||
val txRoots = tx.roots.map(id => tx.nodes(id)).toSeq
|
val nodeSeedMap = HashMap(nodeSeeds.toSeq: _*)
|
||||||
|
val roots = tx.roots.map(tx.nodes)
|
||||||
|
val rootSeeds = tx.roots.map(nodeSeedMap.get)
|
||||||
|
|
||||||
val reinterpretResult =
|
val reinterpretResult =
|
||||||
engine
|
reinterpret(engine, Set(party), roots, rootSeeds, let, let, lookupPackage)
|
||||||
.reinterpret(let, Some(txSeed), Set(party), txRoots, let)
|
|
||||||
.consume(lookupContract, lookupPackage, lookupKey)
|
|
||||||
.map(_._1)
|
.map(_._1)
|
||||||
(interpretResult |@| reinterpretResult)(_ isReplayedBy _) shouldBe Right(true)
|
(interpretResult.map(_._1) |@| reinterpretResult)(_ isReplayedBy _) shouldBe Right(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
"be validated" in {
|
"be validated" in {
|
||||||
@ -873,7 +880,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
"exercise callable command" should {
|
"exercise callable command" should {
|
||||||
val submissionSeed = hash("exercise callable command")
|
val submissionSeed = hash("exercise callable command")
|
||||||
val originalCoid = toContractId("#1")
|
val originalCoid = toContractId("#BasicTests:CallablePayout:1")
|
||||||
val templateId = Identifier(basicTestsPkgId, "BasicTests:CallablePayout")
|
val templateId = Identifier(basicTestsPkgId, "BasicTests:CallablePayout")
|
||||||
// we need to fix time as cid are depending on it
|
// we need to fix time as cid are depending on it
|
||||||
val let = Time.Timestamp.assertFromString("1969-07-20T20:17:00Z")
|
val let = Time.Timestamp.assertFromString("1969-07-20T20:17:00Z")
|
||||||
@ -883,18 +890,18 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
"Transfer",
|
"Transfer",
|
||||||
ValueRecord(None, ImmArray((Some[Name]("newReceiver"), ValueParty(clara)))))
|
ValueRecord(None, ImmArray((Some[Name]("newReceiver"), ValueParty(clara)))))
|
||||||
|
|
||||||
val Right((tx, meta)) = engine
|
val Right((tx, txMeta)) = engine
|
||||||
.submit(Commands(bob, ImmArray(command), let, "test"), participant, Some(submissionSeed))
|
.submit(Commands(bob, ImmArray(command), let, "test"), participant, Some(submissionSeed))
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
|
|
||||||
val submissionTime = meta.submissionTime
|
val submissionTime = txMeta.submissionTime
|
||||||
|
|
||||||
val txSeed =
|
val txSeed =
|
||||||
crypto.Hash.deriveTransactionSeed(submissionSeed, participant, submissionTime)
|
crypto.Hash.deriveTransactionSeed(submissionSeed, participant, submissionTime)
|
||||||
val Right(cmds) = preprocessor
|
val Right(cmds) = preprocessor
|
||||||
.preprocessCommands(ImmArray(command))
|
.preprocessCommands(ImmArray(command))
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
val Right((rtx, _)) = engine
|
val Right((rtx, _, _)) = engine
|
||||||
.interpretCommands(
|
.interpretCommands(
|
||||||
validating = false,
|
validating = false,
|
||||||
checkSubmitterInMaintainers = true,
|
checkSubmitterInMaintainers = true,
|
||||||
@ -902,9 +909,9 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
commands = cmds,
|
commands = cmds,
|
||||||
ledgerTime = let,
|
ledgerTime = let,
|
||||||
submissionTime = submissionTime,
|
submissionTime = submissionTime,
|
||||||
transactionSeed = Some(txSeed),
|
seeding = InitialSeeding.TransactionSeed(txSeed)
|
||||||
)
|
)
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
|
|
||||||
"be translated" in {
|
"be translated" in {
|
||||||
(rtx isReplayedBy tx) shouldBe true
|
(rtx isReplayedBy tx) shouldBe true
|
||||||
@ -914,11 +921,20 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
Blinding.checkAuthorizationAndBlind(tx, Set(bob))
|
Blinding.checkAuthorizationAndBlind(tx, Set(bob))
|
||||||
|
|
||||||
"reinterpret to the same result" in {
|
"reinterpret to the same result" in {
|
||||||
val txRoots = tx.roots.map(id => tx.nodes(id)).toSeq
|
val roots = tx.roots.map(id => tx.nodes(id))
|
||||||
val Right((rtx, _)) =
|
val nodeSeedMap = HashMap(txMeta.nodeSeeds.toSeq: _*)
|
||||||
engine
|
val rootSeeds = tx.roots.map(nodeSeedMap.get)
|
||||||
.reinterpret(submissionTime, Some(txSeed), Set(bob), txRoots, let)
|
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
val Right((rtx, _, _)) =
|
||||||
|
reinterpret(
|
||||||
|
engine,
|
||||||
|
Set(bob),
|
||||||
|
roots,
|
||||||
|
rootSeeds,
|
||||||
|
submissionTime,
|
||||||
|
let,
|
||||||
|
lookupPackage,
|
||||||
|
defaultContracts)
|
||||||
(rtx isReplayedBy tx) shouldBe true
|
(rtx isReplayedBy tx) shouldBe true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -929,7 +945,6 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
bobView.nodes.size shouldBe 2
|
bobView.nodes.size shouldBe 2
|
||||||
findNodeByIdx(bobView.nodes, 0).getOrElse(fail("node not found")) match {
|
findNodeByIdx(bobView.nodes, 0).getOrElse(fail("node not found")) match {
|
||||||
case NodeExercises(
|
case NodeExercises(
|
||||||
nodeSeed @ _,
|
|
||||||
coid,
|
coid,
|
||||||
_,
|
_,
|
||||||
choice,
|
choice,
|
||||||
@ -952,7 +967,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
}
|
}
|
||||||
|
|
||||||
findNodeByIdx(bobView.nodes, 1).getOrElse(fail("node not found")) match {
|
findNodeByIdx(bobView.nodes, 1).getOrElse(fail("node not found")) match {
|
||||||
case NodeCreate(nodeSeed @ _, _, coins, _, _, stakeholders, _) =>
|
case NodeCreate(_, coins, _, _, stakeholders, _) =>
|
||||||
coins.template shouldBe templateId
|
coins.template shouldBe templateId
|
||||||
stakeholders shouldBe Set(alice, clara)
|
stakeholders shouldBe Set(alice, clara)
|
||||||
case _ => fail("create event is expected")
|
case _ => fail("create event is expected")
|
||||||
@ -963,7 +978,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
claraView.nodes.size shouldBe 1
|
claraView.nodes.size shouldBe 1
|
||||||
findNodeByIdx(claraView.nodes, 1).getOrElse(fail("node not found")) match {
|
findNodeByIdx(claraView.nodes, 1).getOrElse(fail("node not found")) match {
|
||||||
case NodeCreate(nodeSeed @ _, _, coins, _, _, stakeholders, _) =>
|
case NodeCreate(_, coins, _, _, stakeholders, _) =>
|
||||||
coins.template shouldBe templateId
|
coins.template shouldBe templateId
|
||||||
stakeholders shouldBe Set(alice, clara)
|
stakeholders shouldBe Set(alice, clara)
|
||||||
case _ => fail("create event is expected")
|
case _ => fail("create event is expected")
|
||||||
@ -976,7 +991,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
val transactionSeed =
|
val transactionSeed =
|
||||||
crypto.Hash.deriveTransactionSeed(submissionSeed, participant, submissionTime)
|
crypto.Hash.deriveTransactionSeed(submissionSeed, participant, submissionTime)
|
||||||
|
|
||||||
val Right((tx, _)) =
|
val Right((tx, _, _)) =
|
||||||
engine
|
engine
|
||||||
.interpretCommands(
|
.interpretCommands(
|
||||||
validating = false,
|
validating = false,
|
||||||
@ -985,9 +1000,9 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
commands = cmds,
|
commands = cmds,
|
||||||
ledgerTime = let,
|
ledgerTime = let,
|
||||||
submissionTime = submissionTime,
|
submissionTime = submissionTime,
|
||||||
transactionSeed = Some(transactionSeed)
|
seeding = InitialSeeding.TransactionSeed(transactionSeed),
|
||||||
)
|
)
|
||||||
.consume(lookupContractForPayout, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
val Seq(_, noid1) = tx.nodes.keys.toSeq.sortBy(_.index)
|
val Seq(_, noid1) = tx.nodes.keys.toSeq.sortBy(_.index)
|
||||||
val Right(blindingInfo) =
|
val Right(blindingInfo) =
|
||||||
Blinding.checkAuthorizationAndBlind(tx, Set(bob))
|
Blinding.checkAuthorizationAndBlind(tx, Set(bob))
|
||||||
@ -1086,7 +1101,7 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
}
|
}
|
||||||
|
|
||||||
val let = Time.Timestamp.now()
|
val let = Time.Timestamp.now()
|
||||||
val transactionSeed = crypto.Hash.deriveTransactionSeed(submissionSeed, participant, let)
|
val seeding = Engine.initialSeeding(Some(submissionSeed), participant, let)
|
||||||
|
|
||||||
def actFetchActors[Nid, Cid, Val](n: GenNode[Nid, Cid, Val]): Set[Party] = {
|
def actFetchActors[Nid, Cid, Val](n: GenNode[Nid, Cid, Val]): Set[Party] = {
|
||||||
n match {
|
n match {
|
||||||
@ -1122,38 +1137,40 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
commands = r,
|
commands = r,
|
||||||
ledgerTime = let,
|
ledgerTime = let,
|
||||||
submissionTime = let,
|
submissionTime = let,
|
||||||
transactionSeed = Some(transactionSeed),
|
seeding = seeding,
|
||||||
)
|
)
|
||||||
.consume(lookupContract, lookupPackage, lookupKey))
|
.consume(lookupContract, lookupPackage, lookupKey))
|
||||||
.map(_._1)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"propagate the parent's signatories and actors (but not observers) when stakeholders" in {
|
"propagate the parent's signatories and actors (but not observers) when stakeholders" in {
|
||||||
|
|
||||||
val Right(tx) = runExample(fetcher1Cid, clara)
|
val Right((tx, _, _)) = runExample(fetcher1Cid, clara)
|
||||||
txFetchActors(tx) shouldBe Set(alice, clara)
|
txFetchActors(tx) shouldBe Set(alice, clara)
|
||||||
}
|
}
|
||||||
|
|
||||||
"not propagate the parent's signatories nor actors when not stakeholders" in {
|
"not propagate the parent's signatories nor actors when not stakeholders" in {
|
||||||
|
|
||||||
val Right(tx) = runExample(fetcher2Cid, party)
|
val Right((tx, _, _)) = runExample(fetcher2Cid, party)
|
||||||
txFetchActors(tx) shouldBe Set()
|
txFetchActors(tx) shouldBe Set()
|
||||||
}
|
}
|
||||||
|
|
||||||
"be retained when reinterpreting single fetch nodes" in {
|
"be retained when reinterpreting single fetch nodes" in {
|
||||||
val Right(tx) = runExample(fetcher1Cid, clara)
|
val Right((tx, _, nodeSeeds)) = runExample(fetcher1Cid, clara)
|
||||||
|
val nodeSeedMap = HashMap(nodeSeeds.toSeq: _*)
|
||||||
val fetchNodes =
|
val fetchNodes =
|
||||||
tx.fold(Seq[(NodeId, GenNode.WithTxValue[NodeId, ContractId])]()) {
|
tx.fold(Seq[(NodeId, GenNode.WithTxValue[NodeId, ContractId])]()) {
|
||||||
case (ns, (nid, n @ NodeFetch(_, _, _, _, _, _, _))) => ns :+ ((nid, n))
|
case (ns, (nid, n @ NodeFetch(_, _, _, _, _, _, _))) => ns :+ ((nid, n))
|
||||||
case (ns, _) => ns
|
case (ns, _) => ns
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchNodes.foreach {
|
fetchNodes.foreach {
|
||||||
case (nid, n) =>
|
case (nid, n) =>
|
||||||
val fetchTx = GenTx(HashMap(nid -> n), ImmArray(nid))
|
val fetchTx = GenTx(HashMap(nid -> n), ImmArray(nid))
|
||||||
val Right((reinterpreted, _)) = engine
|
val Right((reinterpreted, _, _)) =
|
||||||
.reinterpret(let, None, n.requiredAuthorizers, Seq(n), let)
|
engine
|
||||||
.consume(lookupContract, lookupPackage, lookupKey)
|
.reinterpret(n.requiredAuthorizers, n, nodeSeedMap.get(nid), let, let)
|
||||||
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
(fetchTx isReplayedBy reinterpreted) shouldBe true
|
(fetchTx isReplayedBy reinterpreted) shouldBe true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1161,8 +1178,6 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
"reinterpreting fetch nodes" should {
|
"reinterpreting fetch nodes" should {
|
||||||
|
|
||||||
val submissionSeed = hash("reinterpreting fetch nodes")
|
|
||||||
|
|
||||||
val fetchedCid = toContractId("#1")
|
val fetchedCid = toContractId("#1")
|
||||||
val fetchedStrTid = "BasicTests:Fetched"
|
val fetchedStrTid = "BasicTests:Fetched"
|
||||||
val fetchedTid = Identifier(basicTestsPkgId, fetchedStrTid)
|
val fetchedTid = Identifier(basicTestsPkgId, fetchedStrTid)
|
||||||
@ -1203,11 +1218,11 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
)
|
)
|
||||||
|
|
||||||
val let = Time.Timestamp.now()
|
val let = Time.Timestamp.now()
|
||||||
val txSeed = crypto.Hash.deriveTransactionSeed(submissionSeed, participant, let)
|
|
||||||
|
|
||||||
val reinterpreted = engine
|
val reinterpreted =
|
||||||
.reinterpret(let, Some(txSeed), Set.empty, Seq(fetchNode), let)
|
engine
|
||||||
.consume(lookupContract, lookupPackage, lookupKey)
|
.reinterpret(Set.empty, fetchNode, None, let, let)
|
||||||
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
|
|
||||||
reinterpreted shouldBe 'right
|
reinterpreted shouldBe 'right
|
||||||
}
|
}
|
||||||
@ -1247,9 +1262,10 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
)
|
)
|
||||||
|
|
||||||
def firstLookupNode[Nid, Cid, Val](
|
def firstLookupNode[Nid, Cid, Val](
|
||||||
tx: GenTx[Nid, Cid, Val]): Option[NodeLookupByKey[Cid, Val]] =
|
tx: GenTx[Nid, Cid, Val],
|
||||||
tx.nodes.values.collectFirst {
|
): Option[(Nid, NodeLookupByKey[Cid, Val])] =
|
||||||
case nl @ NodeLookupByKey(_, _, _, _) => nl
|
tx.nodes.collectFirst {
|
||||||
|
case (nid, nl @ NodeLookupByKey(_, _, _, _)) => nid -> nl
|
||||||
}
|
}
|
||||||
|
|
||||||
val now = Time.Timestamp.now()
|
val now = Time.Timestamp.now()
|
||||||
@ -1266,25 +1282,23 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
participant,
|
participant,
|
||||||
Some(submissionSeed))
|
Some(submissionSeed))
|
||||||
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
||||||
|
val nodeSeedMap = HashMap(txMeta.nodeSeeds.toSeq: _*)
|
||||||
|
|
||||||
val txSeed =
|
val Some((nid, lookupNode)) = firstLookupNode(tx)
|
||||||
crypto.Hash.deriveTransactionSeed(submissionSeed, participant, txMeta.submissionTime)
|
|
||||||
|
|
||||||
val Some(lookupNode) = firstLookupNode(tx)
|
|
||||||
lookupNode.result shouldBe Some(lookedUpCid)
|
lookupNode.result shouldBe Some(lookedUpCid)
|
||||||
|
|
||||||
val freshEngine = Engine()
|
val Right((reinterpreted, _, _)) =
|
||||||
val Right((reinterpreted, dependsOnTime @ _)) = freshEngine
|
Engine()
|
||||||
.reinterpret(
|
.reinterpret(
|
||||||
txMeta.submissionTime,
|
Set.empty,
|
||||||
Some(txSeed),
|
lookupNode,
|
||||||
Set.empty,
|
nodeSeedMap.get(nid),
|
||||||
Seq(lookupNode),
|
txMeta.submissionTime,
|
||||||
now,
|
now,
|
||||||
)
|
)
|
||||||
.consume(lookupContract, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
|
|
||||||
firstLookupNode(reinterpreted) shouldEqual Some(lookupNode)
|
firstLookupNode(reinterpreted).map(_._2) shouldEqual Some(lookupNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
"reinterpret to the same node when lookup doesn't find a contract" in {
|
"reinterpret to the same node when lookup doesn't find a contract" in {
|
||||||
@ -1299,18 +1313,18 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
participant,
|
participant,
|
||||||
Some(submissionSeed))
|
Some(submissionSeed))
|
||||||
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
||||||
val txSeed =
|
|
||||||
crypto.Hash.deriveTransactionSeed(submissionSeed, participant, txMeta.submissionTime)
|
|
||||||
|
|
||||||
val Some(lookupNode) = firstLookupNode(tx)
|
val nodeSeedMap = HashMap(txMeta.nodeSeeds.toSeq: _*)
|
||||||
|
|
||||||
|
val Some((nid, lookupNode)) = firstLookupNode(tx)
|
||||||
lookupNode.result shouldBe None
|
lookupNode.result shouldBe None
|
||||||
|
|
||||||
val freshEngine = Engine()
|
val Right((reinterpreted, _, _)) =
|
||||||
val Right((reinterpreted, dependsOnTime @ _)) = freshEngine
|
Engine()
|
||||||
.reinterpret(now, Some(txSeed), Set.empty, Seq(lookupNode), now)
|
.reinterpret(Set.empty, lookupNode, nodeSeedMap.get(nid), txMeta.submissionTime, now)
|
||||||
.consume(lookupContract, lookupPackage, lookupKey)
|
.consume(lookupContract, lookupPackage, lookupKey)
|
||||||
|
|
||||||
firstLookupNode(reinterpreted) shouldEqual Some(lookupNode)
|
firstLookupNode(reinterpreted).map(_._2) shouldEqual Some(lookupNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1349,8 +1363,8 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
|
|
||||||
val cmd = speedy.Command.Fetch(BasicTests_WithKey, SValue.SContractId(fetchedCid))
|
val cmd = speedy.Command.Fetch(BasicTests_WithKey, SValue.SContractId(fetchedCid))
|
||||||
|
|
||||||
val Right((tx, dependsOnTime @ _)) = engine
|
val Right((tx, _, _)) = engine
|
||||||
.interpretCommands(false, false, Set(alice), ImmArray(cmd), now, now, None)
|
.interpretCommands(false, false, Set(alice), ImmArray(cmd), now, now, InitialSeeding.NoSeed)
|
||||||
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
||||||
|
|
||||||
tx.nodes.values.headOption match {
|
tx.nodes.values.headOption match {
|
||||||
@ -1403,8 +1417,8 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
))
|
))
|
||||||
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
||||||
|
|
||||||
val Right((tx, dependsOnTime @ _)) = engine
|
val Right((tx, _, _)) = engine
|
||||||
.interpretCommands(false, false, Set(alice), cmds, now, now, None)
|
.interpretCommands(false, false, Set(alice), cmds, now, now, InitialSeeding.NoSeed)
|
||||||
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
.consume(lookupContractMap.get, lookupPackage, lookupKey)
|
||||||
|
|
||||||
tx.nodes.values.collectFirst {
|
tx.nodes.values.collectFirst {
|
||||||
@ -1467,21 +1481,22 @@ class EngineTest extends WordSpec with Matchers with EitherValues with BazelRunf
|
|||||||
}
|
}
|
||||||
|
|
||||||
"be partially reinterpretable" in {
|
"be partially reinterpretable" in {
|
||||||
val Right((tx, metaData)) = run(3)
|
val Right((tx, txMeta)) = run(3)
|
||||||
val ImmArray(_, exeNode1) = tx.roots
|
val ImmArray(_, exeNode1) = tx.roots
|
||||||
val NodeExercises(Some(exeNode1Seed), _, _, _, _, _, _, _, _, _, _, children, _, _) =
|
val NodeExercises(_, _, _, _, _, _, _, _, _, _, children, _, _) =
|
||||||
tx.nodes(exeNode1)
|
tx.nodes(exeNode1)
|
||||||
val ImmArray(createNode2, exeNode2, _, _) = children
|
val nids = children.toSeq.take(2).toImmArray
|
||||||
|
val nodeSeedMap = HashMap(txMeta.nodeSeeds.toSeq: _*)
|
||||||
|
|
||||||
engine
|
reinterpret(
|
||||||
.reinterpret(
|
engine,
|
||||||
metaData.submissionTime,
|
Set(party),
|
||||||
Some(exeNode1Seed),
|
nids.map(tx.nodes),
|
||||||
Set(party),
|
nids.map(nodeSeedMap.get),
|
||||||
List(createNode2, exeNode2).map(tx.nodes),
|
txMeta.submissionTime,
|
||||||
let,
|
let,
|
||||||
)
|
lookupPackage,
|
||||||
.consume(_ => None, lookupPackage, _ => None) shouldBe 'right
|
) shouldBe 'right
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1515,4 +1530,92 @@ object EngineTest {
|
|||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def reinterpret(
|
||||||
|
engine: Engine,
|
||||||
|
submitters: Set[Party],
|
||||||
|
nodes: ImmArray[GenNode.WithTxValue[Value.NodeId, Value.ContractId]],
|
||||||
|
nodeSeeds: ImmArray[Option[crypto.Hash]],
|
||||||
|
submissionTime: Time.Timestamp,
|
||||||
|
ledgerEffectiveTime: Time.Timestamp,
|
||||||
|
lookupPackages: PackageId => Option[Package],
|
||||||
|
contracts: Map[AbsoluteContractId, Tx.ContractInst[AbsoluteContractId]] = Map.empty,
|
||||||
|
): Either[Error, (Tx.Transaction, Boolean, ImmArray[(NodeId, crypto.Hash)])] = {
|
||||||
|
type Acc =
|
||||||
|
(
|
||||||
|
HashMap[NodeId, Tx.Node],
|
||||||
|
BackStack[NodeId],
|
||||||
|
Boolean,
|
||||||
|
BackStack[(NodeId, crypto.Hash)],
|
||||||
|
Map[AbsoluteContractId, Tx.ContractInst[AbsoluteContractId]],
|
||||||
|
Map[GlobalKey, AbsoluteContractId],
|
||||||
|
)
|
||||||
|
|
||||||
|
val iterate =
|
||||||
|
(nodes zip nodeSeeds).foldLeft[Either[Error, Acc]](
|
||||||
|
Right((HashMap.empty, BackStack.empty, false, BackStack.empty, contracts, Map.empty))) {
|
||||||
|
case (acc, (node, nodeSeed)) =>
|
||||||
|
for {
|
||||||
|
previousStep <- acc
|
||||||
|
(nodes, roots, dependOnTime, nodeSeeds, contracts0, keys0) = previousStep
|
||||||
|
currentStep <- engine
|
||||||
|
.reinterpret(submitters, node, nodeSeed, submissionTime, ledgerEffectiveTime)
|
||||||
|
.consume(contracts0.get, lookupPackages, keys0.get)
|
||||||
|
(tr1, dependOnTime1, nodeSeeds1) = currentStep
|
||||||
|
(contracts1, keys1) = tr1.fold((contracts0, keys0)) {
|
||||||
|
case (
|
||||||
|
(contracts, keys),
|
||||||
|
(
|
||||||
|
_,
|
||||||
|
NodeExercises(
|
||||||
|
targetCoid: AbsoluteContractId,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
true,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_))) =>
|
||||||
|
(contracts - targetCoid, keys)
|
||||||
|
case (
|
||||||
|
(contracts, keys),
|
||||||
|
(_, NodeCreate(cid: AbsoluteContractId, coinst, _, _, _, key))) =>
|
||||||
|
(
|
||||||
|
contracts.updated(
|
||||||
|
cid,
|
||||||
|
coinst.assertNoRelCid(cid => s"unexpected relative contract ID $cid")),
|
||||||
|
key.fold(keys)(
|
||||||
|
k =>
|
||||||
|
keys.updated(
|
||||||
|
GlobalKey(
|
||||||
|
coinst.template,
|
||||||
|
k.key.value.assertNoCid(cid => s"unexpected relative contract ID $cid")),
|
||||||
|
cid))
|
||||||
|
)
|
||||||
|
case (acc, _) => acc
|
||||||
|
}
|
||||||
|
n = nodes.size
|
||||||
|
nodeRenaming = (nid: NodeId) => NodeId(nid.index + n)
|
||||||
|
tr = tr1.mapNodeId(nodeRenaming)
|
||||||
|
} yield
|
||||||
|
(
|
||||||
|
nodes ++ tr.nodes,
|
||||||
|
roots :++ tr.roots,
|
||||||
|
dependOnTime || dependOnTime1,
|
||||||
|
nodeSeeds :++ nodeSeeds1.map { case (nid, seed) => nodeRenaming(nid) -> seed },
|
||||||
|
contracts1,
|
||||||
|
keys1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
iterate.map {
|
||||||
|
case (nodes, roots, dependOnTime, nodeSeeds, _, _) =>
|
||||||
|
(GenTx(nodes, roots.toImmArray), dependOnTime, nodeSeeds.toImmArray)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -92,9 +92,9 @@ class LargeTransactionTest extends WordSpec with Matchers with BazelRunfiles {
|
|||||||
cmdReference = "create RangeOfInts",
|
cmdReference = "create RangeOfInts",
|
||||||
seed = hash("testLargeTransactionOneContract:create", txSize))
|
seed = hash("testLargeTransactionOneContract:create", txSize))
|
||||||
val contractId: AbsoluteContractId = firstRootNode(createCmdTx) match {
|
val contractId: AbsoluteContractId = firstRootNode(createCmdTx) match {
|
||||||
case N.NodeCreate(_, x: RelativeContractId, _, _, _, _, _) =>
|
case N.NodeCreate(x: RelativeContractId, _, _, _, _, _) =>
|
||||||
AbsoluteContractId.V0(pcs.toContractIdString(pcs.transactionCounter - 1)(x))
|
AbsoluteContractId.V0(pcs.toContractIdString(pcs.transactionCounter - 1)(x))
|
||||||
case N.NodeCreate(_, x: AbsoluteContractId, _, _, _, _, _) => x
|
case N.NodeCreate(x: AbsoluteContractId, _, _, _, _, _) => x
|
||||||
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
||||||
}
|
}
|
||||||
val exerciseCmd = toListContainerExerciseCmd(rangeOfIntsTemplateId, contractId)
|
val exerciseCmd = toListContainerExerciseCmd(rangeOfIntsTemplateId, contractId)
|
||||||
@ -121,9 +121,9 @@ class LargeTransactionTest extends WordSpec with Matchers with BazelRunfiles {
|
|||||||
cmdReference = "create RangeOfInts",
|
cmdReference = "create RangeOfInts",
|
||||||
seed = hash("testLargeTransactionManySmallContracts:create", num))
|
seed = hash("testLargeTransactionManySmallContracts:create", num))
|
||||||
val contractId: AbsoluteContractId = firstRootNode(createCmdTx) match {
|
val contractId: AbsoluteContractId = firstRootNode(createCmdTx) match {
|
||||||
case N.NodeCreate(_, x: RelativeContractId, _, _, _, _, _) =>
|
case N.NodeCreate(x: RelativeContractId, _, _, _, _, _) =>
|
||||||
AbsoluteContractId.V0(pcs.toContractIdString(pcs.transactionCounter - 1)(x))
|
AbsoluteContractId.V0(pcs.toContractIdString(pcs.transactionCounter - 1)(x))
|
||||||
case N.NodeCreate(_, x: AbsoluteContractId, _, _, _, _, _) => x
|
case N.NodeCreate(x: AbsoluteContractId, _, _, _, _, _) => x
|
||||||
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
||||||
}
|
}
|
||||||
val exerciseCmd = toListOfIntContainers(rangeOfIntsTemplateId, contractId)
|
val exerciseCmd = toListOfIntContainers(rangeOfIntsTemplateId, contractId)
|
||||||
@ -150,9 +150,9 @@ class LargeTransactionTest extends WordSpec with Matchers with BazelRunfiles {
|
|||||||
cmdReference = "create ListUtil",
|
cmdReference = "create ListUtil",
|
||||||
seed = hash("testLargeChoiceArgument:create", size))
|
seed = hash("testLargeChoiceArgument:create", size))
|
||||||
val contractId: AbsoluteContractId = firstRootNode(createCmdTx) match {
|
val contractId: AbsoluteContractId = firstRootNode(createCmdTx) match {
|
||||||
case N.NodeCreate(_, x: RelativeContractId, _, _, _, _, _) =>
|
case N.NodeCreate(x: RelativeContractId, _, _, _, _, _) =>
|
||||||
AbsoluteContractId.V0(pcs.toContractIdString(pcs.transactionCounter - 1)(x))
|
AbsoluteContractId.V0(pcs.toContractIdString(pcs.transactionCounter - 1)(x))
|
||||||
case N.NodeCreate(_, x: AbsoluteContractId, _, _, _, _, _) => x
|
case N.NodeCreate(x: AbsoluteContractId, _, _, _, _, _) => x
|
||||||
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
case n @ _ => fail(s"Expected NodeCreate, but got: $n")
|
||||||
}
|
}
|
||||||
val exerciseCmd = sizeExerciseCmd(listUtilTemplateId, contractId)(size)
|
val exerciseCmd = sizeExerciseCmd(listUtilTemplateId, contractId)(size)
|
||||||
@ -195,7 +195,7 @@ class LargeTransactionTest extends WordSpec with Matchers with BazelRunfiles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
newContracts.count {
|
newContracts.count {
|
||||||
case N.NodeCreate(_, _, _, _, _, _, _) => true
|
case N.NodeCreate(_, _, _, _, _, _) => true
|
||||||
case n @ _ => fail(s"Unexpected match: $n")
|
case n @ _ => fail(s"Unexpected match: $n")
|
||||||
} shouldBe expectedNumberOfContracts
|
} shouldBe expectedNumberOfContracts
|
||||||
}
|
}
|
||||||
@ -320,7 +320,7 @@ class LargeTransactionTest extends WordSpec with Matchers with BazelRunfiles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createNode match {
|
createNode match {
|
||||||
case N.NodeCreate(_, _, x: ContractInst[_], _, _, _, _) => x
|
case N.NodeCreate(_, x: ContractInst[_], _, _, _, _) => x
|
||||||
case n @ _ => fail(s"Unexpected match: $n")
|
case n @ _ => fail(s"Unexpected match: $n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -631,4 +631,12 @@ object Speedy {
|
|||||||
/** Internal exception thrown when a continuation result needs to be returned. */
|
/** Internal exception thrown when a continuation result needs to be returned. */
|
||||||
final case class SpeedyHungry(result: SResult) extends RuntimeException with NoStackTrace
|
final case class SpeedyHungry(result: SResult) extends RuntimeException with NoStackTrace
|
||||||
|
|
||||||
|
def deriveTransactionSeed(
|
||||||
|
submissionSeed: Option[crypto.Hash],
|
||||||
|
participant: Ref.ParticipantId,
|
||||||
|
submissionTime: Time.Timestamp,
|
||||||
|
): InitialSeeding =
|
||||||
|
InitialSeeding(
|
||||||
|
submissionSeed.map(crypto.Hash.deriveTransactionSeed(_, participant, submissionTime)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,7 @@ object PartialTransaction {
|
|||||||
submissionTime = submissionTime,
|
submissionTime = submissionTime,
|
||||||
nextNodeIdx = 0,
|
nextNodeIdx = 0,
|
||||||
nodes = HashMap.empty,
|
nodes = HashMap.empty,
|
||||||
|
nodeSeeds = BackStack.empty,
|
||||||
consumedBy = Map.empty,
|
consumedBy = Map.empty,
|
||||||
context = Context(initialSeeds),
|
context = Context(initialSeeds),
|
||||||
aborted = None,
|
aborted = None,
|
||||||
@ -146,6 +147,7 @@ case class PartialTransaction(
|
|||||||
submissionTime: Time.Timestamp,
|
submissionTime: Time.Timestamp,
|
||||||
nextNodeIdx: Int,
|
nextNodeIdx: Int,
|
||||||
nodes: HashMap[Value.NodeId, Tx.Node],
|
nodes: HashMap[Value.NodeId, Tx.Node],
|
||||||
|
nodeSeeds: BackStack[(Value.NodeId, crypto.Hash)],
|
||||||
consumedBy: Map[Value.ContractId, Value.NodeId],
|
consumedBy: Map[Value.ContractId, Value.NodeId],
|
||||||
context: PartialTransaction.Context,
|
context: PartialTransaction.Context,
|
||||||
aborted: Option[Tx.TransactionError],
|
aborted: Option[Tx.TransactionError],
|
||||||
@ -285,7 +287,6 @@ case class PartialTransaction(
|
|||||||
Value.RelativeContractId(Value.NodeId(nextNodeIdx))
|
Value.RelativeContractId(Value.NodeId(nextNodeIdx))
|
||||||
)(Value.AbsoluteContractId.V1(_))
|
)(Value.AbsoluteContractId.V1(_))
|
||||||
val createNode = Node.NodeCreate(
|
val createNode = Node.NodeCreate(
|
||||||
nodeSeed,
|
|
||||||
cid,
|
cid,
|
||||||
coinst,
|
coinst,
|
||||||
optLocation,
|
optLocation,
|
||||||
@ -298,6 +299,7 @@ case class PartialTransaction(
|
|||||||
nextNodeIdx = nextNodeIdx + 1,
|
nextNodeIdx = nextNodeIdx + 1,
|
||||||
context = context.addChild(nid),
|
context = context.addChild(nid),
|
||||||
nodes = nodes.updated(nid, createNode),
|
nodes = nodes.updated(nid, createNode),
|
||||||
|
nodeSeeds = nodeSeed.fold(nodeSeeds)(s => nodeSeeds :+ (nid -> s)),
|
||||||
localContracts = localContracts.updated(cid, nid)
|
localContracts = localContracts.updated(cid, nid)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -409,7 +411,6 @@ case class PartialTransaction(
|
|||||||
context.exeContext match {
|
context.exeContext match {
|
||||||
case Some(ec) =>
|
case Some(ec) =>
|
||||||
val exerciseNode = Node.NodeExercises(
|
val exerciseNode = Node.NodeExercises(
|
||||||
nodeSeed = ec.parent.nextChildrenSeed,
|
|
||||||
targetCoid = ec.targetId,
|
targetCoid = ec.targetId,
|
||||||
templateId = ec.templateId,
|
templateId = ec.templateId,
|
||||||
choiceId = ec.choiceId,
|
choiceId = ec.choiceId,
|
||||||
@ -425,7 +426,12 @@ case class PartialTransaction(
|
|||||||
key = ec.contractKey,
|
key = ec.contractKey,
|
||||||
)
|
)
|
||||||
val nodeId = ec.nodeId
|
val nodeId = ec.nodeId
|
||||||
copy(context = ec.parent.addChild(nodeId), nodes = nodes.updated(nodeId, exerciseNode))
|
val nodeSeed = ec.parent.nextChildrenSeed
|
||||||
|
copy(
|
||||||
|
context = ec.parent.addChild(nodeId),
|
||||||
|
nodes = nodes.updated(nodeId, exerciseNode),
|
||||||
|
nodeSeeds = nodeSeed.fold(nodeSeeds)(s => nodeSeeds :+ (nodeId -> s)),
|
||||||
|
)
|
||||||
case None =>
|
case None =>
|
||||||
noteAbort(Tx.EndExerciseInRootContext)
|
noteAbort(Tx.EndExerciseInRootContext)
|
||||||
}
|
}
|
||||||
@ -461,7 +467,7 @@ case class PartialTransaction(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed abstract class InitialSeeding
|
sealed abstract class InitialSeeding extends Product with Serializable
|
||||||
|
|
||||||
object InitialSeeding {
|
object InitialSeeding {
|
||||||
def apply(transactionSeed: Option[crypto.Hash]): InitialSeeding =
|
def apply(transactionSeed: Option[crypto.Hash]): InitialSeeding =
|
||||||
|
@ -243,7 +243,7 @@ object ValueGenerators {
|
|||||||
signatories <- genNonEmptyParties
|
signatories <- genNonEmptyParties
|
||||||
stakeholders <- genNonEmptyParties
|
stakeholders <- genNonEmptyParties
|
||||||
key <- Gen.option(keyWithMaintainersGen)
|
key <- Gen.option(keyWithMaintainersGen)
|
||||||
} yield NodeCreate(None, coid, coinst, None, signatories, stakeholders, key)
|
} yield NodeCreate(coid, coinst, None, signatories, stakeholders, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
val fetchNodeGen: Gen[NodeFetch.WithTxValue[ContractId]] = {
|
val fetchNodeGen: Gen[NodeFetch.WithTxValue[ContractId]] = {
|
||||||
@ -278,7 +278,6 @@ object ValueGenerators {
|
|||||||
maintainers <- genNonEmptyParties
|
maintainers <- genNonEmptyParties
|
||||||
} yield
|
} yield
|
||||||
NodeExercises(
|
NodeExercises(
|
||||||
None,
|
|
||||||
targetCoid,
|
targetCoid,
|
||||||
templateId,
|
templateId,
|
||||||
choiceId,
|
choiceId,
|
||||||
|
@ -60,7 +60,6 @@ object Node {
|
|||||||
f3: A3 => B3,
|
f3: A3 => B3,
|
||||||
): GenNode[A1, A2, A3] => GenNode[B1, B2, B3] = {
|
): GenNode[A1, A2, A3] => GenNode[B1, B2, B3] = {
|
||||||
case NodeCreate(
|
case NodeCreate(
|
||||||
nodeSeed,
|
|
||||||
coid,
|
coid,
|
||||||
coinst,
|
coinst,
|
||||||
optLocation,
|
optLocation,
|
||||||
@ -69,7 +68,6 @@ object Node {
|
|||||||
key,
|
key,
|
||||||
) =>
|
) =>
|
||||||
NodeCreate(
|
NodeCreate(
|
||||||
nodeSeed = nodeSeed,
|
|
||||||
coid = f2(coid),
|
coid = f2(coid),
|
||||||
coinst = value.Value.ContractInst.map1(f3)(coinst),
|
coinst = value.Value.ContractInst.map1(f3)(coinst),
|
||||||
optLocation = optLocation,
|
optLocation = optLocation,
|
||||||
@ -96,7 +94,6 @@ object Node {
|
|||||||
key = key.map(KeyWithMaintainers.map1(f3)),
|
key = key.map(KeyWithMaintainers.map1(f3)),
|
||||||
)
|
)
|
||||||
case NodeExercises(
|
case NodeExercises(
|
||||||
nodeSeed,
|
|
||||||
targetCoid,
|
targetCoid,
|
||||||
templateId,
|
templateId,
|
||||||
choiceId,
|
choiceId,
|
||||||
@ -112,7 +109,6 @@ object Node {
|
|||||||
key,
|
key,
|
||||||
) =>
|
) =>
|
||||||
NodeExercises(
|
NodeExercises(
|
||||||
nodeSeed = nodeSeed,
|
|
||||||
targetCoid = f2(targetCoid),
|
targetCoid = f2(targetCoid),
|
||||||
templateId = templateId,
|
templateId = templateId,
|
||||||
choiceId = choiceId,
|
choiceId = choiceId,
|
||||||
@ -149,7 +145,6 @@ object Node {
|
|||||||
|
|
||||||
/** Denotes the creation of a contract instance. */
|
/** Denotes the creation of a contract instance. */
|
||||||
final case class NodeCreate[+Cid, +Val](
|
final case class NodeCreate[+Cid, +Val](
|
||||||
nodeSeed: Option[crypto.Hash],
|
|
||||||
coid: Cid,
|
coid: Cid,
|
||||||
coinst: ContractInst[Val],
|
coinst: ContractInst[Val],
|
||||||
optLocation: Option[Location], // Optional location of the create expression
|
optLocation: Option[Location], // Optional location of the create expression
|
||||||
@ -181,7 +176,6 @@ object Node {
|
|||||||
* ledgers.
|
* ledgers.
|
||||||
*/
|
*/
|
||||||
final case class NodeExercises[+Nid, +Cid, +Val](
|
final case class NodeExercises[+Nid, +Cid, +Val](
|
||||||
nodeSeed: Option[crypto.Hash],
|
|
||||||
targetCoid: Cid,
|
targetCoid: Cid,
|
||||||
templateId: Identifier,
|
templateId: Identifier,
|
||||||
choiceId: ChoiceName,
|
choiceId: ChoiceName,
|
||||||
@ -210,7 +204,6 @@ object Node {
|
|||||||
* apply method enforces it.
|
* apply method enforces it.
|
||||||
*/
|
*/
|
||||||
def apply[Nid, Cid, Val](
|
def apply[Nid, Cid, Val](
|
||||||
nodeSeed: Option[crypto.Hash] = None,
|
|
||||||
targetCoid: Cid,
|
targetCoid: Cid,
|
||||||
templateId: Identifier,
|
templateId: Identifier,
|
||||||
choiceId: ChoiceName,
|
choiceId: ChoiceName,
|
||||||
@ -225,7 +218,6 @@ object Node {
|
|||||||
key: Option[KeyWithMaintainers[Val]],
|
key: Option[KeyWithMaintainers[Val]],
|
||||||
): NodeExercises[Nid, Cid, Val] =
|
): NodeExercises[Nid, Cid, Val] =
|
||||||
NodeExercises(
|
NodeExercises(
|
||||||
nodeSeed,
|
|
||||||
targetCoid,
|
targetCoid,
|
||||||
templateId,
|
templateId,
|
||||||
choiceId,
|
choiceId,
|
||||||
@ -287,7 +279,7 @@ object Node {
|
|||||||
): Boolean =
|
): Boolean =
|
||||||
ScalazEqual.match2[recorded.type, isReplayedBy.type, Boolean](fallback = false) {
|
ScalazEqual.match2[recorded.type, isReplayedBy.type, Boolean](fallback = false) {
|
||||||
case nc: NodeCreate[Cid, Val] => {
|
case nc: NodeCreate[Cid, Val] => {
|
||||||
case NodeCreate(_, coid2, coinst2, optLocation2 @ _, signatories2, stakeholders2, key2) =>
|
case NodeCreate(coid2, coinst2, optLocation2 @ _, signatories2, stakeholders2, key2) =>
|
||||||
import nc._
|
import nc._
|
||||||
// NOTE(JM): Do not compare location annotations as they may differ due to
|
// NOTE(JM): Do not compare location annotations as they may differ due to
|
||||||
// differing update expression constructed from the root node.
|
// differing update expression constructed from the root node.
|
||||||
@ -313,7 +305,6 @@ object Node {
|
|||||||
}
|
}
|
||||||
case ne: NodeExercises[Nothing, Cid, Val] => {
|
case ne: NodeExercises[Nothing, Cid, Val] => {
|
||||||
case NodeExercises(
|
case NodeExercises(
|
||||||
_,
|
|
||||||
targetCoid2,
|
targetCoid2,
|
||||||
templateId2,
|
templateId2,
|
||||||
choiceId2,
|
choiceId2,
|
||||||
|
@ -207,7 +207,7 @@ final case class GenTransaction[Nid, +Cid, +Val](
|
|||||||
|
|
||||||
def localContracts[Cid2 >: Cid]: Map[Cid2, Nid] =
|
def localContracts[Cid2 >: Cid]: Map[Cid2, Nid] =
|
||||||
fold(Map.empty[Cid2, Nid]) {
|
fold(Map.empty[Cid2, Nid]) {
|
||||||
case (acc, (nid, create @ Node.NodeCreate(_, _, _, _, _, _, _))) =>
|
case (acc, (nid, create @ Node.NodeCreate(_, _, _, _, _, _))) =>
|
||||||
acc.updated(create.coid, nid)
|
acc.updated(create.coid, nid)
|
||||||
case (acc, _) => acc
|
case (acc, _) => acc
|
||||||
}
|
}
|
||||||
@ -217,7 +217,7 @@ final case class GenTransaction[Nid, +Cid, +Val](
|
|||||||
*/
|
*/
|
||||||
def inputContracts[Cid2 >: Cid]: Set[Cid2] =
|
def inputContracts[Cid2 >: Cid]: Set[Cid2] =
|
||||||
fold(Set.empty[Cid2]) {
|
fold(Set.empty[Cid2]) {
|
||||||
case (acc, (_, Node.NodeExercises(_, coid, _, _, _, _, _, _, _, _, _, _, _, _))) =>
|
case (acc, (_, Node.NodeExercises(coid, _, _, _, _, _, _, _, _, _, _, _, _))) =>
|
||||||
acc + coid
|
acc + coid
|
||||||
case (acc, (_, Node.NodeFetch(coid, _, _, _, _, _, _))) =>
|
case (acc, (_, Node.NodeFetch(coid, _, _, _, _, _, _))) =>
|
||||||
acc + coid
|
acc + coid
|
||||||
@ -392,9 +392,11 @@ object Transaction {
|
|||||||
* time.
|
* time.
|
||||||
*/
|
*/
|
||||||
final case class Metadata(
|
final case class Metadata(
|
||||||
|
submissionSeed: Option[crypto.Hash],
|
||||||
submissionTime: Time.Timestamp,
|
submissionTime: Time.Timestamp,
|
||||||
usedPackages: Set[PackageId],
|
usedPackages: Set[PackageId],
|
||||||
dependsOnTime: Boolean
|
dependsOnTime: Boolean,
|
||||||
|
nodeSeeds: ImmArray[(Value.NodeId, crypto.Hash)],
|
||||||
)
|
)
|
||||||
|
|
||||||
type AbsTransaction = GenTransaction.WithTxValue[NodeId, Value.AbsoluteContractId]
|
type AbsTransaction = GenTransaction.WithTxValue[NodeId, Value.AbsoluteContractId]
|
||||||
|
@ -147,7 +147,7 @@ object TransactionCoder {
|
|||||||
minContractKeyInFetch,
|
minContractKeyInFetch,
|
||||||
}
|
}
|
||||||
node match {
|
node match {
|
||||||
case nc @ NodeCreate(_, _, _, _, _, _, _) =>
|
case nc @ NodeCreate(_, _, _, _, _, _) =>
|
||||||
val createBuilder =
|
val createBuilder =
|
||||||
TransactionOuterClass.NodeCreate
|
TransactionOuterClass.NodeCreate
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
@ -211,7 +211,7 @@ object TransactionCoder {
|
|||||||
nodeBuilder.setFetch(fetchBuilder).build()
|
nodeBuilder.setFetch(fetchBuilder).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
case ne @ NodeExercises(_, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
|
case ne @ NodeExercises(_, _, _, _, _, _, _, _, _, _, _, _, _) =>
|
||||||
for {
|
for {
|
||||||
argValue <- encodeValue(encodeCid, ne.chosenValue)
|
argValue <- encodeValue(encodeCid, ne.chosenValue)
|
||||||
(vversion, arg) = argValue
|
(vversion, arg) = argValue
|
||||||
@ -344,7 +344,7 @@ object TransactionCoder {
|
|||||||
else if (txVersion precedes minKeyOrLookupByKey)
|
else if (txVersion precedes minKeyOrLookupByKey)
|
||||||
Left(DecodeError(s"$txVersion is too old to support NodeCreate's `key` field"))
|
Left(DecodeError(s"$txVersion is too old to support NodeCreate's `key` field"))
|
||||||
else decodeKeyWithMaintainers(decodeCid, protoCreate.getKeyWithMaintainers).map(Some(_))
|
else decodeKeyWithMaintainers(decodeCid, protoCreate.getKeyWithMaintainers).map(Some(_))
|
||||||
} yield (ni, NodeCreate(None, c, ci, None, signatories, stakeholders, key))
|
} yield (ni, NodeCreate(c, ci, None, signatories, stakeholders, key))
|
||||||
case NodeTypeCase.FETCH =>
|
case NodeTypeCase.FETCH =>
|
||||||
val protoFetch = protoNode.getFetch
|
val protoFetch = protoNode.getFetch
|
||||||
for {
|
for {
|
||||||
@ -434,7 +434,6 @@ object TransactionCoder {
|
|||||||
(
|
(
|
||||||
ni,
|
ni,
|
||||||
NodeExercises(
|
NodeExercises(
|
||||||
None,
|
|
||||||
targetCoid = targetCoid,
|
targetCoid = targetCoid,
|
||||||
templateId = templateId,
|
templateId = templateId,
|
||||||
choiceId = choiceName,
|
choiceId = choiceName,
|
||||||
|
@ -304,7 +304,6 @@ class TransactionCoderSpec
|
|||||||
"do tx with a lot of root nodes" in {
|
"do tx with a lot of root nodes" in {
|
||||||
val node =
|
val node =
|
||||||
Node.NodeCreate[Value.AbsoluteContractId, Value.VersionedValue[Value.AbsoluteContractId]](
|
Node.NodeCreate[Value.AbsoluteContractId, Value.VersionedValue[Value.AbsoluteContractId]](
|
||||||
nodeSeed = None,
|
|
||||||
coid = absCid("#test-cid"),
|
coid = absCid("#test-cid"),
|
||||||
coinst = ContractInst(
|
coinst = ContractInst(
|
||||||
Identifier(
|
Identifier(
|
||||||
|
@ -170,7 +170,6 @@ object TransactionSpec {
|
|||||||
hasExerciseResult: Boolean = true,
|
hasExerciseResult: Boolean = true,
|
||||||
): NodeExercises[V.NodeId, V.ContractId, Value] =
|
): NodeExercises[V.NodeId, V.ContractId, Value] =
|
||||||
NodeExercises(
|
NodeExercises(
|
||||||
nodeSeed = None,
|
|
||||||
targetCoid = toCid(cid),
|
targetCoid = toCid(cid),
|
||||||
templateId = Ref.Identifier(
|
templateId = Ref.Identifier(
|
||||||
Ref.PackageId.assertFromString("-dummyPkg-"),
|
Ref.PackageId.assertFromString("-dummyPkg-"),
|
||||||
@ -191,7 +190,6 @@ object TransactionSpec {
|
|||||||
|
|
||||||
def dummyCreateNode(cid: String): NodeCreate[V.ContractId, Value] =
|
def dummyCreateNode(cid: String): NodeCreate[V.ContractId, Value] =
|
||||||
NodeCreate(
|
NodeCreate(
|
||||||
nodeSeed = None,
|
|
||||||
coid = toCid(cid),
|
coid = toCid(cid),
|
||||||
coinst = V.ContractInst(
|
coinst = V.ContractInst(
|
||||||
Ref.Identifier(
|
Ref.Identifier(
|
||||||
|
@ -86,13 +86,13 @@ private[kvutils] object InputsAndEffects {
|
|||||||
GlobalKey(fetch.templateId, forceNoContractIds(keyWithMaintainers.key.value)))
|
GlobalKey(fetch.templateId, forceNoContractIds(keyWithMaintainers.key.value)))
|
||||||
}
|
}
|
||||||
|
|
||||||
case create @ NodeCreate(_, _, _, _, _, _, _) =>
|
case create @ NodeCreate(_, _, _, _, _, _) =>
|
||||||
create.key.foreach { keyWithMaintainers =>
|
create.key.foreach { keyWithMaintainers =>
|
||||||
inputs += globalKeyToStateKey(
|
inputs += globalKeyToStateKey(
|
||||||
GlobalKey(create.coinst.template, forceNoContractIds(keyWithMaintainers.key.value)))
|
GlobalKey(create.coinst.template, forceNoContractIds(keyWithMaintainers.key.value)))
|
||||||
}
|
}
|
||||||
|
|
||||||
case exe @ NodeExercises(_, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
|
case exe @ NodeExercises(_, _, _, _, _, _, _, _, _, _, _, _, _) =>
|
||||||
addContractInput(exe.targetCoid)
|
addContractInput(exe.targetCoid)
|
||||||
|
|
||||||
case lookup @ NodeLookupByKey(_, _, _, _) =>
|
case lookup @ NodeLookupByKey(_, _, _, _) =>
|
||||||
@ -118,7 +118,7 @@ private[kvutils] object InputsAndEffects {
|
|||||||
node match {
|
node match {
|
||||||
case fetch @ NodeFetch(_, _, _, _, _, _, _) =>
|
case fetch @ NodeFetch(_, _, _, _, _, _, _) =>
|
||||||
effects
|
effects
|
||||||
case create @ NodeCreate(_, _, _, _, _, _, _) =>
|
case create @ NodeCreate(_, _, _, _, _, _) =>
|
||||||
effects.copy(
|
effects.copy(
|
||||||
createdContracts = contractIdToStateKey(create.coid) -> create :: effects.createdContracts,
|
createdContracts = contractIdToStateKey(create.coid) -> create :: effects.createdContracts,
|
||||||
updatedContractKeys = create.key
|
updatedContractKeys = create.key
|
||||||
@ -141,7 +141,7 @@ private[kvutils] object InputsAndEffects {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
case exe @ NodeExercises(_, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
|
case exe @ NodeExercises(_, _, _, _, _, _, _, _, _, _, _, _, _) =>
|
||||||
if (exe.consuming) {
|
if (exe.consuming) {
|
||||||
effects.copy(
|
effects.copy(
|
||||||
consumedContracts = contractIdToStateKey(exe.targetCoid) :: effects.consumedContracts,
|
consumedContracts = contractIdToStateKey(exe.targetCoid) :: effects.consumedContracts,
|
||||||
|
@ -252,13 +252,13 @@ private[kvutils] class ProcessTransactionSubmission(
|
|||||||
.fold((true, startingKeys)) {
|
.fold((true, startingKeys)) {
|
||||||
case (
|
case (
|
||||||
(allUnique, existingKeys),
|
(allUnique, existingKeys),
|
||||||
(_, exe @ Node.NodeExercises(_, _, _, _, _, _, _, _, _, _, _, _, _, _)))
|
(_, exe @ Node.NodeExercises(_, _, _, _, _, _, _, _, _, _, _, _, _)))
|
||||||
if exe.key.isDefined && exe.consuming =>
|
if exe.key.isDefined && exe.consuming =>
|
||||||
val stateKey = Conversions.globalKeyToStateKey(
|
val stateKey = Conversions.globalKeyToStateKey(
|
||||||
Node.GlobalKey(exe.templateId, Conversions.forceNoContractIds(exe.key.get.key.value)))
|
Node.GlobalKey(exe.templateId, Conversions.forceNoContractIds(exe.key.get.key.value)))
|
||||||
(allUnique, existingKeys - stateKey)
|
(allUnique, existingKeys - stateKey)
|
||||||
|
|
||||||
case ((allUnique, existingKeys), (_, create @ Node.NodeCreate(_, _, _, _, _, _, _)))
|
case ((allUnique, existingKeys), (_, create @ Node.NodeCreate(_, _, _, _, _, _)))
|
||||||
if create.key.isDefined =>
|
if create.key.isDefined =>
|
||||||
val stateKey = Conversions.globalKeyToStateKey(
|
val stateKey = Conversions.globalKeyToStateKey(
|
||||||
Node.GlobalKey(
|
Node.GlobalKey(
|
||||||
|
@ -25,7 +25,6 @@ class ProjectionsSpec extends WordSpec with Matchers {
|
|||||||
|
|
||||||
def makeCreateNode(cid: ContractId, signatories: Set[Party], stakeholders: Set[Party]) =
|
def makeCreateNode(cid: ContractId, signatories: Set[Party], stakeholders: Set[Party]) =
|
||||||
Node.NodeCreate(
|
Node.NodeCreate(
|
||||||
nodeSeed = None,
|
|
||||||
coid = cid,
|
coid = cid,
|
||||||
coinst = ContractInst(
|
coinst = ContractInst(
|
||||||
Identifier(
|
Identifier(
|
||||||
@ -47,7 +46,6 @@ class ProjectionsSpec extends WordSpec with Matchers {
|
|||||||
stakeholders: Set[Party],
|
stakeholders: Set[Party],
|
||||||
children: ImmArray[NodeId]) =
|
children: ImmArray[NodeId]) =
|
||||||
Node.NodeExercises(
|
Node.NodeExercises(
|
||||||
nodeSeed = None,
|
|
||||||
targetCoid = target,
|
targetCoid = target,
|
||||||
templateId = Identifier(
|
templateId = Identifier(
|
||||||
PackageId.assertFromString("some-package"),
|
PackageId.assertFromString("some-package"),
|
||||||
|
@ -55,7 +55,7 @@ class V5_1__Populate_Event_Data extends BaseJavaMigration {
|
|||||||
val data = txs.flatMap {
|
val data = txs.flatMap {
|
||||||
case (txId, tx) =>
|
case (txId, tx) =>
|
||||||
tx.nodes.collect {
|
tx.nodes.collect {
|
||||||
case (eventId, NodeCreate(nodeSeed @ _, cid, _, _, signatories, stakeholders, _)) =>
|
case (eventId, NodeCreate(cid, _, _, signatories, stakeholders, _)) =>
|
||||||
(cid, eventId, signatories, stakeholders -- signatories)
|
(cid, eventId, signatories, stakeholders -- signatories)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ class V10_1__Populate_Event_Data extends BaseJavaMigration {
|
|||||||
val data = txs.flatMap {
|
val data = txs.flatMap {
|
||||||
case (txId, tx) =>
|
case (txId, tx) =>
|
||||||
tx.nodes.collect {
|
tx.nodes.collect {
|
||||||
case (eventId, NodeCreate(nodeSeed @ _, cid, _, _, signatories, stakeholders, _)) =>
|
case (eventId, NodeCreate(cid, _, _, signatories, stakeholders, _)) =>
|
||||||
(cid, eventId, signatories, stakeholders -- signatories)
|
(cid, eventId, signatories, stakeholders -- signatories)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ private[dao] trait JdbcLedgerDaoContractsSpec {
|
|||||||
GenTransaction(
|
GenTransaction(
|
||||||
HashMap(
|
HashMap(
|
||||||
event1 -> NodeCreate(
|
event1 -> NodeCreate(
|
||||||
nodeSeed = None,
|
|
||||||
coid = absCid,
|
coid = absCid,
|
||||||
coinst = someContractInstance,
|
coinst = someContractInstance,
|
||||||
optLocation = None,
|
optLocation = None,
|
||||||
|
@ -66,7 +66,6 @@ private[dao] trait JdbcLedgerDaoLedgerEntriesSpec extends LoneElement {
|
|||||||
GenTransaction(
|
GenTransaction(
|
||||||
HashMap(
|
HashMap(
|
||||||
event1 -> NodeCreate(
|
event1 -> NodeCreate(
|
||||||
nodeSeed = None,
|
|
||||||
coid = absCid,
|
coid = absCid,
|
||||||
coinst = someContractInstance,
|
coinst = someContractInstance,
|
||||||
optLocation = None,
|
optLocation = None,
|
||||||
@ -114,7 +113,6 @@ private[dao] trait JdbcLedgerDaoLedgerEntriesSpec extends LoneElement {
|
|||||||
GenTransaction(
|
GenTransaction(
|
||||||
HashMap(
|
HashMap(
|
||||||
event1 -> NodeCreate(
|
event1 -> NodeCreate(
|
||||||
nodeSeed = None,
|
|
||||||
coid = absCid,
|
coid = absCid,
|
||||||
coinst = someContractInstance,
|
coinst = someContractInstance,
|
||||||
optLocation = None,
|
optLocation = None,
|
||||||
|
@ -110,7 +110,6 @@ private[dao] trait JdbcLedgerDaoSuite extends AkkaBeforeAndAfterAll with JdbcLed
|
|||||||
absCid: AbsoluteContractId,
|
absCid: AbsoluteContractId,
|
||||||
): NodeCreate.WithTxValue[AbsoluteContractId] =
|
): NodeCreate.WithTxValue[AbsoluteContractId] =
|
||||||
NodeCreate(
|
NodeCreate(
|
||||||
nodeSeed = None,
|
|
||||||
coid = absCid,
|
coid = absCid,
|
||||||
coinst = someContractInstance,
|
coinst = someContractInstance,
|
||||||
optLocation = None,
|
optLocation = None,
|
||||||
@ -123,7 +122,6 @@ private[dao] trait JdbcLedgerDaoSuite extends AkkaBeforeAndAfterAll with JdbcLed
|
|||||||
targetCid: AbsoluteContractId,
|
targetCid: AbsoluteContractId,
|
||||||
): NodeExercises.WithTxValue[EventId, AbsoluteContractId] =
|
): NodeExercises.WithTxValue[EventId, AbsoluteContractId] =
|
||||||
NodeExercises(
|
NodeExercises(
|
||||||
nodeSeed = None,
|
|
||||||
targetCoid = targetCid,
|
targetCoid = targetCid,
|
||||||
templateId = someTemplateId,
|
templateId = someTemplateId,
|
||||||
choiceId = Ref.Name.assertFromString("choice"),
|
choiceId = Ref.Name.assertFromString("choice"),
|
||||||
@ -425,7 +423,6 @@ private[dao] trait JdbcLedgerDaoSuite extends AkkaBeforeAndAfterAll with JdbcLed
|
|||||||
GenTransaction(
|
GenTransaction(
|
||||||
HashMap(
|
HashMap(
|
||||||
event(s"transactionId$id", id) -> NodeCreate(
|
event(s"transactionId$id", id) -> NodeCreate(
|
||||||
nodeSeed = None,
|
|
||||||
coid = AbsoluteContractId.assertFromString(s"#contractId$id"),
|
coid = AbsoluteContractId.assertFromString(s"#contractId$id"),
|
||||||
coinst = someContractInstance,
|
coinst = someContractInstance,
|
||||||
optLocation = None,
|
optLocation = None,
|
||||||
@ -465,7 +462,6 @@ private[dao] trait JdbcLedgerDaoSuite extends AkkaBeforeAndAfterAll with JdbcLed
|
|||||||
GenTransaction(
|
GenTransaction(
|
||||||
HashMap(
|
HashMap(
|
||||||
event(s"transactionId$id", id) -> NodeExercises(
|
event(s"transactionId$id", id) -> NodeExercises(
|
||||||
nodeSeed = None,
|
|
||||||
targetCoid = AbsoluteContractId.assertFromString(s"#contractId${cid.toLong}"),
|
targetCoid = AbsoluteContractId.assertFromString(s"#contractId${cid.toLong}"),
|
||||||
templateId = someTemplateId,
|
templateId = someTemplateId,
|
||||||
choiceId = Ref.ChoiceName.assertFromString("Archive"),
|
choiceId = Ref.ChoiceName.assertFromString("Archive"),
|
||||||
|
@ -81,7 +81,6 @@ class ImplicitPartyAdditionIT
|
|||||||
"create-signatory",
|
"create-signatory",
|
||||||
"CmdId1",
|
"CmdId1",
|
||||||
NodeCreate(
|
NodeCreate(
|
||||||
nodeSeed = None,
|
|
||||||
coid = Value.AbsoluteContractId.assertFromString("#cId1"),
|
coid = Value.AbsoluteContractId.assertFromString("#cId1"),
|
||||||
coinst = Value.ContractInst(
|
coinst = Value.ContractInst(
|
||||||
templateId1,
|
templateId1,
|
||||||
@ -99,7 +98,6 @@ class ImplicitPartyAdditionIT
|
|||||||
"exercise-signatory",
|
"exercise-signatory",
|
||||||
"CmdId2",
|
"CmdId2",
|
||||||
NodeExercises(
|
NodeExercises(
|
||||||
nodeSeed = None,
|
|
||||||
targetCoid = Value.AbsoluteContractId.assertFromString("#cId1"),
|
targetCoid = Value.AbsoluteContractId.assertFromString("#cId1"),
|
||||||
templateId = templateId1,
|
templateId = templateId1,
|
||||||
choiceId = Ref.ChoiceName.assertFromString("choice"),
|
choiceId = Ref.ChoiceName.assertFromString("choice"),
|
||||||
|
Loading…
Reference in New Issue
Block a user