Skip to content

Commit

Permalink
Error when fetching the wrong template id (via fetch by interface). (#…
Browse files Browse the repository at this point in the history
…11862)

* Prevent wrongly typed fetch by interface.

When doing a "fetch by interface" command with a known template id,
error out with a WronglyTypedContract if the fetched contract has
a different template id. This doesn't affect daml, only affects
replays, so it's rather minor. I also enabled the engine test that
caught this.

Part of #11703, follow up to #11836.

changelog_begin
changelog_end

* strengthen test output checks
  • Loading branch information
sofiafaro-da authored Nov 25, 2021
1 parent 0852c8f commit 024400b
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import org.scalatest.prop.TableDrivenPropertyChecks
import org.scalatest.EitherValues
import org.scalatest.wordspec.AnyWordSpec
import org.scalatest.matchers.should.Matchers
import interpretation.{Error => IE}

import scala.language.implicitConversions

Expand Down Expand Up @@ -220,7 +221,7 @@ class InterfacesTest
ExerciseByInterfaceCommand(idI2, idT2, cid2, "C2", ValueRecord(None, ImmArray.empty))
run(command) shouldBe a[Right[_, _]]
}
"be unable to exercise T1 by interface I2 (stopped in preprocessor)" in {
"be unable to exercise T1 by interface I2 via 'exercise by interface' (stopped in preprocessor)" in {
val command =
ExerciseByInterfaceCommand(idI2, idT1, cid1, "C2", ValueRecord(None, ImmArray.empty))
preprocess(command) shouldBe a[Left[_, _]]
Expand All @@ -229,12 +230,22 @@ class InterfacesTest
"be unable to exercise T1 (disguised as T2) by interface I1 via 'exercise by interface'" in {
val command =
ExerciseByInterfaceCommand(idI1, idT2, cid1, "C1", ValueRecord(None, ImmArray.empty))
run(command) shouldBe a[Left[_, _]]
run(command) match {
case Left(Error.Interpretation(err, _)) =>
err shouldBe Error.Interpretation.DamlException(IE.WronglyTypedContract(cid1, idT2, idT1))
case result =>
fail(s"Expected Left(Error.Interpretation(err, _)), not $result")
}
}
"be unable to exercise T2 (disguised as T1) by interface I1 via 'exercise by interface'" in {
val command =
ExerciseByInterfaceCommand(idI1, idT1, cid2, "C1", ValueRecord(None, ImmArray.empty))
run(command) shouldBe a[Left[_, _]]
run(command) match {
case Left(Error.Interpretation(err, _)) =>
err shouldBe Error.Interpretation.DamlException(IE.WronglyTypedContract(cid2, idT1, idT2))
case result =>
fail(s"Expected Left(Error.Interpretation(err, _)), not $result")
}
}
"be unable to exercise T2 (disguised as T1) by interface I2 via 'exercise by interface' (stopped in preprocessor)" in {
val command =
Expand Down Expand Up @@ -274,18 +285,24 @@ class InterfacesTest
val command = FetchByInterfaceCommand(idI2, idT2, cid1)
run(command) shouldBe a[Left[_, _]]
}
// TODO https://github.com/digital-asset/daml/issues/11703
// Enable these tests.
/*
"be unable to fetch T1 (disguised as T2) via interface I1" in {
val command = FetchByInterfaceCommand(idI1, idT2, cid1)
run(command) shouldBe a[Left[_, _]]
"be unable to fetch T1 (disguised as T2) via interface I1" in {
val command = FetchByInterfaceCommand(idI1, idT2, cid1)
run(command) match {
case Left(Error.Interpretation(err, _)) =>
err shouldBe Error.Interpretation.DamlException(IE.WronglyTypedContract(cid1, idT2, idT1))
case result =>
fail(s"Expected Left(Error.Interpretation(err, _)), not $result")
}
"be unable to fetch T2 (disguised as T1) via interface I1" in {
val command = FetchByInterfaceCommand(idI1, idT1, cid2)
run(command) shouldBe a[Left[_, _]]
}
"be unable to fetch T2 (disguised as T1) via interface I1" in {
val command = FetchByInterfaceCommand(idI1, idT1, cid2)
run(command) match {
case Left(Error.Interpretation(err, _)) =>
err shouldBe Error.Interpretation.DamlException(IE.WronglyTypedContract(cid2, idT1, idT2))
case result =>
fail(s"Expected Left(Error.Interpretation(err, _)), not $result")
}
*/
}
"be unable to fetch T2 (disguised as T1) by interface I2 (stopped in preprocessor)" in {
val command = FetchByInterfaceCommand(idI2, idT1, cid2)
preprocess(command) shouldBe a[Left[_, _]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,21 @@ private[lf] final class Compiler(
}
}

private[this] def compileFetchByInterface(
interfaceId: TypeConName,
templateId: TypeConName,
contractId: SValue,
): s.SExpr =
unaryFunction(Env.Empty) { (tokenPos, env) =>
let(env, t.FetchDefRef(interfaceId)(s.SEValue(contractId), env.toSEVar(tokenPos))) {
(payloadPos, env) =>
let(env, SBGuardTemplateId(templateId)(s.SEValue(contractId), env.toSEVar(payloadPos))) {
(_, env) =>
env.toSEVar(payloadPos)
}
}
}

private[this] def compileCommand(cmd: Command): s.SExpr = cmd match {
case Command.Create(templateId, argument) =>
t.CreateDefRef(templateId)(s.SEValue(argument))
Expand All @@ -1528,10 +1543,8 @@ private[lf] final class Compiler(
t.ChoiceByKeyDefRef(templateId, choiceId)(s.SEValue(contractKey), s.SEValue(argument))
case Command.Fetch(templateId, coid) =>
t.FetchDefRef(templateId)(s.SEValue(coid))
case Command.FetchByInterface(interfaceId, templateId @ _, coid) =>
// TODO https://github.com/digital-asset/daml/issues/11703
// Ensure that fetched template has expected templateId.
t.FetchDefRef(interfaceId)(s.SEValue(coid))
case Command.FetchByInterface(interfaceId, templateId, coid) =>
compileFetchByInterface(interfaceId, templateId, coid)
case Command.FetchByKey(templateId, key) =>
t.FetchByKeyDefRef(templateId)(s.SEValue(key))
case Command.CreateAndExercise(templateId, createArg, choice, choiceArg) =>
Expand Down

0 comments on commit 024400b

Please sign in to comment.