diff --git a/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/ValueEnricher.scala b/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/ValueEnricher.scala index 17df381f5168..a935024f2b05 100644 --- a/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/ValueEnricher.scala +++ b/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/ValueEnricher.scala @@ -4,20 +4,35 @@ package com.daml.lf package engine -import com.daml.lf.data.Ref.{Identifier, Name} +import com.daml.lf.data.Ref.{Identifier, Name, PackageId} import com.daml.lf.language.{Ast, LookupError} import com.daml.lf.transaction.Node.{GenNode, KeyWithMaintainers} import com.daml.lf.transaction.{CommittedTransaction, Node, NodeId, VersionedTransaction} import com.daml.lf.value.Value import com.daml.lf.value.Value.VersionedValue +import com.daml.lf.speedy.SValue // Provide methods to add missing information in values (and value containers): // - type constructor in records, variants, and enums // - Records' field names -final class ValueEnricher(engine: Engine) { - def enrichValue(typ: Ast.Type, value: Value): Result[Value] = - engine.preprocessor.translateValue(typ, value).map(_.toUnnormalizedValue) +final class ValueEnricher( + compiledPackages: CompiledPackages, + translateValue: (Ast.Type, Value) => Result[SValue], + loadPackage: (PackageId, language.Reference) => Result[Unit], +) { + + def this(engine: Engine) = { + this( + engine.compiledPackages(), + engine.preprocessor.translateValue, + engine.loadPackage, + ) + } + + def enrichValue(typ: Ast.Type, value: Value): Result[Value] = { + translateValue(typ, value).map(_.toUnnormalizedValue) + } def enrichVersionedValue( typ: Ast.Type, @@ -44,13 +59,12 @@ final class ValueEnricher(engine: Engine) { def enrichContract(tyCon: Identifier, value: Value): Result[Value] = enrichValue(Ast.TTyCon(tyCon), value) - private[this] def interface = engine.compiledPackages().interface + private[this] def interface = compiledPackages.interface private[this] def handleLookup[X](lookup: => Either[LookupError, X]) = lookup match { case Right(value) => ResultDone(value) case Left(LookupError.MissingPackage(pkgId, context)) => - engine - .loadPackage(pkgId, context) + loadPackage(pkgId, context) .flatMap(_ => lookup match { case Right(value) => ResultDone(value) diff --git a/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/ValueTranslator.scala b/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/ValueTranslator.scala index 33ee8f825344..9c472dafa08c 100644 --- a/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/ValueTranslator.scala +++ b/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/ValueTranslator.scala @@ -14,7 +14,7 @@ import com.daml.lf.value.Value._ import scala.annotation.tailrec -private[engine] final class ValueTranslator( +private[lf] final class ValueTranslator( interface: language.PackageInterface, // See Preprocessor scala doc for more details about the following flags. forbidV0ContractId: Boolean, diff --git a/daml-lf/scenario-interpreter/BUILD.bazel b/daml-lf/scenario-interpreter/BUILD.bazel index 2b9f77045804..dcf7de2b6243 100644 --- a/daml-lf/scenario-interpreter/BUILD.bazel +++ b/daml-lf/scenario-interpreter/BUILD.bazel @@ -47,6 +47,7 @@ da_scala_test_suite( deps = [ ":scenario-interpreter", "//daml-lf/data", + "//daml-lf/engine", "//daml-lf/interpreter", "//daml-lf/language", "//daml-lf/transaction", @@ -77,6 +78,7 @@ da_scala_benchmark_jmh( "//daml-lf/archive:daml_lf_archive_reader", "//daml-lf/archive:daml_lf_dev_archive_proto_java", "//daml-lf/data", + "//daml-lf/engine", "//daml-lf/interpreter", "//daml-lf/language", "//daml-lf/scenario-interpreter", diff --git a/daml-lf/scenario-interpreter/src/main/scala/com/digitalasset/daml/lf/ScenarioRunner.scala b/daml-lf/scenario-interpreter/src/main/scala/com/digitalasset/daml/lf/ScenarioRunner.scala index ab161eb54efc..2a452dec8b5c 100644 --- a/daml-lf/scenario-interpreter/src/main/scala/com/digitalasset/daml/lf/ScenarioRunner.scala +++ b/daml-lf/scenario-interpreter/src/main/scala/com/digitalasset/daml/lf/ScenarioRunner.scala @@ -6,9 +6,10 @@ package scenario import com.daml.lf.data.Ref._ import com.daml.lf.data.{ImmArray, Ref, Time} -import com.daml.lf.engine.Engine +import com.daml.lf.engine.{Engine, ValueEnricher, Result, ResultDone, ResultError} +import com.daml.lf.engine.preprocessing.ValueTranslator import com.daml.lf.language.{Ast, LookupError} -import com.daml.lf.transaction.{GlobalKey, NodeId, SubmittedTransaction} +import com.daml.lf.transaction.{GlobalKey, NodeId, SubmittedTransaction, CommittedTransaction} import com.daml.lf.value.Value.{ContractId, ContractInst} import com.daml.lf.speedy._ import com.daml.lf.speedy.SResult._ @@ -139,9 +140,6 @@ final case class ScenarioRunner( ScenarioSuccess(ledger, machine.traceLog, machine.warningLog, diff, steps, finalValue) } - private def crash(reason: String) = - throw Error.Internal(reason) - private def getParty(partyText: String, callback: Party => Unit) = { val mangledPartyText = partyNameMangler(partyText) Party.fromString(mangledPartyText) match { @@ -158,6 +156,9 @@ final case class ScenarioRunner( object ScenarioRunner { + private def crash(reason: String) = + throw Error.Internal(reason) + @deprecated("can be used only by sandbox classic.", since = "1.4.0") def getScenarioLedger( engine: Engine, @@ -408,16 +409,41 @@ object ScenarioRunner { traceLog = traceLog, warningLog = warningLog, commitLocation = location, - transactionNormalization = false, ) val onLedger = ledgerMachine.withOnLedger(NameOf.qualifiedNameOfCurrentFunc)(identity) + + def enrich(tx: SubmittedTransaction): SubmittedTransaction = { + val config = Engine.DevEngine().config + val valueTranslator = + new ValueTranslator( + interface = compiledPackages.interface, + forbidV0ContractId = config.forbidV0ContractId, + requireV1ContractIdSuffix = config.requireSuffixedGlobalContractId, + ) + def translateValue(typ: Ast.Type, value: Value): Result[SValue] = + valueTranslator.translateValue(typ, value) match { + case Left(err) => ResultError(err) + case Right(sv) => ResultDone(sv) + } + def loadPackage(pkgId: PackageId, context: language.Reference): Result[Unit] = { + crash(LookupError.MissingPackage.pretty(pkgId, context)) + } + val enricher = new ValueEnricher(compiledPackages, translateValue, loadPackage) + def consume[V](res: Result[V]): V = + res match { + case ResultDone(x) => x + case x => crash(s"unexpected Result when enriching value: $x") + } + SubmittedTransaction(consume(enricher.enrichTransaction(CommittedTransaction(tx)))) + } + @tailrec def go(): SubmissionResult[R] = { ledgerMachine.run() match { case SResult.SResultFinalValue(resultValue) => onLedger.ptxInternal.finish match { case PartialTransaction.CompleteTransaction(tx, locationInfo, _) => - ledger.commit(committers, readAs, location, tx, locationInfo) match { + ledger.commit(committers, readAs, location, enrich(tx), locationInfo) match { case Left(err) => SubmissionError(err, onLedger.ptxInternal) case Right(r) =>