diff --git a/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Compiler.scala b/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Compiler.scala index 36b2a4494559..b3c5228a126a 100644 --- a/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Compiler.scala +++ b/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Compiler.scala @@ -4,6 +4,7 @@ package com.digitalasset.daml.lf package speedy +import com.daml.scalautil.Statement.discard import com.digitalasset.daml.lf.data.Ref._ import com.digitalasset.daml.lf.data.{ImmArray, Ref, Struct, Time} import com.digitalasset.daml.lf.language.Ast._ @@ -19,11 +20,9 @@ import com.digitalasset.daml.lf.speedy.PhaseOne.{Env, Position} import com.digitalasset.daml.lf.speedy.Profile.LabelModule import com.digitalasset.daml.lf.speedy.SBuiltinFun._ import com.digitalasset.daml.lf.speedy.SValue._ -import com.digitalasset.daml.lf.speedy.{SExpr => t} -import com.digitalasset.daml.lf.speedy.{SExpr0 => s} +import com.digitalasset.daml.lf.speedy.{SExpr => t, SExpr0 => s} import com.digitalasset.daml.lf.stablepackages.{StablePackages, StablePackagesV2} import com.digitalasset.daml.lf.validation.{Validation, ValidationError} -import com.daml.scalautil.Statement.discard import org.slf4j.LoggerFactory import scala.annotation.nowarn @@ -287,6 +286,11 @@ private[lf] final class Compiler( private[this] def fun4(body: (Position, Position, Position, Position, Env) => s.SExpr): s.SExpr = s.SEAbs(4, body(Pos1, Pos2, Pos3, Pos4, Env4)) + private[this] def unlabelledTopLevelFunction1(ref: t.SDefinitionRef)( + body: (Position, Env) => s.SExpr + ): (t.SDefinitionRef, SDefinition) = + ref -> SDefinition(pipeline(fun1(body))) + private[this] def topLevelFunction1[SDefRef <: t.SDefinitionRef: LabelModule.Allowed]( ref: SDefRef )( @@ -294,11 +298,6 @@ private[lf] final class Compiler( ): (SDefRef, SDefinition) = topLevelFunction(ref)(fun1(body)) - private[this] def unlabelledTopLevelFunction2(ref: t.SDefinitionRef)( - body: (Position, Position, Env) => s.SExpr - ): (t.SDefinitionRef, SDefinition) = - ref -> SDefinition(pipeline(fun2(body))) - private[this] def topLevelFunction2[SDefRef <: t.SDefinitionRef: LabelModule.Allowed]( ref: SDefRef )( @@ -496,8 +495,7 @@ private[lf] final class Compiler( let( env, SBFetchTemplate(tmplId)( - env.toSEVar(cidPos), - mbKey.fold(s.SEValue.None: s.SExpr)(pos => SBSome(env.toSEVar(pos))), + env.toSEVar(cidPos) ), ) { (tmplArgPos, _env) => val env = @@ -721,10 +719,8 @@ private[lf] final class Compiler( byKey = mbKey.isDefined, interfaceId = None, )( - env.toSEVar(cidPos), - mbKey.fold(s.SEValue.None: s.SExpr)(pos => SBSome(env.toSEVar(pos))), + env.toSEVar(cidPos) ) - } private[this] def compileFetchTemplate( @@ -748,7 +744,6 @@ private[lf] final class Compiler( SBResolveSBUInsertFetchNode(ifaceId)( env.toSEVar(payloadPos), env.toSEVar(cidPos), - s.SEValue.None, ), ) { (_, env) => env.toSEVar(payloadPos) @@ -777,43 +772,34 @@ private[lf] final class Compiler( tmplId: Identifier, tmpl: Template, ): (t.SDefinitionRef, SDefinition) = - unlabelledTopLevelFunction2(t.ToContractInfoDefRef(tmplId)) { (tmplArgPos, mbKeyPos, env) => + unlabelledTopLevelFunction1(t.ToContractInfoDefRef(tmplId)) { (tmplArgPos, env) => // We use a chain of let bindings to make the evaluation order of SBuildContractInfoStruct's arguments is // independent from the evaluation strategy imposed by the ANF transformation. checkPreCondition(env, tmplId, env.toSEVar(tmplArgPos)) { env => let(env, s.SEValue(STypeRep(TTyCon(tmplId)))) { (typePos, env) => let(env, t.SignatoriesDefRef(tmplId)(env.toSEVar(tmplArgPos))) { (signatoriesPos, env) => let(env, t.ObserversDefRef(tmplId)(env.toSEVar(tmplArgPos))) { (observersPos, env) => - val body = tmpl.key match { + val mbKeyWithMaintainers = tmpl.key match { case None => s.SEValue.None case Some(tmplKey) => - s.SECase( - env.toSEVar(mbKeyPos), - List( - s.SCaseAlt( - t.SCPNone, - let( - env, - translateExp( - env.bindExprVar(tmpl.param, tmplArgPos), - tmplKey.body, - ), - ) { (keyPos, env) => - SBSome(translateKeyWithMaintainers(env, keyPos, tmplKey)) - }, - ), - s.SCaseAlt(t.SCPDefault, env.toSEVar(mbKeyPos)), + let( + env, + translateExp( + env.bindExprVar(tmpl.param, tmplArgPos), + tmplKey.body, ), - ) + ) { (keyPos, env) => + SBSome(translateKeyWithMaintainers(env, keyPos, tmplKey)) + } } - let(env, body) { (bodyPos, env) => + let(env, mbKeyWithMaintainers) { (mbKeyWithMaintainersPos, env) => SBuildContractInfoStruct( env.toSEVar(typePos), env.toSEVar(tmplArgPos), env.toSEVar(signatoriesPos), env.toSEVar(observersPos), - env.toSEVar(bodyPos), + env.toSEVar(mbKeyWithMaintainersPos), ) } } @@ -950,15 +936,16 @@ private[lf] final class Compiler( // _ = $insertLookup(tmplId> // in topLevelFunction2(t.LookupByKeyDefRef(tmplId)) { (keyPos, _, env) => - let(env, translateKeyWithMaintainers(env, keyPos, tmplKey)) { (keyWithMPos, env) => - let(env, SBULookupKey(tmplId)(env.toSEVar(keyWithMPos))) { (maybeCidPos, env) => - let( - env, - SBUInsertLookupNode(tmplId)(env.toSEVar(keyWithMPos), env.toSEVar(maybeCidPos)), - ) { (_, env) => - env.toSEVar(maybeCidPos) + let(env, s.SEPreventCatch(translateKeyWithMaintainers(env, keyPos, tmplKey))) { + (keyWithMPos, env) => + let(env, SBULookupKey(tmplId)(env.toSEVar(keyWithMPos))) { (maybeCidPos, env) => + let( + env, + SBUInsertLookupNode(tmplId)(env.toSEVar(keyWithMPos), env.toSEVar(maybeCidPos)), + ) { (_, env) => + env.toSEVar(maybeCidPos) + } } - } } } @@ -980,19 +967,20 @@ private[lf] final class Compiler( // _ = $insertFetch (Some ) // in { contractId: ContractId Foo, contract: Foo } topLevelFunction2(t.FetchByKeyDefRef(tmplId)) { (keyPos, tokenPos, env) => - let(env, translateKeyWithMaintainers(env, keyPos, tmplKey)) { (keyWithMPos, env) => - let(env, SBUFetchKey(tmplId)(env.toSEVar(keyWithMPos))) { (cidPos, env) => - let( - env, - translateFetchTemplateBody(env, tmplId)( - cidPos, - Some(keyWithMPos), - tokenPos, - ), - ) { (contractPos, env) => - Tuple2(env.toSEVar(cidPos), env.toSEVar(contractPos)) + let(env, s.SEPreventCatch(translateKeyWithMaintainers(env, keyPos, tmplKey))) { + (keyWithMPos, env) => + let(env, SBUFetchKey(tmplId)(env.toSEVar(keyWithMPos))) { (cidPos, env) => + let( + env, + translateFetchTemplateBody(env, tmplId)( + cidPos, + Some(keyWithMPos), + tokenPos, + ), + ) { (contractPos, env) => + Tuple2(env.toSEVar(cidPos), env.toSEVar(contractPos)) + } } - } } } @@ -1082,7 +1070,7 @@ private[lf] final class Compiler( val expr1 = s.SEApp( s.SEVal(t.ToContractInfoDefRef(contract.templateId)), - List(s.SEValue(argument), s.SEValue.None), + List(s.SEValue(argument)), ) val contractPos = env.nextPosition env = env.pushVar 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 7834d73e9822..4f75f40ab6cb 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 @@ -955,9 +955,13 @@ private[lf] object SBuiltinFun { machine: UpdateMachine, ): Control[Question.Update] = { val templateArg: SValue = args.get(0) - val keyOpt: SValue = SOptional(None) - computeContractInfo(machine, templateId, templateArg, keyOpt) { contract => + computeContractInfo( + machine, + templateId, + templateArg, + allowCatchingContractInfoErrors = true, + ) { contract => contract.keyOpt match { case Some(contractKey) if contractKey.maintainers.isEmpty => Control.Error( @@ -1016,9 +1020,14 @@ private[lf] object SBuiltinFun { val coid = getSContractId(args, 1) val templateArg: SValue = args.get(5) - val keyOpt: SValue = SOptional(None) - getContractInfo(machine, coid, templateId, templateArg, keyOpt) { contract => + getContractInfo( + machine, + coid, + templateId, + templateArg, + allowCatchingContractInfoErrors = false, + ) { contract => val templateVersion = machine.tmplId2TxVersion(templateId) val (pkgName, _) = machine.tmplId2PackageNameVersion(templateId) val interfaceVersion = interfaceId.map(machine.tmplId2TxVersion) @@ -1158,13 +1167,13 @@ private[lf] object SBuiltinFun { coid, dstTplId, dstArg, - SValue.SValue.None, + allowCatchingContractInfoErrors = false, ) { _ => k(SAny(Ast.TTyCon(dstTplId), dstArg)) } } - hardFetchTemplate(machine, coid, SValue.SValue.None) { (pkgName, srcTplId, srcArg) => + hardFetchTemplate(machine, coid) { (pkgName, srcTplId, srcArg) => ensureTemplateImplementsInterface(machine, interfaceId, coid, srcTplId) { viewInterface(machine, interfaceId, srcTplId, srcArg) { srcView => resolvePackageName(machine, pkgName) { pkgId => @@ -1233,14 +1242,13 @@ private[lf] object SBuiltinFun { * -> a */ - final case class SBFetchTemplate(templateId: TypeConName) extends UpdateBuiltin(2) { + final case class SBFetchTemplate(templateId: TypeConName) extends UpdateBuiltin(1) { override protected def executeUpdate( args: util.ArrayList[SValue], machine: UpdateMachine, ): Control[Question.Update] = { val coid = getSContractId(args, 0) - val keyOpt = args.get(1) - fetchTemplate(machine, templateId, coid, keyOpt)(Control.Value) + fetchTemplate(machine, templateId, coid)(Control.Value) } } @@ -1535,16 +1543,21 @@ private[lf] object SBuiltinFun { templateId: TypeConName, byKey: Boolean, interfaceId: Option[TypeConName], - ) extends UpdateBuiltin(2) { + ) extends UpdateBuiltin(1) { protected def executeUpdate( args: util.ArrayList[SValue], machine: UpdateMachine, ): Control[Question.Update] = { val coid = getSContractId(args, 0) - val keyOpt: SValue = args.get(1) - fetchTemplate(machine, templateId, coid, keyOpt) { templateArg => - getContractInfo(machine, coid, templateId, templateArg, keyOpt) { contract => + fetchTemplate(machine, templateId, coid) { templateArg => + getContractInfo( + machine, + coid, + templateId, + templateArg, + allowCatchingContractInfoErrors = false, + ) { contract => val version = machine.tmplId2TxVersion(templateId) machine.ptx.insertFetch( coid = coid, @@ -1669,17 +1682,20 @@ private[lf] object SBuiltinFun { ) ) } else { - val keyOpt = SOptional(Some(keyValue)) val gkey = cachedKey.globalKey machine.ptx.contractState.resolveKey(gkey) match { case Right((keyMapping, next)) => machine.ptx = machine.ptx.copy(contractState = next) keyMapping match { case ContractStateMachine.KeyActive(coid) => - fetchTemplate(machine, templateId, coid, keyOpt) { templateArg => - getContractInfo(machine, coid, templateId, templateArg, keyOpt)(_ => - operation.handleKeyFound(coid) - ) + fetchTemplate(machine, templateId, coid) { templateArg => + getContractInfo( + machine, + coid, + templateId, + templateArg, + allowCatchingContractInfoErrors = false, + )(_ => operation.handleKeyFound(coid)) } case ContractStateMachine.KeyInactive => @@ -1693,10 +1709,14 @@ private[lf] object SBuiltinFun { keyMapping match { case ContractStateMachine.KeyActive(coid) => val c = - fetchTemplate(machine, templateId, coid, keyOpt) { templateArg => - getContractInfo(machine, coid, templateId, templateArg, keyOpt)(_ => - operation.handleKeyFound(coid) - ) + fetchTemplate(machine, templateId, coid) { templateArg => + getContractInfo( + machine, + coid, + templateId, + templateArg, + allowCatchingContractInfoErrors = false, + )(_ => operation.handleKeyFound(coid)) } (c, true) case ContractStateMachine.KeyInactive => @@ -2267,7 +2287,6 @@ private[lf] object SBuiltinFun { machine: UpdateMachine, dstTmplId: TypeConName, coid: V.ContractId, - keyOpt: SValue, )(f: SValue => Control[Question.Update]): Control[Question.Update] = machine.getIfLocalContract(coid) match { case Some((srcTmplId, templateArg)) => @@ -2290,7 +2309,13 @@ private[lf] object SBuiltinFun { language.Reference.Template(dstTmplId), ) { () => importValue(machine, dstTmplId, coinstArg) { templateArg => - getContractInfo(machine, coid, dstTmplId, templateArg, keyOpt) { contract => + getContractInfo( + machine, + coid, + dstTmplId, + templateArg, + allowCatchingContractInfoErrors = false, + ) { contract => ensureContractActive(machine, coid, contract.templateId) { machine.checkContractVisibility(coid, contract) @@ -2321,14 +2346,19 @@ private[lf] object SBuiltinFun { private def hardFetchTemplate( machine: UpdateMachine, coid: V.ContractId, - keyOpt: SValue, )( k: (Ref.PackageName, Ref.TypeConName, SRecord) => Control[Question.Update] ): Control[Question.Update] = { machine.getIfLocalContract(coid) match { case Some((templateId, templateArg)) => ensureContractActive(machine, coid, templateId) { - getContractInfo(machine, coid, templateId, templateArg, keyOpt) { contract => + getContractInfo( + machine, + coid, + templateId, + templateArg, + allowCatchingContractInfoErrors = false, + ) { contract => k(contract.packageName, templateId, templateArg.asInstanceOf[SRecord]) } } @@ -2339,7 +2369,13 @@ private[lf] object SBuiltinFun { language.Reference.Template(srcTmplId), ) { () => importValue(machine, srcTmplId, coinstArg) { templateArg => - getContractInfo(machine, coid, srcTmplId, templateArg, keyOpt) { contract => + getContractInfo( + machine, + coid, + srcTmplId, + templateArg, + allowCatchingContractInfoErrors = false, + ) { contract => ensureContractActive(machine, coid, contract.templateId) { machine.checkContractVisibility(coid, contract) @@ -2428,7 +2464,7 @@ private[lf] object SBuiltinFun { coid: V.ContractId, templateId: Identifier, templateArg: SValue, - keyOpt: SValue, + allowCatchingContractInfoErrors: Boolean, )(f: ContractInfo => Control[Question.Update]): Control[Question.Update] = { machine.contractInfoCache.get((coid, templateId.packageId)) match { case Some(contract) => @@ -2436,7 +2472,12 @@ private[lf] object SBuiltinFun { assert(contract.templateId == templateId) f(contract) case None => - computeContractInfo(machine, templateId, templateArg, keyOpt) { contract => + computeContractInfo( + machine, + templateId, + templateArg, + allowCatchingContractInfoErrors, + ) { contract => machine.insertContractInfoCache(coid, contract) f(contract) } @@ -2447,22 +2488,22 @@ private[lf] object SBuiltinFun { machine: Machine[Q], templateId: Identifier, templateArg: SValue, - keyOpt: SValue, + allowCatchingContractInfoErrors: Boolean, )(f: ContractInfo => Control[Q]): Control[Q] = { val e: SExpr = SEApp( SEVal(ToContractInfoDefRef(templateId)), Array( - templateArg, - keyOpt, + templateArg ), ) - executeExpression(machine, e) { contractInfoStruct => - val contract = extractContractInfo( - machine.tmplId2TxVersion, - machine.tmplId2PackageNameVersion, - contractInfoStruct, - ) - f(contract) + executeExpression(machine, if (allowCatchingContractInfoErrors) e else SEPreventCatch(e)) { + contractInfoStruct => + val contract = extractContractInfo( + machine.tmplId2TxVersion, + machine.tmplId2PackageNameVersion, + contractInfoStruct, + ) + f(contract) } } 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 08104a896daf..0c48b8c03cd1 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 @@ -1370,6 +1370,8 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) "precondition", "contract signatories", "contract observers", + "key", + "maintainers", "template choice controllers", "template choice observers", "template choice authorizers", @@ -1433,6 +1435,8 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) "precondition", "contract signatories", "contract observers", + "key", + "maintainers", "template choice controllers", "template choice observers", "template choice authorizers", @@ -1677,6 +1681,8 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) "precondition", "contract signatories", "contract observers", + "key", + "maintainers", "template choice controllers", "template choice observers", "template choice authorizers", @@ -1706,6 +1712,8 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) "precondition", "contract signatories", "contract observers", + "key", + "maintainers", "template choice controllers", "template choice observers", "template choice authorizers", @@ -2478,6 +2486,8 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) "precondition", "contract signatories", "contract observers", + "key", + "maintainers", "ends test", ) } @@ -2536,6 +2546,8 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) "precondition", "contract signatories", "contract observers", + "key", + "maintainers", ) } } @@ -3067,6 +3079,8 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) "precondition", "contract signatories", "contract observers", + "key", + "maintainers", "ends test", ) } @@ -3103,6 +3117,8 @@ abstract class EvaluationOrderTest(languageVersion: LanguageVersion) "precondition", "contract signatories", "contract observers", + "key", + "maintainers", ) } } 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 162084c4d9e1..9abecaf36577 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 @@ -5,18 +5,25 @@ package com.digitalasset.daml.lf package speedy import com.digitalasset.daml.lf.data.Ref.Party +import com.digitalasset.daml.lf.data.{FrontStack, ImmArray, Ref} import com.digitalasset.daml.lf.interpretation.{Error => IE} import com.digitalasset.daml.lf.language.Ast._ -import com.digitalasset.daml.lf.language.{LanguageMajorVersion, LanguageVersion} +import com.digitalasset.daml.lf.language.{Ast, LanguageMajorVersion, LanguageVersion} import com.digitalasset.daml.lf.speedy.SError.{SError, SErrorDamlException} import com.digitalasset.daml.lf.speedy.SExpr._ import com.digitalasset.daml.lf.speedy.SResult.{SResultError, SResultFinal} -import com.digitalasset.daml.lf.speedy.SValue.{SParty, SUnit} +import com.digitalasset.daml.lf.speedy.SValue.{SContractId, SParty, SUnit} import com.digitalasset.daml.lf.speedy.SpeedyTestLib.typeAndCompile import com.digitalasset.daml.lf.stablepackages.StablePackages import com.digitalasset.daml.lf.testing.parser import com.digitalasset.daml.lf.testing.parser.Implicits.SyntaxHelper import com.digitalasset.daml.lf.testing.parser.ParserParameters +import com.digitalasset.daml.lf.transaction.{ + GlobalKeyWithMaintainers, + TransactionVersion, + Versioned, +} +import com.digitalasset.daml.lf.value.Value import com.digitalasset.daml.lf.value.Value.{ValueRecord, ValueText} import org.scalatest.Inside import org.scalatest.freespec.AnyFreeSpec @@ -38,17 +45,69 @@ class ExceptionTest(majorLanguageVersion: LanguageMajorVersion) ParserParameters.defaultFor[this.type](majorLanguageVersion) val defaultPackageId = defaultParserParameters.defaultPackageId + private val stablePackages = + com.digitalasset.daml.lf.stablepackages.StablePackages(majorLanguageVersion) + + private val tuple2TyCon: String = { + import stablePackages.Tuple2 + s"'${Tuple2.packageId}':${Tuple2.qualifiedName}" + } + private def applyToParty(pkgs: CompiledPackages, e: Expr, p: Party): SExpr = { val se = pkgs.compiler.unsafeCompile(e) SEApp(se, Array(SParty(p))) } - private val party = Party.assertFromString("Alice") + private val alice = Party.assertFromString("Alice") + + private def runUpdateExpr( + compiledPackages: PureCompiledPackages, + expr: Expr, + getKey: PartialFunction[GlobalKeyWithMaintainers, Value.ContractId] = Map.empty, + ): Either[SError, SValue] = { + runUpdateExpr( + compiledPackages, + Map.empty, + compiledPackages.compiler.unsafeCompile(expr), + PartialFunction.empty, + getKey, + ) + } - private def runUpdateExpr(pkgs1: PureCompiledPackages)(e: Expr): SResult[Question.Update] = { - def transactionSeed: crypto.Hash = crypto.Hash.hashPrivateKey("ExceptionTest.scala") + private def runUpdateApp( + compiledPackages: PureCompiledPackages, + packageResolution: Map[Ref.PackageName, Ref.PackageId], + expr: Expr, + args: Array[SValue], + getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance], + getKey: PartialFunction[GlobalKeyWithMaintainers, Value.ContractId], + ): Either[SError, SValue] = { + runUpdateExpr( + compiledPackages, + packageResolution, + SEApp(compiledPackages.compiler.unsafeCompile(expr), args), + getContract, + getKey, + ) + } - Speedy.Machine.fromUpdateExpr(pkgs1, transactionSeed, e, Set(party)).run() + private def runUpdateExpr( + compiledPackages: PureCompiledPackages, + packageResolution: Map[Ref.PackageName, Ref.PackageId], + sexpr: SExpr, + getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance], + getKey: PartialFunction[GlobalKeyWithMaintainers, Value.ContractId], + ): Either[SError, SValue] = { + val machine = Speedy.Machine + .fromUpdateSExpr( + compiledPackages = compiledPackages, + packageResolution = packageResolution, + transactionSeed = crypto.Hash.hashPrivateKey("ExceptionTest.scala"), + updateSE = sexpr, + committers = Set(alice), + ) + SpeedyTestLib + .run(machine, getContract = getContract, getKey = getKey) } "unhandled throw" - { @@ -115,7 +174,7 @@ class ExceptionTest(majorLanguageVersion: LanguageMajorVersion) forEvery(testCases) { (exp: String, expected: SError) => s"eval[$exp] --> $expected" in { - inside(runUpdateExpr(pkgs)(e"$exp")) { case SResultError(err) => + inside(runUpdateExpr(pkgs, e"$exp")) { case Left(err) => err shouldBe expected } } @@ -151,7 +210,7 @@ class ExceptionTest(majorLanguageVersion: LanguageMajorVersion) forEvery(testCases) { (exp: String, num: Long) => s"eval[$exp] --> $num" in { - inside(runUpdateExpr(pkgs)(e"$exp")) { case SResultFinal(v) => + inside(runUpdateExpr(pkgs, e"$exp")) { case Right(v) => v shouldBe SValue.SInt64(num) } } @@ -190,7 +249,7 @@ class ExceptionTest(majorLanguageVersion: LanguageMajorVersion) forEvery(testCases) { (exp: String, num: Long) => s"eval[$exp] --> $num" in { - inside(runUpdateExpr(pkgs)(e"$exp")) { case SResultFinal(v) => + inside(runUpdateExpr(pkgs, e"$exp")) { case Right(v) => v shouldBe SValue.SInt64(num) } } @@ -275,7 +334,7 @@ class ExceptionTest(majorLanguageVersion: LanguageMajorVersion) forEvery(testCases) { (exp: String, num: Long) => s"eval[$exp] --> $num" in { - inside(runUpdateExpr(pkgs)(e"$exp")) { case SResultFinal(v) => + inside(runUpdateExpr(pkgs, e"$exp")) { case Right(v) => v shouldBe SValue.SInt64(num) } } @@ -346,7 +405,7 @@ class ExceptionTest(majorLanguageVersion: LanguageMajorVersion) forEvery(testCases) { (exp: String, num: Long) => s"eval[$exp] --> $num" in { - inside(runUpdateExpr(pkgs)(e"$exp")) { case SResultFinal(v) => + inside(runUpdateExpr(pkgs, e"$exp")) { case Right(v) => v shouldBe SValue.SInt64(num) } } @@ -420,7 +479,7 @@ class ExceptionTest(majorLanguageVersion: LanguageMajorVersion) forEvery(testCases) { (exp: String, num: Long) => s"eval[$exp] --> $num" in { - inside(runUpdateExpr(pkgs)(e"$exp")) { case SResultFinal(v) => + inside(runUpdateExpr(pkgs, e"$exp")) { case Right(v) => v shouldBe SValue.SInt64(num) } } @@ -503,7 +562,7 @@ class ExceptionTest(majorLanguageVersion: LanguageMajorVersion) forEvery(testCases) { (exp: String, str: String) => s"eval[$exp] --> $str" in { - inside(runUpdateExpr(pkgs)(e"$exp")) { case SResultFinal(v) => + inside(runUpdateExpr(pkgs, e"$exp")) { case Right(v) => v shouldBe SValue.SText(str) } } @@ -641,8 +700,8 @@ class ExceptionTest(majorLanguageVersion: LanguageMajorVersion) .fromUpdateSExpr( pkgs, transactionSeed, - applyToParty(pkgs, expr, party), - Set(party), + applyToParty(pkgs, expr, alice), + Set(alice), packageResolution = Map(pkg.pkgName -> defaultParserParameters.defaultPackageId), ) .run() @@ -723,6 +782,336 @@ class ExceptionTest(majorLanguageVersion: LanguageMajorVersion) } """ (parserParameters)) } + } + + // Section testing exceptions thrown when computing the metadata of a contract + { + val parserParameters = defaultParserParameters.copy(languageVersion = LanguageVersion.default) + + // A package that defines an interface, a key type, an exception, and a party to be used by + // the packages defined below. + val commonDefsPkgId = Ref.PackageId.assertFromString("-common-defs-v1-") + val commonDefsPkg = + p"""metadata ( '-common-defs-' : '1.0.0' ) + module Mod { + record @serializable MyUnit = {}; + interface (this : Iface) = { viewtype Mod:MyUnit; }; + + record @serializable Key = { label: Text, maintainers: List Party }; + + record @serializable Ex = { message: Text } ; + exception Ex = { + message \(e: Mod:Ex) -> Mod:Ex {message} e + }; + + val mkParty : Text -> Party = \(t:Text) -> case TEXT_TO_PARTY t of None -> ERROR @Party "none" | Some x -> x; + val alice : Party = Mod:mkParty "alice"; + } + """ (parserParameters.copy(defaultPackageId = commonDefsPkgId)) + + /** An abstract class whose [[templateDefinition]] method generates LF code that defines a template named + * [[templateName]]. + * The class is meant to be extended by concrete case objects which override one the metadata's expressions with an + * expression that throws an exception. + */ + abstract class TemplateGenerator(val templateName: String) { + def precondition = """True""" + + def signatories = s"""Cons @Party [Mod:${templateName} {p} this] (Nil @Party)""" + + def observers = """Nil @Party""" + + def key = + s""" + | '$commonDefsPkgId':Mod:Key { + | label = "test-key", + | maintainers = (Cons @Party [Mod:${templateName} {p} this] (Nil @Party)) + | }""".stripMargin + + def maintainers = + s"""\\(key: '$commonDefsPkgId':Mod:Key) -> ('$commonDefsPkgId':Mod:Key {maintainers} key)""" + + def templateDefinition: String = + s""" + | record @serializable $templateName = { p: Party }; + | template (this: $templateName) = { + | precondition $precondition; + | signatories $signatories; + | observers $observers; + | + | choice @nonConsuming SomeChoice (self) (u: Unit): Text + | , controllers (Nil @Party) + | , observers (Nil @Party) + | to upure @Text "SomeChoice was called"; + | + | implements '$commonDefsPkgId':Mod:Iface { view = '$commonDefsPkgId':Mod:MyUnit {}; }; + | + | key @'$commonDefsPkgId':Mod:Key ($key) ($maintainers); + | };""".stripMargin + } + + case class ValidMetadata(override val templateName: String) + extends TemplateGenerator(templateName) + + case object FailingPrecondition extends TemplateGenerator("Precondition") { + override def precondition = + s"""throw @Bool @'$commonDefsPkgId':Mod:Ex ('$commonDefsPkgId':Mod:Ex {message = "Precondition"})""" + } + case object FailingSignatories extends TemplateGenerator("Signatories") { + override def signatories = + s"""throw @(List Party) @'$commonDefsPkgId':Mod:Ex ('$commonDefsPkgId':Mod:Ex {message = "Signatories"})""" + } + case object FailingObservers extends TemplateGenerator("Observers") { + override def observers = + s"""throw @(List Party) @'$commonDefsPkgId':Mod:Ex ('$commonDefsPkgId':Mod:Ex {message = "Observers"})""" + } + case object FailingKey extends TemplateGenerator("Key") { + override def key = + s"""throw @'$commonDefsPkgId':Mod:Key @'$commonDefsPkgId':Mod:Ex ('$commonDefsPkgId':Mod:Ex {message = "Key"})""" + } + case object FailingMaintainers extends TemplateGenerator("Maintainers") { + override def maintainers = + s"""throw @('$commonDefsPkgId':Mod:Key -> List Party) @'$commonDefsPkgId':Mod:Ex ('$commonDefsPkgId':Mod:Ex {message = "Maintainers"})""" + } + + val templateDefsPkgName = Ref.PackageName.assertFromString("-template-defs-") + + /** A package that defines templates called Precondition, Signatories, ... whose metadata should evaluate without + * throwing exceptions. + */ + val templateDefsV1PkgId = Ref.PackageId.assertFromString("-template-defs-v1-id-") + val templateDefsV1ParserParams = parserParameters.copy(defaultPackageId = templateDefsV1PkgId) + val templateDefsV1Pkg = + p"""metadata ( '$templateDefsPkgName' : '1.0.0' ) + module Mod { + ${ValidMetadata("Precondition").templateDefinition} + ${ValidMetadata("Signatories").templateDefinition} + ${ValidMetadata("Observers").templateDefinition} + ${ValidMetadata("Key").templateDefinition} + ${ValidMetadata("Maintainers").templateDefinition} + } + """ (templateDefsV1ParserParams) + + /** Version 2 of the package above. It upgrades the previously defined templates such that: + * - the precondition in the Precondition template is changed to throw an exception + * - the signatories in the Signatories template is changed to throw an exception + * - etc. + */ + val templateDefsV2PkgId = Ref.PackageId.assertFromString("-template-defs-v2-id-") + val templateDefsV2ParserParams = parserParameters.copy(defaultPackageId = templateDefsV2PkgId) + val templateDefsV2Pkg = + p"""metadata ( '$templateDefsPkgName' : '2.0.0' ) + module Mod { + ${FailingPrecondition.templateDefinition} + ${FailingSignatories.templateDefinition} + ${FailingObservers.templateDefinition} + ${FailingKey.templateDefinition} + ${FailingMaintainers.templateDefinition} + } + """ (templateDefsV2ParserParams) + + /** Generates a series of expressions meant to test that: + * - When [[templateName]] is created, exceptions thrown when evaluating its metadata can be caught. + * - When an instance of [[templateName]] is fetched/exercised by id/key/interface, exceptions thrown when + * evaluating its metadata cannot be caught. + */ + def tests(pkgId: Ref.PackageId, templateName: String): String = { + val tplQualifiedName = s"'$pkgId':Mod:$templateName" + s""" + | // Checks that the error thrown when creating a $templateName instance can be caught. + | val create${templateName}AndCatchError: Update Unit = + | try @Unit + | ubind _:(ContractId $tplQualifiedName) <- + | create @$tplQualifiedName ($tplQualifiedName { p = '$commonDefsPkgId':Mod:alice }) + | in upure @Unit () + | catch + | e -> Some @(Update Unit) (upure @Unit ()); + | + | // Tries to catch the error thrown by the contract info of $templateName when exercising a choice on + | // it, should fail to do so. + | val exercise${templateName}AndCatchError: (ContractId $tplQualifiedName) -> Update Text = + | \\(cid: ContractId $tplQualifiedName) -> + | try @Text + | exercise @$tplQualifiedName SomeChoice cid () + | catch + | e -> Some @(Update Text) (upure @Text "unexpected: some exception was caught"); + | + | // Tries to catch the error thrown by the contract info of a $templateName contract when fetching it, + | // should fail to do so. + | val fetch${templateName}AndCatchError: (ContractId $tplQualifiedName) -> Update Text = + | \\(cid: ContractId $tplQualifiedName) -> + | try @Text + | ubind _:$tplQualifiedName <- fetch_template @$tplQualifiedName cid + | in upure @Text "unexpected: contract was fetched" + | catch + | e -> Some @(Update Text) (upure @Text "unexpected: some exception was caught"); + | + | // Tries to catch the error thrown by the contract info of a $templateName contract when fetching it + | // by interface, should fail to do so. + | val fetch${templateName}ByInterfaceAndCatchError: (ContractId $tplQualifiedName) -> Update Text = + | \\(cid: ContractId $tplQualifiedName) -> + | try @Text + | ubind _:'$commonDefsPkgId':Mod:Iface <- + | fetch_interface @'$commonDefsPkgId':Mod:Iface + | (COERCE_CONTRACT_ID @$tplQualifiedName @'$commonDefsPkgId':Mod:Iface cid) + | in upure @Text "unexpected: contract was fetched by interface" + | catch + | e -> Some @(Update Text) (upure @Text "unexpected: some exception was caught"); + | + | // Tries to catch the error thrown by the contract info of a $templateName contract when fetching it + | // by key, should fail to do so. + | val fetch${templateName}ByKeyAndCatchError: '$commonDefsPkgId':Mod:Key -> Update Text = + | \\(key: '$commonDefsPkgId':Mod:Key) -> + | try @Text + | ubind _:$tuple2TyCon (ContractId $tplQualifiedName) $tplQualifiedName <- + | fetch_by_key @$tplQualifiedName key + | in upure @Text "unexpected: contract was fetched by key" + | catch + | e -> Some @(Update Text) (upure @Text "unexpected: some exception was caught"); + | + | // Tries to catch the error thrown by the contract info of a $templateName contract when looking it up + | // by key, should fail to do so. + | val lookUp${templateName}ByKeyAndCatchError: '$commonDefsPkgId':Mod:Key -> Update Text = + | \\(key: '$commonDefsPkgId':Mod:Key) -> + | try @Text + | ubind _:Option (ContractId $tplQualifiedName) <- + | lookup_by_key @$tplQualifiedName key + | in upure @Text "unexpected: contract was looked up by key" + | catch + | e -> Some @(Update Text) (upure @Text "unexpected: some exception was caught"); + |""".stripMargin + } + + val metadataTestsPkgId = Ref.PackageId.assertFromString("-metadata-tests-id-") + val metadataTestsParserParams = parserParameters.copy(defaultPackageId = metadataTestsPkgId) + val metadataTestsPkg = + p"""metadata ( '-metadata-tests-' : '1.0.0' ) + module Mod { + ${tests(templateDefsV2PkgId, "Precondition")} + ${tests(templateDefsV2PkgId, "Signatories")} + ${tests(templateDefsV2PkgId, "Observers")} + ${tests(templateDefsV2PkgId, "Key")} + ${tests(templateDefsV2PkgId, "Maintainers")} + } + """ (metadataTestsParserParams) + + val compiledPackages: PureCompiledPackages = + PureCompiledPackages.assertBuild( + Map( + stablePackages.Tuple2.packageId -> stablePackages.packagesMap( + stablePackages.Tuple2.packageId + ), + commonDefsPkgId -> commonDefsPkg, + templateDefsV1PkgId -> templateDefsV1Pkg, + templateDefsV2PkgId -> templateDefsV2Pkg, + metadataTestsPkgId -> metadataTestsPkg, + ), + Compiler.Config.Default(majorLanguageVersion), + ) + for { + test <- List( + FailingPrecondition, + FailingSignatories, + FailingObservers, + FailingKey, + FailingMaintainers, + ) + } { + + s"exceptions thrown by ${test.templateName} can be caught on when creating a contract" in { + runUpdateExpr( + compiledPackages, + e"Mod:create${test.templateName}AndCatchError" (metadataTestsParserParams), + ) shouldBe Right(SUnit) + } + + s"exceptions thrown by ${test.templateName} cannot be caught when fetched or exercised" in { + val alice = Ref.Party.assertFromString("Alice") + val templateId = Ref.Identifier.assertFromString(s"-pkgId-:Mod:${test.templateName}") + val cid = Value.ContractId.V1(crypto.Hash.hashPrivateKey("abc")) + val key = SValue.SRecord( + templateId, + ImmArray( + Ref.Name.assertFromString("label"), + Ref.Name.assertFromString("maintainers"), + ), + ArrayList( + SValue.SText("test-key"), + SValue.SList(FrontStack(SValue.SParty(alice))), + ), + ) + val globalKey = GlobalKeyWithMaintainers.assertBuild( + templateId, + key.toUnnormalizedValue, + Set(alice), + templateDefsPkgName, + ) + + val testCases = { + Table[Expr, SValue]( + ("expression", "arg"), + ( + e"Mod:exercise${test.templateName}AndCatchError" (metadataTestsParserParams), + SContractId(cid), + ), + ( + e"Mod:fetch${test.templateName}AndCatchError" (metadataTestsParserParams), + SContractId(cid), + ), + ( + e"Mod:fetch${test.templateName}ByInterfaceAndCatchError" (metadataTestsParserParams), + SContractId(cid), + ), + ( + e"Mod:fetch${test.templateName}ByKeyAndCatchError" (metadataTestsParserParams), + key, + ), + ( + e"Mod:lookUp${test.templateName}ByKeyAndCatchError" (metadataTestsParserParams), + key, + ), + ) + } + + forEvery(testCases) { (expr, arg) => + inside { + runUpdateApp( + compiledPackages, + packageResolution = Map( + templateDefsPkgName -> templateDefsV2PkgId + ), + expr, + Array(arg), + getContract = Map( + cid -> Versioned( + version = TransactionVersion.StableVersions.max, + Value.ContractInstance( + packageName = metadataTestsPkg.pkgName, + template = t"Mod:${test.templateName}" (templateDefsV1ParserParams) + .asInstanceOf[Ast.TTyCon] + .tycon, + arg = Value.ValueRecord(None, ImmArray(None -> Value.ValueParty(alice))), + ), + ) + ), + getKey = Map( + globalKey -> cid + ), + ) + } { + case Left( + SError.SErrorDamlException( + IE.UnhandledException( + _, + Value.ValueRecord(_, ImmArray((_, Value.ValueText(msg)))), + ) + ) + ) => + msg shouldBe test.templateName + } + } + } + } } } diff --git a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExplicitDisclosureTest.scala b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExplicitDisclosureTest.scala index aaced484a40f..c817d91edbf3 100644 --- a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExplicitDisclosureTest.scala +++ b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExplicitDisclosureTest.scala @@ -7,17 +7,17 @@ package speedy import com.digitalasset.daml.lf.data.Ref.Party import com.digitalasset.daml.lf.interpretation.Error.{ContractKeyNotFound, ContractNotActive} import com.digitalasset.daml.lf.language.LanguageMajorVersion +import com.digitalasset.daml.lf.speedy.SBuiltinFun.{SBFetchTemplate, SBUFetchKey, SBULookupKey} import com.digitalasset.daml.lf.speedy.SExpr.SEValue +import com.digitalasset.daml.lf.speedy.SValue.SContractId +import com.digitalasset.daml.lf.speedy.Speedy.ContractInfo +import com.digitalasset.daml.lf.testing.parser.Implicits._ +import com.digitalasset.daml.lf.transaction.GlobalKeyWithMaintainers import com.digitalasset.daml.lf.value.Value import com.digitalasset.daml.lf.value.Value.ContractId -import org.scalatest.{Assertion, Inside} import org.scalatest.freespec.AnyFreeSpec import org.scalatest.matchers.should.Matchers -import com.digitalasset.daml.lf.speedy.SBuiltinFun.{SBFetchTemplate, SBUFetchKey, SBULookupKey} -import com.digitalasset.daml.lf.speedy.SValue.SContractId -import com.digitalasset.daml.lf.speedy.Speedy.ContractInfo -import com.digitalasset.daml.lf.transaction.GlobalKeyWithMaintainers -import com.digitalasset.daml.lf.testing.parser.Implicits._ +import org.scalatest.{Assertion, Inside} class ExplicitDisclosureTestV2 extends ExplicitDisclosureTest(LanguageMajorVersion.V2) @@ -45,7 +45,7 @@ private[lf] class ExplicitDisclosureTest(majorLanguageVersion: LanguageMajorVers "disclosure table queried when contract ID is disclosed" - { "contract ID in disclosure table only" in { disclosureTableQueriedWhenContractDisclosed( - SBFetchTemplate(caveTemplateId)(SEValue(SContractId(contractId)), SEValue.None), + SBFetchTemplate(caveTemplateId)(SEValue(SContractId(contractId))), disclosedCaveContract, disclosures = List(disclosedCaveContract), )(result => @@ -57,7 +57,7 @@ private[lf] class ExplicitDisclosureTest(majorLanguageVersion: LanguageMajorVers "contract ID in ledger and disclosure table" in { disclosureTableQueriedWhenContractDisclosed( - SBFetchTemplate(caveTemplateId)(SEValue(SContractId(contractId)), SEValue.None), + SBFetchTemplate(caveTemplateId)(SEValue(SContractId(contractId))), disclosedCaveContract, getContract = Map(contractId -> ledgerCaveContract), disclosures = List(disclosedCaveContract), @@ -72,7 +72,7 @@ private[lf] class ExplicitDisclosureTest(majorLanguageVersion: LanguageMajorVers "contract IDs that are inactive" - { "ledger query fails when contract ID is not disclosed" in { ledgerQueryFailsWhenContractNotDisclosed( - SBFetchTemplate(caveTemplateId)(SEValue(SContractId(contractId)), SEValue.None), + SBFetchTemplate(caveTemplateId)(SEValue(SContractId(contractId))), contractId, "TestMod:destroyCave", committers = Set(ledgerParty), @@ -92,7 +92,7 @@ private[lf] class ExplicitDisclosureTest(majorLanguageVersion: LanguageMajorVers "disclosure table query fails when contract ID is disclosed" - { "contract ID in disclosure table only" in { disclosureTableQueryFailsWhenContractDisclosed( - SBFetchTemplate(caveTemplateId)(SEValue(SContractId(contractId)), SEValue.None), + SBFetchTemplate(caveTemplateId)(SEValue(SContractId(contractId))), disclosedCaveContract, contractId, "TestMod:destroyCave", @@ -112,7 +112,7 @@ private[lf] class ExplicitDisclosureTest(majorLanguageVersion: LanguageMajorVers "contract ID in ledger and disclosure table" in { disclosureTableQueryFailsWhenContractDisclosed( - SBFetchTemplate(caveTemplateId)(SEValue(SContractId(contractId)), SEValue.None), + SBFetchTemplate(caveTemplateId)(SEValue(SContractId(contractId))), disclosedCaveContract, contractId, "TestMod:destroyCave", diff --git a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/SBuiltinTest.scala b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/SBuiltinTest.scala index efbab77e9d65..15a0342c6609 100644 --- a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/SBuiltinTest.scala +++ b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/SBuiltinTest.scala @@ -9,7 +9,7 @@ import com.digitalasset.daml.lf.data.Ref.Party import com.digitalasset.daml.lf.data._ import com.digitalasset.daml.lf.interpretation.{Error => IE} import com.digitalasset.daml.lf.language.Ast._ -import com.digitalasset.daml.lf.language.LanguageMajorVersion +import com.digitalasset.daml.lf.language.{Ast, LanguageMajorVersion} import com.digitalasset.daml.lf.speedy.SBuiltinFun.{ SBCrash, SBImportInputContract, @@ -22,24 +22,17 @@ import com.digitalasset.daml.lf.speedy.Speedy.{CachedKey, ContractInfo, Machine} import com.digitalasset.daml.lf.stablepackages.StablePackages import com.digitalasset.daml.lf.testing.parser.Implicits.SyntaxHelper import com.digitalasset.daml.lf.testing.parser.ParserParameters -import com.digitalasset.daml.lf.transaction.{ - FatContractInstance, - GlobalKey, - GlobalKeyWithMaintainers, - Node, - Versioned, -} +import com.digitalasset.daml.lf.transaction._ import com.digitalasset.daml.lf.value.Value import com.digitalasset.daml.lf.value.Value.ValueArithmeticError -import org.scalatest.prop.TableDrivenPropertyChecks -import org.scalatest.matchers.should.Matchers -import org.scalatest.freespec.AnyFreeSpec import org.scalatest.Inside +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should.Matchers +import org.scalatest.prop.TableDrivenPropertyChecks import java.util import scala.language.implicitConversions import scala.util.{Failure, Try} -import scala.Ordering.Implicits._ class SBuiltinTestV2 extends SBuiltinTest(LanguageMajorVersion.V2) @@ -1734,6 +1727,42 @@ class SBuiltinTest(majorLanguageVersion: LanguageMajorVersion) } } } + + "ensure clause exception" - { + "can be caught on when creating a contract" in { + evalUpdateOnLedger(e"Mod:createFailingPreconditionAndCatchError") shouldBe Right(SUnit) + } + + "cannot be caught when exercising a choice" in { + inside { + val cid = Value.ContractId.V1(Hash.hashPrivateKey("abc")) + evalUpdateAppOnLedger( + e"Mod:exerciseFailingPreconditionAndCatchError", + Array(SContractId(cid)), + getContract = Map( + cid -> Versioned( + version = txVersion, + Value.ContractInstance( + packageName = pkg.pkgName, + template = t"Mod:FailingPrecondition".asInstanceOf[Ast.TTyCon].tycon, + arg = Value.ValueRecord(None, ImmArray(None -> Value.ValueParty(alice))), + ), + ) + ), + ) + } { + case Left( + SError.SErrorDamlException( + IE.UnhandledException( + _, + Value.ValueRecord(_, ImmArray((_, Value.ValueText(msg)))), + ) + ) + ) => + msg shouldBe "failed precondition" + } + } + } } final class SBuiltinTestHelpers(majorLanguageVersion: LanguageMajorVersion) { @@ -1808,8 +1837,40 @@ final class SBuiltinTestHelpers(majorLanguageVersion: LanguageMajorVersion) { val aliceOwesBob : Mod:Iou = Mod:Iou { i = Mod:alice, u = Mod:bob, name = "alice owes bob" }; val aliceOwesBobIface : Mod:Iface = to_interface @Mod:Iface @Mod:Iou Mod:aliceOwesBob; - } + // a template whose precondition always evaluates to false + record @serializable FailingPrecondition = { p: Party }; + template (this: FailingPrecondition) = { + // Damlc will trhow DA.Exception.PreconditionFailed:PreconditionFailed but the engine expects no particular + // exception type so we can throw Ex1 without modifying the outcome of the tests. + precondition throw @Bool @Mod:Ex1 (Mod:Ex1 {message = "failed precondition"}); + signatories Cons @Party [Mod:FailingPrecondition {p} this] (Nil @Party); + observers Nil @Party; + + choice @nonConsuming SomeChoice (self) (u: Unit): Text + , controllers (Nil @Party) + , observers (Nil @Party) + to upure @Text "SomeChoice was called"; + }; + + // checks that the FailedPrecondition error thrown when creating a FailingPrecondition instance can be caught + val createFailingPreconditionAndCatchError: Update Unit = + try @Unit + ubind _:(ContractId Mod:FailingPrecondition) <- + create @Mod:FailingPrecondition (Mod:FailingPrecondition { p = Mod:alice }) + in upure @Unit () + catch + e -> Some @(Update Unit) (upure @Unit ()); + + // Tries to catch the error throw by the ensure clause of FailingPrecondition when exercising a choice on it, + // should fail to do so. + val exerciseFailingPreconditionAndCatchError: (ContractId Mod:FailingPrecondition) -> Update Text = + \(cid: ContractId Mod:FailingPrecondition) -> + try @Text + exercise @Mod:FailingPrecondition SomeChoice cid () + catch + e -> Some @(Update Text) (upure @Text "some exception was caught"); + } """ val txVersion = pkg.languageVersion @@ -1861,12 +1922,38 @@ final class SBuiltinTestHelpers(majorLanguageVersion: LanguageMajorVersion) { Map[Value.ContractId, ContractInfo], Map[GlobalKey, Value.ContractId], ), + ] = evalUpdateOnLedger(SELet1(sexpr, SEMakeClo(Array(SELocS(1)), 1, SELocF(0))), getContract) + + def evalUpdateOnLedger( + e: Expr, + getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance] = Map.empty, + ): Either[SError, SValue] = + evalUpdateOnLedger(compiledPackages.compiler.unsafeCompile(e), getContract).map(_._1) + + def evalUpdateAppOnLedger( + e: Expr, + args: Array[SValue], + getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance] = Map.empty, + ): Either[SError, SValue] = + evalUpdateOnLedger(SEApp(compiledPackages.compiler.unsafeCompile(e), args), getContract) + .map(_._1) + + def evalUpdateOnLedger( + sexpr: SExpr, + getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance], + ): Either[ + SError, + ( + SValue, + Map[Value.ContractId, ContractInfo], + Map[GlobalKey, Value.ContractId], + ), ] = { val machine = Speedy.Machine.fromUpdateSExpr( compiledPackages, transactionSeed = crypto.Hash.hashPrivateKey("SBuiltinTest"), - updateSE = SELet1(sexpr, SEMakeClo(Array(SELocS(1)), 1, SELocF(0))), + updateSE = sexpr, committers = committers, ) diff --git a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/TransactionVersionTest.scala b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/TransactionVersionTest.scala index 8fc6dac52c53..fb92d3f2734c 100644 --- a/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/TransactionVersionTest.scala +++ b/sdk/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/TransactionVersionTest.scala @@ -4,15 +4,15 @@ package com.digitalasset.daml.lf package speedy -import com.digitalasset.daml.lf.data.{FrontStack, ImmArray, Ref} import com.digitalasset.daml.lf.data.Ref.{IdString, PackageId, Party, TypeConName} +import com.digitalasset.daml.lf.data.{FrontStack, ImmArray, Ref} import com.digitalasset.daml.lf.language.LanguageMajorVersion.V2 import com.digitalasset.daml.lf.language.{LanguageMajorVersion, LanguageVersion} import com.digitalasset.daml.lf.speedy.SBuiltinFun.SBFetchTemplate -import com.digitalasset.daml.lf.speedy.SExpr.{SEMakeClo, SEValue} +import com.digitalasset.daml.lf.speedy.SExpr.SEMakeClo import com.digitalasset.daml.lf.testing.parser -import com.digitalasset.daml.lf.transaction.{SubmittedTransaction, Versioned} import com.digitalasset.daml.lf.testing.parser.Implicits.SyntaxHelper +import com.digitalasset.daml.lf.transaction.{SubmittedTransaction, Versioned} import com.digitalasset.daml.lf.value.Value import com.digitalasset.daml.lf.value.Value.ContractId import org.scalatest.Inside @@ -258,7 +258,7 @@ private[lf] class TransactionVersionTestHelpers(majorLanguageVersion: LanguageMa Array(), 1, SExpr.SELet1General( - SBFetchTemplate(templateId)(speedyContractId, SEValue.None), + SBFetchTemplate(templateId)(speedyContractId), SExpr.SEScopeExercise( SBuiltinFun.SBUBeginExercise( templateId, diff --git a/sdk/daml-script/test/daml/upgrades/ContractKeys.daml b/sdk/daml-script/test/daml/upgrades/ContractKeys.daml index 17fd9039aaf3..3fb5474e544b 100644 --- a/sdk/daml-script/test/daml/upgrades/ContractKeys.daml +++ b/sdk/daml-script/test/daml/upgrades/ContractKeys.daml @@ -43,11 +43,11 @@ main = tests [ broken ("queryContractId, src=v1 tgt=v2", queryKeyChangedExprChangedValue) , broken ("queryContractKey, src=v1 tgt=v2", qckKeyChangedExprChangedValue) , ("fetch, src=v1 tgt=v2", fetchKeyChangedExprChangedValue) - , broken ("fetchByKey, src=v1 tgt=v2", fbkKeyChangedExprChangedValue) + , ("fetchByKey, src=v1 tgt=v2", fbkKeyChangedExprChangedValue) , ("exercise, src=v1 tgt=v2", exerciseKeyChangedExprChangedValue) - , broken ("exerciseByKey, src=v1 tgt=v2", ebkKeyChangedExprChangedValue) + , ("exerciseByKey, src=v1 tgt=v2", ebkKeyChangedExprChangedValue) , ("exerciseCmd, src=v1 tgt=v2", exerciseCmdKeyChangedExprChangedValue) - , broken ("exerciseByKeyCmd, src=v1 tgt=v2", ebkCmdKeyChangedExprChangedValue) + , ("exerciseByKeyCmd, src=v1 tgt=v2", ebkCmdKeyChangedExprChangedValue) ] ] ] diff --git a/sdk/security-evidence.md b/sdk/security-evidence.md index 23b9195292cf..d2946c6b79fe 100644 --- a/sdk/security-evidence.md +++ b/sdk/security-evidence.md @@ -46,9 +46,9 @@ - Evaluation order of create_interface with duplicate contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L746) - 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#L770) - Evaluation order of create_interface with failed precondition: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L726) -- 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#L1897) -- 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#L1879) -- 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#L1939) +- 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#L1905) +- 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#L1887) +- 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#L1947) - 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#L1235) - 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#L953) - 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#L997) @@ -61,87 +61,87 @@ - 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#L1111) - Evaluation order of exercise with argument exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1292) - Evaluation order of exercise with output exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1320) -- 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#L1600) -- 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#L1398) -- 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#L1491) -- 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#L1472) -- 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#L1580) -- 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#L1643) -- 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#L1510) -- 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#L1658) -- 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#L1733) -- 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#L1687) -- 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#L2071) -- 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#L1804) -- 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#L2007) -- 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#L2026) -- 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#L1717) -- 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#L2392) -- 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#L2157) -- 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#L2192) -- 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#L2255) -- Evaluation order of fetch of a wrongly typed disclosed contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2424) -- 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#L2142) -- Evaluation order of fetch of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2239) -- Evaluation order of fetch of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2340) -- Evaluation order of fetch of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2443) -- 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#L2357) -- 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#L2293) -- 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#L2582) -- 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#L2648) -- 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#L2507) -- 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#L2563) -- 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#L2630) -- 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#L2678) -- 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#L2710) -- 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#L2724) -- 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#L2694) -- 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#L2861) -- 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#L3001) -- 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#L2769) -- 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#L2788) -- 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#L2844) -- 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#L2946) -- 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#L2963) -- Evaluation order of fetch_interface of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3031) -- 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#L2899) -- 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#L3148) -- 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#L3213) -- 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#L3075) -- 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#L3130) -- 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#L3196) -- 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#L3243) -- 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#L3275) -- 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#L3289) -- 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#L3259) +- 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#L1604) +- 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#L1400) +- 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#L1495) +- 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#L1476) +- 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#L1584) +- 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#L1647) +- 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#L1514) +- 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#L1662) +- 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#L1741) +- 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#L1693) +- 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#L2079) +- 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#L1812) +- 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#L2015) +- 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#L2034) +- 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#L1725) +- 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#L2400) +- 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#L2165) +- 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#L2200) +- 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#L2263) +- Evaluation order of fetch of a wrongly typed disclosed contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2432) +- 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#L2150) +- Evaluation order of fetch of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2247) +- Evaluation order of fetch of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2348) +- Evaluation order of fetch of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2451) +- 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#L2365) +- 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#L2301) +- 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#L2594) +- 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#L2660) +- 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#L2517) +- 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#L2575) +- 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#L2642) +- 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#L2690) +- 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#L2722) +- 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#L2736) +- 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#L2706) +- 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#L2873) +- 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#L3013) +- 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#L2781) +- 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#L2800) +- 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#L2856) +- 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#L2958) +- 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#L2975) +- Evaluation order of fetch_interface of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3043) +- 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#L2911) +- 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#L3164) +- 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#L3229) +- 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#L3089) +- 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#L3146) +- 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#L3212) +- 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#L3259) +- 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#L3291) +- 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#L3305) +- 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#L3275) - Evaluation order of successful create: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L498) - Evaluation order of successful create_interface: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L702) -- 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#L1758) +- 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#L1766) - 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#L1030) - Evaluation order of successful exercise of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1154) - 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#L911) -- 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#L1446) -- 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#L1556) +- 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#L1450) +- 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#L1560) - 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#L1354) -- 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#L1854) -- 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#L1983) -- 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#L2222) -- Evaluation order of successful fetch of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2325) -- 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#L2119) -- 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#L2546) -- 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#L2614) -- 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#L2462) -- 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#L2827) -- 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#L2931) -- 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#L2745) -- 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#L3113) -- 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#L3180) -- 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#L3051) -- Exceptions, throw/catch.: [ExceptionTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExceptionTest.scala#L28) +- 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#L1862) +- 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#L1991) +- 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#L2230) +- Evaluation order of successful fetch of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2333) +- 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#L2127) +- 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#L2558) +- 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#L2626) +- 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#L2470) +- 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#L2839) +- 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#L2943) +- 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#L2757) +- 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#L3129) +- 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#L3196) +- 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#L3063) +- 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#L2081) -- 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#L2051) -- 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#L1921) -- 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#L2983) +- 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#L2059) +- 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#L1929) +- 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#L2995) - contract key behaviour (non-unique mode): [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L426) - contract key behaviour (unique mode): [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L436) - 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#L240) @@ -151,7 +151,7 @@ - disclosure with well-formed argument is accepted: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/preprocessing/CommandPreprocessorSpec.scala#L476) - ensure builtin operators have the correct type: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L78) - ensure expression forms have the correct type: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L138) -- 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#L1786) +- 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#L1794) - ill-formed API command is rejected: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/preprocessing/CommandPreprocessorSpec.scala#L387) - ill-formed create API command is rejected: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/preprocessing/CommandPreprocessorSpec.scala#L211) - ill-formed create replay command is rejected: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/preprocessing/CommandPreprocessorSpec.scala#L340)