diff --git a/compiler/damlc/tests/daml-test-files/TransientFailure.daml b/compiler/damlc/tests/daml-test-files/TransientFailure.daml new file mode 100644 index 00000000000..931977f8623 --- /dev/null +++ b/compiler/damlc/tests/daml-test-files/TransientFailure.daml @@ -0,0 +1,35 @@ +-- Copyright (c) 2020, Digital Asset (Switzerland) GmbH and/or its affiliates. +-- All rights reserved. + +-- @ERROR exercise C on #1:1 +module TransientFailure where + +template T' + with + p: Party + where + signatory p + choice C : () + controller p + do assert False + +template T + with + p: Party + where + signatory p + nonconsuming choice FailingTransient : () + controller p + do cid <- create T' with p + exercise cid C + +testBio : Scenario () +testBio = do + p <- getParty "p" + latestCid <- submit p do create T with p + -- This produces a failing transaction with a contract created + -- in the same transaction. In the past this resulted + -- in an exception in the scenario service when converting + -- between contract ids and node ids. + submit p do exercise latestCid FailingTransient + return () diff --git a/compiler/scenario-service/server/src/main/scala/com/digitalasset/daml/lf/scenario/Conversions.scala b/compiler/scenario-service/server/src/main/scala/com/digitalasset/daml/lf/scenario/Conversions.scala index be5dde343f1..720816b6b1a 100644 --- a/compiler/scenario-service/server/src/main/scala/com/digitalasset/daml/lf/scenario/Conversions.scala +++ b/compiler/scenario-service/server/src/main/scala/com/digitalasset/daml/lf/scenario/Conversions.scala @@ -24,7 +24,20 @@ final class Conversions( private val packageIdSelf: PackageIdentifier = PackageIdentifier.newBuilder.setSelf(empty).build - private val coidToNodeId = ledger.ledgerData.coidToNodeId + // The ledger data will not contain information from the partial transaction at this point. + // We need the mapping for converting error message so we manually add it here. + private val ptxCoidToNodeId = machine.ptx.nodes + .collect { + case (nodeId, node: N.NodeCreate.WithTxValue[V.ContractId]) => + node.coid match { + case acoid: V.AbsoluteContractId => + acoid -> ledger.ptxNodeId(nodeId) + case V.RelativeContractId(_) => + throw new IllegalArgumentException("unexpected relative contract id") + } + } + + private val coidToNodeId = ledger.ledgerData.coidToNodeId ++ ptxCoidToNodeId private val nodes = ledger.ledgerData.nodeInfos.map(Function.tupled(convertNode)) @@ -308,7 +321,7 @@ final class Conversions( case acoid: V.AbsoluteContractId => coidToNodeId(acoid) case V.RelativeContractId(_) => - throw new IllegalArgumentException("unexpected relative cotnract id") + throw new IllegalArgumentException("unexpected relative contract id") } def convertScenarioStep( diff --git a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/types/Ledger.scala b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/types/Ledger.scala index 3a84adf2315..23945de8038 100644 --- a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/types/Ledger.scala +++ b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/types/Ledger.scala @@ -389,6 +389,11 @@ object Ledger { } } } + + // Given a ledger and the node index of a node in a partial transaction + // turn it into a node it that can be used in scenario error messages. + def ptxNodeId(nodeIdx: NodeId): ScenarioNodeId = + ScenarioNodeId(scenarioStepId.makeCommitPrefix, nodeIdx) } sealed trait CommitError