mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 09:17:43 +03:00
[Trigger] update Created with interface (#15299)
CHANGELOG_BEGIN CHANGELOG_END
This commit is contained in:
parent
1a4ef5b238
commit
15dd81b524
@ -148,7 +148,8 @@ lookupTpl cid acs = do
|
||||
-- | HIDE
|
||||
applyEvent : Event -> ACS -> ACS
|
||||
applyEvent ev acs = case ev of
|
||||
CreatedEvent (Created _ cid tpl) -> insertTpl cid tpl acs
|
||||
CreatedEvent (Created _ cid (Some tpl) _) -> insertTpl cid tpl acs
|
||||
CreatedEvent _ -> acs
|
||||
ArchivedEvent (Archived _ cid) -> deleteTpl cid acs
|
||||
|
||||
-- | HIDE
|
||||
|
@ -95,6 +95,15 @@ data Transaction = Transaction
|
||||
, events : [Event]
|
||||
}
|
||||
|
||||
-- TODO: https://github.com/digital-asset/daml/issues/14830
|
||||
-- replace by DA.Internal.Any.AnyView.AnyView once it is introduced as stable package
|
||||
type AnyView = ()
|
||||
|
||||
data InterfaceView = InterfaceView {
|
||||
interfaceTypeRep : TemplateTypeRep,
|
||||
anyView: Optional AnyView
|
||||
}
|
||||
|
||||
-- | An event in a transaction.
|
||||
-- This definition should be kept consistent with the object `EventVariant` defined in
|
||||
-- triggers/runner/src/main/scala/com/digitalasset/daml/lf/engine/trigger/Converter.scala
|
||||
@ -106,15 +115,17 @@ data Event
|
||||
data Created = Created
|
||||
{ eventId : EventId
|
||||
, contractId : AnyContractId
|
||||
, argument : AnyTemplate
|
||||
, argument : Optional AnyTemplate
|
||||
, views : [InterfaceView]
|
||||
}
|
||||
|
||||
-- | Check if a `Created` event corresponds to the given template.
|
||||
fromCreated : Template t => Created -> Optional (EventId, ContractId t, t)
|
||||
fromCreated Created {eventId, contractId, argument}
|
||||
| Some contractId' <- fromAnyContractId contractId
|
||||
, Some argument' <- fromAnyTemplate argument
|
||||
= Some (eventId, contractId', argument')
|
||||
, Some argument' <- argument
|
||||
, Some argument'' <- fromAnyTemplate argument'
|
||||
= Some (eventId, contractId', argument'')
|
||||
| otherwise
|
||||
= None
|
||||
|
||||
|
@ -6,6 +6,8 @@ package engine
|
||||
package trigger
|
||||
|
||||
import scalaz.std.either._
|
||||
import scalaz.std.option._
|
||||
import scalaz.std.list._
|
||||
import scalaz.syntax.traverse._
|
||||
import com.daml.lf.data.{FrontStack, ImmArray}
|
||||
import com.daml.lf.data.Ref._
|
||||
@ -21,7 +23,7 @@ import com.daml.ledger.api.v1.commands.{
|
||||
ExerciseCommand,
|
||||
}
|
||||
import com.daml.ledger.api.v1.completion.Completion
|
||||
import com.daml.ledger.api.v1.event.{ArchivedEvent, CreatedEvent, Event}
|
||||
import com.daml.ledger.api.v1.event.{ArchivedEvent, CreatedEvent, Event, InterfaceView}
|
||||
import com.daml.ledger.api.v1.transaction.Transaction
|
||||
import com.daml.ledger.api.v1.value
|
||||
import com.daml.ledger.api.validation.NoLoggingValueValidator
|
||||
@ -36,7 +38,10 @@ import com.daml.platform.participant.util.LfEngineToApi.{
|
||||
import scala.concurrent.duration.{FiniteDuration, MICROSECONDS}
|
||||
|
||||
// Convert from a Ledger API transaction to an SValue corresponding to a Message from the Daml.Trigger module
|
||||
final class Converter(compiledPackages: CompiledPackages, triggerIds: TriggerIds) {
|
||||
final class Converter(
|
||||
compiledPackages: CompiledPackages,
|
||||
triggerDef: TriggerDefinition,
|
||||
) {
|
||||
|
||||
import Converter._
|
||||
import com.daml.script.converter.Converter._, Implicits._
|
||||
@ -52,8 +57,13 @@ final class Converter(compiledPackages: CompiledPackages, triggerIds: TriggerIds
|
||||
private[this] def translateValue(ty: Type, value: Value): Either[String, SValue] =
|
||||
valueTranslator.translateValue(ty, value).left.map(res => s"Failure to translate value: $res")
|
||||
|
||||
private[this] val anyTemplateTyCon = DA.Internal.Any.assertIdentifier("AnyTemplate")
|
||||
private[this] val templateTypeRepTyCon = DA.Internal.Any.assertIdentifier("TemplateTypeRep")
|
||||
private[this] val anyTemplateTyCon = DA.Internal.Any.assertIdentifier("AnyTemplate")
|
||||
// TODO: https://github.com/digital-asset/daml/issues/14830
|
||||
// replace by DA.Internal.Any.AnyView.AnyView once it is introduced as stable package
|
||||
private[this] val anyViewTyCon = DA.Internal.Any.assertIdentifier("AnyView")
|
||||
|
||||
private[this] def triggerIds = triggerDef.triggerIds
|
||||
|
||||
private[this] val activeContractsTy = triggerIds.damlTriggerLowLevel("ActiveContracts")
|
||||
private[this] val anyContractIdTy = triggerIds.damlTriggerLowLevel("AnyContractId")
|
||||
@ -130,25 +140,66 @@ final class Converter(compiledPackages: CompiledPackages, triggerIds: TriggerIds
|
||||
"contractId" -> fromAnyContractId(archived.getTemplateId, archived.contractId),
|
||||
)
|
||||
|
||||
private[this] def fromCreatedEvent(
|
||||
private[this] def fromRecord(typ: Type, record: value.Record): Either[String, SValue] =
|
||||
for {
|
||||
record <- validateRecord(record)
|
||||
tmplPayload <- translateValue(typ, record)
|
||||
} yield tmplPayload
|
||||
|
||||
private[this] def fromAnyTemplate(typ: Type, value: SValue) =
|
||||
record(anyTemplateTyCon, "getAnyTemplate" -> SAny(typ, value))
|
||||
|
||||
private[this] def fromV20CreatedEvent(
|
||||
created: CreatedEvent
|
||||
): Either[String, SValue] =
|
||||
for {
|
||||
tmplId <- fromIdentifier(created.getTemplateId)
|
||||
createArguments <- validateRecord(created.getCreateArguments)
|
||||
tmplPayload <- translateValue(TTyCon(tmplId), createArguments)
|
||||
tmplType = TTyCon(tmplId)
|
||||
tmplPayload <- fromRecord(tmplType, created.getCreateArguments)
|
||||
} yield {
|
||||
record(
|
||||
createdTy,
|
||||
"eventId" -> fromEventId(created.eventId),
|
||||
"contractId" -> fromAnyContractId(created.getTemplateId, created.contractId),
|
||||
"argument" -> record(
|
||||
anyTemplateTyCon,
|
||||
"getAnyTemplate" -> SAny(TTyCon(tmplId), tmplPayload),
|
||||
),
|
||||
"argument" -> fromAnyTemplate(tmplType, tmplPayload),
|
||||
)
|
||||
}
|
||||
|
||||
private[this] def fromAnyView(typ: Type, value: SValue) =
|
||||
record(anyViewTyCon, "getAnyView" -> SAny(typ, value))
|
||||
|
||||
private[this] def fromInterfaceView(view: InterfaceView): Either[String, SOptional] =
|
||||
for {
|
||||
ifaceId <- fromIdentifier(view.getInterfaceId)
|
||||
iface <- compiledPackages.pkgInterface.lookupInterface(ifaceId).left.map(_.pretty)
|
||||
viewType = iface.view
|
||||
viewValue <- view.viewValue.traverseU(fromRecord(viewType, _))
|
||||
} yield SOptional(viewValue.map(fromAnyView(viewType, _)))
|
||||
|
||||
private[this] def fromV25CreatedEvent(
|
||||
created: CreatedEvent
|
||||
): Either[String, SValue] =
|
||||
for {
|
||||
tmplId <- fromIdentifier(created.getTemplateId)
|
||||
tmplType = TTyCon(tmplId)
|
||||
tmplPayload <- created.createArguments.traverseU(fromRecord(tmplType, _))
|
||||
views <- created.interfaceViews.toList.traverseU(fromInterfaceView)
|
||||
} yield {
|
||||
record(
|
||||
createdTy,
|
||||
"eventId" -> fromEventId(created.eventId),
|
||||
"contractId" -> fromAnyContractId(created.getTemplateId, created.contractId),
|
||||
"argument" -> SOptional(tmplPayload.map(fromAnyTemplate(tmplType, _))),
|
||||
"views" -> SList(views.to(FrontStack)),
|
||||
)
|
||||
}
|
||||
|
||||
private[this] val fromCreatedEvent: CreatedEvent => Either[String, SValue] =
|
||||
triggerDef.version match {
|
||||
case Trigger.Version.`2.0` => fromV20CreatedEvent
|
||||
case Trigger.Version.`2.5` => fromV25CreatedEvent
|
||||
}
|
||||
|
||||
private def fromEvent(ev: Event): Either[String, SValue] =
|
||||
ev.event match {
|
||||
case Event.Event.Archived(archivedEvent) =>
|
||||
@ -427,6 +478,7 @@ object Converter {
|
||||
|
||||
private final case class AnyContractId(templateId: Identifier, contractId: ContractId)
|
||||
private final case class AnyTemplate(ty: Identifier, arg: SValue)
|
||||
|
||||
private final case class AnyChoice(name: ChoiceName, arg: SValue)
|
||||
private final case class AnyContractKey(key: SValue)
|
||||
|
||||
|
@ -222,7 +222,7 @@ object Trigger extends StrictLogging {
|
||||
for {
|
||||
triggerDef <- detectTriggerDefinition(compiledPackages.pkgInterface, triggerId)
|
||||
hasReadAs <- detectHasReadAs(compiledPackages.pkgInterface, triggerDef.triggerIds)
|
||||
converter = new Converter(compiledPackages, triggerDef.triggerIds)
|
||||
converter = new Converter(compiledPackages, triggerDef)
|
||||
filter <- getTriggerFilter(compiledPackages, compiler, converter, triggerDef)
|
||||
heartbeat <- getTriggerHeartbeat(compiledPackages, compiler, converter, triggerDef)
|
||||
} yield Trigger(triggerDef, filter, heartbeat, hasReadAs)
|
||||
@ -354,14 +354,14 @@ class Runner(
|
||||
import Runner.{SeenMsgs, alterF}
|
||||
|
||||
// Compiles LF expressions into Speedy expressions.
|
||||
private val compiler: Compiler = compiledPackages.compiler
|
||||
private val compiler = compiledPackages.compiler
|
||||
// Converts between various objects and SValues.
|
||||
private val converter: Converter = new Converter(compiledPackages, trigger.defn.triggerIds)
|
||||
private val converter: Converter = new Converter(compiledPackages, trigger.defn)
|
||||
// These are the command IDs used on the ledger API to submit commands for
|
||||
// this trigger for which we are awaiting either a completion or transaction
|
||||
// message, or both.
|
||||
private[this] var pendingCommandIds: Map[UUID, SeenMsgs] = Map.empty
|
||||
private val transactionFilter: TransactionFilter =
|
||||
private[this] var pendingCommandIds = Map.empty[UUID, SeenMsgs]
|
||||
private val transactionFilter =
|
||||
TransactionFilter(parties.readers.map(p => (p.unwrap, trigger.filters)).toMap)
|
||||
|
||||
private[this] def logger = ContextualizedLogger get getClass
|
||||
|
@ -154,7 +154,6 @@ da_scala_library(
|
||||
"//daml-lf/engine",
|
||||
"//daml-lf/interpreter",
|
||||
"//daml-lf/language",
|
||||
"//daml-script/converter",
|
||||
"//language-support/scala/bindings",
|
||||
"//language-support/scala/bindings-akka",
|
||||
"//ledger-api/rs-grpc-bridge",
|
||||
|
@ -13,7 +13,6 @@ import org.scalatest._
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AsyncWordSpec
|
||||
import com.daml.lf.engine.trigger.TriggerMsg
|
||||
import com.daml.script.converter.ConverterException
|
||||
|
||||
class DevOnly
|
||||
extends AsyncWordSpec
|
||||
@ -107,10 +106,9 @@ class DevOnly
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: modify Converter so that it may parse interface and view related transaction messages
|
||||
"fail with interface registration and implementing template not registered" in {
|
||||
"succeed with interface registration and implementing template not registered" in {
|
||||
val triggerId = QualifiedName.assertFromString("InterfaceTriggers:triggerWithRegistration")
|
||||
val result = for {
|
||||
for {
|
||||
client <- ledgerClient()
|
||||
party <- allocateParty(client)
|
||||
runner = getRunner(client, triggerId, party)
|
||||
@ -163,10 +161,10 @@ class DevOnly
|
||||
// 1 for create of template A
|
||||
// 1 for create of template B, via interface I
|
||||
_ <- runner.runWithACS(acs, offset, msgFlow = Flow[TriggerMsg].take(2))._2
|
||||
} yield fail()
|
||||
|
||||
result.recoverWith { case exn: ConverterException =>
|
||||
exn.getMessage should startWith("Failure to translate value: TypeMismatch")
|
||||
acs <- queryACS(client, party)
|
||||
} yield {
|
||||
acs(templateA) should have length 1
|
||||
acs(templateB) should have length 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user