mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 01:07:18 +03:00
Add separate commands for create/fetch/exercise by template/interface. (#11724)
* Add separate commands wrt by template/interface Resolves #11674 and #11675 changelog_begin changelog_end * remove unnecessary commands
This commit is contained in:
parent
7e4acf97fc
commit
c2d4ea4ef1
@ -33,34 +33,82 @@ private[lf] final class CommandPreprocessor(
|
||||
templateId: Ref.Identifier,
|
||||
argument: Value,
|
||||
): speedy.Command.Create = {
|
||||
discard(handleLookup(interface.lookupTemplate(templateId)))
|
||||
val arg = valueTranslator.unsafeTranslateValue(Ast.TTyCon(templateId), argument)
|
||||
speedy.Command.Create(templateId, arg)
|
||||
}
|
||||
|
||||
@throws[Error.Preprocessing.Error]
|
||||
def unsafePreprocessCreateByInterface(
|
||||
interfaceId: Ref.Identifier,
|
||||
templateId: Ref.Identifier,
|
||||
argument: Value,
|
||||
): speedy.Command.CreateByInterface = {
|
||||
discard(handleLookup(interface.lookupTemplateImplements(templateId, interfaceId)))
|
||||
val arg = valueTranslator.unsafeTranslateValue(Ast.TTyCon(templateId), argument)
|
||||
speedy.Command.CreateByInterface(interfaceId, templateId, arg)
|
||||
}
|
||||
|
||||
def unsafePreprocessExercise(
|
||||
identifier: Ref.Identifier,
|
||||
contractId: Value.ContractId,
|
||||
choiceId: Ref.ChoiceName,
|
||||
argument: Value,
|
||||
): speedy.Command.Exercise = {
|
||||
): speedy.Command = {
|
||||
import language.PackageInterface.ChoiceInfo
|
||||
|
||||
val cid = valueTranslator.unsafeTranslateCid(contractId)
|
||||
def command(id: Ref.Identifier, choice: Ast.TemplateChoiceSignature) = {
|
||||
def command(
|
||||
choice: Ast.TemplateChoiceSignature,
|
||||
toSpeedyCommand: speedy.SValue => speedy.Command,
|
||||
) = {
|
||||
val arg = valueTranslator.unsafeTranslateValue(choice.argBinder._2, argument)
|
||||
speedy.Command.Exercise(id, cid, choiceId, arg)
|
||||
toSpeedyCommand(arg)
|
||||
}
|
||||
|
||||
handleLookup(interface.lookupChoice(identifier, choiceId)) match {
|
||||
case ChoiceInfo.Template(choice) =>
|
||||
command(identifier, choice)
|
||||
command(choice, speedy.Command.Exercise(identifier, cid, choiceId, _))
|
||||
case ChoiceInfo.Interface(choice) =>
|
||||
command(identifier, choice)
|
||||
command(choice, speedy.Command.ExerciseInterface(identifier, cid, choiceId, _))
|
||||
case ChoiceInfo.Inherited(ifaceId, choice) =>
|
||||
command(ifaceId, choice)
|
||||
command(choice, speedy.Command.ExerciseByInterface(ifaceId, identifier, cid, choiceId, _))
|
||||
}
|
||||
}
|
||||
|
||||
/* Like unsafePreprocessExercise, but expects the choice to come from the template specifically, not inherited from an interface. */
|
||||
@throws[Error.Preprocessing.Error]
|
||||
def unsafePreprocessExerciseTemplate(
|
||||
templateId: Ref.Identifier,
|
||||
contractId: Value.ContractId,
|
||||
choiceId: Ref.ChoiceName,
|
||||
argument: Value,
|
||||
): speedy.Command.Exercise = {
|
||||
val cid = valueTranslator.unsafeTranslateCid(contractId)
|
||||
val choiceArgType = handleLookup(
|
||||
interface.lookupTemplateChoice(templateId, choiceId)
|
||||
).argBinder._2
|
||||
val arg = valueTranslator.unsafeTranslateValue(choiceArgType, argument)
|
||||
speedy.Command.Exercise(templateId, cid, choiceId, arg)
|
||||
}
|
||||
|
||||
/* Like unsafePreprocessExercise, but expects the choice to be inherited from the given interface. */
|
||||
@throws[Error.Preprocessing.Error]
|
||||
def unsafePreprocessExerciseByInterface(
|
||||
interfaceId: Ref.Identifier,
|
||||
templateId: Ref.Identifier,
|
||||
contractId: Value.ContractId,
|
||||
choiceId: Ref.ChoiceName,
|
||||
argument: Value,
|
||||
): speedy.Command.ExerciseByInterface = {
|
||||
val cid = valueTranslator.unsafeTranslateCid(contractId)
|
||||
val choiceArgType = handleLookup(
|
||||
interface.lookupInheritedChoice(interfaceId, templateId, choiceId)
|
||||
).argBinder._2
|
||||
val arg = valueTranslator.unsafeTranslateValue(choiceArgType, argument)
|
||||
speedy.Command.ExerciseByInterface(interfaceId, templateId, cid, choiceId, arg)
|
||||
}
|
||||
|
||||
@throws[Error.Preprocessing.Error]
|
||||
def unsafePreprocessExerciseByKey(
|
||||
templateId: Ref.Identifier,
|
||||
@ -118,8 +166,20 @@ private[lf] final class CommandPreprocessor(
|
||||
cmd match {
|
||||
case command.CreateCommand(templateId, argument) =>
|
||||
unsafePreprocessCreate(templateId, argument)
|
||||
case command.CreateByInterfaceCommand(interfaceId, templateId, argument) =>
|
||||
unsafePreprocessCreateByInterface(interfaceId, templateId, argument)
|
||||
case command.ExerciseCommand(templateId, contractId, choiceId, argument) =>
|
||||
unsafePreprocessExercise(templateId, contractId, choiceId, argument)
|
||||
case command.ExerciseTemplateCommand(templateId, contractId, choiceId, argument) =>
|
||||
unsafePreprocessExerciseTemplate(templateId, contractId, choiceId, argument)
|
||||
case command.ExerciseByInterfaceCommand(
|
||||
interfaceId,
|
||||
templateId,
|
||||
contractId,
|
||||
choiceId,
|
||||
argument,
|
||||
) =>
|
||||
unsafePreprocessExerciseByInterface(interfaceId, templateId, contractId, choiceId, argument)
|
||||
case command.ExerciseByKeyCommand(templateId, contractKey, choiceId, argument) =>
|
||||
unsafePreprocessExerciseByKey(templateId, contractKey, choiceId, argument)
|
||||
case command.CreateAndExerciseCommand(
|
||||
@ -134,12 +194,16 @@ private[lf] final class CommandPreprocessor(
|
||||
choiceId,
|
||||
choiceArgument,
|
||||
)
|
||||
case command.FetchCommand(templateId, coid) =>
|
||||
// TODO https://github.com/digital-asset/daml/issues/10810
|
||||
// -- handle the case where templateId is an interface
|
||||
discard[Ast.TemplateSignature](handleLookup(interface.lookupTemplate(templateId)))
|
||||
case command.FetchCommand(templateId, coid) => {
|
||||
discard(handleLookup(interface.lookupTemplate(templateId)))
|
||||
val cid = valueTranslator.unsafeTranslateCid(coid)
|
||||
speedy.Command.Fetch(templateId, cid)
|
||||
}
|
||||
case command.FetchByInterfaceCommand(interfaceId, templateId, coid) => {
|
||||
discard(handleLookup(interface.lookupTemplateImplements(templateId, interfaceId)))
|
||||
val cid = valueTranslator.unsafeTranslateCid(coid)
|
||||
speedy.Command.FetchByInterface(interfaceId, templateId, cid)
|
||||
}
|
||||
case command.FetchByKeyCommand(templateId, key) =>
|
||||
val ckTtype = handleLookup(interface.lookupTemplateKey(templateId)).typ
|
||||
val sKey = valueTranslator.unsafeTranslateValue(ckTtype, key)
|
||||
|
@ -71,7 +71,16 @@ private[preprocessing] final class TransactionPreprocessor(
|
||||
case Some(node: Node.Action) =>
|
||||
node match {
|
||||
case create: Node.Create =>
|
||||
val cmd = commandPreprocessor.unsafePreprocessCreate(create.templateId, create.arg)
|
||||
val cmd = create.byInterface match {
|
||||
case None =>
|
||||
commandPreprocessor.unsafePreprocessCreate(create.templateId, create.arg)
|
||||
case Some(interfaceId) =>
|
||||
commandPreprocessor.unsafePreprocessCreateByInterface(
|
||||
interfaceId,
|
||||
create.templateId,
|
||||
create.arg,
|
||||
)
|
||||
}
|
||||
acc :+ cmd
|
||||
case exe: Node.Exercise =>
|
||||
val cmd = exe.key match {
|
||||
@ -83,12 +92,23 @@ private[preprocessing] final class TransactionPreprocessor(
|
||||
exe.chosenValue,
|
||||
)
|
||||
case _ =>
|
||||
commandPreprocessor.unsafePreprocessExercise(
|
||||
exe.templateId,
|
||||
exe.targetCoid,
|
||||
exe.choiceId,
|
||||
exe.chosenValue,
|
||||
)
|
||||
exe.byInterface match {
|
||||
case None =>
|
||||
commandPreprocessor.unsafePreprocessExerciseTemplate(
|
||||
exe.templateId,
|
||||
exe.targetCoid,
|
||||
exe.choiceId,
|
||||
exe.chosenValue,
|
||||
)
|
||||
case Some(interfaceId) =>
|
||||
commandPreprocessor.unsafePreprocessExerciseByInterface(
|
||||
interfaceId,
|
||||
exe.templateId,
|
||||
exe.targetCoid,
|
||||
exe.choiceId,
|
||||
exe.chosenValue,
|
||||
)
|
||||
}
|
||||
}
|
||||
acc :+ cmd
|
||||
case _: Node.Fetch =>
|
||||
|
@ -15,11 +15,20 @@ sealed abstract class Command extends Product with Serializable {
|
||||
|
||||
object Command {
|
||||
|
||||
/** Create a template, not by interface */
|
||||
final case class Create(
|
||||
templateId: Identifier,
|
||||
argument: SValue,
|
||||
) extends Command
|
||||
|
||||
/** Create a template, by interface */
|
||||
final case class CreateByInterface(
|
||||
interfaceId: Identifier,
|
||||
templateId: Identifier,
|
||||
argument: SValue,
|
||||
) extends Command
|
||||
|
||||
/** Exercise a template choice, not by interface */
|
||||
final case class Exercise(
|
||||
templateId: Identifier,
|
||||
contractId: SContractId,
|
||||
@ -27,6 +36,30 @@ object Command {
|
||||
argument: SValue,
|
||||
) extends Command
|
||||
|
||||
/** Exercise a template choice, by interface */
|
||||
final case class ExerciseByInterface(
|
||||
interfaceId: Identifier,
|
||||
templateId: Identifier,
|
||||
contractId: SContractId,
|
||||
choiceId: ChoiceName,
|
||||
argument: SValue,
|
||||
) extends Command
|
||||
|
||||
/** Exercise an interface choice. This is used for exercising an interface
|
||||
* on the ledger api, where the template id is unknown.
|
||||
*/
|
||||
final case class ExerciseInterface(
|
||||
interfaceId: Identifier,
|
||||
contractId: SContractId,
|
||||
choiceId: ChoiceName,
|
||||
argument: SValue,
|
||||
) extends Command {
|
||||
// TODO https://github.com/digital-asset/daml/issues/11342
|
||||
// The actual template id isn't known until run time.
|
||||
// The interface id is the best we've got.
|
||||
val templateId = interfaceId
|
||||
}
|
||||
|
||||
final case class ExerciseByKey(
|
||||
templateId: Identifier,
|
||||
contractKey: SValue,
|
||||
@ -34,11 +67,19 @@ object Command {
|
||||
argument: SValue,
|
||||
) extends Command
|
||||
|
||||
/** Fetch a template, not by interface */
|
||||
final case class Fetch(
|
||||
templateId: Identifier,
|
||||
coid: SContractId,
|
||||
) extends Command
|
||||
|
||||
/** Fetch a template, by interface */
|
||||
final case class FetchByInterface(
|
||||
interfaceId: Identifier,
|
||||
templateId: Identifier,
|
||||
coid: SContractId,
|
||||
) extends Command
|
||||
|
||||
final case class FetchByKey(
|
||||
templateId: Identifier,
|
||||
key: SValue,
|
||||
|
@ -1411,12 +1411,24 @@ private[lf] final class Compiler(
|
||||
private[this] def compileCommand(cmd: Command): s.SExpr = cmd match {
|
||||
case Command.Create(templateId, argument) =>
|
||||
t.CreateDefRef(templateId)(s.SEValue(argument))
|
||||
case Command.CreateByInterface(interfaceId, templateId, argument) =>
|
||||
t.CreateByInterfaceDefRef(templateId, interfaceId)(s.SEValue(argument))
|
||||
case Command.Exercise(templateId, contractId, choiceId, argument) =>
|
||||
t.ChoiceDefRef(templateId, choiceId)(s.SEValue(contractId), s.SEValue(argument))
|
||||
case Command.ExerciseByInterface(interfaceId, templateId @ _, contractId, choiceId, argument) =>
|
||||
// TODO https://github.com/digital-asset/daml/issues/11703
|
||||
// Ensure that fetched template has expected templateId.
|
||||
t.ChoiceDefRef(interfaceId, choiceId)(s.SEValue(contractId), s.SEValue(argument))
|
||||
case Command.ExerciseInterface(interfaceId, contractId, choiceId, argument) =>
|
||||
t.ChoiceDefRef(interfaceId, choiceId)(s.SEValue(contractId), s.SEValue(argument))
|
||||
case Command.ExerciseByKey(templateId, contractKey, choiceId, argument) =>
|
||||
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.FetchByKey(templateId, key) =>
|
||||
t.FetchByKeyDefRef(templateId)(s.SEValue(key))
|
||||
case Command.CreateAndExercise(templateId, createArg, choice, choiceArg) =>
|
||||
|
@ -103,6 +103,11 @@ object Reference {
|
||||
override def pretty: String = s"template without contract key $tyCon."
|
||||
}
|
||||
|
||||
final case class TemplateImplements(templateName: TypeConName, ifaceName: TypeConName)
|
||||
extends Reference {
|
||||
override def pretty: String = s"template $templateName implementation of interface $ifaceName"
|
||||
}
|
||||
|
||||
final case class TemplateChoice(tyCon: TypeConName, choiceName: ChoiceName) extends Reference {
|
||||
override def pretty: String = s"choice $choiceName in template $tyCon"
|
||||
}
|
||||
@ -111,6 +116,15 @@ object Reference {
|
||||
override def pretty: String = s"choice $choiceName in interface $tyCon"
|
||||
}
|
||||
|
||||
final case class InheritedChoice(
|
||||
ifaceName: TypeConName,
|
||||
templateName: TypeConName,
|
||||
choiceName: ChoiceName,
|
||||
) extends Reference {
|
||||
override def pretty: String =
|
||||
s"choice $choiceName in template $templateName by interface $ifaceName"
|
||||
}
|
||||
|
||||
final case class TemplateOrInterface(tyCon: TypeConName) extends Reference {
|
||||
override def pretty: String = s"template or interface $tyCon"
|
||||
}
|
||||
|
@ -219,6 +219,23 @@ private[lf] class PackageInterface(signatures: PartialFunction[PackageId, Packag
|
||||
): Either[LookupError, TemplateChoiceSignature] =
|
||||
lookupTemplateChoice(tmpName, chName, Reference.TemplateChoice(tmpName, chName))
|
||||
|
||||
private[this] def lookupTemplateImplements(
|
||||
tmpName: TypeConName,
|
||||
ifaceName: TypeConName,
|
||||
context: => Reference,
|
||||
): Either[LookupError, TemplateImplementsSignature] =
|
||||
lookupTemplate(tmpName, context).flatMap(
|
||||
_.implements
|
||||
.get(ifaceName)
|
||||
.toRight(LookupError(Reference.TemplateImplements(tmpName, ifaceName), context))
|
||||
)
|
||||
|
||||
def lookupTemplateImplements(
|
||||
tmpName: TypeConName,
|
||||
ifaceName: TypeConName,
|
||||
): Either[LookupError, TemplateImplementsSignature] =
|
||||
lookupTemplateImplements(tmpName, ifaceName, Reference.TemplateImplements(tmpName, ifaceName))
|
||||
|
||||
private[this] def lookupInterfaceChoice(
|
||||
ifaceName: TypeConName,
|
||||
chName: ChoiceName,
|
||||
@ -236,6 +253,35 @@ private[lf] class PackageInterface(signatures: PartialFunction[PackageId, Packag
|
||||
): Either[LookupError, TemplateChoiceSignature] =
|
||||
lookupInterfaceChoice(ifaceName, chName, Reference.InterfaceChoice(ifaceName, chName))
|
||||
|
||||
/* Looks up a choice inherited by a template through a specific interface.
|
||||
* Fails if the template does not implement the interface, and/or the choice is not defined in this interface. */
|
||||
private[lf] def lookupInheritedChoice(
|
||||
ifaceName: TypeConName,
|
||||
tmpName: TypeConName,
|
||||
chName: ChoiceName,
|
||||
context: => Reference,
|
||||
): Either[LookupError, TemplateChoiceSignature] =
|
||||
lookupTemplate(tmpName, context).flatMap(template =>
|
||||
template.inheritedChoices.get(chName) match {
|
||||
case Some(gotIfaceName) if gotIfaceName == ifaceName =>
|
||||
lookupInterfaceChoice(ifaceName, chName, context)
|
||||
case _ =>
|
||||
Left(LookupError(Reference.InheritedChoice(ifaceName, tmpName, chName), context))
|
||||
}
|
||||
)
|
||||
|
||||
private[lf] def lookupInheritedChoice(
|
||||
ifaceName: TypeConName,
|
||||
tmpName: TypeConName,
|
||||
chName: ChoiceName,
|
||||
): Either[LookupError, TemplateChoiceSignature] =
|
||||
lookupInheritedChoice(
|
||||
ifaceName,
|
||||
tmpName,
|
||||
chName,
|
||||
Reference.InheritedChoice(ifaceName, tmpName, chName),
|
||||
)
|
||||
|
||||
private[lf] def lookupTemplateOrInterface(
|
||||
identier: TypeConName,
|
||||
context: => Reference,
|
||||
|
@ -27,6 +27,13 @@ sealed abstract class ApiCommand extends Command
|
||||
*/
|
||||
final case class CreateCommand(templateId: Identifier, argument: Value) extends ApiCommand
|
||||
|
||||
/** Create template contract, by interface */
|
||||
final case class CreateByInterfaceCommand(
|
||||
interfaceId: Identifier,
|
||||
templateId: Identifier,
|
||||
argument: Value,
|
||||
) extends Command
|
||||
|
||||
/** Command for exercising a choice on an existing contract
|
||||
*
|
||||
* @param templateId identifier of the original contract
|
||||
@ -41,6 +48,23 @@ final case class ExerciseCommand(
|
||||
argument: Value,
|
||||
) extends ApiCommand
|
||||
|
||||
/** Exercise a template choice, not by interface. */
|
||||
final case class ExerciseTemplateCommand(
|
||||
templateId: Identifier,
|
||||
contractId: Value.ContractId,
|
||||
choiceId: ChoiceName,
|
||||
argument: Value,
|
||||
) extends Command
|
||||
|
||||
/** Exercise a template choice, by interface. */
|
||||
final case class ExerciseByInterfaceCommand(
|
||||
interfaceId: Identifier,
|
||||
templateId: Identifier,
|
||||
contractId: Value.ContractId,
|
||||
choiceId: ChoiceName,
|
||||
argument: Value,
|
||||
) extends Command
|
||||
|
||||
/** Command for exercising a choice on an existing contract specified by its key
|
||||
*
|
||||
* @param templateId identifier of the original contract
|
||||
@ -70,11 +94,19 @@ final case class CreateAndExerciseCommand(
|
||||
choiceArgument: Value,
|
||||
) extends ApiCommand
|
||||
|
||||
/** Fetch a template, not by interface */
|
||||
final case class FetchCommand(
|
||||
templateId: Identifier,
|
||||
coid: Value.ContractId,
|
||||
) extends Command
|
||||
|
||||
/** Fetch a template, by interface */
|
||||
final case class FetchByInterfaceCommand(
|
||||
interfaceId: Identifier,
|
||||
templateId: Identifier,
|
||||
coid: Value.ContractId,
|
||||
) extends Command
|
||||
|
||||
final case class FetchByKeyCommand(
|
||||
templateId: Identifier,
|
||||
key: Value,
|
||||
|
Loading…
Reference in New Issue
Block a user