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