[LF] factorize GlobalKeyWithMaintainers and KeyWithMaintainers (#16251)

This commit is contained in:
Remy 2023-02-08 13:58:43 +01:00 committed by GitHub
parent aa81f567db
commit a75db47275
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 443 additions and 405 deletions

View File

@ -8,7 +8,13 @@ import com.daml.lf.data.{ImmArray, Numeric, Ref}
import com.daml.lf.ledger.EventId
import com.daml.lf.scenario.api.{v1 => proto}
import com.daml.lf.speedy.{SError, SValue, TraceLog, Warning, WarningLog}
import com.daml.lf.transaction.{GlobalKey, IncompleteTransaction, Node, NodeId}
import com.daml.lf.transaction.{
GlobalKey,
GlobalKeyWithMaintainers,
IncompleteTransaction,
Node,
NodeId,
}
import com.daml.lf.ledger._
import com.daml.lf.value.{Value => V}
@ -588,7 +594,7 @@ final class Conversions(
.addAllSignatories(fetch.signatories.map(convertParty).asJava)
.addAllStakeholders(fetch.stakeholders.map(convertParty).asJava)
if (fetch.byKey) {
fetch.versionedKey.foreach { key =>
fetch.keyOpt.foreach { key =>
fetchBuilder.setFetchByKey(convertKeyWithMaintainers(key))
}
}
@ -615,7 +621,7 @@ final class Conversions(
exerciseBuilder.setExerciseResult(convertValue(result))
}
if (ex.byKey) {
ex.versionedKey.foreach { key =>
ex.keyOpt.foreach { key =>
exerciseBuilder.setExerciseByKey(convertKeyWithMaintainers(key))
}
}
@ -625,7 +631,7 @@ final class Conversions(
nodeInfo.optLocation.foreach(loc => builder.setLocation(convertLocation(loc)))
val lbkBuilder = proto.Node.LookupByKey.newBuilder
.setTemplateId(convertIdentifier(lbk.templateId))
.setKeyWithMaintainers(convertKeyWithMaintainers(lbk.versionedKey))
.setKeyWithMaintainers(convertKeyWithMaintainers(lbk.key))
lbk.result.foreach(cid => lbkBuilder.setContractId(coidToEventId(cid).toLedgerString))
builder.setLookupByKey(lbkBuilder)
@ -634,12 +640,12 @@ final class Conversions(
}
def convertKeyWithMaintainers(
key: Node.VersionedKeyWithMaintainers
key: GlobalKeyWithMaintainers
): proto.KeyWithMaintainers = {
proto.KeyWithMaintainers
.newBuilder()
.setKey(convertVersionedValue(key.map(_.key)))
.addAllMaintainers(key.unversioned.maintainers.map(convertParty).asJava)
.setKey(convertValue(key.value))
.addAllMaintainers(key.maintainers.map(convertParty).asJava)
.build()
}
@ -675,7 +681,7 @@ final class Conversions(
)
.addAllSignatories(create.signatories.map(convertParty).asJava)
.addAllStakeholders(create.stakeholders.map(convertParty).asJava)
create.versionedKey.foreach(key =>
create.keyOpt.foreach(key =>
createBuilder.setKeyWithMaintainers(convertKeyWithMaintainers(key))
)
optLocation.map(loc => builder.setLocation(convertLocation(loc)))
@ -714,7 +720,7 @@ final class Conversions(
optLocation.map(loc => builder.setLocation(convertLocation(loc)))
builder.setLookupByKey({
val builder = proto.Node.LookupByKey.newBuilder
.setKeyWithMaintainers(convertKeyWithMaintainers(lookup.versionedKey))
.setKeyWithMaintainers(convertKeyWithMaintainers(lookup.key))
lookup.result.foreach(cid => builder.setContractId(coidToEventId(cid).toLedgerString))
builder.build
})
@ -750,9 +756,6 @@ final class Conversions(
}
private def convertVersionedValue(value: V.VersionedValue): proto.Value =
convertValue(value.unversioned)
def convertValue(value: V): proto.Value = {
val builder = proto.Value.newBuilder
value match {

View File

@ -5,9 +5,9 @@ package com.daml.lf
package engine
import com.daml.lf.data.Ref.{ChoiceName, Identifier, Party}
import com.daml.lf.transaction.Node._
import com.daml.lf.transaction.NodeId
import com.daml.lf.data.ImmArray
import com.daml.lf.transaction.GlobalKeyWithMaintainers
import com.daml.lf.value.Value
import com.daml.lf.value.Value.ContractId
import com.daml.scalautil.Statement.discard
@ -33,7 +33,7 @@ sealed trait Event extends Product with Serializable {
final case class CreateEvent(
contractId: ContractId,
templateId: Identifier,
contractKey: Option[KeyWithMaintainers],
contractKey: Option[GlobalKeyWithMaintainers],
argument: Value,
agreementText: String,
signatories: Set[Party],

View File

@ -7,10 +7,13 @@ package engine
import com.daml.lf.data.Ref.{Identifier, Name, PackageId}
import com.daml.lf.language.{Ast, LookupError}
import com.daml.lf.transaction.{
GlobalKey,
GlobalKeyWithMaintainers,
IncompleteTransaction,
Transaction,
Node,
NodeId,
Versioned,
VersionedTransaction,
}
import com.daml.lf.value.Value
@ -120,35 +123,33 @@ final class ValueEnricher(
private val ResultNone = ResultDone(None)
def enrichContractKey(
tyCon: Identifier,
key: Node.KeyWithMaintainers,
): Result[Node.KeyWithMaintainers] =
enrichContractKey(tyCon, key.key).map(normalizedKey => key.copy(key = normalizedKey))
key: GlobalKeyWithMaintainers
): Result[GlobalKeyWithMaintainers] =
enrichContractKey(key.globalKey.templateId, key.globalKey.key).map(normalizedKey =>
key.copy(globalKey = GlobalKey.assertBuild(key.globalKey.templateId, normalizedKey))
)
def enrichContractKey(
tyCon: Identifier,
key: Option[Node.KeyWithMaintainers],
): Result[Option[Node.KeyWithMaintainers]] =
key: Option[GlobalKeyWithMaintainers]
): Result[Option[GlobalKeyWithMaintainers]] =
key match {
case Some(k) =>
enrichContractKey(tyCon, k).map(Some(_))
enrichContractKey(k).map(Some(_))
case None =>
ResultNone
}
def enrichVersionedContractKey(
tyCon: Identifier,
key: Node.VersionedKeyWithMaintainers,
): Result[Node.VersionedKeyWithMaintainers] =
enrichContractKey(tyCon, key.unversioned).map(normalizedValue => key.map(_ => normalizedValue))
key: Versioned[GlobalKeyWithMaintainers]
): Result[Versioned[GlobalKeyWithMaintainers]] =
enrichContractKey(key.unversioned).map(normalizedValue => key.map(_ => normalizedValue))
def enrichVersionedContractKey(
tyCon: Identifier,
key: Option[Node.VersionedKeyWithMaintainers],
): Result[Option[Node.VersionedKeyWithMaintainers]] =
key: Option[Versioned[GlobalKeyWithMaintainers]]
): Result[Option[Versioned[GlobalKeyWithMaintainers]]] =
key match {
case Some(k) =>
enrichVersionedContractKey(tyCon, k).map(Some(_))
enrichVersionedContractKey(k).map(Some(_))
case None =>
ResultNone
}
@ -162,15 +163,15 @@ final class ValueEnricher(
case create: Node.Create =>
for {
arg <- enrichValue(Ast.TTyCon(create.templateId), create.arg)
key <- enrichContractKey(create.templateId, create.key)
} yield create.copy(arg = arg, key = key)
key <- enrichContractKey(create.keyOpt)
} yield create.copy(arg = arg, keyOpt = key)
case fetch: Node.Fetch =>
for {
key <- enrichContractKey(fetch.templateId, fetch.key)
} yield fetch.copy(key = key)
key <- enrichContractKey(fetch.keyOpt)
} yield fetch.copy(keyOpt = key)
case lookup: Node.LookupByKey =>
for {
key <- enrichContractKey(lookup.templateId, lookup.key)
key <- enrichContractKey(lookup.key)
} yield lookup.copy(key = key)
case exe: Node.Exercise =>
for {
@ -188,8 +189,8 @@ final class ValueEnricher(
case None =>
ResultNone
}
key <- enrichContractKey(exe.templateId, exe.key)
} yield exe.copy(chosenValue = choiceArg, exerciseResult = result, key = key)
key <- enrichContractKey(exe.keyOpt)
} yield exe.copy(chosenValue = choiceArg, exerciseResult = result, keyOpt = key)
}
def enrichTransaction(tx: Transaction): Result[Transaction] =

View File

@ -73,11 +73,11 @@ private[preprocessing] final class TransactionPreprocessor(
case create: Node.Create =>
acc :+ commandPreprocessor.unsafePreprocessCreate(create.templateId, create.arg)
case exe: Node.Exercise =>
val cmd = exe.key match {
val cmd = exe.keyOpt match {
case Some(key) if exe.byKey =>
commandPreprocessor.unsafePreprocessExerciseByKey(
exe.templateId,
key.key,
key.globalKey.key,
exe.choiceId,
exe.chosenValue,
)

View File

@ -34,7 +34,7 @@ class AuthorizationSpec extends AnyFreeSpec with Matchers with Inside {
argument = ValueRecord(None, ImmArray.Empty),
signatories = signatories,
observers = Seq("Carl"),
key = Some(Value.ValueUnit),
keyOpt = Some(Value.ValueUnit),
maintainers = maintainers,
)

View File

@ -101,7 +101,7 @@ class BlindingSpec extends AnyFreeSpec with Matchers {
argument = ValueRecord(None, ImmArray.empty),
signatories = Seq("Alice", "Bob"),
observers = Seq("Carl"),
key = Some(ValueRecord(None, ImmArray.empty)),
keyOpt = Some(ValueRecord(None, ImmArray.empty)),
maintainers = Seq("Alice"),
)
val lookup = builder.lookupByKey(create, true)
@ -122,7 +122,7 @@ class BlindingSpec extends AnyFreeSpec with Matchers {
argument = ValueRecord(None, ImmArray.empty),
signatories = Seq("Alice", "Bob"),
observers = Seq("Carl"),
key = Some(ValueRecord(None, ImmArray.empty)),
keyOpt = Some(ValueRecord(None, ImmArray.empty)),
maintainers = Seq("Alice"),
)
val lookup = builder.lookupByKey(create, false)

View File

@ -785,7 +785,7 @@ class EngineTest
driverMetadata = usedDisclosedContract.metadata.driverMetadata,
signatories = Set(alice),
stakeholders = Set(alice),
maybeKeyWithMaintainers = Some(
keyOpt = Some(
Versioned(
transactionVersion,
GlobalKeyWithMaintainers(
@ -1533,7 +1533,7 @@ class EngineTest
newEngine()
.reinterpret(
submitters,
ReplayCommand.LookupByKey(lookupNode.templateId, lookupNode.key.key),
ReplayCommand.LookupByKey(lookupNode.templateId, lookupNode.key.value),
nodeSeedMap.get(nid),
txMeta.submissionTime,
now,
@ -1577,7 +1577,7 @@ class EngineTest
newEngine()
.reinterpret(
submitters,
ReplayCommand.LookupByKey(lookupNode.templateId, lookupNode.key.key),
ReplayCommand.LookupByKey(lookupNode.templateId, lookupNode.key.value),
nodeSeedMap.get(nid),
txMeta.submissionTime,
now,
@ -1680,7 +1680,7 @@ class EngineTest
driverMetadata = usedDisclosedContract.metadata.driverMetadata,
signatories = Set(alice),
stakeholders = Set(alice),
maybeKeyWithMaintainers = Some(
keyOpt = Some(
Versioned(
transactionVersion,
GlobalKeyWithMaintainers(
@ -1742,7 +1742,7 @@ class EngineTest
driverMetadata = usedDisclosedContract.metadata.driverMetadata,
signatories = Set(alice),
stakeholders = Set(alice),
maybeKeyWithMaintainers = None,
keyOpt = None,
agreementText = s"'$alice'", // agreement show party
),
)
@ -1824,7 +1824,7 @@ class EngineTest
case Some(Node.Fetch(_, _, _, _, _, key, _, _)) =>
key match {
// just test that the maintainers match here, getting the key out is a bit hairier
case Some(Node.KeyWithMaintainers(_, maintainers)) =>
case Some(GlobalKeyWithMaintainers(_, maintainers)) =>
assert(maintainers == Set(alice))
case None => fail("the recomputed fetch didn't have a key")
}
@ -1894,9 +1894,9 @@ class EngineTest
tx.transaction.nodes
.collectFirst { case (id, nf: Node.Fetch) =>
nf.key match {
nf.keyOpt match {
// just test that the maintainers match here, getting the key out is a bit hairier
case Some(Node.KeyWithMaintainers(_, maintainers)) =>
case Some(GlobalKeyWithMaintainers(_, maintainers)) =>
assert(maintainers == Set(alice))
case None => fail("the recomputed fetch didn't have a key")
}
@ -2647,14 +2647,14 @@ object EngineTest {
case create: Node.Create =>
ReplayCommand.Create(create.templateId, create.arg)
case fetch: Node.Fetch if fetch.byKey =>
val key = fetch.key.getOrElse(sys.error("unexpected empty contract key")).key
val key = fetch.keyOpt.getOrElse(sys.error("unexpected empty contract key")).value
ReplayCommand.FetchByKey(fetch.templateId, key)
case fetch: Node.Fetch =>
ReplayCommand.Fetch(fetch.templateId, fetch.coid)
case lookup: Node.LookupByKey =>
ReplayCommand.LookupByKey(lookup.templateId, lookup.key.key)
ReplayCommand.LookupByKey(lookup.templateId, lookup.key.value)
case exe: Node.Exercise if exe.byKey =>
val key = exe.key.getOrElse(sys.error("unexpected empty contract key")).key
val key = exe.keyOpt.getOrElse(sys.error("unexpected empty contract key")).value
ReplayCommand.ExerciseByKey(
exe.templateId,
key,
@ -2805,8 +2805,8 @@ object EngineTest {
create.coid,
create.versionedCoinst,
),
create.key.fold(keys)(k =>
keys.updated(GlobalKey.assertBuild(create.templateId, k.key), create.coid)
create.keyOpt.fold(keys)(k =>
keys.updated(GlobalKey.assertBuild(create.templateId, k.value), create.coid)
),
)
case (acc, _) => acc

View File

@ -25,7 +25,7 @@ class MetaDataTest extends AnyWordSpec with Matchers with TableDrivenPropertyChe
argument = ValueUnit,
signatories = parties,
observers = noOne,
key = Some(ValueParty("alice")),
keyOpt = Some(ValueParty("alice")),
maintainers = parties,
)
val nodeWithoutInterface = Table[TransactionBuilder => Node](
@ -56,7 +56,7 @@ class MetaDataTest extends AnyWordSpec with Matchers with TableDrivenPropertyChe
argument = ValueUnit,
signatories = parties,
observers = noOne,
key = Some(ValueParty("alice")),
keyOpt = Some(ValueParty("alice")),
maintainers = parties,
)
val nodeWithInterface = Table[TransactionBuilder => Node](

View File

@ -13,7 +13,12 @@ import com.daml.lf.ledger._
import com.daml.lf.data.Ref._
import com.daml.lf.scenario.ScenarioLedger.{TransactionId, Disclosure}
import com.daml.lf.scenario._
import com.daml.lf.transaction.{Node, NodeId, TransactionVersion => TxVersion}
import com.daml.lf.transaction.{
GlobalKeyWithMaintainers,
Node,
NodeId,
TransactionVersion => TxVersion,
}
import com.daml.lf.speedy.SError._
import com.daml.lf.speedy.SValue._
import com.daml.lf.speedy.SBuiltin._
@ -269,13 +274,9 @@ private[lf] object Pretty {
prettyLoc(amf.optLocation)
}
def prettyKeyWithMaintainers(key: Node.KeyWithMaintainers): Doc =
def prettyKeyWithMaintainers(key: GlobalKeyWithMaintainers): Doc =
// the maintainers are induced from the key -- so don't clutter
prettyValue(false)(key.key)
def prettyVersionedKeyWithMaintainers(key: Node.VersionedKeyWithMaintainers): Doc =
// the maintainers are induced from the key -- so don't clutter
prettyKeyWithMaintainers(key.unversioned)
prettyValue(false)(key.value)
def prettyEventInfo(l: ScenarioLedger, txId: TransactionId)(nodeId: NodeId): Doc = {
def arrowRight(d: Doc) = text("└─>") & d
@ -289,9 +290,9 @@ private[lf] object Pretty {
text("rollback:") / stack(children.toList.map(prettyEventInfo(l, txId)))
case create: Node.Create =>
val d = "create" &: prettyContractInst(create.coinst)
create.versionedKey match {
create.keyOpt match {
case None => d
case Some(key) => d / text("key") & prettyVersionedKeyWithMaintainers(key)
case Some(key) => d / text("key") & prettyKeyWithMaintainers(key)
}
case ea: Node.Fetch =>
"ensure active" &: prettyContractId(ea.coid)
@ -310,7 +311,7 @@ private[lf] object Pretty {
.nested(4)
case lbk: Node.LookupByKey =>
text("lookup by key") & prettyIdentifier(lbk.templateId) /
text("key") & prettyVersionedKeyWithMaintainers(lbk.versionedKey) /
text("key") & prettyKeyWithMaintainers(lbk.key) /
(lbk.result match {
case None => text("not found")
case Some(coid) => text("found") & prettyContractId(coid)

View File

@ -24,6 +24,7 @@ import com.daml.lf.transaction.{
GlobalKey,
GlobalKeyWithMaintainers,
Transaction => Tx,
TransactionVersion,
}
import com.daml.lf.value.{Value => V}
import com.daml.lf.value.Value.ValueArithmeticError
@ -982,15 +983,13 @@ private[lf] object SBuiltin {
args: util.ArrayList[SValue],
machine: UpdateMachine,
): Control[Nothing] = {
val cached = extractCachedContract(args.get(0))
val version = machine.tmplId2TxVersion(cached.templateId)
val createArgValue = cached.value.toNormalizedValue(version)
val cached = extractCachedContract(machine.tmplId2TxVersion, args.get(0))
cached.key match {
case Some(cachedKey) if cachedKey.maintainers.isEmpty =>
Control.Error(
IE.CreateEmptyContractKeyMaintainers(
cached.templateId,
createArgValue,
cached.arg,
cachedKey.lfValue,
)
)
@ -1000,7 +999,6 @@ private[lf] object SBuiltin {
submissionTime = machine.submissionTime,
contract = cached,
optLocation = machine.getLastLocation,
version = version,
) match {
case Right((coid, newPtx)) =>
machine.updateCachedContracts(coid, cached)
@ -1485,7 +1483,9 @@ private[lf] object SBuiltin {
args: util.ArrayList[SValue],
machine: UpdateMachine,
): Control[Nothing] = {
val cachedKey = extractKey(NameOf.qualifiedNameOfCurrentFunc, templateId, args.get(0))
val keyVersion = machine.tmplId2TxVersion(templateId)
val cachedKey =
extractKey(NameOf.qualifiedNameOfCurrentFunc, keyVersion, templateId, args.get(0))
val mbCoid = args.get(1) match {
case SOptional(mb) =>
mb.map {
@ -1494,13 +1494,11 @@ private[lf] object SBuiltin {
}
case _ => crash(s"Non option value when inserting lookup node")
}
val version = machine.tmplId2TxVersion(templateId)
machine.ptx.insertLookup(
templateId = templateId,
optLocation = machine.getLastLocation,
key = cachedKey,
result = mbCoid,
version = version,
keyVersion = keyVersion,
) match {
case Right(ptx) =>
machine.ptx = ptx
@ -1561,12 +1559,14 @@ private[lf] object SBuiltin {
machine: UpdateMachine,
): Control[Question.Update] = {
val svalue = args.get(0)
val cachedKey = extractKey(NameOf.qualifiedNameOfCurrentFunc, operation.templateId, svalue)
val version = machine.tmplId2TxVersion(operation.templateId)
val cachedKey =
extractKey(NameOf.qualifiedNameOfCurrentFunc, version, operation.templateId, svalue)
if (cachedKey.maintainers.isEmpty) {
Control.Error(
IE.FetchEmptyContractKeyMaintainers(
operation.templateId,
cachedKey.templateId,
cachedKey.lfValue,
)
)
@ -2128,14 +2128,13 @@ private[lf] object SBuiltin {
args: util.ArrayList[SValue],
machine: UpdateMachine,
): Control[Nothing] = {
val cachedContract = extractCachedContract(args.get(0))
val templateId = cachedContract.templateId
val cachedContract = extractCachedContract(machine.tmplId2TxVersion, args.get(0))
val optError: Option[Either[IE, Unit]] = for {
cachedKey <- cachedContract.key
} yield {
for {
result <- machine.disclosureKeyTable
.addContractKey(templateId, cachedKey.globalKey.hash, contractId)
.addContractKey(cachedContract.templateId, cachedKey.globalKey.hash, contractId)
} yield result
}
@ -2187,22 +2186,25 @@ private[lf] object SBuiltin {
private[this] def extractKey(
location: String,
version: TransactionVersion,
templateId: Ref.TypeConName,
v: SValue,
): CachedKey =
v match {
case SStruct(_, vals) =>
val keyValue = vals.get(keyIdx)
val lfValue = keyValue.toUnnormalizedValue
val lfValue = keyValue.toNormalizedValue(version)
val gkey = GlobalKey
.build(templateId, lfValue)
.getOrElse(
throw SErrorDamlException(IE.ContractIdInContractKey(keyValue.toUnnormalizedValue))
)
CachedKey(
gkey,
GlobalKeyWithMaintainers(
gkey,
extractParties(NameOf.qualifiedNameOfCurrentFunc, vals.get(maintainerIdx)),
),
keyValue,
extractParties(NameOf.qualifiedNameOfCurrentFunc, vals.get(maintainerIdx)),
)
case _ => throw SErrorCrash(location, s"Invalid key with maintainers: $v")
}
@ -2229,7 +2231,10 @@ private[lf] object SBuiltin {
private[speedy] val SBuildCachedContract =
SBuiltin.SBStructCon(cachedContractStruct)
private[speedy] def extractCachedContract(v: SValue): CachedContract =
private[speedy] def extractCachedContract(
tmplId2TxVersion: TypeConName => TransactionVersion,
v: SValue,
): CachedContract =
v match {
case SStruct(_, vals) if vals.size == cachedContractStruct.size =>
val templateId = vals.get(cachedContractTypeFieldIdx) match {
@ -2237,9 +2242,10 @@ private[lf] object SBuiltin {
case _ =>
throw SErrorCrash(NameOf.qualifiedNameOfCurrentFunc, s"Invalid cached contract: $v")
}
val version = tmplId2TxVersion(templateId)
val mbKey = vals.get(cachedContractKeyIdx) match {
case SOptional(mbKey) =>
mbKey.map(extractKey(NameOf.qualifiedNameOfCurrentFunc, templateId, _))
mbKey.map(extractKey(NameOf.qualifiedNameOfCurrentFunc, version, templateId, _))
case v =>
throw SErrorCrash(
NameOf.qualifiedNameOfCurrentFunc,
@ -2247,6 +2253,7 @@ private[lf] object SBuiltin {
)
}
CachedContract(
version = version,
templateId = templateId,
value = vals.get(cachedContractArgIdx),
agreementText =

View File

@ -111,16 +111,17 @@ private[lf] object Speedy {
sealed abstract class LedgerMode extends Product with Serializable
final case class CachedKey(
globalKey: GlobalKey,
globalKeyWithMaintainers: GlobalKeyWithMaintainers,
key: SValue,
maintainers: Set[Party],
) {
def toNodeKey(version: TxVersion) =
Node.KeyWithMaintainers(key.toNormalizedValue(version), maintainers)
def globalKey: GlobalKey = globalKeyWithMaintainers.globalKey
def templateId: TypeConName = globalKey.templateId
def maintainers: Set[Party] = globalKeyWithMaintainers.maintainers
val lfValue = globalKey.key
}
final case class CachedContract(
version: TxVersion,
templateId: Ref.TypeConName,
value: SValue,
agreementText: String,
@ -130,6 +131,18 @@ private[lf] object Speedy {
) {
val stakeholders: Set[Party] = signatories union observers
private[speedy] val any = SValue.SAny(TTyCon(templateId), value)
private[speedy] def arg = value.toNormalizedValue(version)
private[speedy] def toCreateNode(coid: V.ContractId) =
Node.Create(
coid = coid,
templateId = templateId,
arg = arg,
agreementText = agreementText,
signatories = signatories,
stakeholders = stakeholders,
keyOpt = key.map(_.globalKeyWithMaintainers),
version = version,
)
}
private[this] def enforceLimit(actual: Int, limit: Int, error: Int => IError.Limit.Error): Unit =
@ -331,23 +344,16 @@ private[lf] object Speedy {
)
)
val transactionVersion = tmplId2TxVersion(cachedContract.templateId)
val maybeKeyWithMaintainers =
cachedContract.key
.map(_.toNodeKey(transactionVersion))
.map { case Node.KeyWithMaintainers(key, maintainers) =>
GlobalKeyWithMaintainers(
globalKey = GlobalKey.assertBuild(disclosedContract.templateId, key),
maintainers = maintainers,
)
}
.map(Versioned(transactionVersion, _))
val keyOpt = cachedContract.key.map(k =>
Versioned(cachedContract.version, k.globalKeyWithMaintainers)
)
val engineEnrichedContractMetadata = EngineEnrichedContractMetadata(
createdAt = disclosedContract.metadata.createdAt,
driverMetadata = disclosedContract.metadata.driverMetadata,
signatories = cachedContract.signatories,
stakeholders = cachedContract.stakeholders,
maybeKeyWithMaintainers = maybeKeyWithMaintainers,
keyOpt = keyOpt,
agreementText = cachedContract.agreementText,
)
val engineEnrichedDisclosedContract =
@ -1704,7 +1710,7 @@ private[lf] object Speedy {
private[speedy] final case class KCacheContract(cid: V.ContractId) extends Kont {
override def execute[Q](machine: Machine[Q], sv: SValue): Control[Q] =
machine.asUpdateMachine(productPrefix) { machine =>
val cached = SBuiltin.extractCachedContract(sv)
val cached = SBuiltin.extractCachedContract(machine.tmplId2TxVersion, sv)
machine.checkContractVisibility(cid, cached)
machine.addGlobalContract(cid, cached)
Control.Value(cached.any)

View File

@ -73,7 +73,7 @@ private[lf] object DefaultAuthorizationChecker extends AuthorizationChecker {
passIf = create.signatories.nonEmpty,
failWith = FailedAuthorization.NoSignatories(create.templateId, optLocation),
) ++
(create.key match {
(create.keyOpt match {
case None => List()
case Some(key) =>
val maintainers = key.maintainers

View File

@ -11,6 +11,8 @@ import com.daml.lf.speedy.Speedy.{CachedContract, CachedKey}
import com.daml.lf.transaction.ContractKeyUniquenessMode
import com.daml.lf.transaction.{
ContractStateMachine,
GlobalKey,
GlobalKeyWithMaintainers,
Node,
NodeId,
SubmittedTransaction => SubmittedTx,
@ -142,7 +144,7 @@ private[lf] object PartialTransaction {
targetId: Value.ContractId,
templateId: TypeConName,
interfaceId: Option[TypeConName],
contractKey: Option[Node.KeyWithMaintainers],
contractKey: Option[GlobalKeyWithMaintainers],
choiceId: ChoiceName,
consuming: Boolean,
actingParties: Set[Party],
@ -347,28 +349,18 @@ private[speedy] case class PartialTransaction(
submissionTime: Time.Timestamp,
contract: CachedContract,
optLocation: Option[Location],
version: TxVersion,
): Either[(PartialTransaction, Tx.TransactionError), (Value.ContractId, PartialTransaction)] = {
val auth = Authorize(context.info.authorizers)
val actionNodeSeed = context.nextActionChildSeed
val discriminator =
crypto.Hash.deriveContractDiscriminator(actionNodeSeed, submissionTime, contract.stakeholders)
val cid = Value.ContractId.V1(discriminator)
val createNode = Node.Create(
cid,
contract.templateId,
contract.value.toNormalizedValue(version),
contract.agreementText,
contract.signatories,
contract.stakeholders,
contract.key.map(_.toNodeKey(version)),
version,
)
val createNode = contract.toCreateNode(cid)
val nid = NodeId(nextNodeIdx)
val ptx = copy(
actionNodeLocations = actionNodeLocations :+ optLocation,
nextNodeIdx = nextNodeIdx + 1,
context = context.addActionChild(nid, version),
context = context.addActionChild(nid, createNode.version),
nodes = nodes.updated(nid, createNode),
actionNodeSeeds = actionNodeSeeds :+ actionNodeSeed,
)
@ -405,7 +397,7 @@ private[speedy] case class PartialTransaction(
actingParties,
contract.signatories,
contract.stakeholders,
contract.key.map(_.toNodeKey(version)),
contract.key.map(_.globalKeyWithMaintainers),
normByKey(version, byKey),
version,
)
@ -427,15 +419,19 @@ private[speedy] case class PartialTransaction(
}
def insertLookup(
templateId: TypeConName,
optLocation: Option[Location],
key: CachedKey,
result: Option[Value.ContractId],
version: TxVersion,
keyVersion: TxVersion,
): Either[Tx.TransactionError, PartialTransaction] = {
val auth = Authorize(context.info.authorizers)
val nid = NodeId(nextNodeIdx)
val node = Node.LookupByKey(templateId, key.toNodeKey(version), result, version)
val node = Node.LookupByKey(
key.templateId,
key.globalKeyWithMaintainers,
result,
keyVersion,
)
// This method is only called after we have already resolved the key in com.daml.lf.speedy.SBuiltin.SBUKeyBuiltin.execute
// so the current state's global key inputs must resolve the key.
val keyInput = contractState.globalKeyInputs(key.globalKey)
@ -444,7 +440,7 @@ private[speedy] case class PartialTransaction(
authorizationChecker.authorizeLookupByKey(optLocation, node)(auth) match {
case fa :: _ => Left(Tx.AuthFailureDuringExecution(nid, fa))
case Nil =>
Right(insertLeafNode(node, version, optLocation, newContractState))
Right(insertLeafNode(node, keyVersion, optLocation, newContractState))
}
}
@ -471,7 +467,17 @@ private[speedy] case class PartialTransaction(
targetId = targetId,
templateId = contract.templateId,
interfaceId = interfaceId,
contractKey = contract.key.map(_.toNodeKey(version)),
contractKey = contract.key.map {
// We need to renormalize the key
case CachedKey(GlobalKeyWithMaintainers(_, maintainers), key) =>
GlobalKeyWithMaintainers(
GlobalKey.assertBuild(
contract.templateId,
key.toNormalizedValue(version),
),
maintainers,
)
},
choiceId = choiceId,
consuming = consuming,
actingParties = actingParties,
@ -573,7 +579,7 @@ private[speedy] case class PartialTransaction(
choiceObservers = ec.choiceObservers,
children = ImmArray.Empty,
exerciseResult = None,
key = ec.contractKey,
keyOpt = ec.contractKey,
byKey = normByKey(ec.version, ec.byKey),
version = ec.version,
)

View File

@ -14,7 +14,7 @@ import com.daml.lf.speedy.SError._
import com.daml.lf.speedy.SExpr._
import com.daml.lf.speedy.SValue._
import com.daml.lf.testing.parser.Implicits.{defaultParserParameters => _, _}
import com.daml.lf.transaction.{GlobalKey, GlobalKeyWithMaintainers, TransactionVersion, Versioned}
import com.daml.lf.transaction.{GlobalKeyWithMaintainers, TransactionVersion, Versioned}
import com.daml.lf.ledger.FailedAuthorization
import com.daml.lf.ledger.FailedAuthorization.{
ExerciseMissingAuthorization,
@ -402,7 +402,7 @@ class EvaluationOrderTest extends AnyFreeSpec with Matchers with Inside {
private[this] val getHelper = Map(helperCId -> helper)
private[this] val getKey = Map(
GlobalKeyWithMaintainers(GlobalKey.assertBuild(T, keyValue), Set(alice)) -> cId
GlobalKeyWithMaintainers.assertBuild(T, keyValue, Set(alice)) -> cId
)
private[this] val dummyContract = Versioned(

View File

@ -222,14 +222,15 @@ object ExplicitDisclosureLib {
if (withKey)
Some(
CachedKey(
GlobalKey.assertBuild(templateId, contract.toUnnormalizedValue),
GlobalKeyWithMaintainers
.assertBuild(templateId, contract.toUnnormalizedValue, Set(maintainer)),
contract,
Set(maintainer),
)
)
else None
CachedContract(
TransactionVersion.minExplicitDisclosure,
templateId,
contract,
agreementText = "",

View File

@ -306,7 +306,7 @@ object NormalizeRollbackSpec {
agreementText = "dummyAgreement",
signatories = Set.empty,
stakeholders = Set.empty,
key = None,
keyOpt = None,
version = TransactionVersion.minVersion,
)
@ -338,7 +338,7 @@ object NormalizeRollbackSpec {
choiceObservers = Set.empty,
children = children,
exerciseResult = None,
key = None,
keyOpt = None,
byKey = false,
version = TransactionVersion.minVersion,
)

View File

@ -42,6 +42,7 @@ class PartialTransactionSpec extends AnyWordSpec with Matchers with Inside {
private[this] implicit class PartialTransactionExtra(val ptx: PartialTransaction) {
val contract = CachedContract(
version = TransactionVersion.maxVersion,
templateId = templateId,
value = SValue.SUnit,
agreementText = "agreement",
@ -56,7 +57,6 @@ class PartialTransactionSpec extends AnyWordSpec with Matchers with Inside {
submissionTime = data.Time.Timestamp.Epoch,
contract = contract,
optLocation = None,
version = TransactionVersion.maxVersion,
)
.toOption
.get

View File

@ -22,7 +22,7 @@ import com.daml.lf.speedy.SExpr._
import com.daml.lf.speedy.SValue.{SValue => _, _}
import com.daml.lf.speedy.Speedy.{CachedContract, Machine, CachedKey}
import com.daml.lf.testing.parser.Implicits._
import com.daml.lf.transaction.{GlobalKey, GlobalKeyWithMaintainers, TransactionVersion}
import com.daml.lf.transaction.{GlobalKeyWithMaintainers, TransactionVersion}
import com.daml.lf.value.Value
import com.daml.lf.value.Value.{ContractId, ValueArithmeticError, VersionedContractInstance}
import org.scalatest.prop.TableDrivenPropertyChecks
@ -1651,6 +1651,7 @@ class SBuiltinTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChe
val (disclosedContract, None) =
buildDisclosedContract(contractId, alice, alice, templateId, withKey = false)
val cachedContract = CachedContract(
version = txVersion,
templateId,
disclosedContract.argument,
"",
@ -1694,9 +1695,13 @@ class SBuiltinTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChe
val (disclosedContract, Some((key, keyWithMaintainers, keyHash))) =
buildDisclosedContract(contractId, alice, alice, templateId, withKey = true)
val optionalKey = Some(
CachedKey(GlobalKey.assertBuild(templateId, key.toUnnormalizedValue), key, Set(alice))
CachedKey(
GlobalKeyWithMaintainers.assertBuild(templateId, key.toUnnormalizedValue, Set(alice)),
key,
)
)
val cachedContract = CachedContract(
version = txVersion,
templateId,
disclosedContract.argument,
"agreement",
@ -1813,6 +1818,8 @@ object SBuiltinTest {
"""
private val txVersion = TransactionVersion.assignNodeVersion(pkg.languageVersion)
val compiledPackages: PureCompiledPackages =
PureCompiledPackages.assertBuild(Map(defaultParserParameters.defaultPackageId -> pkg))
@ -1914,10 +1921,7 @@ object SBuiltinTest {
val globalKey =
if (withKey) {
Some(
GlobalKeyWithMaintainers(
GlobalKey.assertBuild(templateId, key.toUnnormalizedValue),
Set(maintainer),
)
GlobalKeyWithMaintainers.assertBuild(templateId, key.toUnnormalizedValue, Set(maintainer))
)
} else {
None

View File

@ -537,7 +537,7 @@ object TransactionConversionsSpec {
choiceObservers = choiceObservers,
children = children,
exerciseResult = None,
key = None,
keyOpt = None,
byKey = false,
version = TransactionVersion.VDev,
)

View File

@ -35,7 +35,7 @@ final class Adapter(
create.copy(
templateId = adapt(create.templateId),
arg = adapt(create.arg),
key = create.key.map(adapt),
keyOpt = create.keyOpt.map(adapt),
)
case exe: Node.Exercise =>
exe.copy(
@ -43,12 +43,12 @@ final class Adapter(
chosenValue = adapt(exe.chosenValue),
children = ImmArray.Empty,
exerciseResult = exe.exerciseResult.map(adapt),
key = exe.key.map(adapt),
keyOpt = exe.keyOpt.map(adapt),
)
case fetch: Node.Fetch =>
fetch.copy(
templateId = adapt(fetch.templateId),
key = fetch.key.map(adapt),
keyOpt = fetch.keyOpt.map(adapt),
)
case lookup: Node.LookupByKey =>
lookup
@ -58,20 +58,14 @@ final class Adapter(
)
}
// drop value version
private[this] def adapt(
k: Node.KeyWithMaintainers
): Node.KeyWithMaintainers =
k.copy(adapt(k.key))
def adapt(k: GlobalKeyWithMaintainers): GlobalKeyWithMaintainers =
k.copy(globalKey = adapt(k.globalKey))
def adapt(coinst: Value.VersionedContractInstance): Value.VersionedContractInstance =
coinst.map(unversioned =>
unversioned.copy(template = adapt(unversioned.template), arg = adapt(unversioned.arg))
)
def adapt(gkey: GlobalKeyWithMaintainers): GlobalKeyWithMaintainers =
GlobalKeyWithMaintainers(adapt(gkey.globalKey), gkey.maintainers)
def adapt(gkey: GlobalKey): GlobalKey =
GlobalKey.assertBuild(adapt(gkey.templateId), adapt(gkey.key))

View File

@ -11,7 +11,6 @@ import com.daml.lf.language.{Ast, LanguageVersion, Util => AstUtil}
import com.daml.lf.testing.snapshot.Snapshot.SubmissionEntry.EntryCase
import com.daml.lf.transaction.Transaction.ChildrenRecursion
import com.daml.lf.transaction.{
GlobalKey,
GlobalKeyWithMaintainers,
Node,
SubmittedTransaction => SubmittedTx,
@ -168,12 +167,7 @@ private[snapshot] object TransactionSnapshot {
cid -> create.versionedCoinst
}.toMap
val contractKeys = relevantCreateNodes.view.flatMap { case (cid, create) =>
create.key.map { case Node.KeyWithMaintainers(key, maintainers) =>
GlobalKeyWithMaintainers(
GlobalKey.assertBuild(create.templateId, key),
maintainers,
) -> cid
}.toList
create.keyOpt.map(_ -> cid).toList
}.toMap
new TransactionSnapshot(
transaction = tx,

View File

@ -106,7 +106,7 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion
argument: Value,
signatories: Set[Ref.Party],
observers: Set[Ref.Party],
key: Option[Value],
keyOpt: Option[Value],
maintainers: Set[Ref.Party],
): Node.Create = {
Node.Create(
@ -116,7 +116,8 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion
agreementText = "",
signatories = signatories,
stakeholders = signatories | observers,
key = key.map(Node.KeyWithMaintainers(_, maintainers)),
keyOpt =
keyOpt.map(key => GlobalKeyWithMaintainers.assertBuild(templateId, key, maintainers)),
version = pkgTxVersion(templateId.packageId),
)
}
@ -145,7 +146,7 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion
signatories = contract.signatories,
children = ImmArray.Empty,
exerciseResult = result,
key = contract.key,
keyOpt = contract.keyOpt,
byKey = byKey,
version = pkgTxVersion(contract.templateId.packageId),
)
@ -169,7 +170,7 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion
actingParties = contract.signatories.map(Ref.Party.assertFromString),
signatories = contract.signatories,
stakeholders = contract.stakeholders,
key = contract.key,
keyOpt = contract.keyOpt,
byKey = byKey,
version = pkgTxVersion(contract.templateId.packageId),
)
@ -180,7 +181,7 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion
def lookupByKey(contract: Node.Create, found: Boolean = true): Node.LookupByKey =
Node.LookupByKey(
templateId = contract.templateId,
key = contract.key.get,
key = contract.keyOpt.get,
result = if (found) Some(contract.coid) else None,
version = pkgTxVersion(contract.templateId.packageId),
)
@ -195,8 +196,8 @@ object TransactionBuilder {
type TxValue = value.Value.VersionedValue
type KeyWithMaintainers = Node.KeyWithMaintainers
type TxKeyWithMaintainers = Node.VersionedKeyWithMaintainers
type KeyWithMaintainers = GlobalKeyWithMaintainers
type TxKeyWithMaintainers = Versioned[GlobalKeyWithMaintainers]
def apply(
pkgLangVersion: Ref.PackageId => LanguageVersion = _ => LanguageVersion.StableVersions.max

View File

@ -8,6 +8,8 @@ package test
import com.daml.lf.data.Ref._
import com.daml.lf.data._
import com.daml.lf.transaction.{
GlobalKey,
GlobalKeyWithMaintainers,
Transaction,
Node,
NodeId,
@ -268,11 +270,13 @@ object ValueGenerators {
arg <- versionedValueGen
} yield arg.map(Value.ContractInstance(template, _))
val keyWithMaintainersGen: Gen[Node.KeyWithMaintainers] = {
def keyWithMaintainersGen(templateId: Ref.TypeConName): Gen[GlobalKeyWithMaintainers] = {
for {
key <- valueGen()
maintainers <- genNonEmptyParties
} yield Node.KeyWithMaintainers(key, maintainers)
gkey = GlobalKey.build(templateId, key).toOption
if gkey.isDefined
} yield GlobalKeyWithMaintainers(gkey.get, maintainers)
}
val versionedContraactInstanceWithAgreement: Gen[Versioned[Value.ContractInstanceWithAgreement]] =
@ -308,7 +312,7 @@ object ValueGenerators {
agreement <- Arbitrary.arbitrary[String]
signatories <- genNonEmptyParties
stakeholders <- genNonEmptyParties
key <- Gen.option(keyWithMaintainersGen)
key <- Gen.option(keyWithMaintainersGen(templateId))
} yield Node.Create(
coid = coid,
templateId = templateId,
@ -316,7 +320,7 @@ object ValueGenerators {
agreementText = agreement,
signatories = signatories,
stakeholders = stakeholders,
key = key,
keyOpt = key,
version = version,
)
@ -333,7 +337,7 @@ object ValueGenerators {
actingParties <- genNonEmptyParties
signatories <- genNonEmptyParties
stakeholders <- genNonEmptyParties
key <- Gen.option(keyWithMaintainersGen)
key <- Gen.option(keyWithMaintainersGen(templateId))
byKey <- Gen.oneOf(true, false)
} yield Node.Fetch(
coid = coid,
@ -341,7 +345,7 @@ object ValueGenerators {
actingParties = actingParties,
signatories = signatories,
stakeholders = stakeholders,
key = key,
keyOpt = key,
byKey = byKey,
version = version,
)
@ -384,7 +388,7 @@ object ValueGenerators {
.map(_.to(ImmArray))
exerciseResult <-
if (version < minExceptions) valueGen().map(Some(_)) else Gen.option(valueGen())
key <- Gen.option(keyWithMaintainersGen)
key <- Gen.option(keyWithMaintainersGen(templateId))
byKey <- Gen.oneOf(true, false)
} yield Node.Exercise(
targetCoid = targetCoid,
@ -399,7 +403,7 @@ object ValueGenerators {
choiceObservers = choiceObservers,
children = children,
exerciseResult = exerciseResult,
key = key,
keyOpt = key,
byKey = byKey,
version = version,
)
@ -409,7 +413,7 @@ object ValueGenerators {
version <- transactionVersionGen()
targetCoid <- coidGen
templateId <- idGen
key <- keyWithMaintainersGen
key <- keyWithMaintainersGen(templateId)
result <- Gen.option(targetCoid)
} yield Node.LookupByKey(
templateId,

View File

@ -144,6 +144,6 @@ final case class EngineEnrichedContractMetadata(
driverMetadata: Bytes,
signatories: Set[Party],
stakeholders: Set[Party],
maybeKeyWithMaintainers: Option[Versioned[GlobalKeyWithMaintainers]],
keyOpt: Option[Versioned[GlobalKeyWithMaintainers]],
agreementText: String,
)

View File

@ -304,9 +304,6 @@ object Hash {
.addTypedValue(key)
.build
def safeHashContractKey(templateId: Ref.Identifier, key: Value): Hash =
assertHashContractKey(templateId, key)
def hashContractKey(
templateId: Ref.Identifier,
key: Value,

View File

@ -125,7 +125,7 @@ class ContractStateMachine[Nid](mode: ContractKeyUniquenessMode) {
/** Visit a create node */
def handleCreate(node: Node.Create): Either[KeyInputError, State] =
visitCreate(node.coid, globalKeyOpt(node)).left.map(Right(_))
visitCreate(node.coid, node.gkeyOpt).left.map(Right(_))
private[lf] def visitCreate(
contractId: ContractId,
@ -164,7 +164,7 @@ class ContractStateMachine[Nid](mode: ContractKeyUniquenessMode) {
visitExercise(
nid,
exe.targetCoid,
globalKeyOpt(exe),
exe.gkeyOpt,
exe.byKey,
exe.consuming,
).left
@ -204,7 +204,7 @@ class ContractStateMachine[Nid](mode: ContractKeyUniquenessMode) {
throw new UnsupportedOperationException(
"handleLookup can only be used if all key nodes are considered"
)
visitLookup(globalKey(lookup), lookup.result, lookup.result).left.map(Left(_))
visitLookup(lookup.gkey, lookup.result, lookup.result).left.map(Left(_))
}
/** Must be used to handle lookups iff in [[com.daml.lf.transaction.ContractKeyUniquenessMode.Off]] mode
@ -226,7 +226,7 @@ class ContractStateMachine[Nid](mode: ContractKeyUniquenessMode) {
throw new UnsupportedOperationException(
"handleLookupWith can only be used if only by-key nodes are considered"
)
visitLookup(globalKey(lookup), keyInput, lookup.result).left.map(Left(_))
visitLookup(lookup.gkey, keyInput, lookup.result).left.map(Left(_))
}
private[lf] def visitLookup(
@ -274,7 +274,7 @@ class ContractStateMachine[Nid](mode: ContractKeyUniquenessMode) {
}
def handleFetch(node: Node.Fetch): Either[KeyInputError, State] =
visitFetch(node.coid, globalKeyOpt(node), node.byKey).left.map(Left(_))
visitFetch(node.coid, node.gkeyOpt, node.byKey).left.map(Left(_))
private[lf] def visitFetch(
contractId: ContractId,
@ -532,10 +532,4 @@ object ContractStateMachine {
def empty[Nid]: ActiveLedgerState[Nid] = EMPTY
}
private def globalKeyOpt(node: Node.Action) =
node.keyOpt.map(k => GlobalKey.assertBuild(node.templateId, k.key))
private def globalKey(node: Node.LookupByKey) =
GlobalKey.assertBuild(node.templateId, node.key.key)
}

View File

@ -40,7 +40,18 @@ object GlobalKey {
final case class GlobalKeyWithMaintainers(
globalKey: GlobalKey,
maintainers: Set[Ref.Party],
)
) {
def value: Value = globalKey.key
}
object GlobalKeyWithMaintainers {
def assertBuild(
templateId: Ref.TypeConName,
value: Value,
maintainers: Set[Ref.Party],
): GlobalKeyWithMaintainers =
GlobalKeyWithMaintainers(GlobalKey.assertBuild(templateId, value), maintainers)
}
/** Controls whether the engine should error out when it encounters duplicate keys.
* This is always turned on with the exception of Canton which allows turning this on or off

View File

@ -38,7 +38,12 @@ object Node {
*/
def packageIds: Iterable[PackageId]
def keyOpt: Option[KeyWithMaintainers]
def keyOpt: Option[GlobalKeyWithMaintainers]
final def gkeyOpt: Option[GlobalKey] = keyOpt.map(_.globalKey)
def versionedKeyOpt: Option[Versioned[GlobalKeyWithMaintainers]] =
keyOpt.map(Versioned(version, _))
final override protected def self: this.type = this
@ -71,21 +76,22 @@ object Node {
agreementText: String,
signatories: Set[Party],
stakeholders: Set[Party],
key: Option[KeyWithMaintainers],
keyOpt: Option[GlobalKeyWithMaintainers],
// For the sake of consistency between types with a version field, keep this field the last.
override val version: TransactionVersion,
) extends LeafOnlyAction
with ActionNodeInfo.Create {
override def byKey: Boolean = false
@deprecated("use keyOpt", since = "2.6.0")
def key: Option[GlobalKeyWithMaintainers] = keyOpt
override def keyOpt: Option[KeyWithMaintainers] = key
override def byKey: Boolean = false
override private[lf] def updateVersion(version: TransactionVersion): Node.Create =
copy(version = version)
override def mapCid(f: ContractId => ContractId): Node.Create =
copy(coid = f(coid), arg = arg.mapCid(f), key = key.map(_.mapCid(f)))
copy(coid = f(coid), arg = arg.mapCid(f))
override def packageIds: Iterable[PackageId] = Iterable(templateId.packageId)
@ -96,9 +102,7 @@ object Node {
def versionedCoinst: Value.VersionedContractInstance = versioned(coinst)
def versionedKey: Option[VersionedKeyWithMaintainers] = key.map(versioned)
def keyValue: Option[Value] = key.map(_.key)
def versionedKey: Option[Versioned[GlobalKeyWithMaintainers]] = keyOpt.map(versioned(_))
}
/** Denotes that the contract identifier `coid` needs to be active for the transaction to be valid. */
@ -108,26 +112,23 @@ object Node {
actingParties: Set[Party],
signatories: Set[Party],
stakeholders: Set[Party],
key: Option[KeyWithMaintainers],
override val keyOpt: Option[GlobalKeyWithMaintainers],
override val byKey: Boolean,
// For the sake of consistency between types with a version field, keep this field the last.
override val version: TransactionVersion,
) extends LeafOnlyAction
with ActionNodeInfo.Fetch {
override def keyOpt: Option[KeyWithMaintainers] = key
@deprecated("use keyOpt", since = "2.6.0")
def key: Option[GlobalKeyWithMaintainers] = keyOpt
override private[lf] def updateVersion(version: TransactionVersion): Node.Fetch =
copy(version = version)
override def mapCid(f: ContractId => ContractId): Node.Fetch =
copy(coid = f(coid), key = key.map(_.mapCid(f)))
copy(coid = f(coid))
override def packageIds: Iterable[PackageId] = Iterable(templateId.packageId)
def versionedKey: Option[VersionedKeyWithMaintainers] = key.map(versioned)
def keyValue: Option[Value] = key.map(_.key)
}
/** Denotes a transaction node for an exercise.
@ -148,7 +149,7 @@ object Node {
choiceObservers: Set[Party],
children: ImmArray[NodeId],
exerciseResult: Option[Value],
key: Option[KeyWithMaintainers],
keyOpt: Option[GlobalKeyWithMaintainers],
override val byKey: Boolean,
// For the sake of consistency between types with a version field, keep this field the last.
override val version: TransactionVersion,
@ -157,7 +158,8 @@ object Node {
def qualifiedChoiceName = QualifiedChoiceName(interfaceId, choiceId)
override def keyOpt: Option[KeyWithMaintainers] = key
@deprecated("use keyOpt", since = "2.6.0")
def key: Option[GlobalKeyWithMaintainers] = keyOpt
override private[lf] def updateVersion(
version: TransactionVersion
@ -168,7 +170,6 @@ object Node {
targetCoid = f(targetCoid),
chosenValue = chosenValue.mapCid(f),
exerciseResult = exerciseResult.map(_.mapCid(f)),
key = key.map(_.mapCid(f)),
)
override def mapNodeId(f: NodeId => NodeId): Node.Exercise =
@ -181,24 +182,25 @@ object Node {
def versionedExerciseResult: Option[Value.VersionedValue] = exerciseResult.map(versioned)
def versionedKey: Option[VersionedKeyWithMaintainers] = key.map(versioned)
def versionedKey: Option[Versioned[GlobalKeyWithMaintainers]] = keyOpt.map(versioned)
def keyValue: Option[Value] = key.map(_.key)
}
final case class LookupByKey(
override val templateId: TypeConName,
key: KeyWithMaintainers,
key: GlobalKeyWithMaintainers,
result: Option[ContractId],
// For the sake of consistency between types with a version field, keep this field the last.
override val version: TransactionVersion,
) extends LeafOnlyAction
with ActionNodeInfo.LookupByKey {
override def keyOpt: Some[KeyWithMaintainers] = Some(key)
override def keyOpt: Some[GlobalKeyWithMaintainers] = Some(key)
def gkey: GlobalKey = key.globalKey
override def mapCid(f: ContractId => ContractId): Node.LookupByKey =
copy(key = key.mapCid(f), result = result.map(f))
copy(result = result.map(f))
override def keyMaintainers: Set[Party] = key.maintainers
override def hasResult: Boolean = result.isDefined
@ -208,25 +210,15 @@ object Node {
copy(version = version)
override def packageIds: Iterable[PackageId] = Iterable(templateId.packageId)
def versionedKey: VersionedKeyWithMaintainers = versioned(key)
def keyValue: Value = key.key
}
final case class KeyWithMaintainers(key: Value, maintainers: Set[Party])
extends CidContainer[KeyWithMaintainers] {
@deprecated("use GlobalKey", since = "2.6.0")
type KeyWithMaintainers = GlobalKey
@deprecated("use GlobalKey", since = "2.6.0")
val KeyWithMaintainers = GlobalKey
def map(f: Value => Value): KeyWithMaintainers =
copy(key = f(key))
override protected def self: this.type = this
override def mapCid(f: ContractId => ContractId): KeyWithMaintainers =
copy(key = key.mapCid(f))
}
type VersionedKeyWithMaintainers = Versioned[KeyWithMaintainers]
@deprecated("use VersionedGlobalKey", since = "2.6.0")
type VersionedKeyWithMaintainers = VersionedGlobalKey
final case class Rollback(
children: ImmArray[NodeId]

View File

@ -28,7 +28,7 @@ class Normalization {
* longer need this separate normalization pass.
*/
private type KWM = Node.KeyWithMaintainers
private type KWM = GlobalKeyWithMaintainers
private type VTX = VersionedTransaction
def normalizeTx(vtx: VTX): VTX = {
@ -55,7 +55,7 @@ class Normalization {
case old: Node.Create =>
old
.copy(arg = normValue(old.version)(old.arg))
.copy(key = old.key.map(normKWM(old.version)))
.copy(keyOpt = old.keyOpt.map(normKWM(old.version)))
case old: Node.Fetch =>
(if (old.version >= TransactionVersion.minByKey) {
@ -64,7 +64,7 @@ class Normalization {
old.copy(byKey = false)
})
.copy(
key = old.key.map(normKWM(old.version))
keyOpt = old.keyOpt.map(normKWM(old.version))
)
case old: Node.Exercise =>
@ -76,7 +76,7 @@ class Normalization {
.copy(
chosenValue = normValue(old.version)(old.chosenValue),
exerciseResult = old.exerciseResult.map(normValue(old.version)),
key = old.key.map(normKWM(old.version)),
keyOpt = old.keyOpt.map(normKWM(old.version)),
)
case old: Node.LookupByKey =>
@ -95,8 +95,11 @@ class Normalization {
private def normKWM(version: TransactionVersion)(x: KWM): KWM = {
x match {
case Node.KeyWithMaintainers(key, maintainers) =>
Node.KeyWithMaintainers(normValue(version)(key), maintainers)
case GlobalKeyWithMaintainers(key, maintainers) =>
GlobalKeyWithMaintainers(
GlobalKey.assertBuild(key.templateId, normValue(version)(key.key)),
maintainers,
)
}
}

View File

@ -237,12 +237,12 @@ final case class Transaction(
errs
case _: Node.Fetch => errs
case nc: Node.Create =>
errs :++ f(nc.arg) :++ (nc.key match {
errs :++ f(nc.arg) :++ (nc.keyOpt match {
case None => ImmArray.Empty
case Some(key) => f(key.key)
case Some(key) => f(key.globalKey.key)
})
case ne: Node.Exercise => errs :++ f(ne.chosenValue)
case nlbk: Node.LookupByKey => errs :++ f(nlbk.key.key)
case nlbk: Node.LookupByKey => errs :++ f(nlbk.gkey.key)
}
}.toImmArray
}
@ -257,14 +257,14 @@ final case class Transaction(
z
case c: Node.Create =>
val z1 = f(z, c.arg)
val z2 = c.key match {
val z2 = c.keyOpt match {
case None => z1
case Some(k) => f(z1, k.key)
case Some(k) => f(z1, k.globalKey.key)
}
z2
case nf: Node.Fetch => nf.key.fold(z)(k => f(z, k.key))
case nf: Node.Fetch => nf.keyOpt.fold(z)(k => f(z, k.globalKey.key))
case e: Node.Exercise => f(z, e.chosenValue)
case lk: Node.LookupByKey => f(z, lk.key.key)
case lk: Node.LookupByKey => f(z, lk.gkey.key)
}
}
@ -487,17 +487,9 @@ sealed abstract class HasTxNodes {
*/
final def contractKeys: Set[GlobalKey] = {
fold(Set.empty[GlobalKey]) {
case (acc, (_, node: Node.Create)) =>
node.key.fold(acc)(key => acc + GlobalKey.assertBuild(node.templateId, key.key))
case (acc, (_, node: Node.Exercise)) =>
node.key.fold(acc)(key => acc + GlobalKey.assertBuild(node.templateId, key.key))
case (acc, (_, node: Node.Fetch)) =>
node.key.fold(acc)(key => acc + GlobalKey.assertBuild(node.templateId, key.key))
case (acc, (_, node: Node.LookupByKey)) =>
acc + GlobalKey.assertBuild(node.templateId, node.key.key)
case (acc, (_, _: Node.Authority)) =>
acc
case (acc, (_, _: Node.Rollback)) =>
case (acc, (_, node: Node.Action)) =>
node.gkeyOpt.fold(acc)(acc + _)
case (acc, (_, (_: Node.Authority | _: Node.Rollback))) =>
acc
}
}
@ -570,9 +562,7 @@ sealed abstract class HasTxNodes {
exerciseBegin = {
case (acc, _, exec) if exec.consuming =>
(
exec.key.fold(acc)(key =>
acc.updated(GlobalKey.assertBuild(exec.templateId, key.key), None)
),
exec.gkeyOpt.fold(acc)(acc.updated(_, None)),
ChildrenRecursion.DoRecurse,
)
case (acc, _, _) => (acc, ChildrenRecursion.DoRecurse)
@ -580,9 +570,7 @@ sealed abstract class HasTxNodes {
rollbackBegin = (acc, _, _) => (acc, ChildrenRecursion.DoNotRecurse),
leaf = {
case (acc, _, create: Node.Create) =>
create.key.fold(acc)(key =>
acc.updated(GlobalKey.assertBuild(create.templateId, key.key), Some(create.coid))
)
create.gkeyOpt.fold(acc)(acc.updated(_, Some(create.coid)))
case (acc, _, _: Node.Fetch | _: Node.LookupByKey) => acc
},
exerciseEnd = (acc, _, _) => acc,

View File

@ -181,9 +181,8 @@ object TransactionCoder {
)
private[this] def encodeKeyWithMaintainers(
encodeCid: ValueCoder.EncodeCid,
version: TransactionVersion,
key: Node.KeyWithMaintainers,
key: GlobalKeyWithMaintainers,
): Either[EncodeError, TransactionOuterClass.KeyWithMaintainers] = {
val builder =
TransactionOuterClass.KeyWithMaintainers
@ -191,24 +190,23 @@ object TransactionCoder {
.addAllMaintainers(key.maintainers.toSet[String].asJava)
if (version < TransactionVersion.minNoVersionValue) {
ValueCoder
.encodeVersionedValue(encodeCid, version, key.key)
.encodeVersionedValue(ValueCoder.UnsafeNoCidEncoder, version, key.value)
.map(builder.setKeyVersioned(_).build())
} else {
ValueCoder
.encodeValue(encodeCid, version, key.key)
.encodeValue(ValueCoder.UnsafeNoCidEncoder, version, key.value)
.map(builder.setKeyUnversioned(_).build())
}
}
private[this] def encodeAndSetContractKey(
encodeCid: ValueCoder.EncodeCid,
version: TransactionVersion,
key: Option[Node.KeyWithMaintainers],
key: Option[GlobalKeyWithMaintainers],
setKey: TransactionOuterClass.KeyWithMaintainers => GeneratedMessageV3.Builder[_],
) = {
key match {
case Some(key) =>
encodeKeyWithMaintainers(encodeCid, version, key).map(k => discard(setKey(k)))
encodeKeyWithMaintainers(version, key).map(k => discard(setKey(k)))
case None =>
Right(())
}
@ -303,9 +301,8 @@ object TransactionCoder {
)
}
_ <- encodeAndSetContractKey(
encodeCid,
nodeVersion,
nc.key,
nc.keyOpt,
builder.setKeyWithMaintainers,
)
} yield nodeBuilder.setCreate(builder).build()
@ -322,9 +319,8 @@ object TransactionCoder {
nf.actingParties.foreach(builder.addActors)
for {
_ <- encodeAndSetContractKey(
encodeCid,
nodeVersion,
nf.key,
nf.keyOpt,
builder.setKeyWithMaintainers,
)
} yield nodeBuilder.setFetch(builder).build()
@ -382,9 +378,8 @@ object TransactionCoder {
)
}
_ <- encodeAndSetContractKey(
encodeCid,
nodeVersion,
ne.key,
ne.keyOpt,
builder.setKeyWithMaintainers,
)
} yield nodeBuilder.setExercise(builder).build()
@ -396,7 +391,7 @@ object TransactionCoder {
discard(builder.setContractIdStruct(encodeCid.encode(cid)))
)
for {
encodedKey <- encodeKeyWithMaintainers(encodeCid, nlbk.version, nlbk.key)
encodedKey <- encodeKeyWithMaintainers(nlbk.version, nlbk.key)
} yield {
discard(builder.setKeyWithMaintainers(encodedKey))
nodeBuilder.setLookupByKey(builder).build()
@ -407,42 +402,33 @@ object TransactionCoder {
}
private[this] def decodeKeyWithMaintainers(
decodeCid: ValueCoder.DecodeCid,
version: TransactionVersion,
templateId: Ref.TypeConName,
keyWithMaintainers: TransactionOuterClass.KeyWithMaintainers,
): Either[DecodeError, Node.KeyWithMaintainers] = {
): Either[DecodeError, GlobalKeyWithMaintainers] = {
for {
maintainers <- toPartySet(keyWithMaintainers.getMaintainersList)
key <- decodeValue(
decodeCid,
value <- decodeValue(
ValueCoder.NoCidDecoder,
version,
keyWithMaintainers.getKeyVersioned,
keyWithMaintainers.getKeyUnversioned,
)
} yield Node.KeyWithMaintainers(key, maintainers)
gkey <- GlobalKey.build(templateId, value).left.map(DecodeError)
} yield GlobalKeyWithMaintainers(gkey, maintainers)
}
private val RightNone = Right(None)
private[this] def decodeOptionalKeyWithMaintainers(
decodeCid: ValueCoder.DecodeCid,
version: TransactionVersion,
templateId: Ref.TypeConName,
keyWithMaintainers: TransactionOuterClass.KeyWithMaintainers,
): Either[DecodeError, Option[Node.KeyWithMaintainers]] = {
if (keyWithMaintainers == TransactionOuterClass.KeyWithMaintainers.getDefaultInstance) {
): Either[DecodeError, Option[GlobalKeyWithMaintainers]] =
if (keyWithMaintainers == TransactionOuterClass.KeyWithMaintainers.getDefaultInstance)
RightNone
} else {
for {
maintainers <- toPartySet(keyWithMaintainers.getMaintainersList)
key <- decodeValue(
decodeCid,
version,
keyWithMaintainers.getKeyVersioned,
keyWithMaintainers.getKeyUnversioned,
)
} yield Some(Node.KeyWithMaintainers(key, maintainers))
}
}
else
decodeKeyWithMaintainers(version, templateId, keyWithMaintainers).map(Some(_))
// package private for test, do not use outside TransactionCoder
private[lf] def decodeValue(
@ -520,9 +506,9 @@ object TransactionCoder {
Value.ContractInstanceWithAgreement(ci, agreementText) = entry
stakeholders <- toPartySet(protoCreate.getStakeholdersList)
signatories <- toPartySet(protoCreate.getSignatoriesList)
key <- decodeOptionalKeyWithMaintainers(
decodeCid,
keyOpt <- decodeOptionalKeyWithMaintainers(
nodeVersion,
ci.template,
protoCreate.getKeyWithMaintainers,
)
} yield ni -> Node.Create(
@ -532,7 +518,7 @@ object TransactionCoder {
agreementText = agreementText,
signatories = signatories,
stakeholders = stakeholders,
key = key,
keyOpt = keyOpt,
version = nodeVersion,
)
case NodeTypeCase.FETCH =>
@ -544,9 +530,9 @@ object TransactionCoder {
actingParties <- toPartySet(protoFetch.getActorsList)
stakeholders <- toPartySet(protoFetch.getStakeholdersList)
signatories <- toPartySet(protoFetch.getSignatoriesList)
key <- decodeOptionalKeyWithMaintainers(
decodeCid,
keyOpt <- decodeOptionalKeyWithMaintainers(
nodeVersion,
templateId,
protoFetch.getKeyWithMaintainers,
)
byKey =
@ -559,7 +545,7 @@ object TransactionCoder {
actingParties = actingParties,
signatories = signatories,
stakeholders = stakeholders,
key = key,
keyOpt = keyOpt,
byKey = byKey,
version = nodeVersion,
)
@ -567,6 +553,7 @@ object TransactionCoder {
case NodeTypeCase.EXERCISE =>
val protoExe = protoNode.getExercise
for {
templateId <- ValueCoder.decodeIdentifier(protoExe.getTemplateId)
rvOpt <-
if (!protoExe.hasResultVersioned && protoExe.getResultUnversioned.isEmpty) {
Either.cond(
@ -585,7 +572,11 @@ object TransactionCoder {
).map(v => Some(v))
}
keyWithMaintainers <-
decodeOptionalKeyWithMaintainers(decodeCid, nodeVersion, protoExe.getKeyWithMaintainers)
decodeOptionalKeyWithMaintainers(
nodeVersion,
templateId,
protoExe.getKeyWithMaintainers,
)
ni <- nodeId
targetCoid <- decodeCid.decode(protoExe.getContractIdStruct)
children <- decodeChildren(decodeNid, protoExe.getChildrenList)
@ -595,7 +586,6 @@ object TransactionCoder {
protoExe.getArgVersioned,
protoExe.getArgUnversioned,
)
templateId <- ValueCoder.decodeIdentifier(protoExe.getTemplateId)
actingParties <- toPartySet(protoExe.getActorsList)
signatories <- toPartySet(protoExe.getSignatoriesList)
stakeholders <- toPartySet(protoExe.getStakeholdersList)
@ -629,7 +619,7 @@ object TransactionCoder {
choiceObservers = choiceObservers,
children = children,
exerciseResult = rvOpt,
key = keyWithMaintainers,
keyOpt = keyWithMaintainers,
byKey = byKey,
version = nodeVersion,
)
@ -639,7 +629,11 @@ object TransactionCoder {
ni <- nodeId
templateId <- ValueCoder.decodeIdentifier(protoLookupByKey.getTemplateId)
key <-
decodeKeyWithMaintainers(decodeCid, nodeVersion, protoLookupByKey.getKeyWithMaintainers)
decodeKeyWithMaintainers(
nodeVersion,
templateId,
protoLookupByKey.getKeyWithMaintainers,
)
cid <- decodeCid.decodeOptional(protoLookupByKey.getContractIdStruct)
} yield ni -> Node.LookupByKey(templateId, key, cid, nodeVersion)
case NodeTypeCase.NODETYPE_NOT_SET => Left(DecodeError("Unset Node type"))

View File

@ -88,15 +88,17 @@ object Util {
.map(normalized => contract.map(_.copy(arg = normalized)))
def normalizeKey(
key: Node.KeyWithMaintainers,
key: GlobalKeyWithMaintainers,
version: TransactionVersion,
): Either[String, Node.KeyWithMaintainers] =
normalizeValue(key.key, version).map(normalized => key.copy(key = normalized))
): Either[String, GlobalKeyWithMaintainers] =
normalizeValue(key.globalKey.key, version).map(normalized =>
key.copy(globalKey = GlobalKey.assertBuild(key.globalKey.templateId, normalized))
)
def normalizeOptKey(
key: Option[Node.KeyWithMaintainers],
key: Option[GlobalKeyWithMaintainers],
version: TransactionVersion,
): Either[String, Option[Node.KeyWithMaintainers]] =
): Either[String, Option[GlobalKeyWithMaintainers]] =
key match {
case Some(value) => normalizeKey(value, version).map(Some(_))
case None => Right(None)

View File

@ -30,4 +30,6 @@ package object transaction {
val CommittedTransaction = DiscriminatedSubtype[VersionedTransaction]
type CommittedTransaction = CommittedTransaction.T
type VersionedGlobalKey = Versioned[GlobalKey]
}

View File

@ -10,6 +10,7 @@ import com.daml.lf.data._
import com.daml.lf.transaction.{TransactionVersion, Versioned}
import com.daml.lf.value.Value._
import com.daml.lf.value.{ValueOuterClass => proto}
import com.daml.nameof.NameOf
import com.daml.scalautil.Statement.discard
import com.google.protobuf
import com.google.protobuf.{ByteString, CodedInputStream}
@ -90,6 +91,12 @@ object ValueCoder {
override def decodeOptional(structForm: ValueOuterClass.ContractId) = Right(None)
}
// To be use only when certain the value does not contain Contract Ids
val UnsafeNoCidEncoder: EncodeCid = new EncodeCid {
override private[lf] def encode(contractId: ContractId) =
InternalError.runtimeException(NameOf.qualifiedNameOfCurrentFunc, "unexpected contract ID")
}
/** Simple encoding to wire of identifiers
* @param id identifier value
* @return wire format identifier

View File

@ -14,7 +14,6 @@ import com.daml.lf.transaction.ContractStateMachine.{
KeyResolver,
}
import com.daml.lf.transaction.ContractStateMachineSpec._
import com.daml.lf.transaction.Node.KeyWithMaintainers
import com.daml.lf.transaction.Transaction.{
ChildrenRecursion,
DuplicateContractKey,
@ -60,8 +59,18 @@ class ContractStateMachineSpec extends AnyWordSpec with Matchers with TableDrive
ContractId.V1(hash)
}
private def toKeyWithMaintainers(key: String): Option[KeyWithMaintainers] =
if (key.isEmpty) None else Some(Node.KeyWithMaintainers(Value.ValueText(key), aliceS))
private def toKeyWithMaintainers(
templateId: Ref.TypeConName,
key: String,
): GlobalKeyWithMaintainers =
GlobalKeyWithMaintainers.assertBuild(templateId, Value.ValueText(key), aliceS)
private def toOptKeyWithMaintainers(
templateId: Ref.TypeConName,
key: String,
): Option[GlobalKeyWithMaintainers] =
if (key.isEmpty) None
else Some(toKeyWithMaintainers(templateId, key))
def gkey(key: String): GlobalKey =
GlobalKey.assertBuild(templateId, Value.ValueText(key))
@ -77,7 +86,7 @@ class ContractStateMachineSpec extends AnyWordSpec with Matchers with TableDrive
agreementText = "",
signatories = aliceS,
stakeholders = aliceS,
key = toKeyWithMaintainers(key),
keyOpt = toOptKeyWithMaintainers(templateId, key),
version = txVersion,
)
@ -100,7 +109,7 @@ class ContractStateMachineSpec extends AnyWordSpec with Matchers with TableDrive
choiceObservers = Set.empty,
children = ImmArray.Empty,
exerciseResult = None,
key = toKeyWithMaintainers(key),
keyOpt = toOptKeyWithMaintainers(templateId, key),
byKey = byKey,
version = txVersion,
)
@ -117,7 +126,7 @@ class ContractStateMachineSpec extends AnyWordSpec with Matchers with TableDrive
actingParties = aliceS,
signatories = aliceS,
stakeholders = aliceS,
key = toKeyWithMaintainers(key),
keyOpt = toOptKeyWithMaintainers(templateId, key),
byKey = byKey,
version = txVersion,
)
@ -129,7 +138,7 @@ class ContractStateMachineSpec extends AnyWordSpec with Matchers with TableDrive
): Node.LookupByKey =
Node.LookupByKey(
templateId = templateId,
key = Node.KeyWithMaintainers(Value.ValueText(key), aliceS),
key = toKeyWithMaintainers(templateId, key),
result = contractId,
version = txVersion,
)
@ -655,9 +664,7 @@ class ContractStateMachineSpec extends AnyWordSpec with Matchers with TableDrive
case _: Node.Authority =>
??? // TODO #15882 -- treat like exercise with no keys. recurse directly on children
case actionNode: Node.Action =>
lazy val gkeyO =
actionNode.keyOpt.map(key => GlobalKey.assertBuild(actionNode.templateId, key.key))
state.handleNode((), actionNode, gkeyO.flatMap(resolver))
state.handleNode((), actionNode, actionNode.gkeyOpt.flatMap(resolver))
case _: Node.Rollback =>
Right(state.beginRollback())
}
@ -736,25 +743,24 @@ object ContractStateMachineSpec {
def resolverFromTx(tx: HasTxNodes): KeyResolver = {
def updateKey(
resolver: KeyResolver,
templateId: Ref.TypeConName,
mbKey: Option[KeyWithMaintainers],
mbKey: Option[GlobalKey],
mapping: KeyMapping,
): KeyResolver = mbKey.fold(resolver) { key =>
val gkey = GlobalKey.assertBuild(templateId, key.key)
): KeyResolver = mbKey.fold(resolver) { gkey =>
if (resolver.contains(gkey)) resolver else resolver.updated(gkey, mapping)
}
tx.foldInExecutionOrder(Map.empty: KeyResolver)(
exerciseBegin = (s, _, ex) =>
updateKey(s, ex.templateId, ex.key, KeyActive(ex.targetCoid)) ->
updateKey(s, ex.gkeyOpt, KeyActive(ex.targetCoid)) ->
ChildrenRecursion.DoRecurse,
exerciseEnd = (s, _, _) => s,
leaf = (s, _, leaf) =>
leaf match {
case create: Node.Create => updateKey(s, create.templateId, create.key, KeyInactive)
case fetch: Node.Fetch => updateKey(s, fetch.templateId, fetch.key, KeyActive(fetch.coid))
case create: Node.Create => updateKey(s, create.gkeyOpt, KeyInactive)
case fetch: Node.Fetch =>
updateKey(s, fetch.gkeyOpt, KeyActive(fetch.coid))
case lookup: Node.LookupByKey =>
updateKey(s, lookup.templateId, Some(lookup.key), lookup.result)
updateKey(s, Some(lookup.gkey), lookup.result)
},
rollbackBegin = (s, _, _) => s -> ChildrenRecursion.DoRecurse,
rollbackEnd = (s, _, _) => s,

View File

@ -232,7 +232,7 @@ class TransactionCoderSpec
agreementText = "agreement",
signatories = Set(Party.assertFromString("alice")),
stakeholders = Set(Party.assertFromString("alice"), Party.assertFromString("bob")),
key = None,
keyOpt = None,
version = TransactionVersion.minVersion,
)
@ -410,7 +410,7 @@ class TransactionCoderSpec
"fail if try to encode a fetch node containing value with version different from node" in {
forAll(fetchNodeGen, transactionVersionGen(), minSuccessful(5)) { (node, version) =>
whenever(node.version != version && node.key.isDefined) {
whenever(node.version != version && node.keyOpt.isDefined) {
val nodeVersion = node.version
val encodeVersion = ValueCoder.encodeValueVersion(version)
val Right(encodedNode) = TransactionCoder.encodeNode(
@ -845,13 +845,13 @@ class TransactionCoderSpec
}
def withoutContractKeyInExercise(gn: Node): Node =
gn match {
case ne: Node.Exercise => ne copy (key = None)
case ne: Node.Exercise => ne copy (keyOpt = None)
case _ => gn
}
def withoutMaintainersInExercise(gn: Node): Node =
gn match {
case ne: Node.Exercise =>
ne copy (key = ne.key.map(_.copy(maintainers = Set.empty)))
ne copy (keyOpt = ne.keyOpt.map(_.copy(maintainers = Set.empty)))
case _ => gn
}
@ -908,13 +908,13 @@ class TransactionCoderSpec
): Node.Create = {
create.copy(
arg = normalize(create.arg, create.version),
key = create.key.map(normalizeKey(_, create.version)),
keyOpt = create.keyOpt.map(normalizeKey(_, create.version)),
)
}
private[this] def normalizeFetch(fetch: Node.Fetch) =
fetch.copy(
key = fetch.key.map(normalizeKey(_, fetch.version)),
keyOpt = fetch.keyOpt.map(normalizeKey(_, fetch.version)),
byKey =
if (fetch.version >= TransactionVersion.minByKey)
fetch.byKey
@ -940,7 +940,7 @@ class TransactionCoderSpec
},
choiceObservers =
exe.choiceObservers.filter(_ => exe.version >= TransactionVersion.minChoiceObservers),
key = exe.key.map(normalizeKey(_, exe.version)),
keyOpt = exe.keyOpt.map(normalizeKey(_, exe.version)),
byKey =
if (exe.version >= TransactionVersion.minByKey)
exe.byKey
@ -948,11 +948,12 @@ class TransactionCoderSpec
)
private[this] def normalizeKey(
key: Node.KeyWithMaintainers,
key: GlobalKeyWithMaintainers,
version: TransactionVersion,
) = {
key.copy(key = normalize(key.key, version))
}
) =
key.copy(globalKey =
GlobalKey.assertBuild(key.globalKey.templateId, normalize(key.value, version))
)
private[this] def normalizeContract(contract: Versioned[Value.ContractInstanceWithAgreement]) =
contract.map(

View File

@ -59,7 +59,7 @@ class TransactionNodeStatisticsSpec
argument = Value.ValueUnit,
signatories = parties,
observers = Set.empty,
key = if (withKey) Some(Value.ValueUnit) else None,
keyOpt = if (withKey) Some(Value.ValueUnit) else None,
maintainers = if (withKey) parties else Set.empty,
)
}

View File

@ -559,9 +559,10 @@ class TransactionSpec
val builder = TransactionBuilder()
val create0 = create(cid("#0"))
val create1 = create(cid("#1")).copy(
key = Some(
Node.KeyWithMaintainers(
key = keyValue(cid("#0").coid),
keyOpt = Some(
GlobalKeyWithMaintainers.assertBuild(
templateId = "Mod:T",
value = keyValue(cid("#0").coid),
maintainers = Set.empty,
)
)
@ -1043,7 +1044,7 @@ object TransactionSpec {
choiceObservers = Set.empty,
children = children,
exerciseResult = if (hasExerciseResult) Some(V.ValueUnit) else None,
key = None,
keyOpt = None,
byKey = false,
version = TransactionVersion.minVersion,
)
@ -1056,7 +1057,7 @@ object TransactionSpec {
agreementText = "dummyAgreement",
signatories = Set.empty,
stakeholders = Set.empty,
key = None,
keyOpt = None,
version = TransactionVersion.minVersion,
)

View File

@ -44,7 +44,7 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC
// --[types]--
private type Val = V
private type KWM = Node.KeyWithMaintainers
private type KWM = GlobalKeyWithMaintainers
private type OKWM = Option[KWM]
private type Exe = Node.Exercise
private type VTX = VersionedTransaction
@ -75,11 +75,14 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC
private val samParties4: Set[Party] = Set(samParty1, samParty2)
private val samValue1: Val = V.ValueUnit
private val samValue2: Val = V.ValueContractId(samContractId1)
private val samValue2: Val = V.ValueText(samContractId1.coid)
private val samKWM1 = Node.KeyWithMaintainers(samValue1, samParties1)
private val samKWM2 = Node.KeyWithMaintainers(samValue1, samParties2)
private val samKWM3 = Node.KeyWithMaintainers(samValue2, samParties1)
private val samKWM1 =
GlobalKeyWithMaintainers.assertBuild(samTemplateId1, samValue1, samParties1)
private val samKWM2 =
GlobalKeyWithMaintainers.assertBuild(samTemplateId1, samValue1, samParties2)
private val samKWM3 =
GlobalKeyWithMaintainers.assertBuild(samTemplateId2, samValue2, samParties1)
private val samVersion1: TransactionVersion = TransactionVersion.minVersion
private val samVersion2: TransactionVersion = TransactionVersion.maxVersion
@ -95,7 +98,7 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC
agreementText = samText1,
signatories = samParties1,
stakeholders = samParties2,
key = key,
keyOpt = key,
version = version,
)
@ -110,7 +113,7 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC
actingParties = actingParties,
signatories = samParties2,
stakeholders = samParties3,
key = key,
keyOpt = key,
byKey = samBool1,
version = version,
)
@ -146,7 +149,7 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC
choiceObservers = samParties4,
children = ImmArray.Empty,
exerciseResult = exerciseResult,
key = key,
keyOpt = key,
byKey = samBool2,
version = version,
)
@ -267,7 +270,7 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC
}
private def tweakCreateKey(tweakOptKeyMaintainers: Tweak[OKWM]) = Tweak[Node] {
case nc: Node.Create =>
tweakOptKeyMaintainers.run(nc.key).map { x => nc.copy(key = x) }
tweakOptKeyMaintainers.run(nc.keyOpt).map { x => nc.copy(keyOpt = x) }
}
private val tweakCreateVersion = Tweak.single[Node] { case nc: Node.Create =>
nc.copy(version = changeVersion(nc.version))
@ -304,7 +307,7 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC
}
private def tweakFetchKey(tweakOptKeyMaintainers: Tweak[OKWM]) = Tweak[Node] {
case nf: Node.Fetch =>
tweakOptKeyMaintainers.run(nf.key).map { x => nf.copy(key = x) }
tweakOptKeyMaintainers.run(nf.keyOpt).map { x => nf.copy(keyOpt = x) }
}
private def tweakFetchByKey(whenVersion: TransactionVersion => Boolean) = Tweak.single[Node] {
case nf: Node.Fetch if whenVersion(nf.version) =>
@ -391,7 +394,7 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC
private def tweakExerciseKey(tweakOptKeyMaintainers: Tweak[OKWM]) = Tweak[Node] {
case ne: Node.Exercise =>
tweakOptKeyMaintainers.run(ne.key).map { x => ne.copy(key = x) }
tweakOptKeyMaintainers.run(ne.keyOpt).map { x => ne.copy(keyOpt = x) }
}
private def tweakExerciseByKey(whenVersion: TransactionVersion => Boolean) = Tweak.single[Node] {
case ne: Node.Exercise if whenVersion(ne.version) =>

View File

@ -12,7 +12,7 @@ import com.daml.lf.data.LawlessTraversals._
import com.daml.lf.data.Ref.Identifier
import com.daml.lf.data.{Numeric, Ref}
import com.daml.lf.ledger.EventId
import com.daml.lf.transaction.{Node, NodeId}
import com.daml.lf.transaction.{GlobalKeyWithMaintainers, Node, NodeId}
import com.daml.lf.value.{Value => Lf}
import com.google.protobuf.empty.Empty
import com.google.protobuf.timestamp.Timestamp
@ -173,13 +173,13 @@ object LfEngineToApi {
def lfContractKeyToApiValue(
verbose: Boolean,
lf: Node.KeyWithMaintainers,
lf: GlobalKeyWithMaintainers,
): Either[String, api.Value] =
lfValueToApiValue(verbose, lf.key)
lfValueToApiValue(verbose, lf.value)
def lfContractKeyToApiValue(
verbose: Boolean,
lf: Option[Node.KeyWithMaintainers],
lf: Option[GlobalKeyWithMaintainers],
): Either[String, Option[api.Value]] =
lf.fold[Either[String, Option[api.Value]]](Right(None))(
lfContractKeyToApiValue(verbose, _).map(Some(_))
@ -193,7 +193,7 @@ object LfEngineToApi {
): Either[String, Event] =
for {
arg <- lfValueToApiRecord(verbose, node.arg)
key <- lfContractKeyToApiValue(verbose, node.key)
key <- lfContractKeyToApiValue(verbose, node.keyOpt)
} yield Event(
Event.Event.Created(
CreatedEvent(
@ -238,7 +238,7 @@ object LfEngineToApi {
): Either[String, TreeEvent] =
for {
arg <- lfValueToApiRecord(verbose, node.arg)
key <- lfContractKeyToApiValue(verbose, node.key)
key <- lfContractKeyToApiValue(verbose, node.keyOpt)
} yield TreeEvent(
TreeEvent.Kind.Created(
CreatedEvent(

View File

@ -11,7 +11,6 @@ import com.daml.ledger.api.DeduplicationPeriod.{DeduplicationDuration, Deduplica
import com.daml.ledger.offset.Offset
import com.daml.ledger.participant.state.v2.{CompletionInfo, Update}
import com.daml.ledger.resources.ResourceOwner
import com.daml.lf.crypto.Hash
import com.daml.lf.data.Ref.HexString
import com.daml.lf.engine.Blinding
import com.daml.lf.ledger.EventId
@ -250,7 +249,7 @@ private[platform] object InMemoryStateUpdater {
commandId = txAccepted.optCompletionInfo.map(_.commandId).getOrElse(""),
workflowId = txAccepted.transactionMeta.workflowId.getOrElse(""),
contractKey =
create.key.map(k => com.daml.lf.transaction.Versioned(create.version, k.key)),
create.keyOpt.map(k => com.daml.lf.transaction.Versioned(create.version, k.value)),
treeEventWitnesses = blinding.disclosure.getOrElse(nodeId, Set.empty),
flatEventWitnesses = create.stakeholders,
submitters = txAccepted.optCompletionInfo
@ -260,7 +259,7 @@ private[platform] object InMemoryStateUpdater {
createSignatories = create.signatories,
createObservers = create.stakeholders.diff(create.signatories),
createAgreementText = Some(create.agreementText).filter(_.nonEmpty),
createKeyHash = create.key.map(_.key).map(Hash.safeHashContractKey(create.templateId, _)),
createKeyHash = create.keyOpt.map(_.globalKey.hash),
driverMetadata = txAccepted.contractMetadata.get(create.coid),
)
case (nodeId, exercise: Exercise) =>
@ -276,7 +275,7 @@ private[platform] object InMemoryStateUpdater {
commandId = txAccepted.optCompletionInfo.map(_.commandId).getOrElse(""),
workflowId = txAccepted.transactionMeta.workflowId.getOrElse(""),
contractKey =
exercise.key.map(k => com.daml.lf.transaction.Versioned(exercise.version, k.key)),
exercise.keyOpt.map(k => com.daml.lf.transaction.Versioned(exercise.version, k.value)),
treeEventWitnesses = blinding.disclosure.getOrElse(nodeId, Set.empty),
flatEventWitnesses = if (exercise.consuming) exercise.stakeholders else Set.empty,
submitters = txAccepted.optCompletionInfo

View File

@ -234,8 +234,7 @@ object UpdateToDbDto {
create_agreement_text = Some(create.agreementText).filter(_.nonEmpty),
create_key_value = createKeyValue
.map(compressionStrategy.createKeyValueCompression.compress),
create_key_hash = create.key
.map(key => Key.assertBuild(create.templateId, key.key).hash.bytes.toHexString),
create_key_hash = create.keyOpt.map(_.globalKey.hash.bytes.toHexString),
create_argument_compression = compressionStrategy.createArgumentCompression.id,
create_key_value_compression =
compressionStrategy.createKeyValueCompression.id.filter(_ =>

View File

@ -123,7 +123,7 @@ final class LfValueTranslation(
private def serializeNullableKeyOrThrow(c: Create): Option[Array[Byte]] =
c.versionedKey.map(k =>
ValueSerializer.serializeValue(
value = k.map(_.key),
value = k.map(_.value),
errorContext = cantSerialize(attribute = "key", forContract = c.coid),
)
)
@ -131,7 +131,7 @@ final class LfValueTranslation(
private def serializeNullableKeyOrThrow(e: Exercise): Option[Array[Byte]] = {
e.versionedKey.map(k =>
ValueSerializer.serializeValue(
value = k.map(_.key),
value = k.map(_.value),
errorContext = cantSerialize(attribute = "key", forContract = e.targetCoid),
)
)

View File

@ -3,8 +3,7 @@
package com.daml.platform.store.dao
import com.daml.lf.transaction.GlobalKey
import com.daml.lf.transaction.Node.KeyWithMaintainers
import com.daml.lf.transaction.GlobalKeyWithMaintainers
import com.daml.lf.value.Value.{ValueText, VersionedContractInstance}
import com.daml.platform.store.interfaces.LedgerDaoContractsReader
import org.scalatest.flatspec.AsyncFlatSpec
@ -146,21 +145,28 @@ private[dao] trait JdbcLedgerDaoContractsSpec extends LoneElement with Inside wi
it should "present the contract key state at a specific event sequential id" in {
val aTextValue = ValueText(scala.util.Random.nextString(10))
val key = GlobalKeyWithMaintainers.assertBuild(someTemplateId, aTextValue, Set(alice, bob))
for {
(_, tx) <- createAndStoreContract(
submittingParties = Set(alice),
signatories = Set(alice, bob),
stakeholders = Set(alice, bob),
key = Some(KeyWithMaintainers(aTextValue, Set(alice, bob))),
key = Some(key),
)
key = GlobalKey.assertBuild(someTemplateId, aTextValue)
contractId = nonTransient(tx).loneElement
_ <- store(singleNonConsumingExercise(contractId))
ledgerEndAtCreate <- ledgerDao.lookupLedgerEnd()
_ <- store(txArchiveContract(alice, (contractId, None)))
ledgerEndAfterArchive <- ledgerDao.lookupLedgerEnd()
queryAfterCreate <- contractsReader.lookupKeyState(key, ledgerEndAtCreate.lastOffset)
queryAfterArchive <- contractsReader.lookupKeyState(key, ledgerEndAfterArchive.lastOffset)
queryAfterCreate <- contractsReader.lookupKeyState(
key.globalKey,
ledgerEndAtCreate.lastOffset,
)
queryAfterArchive <- contractsReader.lookupKeyState(
key.globalKey,
ledgerEndAfterArchive.lastOffset,
)
} yield {
queryAfterCreate match {
case LedgerDaoContractsReader.KeyAssigned(fetchedContractId, stakeholders) =>

View File

@ -7,8 +7,7 @@ import java.util.UUID
import com.daml.lf.data.{ImmArray, Ref}
import com.daml.lf.data.Time.Timestamp
import com.daml.lf.transaction.Node
import com.daml.lf.transaction.TransactionVersion
import com.daml.lf.transaction.{GlobalKeyWithMaintainers, Node, TransactionVersion}
import com.daml.lf.transaction.test.TransactionBuilder
import com.daml.lf.value.Value.{ValueParty, VersionedContractInstance}
import com.daml.platform.store.entries.LedgerEntry
@ -33,7 +32,7 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
agreementText = someAgreement,
signatories = Set(alice),
stakeholders = Set(alice),
key = None,
keyOpt = None,
version = TransactionVersion.minVersion,
)
)
@ -50,8 +49,9 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
someAgreement,
signatories = Set(bob),
stakeholders = Set(bob),
key = Some(
Node.KeyWithMaintainers(someContractKey(bob, "some key"), Set(bob))
keyOpt = Some(
GlobalKeyWithMaintainers
.assertBuild(someTemplateId, someContractKey(bob, "some key"), Set(bob))
),
version = TransactionVersion.minVersion,
)
@ -74,7 +74,7 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
choiceObservers = Set.empty,
children = ImmArray.Empty,
exerciseResult = Some(someChoiceResult),
key = None,
keyOpt = None,
byKey = false,
version = TransactionVersion.minVersion,
)
@ -86,8 +86,8 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
actingParties = Set(bob),
signatories = Set(bob),
stakeholders = Set(bob),
key = Some(
Node.KeyWithMaintainers(ValueParty(bob), Set(bob))
keyOpt = Some(
GlobalKeyWithMaintainers.assertBuild(someTemplateId, ValueParty(bob), Set(bob))
),
byKey = false,
version = TransactionVersion.minVersion,
@ -108,8 +108,9 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
choiceObservers = Set.empty,
children = ImmArray.Empty,
exerciseResult = Some(someChoiceResult),
key = Some(
Node.KeyWithMaintainers(someContractKey(bob, "some key"), Set(bob))
keyOpt = Some(
GlobalKeyWithMaintainers
.assertBuild(someTemplateId, someContractKey(bob, "some key"), Set(bob))
),
byKey = false,
version = TransactionVersion.minVersion,
@ -124,8 +125,9 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside {
someAgreement,
signatories = Set(bob),
stakeholders = Set(alice, bob),
key = Some(
Node.KeyWithMaintainers(someContractKey(bob, "some key"), Set(bob))
keyOpt = Some(
GlobalKeyWithMaintainers
.assertBuild(someTemplateId, someContractKey(bob, "some key"), Set(bob))
),
version = TransactionVersion.minVersion,
),

View File

@ -208,7 +208,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
absCid: ContractId,
signatories: Set[Party],
stakeholders: Set[Party],
key: Option[Node.KeyWithMaintainers] = None,
key: Option[GlobalKeyWithMaintainers] = None,
templateId: Identifier = someTemplateId,
contractArgument: LfValue = someContractArgument,
): Node.Create =
@ -219,13 +219,13 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
agreementText = someAgreement,
signatories = signatories,
stakeholders = stakeholders,
key = key,
keyOpt = key,
version = txVersion,
)
protected final def exerciseNode(
targetCid: ContractId,
key: Option[Node.KeyWithMaintainers] = None,
key: Option[GlobalKeyWithMaintainers] = None,
): Node.Exercise =
Node.Exercise(
targetCoid = targetCid,
@ -240,7 +240,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
choiceObservers = Set.empty,
children = ImmArray.Empty,
exerciseResult = Some(someChoiceResult),
key = key,
keyOpt = key,
byKey = false,
version = txVersion,
)
@ -339,18 +339,16 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
protected final def createTestKey(
maintainers: Set[Party]
): (Node.KeyWithMaintainers, GlobalKey) = {
): GlobalKeyWithMaintainers = {
val aTextValue = ValueText(scala.util.Random.nextString(10))
val keyWithMaintainers = Node.KeyWithMaintainers(aTextValue, maintainers)
val globalKey = GlobalKey.assertBuild(someTemplateId, aTextValue)
(keyWithMaintainers, globalKey)
GlobalKeyWithMaintainers.assertBuild(someTemplateId, aTextValue, maintainers)
}
protected final def createAndStoreContract(
submittingParties: Set[Party],
signatories: Set[Party],
stakeholders: Set[Party],
key: Option[Node.KeyWithMaintainers],
key: Option[GlobalKeyWithMaintainers],
contractArgument: LfValue = someContractArgument,
): Future[(Offset, LedgerEntry.Transaction)] =
store(
@ -397,7 +395,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
choiceObservers = Set.empty,
children = ImmArray.Empty,
exerciseResult = Some(someChoiceResult),
key = None,
keyOpt = None,
byKey = false,
version = txVersion,
)
@ -432,7 +430,7 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
protected def singleExercise(
targetCid: ContractId,
key: Option[Node.KeyWithMaintainers] = None,
key: Option[GlobalKeyWithMaintainers] = None,
): (Offset, LedgerEntry.Transaction) = {
val txBuilder = newBuilder()
val nid = txBuilder.add(exerciseNode(targetCid, key))
@ -731,7 +729,10 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
agreementText = someAgreement,
signatories = Set(party),
stakeholders = Set(party),
key = Some(Node.KeyWithMaintainers(someContractKey(party, key), Set(party))),
keyOpt = Some(
GlobalKeyWithMaintainers
.assertBuild(someTemplateId, someContractKey(party, key), Set(party))
),
version = txVersion,
)
)
@ -771,7 +772,10 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
choiceObservers = Set.empty,
children = ImmArray.Empty,
exerciseResult = Some(LfValue.ValueUnit),
key = maybeKey.map(k => Node.KeyWithMaintainers(someContractKey(party, k), Set(party))),
keyOpt = maybeKey.map(k =>
GlobalKeyWithMaintainers
.assertBuild(someTemplateId, someContractKey(party, k), Set(party))
),
byKey = false,
version = txVersion,
)
@ -800,7 +804,8 @@ private[dao] trait JdbcLedgerDaoSuite extends JdbcLedgerDaoBackend {
val lookupByKeyNodeId = txBuilder.add(
Node.LookupByKey(
someTemplateId,
Node.KeyWithMaintainers(someContractKey(party, key), Set(party)),
GlobalKeyWithMaintainers
.assertBuild(someTemplateId, someContractKey(party, key), Set(party)),
result,
version = txVersion,
)

View File

@ -80,7 +80,7 @@ class LedgerTimeAwareCommandExecutorSpec
driverMetadata = Bytes.Empty,
signatories = Set.empty,
stakeholders = Set.empty,
maybeKeyWithMaintainers = None,
keyOpt = None,
agreementText = "",
),
),

View File

@ -80,7 +80,7 @@ class ResolveMaximumLedgerTimeSpec
driverMetadata = Bytes.Empty,
signatories = Set.empty,
stakeholders = Set.empty,
maybeKeyWithMaintainers = None,
keyOpt = None,
agreementText = "",
),
)

View File

@ -45,7 +45,7 @@ class StoreBackedCommandExecutorSpec
driverMetadata = Bytes.Empty,
signatories = Set.empty,
stakeholders = Set.empty,
maybeKeyWithMaintainers = None,
keyOpt = None,
agreementText = "some agreement text",
),
),

View File

@ -218,7 +218,7 @@ class ApiSubmissionServiceSpec
driverMetadata = Bytes.Empty,
signatories = Set.empty,
stakeholders = Set.empty,
maybeKeyWithMaintainers = None,
keyOpt = None,
agreementText = "",
),
)

View File

@ -1573,14 +1573,18 @@ object UpdateToDbDtoSpec {
/** Returns (contract argument, contract key) */
override def serialize(eventId: EventId, create: Create): (Array[Byte], Option[Array[Byte]]) =
(emptyArray, create.key.map(_ => emptyArray))
(emptyArray, create.keyOpt.map(_ => emptyArray))
/** Returns (choice argument, exercise result, contract key) */
override def serialize(
eventId: EventId,
exercise: Exercise,
): (Array[Byte], Option[Array[Byte]], Option[Array[Byte]]) =
(emptyArray, exercise.exerciseResult.map(_ => emptyArray), exercise.key.map(_ => emptyArray))
(
emptyArray,
exercise.exerciseResult.map(_ => emptyArray),
exercise.keyOpt.map(_ => emptyArray),
)
override def deserialize[E](
raw: Raw.Created[E],
eventProjectionProperties: EventProjectionProperties,

View File

@ -30,7 +30,7 @@ class BridgeWriteServiceTest extends AnyFlatSpec with MockitoSugar with Matchers
agreementText = "dummyAgreement",
signatories = Set.empty,
stakeholders = Set.empty,
key = None,
keyOpt = None,
version = TransactionVersion.minVersion,
)

View File

@ -306,7 +306,7 @@ class ConflictCheckWithCommittedSpec
driverMetadata = contractId.toBytes,
signatories = Set.empty,
stakeholders = Set.empty,
maybeKeyWithMaintainers = None,
keyOpt = None,
agreementText = "",
),
)