mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 01:07:18 +03:00
LF: enforce non-empty maintainers in contract key in fetchByKey (#7649)
This fixes a bug in the Speedy interpreter. With this change, the interpreter crashes if it attempts to fetch using a contract key that has an empty set of maintainers. This propagates to exerciseByKey as this command is compiled using fetchByKey speedy built-in. This is a breaking change approved by @bame-da . CHANGELOG_BEGIN [LF] (Bug fix) enforce non-empty maintainers in contract key during fetchByKey and exericiseByKey. CHANGELOG_END
This commit is contained in:
parent
ad79acdb65
commit
9b2a7d59e8
@ -1,5 +1,6 @@
|
||||
-- @ERROR Attempt to create a contract key with an empty set of maintainers
|
||||
-- @ERROR Attempt to fetch or lookup a contract key with an empty set of maintainers
|
||||
-- @ERROR range=14:0-14:18; Attempt to create a contract key with an empty set of maintainers
|
||||
-- @ERROR range=20:0-20:18; Attempt to fetch, lookup or exercise a contract key with an empty set of maintainers
|
||||
-- @ERROR range=26:0-26:17; Attempt to fetch, lookup or exercise a contract key with an empty set of maintainers
|
||||
module EmptyContractKeyMaintainers where
|
||||
|
||||
template NoMaintainer
|
||||
@ -17,8 +18,13 @@ createNoMaintainer = scenario do
|
||||
pure ()
|
||||
|
||||
lookupNoMaintainer = scenario do
|
||||
alice <- getParty "Alice"
|
||||
alice <- getParty "Alice"
|
||||
|
||||
submit alice $ lookupByKey @NoMaintainer alice
|
||||
pure ()
|
||||
submit alice $ lookupByKey @NoMaintainer alice
|
||||
pure ()
|
||||
|
||||
fetchNoMaintainer = scenario do
|
||||
alice <- getParty "Alice"
|
||||
|
||||
submit alice $ fetchByKey @NoMaintainer alice
|
||||
pure ()
|
@ -246,7 +246,7 @@ prettyScenarioErrorError (Just err) = do
|
||||
]
|
||||
ScenarioErrorErrorFetchEmptyContractKeyMaintainers ScenarioError_FetchEmptyContractKeyMaintainers{..} ->
|
||||
pure $ vcat
|
||||
[ "Attempt to fetch or lookup a contract key with an empty set of maintainers"
|
||||
[ "Attempt to fetch, lookup or exercise a contract key with an empty set of maintainers"
|
||||
, label_ "Template:"
|
||||
$ prettyMay "<missing template id>"
|
||||
(prettyDefName world)
|
||||
|
@ -683,6 +683,80 @@ class EngineTest
|
||||
}
|
||||
}
|
||||
|
||||
"exercise-by-key" should {
|
||||
val seed = hash("exercise-by-key")
|
||||
|
||||
val now = Time.Timestamp.now
|
||||
|
||||
"crash if use a contract key with an empty set of maintainers" in {
|
||||
val templateId =
|
||||
Identifier(basicTestsPkgId, "BasicTests:NoMaintainer")
|
||||
|
||||
val cmds = ImmArray(
|
||||
speedy.Command.ExerciseByKey(
|
||||
templateId = templateId,
|
||||
contractKey = SParty(alice),
|
||||
choiceId = ChoiceName.assertFromString("Noop"),
|
||||
argument = SValue.SUnit,
|
||||
)
|
||||
)
|
||||
|
||||
val result = engine
|
||||
.interpretCommands(
|
||||
validating = false,
|
||||
submitters = Set(alice),
|
||||
commands = cmds,
|
||||
ledgerTime = now,
|
||||
submissionTime = now,
|
||||
seeding = InitialSeeding.TransactionSeed(seed),
|
||||
globalCids = Set.empty,
|
||||
)
|
||||
.consume(_ => None, lookupPackage, lookupKey)
|
||||
|
||||
inside(result) {
|
||||
case Left(err) =>
|
||||
err.msg should include(
|
||||
"Update failed due to a contract key with an empty sey of maintainers")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"fecth-by-key" should {
|
||||
val seed = hash("fetch-by-key")
|
||||
|
||||
val now = Time.Timestamp.now
|
||||
|
||||
"crash if use a contract key with an empty set of maintainers" in {
|
||||
val templateId =
|
||||
Identifier(basicTestsPkgId, "BasicTests:NoMaintainer")
|
||||
|
||||
val cmds = ImmArray(
|
||||
speedy.Command.FetchByKey(
|
||||
templateId = templateId,
|
||||
key = SParty(alice),
|
||||
)
|
||||
)
|
||||
|
||||
val result = engine
|
||||
.interpretCommands(
|
||||
validating = false,
|
||||
submitters = Set(alice),
|
||||
commands = cmds,
|
||||
ledgerTime = now,
|
||||
submissionTime = now,
|
||||
seeding = InitialSeeding.TransactionSeed(seed),
|
||||
globalCids = Set.empty,
|
||||
)
|
||||
.consume(_ => None, lookupPackage, lookupKey)
|
||||
|
||||
inside(result) {
|
||||
case Left(err) =>
|
||||
err.msg should include(
|
||||
"Update failed due to a contract key with an empty sey of maintainers")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"create-and-exercise command" should {
|
||||
val submissionSeed = hash("create-and-exercise command")
|
||||
val templateId = Identifier(basicTestsPkgId, "BasicTests:Simple")
|
||||
|
@ -39,6 +39,11 @@ object Command {
|
||||
coid: SContractId,
|
||||
) extends Command
|
||||
|
||||
final case class FetchByKey(
|
||||
templateId: Identifier,
|
||||
key: SValue,
|
||||
) extends Command
|
||||
|
||||
final case class CreateAndExercise(
|
||||
templateId: Identifier,
|
||||
createArgument: SValue,
|
||||
|
@ -1491,6 +1491,8 @@ private[lf] final class Compiler(
|
||||
compileExerciseByKey(templateId, SEValue(contractKey), choiceId, SEValue(argument))
|
||||
case Command.Fetch(templateId, coid) =>
|
||||
FetchDefRef(templateId)(SEValue(coid))
|
||||
case Command.FetchByKey(templateId, key) =>
|
||||
FetchByKeyDefRef(templateId)(SEValue(key))
|
||||
case Command.CreateAndExercise(templateId, createArg, choice, choiceArg) =>
|
||||
compileCreateAndExercise(
|
||||
templateId,
|
||||
|
@ -1148,6 +1148,8 @@ private[lf] object SBuiltin {
|
||||
onLedger: OnLedger
|
||||
): Unit = {
|
||||
val keyWithMaintainers = extractKeyWithMaintainers(args.get(0))
|
||||
if (keyWithMaintainers.maintainers.isEmpty)
|
||||
throw DamlEFetchEmptyContractKeyMaintainers(templateId, keyWithMaintainers.key)
|
||||
val gkey = GlobalKey(templateId, keyWithMaintainers.key)
|
||||
// check if we find it locally
|
||||
onLedger.ptx.keys.get(gkey) match {
|
||||
|
@ -598,3 +598,8 @@ template NoMaintainer
|
||||
signatory sig
|
||||
key sig : Party
|
||||
maintainer [] @Party
|
||||
|
||||
nonconsuming choice Noop: ()
|
||||
controller sig
|
||||
do
|
||||
pure ()
|
Loading…
Reference in New Issue
Block a user