diff --git a/sdk/canton/community/base/src/main/scala/com/digitalasset/canton/protocol/GlobalKeySerialization.scala b/sdk/canton/community/base/src/main/scala/com/digitalasset/canton/protocol/GlobalKeySerialization.scala index 63f8731d8ac9..a70b232dbaab 100644 --- a/sdk/canton/community/base/src/main/scala/com/digitalasset/canton/protocol/GlobalKeySerialization.scala +++ b/sdk/canton/community/base/src/main/scala/com/digitalasset/canton/protocol/GlobalKeySerialization.scala @@ -7,8 +7,9 @@ import cats.syntax.either.* import com.digitalasset.canton.serialization.ProtoConverter import com.digitalasset.canton.serialization.ProtoConverter.ParsingResult import com.digitalasset.canton.{LfVersioned, ProtoDeserializationError} -import com.digitalasset.daml.lf.data.Ref +import com.digitalasset.daml.lf.data.{Bytes, Ref} import com.digitalasset.daml.lf.value.{ValueCoder, ValueOuterClass} +import com.digitalasset.daml.lf.crypto object GlobalKeySerialization { @@ -22,7 +23,7 @@ object GlobalKeySerialization { .leftMap(_.errorMessage) } yield v30.GlobalKey( templateId = templateIdP.toByteString, - key = keyP.toByteString, + key = globalKey.unversioned.hash.bytes.toByteString.concat(keyP.toByteString), globalKey.unversioned.packageName, ) } @@ -33,37 +34,48 @@ object GlobalKeySerialization { def fromProtoV30(globalKeyP: v30.GlobalKey): ParsingResult[LfVersioned[LfGlobalKey]] = { val v30.GlobalKey(templateIdBytes, keyBytes, packageNameP) = globalKeyP - for { - templateIdP <- ProtoConverter.protoParser(ValueOuterClass.Identifier.parseFrom)( - templateIdBytes - ) - templateId <- ValueCoder - .decodeIdentifier(templateIdP) - .leftMap(err => - ProtoDeserializationError - .ValueDeserializationError("GlobalKey.templateId", err.errorMessage) + val hashBytesLength = crypto.Hash.underlyingHashLength + if (keyBytes.size < hashBytesLength) { + Left( + ProtoDeserializationError.OtherError( + s"ByteString too short to contain a GlobalKey hash. Expected at least $hashBytesLength bytes, got ${keyBytes.size}" ) - - keyP <- ProtoConverter.protoParser(ValueOuterClass.VersionedValue.parseFrom)( - keyBytes ) - versionedKey <- ValueCoder - .decodeVersionedValue(keyP) - .leftMap(err => - ProtoDeserializationError.ValueDeserializationError("GlobalKey.proto", err.toString) + } else { + val hashBs = keyBytes.substring(0, hashBytesLength) + val valueBs = keyBytes.substring(hashBytesLength) + for { + templateIdP <- ProtoConverter.protoParser(ValueOuterClass.Identifier.parseFrom)( + templateIdBytes ) + templateId <- ValueCoder + .decodeIdentifier(templateIdP) + .leftMap(err => + ProtoDeserializationError + .ValueDeserializationError("GlobalKey.templateId", err.errorMessage) + ) - packageName <- Ref.PackageName - .fromString(packageNameP) - .leftMap(err => ProtoDeserializationError.ValueDeserializationError("GlobalKey.proto", err)) + hash <- crypto.Hash.fromBytes(Bytes.fromByteString(hashBs)).left.map(ProtoDeserializationError.OtherError(_)) + keyP <- ProtoConverter.protoParser(ValueOuterClass.VersionedValue.parseFrom)(valueBs) + versionedKey <- ValueCoder + .decodeVersionedValue(keyP) + .leftMap(err => + ProtoDeserializationError.ValueDeserializationError("GlobalKey.proto", err.toString) + ) - globalKey <- LfGlobalKey - .build(templateId, versionedKey.unversioned, packageName) - .leftMap(err => - ProtoDeserializationError.ValueDeserializationError("GlobalKey.key", err.toString) - ) + packageName <- Ref.PackageName + .fromString(packageNameP) + .leftMap(err => + ProtoDeserializationError.ValueDeserializationError("GlobalKey.proto", err) + ) - } yield LfVersioned(versionedKey.version, globalKey) - } + globalKey <- LfGlobalKey + .build(templateId, packageName, versionedKey.unversioned, hash) + .leftMap(err => + ProtoDeserializationError.ValueDeserializationError("GlobalKey.key", err.toString) + ) + } yield LfVersioned(versionedKey.version, globalKey) + } + } } diff --git a/sdk/canton/community/common/src/main/scala/com/digitalasset/canton/protocol/ContractIdAbsolutizer.scala b/sdk/canton/community/common/src/main/scala/com/digitalasset/canton/protocol/ContractIdAbsolutizer.scala index 03debc8efb19..e3060dcc6b64 100644 --- a/sdk/canton/community/common/src/main/scala/com/digitalasset/canton/protocol/ContractIdAbsolutizer.scala +++ b/sdk/canton/community/common/src/main/scala/com/digitalasset/canton/protocol/ContractIdAbsolutizer.scala @@ -77,7 +77,7 @@ class ContractIdAbsolutizer( } .map { absolutizedKey => keyWithMaintainers.copy(globalKey = - LfGlobalKey.assertBuild(gkey.templateId, absolutizedKey, gkey.packageName) + LfGlobalKey.assertBuild(gkey.templateId, gkey.packageName, absolutizedKey, gkey.hash) ) } } diff --git a/sdk/canton/community/common/src/test/scala/com/digitalasset/canton/protocol/ExampleContractFactory.scala b/sdk/canton/community/common/src/test/scala/com/digitalasset/canton/protocol/ExampleContractFactory.scala index 23eae905aeee..0f958384846d 100644 --- a/sdk/canton/community/common/src/test/scala/com/digitalasset/canton/protocol/ExampleContractFactory.scala +++ b/sdk/canton/community/common/src/test/scala/com/digitalasset/canton/protocol/ExampleContractFactory.scala @@ -131,7 +131,7 @@ object ExampleContractFactory extends EitherValues { value: Value = ValueInt64(random.nextLong()), maintainers: Set[Ref.Party] = Set(signatory), ): GlobalKeyWithMaintainers = - GlobalKeyWithMaintainers.assertBuild(templateId, value, maintainers, packageName) + GlobalKeyWithMaintainers.assertBuild(templateId, value, null, maintainers, packageName) def modify[Time <: CreationTime]( base: GenContractInstance { type InstCreatedAtTime <: Time }, diff --git a/sdk/canton/community/ledger-api-proto/src/main/protobuf/com/daml/ledger/api/v2/event.proto b/sdk/canton/community/ledger-api-proto/src/main/protobuf/com/daml/ledger/api/v2/event.proto index c0625ecca379..0270562271d4 100644 --- a/sdk/canton/community/ledger-api-proto/src/main/protobuf/com/daml/ledger/api/v2/event.proto +++ b/sdk/canton/community/ledger-api-proto/src/main/protobuf/com/daml/ledger/api/v2/event.proto @@ -64,6 +64,11 @@ message CreatedEvent { // Optional Value contract_key = 5; + // The hash of contract_key. + // This will be set if and only if ``template_id`` defines a contract key. + // Optional + bytes contract_key_hash = 16; + // The arguments that have been used to create the contract. // // Required diff --git a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/apiserver/services/command/interactive/codec/PreparedTransactionDecoder.scala b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/apiserver/services/command/interactive/codec/PreparedTransactionDecoder.scala index 6c00b0171f29..1b3f1822e5d8 100644 --- a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/apiserver/services/command/interactive/codec/PreparedTransactionDecoder.scala +++ b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/apiserver/services/command/interactive/codec/PreparedTransactionDecoder.scala @@ -174,8 +174,9 @@ final class PreparedTransactionDecoder(override val loggerFactory: NamedLoggerFa templateId: TypeConId, key: Value, packageName: Ref.PackageName, + hash: lf.crypto.Hash, ): Result[lf.transaction.GlobalKey] = - lf.transaction.GlobalKey.build(templateId, key, packageName).leftMap(_.msg).toResult + lf.transaction.GlobalKey.build(templateId, packageName, key, hash).leftMap(_.msg).toResult PartialTransformer .define[iscd.GlobalKey, lf.transaction.GlobalKey] diff --git a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/index/InMemoryStateUpdater.scala b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/index/InMemoryStateUpdater.scala index 534e1de31524..f40986559b7e 100644 --- a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/index/InMemoryStateUpdater.scala +++ b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/index/InMemoryStateUpdater.scala @@ -35,6 +35,7 @@ import com.digitalasset.daml.lf.transaction.Node.{Create, Exercise} import org.apache.pekko.NotUsed import org.apache.pekko.stream.FlowShape import org.apache.pekko.stream.scaladsl.{Broadcast, Flow, GraphDSL, Merge, Sink, Source} +import com.digitalasset.daml.lf.crypto import scala.concurrent.duration.FiniteDuration import scala.concurrent.{ExecutionContext, Future} @@ -384,8 +385,11 @@ private[platform] object InMemoryStateUpdater { globalKey = createdEvent.contractKey.map(k => Key.assertBuild( createdEvent.templateId, - k.unversioned, createdEvent.packageName, + k.unversioned, + createdEvent.createKeyHash.getOrElse( + throw new IllegalStateException("contractKey is defined but createKeyHash is not") + ), ) ), ) @@ -395,11 +399,14 @@ private[platform] object InMemoryStateUpdater { if exercisedEvent.consuming && exercisedEvent.flatEventWitnesses.nonEmpty => ContractStateEvent.Archived( contractId = exercisedEvent.contractId, - globalKey = exercisedEvent.contractKey.map(k => - Key.assertBuild( - exercisedEvent.templateId, - k.unversioned, - exercisedEvent.packageName, + globalKey = exercisedEvent.contractKey.flatMap(k => + exercisedEvent.contractKeyHash.map(hash => + Key.assertBuild( + exercisedEvent.templateId, + exercisedEvent.packageName, + k.unversioned, + hash, + ) ) ), ) @@ -487,6 +494,7 @@ private[platform] object InMemoryStateUpdater { contractKey = exercise.keyOpt.map(k => com.digitalasset.daml.lf.transaction.Versioned(exercise.version, k.value) ), + contractKeyHash = exercise.keyOpt.map(_.globalKey.hash), treeEventWitnesses = blinding.disclosure.getOrElse(nodeId, Set.empty), flatEventWitnesses = if (exercise.consuming && txAccepted.isAcsDelta(exercise.targetCoid)) diff --git a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/dao/events/LfValueTranslation.scala b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/dao/events/LfValueTranslation.scala index 765360d65adc..378ed76e7c79 100644 --- a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/dao/events/LfValueTranslation.scala +++ b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/dao/events/LfValueTranslation.scala @@ -45,6 +45,7 @@ import io.grpc.Status.Code import java.io.ByteArrayInputStream import scala.concurrent.{ExecutionContext, Future} import scala.util.chaining.* +import com.digitalasset.daml.lf.crypto /** Serializes and deserializes Daml-Lf values and events. * @@ -300,7 +301,7 @@ final class LfValueTranslation( loggingContext: LoggingContextWithTrace, ): Future[CreatedEvent] = { val createArgument = fatContractInstance.createArg - val createKey = fatContractInstance.contractKeyWithMaintainers.map(_.globalKey.key) + val createKey = fatContractInstance.contractKeyWithMaintainers.map(_.globalKey) val representativeTemplateId = fatContractInstance.templateId @@ -323,7 +324,8 @@ final class LfValueTranslation( templateId = Some( LfEngineToApi.toApiIdentifier(fatContractInstance.templateId) ), - contractKey = apiContractData.contractKey, + contractKey = apiContractData.contractKey.map(_._1), + contractKeyHash = apiContractData.contractKey.fold(ByteString.EMPTY)(_._2.bytes.toByteString), createArguments = Some(apiContractData.createArguments), createdEventBlob = apiContractData.createdEventBlob.getOrElse(ByteString.EMPTY), interfaceViews = apiContractData.interfaceViews, @@ -342,7 +344,7 @@ final class LfValueTranslation( private def toApiContractData( value: Value, - keyO: Option[Value], + keyO: Option[GlobalKey], representativeTemplateId: FullIdentifier, witnesses: Set[String], eventProjectionProperties: EventProjectionProperties, @@ -363,14 +365,14 @@ final class LfValueTranslation( .map(toContractArgumentApi(verbose)) def asyncContractKey = keyO match { case None => Future.successful(None) - case Some(key) => + case Some(gkey) => enrichAsync( verbose = verbose, - value = key, + value = gkey.key, enrich = enricher.enrichContractKey(representativeTemplateId.toIdentifier, _), ) .map(toContractKeyApi(verbose)) - .map(Some(_)) + .map(Some(_, gkey.hash)) } def asyncInterfaceViews = @@ -549,7 +551,7 @@ object LfValueTranslation { final case class ApiContractData( createArguments: ApiRecord, createdEventBlob: Option[ByteString], - contractKey: Option[ApiValue], + contractKey: Option[(ApiValue, crypto.Hash)], interfaceViews: Seq[InterfaceView], ) } diff --git a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/dao/events/TransactionLogUpdatesConversions.scala b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/dao/events/TransactionLogUpdatesConversions.scala index e844c883288d..bfbdbeadde59 100644 --- a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/dao/events/TransactionLogUpdatesConversions.scala +++ b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/dao/events/TransactionLogUpdatesConversions.scala @@ -475,6 +475,9 @@ private[events] object TransactionLogUpdatesConversions { GlobalKeyWithMaintainers.assertBuild( templateId = createdEvent.templateId, value = keyVersionedValue.unversioned, + valueHash = createdEvent.createKeyHash.getOrElse( + throw new IllegalStateException("contractKey is defined but createKeyHash is not") + ), maintainers = maintainers, packageName = createdEvent.packageName, ) diff --git a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/interfaces/TransactionLogUpdate.scala b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/interfaces/TransactionLogUpdate.scala index 6ca5d246aeea..01f445b6d0c3 100644 --- a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/interfaces/TransactionLogUpdate.scala +++ b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/store/interfaces/TransactionLogUpdate.scala @@ -159,6 +159,7 @@ object TransactionLogUpdate { commandId: String, workflowId: String, contractKey: Option[LfValue.VersionedValue], + contractKeyHash: Option[Hash], treeEventWitnesses: Set[Party], flatEventWitnesses: Set[Party], submitters: Set[Party], diff --git a/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/apiserver/services/DisclosedContractCreator.scala b/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/apiserver/services/DisclosedContractCreator.scala index 6c2605f14811..19c2ad9b0b7d 100644 --- a/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/apiserver/services/DisclosedContractCreator.scala +++ b/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/apiserver/services/DisclosedContractCreator.scala @@ -57,6 +57,7 @@ object DisclosedContractCreator { None -> LfValue.ValueText("some key"), ), ), + null, api.keyMaintainers, Ref.PackageName.assertFromString(api.packageName), ) diff --git a/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/apiserver/services/command/CommandSubmissionServiceImplSpec.scala b/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/apiserver/services/command/CommandSubmissionServiceImplSpec.scala index 54f01efbde21..66926722d15b 100644 --- a/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/apiserver/services/command/CommandSubmissionServiceImplSpec.scala +++ b/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/apiserver/services/command/CommandSubmissionServiceImplSpec.scala @@ -129,7 +129,7 @@ class CommandSubmissionServiceImplSpec LfError.Interpretation.DamlException( LfInterpretationError.DuplicateContractKey( GlobalKey - .assertBuild(tmplId, Value.ValueUnit, PackageName.assertFromString("pkg-name")) + .assertBuild(tmplId, packageName = PackageName.assertFromString("pkg-name"), key = Value.ValueUnit, keyHash = null) ) ), None, diff --git a/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/backend/StorageBackendTestsContracts.scala b/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/backend/StorageBackendTestsContracts.scala index c48fdf3e78db..3804474cda1d 100644 --- a/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/backend/StorageBackendTestsContracts.scala +++ b/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/backend/StorageBackendTestsContracts.scala @@ -26,12 +26,12 @@ private[backend] trait StorageBackendTestsContracts val key1 = GlobalKey.assertBuild( Identifier.assertFromString("A:B:C"), ValueUnit, - someTemplateId.pkg.name, + keyHash = null, ) val key2 = GlobalKey.assertBuild( Identifier.assertFromString("A:B:C"), ValueText("value"), - someTemplateId.pkg.name, + keyHash = null, ) val internalContractId = 123L val internalContractId2 = 223L diff --git a/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/backend/UpdateToDbDtoSpec.scala b/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/backend/UpdateToDbDtoSpec.scala index 56bd6f54977c..176495fe58f9 100644 --- a/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/backend/UpdateToDbDtoSpec.scala +++ b/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/backend/UpdateToDbDtoSpec.scala @@ -302,7 +302,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { internal_contract_id = 42L, create_key_hash = Some( GlobalKey - .assertBuild(contractTemplate, keyValue, createNode.packageName) + .assertBuild(contractTemplate, key = keyValue, keyHash = null) .hash .bytes .toHexString @@ -1344,11 +1344,7 @@ class UpdateToDbDtoSpec extends AnyWordSpec with Matchers { internal_contract_id = 42L, create_key_hash = Some( GlobalKey - .assertBuild( - Ref.Identifier.assertFromString("P:M:T2"), - Value.ValueUnit, - createNodeC.packageName, - ) + .assertBuild(Ref.Identifier.assertFromString("P:M:T2"), key = Value.ValueUnit, keyHash = null) .hash .bytes .toHexString diff --git a/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/dao/JdbcLedgerDaoContractsSpec.scala b/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/dao/JdbcLedgerDaoContractsSpec.scala index 12cbd0ea4a56..30f4810c3e7b 100644 --- a/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/dao/JdbcLedgerDaoContractsSpec.scala +++ b/sdk/canton/community/ledger/ledger-api-core/src/test/scala/com/digitalasset/canton/platform/store/dao/JdbcLedgerDaoContractsSpec.scala @@ -91,10 +91,9 @@ private[dao] trait JdbcLedgerDaoContractsSpec extends LoneElement with Inside wi val aTextValue = ValueText(scala.util.Random.nextString(10)) val key = GlobalKeyWithMaintainers.assertBuild( - someTemplateId, - aTextValue, - Set(alice, bob), - somePackageName, + value = aTextValue, + valueHash = null, + maintainers = Set(alice, bob), ) for { @@ -132,10 +131,9 @@ private[dao] trait JdbcLedgerDaoContractsSpec extends LoneElement with Inside wi def genContractWithKey(string: String = scala.util.Random.nextString(5)) = { val aTextValue = ValueText(string) val key = GlobalKeyWithMaintainers.assertBuild( - someTemplateId, - aTextValue, - Set(alice), - somePackageName, + value = aTextValue, + valueHash = null, + maintainers = Set(alice), ) createAndStoreContract( submittingParties = Set(alice), diff --git a/sdk/canton/community/ledger/ledger-json-api/src/main/scala/com/digitalasset/canton/http/json/v2/JsSchema.scala b/sdk/canton/community/ledger/ledger-json-api/src/main/scala/com/digitalasset/canton/http/json/v2/JsSchema.scala index b62804cd18c2..d64ad9eee124 100644 --- a/sdk/canton/community/ledger/ledger-json-api/src/main/scala/com/digitalasset/canton/http/json/v2/JsSchema.scala +++ b/sdk/canton/community/ledger/ledger-json-api/src/main/scala/com/digitalasset/canton/http/json/v2/JsSchema.scala @@ -255,6 +255,7 @@ object JsSchema { contractId: String, templateId: Identifier, contractKey: Option[Json], + contractKeyHash: protobuf.ByteString, createArgument: Option[Json], createdEventBlob: protobuf.ByteString, interfaceViews: Seq[JsInterfaceView], diff --git a/sdk/canton/community/participant/src/main/scala/com/digitalasset/canton/participant/protocol/LedgerEffectAbsolutizer.scala b/sdk/canton/community/participant/src/main/scala/com/digitalasset/canton/participant/protocol/LedgerEffectAbsolutizer.scala index b9e193c0acab..3a23d301e578 100644 --- a/sdk/canton/community/participant/src/main/scala/com/digitalasset/canton/participant/protocol/LedgerEffectAbsolutizer.scala +++ b/sdk/canton/community/participant/src/main/scala/com/digitalasset/canton/participant/protocol/LedgerEffectAbsolutizer.scala @@ -46,7 +46,7 @@ class LedgerEffectAbsolutizer(absolutizer: ContractIdAbsolutizer) { absolutizedKey <- gkey.key.traverseCid(absolutizer.absolutizeContractId) absolutizedResolution <- absolutizeKeyResolution(resolution.unversioned) } yield ( - LfGlobalKey.assertBuild(gkey.templateId, absolutizedKey, gkey.packageName), + LfGlobalKey.assertBuild(gkey.templateId, gkey.packageName, absolutizedKey, gkey.hash), resolution.copy(unversioned = absolutizedResolution), ) } diff --git a/sdk/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/Enricher.scala b/sdk/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/Enricher.scala index 15f41c414ee8..dcab817f2ae2 100644 --- a/sdk/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/Enricher.scala +++ b/sdk/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/Enricher.scala @@ -76,8 +76,9 @@ object Enricher { private def impoverish(key: GlobalKey): GlobalKey = GlobalKey.assertBuild( templateId = key.templateId, - key = impoverish(key.key), key.packageName, + key = impoverish(key.key), + key.hash, ) private def impoverish(key: GlobalKeyWithMaintainers): GlobalKeyWithMaintainers = diff --git a/sdk/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/CommandPreprocessor.scala b/sdk/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/CommandPreprocessor.scala index eed72855a8ff..518213c97f49 100644 --- a/sdk/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/CommandPreprocessor.scala +++ b/sdk/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/CommandPreprocessor.scala @@ -344,7 +344,7 @@ private[lf] final class CommandPreprocessor( keys.map(unsafePreprocessApiContractKey(pkgResolution, _)) @throws[Error.Preprocessing.Error] - private def unsafePreprocessApiContractKey( + def unsafePreprocessApiContractKey( pkgResolution: Map[Ref.PackageName, Ref.PackageId], key: ApiContractKey, ): GlobalKey = { diff --git a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala index 23065f9e1f9b..ea1d6916d095 100644 --- a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala +++ b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala @@ -51,7 +51,13 @@ class AuthorizationSpec extends AnyFreeSpec with Matchers with Inside with TestI init.copy( // By default maintainers are added to signatories so do this to allow error case testing keyOpt = Some( - GlobalKeyWithMaintainers.assertBuild(templateId, Value.ValueUnit, maintainers, pkgName) + GlobalKeyWithMaintainers.assertBuild( + templateId, + Value.ValueUnit, + null, + maintainers, + pkgName, + ) ) ) } diff --git a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala index fd1843f2676c..080ebb66c8b8 100644 --- a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala +++ b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala @@ -4,19 +4,23 @@ package com.digitalasset.daml.lf package engine +import com.digitalasset.daml.lf.crypto.SValueHash import com.digitalasset.daml.lf.data.ImmArray import com.digitalasset.daml.lf.engine.BlindingSpec.TxBuilder +import com.digitalasset.daml.lf.speedy.SValue import com.digitalasset.daml.lf.transaction.{BlindingInfo, Node} import com.digitalasset.daml.lf.transaction.test.{ NodeIdTransactionBuilder, - TransactionBuilder, TestNodeBuilder, + TransactionBuilder, } import com.digitalasset.daml.lf.value.Value import com.digitalasset.daml.lf.value.Value.ValueRecord import org.scalatest.matchers.should.Matchers import org.scalatest.freespec.AnyFreeSpec +import scala.collection.immutable.ArraySeq + object BlindingSpec { class TxBuilder extends NodeIdTransactionBuilder with TestNodeBuilder } @@ -117,7 +121,15 @@ class BlindingSpec extends AnyFreeSpec with Matchers { argument = ValueRecord(None, ImmArray.empty), signatories = Seq("Alice", "Bob"), observers = Seq("Carl"), - key = CreateKey.KeyWithMaintainers(ValueRecord(None, ImmArray.empty), Seq("Alice")), + key = CreateKey.KeyWithMaintainers( + value = ValueRecord(None, ImmArray.empty), + hash = SValueHash.assertHashContractKey( + TestNodeBuilder.defaultPackageName, + "M:T", + SValue.SRecord("M:T", ImmArray.empty, ArraySeq.empty), + ), + maintainers = Seq("Alice"), + ), ) val lookup = builder.lookupByKey(create) val nodeId = builder.add(lookup) @@ -138,7 +150,15 @@ class BlindingSpec extends AnyFreeSpec with Matchers { argument = ValueRecord(None, ImmArray.empty), signatories = Seq("Alice", "Bob"), observers = Seq("Carl"), - key = CreateKey.KeyWithMaintainers(ValueRecord(None, ImmArray.empty), Seq("Alice")), + key = CreateKey.KeyWithMaintainers( + value = ValueRecord(None, ImmArray.empty), + hash = SValueHash.assertHashContractKey( + TestNodeBuilder.defaultPackageName, + "M:T", + SValue.SRecord("M:T", ImmArray.empty, ArraySeq.empty), + ), + maintainers = Seq("Alice"), + ), ) val lookup = builder.lookupByKey(create, found = false) val nodeId = builder.add(lookup) diff --git a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala index d86630ac87b7..3a8b0db02f19 100644 --- a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala +++ b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala @@ -18,7 +18,7 @@ import com.digitalasset.daml.lf.data.Ref.{ import com.digitalasset.daml.lf.data.{Bytes, ImmArray, Ref, Time} import com.digitalasset.daml.lf.language.Ast.Package import com.digitalasset.daml.lf.language.LanguageVersion -import com.digitalasset.daml.lf.speedy.InitialSeeding +import com.digitalasset.daml.lf.speedy.{InitialSeeding, SValue} import com.digitalasset.daml.lf.transaction.{ ContractKeyUniquenessMode, FatContractInstance, @@ -35,6 +35,8 @@ import com.digitalasset.daml.lf.value.Value.{ ValueRecord, } import com.daml.logging.LoggingContext +import com.digitalasset.daml.lf.crypto.SValueHash +import com.digitalasset.daml.lf.stablepackages.StablePackagesV2 import com.digitalasset.daml.lf.transaction.test.TransactionBuilder import java.io.File @@ -44,6 +46,7 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.prop.TableDrivenPropertyChecks import org.scalatest.wordspec.AnyWordSpec +import scala.collection.immutable.ArraySeq import scala.language.implicitConversions class ContractKeySpecV2 extends ContractKeySpec(LanguageVersion.Major.V2) @@ -138,15 +141,27 @@ class ContractKeySpec(majorLanguageVersion: LanguageVersion.Major) withKeyContractInst, ) - val defaultKey = Map( - GlobalKey.assertBuild( - TypeConId(basicTestsPkgId, withKeyTemplate), - ValueRecord(None, ImmArray((None, ValueParty(alice)), (None, ValueInt64(42)))), - basicTestsPkg.pkgName, + val defaultKey = { + val sKey = SValue.SRecord( + StablePackagesV2.Tuple2, + ImmArray(Ref.Name.assertFromString("_1"), Ref.Name.assertFromString("_2")), + ArraySeq(SValue.SParty(alice), SValue.SInt64(42)), ) - -> - toContractId("BasicTests:WithKey:1") - ) + Map( + GlobalKey.assertBuild( + TypeConId(basicTestsPkgId, withKeyTemplate), + basicTestsPkg.pkgName, + sKey.toNormalizedValue, + SValueHash.assertHashContractKey( + basicTestsPkg.pkgName, + Identifier(basicTestsPkgId, "BasicTests:WithKey").qualifiedName, + sKey, + ), + ) + -> + toContractId("BasicTests:WithKey:1") + ) + } private[this] val lookupKey: PartialFunction[GlobalKeyWithMaintainers, ContractId] = { case GlobalKeyWithMaintainers( @@ -300,6 +315,7 @@ class ContractKeySpec(majorLanguageVersion: LanguageVersion.Major) val let = Time.Timestamp.now() val submissionSeed = hash("multikeys") val seeding = Engine.initialSeeding(submissionSeed, participant, let) + val sKey = SValue.SParty(party) val cid1 = toContractId("1") val cid2 = toContractId("2") @@ -314,7 +330,12 @@ class ContractKeySpec(majorLanguageVersion: LanguageVersion.Major) GlobalKey.assertBuild( templateId = TypeConId(multiKeysPkgId, "MultiKeys:Keyed"), packageName = multiKeysPkg.pkgName, - key = ValueParty(party), + key = sKey.toNormalizedValue, + SValueHash.assertHashContractKey( + multiKeysPkg.pkgName, + "MultiKeys:Keyed", + sKey, + ), ), Set(party), ) diff --git a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala index 6f93a0b96b7b..c29beb29e6e0 100644 --- a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala +++ b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala @@ -23,7 +23,7 @@ import com.digitalasset.daml.lf.language.{LanguageVersion, PackageInterface} import com.digitalasset.daml.lf.speedy.metrics.{StepCount, TxNodeCount} import com.digitalasset.daml.lf.speedy.SValue._ import com.digitalasset.daml.lf.speedy.{InitialSeeding, SValue, svalue} -import com.digitalasset.daml.lf.stablepackages.StablePackages +import com.digitalasset.daml.lf.stablepackages.{StablePackages, StablePackagesV2} import com.digitalasset.daml.lf.transaction.test.TransactionBuilder import com.digitalasset.daml.lf.transaction.{ CreationTime, @@ -497,18 +497,18 @@ class EngineTest(majorLanguageVersion: LanguageVersion.Major, contractIdVersion: ) .consume(lookupContract, lookupPackage, lookupKey) inside(submitResult) { case Left(Error.Interpretation(err, _)) => + val sKey = mkSValuePair(SValue.SParty(alice), SValue.SInt64(43)) err shouldBe Interpretation.DamlException( interpretation.Error.ContractKeyNotFound( GlobalKey.assertBuild( templateId = BasicTests_WithKey, - key = ValueRecord( - Some(BasicTests_WithKey), - ImmArray( - (Some[Ref.Name]("p"), ValueParty(alice)), - (Some[Ref.Name]("k"), ValueInt64(43)), - ), - ), packageName = basicTestsPkg.pkgName, + key = sKey.toNormalizedValue, + keyHash = SValueHash.assertHashContractKey( + basicTestsPkg.pkgName, + templateId.qualifiedName, + sKey, + ), ) ) ) @@ -700,30 +700,27 @@ class EngineTest(majorLanguageVersion: LanguageVersion.Major, contractIdVersion: val templateId = Identifier(basicTestsPkgId, "BasicTests:TypedKey") - val keyValue = ValueRecord( - tycon = Some(Identifier(basicTestsPkgId, "BasicTests:NumericKey")), - fields = ImmArray.from( - Seq( - (Some[Ref.Name]("sig"), ValueParty(alice)), - ( - Some[Ref.Name]("n4"), - ValueNumeric(com.digitalasset.daml.lf.data.Numeric.assertFromString("10.1200")), - ), - (Some[Ref.Name]("i"), ValueNone), - ) + val keySValue = SValue.SRecord( + id = Identifier(basicTestsPkgId, "BasicTests:NumericKey"), + fields = ImmArray("sig", "n4", "i"), + values = ArraySeq( + SValue.SParty(alice), + SValue.SNumeric(com.digitalasset.daml.lf.data.Numeric.assertFromString("10.1200")), + SValue.SOptional(None), ), ) + val keyValue = keySValue.toNormalizedValue.asInstanceOf[ValueRecord] - val expected = GlobalKey.assertBuild(templateId, keyValue, basicTestsPkg.pkgName) + val expected = GlobalKey.assertBuild( + templateId, + basicTestsPkg.pkgName, + keyValue, + SValueHash.assertHashContractKey(basicTestsPkg.pkgName, templateId.qualifiedName, keySValue), + ) def translateAndCheck(fields: Seq[(Option[Name], Value)]): Assertion = { - val input = ValueRecord( - tycon = Some(Identifier(basicTestsPkgId, "BasicTests:NumericKey")), - fields = ImmArray.from(fields), - ) - val result = suffixLenientEngine - .buildGlobalKey(templateId, input) + .buildGlobalKey(templateId, ValueRecord(tycon = None, fields = ImmArray.from(fields))) .consume(lookupContract, lookupPackage, lookupKey) inside(result) { case Right(actual) => @@ -836,16 +833,9 @@ class EngineTest(majorLanguageVersion: LanguageVersion.Major, contractIdVersion: "error if the engine fails to find the key" in { val templateId = Identifier(basicTestsPkgId, "BasicTests:WithKey") - val cmds = ImmArray( - speedy.Command.FetchByKey( - templateId = templateId, - key = SRecord( - BasicTests_WithKey, - ImmArray("_1", "_2"), - ArraySeq(SParty(alice), SInt64(43)), - ), - ) - ) + val sKey = mkSValuePair(SValue.SParty(alice), SValue.SInt64(43)) + + val cmds = ImmArray(speedy.Command.FetchByKey(templateId = templateId, key = sKey)) val submitters = Set(alice) @@ -863,28 +853,28 @@ class EngineTest(majorLanguageVersion: LanguageVersion.Major, contractIdVersion: .consume(PartialFunction.empty, lookupPackage, lookupKey) inside(result) { case Left(Error.Interpretation(err, _)) => - err shouldBe - Interpretation.DamlException( - interpretation.Error.ContractKeyNotFound( - GlobalKey.assertBuild( - templateId = BasicTests_WithKey, - key = ValueRecord( - Some(BasicTests_WithKey), - ImmArray( - (Some[Ref.Name]("p"), ValueParty(alice)), - (Some[Ref.Name]("k"), ValueInt64(43)), - ), - ), - packageName = basicTestsPkg.pkgName, - ) + err shouldBe Interpretation.DamlException( + interpretation.Error.ContractKeyNotFound( + GlobalKey.assertBuild( + templateId = BasicTests_WithKey, + packageName = basicTestsPkg.pkgName, + key = sKey.toNormalizedValue, + keyHash = SValueHash.assertHashContractKey( + basicTestsPkg.pkgName, + templateId.qualifiedName, + sKey, + ), ) ) + ) } } "error if Speedy fails to find the key" in { val templateId = Identifier(basicTestsPkgId, "BasicTests:FailedFetchByKey") + val sKey = mkSValuePair(SValue.SParty(alice), SValue.SInt64(43)) + // This first does a negative lookupByKey which succeeds // and then a fetchByKey which fails in speedy without calling back to the engine. val cmds = ImmArray( @@ -912,22 +902,20 @@ class EngineTest(majorLanguageVersion: LanguageVersion.Major, contractIdVersion: .consume(PartialFunction.empty, lookupPackage, lookupKey) inside(result) { case Left(Error.Interpretation(err, _)) => - err shouldBe - Interpretation.DamlException( - interpretation.Error.ContractKeyNotFound( - GlobalKey.assertBuild( - templateId = BasicTests_WithKey, - key = ValueRecord( - Some(BasicTests_WithKey), - ImmArray( - (Some[Ref.Name]("p"), ValueParty(alice)), - (Some[Ref.Name]("k"), ValueInt64(43)), - ), - ), - packageName = basicTestsPkg.pkgName, - ) + err shouldBe Interpretation.DamlException( + interpretation.Error.ContractKeyNotFound( + GlobalKey.assertBuild( + templateId = BasicTests_WithKey, + packageName = basicTestsPkg.pkgName, + key = sKey.toNormalizedValue, + keyHash = SValueHash.assertHashContractKey( + basicTestsPkg.pkgName, + Identifier(basicTestsPkgId, "BasicTests:WithKey").qualifiedName, + sKey, + ), ) ) + ) } } } @@ -2067,6 +2055,7 @@ class EngineTest(majorLanguageVersion: LanguageVersion.Major, contractIdVersion: val submissionSeed = hash("rollback") val seeding = Engine.initialSeeding(submissionSeed, participant, let) val cid = toContractId("1") + val sKey = mkSValuePair(SValue.SParty(party), SValue.SInt64(666)) val contracts = Map( cid -> TransactionBuilder.fatContractInstanceWithDummyDefaults( version = defaultSerializationVersion, @@ -2086,7 +2075,12 @@ class EngineTest(majorLanguageVersion: LanguageVersion.Major, contractIdVersion: GlobalKey.assertBuild( templateId = TypeConId(exceptionsPkgId, "Exceptions:K"), packageName = exceptionsPkg.pkgName, - key = ValueRecord(None, ImmArray((None, ValueParty(party)), (None, ValueInt64(666)))), + key = sKey.toNormalizedValue, + keyHash = SValueHash.assertHashContractKey( + exceptionsPkg.pkgName, + "Exceptions:K", + sKey, + ), ), Set(party), ) @@ -2229,6 +2223,7 @@ class EngineTest(majorLanguageVersion: LanguageVersion.Major, contractIdVersion: val submissionSeed = hash("rollback") val seeding = Engine.initialSeeding(submissionSeed, participant, let) val cid = toContractId("1") + val sKey = mkSValuePair(SValue.SParty(party), SValue.SInt64(777)) val contracts = Map( cid -> TransactionBuilder.fatContractInstanceWithDummyDefaults( version = defaultSerializationVersion, @@ -2248,7 +2243,12 @@ class EngineTest(majorLanguageVersion: LanguageVersion.Major, contractIdVersion: GlobalKey.assertBuild( templateId = TypeConId(exceptionsPkgId, "Exceptions:K"), packageName = exceptionsPkg.pkgName, - key = ValueRecord(None, ImmArray((None, ValueParty(party)), (None, ValueInt64(777)))), + key = sKey.toNormalizedValue, + keyHash = SValueHash.assertHashContractKey( + exceptionsPkg.pkgName, + "Exceptions:K", + sKey, + ), ), Set(party), ) @@ -2319,6 +2319,7 @@ class EngineTest(majorLanguageVersion: LanguageVersion.Major, contractIdVersion: val submissionSeed = hash("global-keys") val seeding = Engine.initialSeeding(submissionSeed, participant, let) val cid = toContractId("1") + val sKey = mkSValuePair(SValue.SParty(party), SValue.SInt64(0)) val contracts = Map( cid -> TransactionBuilder.fatContractInstanceWithDummyDefaults( version = defaultSerializationVersion, @@ -2338,7 +2339,12 @@ class EngineTest(majorLanguageVersion: LanguageVersion.Major, contractIdVersion: GlobalKey.assertBuild( templateId = TypeConId(exceptionsPkgId, "Exceptions:K"), packageName = exceptionsPkg.pkgName, - key = ValueRecord(None, ImmArray((None, ValueParty(party)), (None, ValueInt64(0)))), + key = sKey.toNormalizedValue, + keyHash = SValueHash.assertHashContractKey( + exceptionsPkg.pkgName, + "Exceptions:K", + sKey, + ), ), Set(party), ) @@ -3074,7 +3080,8 @@ class EngineTestHelpers( val withKeyTemplate = "BasicTests:WithKey" val BasicTests_WithKey: lf.data.Ref.ValueRef = Identifier(basicTestsPkgId, withKeyTemplate) - val withKeyContractInst: FatContractInstance = + val withKeyContractInst: FatContractInstance = { + val sKey = mkSValuePair(SValue.SParty(alice), SValue.SInt64(42)) TransactionBuilder.fatContractInstanceWithDummyDefaults( defaultSerializationVersion, packageName = basicTestsPkg.pkgName, @@ -3092,13 +3099,15 @@ class EngineTestHelpers( GlobalKeyWithMaintainers( GlobalKey.assertBuild( templateId = TypeConId(basicTestsPkgId, withKeyTemplate), - key = ValueRecord(None, ImmArray((None, ValueParty(alice)), (None, ValueInt64(42)))), packageName = basicTestsPkg.pkgName, + key = sKey.toNormalizedValue, + keyHash = SValueHash.assertHashContractKey(basicTestsPkg.pkgName, withKeyTemplate, sKey), ), Set(alice), ) ), ) + } val defaultContracts: Map[ContractId, FatContractInstance] = Map( @@ -3133,18 +3142,26 @@ class EngineTestHelpers( withKeyContractInst, ) - val defaultKey = Map( - GlobalKeyWithMaintainers( - GlobalKey.assertBuild( - templateId = TypeConId(basicTestsPkgId, withKeyTemplate), - key = ValueRecord(None, ImmArray((None, ValueParty(alice)), (None, ValueInt64(42)))), - packageName = basicTestsPkg.pkgName, - ), - Set(alice), + val defaultKey = { + val sKey = mkSValuePair(SValue.SParty(alice), SValue.SInt64(42)) + Map( + GlobalKeyWithMaintainers( + GlobalKey.assertBuild( + templateId = TypeConId(basicTestsPkgId, withKeyTemplate), + packageName = basicTestsPkg.pkgName, + key = sKey.toNormalizedValue, + keyHash = SValueHash.assertHashContractKey( + basicTestsPkg.pkgName, + withKeyTemplate.qualifiedName, + sKey, + ), + ), + Set(alice), + ) + -> + toContractId("BasicTests:WithKey:1") ) - -> - toContractId("BasicTests:WithKey:1") - ) + } val lookupContract = defaultContracts @@ -3191,6 +3208,13 @@ class EngineTestHelpers( def suffix(tx: VersionedTransaction): VersionedTransaction = data.assertRight(tx.suffixCid(_ => dummySuffixV1, _ => dummySuffixV2)) + def mkSValuePair(fst: SValue, snd: SValue) = + SValue.SRecord( + StablePackagesV2.Tuple2, + ImmArray(Ref.Name.assertFromString("_1"), Ref.Name.assertFromString("_2")), + ArraySeq(fst, snd), + ) + // Mimics Canton reinterpretation // requires a suffixed transaction. def reinterpret( diff --git a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EnricherSpec.scala b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EnricherSpec.scala index 0d3d231ab8d3..9af51a15339e 100644 --- a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EnricherSpec.scala +++ b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EnricherSpec.scala @@ -6,12 +6,13 @@ package engine import cats.Order import cats.data.NonEmptySet -import com.digitalasset.daml.lf.crypto.Hash +import com.digitalasset.daml.lf.crypto.{Hash, SValueHash} import com.digitalasset.daml.lf.data.Ref.PackageId import com.digitalasset.daml.lf.data._ import com.digitalasset.daml.lf.language.Ast.{TNat, TTyCon, Type} import com.digitalasset.daml.lf.language.Util._ import com.digitalasset.daml.lf.language.Ast +import com.digitalasset.daml.lf.speedy.SValue import com.digitalasset.daml.lf.testing.parser.Implicits.SyntaxHelper import com.digitalasset.daml.lf.testing.parser.ParserParameters import com.digitalasset.daml.lf.transaction.test.TestNodeBuilder.{ @@ -31,6 +32,8 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.prop.TableDrivenPropertyChecks import org.scalatest.wordspec.AnyWordSpec +import scala.collection.immutable.ArraySeq + class EnricherSpec extends AnyWordSpec with Matchers with Inside with TableDrivenPropertyChecks { import TransactionBuilder.Implicits.{defaultPackageId => _, _} @@ -308,6 +311,7 @@ class EnricherSpec extends AnyWordSpec with Matchers with Inside with TableDrive def buildTransaction( contract: Value, key: Value, + keyHash: crypto.Hash, record: Value, ): CommittedTransaction = { @@ -326,7 +330,7 @@ class EnricherSpec extends AnyWordSpec with Matchers with Inside with TableDrive argument = contract, signatories = Set("Alice"), observers = Set("Alice"), - key = CreateKey.SignatoryMaintainerKey(key), + key = CreateKey.SignatoryMaintainerKey(key, keyHash), version = CreateSerializationVersion.Version(SerializationVersion.minVersion), ) txBuilder.toCommittedTransaction( @@ -347,12 +351,18 @@ class EnricherSpec extends AnyWordSpec with Matchers with Inside with TableDrive "enrich transaction as expected" in { - val inputKey: ValueRecord = ValueRecord( - "", - ImmArray( - "" -> ValueParty("Alice"), - "" -> Value.ValueInt64(0), - ), + val inputKeySValue: SValue.SRecord = SValue.SRecord( + "Mod:Key", + ImmArray("party", "idx"), + ArraySeq(SValue.SParty("Alice"), SValue.SInt64(0)), + ) + + val inputKey: Value = inputKeySValue.toNormalizedValue + + val inputKeyHash: Hash = SValueHash.assertHashContractKey( + TestNodeBuilder.defaultPackageName, + "Mod:Key", + inputKeySValue, ) val inputContract: ValueRecord = @@ -370,6 +380,7 @@ class EnricherSpec extends AnyWordSpec with Matchers with Inside with TableDrive val inputTransaction = buildTransaction( inputContract, inputKey, + inputKeyHash, inputRecord, ) @@ -396,6 +407,7 @@ class EnricherSpec extends AnyWordSpec with Matchers with Inside with TableDrive val outputTransaction = buildTransaction( outputContract, outputKey, + inputKeyHash, outputRecord, ) diff --git a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/MetaDataTest.scala b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/MetaDataTest.scala index 4c74f9254320..7af17df8b56b 100644 --- a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/MetaDataTest.scala +++ b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/MetaDataTest.scala @@ -4,6 +4,7 @@ package com.digitalasset.daml.lf package engine +import com.digitalasset.daml.lf.crypto.SValueHash import com.digitalasset.daml.lf.transaction.test.TestNodeBuilder.{ CreateKey, CreateSerializationVersion, @@ -11,6 +12,7 @@ import com.digitalasset.daml.lf.transaction.test.TestNodeBuilder.{ import com.digitalasset.daml.lf.data.Ref import com.digitalasset.daml.lf.data.Ref.PackageId import com.digitalasset.daml.lf.language.LanguageVersion +import com.digitalasset.daml.lf.speedy.SValue import com.digitalasset.daml.lf.transaction.test.TransactionBuilder.Implicits._ import com.digitalasset.daml.lf.transaction.test.{ TestIdFactory, @@ -41,7 +43,14 @@ class MetaDataTest argument = ValueUnit, signatories = parties, observers = noOne, - key = CreateKey.SignatoryMaintainerKey(ValueParty("alice")), + key = CreateKey.SignatoryMaintainerKey( + ValueParty("alice"), + SValueHash.assertHashContractKey( + TestNodeBuilder.defaultPackageName, + "M:T", + SValue.SParty("alice"), + ), + ), version = CreateSerializationVersion.FromPackage, ) val nodeWithoutInterface = Table[TestNodeBuilder => Node]( @@ -74,7 +83,14 @@ class MetaDataTest argument = ValueUnit, signatories = parties, observers = noOne, - key = CreateKey.SignatoryMaintainerKey(ValueParty("alice")), + key = CreateKey.SignatoryMaintainerKey( + ValueParty("alice"), + SValueHash.assertHashContractKey( + TestNodeBuilder.defaultPackageName, + "M:T", + SValue.SParty("alice"), + ), + ), version = CreateSerializationVersion.FromPackage, ) val nodeWithInterface = Table[TestNodeBuilder => Node]( diff --git a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/PreprocessorSpec.scala b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/PreprocessorSpec.scala index 2209c53a01fc..c781669db9b2 100644 --- a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/PreprocessorSpec.scala +++ b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/PreprocessorSpec.scala @@ -6,11 +6,11 @@ package engine import com.daml.nameof.NameOf.qualifiedNameOfMember import com.digitalasset.daml.lf.command.{ApiCommand, ApiContractKey} -import com.digitalasset.daml.lf.crypto.Hash +import com.digitalasset.daml.lf.crypto.{Hash, SValueHash} import com.digitalasset.daml.lf.data.Ref.{PackageId, PackageName, PackageRef, PackageVersion, Party} import com.digitalasset.daml.lf.data.{Bytes, FrontStack, ImmArray, Ref} import com.digitalasset.daml.lf.language.{Ast, LanguageVersion, LookupError} -import com.digitalasset.daml.lf.speedy.{Command, Compiler} +import com.digitalasset.daml.lf.speedy.{Command, Compiler, SValue} import com.digitalasset.daml.lf.testing.parser.Implicits.SyntaxHelper import com.digitalasset.daml.lf.testing.parser.ParserParameters import com.digitalasset.daml.lf.transaction.test.TransactionBuilder.Implicits.{ @@ -228,10 +228,21 @@ class PreprocessorSpec "prefetchContractIdsAndKeys" should { val priority = Map(pkgName -> defaultPackageId) val bob: Party = Ref.Party.assertFromString("Bob") - val bobKey = ValueList(FrontStack(ValueParty(bob))) - - val globalKey1 = GlobalKey.assertBuild(withKeyTmplId, parties, pkgName) - val globalKey2 = GlobalKey.assertBuild(withKeyTmplId, bobKey, pkgName) + val bobKeySValue = SValue.SList(FrontStack(SValue.SParty(bob))) + val bobKey = bobKeySValue.toNormalizedValue + + val globalKey1 = GlobalKey.assertBuild( + withKeyTmplId, + pkgName, + parties, + SValueHash.assertHashContractKey(pkgName, withKeyTmplId.qualifiedName, partiesSValue), + ) + val globalKey2 = GlobalKey.assertBuild( + withKeyTmplId, + pkgName, + bobKey, + SValueHash.assertHashContractKey(pkgName, withKeyTmplId.qualifiedName, bobKeySValue), + ) "extract the keys from ExerciseByKey commands" in { val preprocessor = preprocessing.Preprocessor.forTesting(compilerConfig) @@ -364,7 +375,18 @@ class PreprocessorSpec ) inside(resultAllPrefetch) { case ResultPrefetch(contractIds, keys, resume) => contractIds.toSet shouldBe ((contractId +: moreContractIds).toSet) - keys shouldBe Seq(GlobalKey.assertBuild(withContractIdTmplId, parties, pkgName)) + keys shouldBe Seq( + GlobalKey.assertBuild( + withContractIdTmplId, + pkgName, + parties, + SValueHash.assertHashContractKey( + pkgName, + withContractIdTmplId.qualifiedName, + partiesSValue, + ), + ) + ) resume() shouldBe ResultDone.Unit } @@ -469,7 +491,8 @@ final class PreprocessorSpecHelpers { val alice: Party = Ref.Party.assertFromString("Alice") val bob: Party = Ref.Party.assertFromString("Bob") val signatories = immutable.TreeSet(alice) - val parties: ValueList = ValueList(FrontStack(ValueParty(alice))) + val partiesSValue = SValue.SList(FrontStack(SValue.SParty(alice))) + val parties = partiesSValue.toNormalizedValue val testKeyName: String = "test-key" val contractId: ContractId = Value.ContractId.V1.assertBuild( @@ -529,8 +552,9 @@ final class PreprocessorSpecHelpers { ), signatories = signatories, stakeholders = signatories, - contractKeyWithMaintainers = - key.map(k => GlobalKeyWithMaintainers.assertBuild(templateId, k, signatories, pkgName)), + contractKeyWithMaintainers = key.map(k => + GlobalKeyWithMaintainers.assertBuild(templateId, k, null, signatories, pkgName) + ), createdAt = CreationTime.CreatedAt(data.Time.Timestamp.Epoch), authenticationData = Bytes.Empty, ) diff --git a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala index 80d6b54647f2..77c5be2301d2 100644 --- a/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala +++ b/sdk/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala @@ -9,9 +9,11 @@ import com.daml.logging.LoggingContext import com.digitalasset.daml.lf.archive.DamlLf._ import com.digitalasset.daml.lf.archive.testing.Encode import com.digitalasset.daml.lf.command.ApiCommand +import com.digitalasset.daml.lf.crypto.SValueHash import com.digitalasset.daml.lf.data.Ref._ import com.digitalasset.daml.lf.data._ import com.digitalasset.daml.lf.language.{Ast, LanguageVersion} +import com.digitalasset.daml.lf.speedy.SValue import com.digitalasset.daml.lf.testing.parser.Implicits._ import com.digitalasset.daml.lf.testing.parser.{AstRewriter, ParserParameters} import com.digitalasset.daml.lf.transaction._ @@ -22,6 +24,7 @@ import org.scalatest.freespec.AsyncFreeSpec import org.scalatest.matchers.should.Matchers import scala.annotation.nowarn +import scala.collection.immutable.ArraySeq import scala.concurrent.Future import scala.language.implicitConversions @@ -314,18 +317,20 @@ class UpgradesMatrixCases( def additionalCreateArgsValue(@nowarn v1PkgId: PackageId): ImmArray[(Option[Name], Value)] = ImmArray.empty - // Used for creating disclosures of v1 contracts and the "lookup contract by key" map passed to the engine. - def additionalv1KeyArgsValue( + // Used for creating the "lookup contract by key" map passed to the engine. Specified as SValues instead of Values + // because the key hashing function acts on SValues. + def additionalv1KeyArgsSValue( @nowarn v1PkgId: PackageId, @nowarn setupData: SetupData, - ): ImmArray[(Option[Name], Value)] = - ImmArray.empty - // Used for creating *ByKey commands - def additionalv2KeyArgsValue( + ): List[(Name, SValue)] = + List.empty + // Used for creating *ByKey commands. Specified as SValues instead of Values because the key hashing function acts + // on SValues. + def additionalv2KeyArgsSValue( @nowarn v2PkgId: PackageId, @nowarn setupData: SetupData, - ): ImmArray[(Option[Name], Value)] = - ImmArray.empty + ): List[(Name, SValue)] = + List.empty // Used for looking up contracts by key in choice bodies def additionalv2KeyArgsLf(v2PkgId: PackageId): String = "" @@ -893,15 +898,12 @@ class UpgradesMatrixCases( override def v2Key = v1Key // Used for creating disclosures of v1 contracts and the "lookup contract by key" map passed to the engine. - override def additionalv1KeyArgsValue(pkgId: PackageId, setupData: SetupData) = - ImmArray( - None /* maintainers2 */ -> ValueList( - FrontStack(ValueParty(setupData.bob)) - ) - ) + override def additionalv1KeyArgsSValue(pkgId: PackageId, setupData: SetupData) = + List(("maintainers2": Name) -> SValue.SList(FrontStack(SValue.SParty(setupData.bob)))) + // Used for creating *ByKey commands - override def additionalv2KeyArgsValue(pkgId: PackageId, setupData: SetupData) = - additionalv1KeyArgsValue(pkgId, setupData) + override def additionalv2KeyArgsSValue(pkgId: PackageId, setupData: SetupData) = + additionalv1KeyArgsSValue(pkgId, setupData) // Used for looking up contracts by key in choice bodies override def additionalv2KeyArgsLf(v2PkgId: PackageId) = s", maintainers2 = (Cons @Party [Mod:Client {bob} this] (Nil @Party))" @@ -1634,10 +1636,8 @@ class UpgradesMatrixCases( override def additionalv2KeyArgsLf(v2PkgId: PackageId) = s", extra = None @Unit" - override def additionalv2KeyArgsValue(v2PkgId: PackageId, setupData: SetupData) = - ImmArray( - None /* extra */ -> ValueOptional(None) - ) + override def additionalv2KeyArgsSValue(v2PkgId: PackageId, setupData: SetupData) = + List(("extra": Name) -> SValue.SOptional(None)) override def v1Key = s""" | Mod:${templateName}Key { @@ -1660,10 +1660,8 @@ class UpgradesMatrixCases( override def additionalv2KeyArgsLf(v2PkgId: PackageId) = s", extra = None @Unit" - override def additionalv2KeyArgsValue(v2PkgId: PackageId, setupData: SetupData) = - ImmArray( - None /* extra */ -> ValueOptional(None) - ) + override def additionalv2KeyArgsSValue(v2PkgId: PackageId, setupData: SetupData) = + List(("extra": Name) -> SValue.SOptional(None)) override def v1Key = s""" | Mod:${templateName}Key { @@ -1704,13 +1702,8 @@ class UpgradesMatrixCases( override def v2AdditionalKeyFields: String = "" // Used for creating disclosures of v1 contracts and the "lookup contract by key" map passed to the engine. - override def additionalv1KeyArgsValue( - v1PkgId: PackageId, - setupData: SetupData, - ): ImmArray[(Option[Name], Value)] = - ImmArray( - None /* extra */ -> ValueOptional(Some(ValueUnit)) - ) + override def additionalv1KeyArgsSValue(v1PkgId: PackageId, setupData: SetupData) = + List(("extra": Name) -> SValue.SOptional(Some(SValue.SUnit))) override def v1Key = s""" | Mod:${templateName}Key { @@ -1953,8 +1946,11 @@ class UpgradesMatrixCases( val clientGlobalTplId: Identifier = Identifier(clientGlobalPkgId, "Mod:Client") val ifaceId: Identifier = Identifier(commonDefsPkgId, "Mod:Iface") val tplQualifiedName: QualifiedName = s"Mod:$templateName" + val keyQualifiedName: QualifiedName = s"Mod:${templateName}Key" val tplRef: TypeConRef = TypeConRef.assertFromString(s"#$templateDefsPkgName:Mod:$templateName") val v1TplId: Identifier = Identifier(templateDefsV1PkgId, tplQualifiedName) + val v1KeyId: Identifier = Identifier(templateDefsV1PkgId, keyQualifiedName) + val v2TplId: Identifier = Identifier(templateDefsV2PkgId, tplQualifiedName) def clientContractArg(alice: Party, bob: Party): ValueRecord = ValueRecord( None /* clientTplId */, @@ -1972,31 +1968,47 @@ class UpgradesMatrixCases( ).slowAppend(testCase.additionalCreateArgsValue(templateDefsV1PkgId)), ) - def globalContractv1Key(setupData: SetupData): ValueRecord = ValueRecord( - None, - ImmArray( - None /* label */ -> ValueText("test-key"), - None /* maintainers */ -> ValueList(FrontStack(ValueParty(setupData.alice))), - ).slowAppend(testCase.additionalv1KeyArgsValue(templateDefsV1PkgId, setupData)), - ) + def globalContractv1KeySValue(setupData: SetupData): SValue = { + val (additionalFields, additionalValues) = + testCase.additionalv1KeyArgsSValue(templateDefsV1PkgId, setupData).unzip + SValue.SRecord( + v1KeyId, + ImmArray.from(List[Name]("label", "maintainers") ++ additionalFields), + ArraySeq( + SValue.SText("test-key"), + SValue.SList(FrontStack(SValue.SParty(setupData.alice))), + ) ++ additionalValues, + ) + } - def globalContractv2Key(setupData: SetupData): ValueRecord = ValueRecord( - None, - ImmArray( - None /* label */ -> ValueText("test-key"), - None /* maintainers */ -> ValueList(FrontStack(ValueParty(setupData.alice))), - ).slowAppend(testCase.additionalv2KeyArgsValue(templateDefsV2PkgId, setupData)), - ) + def globalContractv2KeySValue(setupData: SetupData): SValue = { + val (additionalFields, additionalValues) = + testCase.additionalv2KeyArgsSValue(templateDefsV2PkgId, setupData).unzip + SValue.SRecord( + v2TplId, + ImmArray.from(List[Name]("label", "maintainers") ++ additionalFields), + ArraySeq( + SValue.SText("test-key"), + SValue.SList(FrontStack(SValue.SParty(setupData.alice))), + ) ++ additionalValues, + ) + } def globalContractKeyWithMaintainers(setupData: SetupData): Option[GlobalKeyWithMaintainers] = - whenKeysOtherwiseNone( + whenKeysOtherwiseNone { + val keySValue = globalContractv1KeySValue(setupData) GlobalKeyWithMaintainers.assertBuild( v1TplId, - globalContractv1Key(setupData), + keySValue.toNormalizedValue, + SValueHash.assertHashContractKey( + templateDefsPkgName, + v1TplId.qualifiedName, + keySValue, + ), Set(setupData.alice), templateDefsPkgName, ) - ) + } def makeApiCommands( operation: Operation, @@ -2102,7 +2114,7 @@ class UpgradesMatrixCases( ImmArray( ApiCommand.ExerciseByKey( tplRef, // we let package preference select v2 - globalContractv2Key(setupData), + globalContractv2KeySValue(setupData).toNormalizedValue, ChoiceName.assertFromString("TemplateChoice"), choiceArg, ) @@ -2117,7 +2129,7 @@ class UpgradesMatrixCases( ), ApiCommand.ExerciseByKey( tplRef, // we let package preference select v2 - globalContractv2Key(setupData), + globalContractv2KeySValue(setupData).toNormalizedValue, ChoiceName.assertFromString("TemplateChoice"), choiceArg, ), @@ -2136,7 +2148,7 @@ class UpgradesMatrixCases( case Fetch | FetchInterface | Exercise | ExerciseInterface => ValueContractId(setupData.globalContractId) case FetchByKey | LookupByKey | ExerciseByKey => - globalContractv2Key(setupData) + globalContractv2KeySValue(setupData).toNormalizedValue }, ) ) diff --git a/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/PartialTransaction.scala b/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/PartialTransaction.scala index 628c7803b069..8087d7ce4dd6 100644 --- a/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/PartialTransaction.scala +++ b/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/PartialTransaction.scala @@ -443,7 +443,7 @@ private[speedy] case class PartialTransaction( val auth = Authorize(context.info.authorizers) val nid = NodeId(nextNodeIdx) val node = Node.LookupByKey( - key.packageName, + key.globalKey.packageName, key.templateId, key.globalKeyWithMaintainers, result, diff --git a/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltinFun.scala b/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltinFun.scala index 670942e3c41c..010f367976f8 100644 --- a/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltinFun.scala +++ b/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltinFun.scala @@ -2108,7 +2108,7 @@ private[lf] object SBuiltinFun { IE.FetchEmptyContractKeyMaintainers( cachedKey.templateId, cachedKey.lfValue, - cachedKey.packageName, + cachedKey.globalKey.packageName, ) ) } else { @@ -2549,7 +2549,6 @@ private[lf] object SBuiltinFun { val keyValue = vals(keyIdx) val gkey = Speedy.Machine.assertGlobalKey(pkgName, templateId, keyValue) CachedKey( - packageName = pkgName, globalKeyWithMaintainers = GlobalKeyWithMaintainers( gkey, extractParties(NameOf.qualifiedNameOfCurrentFunc, vals(maintainerIdx)), diff --git a/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Speedy.scala b/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Speedy.scala index 7f62e432f31a..2856a23500ab 100644 --- a/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Speedy.scala +++ b/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Speedy.scala @@ -132,7 +132,6 @@ private[lf] object Speedy { sealed abstract class LedgerMode extends Product with Serializable final case class CachedKey( - packageName: PackageName, globalKeyWithMaintainers: GlobalKeyWithMaintainers, key: SValue, ) { @@ -1392,11 +1391,17 @@ private[lf] object Speedy { ) private[lf] def globalKey(pkgName: PackageName, templateId: TypeConId, keyValue: SValue) = { - val lfValue = keyValue.toNormalizedValue - GlobalKey - .build(templateId, lfValue, pkgName) - .toOption - } + for { + hash <- SValueHash.hashContractKey(pkgName, templateId.qualifiedName, keyValue) + res <- GlobalKey + .build( + templateId, + pkgName, + keyValue.toNormalizedValue, + hash, + ) + } yield res + }.toOption private[lf] def assertGlobalKey(pkgName: PackageName, templateId: TypeConId, keyValue: SValue) = globalKey(pkgName, templateId, keyValue) diff --git a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala index 2ae0b7692cd8..2d48780014dc 100644 --- a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala +++ b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala @@ -5,6 +5,7 @@ package com.digitalasset.daml.lf package speedy import com.daml.logging.LoggingContext +import com.digitalasset.daml.lf.crypto.SValueHash import com.digitalasset.daml.lf.data.Ref.{Location, PackageId, PackageName, Party} import com.digitalasset.daml.lf.data.{FrontStack, ImmArray, Ref} import com.digitalasset.daml.lf.interpretation.{Error => IE} @@ -329,6 +330,16 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) case _ => sys.error("unexpect error") } + private[this] val TKey = t"M:TKey" match { + case TTyCon(tycon) => tycon + case _ => sys.error("unexpect error") + } + + private[this] val Nested = t"M:Nested" match { + case TTyCon(tycon) => tycon + case _ => sys.error("unexpect error") + } + private[this] val Human = t"M:Human" match { case TTyCon(tycon) => tycon case _ => sys.error("unexpect error") @@ -357,6 +368,16 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) private[this] val emptyNestedValue = Value.ValueRecord(None, ImmArray.empty) + private[this] val keySValue = SRecord( + TKey, + ImmArray("maintainers", "optCid", "nested").map(Ref.Name.assertFromString), + ArraySeq( + SList(FrontStack(SParty(alice))), + SOptional(None), + SRecord(Nested, ImmArray(Ref.Name.assertFromString("f")), ArraySeq(SOptional(None))), + ), + ) + private[this] val keyValue = Value.ValueRecord( None, ImmArray( @@ -396,11 +417,13 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) observers = List(observer), contractKeyWithMaintainers = Some( GlobalKeyWithMaintainers( - GlobalKey.assertBuild( - templateId = T, - packageName = pkg.pkgName, - key = normalizedKeyValue, - ), + GlobalKey + .assertBuild( + templateId = T, + packageName = pkg.pkgName, + key = normalizedKeyValue, + keyHash = SValueHash.assertHashContractKey(pkg.pkgName, T.qualifiedName, keySValue), + ), Set(alice), ) ), @@ -442,6 +465,7 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) templateId = Human, packageName = pkg.pkgName, key = normalizedKeyValue, + keyHash = SValueHash.assertHashContractKey(pkg.pkgName, Human.qualifiedName, keySValue), ), Set(alice), ) @@ -453,7 +477,13 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) private[this] val getHelper = Map(helperCId -> helper) private[this] val getKey = Map( - GlobalKeyWithMaintainers.assertBuild(T, keyValue, Set(alice), pkg.pkgName) -> cId + GlobalKeyWithMaintainers.assertBuild( + T, + keyValue, + SValueHash.assertHashContractKey(pkg.pkgName, T.qualifiedName, keySValue), + Set(alice), + pkg.pkgName, + ) -> cId ) private[this] val dummyContract = TransactionBuilder.fatContractInstanceWithDummyDefaults( diff --git a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExceptionTest.scala b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExceptionTest.scala index 5572b74c4bcb..fa7da39b6776 100644 --- a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExceptionTest.scala +++ b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExceptionTest.scala @@ -4,7 +4,7 @@ package com.digitalasset.daml.lf package speedy -import com.digitalasset.daml.lf.crypto.Hash +import com.digitalasset.daml.lf.crypto.{Hash, SValueHash} import com.digitalasset.daml.lf.data.Ref.{PackageId, PackageName, Party} import com.digitalasset.daml.lf.data.{FrontStack, ImmArray, Ref} import com.digitalasset.daml.lf.interpretation.{Error => IE} @@ -1305,10 +1305,15 @@ class ExceptionTest extends AnyFreeSpec with Inside with Matchers with TableDriv ), ) val globalKey = GlobalKeyWithMaintainers.assertBuild( - templateId, - key.toNormalizedValue, - Set(alice), - templateDefsPkgName, + templateId = templateId, + value = key.toNormalizedValue, + valueHash = SValueHash.assertHashContractKey( + packageName = templateDefsPkgName, + templateName = templateId.qualifiedName, + key = key, + ), + maintainers = Set(alice), + packageName = templateDefsPkgName, ) val globalContract = TransactionBuilder.fatContractInstanceWithDummyDefaults( version = SerializationVersion.StableVersions.max, diff --git a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/UpgradeTest.scala b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/UpgradeTest.scala index 4b108c31ef83..4b3f7deff35f 100644 --- a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/UpgradeTest.scala +++ b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/UpgradeTest.scala @@ -530,10 +530,22 @@ class UpgradeTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChec ) val v1_key = - GlobalKeyWithMaintainers.assertBuild(i"'-pkg1-':M:T", ValueParty(alice), Set(alice), pkgName) + GlobalKeyWithMaintainers.assertBuild( + i"'-pkg1-':M:T", + ValueParty(alice), + null, + Set(alice), + pkgName, + ) val v2_key = - GlobalKeyWithMaintainers.assertBuild(i"'-pkg2-':M:T", ValueParty(alice), Set(alice), pkgName) + GlobalKeyWithMaintainers.assertBuild( + i"'-pkg2-':M:T", + ValueParty(alice), + null, + Set(alice), + pkgName, + ) "upgrade attempted" - { @@ -548,6 +560,7 @@ class UpgradeTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChec val v_missingFieldKey = GlobalKeyWithMaintainers.assertBuild( i"'-pkg2-':M:T", ValueParty(alice), + null, Set(alice), pkgName, ) @@ -607,6 +620,7 @@ class UpgradeTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChec val v_missingFieldKey = GlobalKeyWithMaintainers.assertBuild( i"'-pkg1-':M:T", ValueParty(alice), + null, Set(alice), pkgName, ) @@ -665,6 +679,7 @@ class UpgradeTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChec def key(templateId: Ref.TypeConId) = GlobalKeyWithMaintainers.assertBuild( templateId, ValueParty(alice), + null, Set(alice), pkgName, ) @@ -879,6 +894,7 @@ class UpgradeTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChec val v1_extraTextKey = GlobalKeyWithMaintainers.assertBuild( i"'-pkg1-':M:T", ValueParty(alice), + null, Set(alice), pkgName, ) @@ -940,6 +956,7 @@ class UpgradeTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChec val v1_extraSomeKey = GlobalKeyWithMaintainers.assertBuild( i"'-pkg3-':M:T", ValueParty(alice), + null, Set(alice), pkgName, ) @@ -1013,6 +1030,7 @@ class UpgradeTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChec val v1_extraNoneKey = GlobalKeyWithMaintainers.assertBuild( i"'-pkg3-':M:T", ValueParty(alice), + null, Set(alice), pkgName, ) @@ -1066,6 +1084,7 @@ class UpgradeTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChec val v1_extraNoneKey = GlobalKeyWithMaintainers.assertBuild( i"'-pkg3-':M:T", ValueParty(alice), + null, Set(alice), pkgName, ) diff --git a/sdk/daml-lf/transaction-test-lib/src/main/scala/com/digitalasset/daml/lf/transaction/test/TestNodeBuilder.scala b/sdk/daml-lf/transaction-test-lib/src/main/scala/com/digitalasset/daml/lf/transaction/test/TestNodeBuilder.scala index cfc8f14593b7..4085dcd3f0ae 100644 --- a/sdk/daml-lf/transaction-test-lib/src/main/scala/com/digitalasset/daml/lf/transaction/test/TestNodeBuilder.scala +++ b/sdk/daml-lf/transaction-test-lib/src/main/scala/com/digitalasset/daml/lf/transaction/test/TestNodeBuilder.scala @@ -56,13 +56,13 @@ trait TestNodeBuilder { val keyOpt = key match { case CreateKey.NoKey => None - case CreateKey.SignatoryMaintainerKey(value) => + case CreateKey.SignatoryMaintainerKey(value, hash) => Some( - GlobalKeyWithMaintainers.assertBuild(templateId, value, signatories, packageName) + GlobalKeyWithMaintainers.assertBuild(templateId, value, hash, signatories, packageName) ) - case CreateKey.KeyWithMaintainers(value, maintainers) => + case CreateKey.KeyWithMaintainers(value, hash, maintainers) => Some( - GlobalKeyWithMaintainers.assertBuild(templateId, value, maintainers, packageName) + GlobalKeyWithMaintainers.assertBuild(templateId, value, hash, maintainers, packageName) ) } @@ -152,8 +152,9 @@ object TestNodeBuilder extends TestNodeBuilder { sealed trait CreateKey object CreateKey { case object NoKey extends CreateKey - final case class SignatoryMaintainerKey(value: Value) extends CreateKey - final case class KeyWithMaintainers(value: Value, maintainers: Set[Party]) extends CreateKey + final case class SignatoryMaintainerKey(value: Value, hash: crypto.Hash) extends CreateKey + final case class KeyWithMaintainers(value: Value, hash: crypto.Hash, maintainers: Set[Party]) + extends CreateKey } sealed trait CreateSerializationVersion diff --git a/sdk/daml-lf/transaction-test-lib/src/main/scala/com/digitalasset/daml/lf/value/test/ValueGenerators.scala b/sdk/daml-lf/transaction-test-lib/src/main/scala/com/digitalasset/daml/lf/value/test/ValueGenerators.scala index 095c32e3c7ca..26e040762ff9 100644 --- a/sdk/daml-lf/transaction-test-lib/src/main/scala/com/digitalasset/daml/lf/value/test/ValueGenerators.scala +++ b/sdk/daml-lf/transaction-test-lib/src/main/scala/com/digitalasset/daml/lf/value/test/ValueGenerators.scala @@ -311,7 +311,14 @@ object ValueGenerators { for { key <- valueGen() maintainers <- genNonEmptyParties - gkey = GlobalKey.build(templateId, key, packageName).toOption + gkey = GlobalKey + .build( + templateId, + packageName, + key, + crypto.Hash.assertFromString("00" * crypto.Hash.underlyingHashLength), + ) + .toOption if gkey.isDefined } yield GlobalKeyWithMaintainers(gkey.get, maintainers) } diff --git a/sdk/daml-lf/transaction/BUILD.bazel b/sdk/daml-lf/transaction/BUILD.bazel index b30a41a26d57..7ceb45eb8f77 100644 --- a/sdk/daml-lf/transaction/BUILD.bazel +++ b/sdk/daml-lf/transaction/BUILD.bazel @@ -85,6 +85,7 @@ da_scala_test( "//canton:crypto", "//daml-lf/api-type-signature", "//daml-lf/data", + "//daml-lf/interpreter", "//daml-lf/language", "//daml-lf/transaction-test-lib", "@maven//:com_google_protobuf_protobuf_java", diff --git a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/GlobalKey.scala b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/GlobalKey.scala index 52fe0fbf0bae..5d914a8c739b 100644 --- a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/GlobalKey.scala +++ b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/GlobalKey.scala @@ -6,7 +6,7 @@ package transaction import com.digitalasset.daml.lf.crypto.Hash import com.digitalasset.daml.lf.data.Ref -import com.digitalasset.daml.lf.data.Ref.{Party, TypeConId} +import com.digitalasset.daml.lf.data.Ref.{PackageName, Party, TypeConId} import com.digitalasset.daml.lf.value.Value /** Useful in various circumstances -- basically this is what a ledger implementation must use as @@ -33,36 +33,25 @@ final class GlobalKey private ( object GlobalKey { def assertWithRenormalizedValue(key: GlobalKey, value: Value): GlobalKey = { - if ( - key.key != value && - Hash.assertHashContractKey(key.templateId, key.packageName, value) != key.hash - ) { - throw new IllegalArgumentException( - s"Hash must not change as a result of value renormalization key=$key, value=$value" - ) - } - new GlobalKey(key.templateId, key.packageName, value, key.hash) - } // Will fail if key contains contract ids def build( templateId: TypeConId, + packageName: PackageName, key: Value, - packageName: Ref.PackageName, - ): Either[crypto.Hash.HashingError, GlobalKey] = { - crypto.Hash - .hashContractKey(templateId, packageName, key) - .map(new GlobalKey(templateId, packageName, key, _)) - } + keyHash: crypto.Hash, + ): Either[crypto.Hash.HashingError, GlobalKey] = + Right(new GlobalKey(templateId, packageName, key, keyHash)) def assertBuild( templateId: TypeConId, + packageName: PackageName, key: Value, - packageName: Ref.PackageName, + keyHash: crypto.Hash, ): GlobalKey = { - data.assertRight(build(templateId, key, packageName).left.map(_.msg)) + data.assertRight(build(templateId, packageName, key, keyHash).left.map(_.msg)) } private[lf] def unapply(globalKey: GlobalKey): Some[(TypeConId, Value)] = @@ -89,18 +78,22 @@ object GlobalKeyWithMaintainers { def assertBuild( templateId: TypeConId, value: Value, + valueHash: crypto.Hash, maintainers: Set[Party], - packageName: Ref.PackageName, + packageName: PackageName, ): GlobalKeyWithMaintainers = - data.assertRight(build(templateId, value, maintainers, packageName).left.map(_.msg)) + data.assertRight(build(templateId, value, valueHash, maintainers, packageName).left.map(_.msg)) def build( templateId: TypeConId, value: Value, + valueHash: crypto.Hash, maintainers: Set[Party], - packageName: Ref.PackageName, + packageName: PackageName, ): Either[Hash.HashingError, GlobalKeyWithMaintainers] = - GlobalKey.build(templateId, value, packageName).map(GlobalKeyWithMaintainers(_, maintainers)) + GlobalKey + .build(templateId, packageName, value, valueHash) + .map(GlobalKeyWithMaintainers(_, maintainers)) } /** Controls whether the engine should error out when it encounters duplicate keys. diff --git a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala index 29d92a807801..9bd8c39a7116 100644 --- a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala +++ b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala @@ -289,6 +289,7 @@ object Node { GlobalKeyWithMaintainers.assertBuild( gk.globalKey.templateId, gk.value, + gk.globalKey.hash, gk.maintainers, gk.globalKey.packageName, ) diff --git a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Normalization.scala b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Normalization.scala index ab4f19e5c28d..3cea542f0d10 100644 --- a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Normalization.scala +++ b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Normalization.scala @@ -96,7 +96,7 @@ class Normalization { case GlobalKeyWithMaintainers(key, maintainers) => GlobalKeyWithMaintainers( GlobalKey - .assertBuild(key.templateId, normValue(version)(key.key), key.packageName), + .assertBuild(key.templateId, key.packageName, normValue(version)(key.key), key.hash), maintainers, ) } diff --git a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala index 9db5bc608a88..49bfca7e9a8c 100644 --- a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala +++ b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala @@ -4,15 +4,15 @@ package com.digitalasset.daml.lf package transaction +import com.daml.scalautil.Statement.discard +import com.digitalasset.daml.lf.data.Ref.{Name, Party} import com.digitalasset.daml.lf.data.{BackStack, ImmArray, Ref, Time} import com.digitalasset.daml.lf.transaction.TransactionOuterClass.Node.NodeTypeCase -import com.digitalasset.daml.lf.data.Ref.{Name, Party} import com.digitalasset.daml.lf.value.{DecodeError, EncodeError, Value, ValueOuterClass} -import com.daml.scalautil.Statement.discard import com.google.protobuf.{ByteString, ProtocolStringList} -import scala.annotation.nowarn import scala.Ordering.Implicits.infixOrderingOps +import scala.annotation.nowarn import scala.collection.immutable.{HashMap, TreeSet} import scala.jdk.CollectionConverters._ @@ -155,9 +155,7 @@ class TransactionCoder(allowNullCharacters: Boolean) { if (version >= SerializationVersion.minVersion) { val builder = TransactionOuterClass.KeyWithMaintainers.newBuilder() TreeSet.from(key.maintainers).foreach(builder.addMaintainers(_)) - ValueCoder - .encodeValue(valueVersion = version, v0 = key.value) - .map(builder.setKey(_).build()) + ValueCoder.encodeKey(version, key.globalKey).map(bs => builder.setKey(bs).build) } else Left(EncodeError(s"Contract key are not supported by $version")) @@ -352,14 +350,7 @@ class TransactionCoder(allowNullCharacters: Boolean) { ): Either[DecodeError, GlobalKeyWithMaintainers] = { for { maintainers <- toPartySet(msg.getMaintainersList) - value <- decodeValue( - version = version, - unversionedProto = msg.getKey, - ) - gkey <- GlobalKey - .build(templateId, value, packageName) - .left - .map(hashErr => DecodeError(hashErr.msg)) + gkey <- ValueCoder.decodeKey(templateId, packageName, version, msg.getKey) } yield GlobalKeyWithMaintainers(gkey, maintainers) } diff --git a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Util.scala b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Util.scala index 5104d58ddb4b..1a9edb819a9a 100644 --- a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Util.scala +++ b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Util.scala @@ -77,7 +77,12 @@ object Util { ): Either[String, GlobalKeyWithMaintainers] = normalizeValue(key.globalKey.key, version).map(normalized => key.copy(globalKey = - GlobalKey.assertBuild(key.globalKey.templateId, normalized, key.globalKey.packageName) + GlobalKey.assertBuild( + key.globalKey.templateId, + key.globalKey.packageName, + normalized, + key.globalKey.hash, + ) ) ) diff --git a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/ValueCoder.scala b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/ValueCoder.scala index 4fe513edf3c1..5974a589390d 100644 --- a/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/ValueCoder.scala +++ b/sdk/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/ValueCoder.scala @@ -9,6 +9,7 @@ import com.daml.SafeProto import com.digitalasset.daml.lf.data.Ref._ import com.digitalasset.daml.lf.data._ import com.digitalasset.daml.lf.transaction.{ + GlobalKey, SerializationVersion, Versioned, ensuresNoUnknownFields, @@ -458,5 +459,35 @@ class ValueCoder(allowNullCharacters: Boolean) { } } + def encodeKey(version: SerializationVersion, key: GlobalKey): Either[EncodeError, ByteString] = + encodeValue(valueVersion = version, v0 = key.key) + .map(bs => key.hash.bytes.toByteString.concat(bs)) + + def decodeKey( + templateId: Ref.TypeConId, + packageName: Ref.PackageName, + version: SerializationVersion, + bytes: ByteString, + ): Either[DecodeError, GlobalKey] = { + val hashBytesLength = crypto.Hash.underlyingHashLength + if (bytes.size < hashBytesLength) { + Left( + DecodeError( + s"ByteString too short to contain a GlobalKey hash. Expected at least $hashBytesLength bytes, got ${bytes.size}" + ) + ) + } else { + val hashBs = bytes.substring(0, hashBytesLength) + val valueBs = bytes.substring(hashBytesLength) + for { + hash <- crypto.Hash.fromBytes(Bytes.fromByteString(hashBs)).left.map(DecodeError(_)) + value <- decodeValue(version, valueBs) + gkey <- GlobalKey + .build(templateId, packageName, value, hash) + .left + .map(hashErr => DecodeError(hashErr.msg)) + } yield gkey + } + } } } diff --git a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/crypto/NodeHashV1Spec.scala b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/crypto/NodeHashV1Spec.scala index 9a23da7b9b9a..e304a413e43e 100644 --- a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/crypto/NodeHashV1Spec.scala +++ b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/crypto/NodeHashV1Spec.scala @@ -36,8 +36,9 @@ class NodeHashV1Spec extends AnyWordSpec with Matchers with HashUtils { private val globalKey = GlobalKeyWithMaintainers( GlobalKey.assertBuild( defRef("module_key", "name"), - VA.text.inj("hello"), PackageName.assertFromString("package_name_key"), + VA.text.inj("hello"), + null, ), Set[Party](Ref.Party.assertFromString("david")), ) @@ -45,8 +46,9 @@ class NodeHashV1Spec extends AnyWordSpec with Matchers with HashUtils { private val globalKey2 = GlobalKeyWithMaintainers( GlobalKey.assertBuild( defRef("module_key", "name"), - VA.text.inj("bye"), PackageName.assertFromString("package_name_key"), + VA.text.inj("bye"), + null, ), Set[Party](Ref.Party.assertFromString("david")), ) diff --git a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/ContractStateMachineSpec.scala b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/ContractStateMachineSpec.scala index 53bd23c0cc74..16ec6ae1f8fe 100644 --- a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/ContractStateMachineSpec.scala +++ b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/ContractStateMachineSpec.scala @@ -5,14 +5,10 @@ package com.digitalasset.daml package lf package transaction +import com.digitalasset.daml.lf.crypto.SValueHash import com.digitalasset.daml.lf.data.{ImmArray, Ref} -import com.digitalasset.daml.lf.transaction.ContractStateMachine.{ - ActiveLedgerState, - KeyActive, - KeyInactive, - KeyMapping, - KeyResolver, -} +import com.digitalasset.daml.lf.speedy.SValue +import com.digitalasset.daml.lf.transaction.ContractStateMachine._ import com.digitalasset.daml.lf.transaction.ContractStateMachineSpec._ import com.digitalasset.daml.lf.transaction.Transaction.{ ChildrenRecursion, @@ -26,13 +22,13 @@ import com.digitalasset.daml.lf.transaction.TransactionErrors.{ InconsistentContractKey, KeyInputError, } -import com.digitalasset.daml.lf.transaction.test.{NodeIdTransactionBuilder, TestNodeBuilder} import com.digitalasset.daml.lf.transaction.test.TransactionBuilder.Implicits.{ defaultPackageId, toIdentifier, toName, toParty, } +import com.digitalasset.daml.lf.transaction.test.{NodeIdTransactionBuilder, TestNodeBuilder} import com.digitalasset.daml.lf.value.Value import com.digitalasset.daml.lf.value.Value.ContractId import org.scalatest.matchers.should.Matchers @@ -67,7 +63,13 @@ class ContractStateMachineSpec extends AnyWordSpec with Matchers with TableDrive templateId: Ref.TypeConId, key: String, ): GlobalKeyWithMaintainers = - GlobalKeyWithMaintainers.assertBuild(templateId, Value.ValueText(key), aliceS, pkgName) + GlobalKeyWithMaintainers.assertBuild( + templateId, + Value.ValueText(key), + SValueHash.assertHashContractKey(pkgName, templateId.qualifiedName, SValue.SText(key)), + aliceS, + pkgName, + ) private def toOptKeyWithMaintainers( templateId: Ref.TypeConId, @@ -77,7 +79,12 @@ class ContractStateMachineSpec extends AnyWordSpec with Matchers with TableDrive else Some(toKeyWithMaintainers(templateId, key)) def gkey(key: String): GlobalKey = - GlobalKey.assertBuild(templateId, Value.ValueText(key), pkgName) + GlobalKey.assertBuild( + templateId, + pkgName, + Value.ValueText(key), + SValueHash.assertHashContractKey(pkgName, templateId.qualifiedName, SValue.SText(key)), + ) def mkCreate( contractId: ContractId, diff --git a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/FatContractInstanceSpec.scala b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/FatContractInstanceSpec.scala index 3d783da7d429..0bcddd50b9c4 100644 --- a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/FatContractInstanceSpec.scala +++ b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/FatContractInstanceSpec.scala @@ -78,8 +78,9 @@ class FatContractInstanceSpec extends AnyFreeSpec with Matchers with TableDriven .build( templateId = Ref.Identifier.assertFromString("-dummyPkg-:NotTemplateModule:dummyName"), value = Value.ValueText("key1"), - packageName = node.packageName, + null, maintainers = node.signatories, + packageName = node.packageName, ) .toOption diff --git a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala index b9b33a16ea41..82020515fd9b 100644 --- a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala +++ b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala @@ -797,8 +797,9 @@ class TransactionCoderSpec key.copy(globalKey = GlobalKey.assertBuild( key.globalKey.templateId, - normalize(key.value, version), key.globalKey.packageName, + normalize(key.value, version), + key.globalKey.hash, ) ) diff --git a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionNodeStatisticsSpec.scala b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionNodeStatisticsSpec.scala index f549086d4ee1..d4e4ba311c6b 100644 --- a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionNodeStatisticsSpec.scala +++ b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionNodeStatisticsSpec.scala @@ -4,6 +4,8 @@ package com.digitalasset.daml.lf package transaction +import com.digitalasset.daml.lf.crypto.SValueHash +import com.digitalasset.daml.lf.speedy.SValue import com.digitalasset.daml.lf.transaction.test.TestNodeBuilder.CreateKey import com.digitalasset.daml.lf.transaction.test.TestNodeBuilder.CreateKey.NoKey import com.digitalasset.daml.lf.transaction.TransactionNodeStatistics.Actions @@ -62,14 +64,22 @@ class TransactionNodeStatisticsSpec def create(b: TxBuilder, withKey: Boolean = false) = { val parties = Set(b.newParty) + val templateId = b.newIdentifier + val packageName = b.newPackageName b.create( id = b.newCid, - packageName = b.newPackageName, - templateId = b.newIdentifier, + packageName = packageName, + templateId = templateId, argument = Value.ValueUnit, signatories = parties, observers = Set.empty, - key = if (withKey) CreateKey.SignatoryMaintainerKey(Value.ValueUnit) else NoKey, + key = + if (withKey) + CreateKey.SignatoryMaintainerKey( + Value.ValueUnit, + SValueHash.assertHashContractKey(packageName, templateId.qualifiedName, SValue.SUnit), + ) + else NoKey, ) } diff --git a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala index a8c6fb974b6e..9378d85f4c40 100644 --- a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala +++ b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala @@ -6,8 +6,9 @@ package transaction import com.digitalasset.daml.lf.transaction.test.TestNodeBuilder.CreateKey import com.digitalasset.daml.lf.transaction.test.TestNodeBuilder.CreateKey.NoKey -import com.digitalasset.daml.lf.crypto.Hash +import com.digitalasset.daml.lf.crypto.{Hash, SValueHash} import com.digitalasset.daml.lf.data.{Bytes, ImmArray, Ref} +import com.digitalasset.daml.lf.speedy.SValue import com.digitalasset.daml.lf.transaction.Transaction.{ AliasedNode, ChildrenRecursion, @@ -314,14 +315,22 @@ class TransactionSpec def create(s: V.ContractId) = { println(s) + val templateId: Ref.TypeConId = s"Mod:t${s.coid}" builder .create( id = s, - templateId = s"Mod:t${s.coid}", + templateId = templateId, argument = V.ValueUnit, signatories = parties, observers = parties, - key = CreateKey.SignatoryMaintainerKey(V.ValueText(s.coid)), + key = CreateKey.SignatoryMaintainerKey( + V.ValueText(s.coid), + SValueHash.assertHashContractKey( + TestNodeBuilder.defaultPackageName, + templateId.qualifiedName, + SValue.SText(s.coid), + ), + ), ) } @@ -406,8 +415,15 @@ class TransactionSpec "RolledBackUnsuccessfulLookup", ).map(s => { val node = create(cid(s)) + val keySValue = SValue.SText(cid(s).coid) GlobalKey - .assertBuild(node.templateId, V.ValueText(cid(s).coid), node.packageName) + .assertBuild( + node.templateId, + node.packageName, + keySValue.toNormalizedValue, + SValueHash + .assertHashContractKey(node.packageName, node.templateId.qualifiedName, keySValue), + ) }).toSet builder.build().contractKeys shouldBe expectedResults @@ -420,7 +436,13 @@ class TransactionSpec val parties = List("Alice") val keyPkgName = Ref.PackageName.assertFromString("key-package-name") def keyValue(s: String) = V.ValueText(s) - def globalKey(k: String) = GlobalKey.assertBuild("Mod:T", keyValue(k), keyPkgName) + def keyHash(s: String) = SValueHash.assertHashContractKey(keyPkgName, "Mod:T", SValue.SText(s)) + def globalKey(k: String) = GlobalKey.assertBuild( + "Mod:T", + keyPkgName, + keyValue(k), + keyHash(k), + ) def create(s: V.ContractId, k: String) = dummyBuilder .create( id = s, @@ -428,7 +450,7 @@ class TransactionSpec argument = V.ValueUnit, signatories = parties, observers = parties, - key = CreateKey.SignatoryMaintainerKey(keyValue(k)), + key = CreateKey.SignatoryMaintainerKey(keyValue(k), keyHash(k)), packageName = keyPkgName, ) @@ -675,7 +697,16 @@ class TransactionSpec argument = V.ValueUnit, signatories = parties, observers = Seq(), - key = key.fold[CreateKey](NoKey)(s => CreateKey.SignatoryMaintainerKey(V.ValueText(s))), + key = key.fold[CreateKey](NoKey)(s => + CreateKey.SignatoryMaintainerKey( + V.ValueText(s), + SValueHash.assertHashContractKey( + TestNodeBuilder.defaultPackageName, + "Mod:T", + SValue.SText(s), + ), + ) + ), ) (cid, node) } @@ -750,7 +781,12 @@ class TransactionSpec builder.add(exercise(builder, create3, parties, true), rollback) builder.add(create4, rollback) - def key(s: String) = GlobalKey.assertBuild("Mod:T", V.ValueText(s), create0.packageName) + def key(s: String) = GlobalKey.assertBuild( + "Mod:T", + create0.packageName, + V.ValueText(s), + SValueHash.assertHashContractKey(create0.packageName, "Mod:T", SValue.SText(s)), + ) builder.build().updatedContractKeys shouldBe Map(key("key0") -> Some(cid0), key("key1") -> None, key("key2") -> Some(cid3)) } diff --git a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/ValidationSpec.scala b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/ValidationSpec.scala index b1e9f15acdcd..c016ddcc1032 100644 --- a/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/ValidationSpec.scala +++ b/sdk/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/ValidationSpec.scala @@ -77,11 +77,11 @@ class ValidationSpec extends AnyFreeSpec with Matchers with TableDrivenPropertyC private val samValue2: Val = V.ValueText(samContractId1.coid) private val samKWM1 = - GlobalKeyWithMaintainers.assertBuild(samTemplateId1, samValue1, samParties1, somePkgName) + GlobalKeyWithMaintainers.assertBuild(samTemplateId1, samValue1, null, samParties1, somePkgName) private val samKWM2 = - GlobalKeyWithMaintainers.assertBuild(samTemplateId1, samValue1, samParties2, somePkgName) + GlobalKeyWithMaintainers.assertBuild(samTemplateId1, samValue1, null, samParties2, somePkgName) private val samKWM3 = - GlobalKeyWithMaintainers.assertBuild(samTemplateId2, samValue2, samParties1, somePkgName) + GlobalKeyWithMaintainers.assertBuild(samTemplateId2, samValue2, null, samParties1, somePkgName) private val samVersion1: SerializationVersion = SerializationVersion.minVersion private val samVersion2: SerializationVersion = SerializationVersion.maxVersion diff --git a/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/GrpcErrorParser.scala b/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/GrpcErrorParser.scala index 210948a8cbe8..d456465b8689 100644 --- a/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/GrpcErrorParser.scala +++ b/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/GrpcErrorParser.scala @@ -96,6 +96,7 @@ object GrpcErrorParser { GlobalKeyWithMaintainers.assertBuild( templateId, globalKey, + null, parseParties(maintainers), PackageName.assertFromString(packageName), ) @@ -142,7 +143,7 @@ object GrpcErrorParser { val templateId = Identifier.assertFromString(tid) val packageName = PackageName.assertFromString(pn) SubmitError.ContractKeyNotFound( - GlobalKey.assertBuild(templateId, key, packageName) + GlobalKey.assertBuild(templateId, packageName, key, keyHash = null) ) } case "DAML_AUTHORIZATION_ERROR" => SubmitError.AuthorizationError(message) @@ -180,7 +181,7 @@ object GrpcErrorParser { val packageName = PackageName.assertFromString(pn) SubmitError.DisclosedContractKeyHashingError( ContractId.assertFromString(cid), - GlobalKey.assertBuild(templateId, key, packageName), + GlobalKey.assertBuild(templateId, packageName, key, keyHash = null), keyHash, ) } @@ -194,7 +195,7 @@ object GrpcErrorParser { val templateId = Identifier.assertFromString(tid) val packageName = PackageName.assertFromString(pn) SubmitError.DuplicateContractKey( - Some(GlobalKey.assertBuild(templateId, key, packageName)) + Some(GlobalKey.assertBuild(templateId, packageName, key, keyHash = null)) ) // TODO[SW] Canton can omit the key, unsure why. case Seq() => SubmitError.DuplicateContractKey(None) @@ -224,7 +225,7 @@ object GrpcErrorParser { val templateId = Identifier.assertFromString(tid) val packageName = PackageName.assertFromString(pn) SubmitError.InconsistentContractKey( - GlobalKey.assertBuild(templateId, key, packageName) + GlobalKey.assertBuild(templateId, packageName, key, keyHash = null) ) } case "UNHANDLED_EXCEPTION" => @@ -259,7 +260,7 @@ object GrpcErrorParser { val templateId = Identifier.assertFromString(tid) val packageName = PackageName.assertFromString(pn) SubmitError.FetchEmptyContractKeyMaintainers( - GlobalKey.assertBuild(templateId, key, packageName) + GlobalKey.assertBuild(templateId, packageName, key, keyHash = null) ) } case "WRONGLY_TYPED_CONTRACT" => diff --git a/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/IdeLedgerClient.scala b/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/IdeLedgerClient.scala index 549a318e3aa5..161d01e10c6e 100644 --- a/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/IdeLedgerClient.scala +++ b/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/IdeLedgerClient.scala @@ -7,45 +7,30 @@ package script package v2 package ledgerinteraction -import org.apache.pekko.stream.Materializer import com.daml.grpc.adapter.ExecutionSequencerFactory -import com.digitalasset.canton.ledger.api.{ - IdentityProviderId, - ObjectMeta, - PartyDetails, - User, - UserRight, -} -import com.digitalasset.daml.lf.command.ApiCommand +import com.daml.nonempty.NonEmpty +import com.digitalasset.canton.ledger.api._ +import com.digitalasset.canton.ledger.localstore.InMemoryUserManagementStore +import com.digitalasset.canton.logging.{LoggingContextWithTrace, NamedLoggerFactory} +import com.digitalasset.daml.lf.command.{ApiCommand, ApiContractKey} import com.digitalasset.daml.lf.data.Ref._ import com.digitalasset.daml.lf.data.{Bytes, ImmArray, Ref, Time} import com.digitalasset.daml.lf.engine.ScriptEngine.{ + ExtendedValueComputationMode, TraceLog, WarningLog, runExtendedValueComputation, - ExtendedValueComputationMode, } import com.digitalasset.daml.lf.interpretation.Error.ContractIdInContractKey -import com.digitalasset.daml.lf.language.{Ast, LanguageVersion, LookupError, Reference} import com.digitalasset.daml.lf.language.Ast.PackageMetadata -import com.digitalasset.daml.lf.script.{IdeLedger, IdeLedgerRunner} +import com.digitalasset.daml.lf.language.{Ast, LanguageVersion, LookupError, Reference} import com.digitalasset.daml.lf.script +import com.digitalasset.daml.lf.script.{IdeLedger, IdeLedgerRunner} import com.digitalasset.daml.lf.speedy.{Pretty, SError} -import com.digitalasset.daml.lf.transaction.{ - CreationTime, - FatContractInstance, - GlobalKey, - IncompleteTransaction, - Node, - NodeId, - Transaction, - TransactionCoder, -} +import com.digitalasset.daml.lf.transaction._ import com.digitalasset.daml.lf.value.Value import com.digitalasset.daml.lf.value.Value.ContractId -import com.daml.nonempty.NonEmpty -import com.digitalasset.canton.logging.{LoggingContextWithTrace, NamedLoggerFactory} -import com.digitalasset.canton.ledger.localstore.InMemoryUserManagementStore +import org.apache.pekko.stream.Materializer import scalaz.OneAnd import scalaz.OneAnd._ import scalaz.std.set._ @@ -295,6 +280,26 @@ class IdeLedgerClient( } } + private[this] def preprocessKey(templateId: Identifier, key: Value)(implicit + ec: ExecutionContext + ): Future[GlobalKey] = + Future( + preprocessor.unsafePreprocessApiContractKey( + Map.empty.withDefault((name: Ref.PackageName) => + throw new IllegalStateException( + s"Unexpected package lookup by name (${name}) during contract key preprocessing." + ) + ), + ApiContractKey(templateId.toRef, key), + ) + ).recoverWith { case Error.Preprocessing.ContractIdInContractKey(key) => + Future.failed( + new RuntimeException( + Pretty.prettyDamlException(ContractIdInContractKey(key)).renderWideStream.mkString + ) + ) + } + override def queryContractKey( parties: OneAnd[Set, Ref.Party], templateId: Identifier, @@ -302,34 +307,14 @@ class IdeLedgerClient( )(implicit ec: ExecutionContext, mat: Materializer, - ): Future[Option[ScriptLedgerClient.ActiveContract]] = { - def keyBuilderError(err: crypto.Hash.HashingError): Future[GlobalKey] = - Future.failed( - err match { - case crypto.Hash.HashingError.ForbiddenContractId() => - new RuntimeException( - Pretty - .prettyDamlException(ContractIdInContractKey(key)) - .renderWideStream - .mkString - ) - } - ) - - val pkg = compiledPackages.pkgInterface - .lookupPackage(templateId.packageId) - .getOrElse(throw new IllegalArgumentException(s"Unknown package ${templateId.packageId}")) - - GlobalKey - .build(templateId, key, pkg.pkgName) - .fold(keyBuilderError(_), Future.successful(_)) - .flatMap { gkey => - ledger.ledgerData.activeKeys.get(gkey) match { - case None => Future.successful(None) - case Some(cid) => queryContractId(parties, templateId, cid) - } + ): Future[Option[ScriptLedgerClient.ActiveContract]] = + for { + gkey <- preprocessKey(templateId, key) + res <- ledger.ledgerData.activeKeys.get(gkey) match { + case None => Future.successful(None) + case Some(cid) => queryContractId(parties, templateId, cid) } - } + } yield res private def getTypeIdentifier(t: Ast.Type): Option[Identifier] = t match { @@ -374,7 +359,7 @@ class IdeLedgerClient( SubmitError.CreateEmptyContractKeyMaintainers(tid, arg) case FetchEmptyContractKeyMaintainers(tid, keyValue, packageName) => SubmitError.FetchEmptyContractKeyMaintainers( - GlobalKey.assertBuild(tid, keyValue, packageName) + GlobalKey.assertBuild(tid, packageName, keyValue, null) ) case WronglyTypedContract(cid, exp, act) => SubmitError.WronglyTypedContract(cid, exp, act) case ContractDoesNotImplementInterface(iid, cid, tid) => diff --git a/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/grpcLedgerClient/GrpcLedgerClient.scala b/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/grpcLedgerClient/GrpcLedgerClient.scala index deb8af297956..c83446a7c4fb 100644 --- a/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/grpcLedgerClient/GrpcLedgerClient.scala +++ b/sdk/daml-script/runner/src/main/scala/com/digitalasset/daml/lf/engine/script/v2/ledgerinteraction/grpcLedgerClient/GrpcLedgerClient.scala @@ -7,7 +7,6 @@ package grpcLedgerClient import java.time.Instant import java.util.UUID - import org.apache.pekko.stream.Materializer import com.daml.grpc.adapter.ExecutionSequencerFactory import com.digitalasset.canton.ledger.api.{PartyDetails, User, UserRight} @@ -18,8 +17,8 @@ import com.daml.ledger.api.v2.admin.package_management_service.{ } import com.daml.ledger.api.v2.admin.package_management_service.VettedPackagesChange.{ Operation, - Vet, Unvet, + Vet, } import com.daml.ledger.api.v2.commands.Commands import com.daml.ledger.api.v2.commands._ @@ -45,11 +44,10 @@ import com.daml.timer.RetryStrategy import com.digitalasset.daml.lf.CompiledPackages import com.digitalasset.canton.ledger.client.LedgerClient import com.digitalasset.daml.lf.command -import com.digitalasset.daml.lf.crypto.Hash import com.digitalasset.daml.lf.data.Ref._ import com.digitalasset.daml.lf.data.{Bytes, Ref, Time} import com.digitalasset.daml.lf.engine.script.v2.Converter -import com.digitalasset.daml.lf.engine.{Enricher, ResultDone} +import com.digitalasset.daml.lf.engine.{Enricher, ResultDone, preprocessing} import com.digitalasset.daml.lf.language.{Ast, LanguageVersion, Reference} import com.digitalasset.daml.lf.value.Value import com.digitalasset.daml.lf.value.Value.ContractId @@ -61,6 +59,7 @@ import com.digitalasset.canton.ledger.api.util.LfEngineToApi.{ } import com.digitalasset.daml.lf.script.converter.ConverterException import com.digitalasset.canton.tracing.TraceContext +import com.digitalasset.daml.lf.command.ApiContractKey import io.grpc.{Status, StatusRuntimeException} import io.grpc.protobuf.StatusProto import com.google.rpc.status.{Status => GoogleStatus} @@ -70,6 +69,7 @@ import scalaz.std.either._ import scalaz.std.list._ import scalaz.std.set._ import scalaz.syntax.foldable._ +import com.digitalasset.daml.lf.crypto import scala.concurrent.{ExecutionContext, Future} import scala.concurrent.duration.DurationInt @@ -83,6 +83,11 @@ class GrpcLedgerClient( override val transport = "gRPC API" implicit val traceContext: TraceContext = TraceContext.empty + private[this] val preprocessor = new preprocessing.CommandPreprocessor( + compiledPackages.pkgInterface, + forbidLocalContractIds = true, + ) + val enricher = new Enricher( compiledPackages = compiledPackages, // Cannot load packages in GrpcLedgerClient @@ -213,13 +218,19 @@ class GrpcLedgerClient( } // Helper shared by query, queryContractId and queryContractKey + // TODO(https://github.com/digital-asset/daml/issues/22283): return a key hash instead of a key. With the current + // code, the enrichment of keys will fail when the key type has been changed by an (invalid) upgrade. We could + // skip the enrichement as the enriched part of the returned key value is not used: the value is merely hashed + // using (at the moment), the upgrades-friendly hasher. We want however to switch to the typed normal form hasher, + // which requires having the creation package handy, which we won't necessarily have. So we want instead to modify + // the ledger API to return the hash of the key directly and pass it along to the caller here. private def queryWithKey( parties: OneAnd[Set, Ref.Party], templateId: Identifier, )(implicit ec: ExecutionContext, mat: Materializer, - ): Future[Vector[(ScriptLedgerClient.ActiveContract, Option[Value])]] = { + ): Future[Vector[(ScriptLedgerClient.ActiveContract, Option[crypto.Hash])]] = { val format = templateFormat(parties, templateId, verbose = false) val acsResponse = grpcClient.stateService.getLedgerEndOffset().flatMap { offset => @@ -238,23 +249,16 @@ class GrpcLedgerClient( case Left(err) => throw new ConverterException(err.toString) case Right(argument) => argument } - val key: Option[Value] = createdEvent.contractKey.map { key => - NoLoggingValueValidator.validateValue(key) match { - case Left(err) => throw new ConverterException(err.toString) - case Right(key) => key + val keyHash: Option[crypto.Hash] = Option.when(!createdEvent.contractKeyHash.isEmpty)( + crypto.Hash.fromBytes(Bytes.fromByteString(createdEvent.contractKeyHash)) match { + case Right(hash) => hash + case Left(err) => throw new ConverterException(err) } - } + ) val enrichedArgument = enricher.enrichContract(templateId, argument).consume() match { case Right(arg) => arg case Left(err) => throw new ConverterException(err.toString) } - val enrichedKey = key.map { key => - enricher.enrichContractKey(templateId, key).consume() match { - case Right(key) => key - case Left(err) => throw new ConverterException(err.toString) - } - } - val cid = ContractId .fromString(createdEvent.contractId) @@ -279,7 +283,7 @@ class GrpcLedgerClient( enrichedArgument, blob, ), - enrichedKey, + keyHash, ) }) ) @@ -369,6 +373,22 @@ class GrpcLedgerClient( } } + private[this] def computeKeyHash(templateId: Identifier, key: Value)(implicit + ec: ExecutionContext + ): Future[crypto.Hash] = + Future( + preprocessor + .unsafePreprocessApiContractKey( + Map.empty.withDefault((name: Ref.PackageName) => + throw new IllegalStateException( + s"Unexpected package lookup by name (${name}) during contract key preprocessing." + ) + ), + ApiContractKey(templateId.toRef, key), + ) + .hash + ) + override def queryContractKey( parties: OneAnd[Set, Ref.Party], templateId: Identifier, @@ -380,20 +400,9 @@ class GrpcLedgerClient( // We cannot do better than a linear search over query here. for { activeContracts <- queryWithKey(parties, templateId) - ownPackageName <- Converter.toFuture( - packageIdToUpgradeName(false, templateId.packageId).toRight("Cannot get package name") - ) - speedyContracts = activeContracts.map { case (t, kOpt) => - (t, kOpt.map(Hash.assertHashContractKey(templateId, ownPackageName, _))) - } - ownHash = Hash.assertHashContractKey(templateId, ownPackageName, key) + ownHash <- computeKeyHash(templateId, key) } yield { - // Note that the Equal instance on Value performs structural equality - // and also compares optional field and constructor names and is - // therefore not correct here. - // Equality.areEqual corresponds to the Daml-LF value equality - // which we want here. - speedyContracts.collectFirst({ case (c, Some(kHash)) if kHash == ownHash => c }) + activeContracts.collectFirst({ case (c, Some(kHash)) if kHash == ownHash => c }) } } diff --git a/sdk/daml-script/test/daml/upgrades/dev/ContractKeys.daml b/sdk/daml-script/test/daml/upgrades/dev/ContractKeys.daml index badd9b9463b3..88155f7dc2d8 100644 --- a/sdk/daml-script/test/daml/upgrades/dev/ContractKeys.daml +++ b/sdk/daml-script/test/daml/upgrades/dev/ContractKeys.daml @@ -121,16 +121,16 @@ main = tests ] ] , subtree "Changed key type, invalid upgrade" - [ broken ("queryContractKeyCmd, global", queryInvalidKeyUpgradeGlobal) - , broken ("exerciseByKeyCmd, global", exerciseInvalidKeyUpgradeGlobal) - , broken ("fetch, local", fetchInvalidKeyUpgradeLocal) - , broken ("exerciseByKey, local", exerciseInvalidKeyUpgradeLocal) + [ ("queryContractKeyCmd, global", queryInvalidKeyUpgradeGlobal) + , ("exerciseByKeyCmd, global", exerciseInvalidKeyUpgradeGlobal) + , ("fetch, local", fetchInvalidKeyUpgradeLocal) + , ("exerciseByKey, local", exerciseInvalidKeyUpgradeLocal) ] , subtree "Renamed key label, invalid upgrade" - [ broken ("queryContractKeyCmd, global", queryInvalidKeyRenamingGlobal) - , broken ("exerciseByKeyCmd, global", exerciseInvalidKeyRenamingGlobal) - , broken ("fetch, local", fetchInvalidKeyRenamingLocal) - , broken ("exerciseByKey, local", exerciseInvalidKeyRenamingLocal) + [ ("queryContractKeyCmd, global", queryInvalidKeyRenamingGlobal) + , ("exerciseByKeyCmd, global", exerciseInvalidKeyRenamingGlobal) + , ("fetch, local", fetchInvalidKeyRenamingLocal) + , ("exerciseByKey, local", exerciseInvalidKeyRenamingLocal) ] , subtree "Changed key presence" [ subtree "Key in v1, no key in v2" diff --git a/sdk/security-evidence.md b/sdk/security-evidence.md index 6c893e068362..163be9eab0fe 100644 --- a/sdk/security-evidence.md +++ b/sdk/security-evidence.md @@ -1,213 +1,213 @@ # Security tests, by category ## Authorization: -- badly-authorized create is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L77) -- badly-authorized exercise is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L178) +- badly-authorized create is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L83) +- badly-authorized exercise is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L184) - badly-authorized exercise/create (create is unauthorized) is rejected: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L278) - badly-authorized exercise/create (exercise is unauthorized) is rejected: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L246) - badly-authorized exercise/exercise (no implicit authority from outer exercise) is rejected: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L337) -- badly-authorized fetch is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L112) -- badly-authorized lookup is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L135) -- create with no signatories is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L67) -- create with non-signatory maintainers is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L89) -- exercise with no controllers is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L168) -- well-authorized create is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L60) -- well-authorized exercise is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L161) +- badly-authorized fetch is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L118) +- badly-authorized lookup is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L141) +- create with no signatories is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L73) +- create with non-signatory maintainers is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L95) +- exercise with no controllers is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L174) +- well-authorized create is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L66) +- well-authorized exercise is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L167) - well-authorized exercise/create is accepted: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L224) - well-authorized exercise/exercise is accepted: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L380) -- well-authorized fetch is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L106) -- well-authorized lookup is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L128) +- well-authorized fetch is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L112) +- well-authorized lookup is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L134) ## Availability: - Tail call optimization: Tail recursion does not blow the scala JVM stack.: [TailCallTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/TailCallTest.scala#L16) ## Confidentiality: -- ensure correct privacy for create node: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L42) -- ensure correct privacy for exercise node (consuming): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L54) -- ensure correct privacy for exercise node (non-consuming): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L75) -- ensure correct privacy for exercise subtree: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L153) -- ensure correct privacy for fetch node: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L97) -- ensure correct privacy for lookup-by-key node (found): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L110) -- ensure correct privacy for lookup-by-key node (not-found): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L131) -- ensure correct privacy for rollback subtree: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L228) +- ensure correct privacy for create node: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L46) +- ensure correct privacy for exercise node (consuming): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L58) +- ensure correct privacy for exercise node (non-consuming): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L79) +- ensure correct privacy for exercise subtree: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L173) +- ensure correct privacy for fetch node: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L101) +- ensure correct privacy for lookup-by-key node (found): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L114) +- ensure correct privacy for lookup-by-key node (not-found): [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L143) +- ensure correct privacy for rollback subtree: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L248) ## Integrity: -- Evaluation order of create with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L633) -- Evaluation order of create with contract ID in contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L667) -- Evaluation order of create with contract key exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L718) -- Evaluation order of create with create argument exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L693) -- Evaluation order of create with duplicate contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L584) -- Evaluation order of create with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L608) -- Evaluation order of create with failed precondition: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L566) -- Evaluation order of create_interface with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L839) -- Evaluation order of create_interface with contract ID in contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L873) -- Evaluation order of create_interface with contract key exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L924) -- Evaluation order of create_interface with create argument exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L899) -- Evaluation order of create_interface with duplicate contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L790) -- Evaluation order of create_interface with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L814) -- Evaluation order of create_interface with failed precondition: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L770) -- Evaluation order of exercise by interface of a cached global contract that does not implement the interface.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1942) -- Evaluation order of exercise by interface of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1924) -- Evaluation order of exercise by interface of cached global contract with failed authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1984) -- Evaluation order of exercise of a cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1275) -- Evaluation order of exercise of a non-cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L997) -- Evaluation order of exercise of a non-cached global contract with inconsistent key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1041) -- Evaluation order of exercise of a wrongly typed cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1115) -- Evaluation order of exercise of a wrongly typed non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L982) -- Evaluation order of exercise of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1098) -- Evaluation order of exercise of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1217) -- Evaluation order of exercise of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1318) -- Evaluation order of exercise of an wrongly typed local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1236) -- Evaluation order of exercise of cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1151) -- Evaluation order of exercise with argument exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1332) -- Evaluation order of exercise with output exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1360) -- Evaluation order of exercise_by_key of a cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1644) -- Evaluation order of exercise_by_key of a non-cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1440) -- Evaluation order of exercise_by_key of a wrongly typed cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1535) -- Evaluation order of exercise_by_key of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1516) -- Evaluation order of exercise_by_key of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1624) -- Evaluation order of exercise_by_key of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1687) -- Evaluation order of exercise_by_key of cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1554) -- Evaluation order of exercise_by_key with argument exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1702) -- Evaluation order of exercise_by_key with contract ID in contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1781) -- Evaluation order of exercise_by_key with result exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1733) -- Evaluation order of exercise_interface of a cached local contract with failed authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2114) -- Evaluation order of exercise_interface of a non-cached global contract with failed authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1851) -- Evaluation order of exercise_interface of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2050) -- Evaluation order of exercise_interface of an local contract not implementing the interface: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2069) -- Evaluation order of exercise_vy_key with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1765) -- Evaluation order of fetch of a cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2430) -- Evaluation order of fetch of a non-cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2199) -- Evaluation order of fetch of a non-cached global contract with inconsistent key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2234) -- Evaluation order of fetch of a wrongly typed cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2297) -- Evaluation order of fetch of a wrongly typed non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2184) -- Evaluation order of fetch of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2281) -- Evaluation order of fetch of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2378) -- Evaluation order of fetch of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2460) -- Evaluation order of fetch of an wrongly typed local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2395) -- Evaluation order of fetch of cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2331) -- Evaluation order of fetch_by_key of a cached global contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2603) -- Evaluation order of fetch_by_key of a local contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2669) -- Evaluation order of fetch_by_key of a non-cached global contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2526) -- Evaluation order of fetch_by_key of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2584) -- Evaluation order of fetch_by_key of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2651) -- Evaluation order of fetch_by_key of an unknown contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2699) -- Evaluation order of fetch_by_key with contract ID in contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2731) -- Evaluation order of fetch_by_key with contract key exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2745) -- Evaluation order of fetch_by_key with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2715) -- Evaluation order of fetch_interface of a cached global contract not implementing the interface.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2880) -- Evaluation order of fetch_interface of a cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3020) -- Evaluation order of fetch_interface of a non-cached global contract that doesn't implement interface.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2789) -- Evaluation order of fetch_interface of a non-cached global contract with failed authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2808) -- Evaluation order of fetch_interface of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2863) -- Evaluation order of fetch_interface of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2965) -- Evaluation order of fetch_interface of an local contract not implementing the interface: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2982) -- Evaluation order of fetch_interface of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3050) -- Evaluation order of fetch_interface of cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2918) -- Evaluation order of lookup_by_key of a cached global contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3171) -- Evaluation order of lookup_by_key of a local contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3236) -- Evaluation order of lookup_by_key of a non-cached global contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3096) -- Evaluation order of lookup_by_key of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3153) -- Evaluation order of lookup_by_key of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3219) -- Evaluation order of lookup_by_key of an unknown contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3266) -- Evaluation order of lookup_by_key with contract ID in contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3298) -- Evaluation order of lookup_by_key with contract key exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3312) -- Evaluation order of lookup_by_key with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3282) -- Evaluation order of successful create: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L543) -- Evaluation order of successful create_interface: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L747) -- Evaluation order of successful exercise by interface of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1806) -- Evaluation order of successful exercise of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1074) -- Evaluation order of successful exercise of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1194) -- Evaluation order of successful exercise of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L955) -- Evaluation order of successful exercise_by_key of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1490) -- Evaluation order of successful exercise_by_key of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1600) -- Evaluation order of successful exercise_by_key of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1394) -- Evaluation order of successful exercise_interface of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1900) -- Evaluation order of successful exercise_interface of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2027) -- Evaluation order of successful fetch of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2264) -- Evaluation order of successful fetch of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2363) -- Evaluation order of successful fetch of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2161) -- Evaluation order of successful fetch_by_key of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2567) -- Evaluation order of successful fetch_by_key of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2635) -- Evaluation order of successful fetch_by_key of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2479) -- Evaluation order of successful fetch_interface of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2846) -- Evaluation order of successful fetch_interface of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2950) -- Evaluation order of successful fetch_interface of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2766) -- Evaluation order of successful lookup_by_key of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3136) -- Evaluation order of successful lookup_by_key of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3203) -- Evaluation order of successful lookup_by_key of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3070) +- Evaluation order of create with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L663) +- Evaluation order of create with contract ID in contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L697) +- Evaluation order of create with contract key exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L748) +- Evaluation order of create with create argument exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L723) +- Evaluation order of create with duplicate contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L614) +- Evaluation order of create with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L638) +- Evaluation order of create with failed precondition: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L596) +- Evaluation order of create_interface with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L869) +- Evaluation order of create_interface with contract ID in contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L903) +- Evaluation order of create_interface with contract key exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L954) +- Evaluation order of create_interface with create argument exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L929) +- Evaluation order of create_interface with duplicate contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L820) +- Evaluation order of create_interface with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L844) +- Evaluation order of create_interface with failed precondition: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L800) +- Evaluation order of exercise by interface of a cached global contract that does not implement the interface.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1972) +- Evaluation order of exercise by interface of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1954) +- Evaluation order of exercise by interface of cached global contract with failed authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2014) +- Evaluation order of exercise of a cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1305) +- Evaluation order of exercise of a non-cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1027) +- Evaluation order of exercise of a non-cached global contract with inconsistent key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1071) +- Evaluation order of exercise of a wrongly typed cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1145) +- Evaluation order of exercise of a wrongly typed non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1012) +- Evaluation order of exercise of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1128) +- Evaluation order of exercise of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1247) +- Evaluation order of exercise of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1348) +- Evaluation order of exercise of an wrongly typed local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1266) +- Evaluation order of exercise of cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1181) +- Evaluation order of exercise with argument exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1362) +- Evaluation order of exercise with output exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1390) +- Evaluation order of exercise_by_key of a cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1674) +- Evaluation order of exercise_by_key of a non-cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1470) +- Evaluation order of exercise_by_key of a wrongly typed cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1565) +- Evaluation order of exercise_by_key of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1546) +- Evaluation order of exercise_by_key of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1654) +- Evaluation order of exercise_by_key of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1717) +- Evaluation order of exercise_by_key of cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1584) +- Evaluation order of exercise_by_key with argument exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1732) +- Evaluation order of exercise_by_key with contract ID in contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1811) +- Evaluation order of exercise_by_key with result exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1763) +- Evaluation order of exercise_interface of a cached local contract with failed authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2144) +- Evaluation order of exercise_interface of a non-cached global contract with failed authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1881) +- Evaluation order of exercise_interface of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2080) +- Evaluation order of exercise_interface of an local contract not implementing the interface: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2099) +- Evaluation order of exercise_vy_key with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1795) +- Evaluation order of fetch of a cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2460) +- Evaluation order of fetch of a non-cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2229) +- Evaluation order of fetch of a non-cached global contract with inconsistent key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2264) +- Evaluation order of fetch of a wrongly typed cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2327) +- Evaluation order of fetch of a wrongly typed non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2214) +- Evaluation order of fetch of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2311) +- Evaluation order of fetch of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2408) +- Evaluation order of fetch of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2490) +- Evaluation order of fetch of an wrongly typed local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2425) +- Evaluation order of fetch of cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2361) +- Evaluation order of fetch_by_key of a cached global contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2633) +- Evaluation order of fetch_by_key of a local contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2699) +- Evaluation order of fetch_by_key of a non-cached global contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2556) +- Evaluation order of fetch_by_key of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2614) +- Evaluation order of fetch_by_key of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2681) +- Evaluation order of fetch_by_key of an unknown contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2729) +- Evaluation order of fetch_by_key with contract ID in contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2761) +- Evaluation order of fetch_by_key with contract key exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2775) +- Evaluation order of fetch_by_key with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2745) +- Evaluation order of fetch_interface of a cached global contract not implementing the interface.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2910) +- Evaluation order of fetch_interface of a cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3050) +- Evaluation order of fetch_interface of a non-cached global contract that doesn't implement interface.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2819) +- Evaluation order of fetch_interface of a non-cached global contract with failed authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2838) +- Evaluation order of fetch_interface of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2893) +- Evaluation order of fetch_interface of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2995) +- Evaluation order of fetch_interface of an local contract not implementing the interface: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3012) +- Evaluation order of fetch_interface of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3080) +- Evaluation order of fetch_interface of cached global contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2948) +- Evaluation order of lookup_by_key of a cached global contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3201) +- Evaluation order of lookup_by_key of a local contract with failure authorization: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3266) +- Evaluation order of lookup_by_key of a non-cached global contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3126) +- Evaluation order of lookup_by_key of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3183) +- Evaluation order of lookup_by_key of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3249) +- Evaluation order of lookup_by_key of an unknown contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3296) +- Evaluation order of lookup_by_key with contract ID in contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3328) +- Evaluation order of lookup_by_key with contract key exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3342) +- Evaluation order of lookup_by_key with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3312) +- Evaluation order of successful create: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L573) +- Evaluation order of successful create_interface: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L777) +- Evaluation order of successful exercise by interface of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1836) +- Evaluation order of successful exercise of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1104) +- Evaluation order of successful exercise of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1224) +- Evaluation order of successful exercise of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L985) +- Evaluation order of successful exercise_by_key of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1520) +- Evaluation order of successful exercise_by_key of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1630) +- Evaluation order of successful exercise_by_key of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1424) +- Evaluation order of successful exercise_interface of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1930) +- Evaluation order of successful exercise_interface of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2057) +- Evaluation order of successful fetch of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2294) +- Evaluation order of successful fetch of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2393) +- Evaluation order of successful fetch of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2191) +- Evaluation order of successful fetch_by_key of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2597) +- Evaluation order of successful fetch_by_key of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2665) +- Evaluation order of successful fetch_by_key of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2509) +- Evaluation order of successful fetch_interface of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2876) +- Evaluation order of successful fetch_interface of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2980) +- Evaluation order of successful fetch_interface of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2796) +- Evaluation order of successful lookup_by_key of a cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3166) +- Evaluation order of successful lookup_by_key of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3233) +- Evaluation order of successful lookup_by_key of a non-cached global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3100) - Exceptions, throw/catch.: [ExceptionTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExceptionTest.scala#L35) -- Rollback creates cannot be exercise: [EngineTest.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala#L2180) +- Rollback creates cannot be exercise: [EngineTest.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala#L2174) - Smart Contract Upgrade: Can catch different errors thrown by different choice version within Update, using AnyException: [Exceptions.daml](daml-script/test/daml/upgrades/stable/Exceptions.daml#L263) - Smart Contract Upgrade: Can catch different errors thrown by different choice version, where one is new to V2 within Update, using AnyException: [Exceptions.daml](daml-script/test/daml/upgrades/stable/Exceptions.daml#L267) - Smart Contract Upgrade: Can catch same errors thrown by different choice versions within Update: [Exceptions.daml](daml-script/test/daml/upgrades/stable/Exceptions.daml#L259) - Smart Contract Upgrade: Cannot catch DowngradeDropDefinedField upgrade exceptions within Update: [Exceptions.daml](daml-script/test/daml/upgrades/stable/Exceptions.daml#L227) - Smart Contract Upgrade: Cannot catch ValidationFailed upgrade exceptions within Update: [Exceptions.daml](daml-script/test/daml/upgrades/stable/Exceptions.daml#L216) -- Smart Contract Upgrade: added an interface instance in v2 when it doesn't yet exist in v1, make sure that it gets picked up: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L804) -- Smart Contract Upgrade: additional choice parameter, None arg, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1155) -- Smart Contract Upgrade: additional choice parameter, Some arg, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1169) -- Smart Contract Upgrade: additional choice parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1143) -- Smart Contract Upgrade: additional constructor in enum used as choice parameter, unused constructor, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1100) -- Smart Contract Upgrade: additional constructor in enum used as choice parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1080) -- Smart Contract Upgrade: additional constructor in enum used as choice parameter, used constructor, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1120) -- Smart Contract Upgrade: additional constructor in enum used as template parameter, unused constructor, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1568) -- Smart Contract Upgrade: additional constructor in enum used as template parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1305) -- Smart Contract Upgrade: additional constructor in enum used as template parameter, used constructor, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1597) -- Smart Contract Upgrade: additional constructor in variant used as choice parameter, unused constructor, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1034) -- Smart Contract Upgrade: additional constructor in variant used as choice parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1014) -- Smart Contract Upgrade: additional constructor in variant used as choice parameter, used constructor, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1057) -- Smart Contract Upgrade: additional constructor in variant used as template parameter, unused constructor, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1505) -- Smart Contract Upgrade: additional constructor in variant used as template parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1245) -- Smart Contract Upgrade: additional constructor in variant used as template parameter, used constructor, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1535) -- Smart Contract Upgrade: additional optional field in key type, None value, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1681) -- Smart Contract Upgrade: additional optional field in key type, None value, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1629) -- Smart Contract Upgrade: additional optional field in key type, Some value, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1700) +- Smart Contract Upgrade: added an interface instance in v2 when it doesn't yet exist in v1, make sure that it gets picked up: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L809) +- Smart Contract Upgrade: additional choice parameter, None arg, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1157) +- Smart Contract Upgrade: additional choice parameter, Some arg, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1171) +- Smart Contract Upgrade: additional choice parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1145) +- Smart Contract Upgrade: additional constructor in enum used as choice parameter, unused constructor, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1102) +- Smart Contract Upgrade: additional constructor in enum used as choice parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1082) +- Smart Contract Upgrade: additional constructor in enum used as choice parameter, used constructor, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1122) +- Smart Contract Upgrade: additional constructor in enum used as template parameter, unused constructor, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1570) +- Smart Contract Upgrade: additional constructor in enum used as template parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1307) +- Smart Contract Upgrade: additional constructor in enum used as template parameter, used constructor, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1599) +- Smart Contract Upgrade: additional constructor in variant used as choice parameter, unused constructor, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1036) +- Smart Contract Upgrade: additional constructor in variant used as choice parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1016) +- Smart Contract Upgrade: additional constructor in variant used as choice parameter, used constructor, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1059) +- Smart Contract Upgrade: additional constructor in variant used as template parameter, unused constructor, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1507) +- Smart Contract Upgrade: additional constructor in variant used as template parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1247) +- Smart Contract Upgrade: additional constructor in variant used as template parameter, used constructor, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1537) +- Smart Contract Upgrade: additional optional field in key type, None value, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1679) +- Smart Contract Upgrade: additional optional field in key type, None value, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1631) +- Smart Contract Upgrade: additional optional field in key type, Some value, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1698) - Smart Contract Upgrade: additional optional field in key type, Some value, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1655) -- Smart Contract Upgrade: additional optional field in record used as choice parameter, None value, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L959) -- Smart Contract Upgrade: additional optional field in record used as choice parameter, Some value, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L985) -- Smart Contract Upgrade: additional optional field in record used as choice parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L933) -- Smart Contract Upgrade: additional optional field in record used as template parameter, None value, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1438) -- Smart Contract Upgrade: additional optional field in record used as template parameter, Some value, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1470) -- Smart Contract Upgrade: additional optional field in record used as template parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1183) -- Smart Contract Upgrade: additional template parameter, None arg, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1422) -- Smart Contract Upgrade: additional template parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1363) -- Smart Contract Upgrade: changed key expression, evaluates to a different value, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L849) -- Smart Contract Upgrade: changed key expression, evaluates to the same value, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L835) -- Smart Contract Upgrade: changed maintainers expression, evaluates to a different value, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L882) -- Smart Contract Upgrade: changed maintainers expression, evaluates to the same value, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L874) -- Smart Contract Upgrade: changed observers expression, evaluates to a different value, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L791) -- Smart Contract Upgrade: changed observers expression, evaluates to the same value, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L785) -- Smart Contract Upgrade: changed precondition expression, evaluates to false, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L748) -- Smart Contract Upgrade: changed precondition expression, evaluates to true, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L742) -- Smart Contract Upgrade: changed signatories expression, evaluates to a different value, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L770) -- Smart Contract Upgrade: changed signatories expression, evaluates to the same value, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L763) -- Smart Contract Upgrade: differently-named field in record used as template parameter, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1214) -- Smart Contract Upgrade: differently-named template parameter, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1369) -- Smart Contract Upgrade: differently-ranked constructor in enum used as template parameter, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1334) -- Smart Contract Upgrade: differently-ranked variant constructor used as template parameter, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1275) -- Smart Contract Upgrade: errors thrown by the choice controllers expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1382) -- Smart Contract Upgrade: errors thrown by the choice observers expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1391) -- Smart Contract Upgrade: errors thrown by the key expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L863) -- Smart Contract Upgrade: errors thrown by the maintainers expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L915) -- Smart Contract Upgrade: errors thrown by the maintainers function body cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L924) -- Smart Contract Upgrade: errors thrown by the observers expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L797) -- Smart Contract Upgrade: errors thrown by the precondition expressions cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L755) -- Smart Contract Upgrade: errors thrown by the signatories expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L777) -- Smart Contract Upgrade: interface views are not calculated during fetches and exercises: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1400) -- Smart Contract Upgrade: the new version of the module defines an additional template, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L821) -- Smart Contract Upgrade: the new version of the template defines an additional choice, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L809) -- This checks that type checking in exercise_interface is done after checking activeness.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2094) -- This checks that type checking is done after checking activeness.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1966) -- This checks that type checking is done after checking activeness.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3002) -- contract key behaviour (non-unique mode): [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L439) -- contract key behaviour (unique mode): [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L449) -- contract keys must have a non-empty set of maintainers: [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L242) -- contract keys should be evaluated after ensure clause: [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L209) -- contract keys should be evaluated only when executing create: [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L167) +- Smart Contract Upgrade: additional optional field in record used as choice parameter, None value, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L961) +- Smart Contract Upgrade: additional optional field in record used as choice parameter, Some value, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L987) +- Smart Contract Upgrade: additional optional field in record used as choice parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L935) +- Smart Contract Upgrade: additional optional field in record used as template parameter, None value, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1440) +- Smart Contract Upgrade: additional optional field in record used as template parameter, Some value, downgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1472) +- Smart Contract Upgrade: additional optional field in record used as template parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1185) +- Smart Contract Upgrade: additional template parameter, None arg, downgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1424) +- Smart Contract Upgrade: additional template parameter, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1365) +- Smart Contract Upgrade: changed key expression, evaluates to a different value, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L854) +- Smart Contract Upgrade: changed key expression, evaluates to the same value, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L840) +- Smart Contract Upgrade: changed maintainers expression, evaluates to a different value, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L887) +- Smart Contract Upgrade: changed maintainers expression, evaluates to the same value, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L879) +- Smart Contract Upgrade: changed observers expression, evaluates to a different value, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L796) +- Smart Contract Upgrade: changed observers expression, evaluates to the same value, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L790) +- Smart Contract Upgrade: changed precondition expression, evaluates to false, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L753) +- Smart Contract Upgrade: changed precondition expression, evaluates to true, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L747) +- Smart Contract Upgrade: changed signatories expression, evaluates to a different value, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L775) +- Smart Contract Upgrade: changed signatories expression, evaluates to the same value, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L768) +- Smart Contract Upgrade: differently-named field in record used as template parameter, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1216) +- Smart Contract Upgrade: differently-named template parameter, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1371) +- Smart Contract Upgrade: differently-ranked constructor in enum used as template parameter, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1336) +- Smart Contract Upgrade: differently-ranked variant constructor used as template parameter, upgrade fails: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1277) +- Smart Contract Upgrade: errors thrown by the choice controllers expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1384) +- Smart Contract Upgrade: errors thrown by the choice observers expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1393) +- Smart Contract Upgrade: errors thrown by the key expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L868) +- Smart Contract Upgrade: errors thrown by the maintainers expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L917) +- Smart Contract Upgrade: errors thrown by the maintainers function body cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L926) +- Smart Contract Upgrade: errors thrown by the observers expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L802) +- Smart Contract Upgrade: errors thrown by the precondition expressions cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L760) +- Smart Contract Upgrade: errors thrown by the signatories expression cannot be caught: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L782) +- Smart Contract Upgrade: interface views are not calculated during fetches and exercises: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L1402) +- Smart Contract Upgrade: the new version of the module defines an additional template, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L826) +- Smart Contract Upgrade: the new version of the template defines an additional choice, upgrade succeeds: [UpgradesMatrix.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/UpgradesMatrix.scala#L814) +- This checks that type checking in exercise_interface is done after checking activeness.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2124) +- This checks that type checking is done after checking activeness.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1996) +- This checks that type checking is done after checking activeness.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3032) +- contract key behaviour (non-unique mode): [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L460) +- contract key behaviour (unique mode): [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L470) +- contract keys must have a non-empty set of maintainers: [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L257) +- contract keys should be evaluated after ensure clause: [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L224) +- contract keys should be evaluated only when executing create: [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L182) - ensure builtin operators have the correct type: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L72) - ensure expression forms have the correct type: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L133) - exercise-by-interface command is rejected for a: [ApiCommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/preprocessing/ApiCommandPreprocessorSpec.scala#L188) -- exercise_interface with a contract instance that does not implement the interface fails.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1833) +- exercise_interface with a contract instance that does not implement the interface fails.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1863) - ill-formed create API command is rejected: [ApiCommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/preprocessing/ApiCommandPreprocessorSpec.scala#L176) - ill-formed create replay command is rejected: [ReplayCommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/preprocessing/ReplayCommandPreprocessorSpec.scala#L121) - ill-formed create-and-exercise API command is rejected: [ApiCommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/preprocessing/ApiCommandPreprocessorSpec.scala#L201) diff --git a/sdk/test-common/canton/it-lib/src/main/scala/com/daml/integrationtest/CantonFixture.scala b/sdk/test-common/canton/it-lib/src/main/scala/com/daml/integrationtest/CantonFixture.scala index 16e88fb8608c..565b4ff091d0 100644 --- a/sdk/test-common/canton/it-lib/src/main/scala/com/daml/integrationtest/CantonFixture.scala +++ b/sdk/test-common/canton/it-lib/src/main/scala/com/daml/integrationtest/CantonFixture.scala @@ -76,7 +76,7 @@ trait CantonFixtureWithResource[A] final case object CantonFixtureDebugRemoveTmpFiles extends CantonFixtureDebugMode final case object CantonFixtureDontDebug extends CantonFixtureDebugMode - protected val cantonFixtureDebugMode: CantonFixtureDebugMode = CantonFixtureDontDebug + protected val cantonFixtureDebugMode: CantonFixtureDebugMode = CantonFixtureDebugKeepTmpFiles def cantonFixtureDebugModeIsDebug: Boolean = cantonFixtureDebugMode match { case CantonFixtureDebugKeepTmpFiles | CantonFixtureDebugRemoveTmpFiles => true case _ => false