Tie right-to-left evaluation order to LF v2 (#17811)

* Tie right-to-left evaluation order to LF v2

* fix typo
This commit is contained in:
Paul Brauner 2023-11-14 10:34:31 +01:00 committed by GitHub
parent 6933514df5
commit 890dee12bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 5350 additions and 5586 deletions

View File

@ -253,6 +253,18 @@ featureNatTypeErasure = Feature
, featureCppFlag = Just "DAML_NAT_TYPE_ERASURE"
}
-- This feature does not impact the compiler, but does control the evaluation
-- order integration tests via @SUPPORTS-LF-FEATURE.
featureRightToLeftEvaluation :: Feature
featureRightToLeftEvaluation = Feature
{ featureName = "Right-to-left evaluation order"
, featureVersionReq = VersionReq \case
V1 -> noMinorVersion
V2 -> allV2MinorVersions
, featureCppFlag = Just "DAML_RIGHT_TO_LEFT_EVALUATION"
}
featureExperimental :: Feature
featureExperimental = Feature
{ featureName = "Daml Experimental"
@ -281,6 +293,7 @@ allFeatures =
, featureDynamicExercise
, featurePackageUpgrades
, featureNatTypeErasure
, featureRightToLeftEvaluation
]
-- | A map from feature CPP flags to features.

View File

@ -8,7 +8,6 @@ module DA.Daml.Options.Types
( Options(..)
, EnableScenarioService(..)
, EnableScenarios(..)
, EvaluationOrder(..)
, AllowLargeTuples(..)
, StudioAutorunAllScenarios(..)
, SkipScenarioValidation(..)
@ -188,11 +187,6 @@ newtype AllowLargeTuples = AllowLargeTuples { getAllowLargeTuples :: Bool }
newtype StudioAutorunAllScenarios = StudioAutorunAllScenarios { getStudioAutorunAllScenarios :: Bool }
deriving Show
data EvaluationOrder
= LeftToRight
| RightToLeft
deriving (Read, Show, Eq)
damlArtifactDir :: FilePath
damlArtifactDir = ".daml"

View File

@ -182,8 +182,6 @@ da_haskell_library(
"true" if skip_validation else "false",
"--daml-script-v2",
"false",
"--evaluation-order",
"LeftToRight",
],
data = [
":bond-trading",
@ -215,52 +213,42 @@ da_haskell_library(
)
]
[
da_haskell_test(
name = "integration{order}-v2dev-script2".format(
order = "-r2l" if eval_order == "RightToLeft" else "",
),
size = "large",
srcs = ["src/DA/Test/DamlcIntegrationMain.hs"],
args = [
"--daml-lf-version",
"2.dev", # script2 only supports 2.x
"--skip-validation",
"false",
"--daml-script-v2",
"true",
"--evaluation-order",
eval_order,
],
data = [
":bond-trading",
":cant-skip-preprocessor",
":daml-test-files",
":package-vetting-package-a.dar",
":package-vetting-package-b.dar",
":query-lf-lib",
"//compiler/damlc/pkg-db",
"//compiler/damlc/stable-packages",
"//compiler/scenario-service/server:scenario_service_jar",
"//daml-script/daml3:daml3-script-2.dev.dar",
"@jq_dev_env//:jq",
ghc_pkg,
],
hackage_deps = [
"base",
],
main_function = "DA.Test.DamlcIntegrationMain.main",
src_strip_prefix = "src",
visibility = ["//visibility:public"],
deps = [
":integration-lib",
],
)
for eval_order in [
"LeftToRight",
"RightToLeft",
]
]
da_haskell_test(
name = "integration-v2dev-script2",
size = "large",
srcs = ["src/DA/Test/DamlcIntegrationMain.hs"],
args = [
"--daml-lf-version",
"2.dev", # script2 only supports 2.x
"--skip-validation",
"false",
"--daml-script-v2",
"true",
],
data = [
":bond-trading",
":cant-skip-preprocessor",
":daml-test-files",
":package-vetting-package-a.dar",
":package-vetting-package-b.dar",
":query-lf-lib",
"//compiler/damlc/pkg-db",
"//compiler/damlc/stable-packages",
"//compiler/scenario-service/server:scenario_service_jar",
"//daml-script/daml3:daml3-script-2.dev.dar",
"@jq_dev_env//:jq",
ghc_pkg,
],
hackage_deps = [
"base",
],
main_function = "DA.Test.DamlcIntegrationMain.main",
src_strip_prefix = "src",
visibility = ["//visibility:public"],
deps = [
":integration-lib",
],
)
# Tests for daml-doc
da_haskell_test(

View File

@ -12,9 +12,9 @@
{-# LANGUAGE ApplicativeDo #-}
module SemanticsEvalOrder where
-- @DOES-NOT-SUPPORT-LF-FEATURE DAML_RIGHT_TO_LEFT_EVALUATION
-- @EVALUATION-ORDER LeftToRight
module SemanticsEvalOrder where
import Daml.Script
import ScriptAssertHelpers

View File

@ -12,9 +12,9 @@
{-# LANGUAGE ApplicativeDo #-}
module SemanticsEvalOrderRightToLeft where
-- @SUPPORTS-LF-FEATURE DAML_RIGHT_TO_LEFT_EVALUATION
-- @EVALUATION-ORDER RightToLeft
module SemanticsEvalOrderRightToLeft where
import Daml.Script
import ScriptAssertHelpers

View File

@ -131,14 +131,6 @@ instance IsOption IsScriptV2Opt where
optionName = Tagged "daml-script-v2"
optionHelp = Tagged "Use daml script v2 (true|false)"
newtype EvaluationOrderOpt = EvaluationOrderOpt EvaluationOrder
instance IsOption EvaluationOrderOpt where
defaultValue = EvaluationOrderOpt LeftToRight
parseValue = fmap EvaluationOrderOpt . readMaybe
optionName = Tagged "evaluation-order"
optionHelp = Tagged "Use the specified evaluation order for Daml expressions"
type ScriptPackageData = (FilePath, [PackageFlag])
-- | Creates a temp directory with daml script v1 installed, gives the database db path and package flag
@ -202,12 +194,11 @@ main = do
-- This is a bit hacky, we want the LF version before we hand over to
-- tasty. To achieve that we first pass with optparse-applicative ignoring
-- everything apart from the LF version.
(LfVersionOpt lfVer, SkipValidationOpt _, IsScriptV2Opt isV2, EvaluationOrderOpt evalOrder) <- do
let parser = (,,,)
(LfVersionOpt lfVer, SkipValidationOpt _, IsScriptV2Opt isV2) <- do
let parser = (,,)
<$> optionCLParser
<*> optionCLParser
<*> optionCLParser
<*> optionCLParser
<* many (strArgument @String mempty)
execParser (info parser forwardOptions)
@ -217,7 +208,7 @@ main = do
let scenarioConf = SS.defaultScenarioServiceConfig
{ SS.cnfJvmOptions = ["-Xmx200M"]
, SS.cnfEvaluationTimeout = Just 3
, SS.cnfEvaluationOrder = evalOrder }
}
withDep $ \scriptPackageData ->
SS.withScenarioService lfVer scenarioLogger scenarioConf $ \scenarioService -> do
@ -236,7 +227,6 @@ main = do
[ Option (Proxy @LfVersionOpt)
, Option (Proxy @SkipValidationOpt)
, Option (Proxy @IsScriptV2Opt)
, Option (Proxy @EvaluationOrderOpt)
] :
defaultIngredients
@ -334,7 +324,6 @@ getIntegrationTests registerTODO scenarioService (packageDbPath, packageFlags) =
tree = askOption $ \(LfVersionOpt version) ->
askOption @IsScriptV2Opt $ \isScriptV2Opt ->
askOption $ \(SkipValidationOpt skipValidation) ->
askOption $ \(EvaluationOrderOpt evalOrder) ->
let opts = (defaultOptions (Just version))
{ optPackageDbs = [packageDbPath]
, optThreads = 0
@ -363,7 +352,7 @@ getIntegrationTests registerTODO scenarioService (packageDbPath, packageFlags) =
shutdown
$ \service ->
testGroup ("Tests for Daml-LF " ++ renderPretty version) $
map (damlFileTestTree version isScriptV2Opt evalOrder service outdir registerTODO) damlTests
map (damlFileTestTree version isScriptV2Opt service outdir registerTODO) damlTests
pure tree
@ -415,8 +404,8 @@ testSetup getService outdir path = do
, buildLog
}
damlFileTestTree :: LF.Version -> IsScriptV2Opt -> EvaluationOrder -> IO IdeState -> FilePath -> (TODO -> IO ()) -> DamlTestInput -> TestTree
damlFileTestTree version (IsScriptV2Opt isScriptV2Opt) evalOrderOpt getService outdir registerTODO input
damlFileTestTree :: LF.Version -> IsScriptV2Opt -> IO IdeState -> FilePath -> (TODO -> IO ()) -> DamlTestInput -> TestTree
damlFileTestTree version (IsScriptV2Opt isScriptV2Opt) getService outdir registerTODO input
| any (ignoreVersion version) anns =
singleTest name $ TestCase \_ ->
pure (testPassed "") { resultShortDescription = "IGNORE" }
@ -466,7 +455,6 @@ damlFileTestTree version (IsScriptV2Opt isScriptV2Opt) evalOrderOpt getService o
SupportsFeature featureName -> not (version `satisfies` versionReqForFeaturePartial featureName)
DoesNotSupportFeature featureName -> version `satisfies` versionReqForFeaturePartial featureName
ScriptV2 -> not isScriptV2Opt
EvaluationOrder evalOrder -> evalOrder /= evalOrderOpt
_ -> False
diff ref new = [POSIX_DIFF, "--strip-trailing-cr", ref, new]
@ -570,8 +558,6 @@ data Ann
| Ledger String FilePath
-- ^ I expect the output of running the script named <first argument> to match the golden file <second argument>.
-- The path of the golden file is relative to the `.daml` test file.
| EvaluationOrder EvaluationOrder
-- ^ Only run this test with the given evaluation order.
readFileAnns :: FilePath -> IO [Ann]
readFileAnns file = do
@ -592,7 +578,6 @@ readFileAnns file = do
("SCRIPT-V2", _) -> Just ScriptV2
("TODO",x) -> Just $ Todo x
("LEDGER", words -> [script, path]) -> Just $ Ledger script path
("EVALUATION-ORDER", x) -> EvaluationOrder <$> readMaybe x
_ -> error $ "Can't understand test annotation in " ++ show file ++ ", got " ++ show x
f _ = Nothing

View File

@ -44,7 +44,7 @@ import qualified Data.Set as S
import qualified Data.Text as T
import System.Directory
import DA.Daml.Options.Types (EnableScenarioService(..), EnableScenarios(..), EvaluationOrder (..))
import DA.Daml.Options.Types (EnableScenarioService(..), EnableScenarios(..))
import DA.Daml.Project.Config
import DA.Daml.Project.Consts
import DA.Daml.Project.Types
@ -75,7 +75,6 @@ toLowLevelOpts optDamlLfVersion Options{..} =
optEvaluationTimeout = fromMaybe 60 $ cnfEvaluationTimeout optScenarioServiceConfig
optGrpcMaxMessageSize = cnfGrpcMaxMessageSize optScenarioServiceConfig
optJvmOptions = cnfJvmOptions optScenarioServiceConfig
optEvaluationOrder = cnfEvaluationOrder optScenarioServiceConfig
data Handle = Handle
{ hLowLevelHandle :: LowLevel.Handle
@ -164,7 +163,6 @@ data ScenarioServiceConfig = ScenarioServiceConfig
, cnfGrpcTimeout :: Maybe LowLevel.TimeoutSeconds
, cnfEvaluationTimeout :: Maybe LowLevel.TimeoutSeconds
, cnfJvmOptions :: [String]
, cnfEvaluationOrder :: EvaluationOrder
} deriving Show
defaultScenarioServiceConfig :: ScenarioServiceConfig
@ -173,7 +171,6 @@ defaultScenarioServiceConfig = ScenarioServiceConfig
, cnfGrpcTimeout = Nothing
, cnfEvaluationTimeout = Nothing
, cnfJvmOptions = []
, cnfEvaluationOrder = LeftToRight
}
readScenarioServiceConfig :: IO ScenarioServiceConfig
@ -191,7 +188,6 @@ parseScenarioServiceConfig conf = do
cnfGrpcTimeout <- queryOpt "grpc-timeout"
cnfEvaluationTimeout <- queryOpt "evaluation-timeout"
cnfJvmOptions <- fromMaybe [] <$> queryOpt "jvm-options"
let cnfEvaluationOrder = LeftToRight
pure ScenarioServiceConfig {..}
where queryOpt opt = do
a <- queryProjectConfig ["script-service", opt] conf

View File

@ -48,7 +48,7 @@ import Control.Exception
import Control.Monad
import Control.Monad.IO.Class
import DA.Daml.LF.Mangling
import DA.Daml.Options.Types (EnableScenarios (..), EvaluationOrder (..))
import DA.Daml.Options.Types (EnableScenarios (..))
import qualified DA.Daml.LF.Proto3.EncodeV1 as EncodeV1
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
@ -89,7 +89,6 @@ data Options = Options
, optLogError :: String -> IO ()
, optDamlLfVersion :: LF.Version
, optEnableScenarios :: EnableScenarios
, optEvaluationOrder :: EvaluationOrder
}
type TimeoutSeconds = Int64
@ -229,7 +228,6 @@ withScenarioService opts@Options{..} f = do
[ optJvmOptions
, ["-jar" , optServerJar]
, ["--max-inbound-message-size=" <> show size | Just size <- [optGrpcMaxMessageSize]]
, ["--evaluation-order=" <> show optEvaluationOrder]
]
exitExpected <- newIORef False

View File

@ -16,14 +16,12 @@ import com.daml.lf.archive
import com.daml.lf.data.ImmArray
import com.daml.lf.data.Ref
import com.daml.lf.data.Ref.ModuleName
import com.daml.lf.language.LanguageDevConfig.{EvaluationOrder, LeftToRight, RightToLeft}
import com.daml.lf.language.LanguageVersion
import com.daml.lf.scenario.api.v1.{Map => _, _}
import com.daml.logging.LoggingContext
import io.grpc.stub.StreamObserver
import io.grpc.{Status, StatusRuntimeException}
import io.grpc.netty.NettyServerBuilder
import scopt.Read
import java.time.Instant
import scala.util.Random
@ -35,8 +33,7 @@ import scala.jdk.CollectionConverters._
import scala.util.control.NonFatal
private final case class ScenarioServiceConfig(
maxInboundMessageSize: Int,
evaluationOrder: EvaluationOrder,
maxInboundMessageSize: Int
)
@SuppressWarnings(Array("org.wartremover.warts.NonUnitStatements"))
@ -53,26 +50,13 @@ private object ScenarioServiceConfig {
.text(
s"Optional max inbound message size in bytes. Defaults to ${DefaultMaxInboundMessageSize}."
)
val evaluationOrderRead: Read[EvaluationOrder] = Read.reads {
case "LeftToRight" => LeftToRight
case "RightToLeft" => RightToLeft
case s => throw new IllegalArgumentException(s"$s is not an EvaluationOrder")
}
opt[EvaluationOrder]("evaluation-order")(evaluationOrderRead)
.optional()
.action((x, c) => c.copy(evaluationOrder = x))
.text(
"The evaluation order of expressions: LeftToRight or RightToLeft. Defaults to LeftToRight."
)
}
def parse(args: Array[String]): Option[ScenarioServiceConfig] =
parser.parse(
args,
ScenarioServiceConfig(
maxInboundMessageSize = DefaultMaxInboundMessageSize,
evaluationOrder = LeftToRight,
maxInboundMessageSize = DefaultMaxInboundMessageSize
),
)
}
@ -92,7 +76,7 @@ object ScenarioServiceMain extends App {
val server =
NettyServerBuilder
.forAddress(new InetSocketAddress(InetAddress.getLoopbackAddress, 0)) // any free port
.addService(new ScenarioService(config.evaluationOrder))
.addService(new ScenarioService())
.maxInboundMessageSize(config.maxInboundMessageSize)
.build
server.start()
@ -190,9 +174,7 @@ object ScriptStream {
}
@SuppressWarnings(Array("org.wartremover.warts.NonUnitStatements"))
class ScenarioService(
evaluationOrder: EvaluationOrder
)(implicit
class ScenarioService(implicit
ec: ExecutionContext,
esf: ExecutionSequencerFactory,
mat: Materializer,
@ -362,7 +344,7 @@ class ScenarioService(
majorVersion,
LanguageVersion.Minor(req.getLfMinor),
)
val ctx = Context.newContext(lfVersion, req.getEvaluationTimeout.seconds, evaluationOrder)
val ctx = Context.newContext(lfVersion, req.getEvaluationTimeout.seconds)
contexts += (ctx.contextId -> ctx)
val response = NewContextResponse.newBuilder.setContextId(ctx.contextId).build
respObs.onNext(response)
@ -480,5 +462,4 @@ class ScenarioService(
}
}
}
}

View File

@ -18,7 +18,6 @@ import com.daml.lf.speedy.SExpr.{LfDefRef, SDefinitionRef}
import com.daml.lf.validation.Validation
import com.google.protobuf.ByteString
import com.daml.lf.engine.script.{Runner, Script}
import com.daml.lf.language.LanguageDevConfig.EvaluationOrder
import com.daml.logging.LoggingContext
import org.slf4j.LoggerFactory
@ -37,17 +36,16 @@ object Context {
private val contextCounter = new AtomicLong()
def newContext(lfVerion: LanguageVersion, timeout: Duration, evaluationOrder: EvaluationOrder)(
implicit loggingContext: LoggingContext
def newContext(lfVerion: LanguageVersion, timeout: Duration)(implicit
loggingContext: LoggingContext
): Context =
new Context(contextCounter.incrementAndGet(), lfVerion, timeout, evaluationOrder)
new Context(contextCounter.incrementAndGet(), lfVerion, timeout)
}
class Context(
val contextId: Context.ContextId,
languageVersion: LanguageVersion,
timeout: Duration,
evaluationOrder: EvaluationOrder,
)(implicit
loggingContext: LoggingContext
) {
@ -61,7 +59,6 @@ class Context(
packageValidation = Compiler.FullPackageValidation,
profiling = Compiler.NoProfile,
stacktracing = Compiler.FullStackTrace,
evaluationOrder = evaluationOrder,
)
/** The package identifier to use for modules added to the context.
@ -81,7 +78,7 @@ class Context(
def loadedPackages(): Iterable[PackageId] = extSignatures.keys
def cloneContext(): Context = synchronized {
val newCtx = Context.newContext(languageVersion, timeout, evaluationOrder)
val newCtx = Context.newContext(languageVersion, timeout)
newCtx.extSignatures = extSignatures
newCtx.extDefns = extDefns
newCtx.modules = modules

View File

@ -4,7 +4,6 @@
package com.daml.lf
package engine
import com.daml.lf.language.LanguageDevConfig.{EvaluationOrder, LeftToRight}
import com.daml.lf.speedy.{
AuthorizationChecker,
DefaultAuthorizationChecker,
@ -38,10 +37,6 @@ import com.daml.lf.transaction.ContractKeyUniquenessMode
* steps needed to produce a Result.
* @param enableContractUpgrading If set this flag a choice that is executed against
* a contract may exist in a package different from that of the package.
* @param evaluationOrder The order in which applications are evaluated: from left
* to right or from right to left. Right-to-left is incompatible with Daml 2.x
* but it is faster and allows for simplifications in the interpreter. We're
* aiming for right-to-left to be the default in Daml 3.
*/
final case class EngineConfig(
allowedLanguageVersions: VersionRange[language.LanguageVersion],
@ -54,35 +49,7 @@ final case class EngineConfig(
checkAuthorization: Boolean = true,
iterationsBetweenInterruptions: Long = 10000,
enableContractUpgrading: Boolean = false,
evaluationOrder: EvaluationOrder = LeftToRight,
) {
// TODO https://github.com/digital-asset/daml/issues/17270
// Remove this overloaded constructor once Canton has been updated.
def this(
allowedLanguageVersions: VersionRange[language.LanguageVersion],
packageValidation: Boolean,
stackTraceMode: Boolean,
profileDir: Option[Path],
contractKeyUniqueness: ContractKeyUniquenessMode,
requireSuffixedGlobalContractId: Boolean,
limits: interpretation.Limits,
checkAuthorization: Boolean,
iterationsBetweenInterruptions: Long,
enableContractUpgrading: Boolean,
) = this(
allowedLanguageVersions,
packageValidation,
stackTraceMode,
profileDir,
contractKeyUniqueness,
requireSuffixedGlobalContractId,
limits,
checkAuthorization,
iterationsBetweenInterruptions,
enableContractUpgrading,
LeftToRight,
)
private[lf] def getCompilerConfig: speedy.Compiler.Config =
speedy.Compiler.Config(
allowedLanguageVersions,
@ -102,7 +69,6 @@ final case class EngineConfig(
else
speedy.Compiler.NoProfile,
enableContractUpgrading = enableContractUpgrading,
evaluationOrder = evaluationOrder,
)
private[lf] def authorizationChecker: AuthorizationChecker =

View File

@ -7,7 +7,7 @@ package speedy
import com.daml.lf.data.Ref._
import com.daml.lf.data.{ImmArray, Ref, Struct, Time}
import com.daml.lf.language.Ast._
import com.daml.lf.language.LanguageDevConfig.{EvaluationOrder, LeftToRight, RightToLeft}
import com.daml.lf.language.LanguageVersionRangeOps.LanguageVersionRange
import com.daml.lf.language.{
LanguageMajorVersion,
LanguageVersion,
@ -77,7 +77,6 @@ private[lf] object Compiler {
profiling: ProfilingMode,
stacktracing: StackTraceMode,
enableContractUpgrading: Boolean = false,
evaluationOrder: EvaluationOrder = LeftToRight,
)
object Config {
@ -365,7 +364,7 @@ private[lf] final class Compiler(
private[this] def pipeline(sexpr: s.SExpr): t.SExpr =
flattenToAnf(
closureConvert(sexpr),
evaluationOrder = config.evaluationOrder,
evaluationOrder = config.allowedLanguageVersions.majorVersion.evaluationOrder,
)
private[this] def compileModule(
@ -470,16 +469,12 @@ private[lf] final class Compiler(
val t0 = Time.Timestamp.now()
pkgInterface.lookupPackage(pkgId) match {
case Right(pkg) => {
case Right(pkg) =>
if (
!stablePackageIds.contains(pkgId) && !config.allowedLanguageVersions
.contains(pkg.languageVersion)
)
throw LanguageVersionError(pkgId, pkg.languageVersion, config.allowedLanguageVersions)
if (config.evaluationOrder == RightToLeft && !pkg.languageVersion.isDevVersion)
throw CompilationError("Right-to-left evaluation is only available in dev")
}
case _ =>
}

View File

@ -7,7 +7,6 @@ package speedy
import com.daml.lf.data.FrontStack
import com.daml.lf.data.Ref.Party
import com.daml.lf.interpretation.Error.FailedAuthorization
import com.daml.lf.language.LanguageDevConfig.{EvaluationOrder}
import com.daml.lf.language.LanguageMajorVersion
import com.daml.lf.ledger.FailedAuthorization.{CreateMissingAuthorization, NoAuthorizers}
import com.daml.lf.speedy.SError.SError
@ -33,188 +32,180 @@ class ChoiceAuthorityTest(majorLanguageVersion: LanguageMajorVersion)
implicit val defaultParserParameters: ParserParameters[this.type] =
ParserParameters.defaultFor[this.type](majorLanguageVersion)
for (evaluationOrder <- EvaluationOrder.valuesFor(majorLanguageVersion)) {
val pkgs: PureCompiledPackages = SpeedyTestLib.typeAndCompile(
p"""
module M {
evaluationOrder.toString - {
record @serializable Goal = { goal: Party } ;
template (record : Goal) = {
precondition True;
signatories Cons @Party [M:Goal {goal} record] (Nil @Party);
observers Nil @Party;
agreement "Agreement";
};
val pkgs: PureCompiledPackages = SpeedyTestLib.typeAndCompile(
p"""
module M {
record @serializable T = { theSig: Party, theCon: Party, theAut: List Party, theGoal: Party };
template (this: T) = {
precondition True;
signatories Cons @Party [M:T {theSig} this] Nil @Party;
observers Nil @Party;
agreement "Agreement";
record @serializable Goal = { goal: Party } ;
template (record : Goal) = {
precondition True;
signatories Cons @Party [M:Goal {goal} record] (Nil @Party);
observers Nil @Party;
agreement "Agreement";
};
choice ChoiceWithExplicitAuthority (self) (u: Unit) : Unit,
controllers Cons @Party [M:T {theCon} this] Nil @Party
, authorizers M:T {theAut} this
to
ubind x1: ContractId M:Goal <- create @M:Goal (M:Goal { goal = M:T {theGoal} this })
in upure @Unit ();
};
record @serializable T = { theSig: Party, theCon: Party, theAut: List Party, theGoal: Party };
template (this: T) = {
precondition True;
signatories Cons @Party [M:T {theSig} this] Nil @Party;
observers Nil @Party;
agreement "Agreement";
val call : Party -> Party -> List Party -> Party -> Update Unit =
\(theSig: Party) ->
\(theCon: Party) ->
\(theAut: List Party) ->
\(theGoal: Party) ->
ubind
cid : ContractId M:T <- create @M:T (M:T {theSig = theSig, theCon = theCon, theAut = theAut, theGoal = theGoal})
in exercise @M:T ChoiceWithExplicitAuthority cid ();
}
"""
)
choice ChoiceWithExplicitAuthority (self) (u: Unit) : Unit,
controllers Cons @Party [M:T {theCon} this] Nil @Party
, authorizers M:T {theAut} this
to
ubind x1: ContractId M:Goal <- create @M:Goal (M:Goal { goal = M:T {theGoal} this })
in upure @Unit ();
};
type Success = (SubmittedTransaction, List[AuthRequest])
val call : Party -> Party -> List Party -> Party -> Update Unit =
\(theSig: Party) ->
\(theCon: Party) ->
\(theAut: List Party) ->
\(theGoal: Party) ->
ubind
cid : ContractId M:T <- create @M:T (M:T {theSig = theSig, theCon = theCon, theAut = theAut, theGoal = theGoal})
in exercise @M:T ChoiceWithExplicitAuthority cid ();
}
""",
evaluationOrder,
)
val alice = Party.assertFromString("Alice")
val bob = Party.assertFromString("Bob")
val charlie = Party.assertFromString("Charlie")
type Success = (SubmittedTransaction, List[AuthRequest])
// In all these tests; alice is the template signatory; bob is the choice controller
val theSig: Party = alice
val theCon: Party = bob
val alice = Party.assertFromString("Alice")
val bob = Party.assertFromString("Bob")
val charlie = Party.assertFromString("Charlie")
def makeSetPartyValue(set: Set[Party]): SValue = {
SList(FrontStack(set.toList.map(SParty(_)): _*))
}
// In all these tests; alice is the template signatory; bob is the choice controller
val theSig: Party = alice
val theCon: Party = bob
def runExample(
theAut: Set[Party], // The set of parties lists in the explicit choice authority decl.
theGoal: Party, // The signatory of the created Goal template.
): Either[SError, Success] = {
import SpeedyTestLib.loggingContext
val committers = Set(theSig, theCon)
val example = SEApp(
pkgs.compiler.unsafeCompile(e"M:call"),
Array(
SParty(theSig),
SParty(theCon),
makeSetPartyValue(theAut),
SParty(theGoal),
),
)
val machine = Speedy.Machine.fromUpdateSExpr(pkgs, transactionSeed, example, committers)
SpeedyTestLib
.buildTransactionCollectRequests(machine)
.map { case (x, ars, _) => (x, ars) } // ignoring any UpgradeVerificationRequest
}
def makeSetPartyValue(set: Set[Party]): SValue = {
SList(FrontStack(set.toList.map(SParty(_)): _*))
"Happy" - {
"restrict authority: {A,B}-->A (need A)" in {
val res = runExample(theAut = Set(alice), theGoal = alice)
inside(res) { case Right((_, ars)) =>
ars shouldBe List()
}
}
def runExample(
theAut: Set[Party], // The set of parties lists in the explicit choice authority decl.
theGoal: Party, // The signatory of the created Goal template.
): Either[SError, Success] = {
import SpeedyTestLib.loggingContext
val committers = Set(theSig, theCon)
val example = SEApp(
pkgs.compiler.unsafeCompile(e"M:call"),
Array(
SParty(theSig),
SParty(theCon),
makeSetPartyValue(theAut),
SParty(theGoal),
),
)
val machine = Speedy.Machine.fromUpdateSExpr(pkgs, transactionSeed, example, committers)
SpeedyTestLib
.buildTransactionCollectRequests(machine)
.map { case (x, ars, _) => (x, ars) } // ignoring any UpgradeVerificationRequest
"restrict authority: {A,B}-->B (need B)" in {
val res = runExample(theAut = Set(bob), theGoal = bob)
inside(res) { case Right((_, ars)) =>
ars shouldBe List()
}
}
"Happy" - {
"restrict authority: {A,B}-->A (need A)" in {
val res = runExample(theAut = Set(alice), theGoal = alice)
inside(res) { case Right((_, ars)) =>
ars shouldBe List()
}
}
"restrict authority: {A,B}-->B (need B)" in {
val res = runExample(theAut = Set(bob), theGoal = bob)
inside(res) { case Right((_, ars)) =>
ars shouldBe List()
}
}
"restrict authority: {A,B}-->{A,B} (need A)" in {
val res = runExample(theAut = Set(alice, bob), theGoal = alice)
inside(res) { case Right((_, ars)) =>
ars shouldBe List()
}
}
"restrict authority: {A,B}-->{A,B} (need B)" in {
val res = runExample(theAut = Set(alice, bob), theGoal = bob)
inside(res) { case Right((_, ars)) =>
ars shouldBe List()
}
}
"change/gain authority {A,B}-->{C} (need C)" in {
inside(runExample(theAut = Set(charlie), theGoal = charlie)) { case Right((_, ars)) =>
ars shouldBe List(AuthRequest(holding = Set(alice, bob), requesting = Set(charlie)))
}
}
"change/gain authority {A,B}-->{A,C} (need A)" in {
inside(runExample(theAut = Set(alice, charlie), theGoal = alice)) {
case Right((_, ars)) =>
ars shouldBe List(AuthRequest(holding = Set(alice, bob), requesting = Set(charlie)))
}
}
"change/gain authority {A,B}-->{B,C} (need B)" in {
inside(runExample(theAut = Set(bob, charlie), theGoal = bob)) { case Right((_, ars)) =>
ars shouldBe List(AuthRequest(holding = Set(alice, bob), requesting = Set(charlie)))
}
}
"restrict authority: {A,B}-->{A,B} (need A)" in {
val res = runExample(theAut = Set(alice, bob), theGoal = alice)
inside(res) { case Right((_, ars)) =>
ars shouldBe List()
}
}
"Sad" - { // examples which cause Authorization failure
"restrict authority: {A,B}-->{A,B} (need B)" in {
val res = runExample(theAut = Set(alice, bob), theGoal = bob)
inside(res) { case Right((_, ars)) =>
ars shouldBe List()
}
}
"restrict authority {A,B}-->{} (empty!)" in {
inside(runExample(theAut = Set(), theGoal = alice)) { case Left(err) =>
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
inside(why) { case _: NoAuthorizers =>
}
}
"change/gain authority {A,B}-->{C} (need C)" in {
inside(runExample(theAut = Set(charlie), theGoal = charlie)) { case Right((_, ars)) =>
ars shouldBe List(AuthRequest(holding = Set(alice, bob), requesting = Set(charlie)))
}
}
"change/gain authority {A,B}-->{A,C} (need A)" in {
inside(runExample(theAut = Set(alice, charlie), theGoal = alice)) { case Right((_, ars)) =>
ars shouldBe List(AuthRequest(holding = Set(alice, bob), requesting = Set(charlie)))
}
}
"change/gain authority {A,B}-->{B,C} (need B)" in {
inside(runExample(theAut = Set(bob, charlie), theGoal = bob)) { case Right((_, ars)) =>
ars shouldBe List(AuthRequest(holding = Set(alice, bob), requesting = Set(charlie)))
}
}
}
"Sad" - { // examples which cause Authorization failure
"restrict authority {A,B}-->{} (empty!)" in {
inside(runExample(theAut = Set(), theGoal = alice)) { case Left(err) =>
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
inside(why) { case _: NoAuthorizers =>
}
}
}
}
"restrict authority {A,B}-->A (need B)" in {
inside(runExample(theAut = Set(alice), theGoal = bob)) { case Left(err) =>
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
inside(why) { case cma: CreateMissingAuthorization =>
cma.authorizingParties shouldBe Set(alice)
cma.requiredParties shouldBe Set(bob)
}
}
"restrict authority {A,B}-->A (need B)" in {
inside(runExample(theAut = Set(alice), theGoal = bob)) { case Left(err) =>
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
inside(why) { case cma: CreateMissingAuthorization =>
cma.authorizingParties shouldBe Set(alice)
cma.requiredParties shouldBe Set(bob)
}
}
}
}
"restrict authority {A,B}-->B (need A)" in {
inside(runExample(theAut = Set(bob), theGoal = alice)) { case Left(err) =>
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
inside(why) { case cma: CreateMissingAuthorization =>
cma.authorizingParties shouldBe Set(bob)
cma.requiredParties shouldBe Set(alice)
}
}
"restrict authority {A,B}-->B (need A)" in {
inside(runExample(theAut = Set(bob), theGoal = alice)) { case Left(err) =>
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
inside(why) { case cma: CreateMissingAuthorization =>
cma.authorizingParties shouldBe Set(bob)
cma.requiredParties shouldBe Set(alice)
}
}
}
}
"restrict authority: {A,B}-->{A,B} (need C)" in {
inside(runExample(theAut = Set(alice, bob), theGoal = charlie)) { case Left(err) =>
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
inside(why) { case cma: CreateMissingAuthorization =>
cma.authorizingParties shouldBe Set(alice, bob)
cma.requiredParties shouldBe Set(charlie)
}
}
"restrict authority: {A,B}-->{A,B} (need C)" in {
inside(runExample(theAut = Set(alice, bob), theGoal = charlie)) { case Left(err) =>
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
inside(why) { case cma: CreateMissingAuthorization =>
cma.authorizingParties shouldBe Set(alice, bob)
cma.requiredParties shouldBe Set(charlie)
}
}
}
}
"change/gain authority {A,B}-->{C} (need A)" in {
inside(runExample(theAut = Set(charlie), theGoal = alice)) { case Left(err) =>
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
inside(why) { case cma: CreateMissingAuthorization =>
cma.authorizingParties shouldBe Set(charlie)
cma.requiredParties shouldBe Set(alice)
}
}
"change/gain authority {A,B}-->{C} (need A)" in {
inside(runExample(theAut = Set(charlie), theGoal = alice)) { case Left(err) =>
inside(err) { case SError.SErrorDamlException(FailedAuthorization(_, why)) =>
inside(why) { case cma: CreateMissingAuthorization =>
cma.authorizingParties shouldBe Set(charlie)
cma.requiredParties shouldBe Set(alice)
}
}
}

View File

@ -7,7 +7,6 @@ package speedy
import com.daml.lf.data.Ref.{IdString, Party}
import com.daml.lf.data.{FrontStack, ImmArray, Ref, Struct}
import com.daml.lf.language.{Ast, LanguageMajorVersion}
import com.daml.lf.language.LanguageDevConfig.EvaluationOrder
import com.daml.lf.speedy.SExpr.SEMakeClo
import com.daml.lf.speedy.SValue.SToken
import com.daml.lf.speedy.Speedy.{CachedKey, ContractInfo}
@ -26,17 +25,13 @@ import org.scalatest.matchers.{MatchResult, Matcher}
/** Shared test data and functions for testing explicit disclosure.
*/
private[lf] class ExplicitDisclosureLib(
majorLanguageVersion: LanguageMajorVersion,
evaluationOrder: EvaluationOrder,
) {
private[lf] class ExplicitDisclosureLib(majorLanguageVersion: LanguageMajorVersion) {
implicit val defaultParserParameters: ParserParameters[this.type] =
ParserParameters.defaultFor[this.type](majorLanguageVersion)
val testKeyName: String = "test-key"
val pkg: PureCompiledPackages = SpeedyTestLib.typeAndCompile(
p"""
val pkg: PureCompiledPackages = SpeedyTestLib.typeAndCompile(p"""
module TestMod {
record @serializable Key = { label: Text, maintainers: List Party };
@ -89,9 +84,7 @@ private[lf] class ExplicitDisclosureLib(
None -> Nil @t
| Some x -> Cons @t [x] (Nil @t);
}
""",
evaluationOrder,
)
""")
val useSharedKeys: Boolean = Util.sharedKey(defaultParserParameters.languageVersion)
val maintainerParty: IdString.Party = Ref.Party.assertFromString("maintainerParty")
val ledgerParty: IdString.Party = Ref.Party.assertFromString("ledgerParty")

View File

@ -6,7 +6,6 @@ package speedy
import com.daml.lf.data.Ref.Party
import com.daml.lf.interpretation.Error.{ContractKeyNotFound, ContractNotActive}
import com.daml.lf.language.LanguageDevConfig.EvaluationOrder
import com.daml.lf.language.LanguageMajorVersion
import com.daml.lf.speedy.SExpr.SEValue
import com.daml.lf.value.Value
@ -28,188 +27,228 @@ private[lf] class ExplicitDisclosureTest(majorLanguageVersion: LanguageMajorVers
with Inside
with Matchers {
for (evaluationOrder <- EvaluationOrder.valuesFor(majorLanguageVersion)) {
val explicitDisclosureLib = new ExplicitDisclosureLib(majorLanguageVersion)
evaluationOrder.toString - {
val explicitDisclosureLib = new ExplicitDisclosureLib(majorLanguageVersion, evaluationOrder)
import explicitDisclosureLib._
import explicitDisclosureLib._
"disclosed contract behaviour" - {
"fetching contracts" - {
"test data validation" in {
ledgerParty should not be disclosureParty
ledgerParty should not be maintainerParty
disclosureParty should not be maintainerParty
getOwner(ledgerCaveContract.unversioned.arg) shouldBe Some(ledgerParty)
inside(disclosedCaveContract) { case (`contractId`, contract) =>
getOwner(contract.arg) shouldBe Some(disclosureParty)
}
"disclosed contract behaviour" - {
"fetching contracts" - {
"test data validation" in {
ledgerParty should not be disclosureParty
ledgerParty should not be maintainerParty
disclosureParty should not be maintainerParty
getOwner(ledgerCaveContract.unversioned.arg) shouldBe Some(ledgerParty)
inside(disclosedCaveContract) { case (`contractId`, contract) =>
getOwner(contract.arg) shouldBe Some(disclosureParty)
}
}
"ledger queried when contract ID is not disclosed" in {
ledgerQueriedWhenContractNotDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
getContract = Map(contractId -> ledgerCaveContract),
)(result =>
inside(result) {
case Right(SValue.SAny(_, contract @ SValue.SRecord(`caveTemplateId`, _, _))) =>
getOwner(contract.toUnnormalizedValue) shouldBe Some(ledgerParty)
}
)
}
"ledger queried when contract ID is not disclosed" in {
ledgerQueriedWhenContractNotDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
getContract = Map(contractId -> ledgerCaveContract),
)(result =>
inside(result) {
case Right(SValue.SAny(_, contract @ SValue.SRecord(`caveTemplateId`, _, _))) =>
getOwner(contract.toUnnormalizedValue) shouldBe Some(ledgerParty)
}
)
}
"disclosure table queried when contract ID is disclosed" - {
"contract ID in disclosure table only" in {
disclosureTableQueriedWhenContractDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
disclosedCaveContract,
disclosures = List(disclosedCaveContract),
)(result =>
inside(result) {
case Right(SValue.SAny(_, contract @ SValue.SRecord(`caveTemplateId`, _, _))) =>
getOwner(contract.toUnnormalizedValue) shouldBe Some(disclosureParty)
}
)
"disclosure table queried when contract ID is disclosed" - {
"contract ID in disclosure table only" in {
disclosureTableQueriedWhenContractDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
disclosedCaveContract,
disclosures = List(disclosedCaveContract),
)(result =>
inside(result) {
case Right(SValue.SAny(_, contract @ SValue.SRecord(`caveTemplateId`, _, _))) =>
getOwner(contract.toUnnormalizedValue) shouldBe Some(disclosureParty)
}
)
}
"contract ID in ledger and disclosure table" in {
disclosureTableQueriedWhenContractDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
disclosedCaveContract,
getContract = Map(contractId -> ledgerCaveContract),
disclosures = List(disclosedCaveContract),
)(result =>
inside(result) {
case Right(SValue.SAny(_, contract @ SValue.SRecord(`caveTemplateId`, _, _))) =>
getOwner(contract.toUnnormalizedValue) shouldBe Some(disclosureParty)
}
)
"contract ID in ledger and disclosure table" in {
disclosureTableQueriedWhenContractDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
disclosedCaveContract,
getContract = Map(contractId -> ledgerCaveContract),
disclosures = List(disclosedCaveContract),
)(result =>
inside(result) {
case Right(SValue.SAny(_, contract @ SValue.SRecord(`caveTemplateId`, _, _))) =>
getOwner(contract.toUnnormalizedValue) shouldBe Some(disclosureParty)
}
}
)
}
}
"contract IDs that are inactive" - {
"ledger query fails when contract ID is not disclosed" in {
ledgerQueryFailsWhenContractNotDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
contractId,
"TestMod:destroyCave",
committers = Set(ledgerParty),
getContract = Map(contractId -> ledgerCaveContract),
) { result =>
inside(result) {
case Left(
SError.SErrorDamlException(
ContractNotActive(`contractId`, `caveTemplateId`, _)
)
) =>
succeed
}
}
}
"disclosure table query fails when contract ID is disclosed" - {
"contract ID in disclosure table only" in {
disclosureTableQueryFailsWhenContractDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
disclosedCaveContract,
contractId,
"TestMod:destroyCave",
committers = Set(disclosureParty),
disclosures = List(disclosedCaveContract),
)(result =>
inside(result) {
case Left(
SError.SErrorDamlException(
ContractNotActive(`contractId`, `caveTemplateId`, _)
)
) =>
succeed
}
)
}
"contract ID in ledger and disclosure table" in {
disclosureTableQueryFailsWhenContractDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
disclosedCaveContract,
contractId,
"TestMod:destroyCave",
committers = Set(disclosureParty, ledgerParty),
getContract = Map(contractId -> ledgerCaveContract),
disclosures = List(disclosedCaveContract),
)(result =>
inside(result) {
case Left(
SError.SErrorDamlException(
ContractNotActive(`contractId`, `caveTemplateId`, _)
)
) =>
succeed
}
)
}
"contract IDs that are inactive" - {
"ledger query fails when contract ID is not disclosed" in {
ledgerQueryFailsWhenContractNotDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
contractId,
"TestMod:destroyCave",
committers = Set(ledgerParty),
getContract = Map(contractId -> ledgerCaveContract),
) { result =>
inside(result) {
case Left(
SError.SErrorDamlException(
ContractNotActive(`contractId`, `caveTemplateId`, _)
)
) =>
succeed
}
}
}
"fetching contract keys" - {
"test data validation" in {
ledgerParty should not be disclosureParty
ledgerParty should not be maintainerParty
disclosureParty should not be maintainerParty
ledgerContractId should not be disclosureContractId
inside(disclosedHouseContract) { case (`disclosureContractId`, contract) =>
getOwner(contract.arg) shouldBe Some(disclosureParty)
getMaintainer(contract.arg) shouldBe Some(maintainerParty)
}
"disclosure table query fails when contract ID is disclosed" - {
"contract ID in disclosure table only" in {
disclosureTableQueryFailsWhenContractDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
disclosedCaveContract,
contractId,
"TestMod:destroyCave",
committers = Set(disclosureParty),
disclosures = List(disclosedCaveContract),
)(result =>
inside(result) {
case Left(
SError.SErrorDamlException(
ContractNotActive(`contractId`, `caveTemplateId`, _)
)
) =>
succeed
}
)
}
"ledger queried when contract key is not disclosed" in {
ledgerQueriedWhenContractNotDisclosed(
"contract ID in ledger and disclosure table" in {
disclosureTableQueryFailsWhenContractDisclosed(
SBFetchAny(None)(SEValue(SContractId(contractId)), SEValue.None),
disclosedCaveContract,
contractId,
"TestMod:destroyCave",
committers = Set(disclosureParty, ledgerParty),
getContract = Map(contractId -> ledgerCaveContract),
disclosures = List(disclosedCaveContract),
)(result =>
inside(result) {
case Left(
SError.SErrorDamlException(
ContractNotActive(`contractId`, `caveTemplateId`, _)
)
) =>
succeed
}
)
}
}
}
}
"fetching contract keys" - {
"test data validation" in {
ledgerParty should not be disclosureParty
ledgerParty should not be maintainerParty
disclosureParty should not be maintainerParty
ledgerContractId should not be disclosureContractId
inside(disclosedHouseContract) { case (`disclosureContractId`, contract) =>
getOwner(contract.arg) shouldBe Some(disclosureParty)
getMaintainer(contract.arg) shouldBe Some(maintainerParty)
}
}
"ledger queried when contract key is not disclosed" in {
ledgerQueriedWhenContractNotDisclosed(
SBUFetchKey(houseTemplateId)(SEValue(contractSStructKey)),
committers = Set(ledgerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
)(_ shouldBe Right(SValue.SContractId(ledgerContractId)))
}
"disclosure table queried when contract key is disclosed" - {
"contract key in disclosure table only" in {
disclosureTableQueriedWhenContractDisclosed(
SBUFetchKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
committers = Set(disclosureParty),
disclosures = List(disclosedHouseContract),
)(_ shouldBe Right(SValue.SContractId(disclosureContractId)))
}
"contract key in ledger and disclosure table" in {
disclosureTableQueriedWhenContractDisclosed(
SBUFetchKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
committers = Set(disclosureParty, ledgerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
disclosures = List(disclosedHouseContract),
)(_ shouldBe Right(SValue.SContractId(disclosureContractId)))
}
}
"disclosed contract keys that are inactive" - {
"ledger query fails when contract key is not disclosed" in {
ledgerQueryFailsWhenContractNotDisclosed(
SBUFetchKey(houseTemplateId)(SEValue(contractSStructKey)),
ledgerContractId,
"TestMod:destroyHouse",
committers = Set(ledgerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
)(result =>
inside(result) {
case Left(SError.SErrorDamlException(ContractKeyNotFound(`contractKey`))) =>
succeed
}
)
}
"disclosure table query fails when contract key is disclosed" - {
"contract key in disclosure table only" in {
disclosureTableQueryFailsWhenContractDisclosed(
SBUFetchKey(houseTemplateId)(SEValue(contractSStructKey)),
committers = Set(ledgerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
)(_ shouldBe Right(SValue.SContractId(ledgerContractId)))
disclosedHouseContract,
disclosureContractId,
"TestMod:destroyHouse",
committers = Set(disclosureParty, maintainerParty),
disclosures = List(disclosedHouseContract),
)(result =>
inside(result) {
case Left(SError.SErrorDamlException(ContractKeyNotFound(`contractKey`))) =>
succeed
}
)
}
"disclosure table queried when contract key is disclosed" - {
"contract key in disclosure table only" in {
disclosureTableQueriedWhenContractDisclosed(
"contract key in ledger and disclosure table" in {
for (contractIdToBurn <- Set(ledgerContractId, disclosureContractId)) {
// Exercising a single contract ID is sufficient to make the key inactive
disclosureTableQueryFailsWhenContractDisclosed(
SBUFetchKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
committers = Set(disclosureParty),
disclosures = List(disclosedHouseContract),
)(_ shouldBe Right(SValue.SContractId(disclosureContractId)))
}
"contract key in ledger and disclosure table" in {
disclosureTableQueriedWhenContractDisclosed(
SBUFetchKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
committers = Set(disclosureParty, ledgerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
disclosures = List(disclosedHouseContract),
)(_ shouldBe Right(SValue.SContractId(disclosureContractId)))
}
}
"disclosed contract keys that are inactive" - {
"ledger query fails when contract key is not disclosed" in {
ledgerQueryFailsWhenContractNotDisclosed(
SBUFetchKey(houseTemplateId)(SEValue(contractSStructKey)),
ledgerContractId,
contractIdToBurn,
"TestMod:destroyHouse",
committers = Set(ledgerParty),
committers = Set(disclosureParty, ledgerParty, maintainerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
GlobalKeyWithMaintainers(
contractKey,
Set(maintainerParty),
) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
disclosures = List(disclosedHouseContract),
)(result =>
inside(result) {
case Left(SError.SErrorDamlException(ContractKeyNotFound(`contractKey`))) =>
@ -217,268 +256,220 @@ private[lf] class ExplicitDisclosureTest(majorLanguageVersion: LanguageMajorVers
}
)
}
"disclosure table query fails when contract key is disclosed" - {
"contract key in disclosure table only" in {
disclosureTableQueryFailsWhenContractDisclosed(
SBUFetchKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
disclosureContractId,
"TestMod:destroyHouse",
committers = Set(disclosureParty, maintainerParty),
disclosures = List(disclosedHouseContract),
)(result =>
inside(result) {
case Left(SError.SErrorDamlException(ContractKeyNotFound(`contractKey`))) =>
succeed
}
)
}
"contract key in ledger and disclosure table" in {
for (contractIdToBurn <- Set(ledgerContractId, disclosureContractId)) {
// Exercising a single contract ID is sufficient to make the key inactive
disclosureTableQueryFailsWhenContractDisclosed(
SBUFetchKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
contractIdToBurn,
"TestMod:destroyHouse",
committers = Set(disclosureParty, ledgerParty, maintainerParty),
getKey = Map(
GlobalKeyWithMaintainers(
contractKey,
Set(maintainerParty),
) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
disclosures = List(disclosedHouseContract),
)(result =>
inside(result) {
case Left(SError.SErrorDamlException(ContractKeyNotFound(`contractKey`))) =>
succeed
}
)
}
}
}
}
}
}
}
"looking up contract keys" - {
"test data validation" in {
ledgerParty should not be disclosureParty
ledgerParty should not be maintainerParty
disclosureParty should not be maintainerParty
ledgerContractId should not be disclosureContractId
inside(disclosedHouseContract) { case (`disclosureContractId`, contract) =>
getOwner(contract.arg) shouldBe Some(disclosureParty)
getMaintainer(contract.arg) shouldBe Some(maintainerParty)
"looking up contract keys" - {
"test data validation" in {
ledgerParty should not be disclosureParty
ledgerParty should not be maintainerParty
disclosureParty should not be maintainerParty
ledgerContractId should not be disclosureContractId
inside(disclosedHouseContract) { case (`disclosureContractId`, contract) =>
getOwner(contract.arg) shouldBe Some(disclosureParty)
getMaintainer(contract.arg) shouldBe Some(maintainerParty)
}
}
"ledger queried when contract key is not disclosed" in {
ledgerQueriedWhenContractNotDisclosed(
SBULookupKey(houseTemplateId)(SEValue(contractSStructKey)),
committers = Set(ledgerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
)(_ shouldBe Right(SValue.SOptional(Some(SValue.SContractId(ledgerContractId)))))
}
"disclosure table queried when contract key is disclosed" - {
"contract key in disclosure table only" in {
disclosureTableQueriedWhenContractDisclosed(
SBULookupKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
committers = Set(disclosureParty),
disclosures = List(disclosedHouseContract),
)(_ shouldBe Right(SValue.SOptional(Some(SValue.SContractId(disclosureContractId)))))
}
"contract key in ledger and disclosure table" in {
disclosureTableQueriedWhenContractDisclosed(
SBULookupKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
committers = Set(disclosureParty, ledgerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
disclosures = List(disclosedHouseContract),
)(_ shouldBe Right(SValue.SOptional(Some(SValue.SContractId(disclosureContractId)))))
}
}
"disclosed contract keys that are inactive" - {
"ledger query fails when contract key is not disclosed" in {
ledgerQueryFailsWhenContractNotDisclosed(
SBULookupKey(houseTemplateId)(SEValue(contractSStructKey)),
ledgerContractId,
"TestMod:destroyHouse",
committers = Set(ledgerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
)(result =>
inside(result) { case Right(SValue.SOptional(None)) =>
succeed
}
}
)
}
"ledger queried when contract key is not disclosed" in {
ledgerQueriedWhenContractNotDisclosed(
"disclosure table query fails when contract key is disclosed" - {
"contract key in disclosure table only" in {
disclosureTableQueryFailsWhenContractDisclosed(
SBULookupKey(houseTemplateId)(SEValue(contractSStructKey)),
committers = Set(ledgerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
)(_ shouldBe Right(SValue.SOptional(Some(SValue.SContractId(ledgerContractId)))))
disclosedHouseContract,
disclosureContractId,
"TestMod:destroyHouse",
committers = Set(disclosureParty, maintainerParty),
disclosures = List(disclosedHouseContract),
)(result =>
inside(result) { case Right(SValue.SOptional(None)) =>
succeed
}
)
}
"disclosure table queried when contract key is disclosed" - {
"contract key in disclosure table only" in {
disclosureTableQueriedWhenContractDisclosed(
"contract key in ledger and disclosure table" in {
for (contractIdToBurn <- Set(ledgerContractId, disclosureContractId)) {
// Exercising a single contract ID is sufficient to make the key inactive
disclosureTableQueryFailsWhenContractDisclosed(
SBULookupKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
committers = Set(disclosureParty),
disclosures = List(disclosedHouseContract),
)(_ shouldBe Right(SValue.SOptional(Some(SValue.SContractId(disclosureContractId)))))
}
"contract key in ledger and disclosure table" in {
disclosureTableQueriedWhenContractDisclosed(
SBULookupKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
committers = Set(disclosureParty, ledgerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
disclosures = List(disclosedHouseContract),
)(_ shouldBe Right(SValue.SOptional(Some(SValue.SContractId(disclosureContractId)))))
}
}
"disclosed contract keys that are inactive" - {
"ledger query fails when contract key is not disclosed" in {
ledgerQueryFailsWhenContractNotDisclosed(
SBULookupKey(houseTemplateId)(SEValue(contractSStructKey)),
ledgerContractId,
contractIdToBurn,
"TestMod:destroyHouse",
committers = Set(ledgerParty),
committers = Set(disclosureParty, ledgerParty, maintainerParty),
getKey = Map(
GlobalKeyWithMaintainers(contractKey, Set(maintainerParty)) -> ledgerContractId
GlobalKeyWithMaintainers(
contractKey,
Set(maintainerParty),
) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
disclosures = List(disclosedHouseContract),
)(result =>
inside(result) { case Right(SValue.SOptional(None)) =>
succeed
}
)
}
"disclosure table query fails when contract key is disclosed" - {
"contract key in disclosure table only" in {
disclosureTableQueryFailsWhenContractDisclosed(
SBULookupKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
disclosureContractId,
"TestMod:destroyHouse",
committers = Set(disclosureParty, maintainerParty),
disclosures = List(disclosedHouseContract),
)(result =>
inside(result) { case Right(SValue.SOptional(None)) =>
succeed
}
)
}
"contract key in ledger and disclosure table" in {
for (contractIdToBurn <- Set(ledgerContractId, disclosureContractId)) {
// Exercising a single contract ID is sufficient to make the key inactive
disclosureTableQueryFailsWhenContractDisclosed(
SBULookupKey(houseTemplateId)(SEValue(contractSStructKey)),
disclosedHouseContract,
contractIdToBurn,
"TestMod:destroyHouse",
committers = Set(disclosureParty, ledgerParty, maintainerParty),
getKey = Map(
GlobalKeyWithMaintainers(
contractKey,
Set(maintainerParty),
) -> ledgerContractId
),
getContract = Map(ledgerContractId -> ledgerHouseContract),
disclosures = List(disclosedHouseContract),
)(result =>
inside(result) { case Right(SValue.SOptional(None)) =>
succeed
}
)
}
}
}
}
}
}
def ledgerQueriedWhenContractNotDisclosed(
sexpr: SExpr.SExpr,
committers: Set[Party] = Set.empty,
disclosures: Iterable[(Value.ContractId, ContractInfo)] = Iterable.empty,
getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance],
getKey: PartialFunction[GlobalKeyWithMaintainers, Value.ContractId] =
PartialFunction.empty,
)(assertResult: Either[SError.SError, SValue] => Assertion): Assertion = {
val (result, machine) =
evaluateSExpr(
sexpr,
committers = committers,
disclosures = disclosures,
getContract = getContract,
getKey = getKey,
)
assertResult(result)
machine should haveDisclosedContracts()
machine should haveInactiveContractIds()
}
def disclosureTableQueriedWhenContractDisclosed(
sexpr: SExpr.SExpr,
disclosedContract: (Value.ContractId, ContractInfo),
committers: Set[Party] = Set.empty,
disclosures: Iterable[(Value.ContractId, ContractInfo)],
getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance] =
PartialFunction.empty,
getKey: PartialFunction[GlobalKeyWithMaintainers, Value.ContractId] =
PartialFunction.empty,
)(assertResult: Either[SError.SError, SValue] => Assertion): Assertion = {
val (result, machine) =
evaluateSExpr(
sexpr,
committers = committers,
disclosures = disclosures,
getContract = getContract,
getKey = getKey,
)
assertResult(result)
machine should haveDisclosedContracts(disclosedContract)
machine should haveInactiveContractIds()
}
def ledgerQueryFailsWhenContractNotDisclosed(
sexpr: SExpr.SExpr,
contractId: ContractId,
action: String,
committers: Set[Party],
disclosures: Iterable[(Value.ContractId, ContractInfo)] = Iterable.empty,
getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance],
getKey: PartialFunction[GlobalKeyWithMaintainers, Value.ContractId] =
PartialFunction.empty,
)(assertResult: Either[SError.SError, SValue] => Assertion): Assertion = {
val (result, machine) =
evaluateSExprWithSetup(
e"""\(contractId: ContractId TestMod:House) ->
$action contractId
""",
Array(SContractId(contractId)),
)(
sexpr,
committers = committers,
disclosures = disclosures,
getContract = getContract,
getKey = getKey,
)
assertResult(result)
machine should haveDisclosedContracts()
machine should haveInactiveContractIds(contractId)
}
def disclosureTableQueryFailsWhenContractDisclosed(
sexpr: SExpr.SExpr,
disclosedContract: (Value.ContractId, ContractInfo),
contractToDestroy: ContractId,
action: String,
committers: Set[Party],
disclosures: Iterable[(Value.ContractId, ContractInfo)],
getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance] =
PartialFunction.empty,
getKey: PartialFunction[GlobalKeyWithMaintainers, Value.ContractId] =
PartialFunction.empty,
)(assertResult: Either[SError.SError, SValue] => Assertion): Assertion = {
val (result, machine) =
evaluateSExprWithSetup(
e"""\(contractId: ContractId TestMod:House) ->
$action contractId
""",
Array(SContractId(contractToDestroy)),
)(
sexpr,
committers = committers,
disclosures = disclosures,
getContract = getContract,
getKey = getKey,
)
assertResult(result)
machine should haveDisclosedContracts(disclosedContract)
machine should haveInactiveContractIds(contractToDestroy)
}
}
}
def ledgerQueriedWhenContractNotDisclosed(
sexpr: SExpr.SExpr,
committers: Set[Party] = Set.empty,
disclosures: Iterable[(Value.ContractId, ContractInfo)] = Iterable.empty,
getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance],
getKey: PartialFunction[GlobalKeyWithMaintainers, Value.ContractId] = PartialFunction.empty,
)(assertResult: Either[SError.SError, SValue] => Assertion): Assertion = {
val (result, machine) =
evaluateSExpr(
sexpr,
committers = committers,
disclosures = disclosures,
getContract = getContract,
getKey = getKey,
)
assertResult(result)
machine should haveDisclosedContracts()
machine should haveInactiveContractIds()
}
def disclosureTableQueriedWhenContractDisclosed(
sexpr: SExpr.SExpr,
disclosedContract: (Value.ContractId, ContractInfo),
committers: Set[Party] = Set.empty,
disclosures: Iterable[(Value.ContractId, ContractInfo)],
getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance] =
PartialFunction.empty,
getKey: PartialFunction[GlobalKeyWithMaintainers, Value.ContractId] = PartialFunction.empty,
)(assertResult: Either[SError.SError, SValue] => Assertion): Assertion = {
val (result, machine) =
evaluateSExpr(
sexpr,
committers = committers,
disclosures = disclosures,
getContract = getContract,
getKey = getKey,
)
assertResult(result)
machine should haveDisclosedContracts(disclosedContract)
machine should haveInactiveContractIds()
}
def ledgerQueryFailsWhenContractNotDisclosed(
sexpr: SExpr.SExpr,
contractId: ContractId,
action: String,
committers: Set[Party],
disclosures: Iterable[(Value.ContractId, ContractInfo)] = Iterable.empty,
getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance],
getKey: PartialFunction[GlobalKeyWithMaintainers, Value.ContractId] = PartialFunction.empty,
)(assertResult: Either[SError.SError, SValue] => Assertion): Assertion = {
val (result, machine) =
evaluateSExprWithSetup(
e"""\(contractId: ContractId TestMod:House) ->
$action contractId
""",
Array(SContractId(contractId)),
)(
sexpr,
committers = committers,
disclosures = disclosures,
getContract = getContract,
getKey = getKey,
)
assertResult(result)
machine should haveDisclosedContracts()
machine should haveInactiveContractIds(contractId)
}
def disclosureTableQueryFailsWhenContractDisclosed(
sexpr: SExpr.SExpr,
disclosedContract: (Value.ContractId, ContractInfo),
contractToDestroy: ContractId,
action: String,
committers: Set[Party],
disclosures: Iterable[(Value.ContractId, ContractInfo)],
getContract: PartialFunction[Value.ContractId, Value.VersionedContractInstance] =
PartialFunction.empty,
getKey: PartialFunction[GlobalKeyWithMaintainers, Value.ContractId] = PartialFunction.empty,
)(assertResult: Either[SError.SError, SValue] => Assertion): Assertion = {
val (result, machine) =
evaluateSExprWithSetup(
e"""\(contractId: ContractId TestMod:House) ->
$action contractId
""",
Array(SContractId(contractToDestroy)),
)(
sexpr,
committers = committers,
disclosures = disclosures,
getContract = getContract,
getKey = getKey,
)
assertResult(result)
machine should haveDisclosedContracts(disclosedContract)
machine should haveInactiveContractIds(contractToDestroy)
}
}

View File

@ -7,7 +7,6 @@ package speedy
import com.daml.lf.data.{FrontStack, ImmArray, Ref}
import com.daml.lf.interpretation.{Error => IE}
import com.daml.lf.language.{Ast, LanguageMajorVersion}
import com.daml.lf.language.LanguageDevConfig.EvaluationOrder
import com.daml.lf.testing.parser.Implicits.SyntaxHelper
import com.daml.lf.testing.parser.ParserParameters
import com.daml.lf.transaction.{SubmittedTransaction, TransactionVersion, Versioned}
@ -31,451 +30,440 @@ class LimitsSpec(majorLanguageVersion: LanguageMajorVersion)
implicit val defaultParserParameters: ParserParameters[this.type] =
ParserParameters.defaultFor[this.type](majorLanguageVersion)
for (evaluationOrder <- EvaluationOrder.valuesFor(majorLanguageVersion)) {
val pkgs = SpeedyTestLib.typeAndCompile(p"""
module Mod {
evaluationOrder.toString - {
record @serializable T = {
signatories: List Party,
observers: List Party
};
val pkgs = SpeedyTestLib.typeAndCompile(
p"""
module Mod {
record @serializable NoOpArg = { controllers: List Party, observers: List Party };
record @serializable T = {
signatories: List Party,
observers: List Party
};
val fetches: List (ContractId Mod:T) -> Update (List Mod:T) =
\(cids: List (ContractId Mod:T)) ->
case cids of
Cons h t ->
ubind
first: Mod:T <- fetch_template @Mod:T h;
rest: List Mod:T <- Mod:fetches t
in
upure @(List Mod:T) Cons @Mod:T [first] rest
| Nil ->
upure @(List Mod:T) Nil @Mod:T;
record @serializable NoOpArg = { controllers: List Party, observers: List Party };
template (this : T) = {
precondition True;
signatories Mod:T {signatories} this;
observers Mod:T {observers} this;
agreement "Agreement";
choice @nonConsuming NoOp (self) (arg: Mod:NoOpArg): Unit,
controllers Mod:NoOpArg {controllers} arg,
observers Mod:NoOpArg {observers} arg
to
upure @Unit ();
};
}
""")
val fetches: List (ContractId Mod:T) -> Update (List Mod:T) =
\(cids: List (ContractId Mod:T)) ->
case cids of
Cons h t ->
ubind
first: Mod:T <- fetch_template @Mod:T h;
rest: List Mod:T <- Mod:fetches t
in
upure @(List Mod:T) Cons @Mod:T [first] rest
| Nil ->
upure @(List Mod:T) Nil @Mod:T;
def eval(
limits: interpretation.Limits,
contracts: PartialFunction[Value.ContractId, Versioned[Value.ContractInstance]],
committers: Set[Ref.Party],
e: Ast.Expr,
agrs: SValue*
): Either[SError.SError, SubmittedTransaction] =
SpeedyTestLib.buildTransaction(
machine = Speedy.Machine.fromUpdateSExpr(
compiledPackages = pkgs,
transactionSeed = txSeed,
updateSE = SExpr.SEApp(pkgs.compiler.unsafeCompile(e), agrs.view.toArray),
committers = committers,
limits = limits,
),
getContract = contracts,
)
template (this : T) = {
precondition True;
signatories Mod:T {signatories} this;
observers Mod:T {observers} this;
agreement "Agreement";
choice @nonConsuming NoOp (self) (arg: Mod:NoOpArg): Unit,
controllers Mod:NoOpArg {controllers} arg,
observers Mod:NoOpArg {observers} arg
to
upure @Unit ();
};
}
""",
evaluationOrder,
"Machine" - {
val committers = (0 to 100).view.map(i => Ref.Party.assertFromString(s"Parties$i")).toSet
val limit = 10
val testCases =
Table(
"size" -> "success",
1 -> true,
limit -> true,
limit + 1 -> false,
5 * limit -> false,
)
def eval(
limits: interpretation.Limits,
contracts: PartialFunction[Value.ContractId, Versioned[Value.ContractInstance]],
committers: Set[Ref.Party],
e: Ast.Expr,
agrs: SValue*
): Either[SError.SError, SubmittedTransaction] =
SpeedyTestLib.buildTransaction(
machine = Speedy.Machine.fromUpdateSExpr(
compiledPackages = pkgs,
transactionSeed = txSeed,
updateSE = SExpr.SEApp(pkgs.compiler.unsafeCompile(e), agrs.view.toArray),
committers = committers,
limits = limits,
),
getContract = contracts,
"refuse to create a contract with too many signatories" in {
val limits = interpretation.Limits.Lenient.copy(contractSignatories = limit)
val e =
e"""\(signatories: List Party) (observers: List Party) ->
create @Mod:T Mod:T { signatories = signatories, observers = observers }
"""
forEvery(testCases) { (i, succeed) =>
val (signatories, observers) = committers.splitAt(i)
val result =
eval(limits, Map.empty, committers, e, asSParties(signatories), asSParties(observers))
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractSignatories(
_,
templateId,
_,
parties,
reportedlimit,
)
),
)
)
) =>
templateId shouldBe T
parties shouldBe signatories
reportedlimit shouldBe limit
}
}
}
"refuse to fetch a contract with too many signatories" in {
val limits = interpretation.Limits.Lenient.copy(contractSignatories = limit)
val e = e"""\(cid: ContractId Mod:T) -> fetch_template @Mod:T cid"""
forEvery(testCases) { (i, succeed) =>
val (signatories, observers) = committers.splitAt(i)
val contract = mkContract(signatories, observers)
val result =
eval(limits, Map(aCid -> contract), signatories, e, SValue.SContractId(aCid))
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractSignatories(
_,
templateId,
_,
parties,
reportedlimit,
)
),
)
)
) =>
templateId shouldBe T
parties shouldBe signatories
reportedlimit shouldBe limit
}
}
}
"refuse to exercise a contract with too many signatories" in {
val limits = interpretation.Limits.Lenient.copy(contractSignatories = limit)
val e =
e"""\(cid: ContractId Mod:T) (controllers: List Party) ->
exercise @Mod:T NoOp cid Mod:NoOpArg {controllers = controllers, observers = Nil @Party }"""
forEvery(testCases) { (i, succeed) =>
val (signatories, observers) = committers.splitAt(i)
val contract = mkContract(signatories, observers)
val result = eval(
limits,
Map(aCid -> contract),
signatories,
e,
SValue.SContractId(aCid),
asSParties(signatories),
)
"Machine" - {
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractSignatories(
_,
templateId,
_,
parties,
reportedlimit,
)
),
)
)
) =>
templateId shouldBe T
parties shouldBe signatories
reportedlimit shouldBe limit
}
}
}
val committers = (0 to 100).view.map(i => Ref.Party.assertFromString(s"Parties$i")).toSet
val limit = 10
val testCases =
Table(
"size" -> "success",
1 -> true,
limit -> true,
limit + 1 -> false,
5 * limit -> false,
"refuse to create a contract with too many observers" in {
val limits = interpretation.Limits.Lenient.copy(contractObservers = limit)
val e =
e"""\(signatories: List Party) (observers: List Party) ->
create @Mod:T Mod:T { signatories = signatories, observers = observers }
"""
forEvery(testCases) { (i, succeed) =>
val (observers, signatories) = committers.splitAt(i)
val result =
eval(
limits,
Map.empty,
signatories,
e,
asSParties(signatories),
asSParties(observers),
)
"refuse to create a contract with too many signatories" in {
val limits = interpretation.Limits.Lenient.copy(contractSignatories = limit)
val e =
e"""\(signatories: List Party) (observers: List Party) ->
create @Mod:T Mod:T { signatories = signatories, observers = observers }
"""
forEvery(testCases) { (i, succeed) =>
val (signatories, observers) = committers.splitAt(i)
val result =
eval(limits, Map.empty, committers, e, asSParties(signatories), asSParties(observers))
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractSignatories(
_,
templateId,
_,
parties,
reportedlimit,
)
),
)
)
) =>
templateId shouldBe T
parties shouldBe signatories
reportedlimit shouldBe limit
}
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractObservers(_, templateId, _, parties, reportedlimit)
),
)
)
) =>
templateId shouldBe T
parties shouldBe observers
reportedlimit shouldBe limit
}
}
"refuse to fetch a contract with too many signatories" in {
val limits = interpretation.Limits.Lenient.copy(contractSignatories = limit)
val e = e"""\(cid: ContractId Mod:T) -> fetch_template @Mod:T cid"""
forEvery(testCases) { (i, succeed) =>
val (signatories, observers) = committers.splitAt(i)
val contract = mkContract(signatories, observers)
val result =
eval(limits, Map(aCid -> contract), signatories, e, SValue.SContractId(aCid))
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractSignatories(
_,
templateId,
_,
parties,
reportedlimit,
)
),
)
)
) =>
templateId shouldBe T
parties shouldBe signatories
reportedlimit shouldBe limit
}
}
}
"refuse to exercise a contract with too many signatories" in {
val limits = interpretation.Limits.Lenient.copy(contractSignatories = limit)
val e =
e"""\(cid: ContractId Mod:T) (controllers: List Party) ->
exercise @Mod:T NoOp cid Mod:NoOpArg {controllers = controllers, observers = Nil @Party }"""
forEvery(testCases) { (i, succeed) =>
val (signatories, observers) = committers.splitAt(i)
val contract = mkContract(signatories, observers)
val result = eval(
limits,
Map(aCid -> contract),
signatories,
e,
SValue.SContractId(aCid),
asSParties(signatories),
)
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractSignatories(
_,
templateId,
_,
parties,
reportedlimit,
)
),
)
)
) =>
templateId shouldBe T
parties shouldBe signatories
reportedlimit shouldBe limit
}
}
}
"refuse to create a contract with too many observers" in {
val limits = interpretation.Limits.Lenient.copy(contractObservers = limit)
val e =
e"""\(signatories: List Party) (observers: List Party) ->
create @Mod:T Mod:T { signatories = signatories, observers = observers }
"""
forEvery(testCases) { (i, succeed) =>
val (observers, signatories) = committers.splitAt(i)
val result =
eval(
limits,
Map.empty,
signatories,
e,
asSParties(signatories),
asSParties(observers),
)
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractObservers(_, templateId, _, parties, reportedlimit)
),
)
)
) =>
templateId shouldBe T
parties shouldBe observers
reportedlimit shouldBe limit
}
}
}
"refuse to fetch a contract with too many observers" in {
val limits = interpretation.Limits.Lenient.copy(contractObservers = limit)
val e = e"""\(cid: ContractId Mod:T) -> fetch_template @Mod:T cid"""
forEvery(testCases) { (i, succeed) =>
val (observers, signatories) = committers.splitAt(i)
val contract = mkContract(signatories, observers)
val result =
eval(limits, Map(aCid -> contract), signatories, e, SValue.SContractId(aCid))
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractObservers(_, templateId, _, parties, reportedlimit)
),
)
)
) =>
templateId shouldBe T
parties shouldBe observers
reportedlimit shouldBe limit
}
}
}
"refuse to exercise a contract with too many observers" in {
val limits = interpretation.Limits.Lenient.copy(contractObservers = limit)
val e =
e"""\(cid: ContractId Mod:T) (controllers: List Party) ->
exercise @Mod:T NoOp cid Mod:NoOpArg {controllers = controllers, observers = Nil @Party }"""
forEvery(testCases) { (i, succeed) =>
val (observers, signatories) = committers.splitAt(i)
val contract = mkContract(signatories, observers)
val result = eval(
limits,
Map(aCid -> contract),
signatories,
e,
SValue.SContractId(aCid),
asSParties(signatories),
)
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractObservers(_, templateId, _, parties, reportedlimit)
),
)
)
) =>
templateId shouldBe T
parties shouldBe observers
reportedlimit shouldBe limit
}
}
}
"refuse to exercise a choice with too many controllers" in {
val limits = interpretation.Limits.Lenient.copy(choiceControllers = limit)
val e =
e"""\(signatories: List Party) (controllers: List Party) ->
ubind
cid: ContractId Mod:T <- create @Mod:T Mod:T {
signatories = signatories,
observers = Nil @Party
}
in exercise @Mod:T NoOp cid Mod:NoOpArg {controllers = controllers, observers = Nil @Party }
"""
forEvery(testCases) { (i, succeed) =>
val (controllers, signatories) = committers.splitAt(i)
val result =
eval(
limits,
Map.empty,
committers,
e,
asSParties(signatories),
asSParties(controllers),
)
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ChoiceControllers(
_,
templateId,
choiceName,
_,
parties,
reportedlimit,
)
),
)
)
) =>
templateId shouldBe T
choiceName shouldBe "NoOp"
parties shouldBe controllers
reportedlimit shouldBe limit
}
}
}
// TODO: https://github.com/digital-asset/daml/issues/15882
// -- Add a similar test for "too many choice authorizers"
"refuse to exercise a choice with too many observers" in {
val limits = interpretation.Limits.Lenient.copy(choiceObservers = limit)
val committers = (0 to 99).view.map(i => Ref.Party.assertFromString(s"Party$i")).toSet
val e =
e"""\(signatories: List Party) (controllers: List Party) (observers: List Party) ->
ubind
cid: ContractId Mod:T <- create @Mod:T Mod:T {
signatories = signatories,
observers = Nil @Party
}
in exercise @Mod:T NoOp cid Mod:NoOpArg {controllers = controllers, observers = observers}
"""
forEvery(testCases) { (i, succeed) =>
val (observers, signatories) = committers.splitAt(i)
val result = eval(
limits,
Map.empty,
committers,
e,
asSParties(signatories),
asSParties(signatories),
asSParties(observers),
)
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ChoiceObservers(
_,
templateId,
choiceName,
_,
parties,
reportedlimit,
)
),
)
)
) =>
templateId shouldBe T
choiceName shouldBe "NoOp"
parties shouldBe observers
reportedlimit shouldBe limit
false
}
}
}
"refuse to build a transaction with too many input contracts" in {
val limits = interpretation.Limits.Lenient.copy(transactionInputContracts = limit)
val signatories = committers.take(1)
val contract = mkContract(signatories, Set.empty)
val cids =
(1 to 99).map(i => Value.ContractId.V1(crypto.Hash.hashPrivateKey(s"contract$i")))
val e = e"Mod:fetches"
forEvery(testCases) { (i, succeed) =>
val result = eval(limits, _ => contract, committers, e, asSCids(cids.take(i)))
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(IE.Dev.Limit.TransactionInputContracts(reportedlimit)),
)
)
) =>
reportedlimit shouldBe limit
false
}
}
}
}
}
"refuse to fetch a contract with too many observers" in {
val limits = interpretation.Limits.Lenient.copy(contractObservers = limit)
val e = e"""\(cid: ContractId Mod:T) -> fetch_template @Mod:T cid"""
forEvery(testCases) { (i, succeed) =>
val (observers, signatories) = committers.splitAt(i)
val contract = mkContract(signatories, observers)
val result =
eval(limits, Map(aCid -> contract), signatories, e, SValue.SContractId(aCid))
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractObservers(_, templateId, _, parties, reportedlimit)
),
)
)
) =>
templateId shouldBe T
parties shouldBe observers
reportedlimit shouldBe limit
}
}
}
"refuse to exercise a contract with too many observers" in {
val limits = interpretation.Limits.Lenient.copy(contractObservers = limit)
val e =
e"""\(cid: ContractId Mod:T) (controllers: List Party) ->
exercise @Mod:T NoOp cid Mod:NoOpArg {controllers = controllers, observers = Nil @Party }"""
forEvery(testCases) { (i, succeed) =>
val (observers, signatories) = committers.splitAt(i)
val contract = mkContract(signatories, observers)
val result = eval(
limits,
Map(aCid -> contract),
signatories,
e,
SValue.SContractId(aCid),
asSParties(signatories),
)
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ContractObservers(_, templateId, _, parties, reportedlimit)
),
)
)
) =>
templateId shouldBe T
parties shouldBe observers
reportedlimit shouldBe limit
}
}
}
"refuse to exercise a choice with too many controllers" in {
val limits = interpretation.Limits.Lenient.copy(choiceControllers = limit)
val e =
e"""\(signatories: List Party) (controllers: List Party) ->
ubind
cid: ContractId Mod:T <- create @Mod:T Mod:T {
signatories = signatories,
observers = Nil @Party
}
in exercise @Mod:T NoOp cid Mod:NoOpArg {controllers = controllers, observers = Nil @Party }
"""
forEvery(testCases) { (i, succeed) =>
val (controllers, signatories) = committers.splitAt(i)
val result =
eval(
limits,
Map.empty,
committers,
e,
asSParties(signatories),
asSParties(controllers),
)
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ChoiceControllers(
_,
templateId,
choiceName,
_,
parties,
reportedlimit,
)
),
)
)
) =>
templateId shouldBe T
choiceName shouldBe "NoOp"
parties shouldBe controllers
reportedlimit shouldBe limit
}
}
}
// TODO: https://github.com/digital-asset/daml/issues/15882
// -- Add a similar test for "too many choice authorizers"
"refuse to exercise a choice with too many observers" in {
val limits = interpretation.Limits.Lenient.copy(choiceObservers = limit)
val committers = (0 to 99).view.map(i => Ref.Party.assertFromString(s"Party$i")).toSet
val e =
e"""\(signatories: List Party) (controllers: List Party) (observers: List Party) ->
ubind
cid: ContractId Mod:T <- create @Mod:T Mod:T {
signatories = signatories,
observers = Nil @Party
}
in exercise @Mod:T NoOp cid Mod:NoOpArg {controllers = controllers, observers = observers}
"""
forEvery(testCases) { (i, succeed) =>
val (observers, signatories) = committers.splitAt(i)
val result = eval(
limits,
Map.empty,
committers,
e,
asSParties(signatories),
asSParties(signatories),
asSParties(observers),
)
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(
IE.Dev.Limit.ChoiceObservers(
_,
templateId,
choiceName,
_,
parties,
reportedlimit,
)
),
)
)
) =>
templateId shouldBe T
choiceName shouldBe "NoOp"
parties shouldBe observers
reportedlimit shouldBe limit
false
}
}
}
"refuse to build a transaction with too many input contracts" in {
val limits = interpretation.Limits.Lenient.copy(transactionInputContracts = limit)
val signatories = committers.take(1)
val contract = mkContract(signatories, Set.empty)
val cids =
(1 to 99).map(i => Value.ContractId.V1(crypto.Hash.hashPrivateKey(s"contract$i")))
val e = e"Mod:fetches"
forEvery(testCases) { (i, succeed) =>
val result = eval(limits, _ => contract, committers, e, asSCids(cids.take(i)))
if (succeed)
result shouldBe a[Right[_, _]]
else
inside(result) {
case Left(
SError.SErrorDamlException(
IE.Dev(
_,
IE.Dev.Limit(IE.Dev.Limit.TransactionInputContracts(reportedlimit)),
)
)
) =>
reportedlimit shouldBe limit
false
}
}
}
}

View File

@ -7,7 +7,6 @@ package speedy
import com.daml.lf.data.ImmArray
import com.daml.lf.data.Ref.Party
import com.daml.lf.language.Ast.Expr
import com.daml.lf.language.LanguageDevConfig.EvaluationOrder
import com.daml.lf.language.LanguageMajorVersion
import com.daml.lf.speedy.SExpr._
import com.daml.lf.speedy.SValue._
@ -49,173 +48,164 @@ class RollbackTest(majorLanguageVersion: LanguageMajorVersion)
.fold(e => fail(Pretty.prettyError(e).render(80)), identity)
}
for (evaluationOrder <- EvaluationOrder.valuesFor(majorLanguageVersion)) {
val pkgs: PureCompiledPackages = SpeedyTestLib.typeAndCompile(p"""
module M {
evaluationOrder.toString - {
record @serializable MyException = { message: Text } ;
exception MyException = {
message \(e: M:MyException) -> M:MyException {message} e
};
val pkgs: PureCompiledPackages = SpeedyTestLib.typeAndCompile(
p"""
module M {
record @serializable T1 = { party: Party, info: Int64 } ;
template (record : T1) = {
precondition True;
signatories Cons @Party [M:T1 {party} record] (Nil @Party);
observers Nil @Party;
agreement "Agreement";
choice Ch1 (self) (i : Unit) : Unit,
controllers Cons @Party [M:T1 {party} record] (Nil @Party)
to
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = M:T1 {party} record, info = 400 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = M:T1 {party} record, info = 500 }
in upure @Unit ();
choice Ch2 (self) (i : Unit) : Unit,
controllers Cons @Party [M:T1 {party} record] (Nil @Party)
to
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = M:T1 {party} record, info = 400 };
u: Unit <- throw @(Update Unit) @M:MyException (M:MyException {message = "oops"});
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = M:T1 {party} record, info = 500 }
in upure @Unit ();
};
record @serializable MyException = { message: Text } ;
exception MyException = {
message \(e: M:MyException) -> M:MyException {message} e
};
val create0 : Party -> Update Unit = \(party: Party) ->
upure @Unit ();
record @serializable T1 = { party: Party, info: Int64 } ;
template (record : T1) = {
precondition True;
signatories Cons @Party [M:T1 {party} record] (Nil @Party);
observers Nil @Party;
agreement "Agreement";
choice Ch1 (self) (i : Unit) : Unit,
controllers Cons @Party [M:T1 {party} record] (Nil @Party)
to
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = M:T1 {party} record, info = 400 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = M:T1 {party} record, info = 500 }
in upure @Unit ();
choice Ch2 (self) (i : Unit) : Unit,
controllers Cons @Party [M:T1 {party} record] (Nil @Party)
to
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = M:T1 {party} record, info = 400 };
u: Unit <- throw @(Update Unit) @M:MyException (M:MyException {message = "oops"});
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = M:T1 {party} record, info = 500 }
in upure @Unit ();
};
val create1 : Party -> Update Unit = \(party: Party) ->
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 }
in upure @Unit ();
val create0 : Party -> Update Unit = \(party: Party) ->
upure @Unit ();
val create2 : Party -> Update Unit = \(party: Party) ->
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in upure @Unit ();
val create1 : Party -> Update Unit = \(party: Party) ->
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 }
in upure @Unit ();
val create3 : Party -> Update Unit = \(party: Party) ->
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 };
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
val create2 : Party -> Update Unit = \(party: Party) ->
val create3nested : Party -> Update Unit = \(party: Party) ->
ubind
u1: Unit <-
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in upure @Unit ();
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
val create3 : Party -> Update Unit = \(party: Party) ->
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 };
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
val create3catchNoThrow : Party -> Update Unit = \(party: Party) ->
ubind
u1: Unit <-
try @Unit
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in upure @Unit ()
catch e -> Some @(Update Unit) (upure @Unit ())
;
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
val create3nested : Party -> Update Unit = \(party: Party) ->
ubind
u1: Unit <-
val create3throwAndCatch : Party -> Update Unit = \(party: Party) ->
ubind
u1: Unit <-
try @Unit
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in throw @(Update Unit) @M:MyException (M:MyException {message = "oops"})
catch e -> Some @(Update Unit) (upure @Unit ())
;
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
val create3throwAndOuterCatch : Party -> Update Unit = \(party: Party) ->
ubind
u1: Unit <-
try @Unit
try @Unit
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in upure @Unit ();
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
val create3catchNoThrow : Party -> Update Unit = \(party: Party) ->
ubind
u1: Unit <-
try @Unit
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in upure @Unit ()
catch e -> Some @(Update Unit) (upure @Unit ())
;
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
val create3throwAndCatch : Party -> Update Unit = \(party: Party) ->
ubind
u1: Unit <-
try @Unit
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in throw @(Update Unit) @M:MyException (M:MyException {message = "oops"})
catch e -> Some @(Update Unit) (upure @Unit ())
;
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
val create3throwAndOuterCatch : Party -> Update Unit = \(party: Party) ->
ubind
u1: Unit <-
try @Unit
try @Unit
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in throw @(Update Unit) @M:MyException (M:MyException {message = "oops"})
catch e -> None @(Update Unit)
catch e -> Some @(Update Unit) (upure @Unit ())
;
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
in throw @(Update Unit) @M:MyException (M:MyException {message = "oops"})
catch e -> None @(Update Unit)
catch e -> Some @(Update Unit) (upure @Unit ())
;
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
val exer1 : Party -> Update Unit = \(party: Party) ->
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
val exer1 : Party -> Update Unit = \(party: Party) ->
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
u: Unit <-
try @Unit
ubind
u: Unit <- exercise @M:T1 Ch1 x1 ();
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in upure @Unit ()
catch e -> Some @(Update Unit) (upure @Unit ());
u: Unit <-
try @Unit
ubind
u: Unit <- exercise @M:T1 Ch1 x1 ();
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in upure @Unit ()
catch e -> Some @(Update Unit) (upure @Unit ());
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
val exer2 : Party -> Update Unit = \(party: Party) ->
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
val exer2 : Party -> Update Unit = \(party: Party) ->
ubind
x1: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 100 };
u: Unit <-
try @Unit
ubind
u: Unit <- exercise @M:T1 Ch2 x1 ();
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in upure @Unit ()
catch e -> Some @(Update Unit) (upure @Unit ());
u: Unit <-
try @Unit
ubind
u: Unit <- exercise @M:T1 Ch2 x1 ();
x2: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 200 }
in upure @Unit ()
catch e -> Some @(Update Unit) (upure @Unit ());
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
x3: ContractId M:T1 <- create @M:T1 M:T1 { party = party, info = 300 }
in upure @Unit ();
}
""",
evaluationOrder,
)
}
""")
val testCases = Table[String, List[Tree]](
("expression", "expected-number-of-contracts"),
("create0", Nil),
("create1", List(C(100))),
("create2", List(C(100), C(200))),
("create3", List(C(100), C(200), C(300))),
("create3nested", List(C(100), C(200), C(300))),
("create3catchNoThrow", List(C(100), C(200), C(300))),
("create3throwAndCatch", List[Tree](R(List(C(100), C(200))), C(300))),
("create3throwAndOuterCatch", List[Tree](R(List(C(100), C(200))), C(300))),
("exer1", List[Tree](C(100), X(List(C(400), C(500))), C(200), C(300))),
("exer2", List[Tree](C(100), R(List(X(List(C(400))))), C(300))),
)
val testCases = Table[String, List[Tree]](
("expression", "expected-number-of-contracts"),
("create0", Nil),
("create1", List(C(100))),
("create2", List(C(100), C(200))),
("create3", List(C(100), C(200), C(300))),
("create3nested", List(C(100), C(200), C(300))),
("create3catchNoThrow", List(C(100), C(200), C(300))),
("create3throwAndCatch", List[Tree](R(List(C(100), C(200))), C(300))),
("create3throwAndOuterCatch", List[Tree](R(List(C(100), C(200))), C(300))),
("exer1", List[Tree](C(100), X(List(C(400), C(500))), C(200), C(300))),
("exer2", List[Tree](C(100), R(List(X(List(C(400))))), C(300))),
)
forEvery(testCases) { (exp: String, expected: List[Tree]) =>
s"""$exp, contracts expected: $expected """ in {
val party = Party.assertFromString("Alice")
val tx: SubmittedTransaction = runUpdateExprGetTx(pkgs)(e"M:$exp", party)
val ids: List[Tree] = shapeOfTransaction(tx)
ids shouldBe expected
}
}
forEvery(testCases) { (exp: String, expected: List[Tree]) =>
s"""$exp, contracts expected: $expected """ in {
val party = Party.assertFromString("Alice")
val tx: SubmittedTransaction = runUpdateExprGetTx(pkgs)(e"M:$exp", party)
val ids: List[Tree] = shapeOfTransaction(tx)
ids shouldBe expected
}
}
}

View File

@ -9,7 +9,6 @@ import data.Ref.PackageId
import data.Time
import SResult._
import com.daml.lf.data.Ref.Party
import com.daml.lf.language.LanguageDevConfig.EvaluationOrder
import com.daml.lf.language.{Ast, LanguageMajorVersion, PackageInterface}
import com.daml.lf.speedy.Speedy.{ContractInfo, UpdateMachine}
import com.daml.lf.testing.parser.ParserParameters
@ -196,7 +195,6 @@ private[speedy] object SpeedyTestLib {
def typeAndCompile(
majorLanguageVersion: LanguageMajorVersion,
pkgs: Map[PackageId, Ast.Package],
evaluationOrder: EvaluationOrder,
): PureCompiledPackages = {
require(
pkgs.values.forall(pkg => pkg.languageVersion.major == majorLanguageVersion), {
@ -213,20 +211,18 @@ private[speedy] object SpeedyTestLib {
Compiler.Config
.Dev(majorLanguageVersion)
.copy(
evaluationOrder = evaluationOrder,
stacktracing = Compiler.FullStackTrace,
stacktracing = Compiler.FullStackTrace
),
)
}
@throws[ValidationError]
def typeAndCompile[X](pkg: Ast.Package, evaluationOrder: EvaluationOrder)(implicit
def typeAndCompile[X](pkg: Ast.Package)(implicit
parserParameter: ParserParameters[X]
): PureCompiledPackages =
typeAndCompile(
pkg.languageVersion.major,
Map(parserParameter.defaultPackageId -> pkg),
evaluationOrder,
)
private[speedy] object Implicits {

View File

@ -6,7 +6,6 @@ package speedy
import java.util
import com.daml.lf.language.{Ast, LanguageMajorVersion}
import com.daml.lf.language.LanguageDevConfig.EvaluationOrder
import com.daml.lf.speedy.SResult.SResultFinal
import com.daml.lf.testing.parser.Implicits.SyntaxHelper
import com.daml.lf.testing.parser.ParserParameters
@ -28,126 +27,117 @@ class TailCallTest(majorLanguageVersion: LanguageMajorVersion)
implicit val defaultParserParameters: ParserParameters[this.type] =
ParserParameters.defaultFor[this.type](majorLanguageVersion)
for (evaluationOrder <- EvaluationOrder.valuesFor(majorLanguageVersion)) {
val pkgs = SpeedyTestLib.typeAndCompile(p"""
module F {
evaluationOrder.toString - {
// *Non* tail-recursive definition
val triangle : (Int64 -> Int64) = \ (x: Int64) ->
case (EQUAL @Int64 x 0) of
True -> 0
| _ -> ADD_INT64 x (F:triangle (SUB_INT64 x 1));
val pkgs = SpeedyTestLib.typeAndCompile(
p"""
module F {
// Tail-recursive definition, via helper function
val triangleTR : (Int64 -> Int64) = F:triangleTR_acc 0;
// *Non* tail-recursive definition
val triangle : (Int64 -> Int64) = \ (x: Int64) ->
case (EQUAL @Int64 x 0) of
True -> 0
| _ -> ADD_INT64 x (F:triangle (SUB_INT64 x 1));
// Tail-recursive definition, via helper function
val triangleTR : (Int64 -> Int64) = F:triangleTR_acc 0;
// Tail-recursive definition using accumulator parameter
val triangleTR_acc : (Int64 -> Int64 -> Int64) = \ (acc: Int64) (x: Int64) ->
case (EQUAL @Int64 x 0) of
True -> acc
| _ -> F:triangleTR_acc (ADD_INT64 acc x) (SUB_INT64 x 1);
// Tail-recursive definition using accumulator parameter
val triangleTR_acc : (Int64 -> Int64 -> Int64) = \ (acc: Int64) (x: Int64) ->
case (EQUAL @Int64 x 0) of
True -> acc
| _ -> F:triangleTR_acc (ADD_INT64 acc x) (SUB_INT64 x 1);
val triangle_viaFoldLeft : (Int64 -> Int64) = \ (x: Int64) ->
FOLDL @Int64 @Int64 ADD_INT64 0 (F:generate Nil@Int64 x);
val triangle_viaFoldLeft : (Int64 -> Int64) = \ (x: Int64) ->
FOLDL @Int64 @Int64 ADD_INT64 0 (F:generate Nil@Int64 x);
val triangle_viaFoldRight : (Int64 -> Int64) = \ (x: Int64) ->
FOLDR @Int64 @Int64 ADD_INT64 0 (F:generate Nil@Int64 x);
val triangle_viaFoldRight : (Int64 -> Int64) = \ (x: Int64) ->
FOLDR @Int64 @Int64 ADD_INT64 0 (F:generate Nil@Int64 x);
val triangle_viaFoldRight2 : (Int64 -> Int64) = \ (x: Int64) ->
FOLDR @Int64 @Int64 (\(y: Int64) -> ADD_INT64 y) 0 (F:generate Nil@Int64 x);
val triangle_viaFoldRight2 : (Int64 -> Int64) = \ (x: Int64) ->
FOLDR @Int64 @Int64 (\(y: Int64) -> ADD_INT64 y) 0 (F:generate Nil@Int64 x);
// tail-recursive generator
val generate : (List Int64 -> Int64 -> List Int64) = \ (acc: List Int64) (x: Int64) ->
case (EQUAL @Int64 x 0) of
True -> acc
| _ -> F:generate (Cons @Int64 [x] acc) (SUB_INT64 x 1);
// tail-recursive generator
val generate : (List Int64 -> Int64 -> List Int64) = \ (acc: List Int64) (x: Int64) ->
case (EQUAL @Int64 x 0) of
True -> acc
| _ -> F:generate (Cons @Int64 [x] acc) (SUB_INT64 x 1);
}
""",
evaluationOrder,
)
}
""")
val small: Option[Int] = Some(5)
val unbounded: Option[Int] = None
val small: Option[Int] = Some(5)
val unbounded: Option[Int] = None
// Evaluate an expression with optionally bounded env and kont stacks
def runExpr(e: Ast.Expr, envBound: Option[Int], kontBound: Option[Int]): SValue = {
// create the machine
val machine = Speedy.Machine.fromPureExpr(pkgs, e)
// maybe replace the env-stack with a bounded version
envBound match {
case None => ()
case Some(bound) =>
machine.env = new BoundedArrayList[SValue](bound)
}
// maybe replace the kont-stack with a bounded version
kontBound match {
case None => ()
case Some(bound) =>
val onlyKont: Speedy.Kont[Nothing] =
if (machine.kontDepth() != 1) {
crash(s"setBoundedKontStack, unexpected size of kont-stack: ${machine.kontDepth()}")
} else {
machine.peekKontStackTop()
}
machine.kontStack = new BoundedArrayList[Speedy.Kont[Nothing]](bound)
machine.pushKont(onlyKont)
}
// run the machine
machine.run() match {
case SResultFinal(v) => v
case res => crash(s"runExpr, unexpected result $res")
}
}
"A *non* tail-recursive definition requires an unbounded env-stack, and an unbounded kont-stack" in {
val exp = e"F:triangle 100"
val expected = SValue.SInt64(5050)
// The point of this test is to prove that the bounded-evaluation checking really works.
runExpr(exp, envBound = unbounded, kontBound = unbounded) shouldBe expected
the[RuntimeException]
.thrownBy {
runExpr(exp, envBound = small, kontBound = unbounded)
}
.toString() should include("BoundExceeded")
the[RuntimeException]
.thrownBy {
runExpr(exp, envBound = unbounded, kontBound = small)
}
.toString() should include("BoundExceeded")
}
"A tail-recursive definition executes with a small env-stack, and a small kont-stack" in {
val exp = e"F:triangleTR 100"
val expected = SValue.SInt64(5050)
runExpr(exp, envBound = small, kontBound = small) shouldBe expected
}
"fold-left executes with a small env-stack, and a small kont-stack" in {
val exp = e"F:triangle_viaFoldLeft 100"
val expected = SValue.SInt64(5050)
runExpr(exp, envBound = small, kontBound = small) shouldBe expected
}
"fold-right executes with a small env-stack, and a small kont-stack" in {
val exp = e"F:triangle_viaFoldRight 100"
val expected = SValue.SInt64(5050)
runExpr(exp, envBound = small, kontBound = small) shouldBe expected
}
"fold-right (KFoldr1Map/Reduce case) executes with a small env-stack, and a small kont-stack" in {
val exp = e"F:triangle_viaFoldRight2 100"
val expected = SValue.SInt64(5050)
runExpr(exp, envBound = small, kontBound = small) shouldBe expected
}
// Evaluate an expression with optionally bounded env and kont stacks
def runExpr(e: Ast.Expr, envBound: Option[Int], kontBound: Option[Int]): SValue = {
// create the machine
val machine = Speedy.Machine.fromPureExpr(pkgs, e)
// maybe replace the env-stack with a bounded version
envBound match {
case None => ()
case Some(bound) =>
machine.env = new BoundedArrayList[SValue](bound)
}
// maybe replace the kont-stack with a bounded version
kontBound match {
case None => ()
case Some(bound) =>
val onlyKont: Speedy.Kont[Nothing] =
if (machine.kontDepth() != 1) {
crash(s"setBoundedKontStack, unexpected size of kont-stack: ${machine.kontDepth()}")
} else {
machine.peekKontStackTop()
}
machine.kontStack = new BoundedArrayList[Speedy.Kont[Nothing]](bound)
machine.pushKont(onlyKont)
}
// run the machine
machine.run() match {
case SResultFinal(v) => v
case res => crash(s"runExpr, unexpected result $res")
}
}
"A *non* tail-recursive definition requires an unbounded env-stack, and an unbounded kont-stack" in {
val exp = e"F:triangle 100"
val expected = SValue.SInt64(5050)
// The point of this test is to prove that the bounded-evaluation checking really works.
runExpr(exp, envBound = unbounded, kontBound = unbounded) shouldBe expected
the[RuntimeException]
.thrownBy {
runExpr(exp, envBound = small, kontBound = unbounded)
}
.toString() should include("BoundExceeded")
the[RuntimeException]
.thrownBy {
runExpr(exp, envBound = unbounded, kontBound = small)
}
.toString() should include("BoundExceeded")
}
"A tail-recursive definition executes with a small env-stack, and a small kont-stack" in {
val exp = e"F:triangleTR 100"
val expected = SValue.SInt64(5050)
runExpr(exp, envBound = small, kontBound = small) shouldBe expected
}
"fold-left executes with a small env-stack, and a small kont-stack" in {
val exp = e"F:triangle_viaFoldLeft 100"
val expected = SValue.SInt64(5050)
runExpr(exp, envBound = small, kontBound = small) shouldBe expected
}
"fold-right executes with a small env-stack, and a small kont-stack" in {
val exp = e"F:triangle_viaFoldRight 100"
val expected = SValue.SInt64(5050)
runExpr(exp, envBound = small, kontBound = small) shouldBe expected
}
"fold-right (KFoldr1Map/Reduce case) executes with a small env-stack, and a small kont-stack" in {
val exp = e"F:triangle_viaFoldRight2 100"
val expected = SValue.SInt64(5050)
runExpr(exp, envBound = small, kontBound = small) shouldBe expected
}
private case object BoundExceeded extends RuntimeException

View File

@ -6,7 +6,6 @@ package speedy
import com.daml.lf.data.{FrontStack, ImmArray, Ref}
import com.daml.lf.data.Ref.{IdString, PackageId, Party, TypeConName}
import com.daml.lf.language.LanguageDevConfig.{EvaluationOrder}
import com.daml.lf.language.LanguageMajorVersion.{V1, V2}
import com.daml.lf.language.{LanguageMajorVersion, LanguageVersion}
import com.daml.lf.speedy.SBuiltin.{SBCastAnyContract, SBFetchAny}
@ -33,117 +32,108 @@ class TransactionVersionTest(majorLanguageVersion: LanguageMajorVersion)
val helpers = new TransactionVersionTestHelpers(majorLanguageVersion)
import helpers._
for (evaluationOrder <- EvaluationOrder.valuesFor(majorLanguageVersion)) {
"interface and transaction versioning" - {
evaluationOrder.toString - {
"version testing assumptions" in {
// TODO(#17366): remove this assumption once 2.0 is introduced
assume(majorLanguageVersion == V1)
oldVersion should be < newVersion
Set(
templatePkg.languageVersion,
interfacesPkg.languageVersion,
implementsPkg.languageVersion,
coImplementsPkg.languageVersion,
) shouldBe Set(commonVersion)
}
"interface and transaction versioning" - {
"template version > interface version" in {
val oldPkg1 = templatePkg.copy(languageVersion = oldVersion)
val oldPkg2 = interfacesPkg.copy(languageVersion = oldVersion)
val newPkg1 = implementsPkg.copy(languageVersion = newVersion)
val newPkg2 = coImplementsPkg.copy(languageVersion = newVersion)
val pkgs = SpeedyTestLib.typeAndCompile(
majorLanguageVersion,
Map(
templatePkgId -> oldPkg1,
interfacesPkgId -> oldPkg2,
implementsPkgId -> newPkg1,
coImplementsPkgId -> newPkg2,
),
)
"version testing assumptions" in {
// TODO(#17366): remove this assumption once 2.0 is introduced
assume(majorLanguageVersion == V1)
oldVersion should be < newVersion
Set(
templatePkg.languageVersion,
interfacesPkg.languageVersion,
implementsPkg.languageVersion,
coImplementsPkg.languageVersion,
) shouldBe Set(commonVersion)
for ((templateId, interfaceId, contract) <- testData) {
val result = evaluateBeginExercise(
pkgs,
templateId,
Some(interfaceId),
contractId,
committers = Set(contractParty),
controllers = Set(contractParty),
getContract = Map(contractId -> contract),
)
inside(result) { case Right(transaction) =>
transaction.version shouldBe TransactionVersion.assignNodeVersion(newVersion)
}
}
}
"template version > interface version" in {
val oldPkg1 = templatePkg.copy(languageVersion = oldVersion)
val oldPkg2 = interfacesPkg.copy(languageVersion = oldVersion)
val newPkg1 = implementsPkg.copy(languageVersion = newVersion)
val newPkg2 = coImplementsPkg.copy(languageVersion = newVersion)
val pkgs = SpeedyTestLib.typeAndCompile(
majorLanguageVersion,
Map(
templatePkgId -> oldPkg1,
interfacesPkgId -> oldPkg2,
implementsPkgId -> newPkg1,
coImplementsPkgId -> newPkg2,
),
evaluationOrder,
)
"template version < interface version" in {
val oldPkg1 = implementsPkg.copy(languageVersion = oldVersion)
val oldPkg2 = coImplementsPkg.copy(languageVersion = oldVersion)
val newPkg1 = templatePkg.copy(languageVersion = newVersion)
val newPkg2 = interfacesPkg.copy(languageVersion = newVersion)
val pkgs = SpeedyTestLib.typeAndCompile(
majorLanguageVersion,
Map(
templatePkgId -> newPkg1,
interfacesPkgId -> newPkg2,
implementsPkgId -> oldPkg1,
coImplementsPkgId -> oldPkg2,
),
)
for ((templateId, interfaceId, contract) <- testData) {
val result = evaluateBeginExercise(
pkgs,
templateId,
Some(interfaceId),
contractId,
committers = Set(contractParty),
controllers = Set(contractParty),
getContract = Map(contractId -> contract),
)
for ((templateId, interfaceId, contract) <- testData) {
val result = evaluateBeginExercise(
pkgs,
templateId,
Some(interfaceId),
contractId,
committers = Set(contractParty),
controllers = Set(contractParty),
getContract = Map(contractId -> contract),
)
inside(result) { case Right(transaction) =>
transaction.version shouldBe TransactionVersion.assignNodeVersion(newVersion)
}
}
inside(result) { case Right(transaction) =>
transaction.version shouldBe TransactionVersion.assignNodeVersion(newVersion)
}
}
}
"template version < interface version" in {
val oldPkg1 = implementsPkg.copy(languageVersion = oldVersion)
val oldPkg2 = coImplementsPkg.copy(languageVersion = oldVersion)
val newPkg1 = templatePkg.copy(languageVersion = newVersion)
val newPkg2 = interfacesPkg.copy(languageVersion = newVersion)
val pkgs = SpeedyTestLib.typeAndCompile(
majorLanguageVersion,
Map(
templatePkgId -> newPkg1,
interfacesPkgId -> newPkg2,
implementsPkgId -> oldPkg1,
coImplementsPkgId -> oldPkg2,
),
evaluationOrder,
)
"template version == interface version" in {
val pkgs = SpeedyTestLib.typeAndCompile(
majorLanguageVersion,
Map(
templatePkgId -> templatePkg,
interfacesPkgId -> interfacesPkg,
implementsPkgId -> implementsPkg,
coImplementsPkgId -> coImplementsPkg,
),
)
for ((templateId, interfaceId, contract) <- testData) {
val result = evaluateBeginExercise(
pkgs,
templateId,
Some(interfaceId),
contractId,
committers = Set(contractParty),
controllers = Set(contractParty),
getContract = Map(contractId -> contract),
)
for ((templateId, interfaceId, contract) <- testData) {
val result = evaluateBeginExercise(
pkgs,
templateId,
Some(interfaceId),
contractId,
committers = Set(contractParty),
controllers = Set(contractParty),
getContract = Map(contractId -> contract),
)
inside(result) { case Right(transaction) =>
transaction.version shouldBe TransactionVersion.assignNodeVersion(newVersion)
}
}
}
"template version == interface version" in {
val pkgs = SpeedyTestLib.typeAndCompile(
majorLanguageVersion,
Map(
templatePkgId -> templatePkg,
interfacesPkgId -> interfacesPkg,
implementsPkgId -> implementsPkg,
coImplementsPkgId -> coImplementsPkg,
),
evaluationOrder,
)
for ((templateId, interfaceId, contract) <- testData) {
val result = evaluateBeginExercise(
pkgs,
templateId,
Some(interfaceId),
contractId,
committers = Set(contractParty),
controllers = Set(contractParty),
getContract = Map(contractId -> contract),
)
inside(result) { case Right(transaction) =>
transaction.version shouldBe TransactionVersion.assignNodeVersion(commonVersion)
}
}
inside(result) { case Right(transaction) =>
transaction.version shouldBe TransactionVersion.assignNodeVersion(commonVersion)
}
}
}

View File

@ -15,19 +15,4 @@ object LanguageDevConfig {
sealed abstract class EvaluationOrder extends Product with Serializable
case object LeftToRight extends EvaluationOrder
case object RightToLeft extends EvaluationOrder
object EvaluationOrder {
// We can't test RightToLeft evaluation order with V1 because it only works in dev and V1 tests
// will build packages for versions 1.14 and 1.15. It works by accident in V2 at the moment
// because there's only one V2 version: 2.dev. Eventually, right-to-left evaluation will not be
// dev-only but instead 2.x-only, for all V2 versions. Once we've done this refactoring we can
// remove explicit evaluation orders from the tests.
// TODO(#17366): make RightToLeft a v2.x feature and remove evaluation order flags everywhere
def valuesFor(majorLanguageVersion: LanguageMajorVersion): List[EvaluationOrder] =
majorLanguageVersion match {
case LanguageMajorVersion.V1 => List(LeftToRight)
case LanguageMajorVersion.V2 => List(LeftToRight, RightToLeft)
}
}
}

View File

@ -4,8 +4,11 @@
package com.daml.lf.language
import com.daml.lf.LfVersions
import com.daml.lf.language.LanguageDevConfig.{EvaluationOrder, LeftToRight, RightToLeft}
import scalaz.{IList, NonEmptyList}
import scala.math.Ordering.Implicits.infixOrderingOps
// an ADT version of the Daml-LF version
sealed abstract class LanguageMajorVersion(val pretty: String, minorAscending: List[String])
extends LfVersions(
@ -17,6 +20,8 @@ sealed abstract class LanguageMajorVersion(val pretty: String, minorAscending: L
with Product
with Serializable {
import LanguageMajorVersion._
// TODO(#17366): 2.dev is currently the only 2.x version, but as soon as 2.0 is introduced this
// code should be simplified.
val minStableVersion =
@ -47,6 +52,12 @@ sealed abstract class LanguageMajorVersion(val pretty: String, minorAscending: L
Left(s"LF $this.$minorVersion unsupported. Supported LF versions are ${supportedVersions
.mkString(",")}")
}
// TODO(#17366): Ideally this would be specified as a feature, but at the major version level.
// We may want to allow expressing this once we rework feature specifications (see the TODO
// on features).
final def evaluationOrder: EvaluationOrder =
if (this >= V2) RightToLeft else LeftToRight
}
object LanguageMajorVersion {
@ -65,7 +76,7 @@ object LanguageMajorVersion {
val All: List[LanguageMajorVersion] = List(V1, V2)
implicit val Ordering: scala.Ordering[LanguageMajorVersion] =
implicit val languageMajorVersionOrdering: scala.Ordering[LanguageMajorVersion] =
scala.Ordering.by(All.zipWithIndex.toMap)
def fromString(str: String): Option[LanguageMajorVersion] = str match {

View File

@ -22,7 +22,7 @@
- well-authorized lookup is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L127)
## 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#L20)
- 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#L19)
## Confidentiality:
- ensure correct privacy for create node: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L38)
@ -35,124 +35,124 @@
- ensure correct privacy for rollback subtree: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L224)
## Integrity:
- Evaluation order of create with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L587)
- 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#L610)
- 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#L663)
- 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#L637)
- Evaluation order of create with duplicate contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L536)
- Evaluation order of create with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L561)
- Evaluation order of create with failed precondition: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L518)
- Evaluation order of create_interface with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L789)
- 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#L812)
- 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#L865)
- 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#L839)
- Evaluation order of create_interface with duplicate contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L738)
- 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#L763)
- Evaluation order of create_interface with failed precondition: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L718)
- 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#L1838)
- 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#L1820)
- 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#L1880)
- 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#L1184)
- 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#L939)
- 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#L965)
- 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#L1041)
- 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#L924)
- Evaluation order of exercise of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1023)
- Evaluation order of exercise of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1125)
- Evaluation order of exercise of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1209)
- 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#L1145)
- 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#L1077)
- Evaluation order of exercise with argument exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1223)
- Evaluation order of exercise with output exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1251)
- Evaluation order of exercise-by-key of a cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1476)
- Evaluation order of exercise-by-key of a non-cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1356)
- 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#L1544)
- Evaluation order of exercise_by_key of a local contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1568)
- 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#L1329)
- 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#L1432)
- 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#L1413)
- 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#L1524)
- 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#L1603)
- 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#L1451)
- 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#L1618)
- 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#L1693)
- 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#L1647)
- 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#L1995)
- 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#L1764)
- 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#L1931)
- 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#L1950)
- 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#L1677)
- 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#L2283)
- 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#L2073)
- 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#L2096)
- 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#L2161)
- 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#L2303)
- 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#L2058)
- Evaluation order of fetch of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2144)
- Evaluation order of fetch of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2230)
- Evaluation order of fetch of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2322)
- 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#L2248)
- 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#L2195)
- Evaluation order of fetch-by-key of a cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2493)
- Evaluation order of fetch-by-key of a non-cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2409)
- 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#L2476)
- 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#L2552)
- 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#L2386)
- 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#L2457)
- 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#L2534)
- 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#L2581)
- 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#L2613)
- 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#L2627)
- 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#L2597)
- 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#L2752)
- 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#L2880)
- 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#L2672)
- 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#L2691)
- 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#L2735)
- 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#L2825)
- 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#L2842)
- Evaluation order of fetch_interface of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2898)
- 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#L2790)
- Evaluation order of lookup of a cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3048)
- Evaluation order of lookup of a non-cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2965)
- 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#L3031)
- Evaluation order of lookup_by_key of a local contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3122)
- 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#L3106)
- 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#L2942)
- 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#L3013)
- 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#L3089)
- 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#L3152)
- 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#L3184)
- 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#L3198)
- 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#L3168)
- Evaluation order of successful create: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L494)
- Evaluation order of successful create_interface: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L693)
- 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#L1718)
- 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#L999)
- Evaluation order of successful exercise of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1102)
- 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#L897)
- 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#L1387)
- 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#L1500)
- 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#L1285)
- 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#L1795)
- 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#L1907)
- 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#L2127)
- Evaluation order of successful fetch of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2215)
- 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#L2035)
- 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#L2440)
- 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#L2518)
- 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#L2341)
- 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#L2718)
- 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#L2810)
- 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#L2648)
- 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#L2996)
- 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#L3073)
- 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#L2918)
- Evaluation order of create with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L576)
- 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#L599)
- 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#L652)
- 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#L626)
- Evaluation order of create with duplicate contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L525)
- Evaluation order of create with empty contract key maintainers: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L550)
- Evaluation order of create with failed precondition: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L507)
- Evaluation order of create_interface with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L778)
- 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#L801)
- 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#L854)
- 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#L828)
- Evaluation order of create_interface with duplicate contract key: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L727)
- 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#L752)
- Evaluation order of create_interface with failed precondition: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L707)
- 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#L1823)
- 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#L1805)
- 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#L1865)
- 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#L1170)
- 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#L928)
- 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#L954)
- 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#L1028)
- 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#L913)
- Evaluation order of exercise of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1011)
- Evaluation order of exercise of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1112)
- Evaluation order of exercise of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1195)
- 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#L1131)
- 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#L1064)
- Evaluation order of exercise with argument exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1209)
- Evaluation order of exercise with output exceeding max nesting: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1237)
- Evaluation order of exercise-by-key of a cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1462)
- Evaluation order of exercise-by-key of a non-cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1342)
- 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#L1530)
- Evaluation order of exercise_by_key of a local contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1554)
- 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#L1315)
- 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#L1418)
- 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#L1399)
- 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#L1510)
- 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#L1589)
- 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#L1437)
- 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#L1604)
- 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#L1679)
- 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#L1633)
- 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#L1979)
- 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#L1750)
- 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#L1915)
- 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#L1934)
- 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#L1663)
- 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#L2264)
- 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#L2057)
- 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#L2080)
- 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#L2143)
- 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#L2284)
- 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#L2042)
- Evaluation order of fetch of an inactive global contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2127)
- Evaluation order of fetch of an inactive local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2212)
- Evaluation order of fetch of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2303)
- 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#L2229)
- 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#L2177)
- Evaluation order of fetch-by-key of a cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2474)
- Evaluation order of fetch-by-key of a non-cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2390)
- 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#L2457)
- 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#L2533)
- 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#L2367)
- 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#L2438)
- 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#L2515)
- 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#L2562)
- 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#L2594)
- 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#L2608)
- 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#L2578)
- 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#L2733)
- 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#L2861)
- 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#L2653)
- 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#L2672)
- 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#L2716)
- 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#L2806)
- 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#L2823)
- Evaluation order of fetch_interface of an unknown contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2879)
- 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#L2771)
- Evaluation order of lookup of a cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3029)
- Evaluation order of lookup of a non-cached global contract with visibility failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2946)
- 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#L3012)
- Evaluation order of lookup_by_key of a local contract with authorization failure: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L3103)
- 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#L3087)
- 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#L2923)
- 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#L2994)
- 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#L3070)
- 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#L3133)
- 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#L3165)
- 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#L3179)
- 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#L3149)
- Evaluation order of successful create: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L483)
- Evaluation order of successful create_interface: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L682)
- 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#L1704)
- 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#L987)
- Evaluation order of successful exercise of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1089)
- 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#L886)
- 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#L1373)
- 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#L1486)
- 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#L1271)
- 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#L1780)
- 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#L1891)
- 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#L2110)
- Evaluation order of successful fetch of a local contract: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L2197)
- 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#L2019)
- 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#L2421)
- 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#L2499)
- 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#L2322)
- 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#L2699)
- 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#L2791)
- 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#L2629)
- 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#L2977)
- 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#L3054)
- 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#L2899)
- Exceptions, throw/catch.: [ExceptionTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExceptionTest.scala#L30)
- Rollback creates cannot be exercise: [EngineTest.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala#L2103)
- 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#L1975)
- 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#L1862)
- 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#L2862)
- 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#L1959)
- 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#L1847)
- 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#L2843)
- contract key behaviour (non-unique mode): [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L408)
- contract key behaviour (unique mode): [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L418)
- 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#L224)
@ -161,7 +161,7 @@
- ensure builtin operators have the correct type: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L66)
- ensure expression forms have the correct type: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L126)
- exercise-by-interface command is rejected for a: [ApiCommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ApiCommandPreprocessorSpec.scala#L187)
- 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#L1746)
- 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#L1732)
- ill-formed create API command is rejected: [ApiCommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ApiCommandPreprocessorSpec.scala#L175)
- ill-formed create replay command is rejected: [ReplayCommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ReplayCommandPreprocessorSpec.scala#L124)
- ill-formed create-and-exercise API command is rejected: [ApiCommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ApiCommandPreprocessorSpec.scala#L200)