Use ScenarioRunner.submit in Daml Script (#10053)

* Use ScenarioRunner.submit in Daml Script

changelog_begin
changelog_end

* privatize ledger variable

changelog_begin
changelog_end

* drop space

changelog_begin
changelog_end
This commit is contained in:
Moritz Kiefer 2021-06-17 19:12:45 +02:00 committed by GitHub
parent 3113702dc0
commit febca5d62d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 165 additions and 230 deletions

View File

@ -367,7 +367,7 @@ main =
" pure ()"
]
expectScriptSuccess rs (vr "testAssertFail") $ \r ->
matchRegex r "Active contracts: #0:0, #1:0\n\nReturn value: {}\n\n$"
matchRegex r "Active contracts: #0:0, #2:0\n\nReturn value: {}\n\n$"
pure (),
testCase "contract keys" $ do
rs <-
@ -667,7 +667,7 @@ main =
, " submitMulti [p0] [p1] (createCmd (T p0 p1))"
]
expectScriptSuccess rs (vr "testSucceed") $ \r ->
matchRegex r "Active contracts: #0:0, #1:0"
matchRegex r "Active contracts: #2:0, #3:0"
expectScriptFailure rs (vr "testFail") $ \r ->
matchRegex r "missing authorization from 'p1'",
testCase "submitTree" $ do
@ -816,7 +816,7 @@ main =
matchRegex :: T.Text -> T.Text -> Bool
matchRegex s regex = matchTest (makeRegex regex :: Regex) s
expectScriptSuccess ::
expectScriptSuccess :: HasCallStack =>
-- | The list of script results.
[(VirtualResource, Either T.Text T.Text)] ->
-- | VR of the script

View File

@ -13,6 +13,7 @@ import scalaz.std.scalaFuture._
import scalaz.syntax.traverse._
import com.daml.lf.archive.Decode.ParseError
import com.daml.lf.data.ImmArray
import com.daml.lf.data.Ref
import com.daml.lf.data.Ref.ModuleName
import com.daml.lf.language.LanguageVersion
@ -176,35 +177,33 @@ class ScenarioService(implicit
}
context
.interpretScript(packageId, scenarioId.getName)
.map(_.map { case (ledger, (clientMachine, ledgerMachine), errOrValue) =>
.map(_.map { case (ledger, (clientMachine, submissionCache), errOrValue) =>
val builder = RunScenarioResponse.newBuilder
ledgerMachine.withOnLedger("runScript") { onLedger =>
errOrValue match {
case Left(err) =>
builder.setError(
new Conversions(
context.homePackageId,
ledger,
onLedger.incompleteTransaction(),
clientMachine.traceLog,
onLedger.commitLocation,
ledgerMachine.stackTrace(),
)
.convertScenarioError(err)
errOrValue match {
case Left(err) =>
builder.setError(
new Conversions(
context.homePackageId,
ledger,
submissionCache.ptx.finishIncomplete,
clientMachine.traceLog,
submissionCache.commitLocation,
ImmArray.empty,
)
case Right(value) =>
builder.setResult(
new Conversions(
context.homePackageId,
ledger,
onLedger.incompleteTransaction(),
clientMachine.traceLog,
onLedger.commitLocation,
ledgerMachine.stackTrace(),
)
.convertScenarioResult(value)
.convertScenarioError(err)
)
case Right(value) =>
builder.setResult(
new Conversions(
context.homePackageId,
ledger,
submissionCache.ptx.finishIncomplete,
clientMachine.traceLog,
submissionCache.commitLocation,
ImmArray.empty,
)
}
.convertScenarioResult(value)
)
}
builder.build
})
@ -219,6 +218,7 @@ class ScenarioService(implicit
respObs.onNext(resp)
respObs.onCompleted()
case Failure(err) =>
System.err.println(err)
respObs.onError(err)
}
}

View File

@ -190,7 +190,9 @@ class Context(val contextId: Context.ContextId, languageVersion: LanguageVersion
ec: ExecutionContext,
esf: ExecutionSequencerFactory,
mat: Materializer,
): Future[Option[(ScenarioLedger, (Speedy.Machine, Speedy.Machine), Either[SError, SValue])]] = {
): Future[Option[
(ScenarioLedger, (Speedy.Machine, IdeLedgerClient.SubmissionCache), Either[SError, SValue])
]] = {
val defns = this.defns
val compiledPackages = PureCompiledPackages(allSignatures, defns, compilerConfig)
val expectedScriptId = DottedName.assertFromString("Daml.Script")
@ -220,7 +222,7 @@ class Context(val contextId: Context.ContextId, languageVersion: LanguageVersion
clientMachine.traceLog.add(msg, optLoc)
}
Success(
Some((ledgerClient.scenarioRunner.ledger, (clientMachine, ledgerClient.machine), Left(e)))
Some((ledgerClient.ledger, (clientMachine, ledgerClient.lastSubmission), Left(e)))
)
}
@ -228,7 +230,7 @@ class Context(val contextId: Context.ContextId, languageVersion: LanguageVersion
case Success(v) =>
Success(
Some(
(ledgerClient.scenarioRunner.ledger, (clientMachine, ledgerClient.machine), Right(v))
(ledgerClient.ledger, (clientMachine, ledgerClient.lastSubmission), Right(v))
)
)
case Failure(e: SError) => handleFailure(e)

View File

@ -1310,10 +1310,7 @@ private[lf] object SBuiltin {
commands = args.get(1),
location = optLocation,
mustFail = mustFail,
callback = newValue => {
machine.clearCommit
machine.returnValue = newValue
},
callback = newValue => machine.returnValue = newValue,
)
)
}

View File

@ -30,10 +30,6 @@ import scala.util.control.NoStackTrace
private[lf] object Speedy {
// fake participant to generate a new transactionSeed when running scenarios
private[this] val scenarioServiceParticipant =
Ref.ParticipantId.assertFromString("scenario-service")
// Would like these to have zero cost when not enabled. Better still, to be switchable at runtime.
private[this] val enableInstrumentation: Boolean = false
private[this] val enableLightweightStepTracing: Boolean = false
@ -603,25 +599,6 @@ private[lf] object Speedy {
println("============================================================")
}
// reinitialize the state of the machine with a new fresh submission seed.
// Should be used only when running scenario
private[lf] def clearCommit: Unit = withOnLedger("clearCommit") { onLedger =>
val freshSeed =
crypto.Hash.deriveTransactionSeed(
onLedger.ptx.context.nextActionChildSeed,
scenarioServiceParticipant,
onLedger.ptx.submissionTime,
)
onLedger.committers = Set.empty
onLedger.commitLocation = None
onLedger.ptx = PartialTransaction.initial(
onLedger.ptx.packageToTransactionVersion,
onLedger.ptx.contractKeyUniqueness,
onLedger.ptx.submissionTime,
InitialSeeding.TransactionSeed(freshSeed),
)
}
// This translates a well-typed LF value (typically coming from the ledger)
// to speedy value and set the control of with the result.
// Note the method does not check the value is well-typed as opposed as

View File

@ -52,15 +52,6 @@ final case class ScenarioRunner(
case Right(t) => Right(t)
}
private[this] def nextSeed(submissionSeed: crypto.Hash): crypto.Hash =
crypto.Hash.deriveTransactionSeed(
submissionSeed,
Ref.ParticipantId.assertFromString("scenario-service"),
// MinValue makes no sense here but this is what we did before so
// to avoid breaking all tests we keep it for now at least.
Time.Timestamp.MinValue,
)
private def runUnsafe(): (Double, Int, ScenarioLedger, SValue) = {
// NOTE(JM): Written with an imperative loop and exceptions for speed
// and so that we don't need to worry about stack usage.
@ -92,7 +83,8 @@ final case class ScenarioRunner(
machine.compiledPackages,
ScenarioLedgerApi(ledger),
committers,
commands,
Set.empty,
SExpr.SEValue(commands),
location,
seed,
)
@ -253,6 +245,7 @@ object ScenarioRunner {
def currentTime: Time.Timestamp
def commit(
committers: Set[Party],
readAs: Set[Party],
location: Option[Location],
tx: SubmittedTransaction,
): Either[SError, R]
@ -368,12 +361,13 @@ object ScenarioRunner {
override def currentTime = ledger.currentTime
override def commit(
committers: Set[Party],
readAs: Set[Party],
location: Option[Location],
tx: SubmittedTransaction,
): Either[SError, ScenarioLedger.CommitResult] =
ScenarioLedger.commitTransaction(
actAs = committers,
readAs = Set.empty,
readAs = readAs,
effectiveAt = ledger.currentTime,
optLocation = location,
tx = tx,
@ -390,7 +384,8 @@ object ScenarioRunner {
compiledPackages: CompiledPackages,
ledger: LedgerApi[R],
committers: Set[Party],
commands: SValue,
readAs: Set[Party],
commands: SExpr,
location: Option[Location],
seed: crypto.Hash,
): SubmissionResult[R] = {
@ -398,7 +393,7 @@ object ScenarioRunner {
compiledPackages = compiledPackages,
submissionTime = Time.Timestamp.MinValue,
initialSeeding = InitialSeeding.TransactionSeed(seed),
expr = SExpr.SEApp(SExpr.SEValue(commands), Array(SExpr.SEValue(SValue.SToken))),
expr = SExpr.SEApp(commands, Array(SExpr.SEValue(SValue.SToken))),
globalCids = Set.empty,
committers = committers,
)
@ -412,7 +407,7 @@ object ScenarioRunner {
case SResultFinalValue(resultValue) =>
onLedger.ptxInternal.finish match {
case PartialTransaction.CompleteTransaction(tx) =>
ledger.commit(committers, location, tx) match {
ledger.commit(committers, readAs, location, tx) match {
case Left(err) => SubmissionError(err, onLedger.ptxInternal, ledgerMachine.traceLog)
case Right(r) =>
Commit(r, resultValue, onLedger.ptxInternal, ledgerMachine.traceLog)
@ -423,17 +418,17 @@ object ScenarioRunner {
case SResultError(err) =>
SubmissionError(err, onLedger.ptxInternal, ledgerMachine.traceLog)
case SResultNeedContract(coid, tid @ _, committers, _, cbPresent) =>
ledger.lookupContract(coid, committers, Set.empty, cbPresent) match {
ledger.lookupContract(coid, committers, readAs, cbPresent) match {
case Left(err) => SubmissionError(err, onLedger.ptxInternal, ledgerMachine.traceLog)
case Right(_) => go()
}
case SResultNeedKey(keyWithMaintainers, committers, cb) =>
ledger.lookupKey(keyWithMaintainers.globalKey, committers, Set.empty, cb) match {
ledger.lookupKey(keyWithMaintainers.globalKey, committers, readAs, cb) match {
case Left(err) => SubmissionError(err, onLedger.ptxInternal, ledgerMachine.traceLog)
case Right(_) => go()
}
case SResultNeedLocalKeyVisible(stakeholders, committers, cb) =>
val visible = SVisibleByKey.fromSubmitters(committers, Set.empty)(stakeholders)
val visible = SVisibleByKey.fromSubmitters(committers, readAs)(stakeholders)
cb(visible)
go()
case SResultNeedTime(callback) =>
@ -451,4 +446,13 @@ object ScenarioRunner {
}
go()
}
private[lf] def nextSeed(submissionSeed: crypto.Hash): crypto.Hash =
crypto.Hash.deriveTransactionSeed(
submissionSeed,
Ref.ParticipantId.assertFromString("scenario-service"),
// MinValue makes no sense here but this is what we did before so
// to avoid breaking all tests we keep it for now at least.
Time.Timestamp.MinValue,
)
}

View File

@ -90,7 +90,8 @@ class CollectAuthorityState {
machine.compiledPackages,
api,
committers,
commands,
Set.empty,
SExpr.SEValue(commands),
location,
crypto.Hash.hashPrivateKey(step.toString),
) match {
@ -131,7 +132,8 @@ class CollectAuthorityState {
machine.compiledPackages,
api,
committers,
commands,
Set.empty,
SExpr.SEValue(commands),
location,
crypto.Hash.hashPrivateKey(step.toString),
) match {
@ -203,6 +205,7 @@ class CannedLedgerApi(
override def commit(
committers: Set[Party],
readAs: Set[Party],
location: Option[Location],
tx: SubmittedTransaction,
) = Right(())

View File

@ -56,7 +56,6 @@ da_scala_library(
"//ledger/ledger-api-client",
"//ledger/ledger-api-common",
"//libs-scala/auth-utils",
"//libs-scala/scala-utils",
],
)

View File

@ -71,7 +71,6 @@ object ScriptF {
for ((msg, optLoc) <- client.tracelogIterator) {
machine.traceLog.add(msg, optLoc)
}
client.clearTracelog
}
def addPartyParticipantMapping(party: Party, participant: Participant) = {
_clients =

View File

@ -324,5 +324,4 @@ class GrpcLedgerClient(val grpcClient: LedgerClient, val applicationId: Applicat
}
override def tracelogIterator = Iterator.empty
override def clearTracelog = ()
}

View File

@ -9,13 +9,15 @@ import com.daml.ledger.api.domain.PartyDetails
import com.daml.lf.data.Ref._
import com.daml.lf.data.{ImmArray, Ref, Time}
import com.daml.lf.scenario.ScenarioLedger
import com.daml.lf.scenario.ScenarioLedger.RichTransaction
import com.daml.lf.speedy.SError._
import com.daml.lf.speedy.SExpr._
import com.daml.lf.speedy.SResult._
import com.daml.lf.speedy.SValue._
import com.daml.lf.speedy.Speedy.{Machine, OffLedger, OnLedger}
import com.daml.lf.speedy.{PartialTransaction, SValue, ScenarioRunner, TraceLog}
import com.daml.lf.speedy.SValue
import com.daml.lf.speedy.{
InitialSeeding,
PartialTransaction,
RingBufferTraceLog,
ScenarioRunner,
TraceLog,
}
import com.daml.lf.transaction.Node.{
NodeRollback,
NodeCreate,
@ -23,60 +25,63 @@ import com.daml.lf.transaction.Node.{
NodeFetch,
NodeLookupByKey,
}
import com.daml.lf.transaction.{GlobalKey, NodeId}
import com.daml.lf.transaction.{ContractKeyUniquenessMode, GlobalKey, NodeId, TransactionVersion}
import com.daml.lf.value.Value
import com.daml.lf.value.Value.ContractId
import com.daml.lf._
import com.daml.scalautil.Statement.discard
import com.daml.script.converter.ConverterException
import io.grpc.StatusRuntimeException
import org.slf4j.LoggerFactory
import scalaz.OneAnd
import scalaz.OneAnd._
import scalaz.std.set._
import scalaz.syntax.foldable._
import scala.collection.compat.immutable.LazyList
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success}
// Client for the script service.
class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedgerClient {
class ArrayBufferTraceLog extends TraceLog {
val buffer = ArrayBuffer[(String, Option[Location])]()
override def add(message: String, optLocation: Option[Location]): Unit = {
discard { buffer.append((message, optLocation)) }
}
override def iterator: Iterator[(String, Option[Location])] = {
buffer.iterator
}
def clear: Unit = buffer.clear()
}
private val pkg2TxVersion =
compiledPackages.interface.packageLanguageVersion.andThen(
TransactionVersion.assignNodeVersion
)
private val contractKeyUniqueness = ContractKeyUniquenessMode.On
private val damlTraceLog = LoggerFactory.getLogger("daml.tracelog")
val traceLog = new ArrayBufferTraceLog()
import IdeLedgerClient.SubmissionCache
private var seed = crypto.Hash.hashPrivateKey(s"script-service")
private var _lastSubmission: Option[SubmissionCache] = None
private[this] def emptyPtx: PartialTransaction = PartialTransaction.initial(
pkg2TxVersion,
contractKeyUniqueness,
ledger.currentTime,
InitialSeeding.TransactionSeed(seed),
)
private[this] def clearPtx(): Unit =
_lastSubmission = _lastSubmission.map(cache =>
cache.copy(
ptx = emptyPtx
)
)
def lastSubmission: SubmissionCache = _lastSubmission.getOrElse(
SubmissionCache(
ptx = emptyPtx,
traceLog = RingBufferTraceLog(damlTraceLog, 100),
commitLocation = None,
)
)
private[this] val preprocessor = new engine.preprocessing.CommandPreprocessor(compiledPackages)
private val seed = crypto.Hash.hashPrivateKey(s"script-service")
private val txSeeding =
speedy.InitialSeeding.TransactionSeed(seed)
// Machine for submissions.
val machine = Machine(
compiledPackages,
submissionTime = Time.Timestamp.Epoch,
initialSeeding = txSeeding,
expr = null,
globalCids = Set.empty,
committers = Set.empty,
traceLog = traceLog,
)
val onLedger = machine.ledgerMode match {
case OffLedger => throw SRequiresOnLedger("ScenarioRunner")
case onLedger: OnLedger => onLedger
}
val scenarioRunner = ScenarioRunner(machine, seed)
private var _ledger: ScenarioLedger = ScenarioLedger.initialLedger(Time.Timestamp.Epoch)
def ledger: ScenarioLedger = _ledger
private var allocatedParties: Map[String, PartyDetails] = Map()
@ -84,9 +89,9 @@ class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedg
ec: ExecutionContext,
mat: Materializer,
): Future[Seq[ScriptLedgerClient.ActiveContract]] = {
val acs = scenarioRunner.ledger.query(
val acs = ledger.query(
view = ScenarioLedger.ParticipantView(Set(), Set(parties.toList: _*)),
effectiveAt = scenarioRunner.ledger.currentTime,
effectiveAt = ledger.currentTime,
)
val filtered = acs.collect {
case ScenarioLedger.LookupOk(cid, Value.ContractInst(tpl, arg, _), stakeholders)
@ -106,9 +111,9 @@ class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedg
ec: ExecutionContext,
mat: Materializer,
): Future[Option[ScriptLedgerClient.ActiveContract]] = {
scenarioRunner.ledger.lookupGlobalContract(
ledger.lookupGlobalContract(
view = ScenarioLedger.ParticipantView(Set(), Set(parties.toList: _*)),
effectiveAt = scenarioRunner.ledger.currentTime,
effectiveAt = ledger.currentTime,
cid,
) match {
case ScenarioLedger.LookupOk(_, Value.ContractInst(_, arg, _), stakeholders)
@ -137,7 +142,7 @@ class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedg
.build(templateId, key.toValue)
.fold(err => Future.failed(new ConverterException(err)), Future.successful(_))
.flatMap { gkey =>
scenarioRunner.ledger.ledgerData.activeKeys.get(gkey) match {
ledger.ledgerData.activeKeys.get(gkey) match {
case None => Future.successful(None)
case Some(cid) => queryContractId(parties, templateId, cid)
}
@ -151,85 +156,24 @@ class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedg
commands: List[command.ApiCommand],
optLocation: Option[Location],
)(implicit ec: ExecutionContext): Future[
Either[StatusRuntimeException, RichTransaction]
ScenarioRunner.SubmissionResult[ScenarioLedger.CommitResult]
] =
Future {
// Clear state at the beginning like in SBSBeginCommit for scenarios.
machine.returnValue = null
onLedger.commitLocation = optLocation
onLedger.globalDiscriminators = Set.empty
onLedger.cachedContracts = Map.empty
val speedyCommands = preprocessor.unsafePreprocessCommands(commands.to(ImmArray))._1
val translated = compiledPackages.compiler.unsafeCompile(speedyCommands)
machine.setExpressionToEvaluate(SEApp(translated, Array(SEValue.Token)))
onLedger.committers = actAs.toSet
var result: RichTransaction = null
while (result == null) {
machine.run() match {
case SResultNeedContract(coid, tid @ _, committers @ _, _, cbPresent) =>
discard {
ScenarioRunner
.ScenarioLedgerApi(scenarioRunner.ledger)
.lookupContract(coid, actAs.toSet, readAs, cbPresent)
.toTry
.get
}
case SResultNeedKey(keyWithMaintainers, committers @ _, cb) =>
ScenarioRunner
.ScenarioLedgerApi(scenarioRunner.ledger)
.lookupKey(keyWithMaintainers.globalKey, actAs.toSet, readAs, cb)
.toTry
.get
case SResultNeedLocalKeyVisible(stakeholders, committers @ _, cb) =>
val visible = SVisibleByKey.fromSubmitters(actAs.toSet, readAs)(stakeholders)
cb(visible)
case SResultFinalValue(SUnit) =>
onLedger.ptxInternal.finish match {
case PartialTransaction.CompleteTransaction(tx) =>
ScenarioLedger.commitTransaction(
actAs = actAs.toSet,
readAs = readAs,
effectiveAt = scenarioRunner.ledger.currentTime,
optLocation = onLedger.commitLocation,
tx = tx,
l = scenarioRunner.ledger,
) match {
case Left(fas) =>
// Capture the error and exit.
throw ScenarioErrorCommitError(fas)
case Right(commitResult) =>
scenarioRunner.ledger = commitResult.newLedger
// Capture the result and exit.
result = commitResult.richTransaction
}
case PartialTransaction.IncompleteTransaction(ptx) =>
throw new RuntimeException(s"Unexpected abort: $ptx")
}
case SResultFinalValue(v) =>
// The final result should always be unit.
throw new RuntimeException(s"FATAL: Unexpected non-unit final result: $v")
case _: SResultScenarioSubmit =>
throw new RuntimeException("FATAL: Encountered scenario submit in Daml Script")
case SResultError(err) =>
// Capture the error and exit.
throw err
case SResultNeedTime(callback) =>
callback(scenarioRunner.ledger.currentTime)
case SResultNeedPackage(pkg, callback @ _) =>
throw new RuntimeException(
s"FATAL: Missing package $pkg should have been reported at Script compilation"
)
case SResultScenarioPassTime(relTime @ _, callback @ _) =>
throw new RuntimeException(
"FATAL: Encountered scenario instruction setTime in Daml Script"
)
case SResultScenarioGetParty(partyText @ _, callback @ _) =>
throw new RuntimeException(
"FATAL: Encountered scenario instruction getParty in Daml Script"
)
}
}
Right(result)
val ledgerApi = ScenarioRunner.ScenarioLedgerApi(ledger)
val result = ScenarioRunner.submit(
compiledPackages,
ledgerApi,
actAs.toSet,
readAs,
translated,
optLocation,
seed,
)
_lastSubmission = Some(SubmissionCache(result.traceLog, result.ptx, optLocation))
result
}
override def submit(
@ -242,10 +186,13 @@ class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedg
mat: Materializer,
): Future[Either[StatusRuntimeException, Seq[ScriptLedgerClient.CommandResult]]] =
unsafeSubmit(actAs, readAs, commands, optLocation).map {
case Right(richTransaction) =>
val transaction = richTransaction.transaction
// Expected successful commit so clear.
machine.clearCommit
case ScenarioRunner.Commit(result, _, _, _) =>
_ledger = result.newLedger
seed = ScenarioRunner.nextSeed(
crypto.Hash.deriveNodeSeed(seed, result.richTransaction.transaction.roots.length)
)
clearPtx()
val transaction = result.richTransaction.transaction
def convRootEvent(id: NodeId): ScriptLedgerClient.CommandResult = {
val node = transaction.nodes.getOrElse(
id,
@ -264,10 +211,10 @@ class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedg
}
}
Right(transaction.roots.toSeq.map(convRootEvent(_)))
case Left(err) =>
case ScenarioRunner.SubmissionError(err, _, _) =>
// Unexpected failure, do not clear so we can display the partial
// transaction.
Left(err)
throw err
}
override def submitMustFail(
@ -278,15 +225,14 @@ class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedg
)(implicit ec: ExecutionContext, mat: Materializer): Future[Either[Unit, Unit]] = {
unsafeSubmit(actAs, readAs, commands, optLocation)
.map({
case Right(_) => Left(())
// We don't expect to hit this case but list it for completeness.
case Left(_) => Right(())
})
.recoverWith({ case _: SError =>
// Expected failed commit so clear, we do not clear on
// unexpected successes to keep the partial transaction.
machine.clearCommit
Future.successful(Right(()))
case _: ScenarioRunner.Commit[_] => Left(())
case error: ScenarioRunner.SubmissionError =>
_ledger = ledger.insertAssertMustFail(actAs.toSet, readAs, optLocation)
seed = ScenarioRunner.nextSeed(
error.ptx.unwind.context.nextActionChildSeed
)
clearPtx()
Right(())
})
}
@ -300,10 +246,13 @@ class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedg
mat: Materializer,
): Future[ScriptLedgerClient.TransactionTree] = {
unsafeSubmit(actAs, readAs, commands, optLocation).map {
case Right(richTransaction) =>
// Expected successful commit so clear.
machine.clearCommit
val transaction = richTransaction.transaction
case ScenarioRunner.Commit(result, _, _, _) =>
_ledger = result.newLedger
seed = ScenarioRunner.nextSeed(
crypto.Hash.deriveNodeSeed(seed, result.richTransaction.transaction.roots.length)
)
clearPtx()
val transaction = result.richTransaction.transaction
def convEvent(id: NodeId): Option[ScriptLedgerClient.TreeEvent] =
transaction.nodes(id) match {
case create: NodeCreate[ContractId] =>
@ -323,14 +272,14 @@ class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedg
ScriptLedgerClient.TransactionTree(
transaction.roots.collect(Function.unlift(convEvent(_))).toList
)
case Left(err) => throw new IllegalStateException(err)
case ScenarioRunner.SubmissionError(err, _, _) => throw new IllegalStateException(err)
}
}
// All parties known to the ledger. This may include parties that were not
// allocated explicitly, e.g. parties created by `partyFromText`.
private def getLedgerParties(): Iterable[Ref.Party] = {
scenarioRunner.ledger.ledgerData.nodeInfos.values.flatMap(_.disclosures.keys)
ledger.ledgerData.nodeInfos.values.flatMap(_.disclosures.keys)
}
override def allocateParty(partyIdHint: String, displayName: String)(implicit
@ -374,7 +323,7 @@ class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedg
esf: ExecutionSequencerFactory,
mat: Materializer,
): Future[Time.Timestamp] = {
Future.successful(scenarioRunner.ledger.currentTime)
Future.successful(ledger.currentTime)
}
override def setStaticTime(time: Time.Timestamp)(implicit
@ -382,13 +331,22 @@ class IdeLedgerClient(val compiledPackages: CompiledPackages) extends ScriptLedg
esf: ExecutionSequencerFactory,
mat: Materializer,
): Future[Unit] = {
val diff = time.micros - scenarioRunner.ledger.currentTime.micros
val diff = time.micros - ledger.currentTime.micros
// ScenarioLedger only provides pass, so we have to calculate the diff.
// Note that ScenarioLedger supports going backwards in time.
scenarioRunner.ledger = scenarioRunner.ledger.passTime(diff)
_ledger = ledger.passTime(diff)
Future.unit
}
override def tracelogIterator = traceLog.iterator
override def clearTracelog = traceLog.clear
override def tracelogIterator =
_lastSubmission.map(_.traceLog.iterator).getOrElse(Iterator.empty)
}
object IdeLedgerClient {
// Data cached from the last submission so we can pluck it out the client at the end.
case class SubmissionCache(
traceLog: TraceLog,
ptx: PartialTransaction,
commitLocation: Option[Location],
)
}

View File

@ -453,7 +453,6 @@ class JsonLedgerClient(
}
override def tracelogIterator = Iterator.empty
override def clearTracelog = ()
}
object JsonLedgerClient {

View File

@ -128,6 +128,4 @@ trait ScriptLedgerClient {
)(implicit ec: ExecutionContext, esf: ExecutionSequencerFactory, mat: Materializer): Future[Unit]
def tracelogIterator: Iterator[(String, Option[Location])]
def clearTracelog: Unit
}