mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 01:07:18 +03:00
Use the appropriate daml-script
for each Script
(#14321)
* Add failing test * Overload daml-script 'Runner.run' to work directly with 'PureCompiledPackages' * Use new daml-script 'Runner.run' in scenario-service changelog_begin * data-dependencies: fixed an issue with the handling of multiple versions of the daml-script package (#14291) changelog_end Co-authored-by: Remy <remy.haemmerle@daml.com>
This commit is contained in:
parent
89b068ecde
commit
ba9abf3c5f
@ -453,8 +453,11 @@ da_haskell_test(
|
||||
"//compiler/damlc",
|
||||
"@damlc_legacy",
|
||||
"//compiler/damlc/tests:generate-simple-dalf",
|
||||
"//daml-script/daml:daml-script.dar",
|
||||
# Feel free to update this to 0.13.55 once that is frozen.
|
||||
":dars/old-proj-0.13.55-snapshot.20200309.3401.0.6f8c3ad8-1.8.dar",
|
||||
# Used in regression test for https://github.com/digital-asset/daml/issues/14291
|
||||
":dars/lib-with-script-0.0.1-sdk-2.2.0-lf-1.14.dar",
|
||||
],
|
||||
hackage_deps = [
|
||||
"base",
|
||||
|
Binary file not shown.
@ -31,7 +31,9 @@ main = do
|
||||
setEnv "TASTY_NUM_THREADS" "3" True
|
||||
damlc <- locateRunfiles (mainWorkspace </> "compiler" </> "damlc" </> exe "damlc")
|
||||
damlcLegacy <- locateRunfiles ("damlc_legacy" </> exe "damlc_legacy")
|
||||
damlScriptDar <- locateRunfiles (mainWorkspace </> "daml-script" </> "daml" </> "daml-script.dar")
|
||||
oldProjDar <- locateRunfiles (mainWorkspace </> "compiler" </> "damlc" </> "tests" </> "dars" </> "old-proj-0.13.55-snapshot.20200309.3401.0.6f8c3ad8-1.8.dar")
|
||||
libWithScriptDar <- locateRunfiles (mainWorkspace </> "compiler" </> "damlc" </> "tests" </> "dars" </> "lib-with-script-0.0.1-sdk-2.2.0-lf-1.14.dar")
|
||||
let validate dar = callProcessSilent damlc ["validate-dar", dar]
|
||||
defaultMain $ tests Tools{..}
|
||||
|
||||
@ -39,7 +41,9 @@ data Tools = Tools -- and places
|
||||
{ damlc :: FilePath
|
||||
, damlcLegacy :: FilePath
|
||||
, validate :: FilePath -> IO ()
|
||||
, damlScriptDar :: FilePath
|
||||
, oldProjDar :: FilePath
|
||||
, libWithScriptDar :: FilePath
|
||||
}
|
||||
|
||||
damlcForTarget :: Tools -> LF.Version -> FilePath
|
||||
@ -65,7 +69,7 @@ lfVersionTestPairs =
|
||||
in legacyPairs ++ zip versions (tail versions)
|
||||
|
||||
tests :: Tools -> TestTree
|
||||
tests tools@Tools{damlc,validate,oldProjDar} = testGroup "Data Dependencies" $
|
||||
tests tools = testGroup "Data Dependencies" $
|
||||
[ testCaseSteps ("Cross Daml-LF version: " <> LF.renderVersion depLfVer <> " -> " <> LF.renderVersion targetLfVer) $ \step -> withTempDir $ \tmpDir -> do
|
||||
let proja = tmpDir </> "proja"
|
||||
let projb = tmpDir </> "projb"
|
||||
@ -2329,6 +2333,63 @@ tests tools@Tools{damlc,validate,oldProjDar} = testGroup "Data Dependencies" $
|
||||
, "--project-root", path mainProj
|
||||
]
|
||||
|
||||
, testCaseSteps "Cross-SDK data-dependency with daml-script" $ \step' -> withTempDir $ \tmpDir -> do
|
||||
-- regression test for https://github.com/digital-asset/daml/issues/14291
|
||||
let
|
||||
mainProj = "main"
|
||||
|
||||
path proj = tmpDir </> proj
|
||||
damlYaml proj = path proj </> "daml.yaml"
|
||||
damlMod proj mod = path proj </> mod <.> "daml"
|
||||
step proj = step' ("building '" <> proj <> "' project")
|
||||
|
||||
step mainProj >> do
|
||||
createDirectoryIfMissing True (path mainProj)
|
||||
writeFileUTF8 (damlYaml mainProj) $ unlines
|
||||
[ "sdk-version: " <> sdkVersion
|
||||
, "name: " <> mainProj
|
||||
, "source: ."
|
||||
, "version: 0.1.0"
|
||||
, "dependencies: [daml-prim, daml-stdlib, " <> damlScriptDar <> "]"
|
||||
, "data-dependencies: [" <> libWithScriptDar <> "]"
|
||||
]
|
||||
writeFileUTF8 (damlMod mainProj "Main") $ unlines
|
||||
[ "module Main where"
|
||||
, "import Daml.Script"
|
||||
, "import Lib qualified"
|
||||
|
||||
, "template T1"
|
||||
, " with"
|
||||
, " party : Party"
|
||||
, " where"
|
||||
, " signatory party"
|
||||
|
||||
, " nonconsuming choice C1 : Bool"
|
||||
, " controller party"
|
||||
, " do pure False"
|
||||
|
||||
, "run1 : Lib.Script ()"
|
||||
, "run1 = Lib.run"
|
||||
|
||||
, "run2 : Script ()"
|
||||
, "run2 = script do"
|
||||
, " alice <- allocateParty \"alice\""
|
||||
|
||||
, " t <- alice `submit` createCmd Lib.T0 with party = alice"
|
||||
, " b <- alice `submit` exerciseCmd t Lib.C0"
|
||||
, " debug b"
|
||||
, " alice `submit` archiveCmd t"
|
||||
|
||||
, " t <- alice `submit` createCmd T1 with party = alice"
|
||||
, " b <- alice `submit` exerciseCmd t C1"
|
||||
, " debug b"
|
||||
, " alice `submit` archiveCmd t"
|
||||
]
|
||||
callProcessSilent damlc
|
||||
[ "test"
|
||||
, "--project-root", path mainProj
|
||||
]
|
||||
|
||||
, testCaseSteps "User-defined exceptions" $ \step -> withTempDir $ \tmpDir -> do
|
||||
step "building project to be imported via data-dependencies"
|
||||
createDirectoryIfMissing True (tmpDir </> "lib")
|
||||
@ -2506,6 +2567,14 @@ tests tools@Tools{damlc,validate,oldProjDar} = testGroup "Data Dependencies" $
|
||||
, "--target", LF.renderVersion LF.versionDev ]
|
||||
]
|
||||
where
|
||||
Tools
|
||||
{ damlc
|
||||
, validate
|
||||
, damlScriptDar
|
||||
, oldProjDar
|
||||
, libWithScriptDar
|
||||
} = tools
|
||||
|
||||
simpleImportTest :: String -> [String] -> [String] -> TestTree
|
||||
simpleImportTest title = simpleImportTestOptions title []
|
||||
|
||||
|
@ -10,15 +10,15 @@ import akka.stream.Materializer
|
||||
import com.daml.grpc.adapter.ExecutionSequencerFactory
|
||||
import com.daml.lf.archive
|
||||
import com.daml.lf.data.{assertRight, ImmArray}
|
||||
import com.daml.lf.data.Ref.{DottedName, Identifier, ModuleName, PackageId, QualifiedName}
|
||||
import com.daml.lf.data.Ref.{Identifier, ModuleName, PackageId, QualifiedName}
|
||||
import com.daml.lf.engine.script.ledgerinteraction.{IdeLedgerClient, ScriptTimeMode}
|
||||
import com.daml.lf.language.{Ast, LanguageVersion, Util => AstUtil}
|
||||
import com.daml.lf.scenario.api.v1.{ScenarioModule => ProtoScenarioModule}
|
||||
import com.daml.lf.speedy.{Compiler, SDefinition, SExpr, Speedy}
|
||||
import com.daml.lf.speedy.{Compiler, SDefinition, Speedy}
|
||||
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.{Participants, Runner, Script, ScriptF, ScriptIds}
|
||||
import com.daml.lf.engine.script.{Participants, Runner, ScriptF}
|
||||
import com.daml.logging.LoggingContext
|
||||
|
||||
import scala.concurrent.ExecutionContext
|
||||
@ -164,23 +164,22 @@ class Context(val contextId: Context.ContextId, languageVersion: LanguageVersion
|
||||
): Future[Option[ScenarioRunner.ScenarioResult]] = {
|
||||
val defns = this.defns
|
||||
val compiledPackages = PureCompiledPackages(allSignatures, defns, compilerConfig)
|
||||
val expectedScriptId = DottedName.assertFromString("Daml.Script")
|
||||
val Some(scriptPackageId) = allSignatures.collectFirst {
|
||||
case (pkgId, pkg) if pkg.modules contains expectedScriptId => pkgId
|
||||
}
|
||||
val scriptExpr = SExpr.SEVal(
|
||||
LfDefRef(Identifier(PackageId.assertFromString(pkgId), QualifiedName.assertFromString(name)))
|
||||
)
|
||||
val runner = new Runner(
|
||||
compiledPackages,
|
||||
Script.Action(scriptExpr, ScriptIds(scriptPackageId)),
|
||||
ScriptTimeMode.Static,
|
||||
)
|
||||
val scriptId =
|
||||
Identifier(PackageId.assertFromString(pkgId), QualifiedName.assertFromString(name))
|
||||
val traceLog = Speedy.Machine.newTraceLog
|
||||
val warningLog = Speedy.Machine.newWarningLog
|
||||
val ledgerClient: IdeLedgerClient = new IdeLedgerClient(compiledPackages, traceLog, warningLog)
|
||||
val participants = Participants(Some(ledgerClient), Map.empty, Map.empty)
|
||||
val (clientMachine, resultF) = runner.runWithClients(participants, traceLog, warningLog)
|
||||
val (clientMachine, resultF) = Runner.run(
|
||||
compiledPackages = compiledPackages,
|
||||
scriptId = scriptId,
|
||||
convertInputValue = None,
|
||||
inputValue = None,
|
||||
initialClients = participants,
|
||||
timeMode = ScriptTimeMode.Static,
|
||||
traceLog = traceLog,
|
||||
warningLog = warningLog,
|
||||
)
|
||||
|
||||
def handleFailure(e: Error) =
|
||||
// SError are the errors that should be handled and displayed as
|
||||
|
@ -320,31 +320,68 @@ object Runner {
|
||||
): Future[SValue] = {
|
||||
val darMap = dar.all.toMap
|
||||
val compiledPackages = PureCompiledPackages.assertBuild(darMap, Runner.compilerConfig)
|
||||
def converter(json: JsValue, typ: Type) = {
|
||||
val ifaceDar = dar.map(pkg => InterfaceReader.readInterface(() => \/-(pkg))._2)
|
||||
val envIface = EnvironmentInterface.fromReaderInterfaces(ifaceDar)
|
||||
Converter.fromJsonValue(
|
||||
scriptId.qualifiedName,
|
||||
envIface,
|
||||
compiledPackages,
|
||||
typ,
|
||||
json,
|
||||
)
|
||||
}
|
||||
run(
|
||||
compiledPackages,
|
||||
scriptId,
|
||||
Some(converter),
|
||||
inputValue,
|
||||
initialClients,
|
||||
timeMode,
|
||||
)._2
|
||||
}
|
||||
|
||||
// Executes a Daml script
|
||||
//
|
||||
// Looks for the script in the given compiledPackages, applies the input
|
||||
// value as an argument if provided together with a conversion function,
|
||||
// and runs the script with the given participants.
|
||||
def run(
|
||||
compiledPackages: PureCompiledPackages,
|
||||
scriptId: Identifier,
|
||||
convertInputValue: Option[(JsValue, Type) => Either[String, SValue]],
|
||||
inputValue: Option[JsValue],
|
||||
initialClients: Participants[ScriptLedgerClient],
|
||||
timeMode: ScriptTimeMode,
|
||||
traceLog: TraceLog = Speedy.Machine.newTraceLog,
|
||||
warningLog: WarningLog = Speedy.Machine.newWarningLog,
|
||||
)(implicit
|
||||
ec: ExecutionContext,
|
||||
esf: ExecutionSequencerFactory,
|
||||
mat: Materializer,
|
||||
): (Speedy.Machine, Future[SValue]) = {
|
||||
val script = data.assertRight(Script.fromIdentifier(compiledPackages, scriptId))
|
||||
val scriptAction: Script.Action = (script, inputValue) match {
|
||||
case (script: Script.Action, None) => script
|
||||
case (script: Script.Function, Some(inputJson)) =>
|
||||
val ifaceDar = dar.map(pkg => InterfaceReader.readInterface(() => \/-(pkg))._2)
|
||||
val envIface = EnvironmentInterface.fromReaderInterfaces(ifaceDar)
|
||||
val arg = Converter
|
||||
.fromJsonValue(
|
||||
scriptId.qualifiedName,
|
||||
envIface,
|
||||
compiledPackages,
|
||||
script.param,
|
||||
inputJson,
|
||||
) match {
|
||||
case Left(msg) => throw new ConverterException(msg)
|
||||
case Right(x) => x
|
||||
convertInputValue match {
|
||||
case Some(f) =>
|
||||
f(inputJson, script.param) match {
|
||||
case Left(msg) => throw new ConverterException(msg)
|
||||
case Right(arg) => script.apply(SEValue(arg))
|
||||
}
|
||||
case None =>
|
||||
throw new RuntimeException(
|
||||
s"The script ${scriptId} requires an argument, but a converter was not provided"
|
||||
)
|
||||
}
|
||||
script.apply(SEValue(arg))
|
||||
case (_: Script.Action, Some(_)) =>
|
||||
throw new RuntimeException(s"The script ${scriptId} does not take arguments.")
|
||||
case (_: Script.Function, None) =>
|
||||
throw new RuntimeException(s"The script ${scriptId} requires an argument.")
|
||||
}
|
||||
val runner = new Runner(compiledPackages, scriptAction, timeMode)
|
||||
runner.runWithClients(initialClients)._2
|
||||
runner.runWithClients(initialClients, traceLog, warningLog)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user