Skip to content

Commit

Permalink
Infer templateId and choiceName in daml trigger commands (digital-ass…
Browse files Browse the repository at this point in the history
…et#2945)

* Infer templateId from createCmd argument

* Infer templateId and choiceName in exerciseCmd

* Use exerciseCmd in ACS test

Add a layer of indirection to test `exerciseCmd` in the ACS test.

The trigger first creates a `AssetMirrorProposal`, only when the
proposal has been created, will it exercise the `Accept` choice to
create the actual `AssetMirror` contract.

* Remove toTemplateId

* getTemplateId --> toTemplateId

* Tuple2 --> AnyContractId

* Run Scala formatter

* Export AnyContractId

* extractTemplateId|ChoiceName
  • Loading branch information
aherrmann-da authored and mergify[bot] committed Sep 18, 2019
1 parent 5a9a037 commit df7262e
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 46 deletions.
31 changes: 16 additions & 15 deletions triggers/daml/Daml/Trigger.daml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module Daml.Trigger
( Message(..)
, Transaction(..)
, Identifier(..)
, AnyContractId(..)
, Event(..)
, Created(..)
, Archived(..)
Expand All @@ -24,6 +25,11 @@ data Identifier = Identifier
, entityName : Text
} deriving (Show, Eq)

data AnyContractId = AnyContractId
{ templateId : Identifier
, contractId : Text
} deriving (Show, Eq)

data Transaction = Transaction
{ transactionId : Text
, events : [Event]
Expand All @@ -36,14 +42,12 @@ data Event

data Created = Created
{ eventId : Text
, contractId : Text
, templateId : Identifier
, contractId : AnyContractId
} deriving (Show, Eq)

data Archived = Archived
{ eventId : Text
, contractId : Text
, templateId : Identifier
, contractId : AnyContractId
} deriving (Show, Eq)

data Message
Expand Down Expand Up @@ -80,23 +84,20 @@ toLedgerValue = error "toLedgerValue should be removed."

data Command
= CreateCommand
{ templateId : TemplateId
, templateArg : LedgerValue
{ templateArg : LedgerValue
}
| ExerciseCommand
{ templateId : TemplateId
, contractId : Text
, choiceName : Text
{ contractId : AnyContractId
, choiceArg : LedgerValue
}

createCmd : Template t => TemplateId -> t -> Command
createCmd templateId templateArg =
CreateCommand templateId (toLedgerValue templateArg)
createCmd : Template t => t -> Command
createCmd templateArg =
CreateCommand (toLedgerValue templateArg)

exerciseCmd : Choice t c r => TemplateId -> Text -> Text -> c -> Command
exerciseCmd templateId contractId choiceName choiceArg =
ExerciseCommand templateId contractId choiceName (toLedgerValue choiceArg)
exerciseCmd : Choice t c r => AnyContractId -> c -> Command
exerciseCmd contractId choiceArg =
ExerciseCommand contractId (toLedgerValue choiceArg)

data Commands = Commands
{ commandId : Text
Expand Down
82 changes: 62 additions & 20 deletions triggers/runner/src/main/scala/com/daml/trigger/Runner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ object TriggerIds {
}
}

case class AnyContractId(templateId: Identifier, contractId: String)

object Converter {
// Helper to make constructing an SRecord more convenient
private def record(ty: Identifier, fields: (String, SValue)*): SValue = {
Expand Down Expand Up @@ -177,13 +179,24 @@ object Converter {
("name", SText(id.entityName)))
}

private def fromAnyContractId(
triggerIds: TriggerIds,
templateId: value.Identifier,
contractId: String): SValue = {
val contractIdTy = triggerIds.getId("AnyContractId")
record(
contractIdTy,
("templateId", fromIdentifier(triggerIds, templateId)),
("contractId", SText(contractId))
)
}

private def fromArchivedEvent(triggerIds: TriggerIds, archived: ArchivedEvent): SValue = {
val archivedTy = triggerIds.getId("Archived")
record(
archivedTy,
("eventId", SText(archived.eventId)),
("contractId", SText(archived.contractId)),
("templateId", fromIdentifier(triggerIds, archived.getTemplateId))
("contractId", fromAnyContractId(triggerIds, archived.getTemplateId, archived.contractId))
)
}

Expand All @@ -192,8 +205,7 @@ object Converter {
record(
createdTy,
("eventId", SText(created.eventId)),
("contractId", SText(created.contractId)),
("templateId", fromIdentifier(triggerIds, created.getTemplateId))
("contractId", fromAnyContractId(triggerIds, created.getTemplateId, created.contractId))
)
}

Expand Down Expand Up @@ -240,26 +252,56 @@ object Converter {
}
}

private def toTemplateId(triggerIds: TriggerIds, v: SValue): Either[String, Identifier] = {
private def toIdentifier(v: SValue): Either[String, Identifier] = {
v match {
case SRecord(_, _, vals) => {
assert(vals.size == 3)
for {
packageId <- toText(vals.get(0)).flatMap(PackageId.fromString)
moduleName <- toText(vals.get(1)).flatMap(DottedName.fromString)
entityName <- toText(vals.get(2)).flatMap(DottedName.fromString)
} yield Identifier(packageId, QualifiedName(moduleName, entityName))
}
case _ => Left(s"Expected Identifier but got $v")
}
}

private def extractTemplateId(v: SValue): Either[String, Identifier] = {
v match {
case SRecord(templateId, _, _) => Right(templateId)
case _ => Left(s"Expected contract value but got $v")
}
}

private def toAnyContractId(v: SValue): Either[String, AnyContractId] = {
v match {
case SRecord(_, _, vals) => {
assert(vals.size == 2)
for {
moduleName <- toText(vals.get(0)).flatMap(DottedName.fromString)
entityName <- toText(vals.get(1)).flatMap(DottedName.fromString)
} yield Identifier(triggerIds.mainPackageId, QualifiedName(moduleName, entityName))
templateId <- toIdentifier(vals.get(0))
contractId <- toText(vals.get(1))
} yield AnyContractId(templateId, contractId)
}
case _ => Left(s"Expected TemplateId but got $v")
case _ => Left(s"Expected AnyContractId but got $v")
}
}

private def extractChoiceName(v: SValue): Either[String, String] = {
v match {
case SRecord(ty, _, _) => {
Right(ty.qualifiedName.name.toString)
}
case _ => Left(s"Expected choice value but got $v")
}
}

private def toCreate(triggerIds: TriggerIds, v: SValue): Either[String, CreateCommand] = {
v match {
case SRecord(_, _, vals) => {
assert(vals.size == 2)
assert(vals.size == 1)
for {
templateId <- toTemplateId(triggerIds, vals.get(0))
templateArg <- toLedgerRecord(vals.get(1))
templateId <- extractTemplateId(vals.get(0))
templateArg <- toLedgerRecord(vals.get(0))
} yield CreateCommand(Some(toApiIdentifier(templateId)), Some(templateArg))
}
case _ => Left(s"Expected CreateCommand but got $v")
Expand All @@ -269,18 +311,18 @@ object Converter {
private def toExercise(triggerIds: TriggerIds, v: SValue): Either[String, ExerciseCommand] = {
v match {
case SRecord(_, _, vals) => {
assert(vals.size == 4)
assert(vals.size == 2)
for {
templateId <- toTemplateId(triggerIds, vals.get(0))
contractId <- toText(vals.get(1))
choiceName <- toText(vals.get(2))
choiceArg <- toLedgerValue(vals.get(2))
} yield
anyContractId <- toAnyContractId(vals.get(0))
choiceName <- extractChoiceName(vals.get(1))
choiceArg <- toLedgerValue(vals.get(1))
} yield {
ExerciseCommand(
Some(toApiIdentifier(templateId)),
contractId,
Some(toApiIdentifier(anyContractId.templateId)),
anyContractId.contractId,
choiceName,
Some(choiceArg))
}
}
case _ => Left(s"Expected ExerciseCommand but got $v")
}
Expand Down
29 changes: 21 additions & 8 deletions triggers/tests/daml/ACS.daml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ initState : Party -> ActiveContracts -> TriggerState
initState party (ActiveContracts events) = TriggerState (foldl updateAcs TM.empty events) 0 party
where
updateAcs : TextMap Identifier -> Created -> TextMap Identifier
updateAcs acs (Created _ cId tId)
| tId.entityName == "Asset" = TM.insert cId tId acs
updateAcs acs (Created _ cId)
| cId.templateId.entityName == "Asset" = TM.insert cId.contractId cId.templateId acs
| otherwise = acs

-- | This is a very silly trigger for testing purposes:
Expand All @@ -43,12 +43,15 @@ test = Trigger
where
updateEvent : ([Command], TextMap Identifier) -> Event -> ([Command], TextMap Identifier)
updateEvent (cmds, acs) ev = case ev of
CreatedEvent (Created _ cId tId)
| tId.entityName == "Asset" ->
let createMirror : Command = createCmd (TemplateId "ACS" "AssetMirror") (AssetMirror { issuer = party })
in (createMirror :: cmds, TM.insert cId tId acs)
ArchivedEvent (Archived _ cId tId)
| tId.entityName == "Asset" -> (cmds, TM.delete cId acs)
CreatedEvent (Created _ cId)
| cId.templateId.entityName == "Asset" ->
let proposeMirror : Command = createCmd (AssetMirrorProposal { issuer = party })
in (proposeMirror :: cmds, TM.insert cId.contractId cId.templateId acs)
| cId.templateId.entityName == "AssetMirrorProposal" ->
let accept : Command = exerciseCmd @AssetMirrorProposal cId Accept
in (accept :: cmds, acs)
ArchivedEvent (Archived _ cId)
| cId.templateId.entityName == "Asset" -> (cmds, TM.delete cId.contractId acs)
_ -> (cmds, acs)

template Asset
Expand All @@ -62,3 +65,13 @@ template AssetMirror
issuer : Party
where
signatory issuer

template AssetMirrorProposal
with
issuer : Party
where
signatory issuer

controller issuer can
Accept : ContractId AssetMirror
do create AssetMirror { issuer = issuer }
Original file line number Diff line number Diff line change
Expand Up @@ -292,14 +292,14 @@ object AcsMain {

try {

test(NumTransactions(2), (client, party) => {
test(NumTransactions(3), (client, party) => {
for {
contractId <- create(client, party, "1.0")
} yield (Set(contractId), ActiveAssetMirrors(1))
})

test(
NumTransactions(4),
NumTransactions(6),
(client, party) => {
for {
contractId1 <- create(client, party, "2.0")
Expand All @@ -309,7 +309,7 @@ object AcsMain {
)

test(
NumTransactions(6),
NumTransactions(8),
(client, party) => {
for {
contractId1 <- create(client, party, "3.0")
Expand Down

0 comments on commit df7262e

Please sign in to comment.