clean up the static types of LF transaction nodes in Engine (#206)

* introduce WithTxValue aliases for common GenNode type applications

* use WithTxValue aliases in more places

* more WithTxValue factoring
This commit is contained in:
Stephen Compall 2019-04-10 20:42:16 +07:00 committed by GitHub
parent f564fc3e90
commit 3974ebe4b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 45 additions and 38 deletions

View File

@ -127,9 +127,8 @@ object Blinding {
go(filteredRoots :+ root, remainingRoots)
} else {
tx.nodes(root) match {
case _: NodeFetch[Cid] => go(filteredRoots, remainingRoots)
case _: NodeCreate[Cid, Val] => go(filteredRoots, remainingRoots)
case _: NodeLookupByKey[Cid, Val] => go(filteredRoots, remainingRoots)
case _: NodeFetch[Cid] | _: NodeCreate[Cid, Val] | _: NodeLookupByKey[Cid, Val] =>
go(filteredRoots, remainingRoots)
case ne: NodeExercises[Nid, Cid, Val] =>
go(filteredRoots, ne.children ++: remainingRoots)
}

View File

@ -196,11 +196,11 @@ final class Engine {
// but the input has non-empty location, so when not given both locations we won't compare
// this is not part of the generic utilities because it only valid in this context
def nodeEqualityWithoutLocation(
n1: GenNode[Tx.NodeId, AbsoluteContractId, Tx.Value[AbsoluteContractId]],
n2: GenNode[Tx.NodeId, AbsoluteContractId, Tx.Value[AbsoluteContractId]]) = {
n1: GenNode.WithTxValue[Tx.NodeId, AbsoluteContractId],
n2: GenNode.WithTxValue[Tx.NodeId, AbsoluteContractId]) = {
def removeLocation(n: GenNode[Tx.NodeId, AbsoluteContractId, Tx.Value[AbsoluteContractId]])
: GenNode[Tx.NodeId, AbsoluteContractId, Tx.Value[AbsoluteContractId]] = {
def removeLocation(n: GenNode.WithTxValue[Tx.NodeId, AbsoluteContractId])
: GenNode.WithTxValue[Tx.NodeId, AbsoluteContractId] = {
n match {
case c: NodeCreate[_, _] => c.copy(optLocation = None)
case e: NodeExercises[_, _, _] => e.copy(optLocation = None)
@ -257,7 +257,7 @@ final class Engine {
// Translate a GenNode into an expression re-interpretable by the interpreter
private[this] def translateNode[Cid <: ContractId](commandTranslation: CommandTranslation)(
node: GenNode[Transaction.NodeId, Cid, Transaction.Value[Cid]]): Result[(Type, Expr)] = {
node: GenNode.WithTxValue[Transaction.NodeId, Cid]): Result[(Type, Expr)] = {
node match {
case NodeCreate(coid @ _, coinst, optLoc @ _, sigs @ _, stks @ _, key @ _) =>

View File

@ -97,7 +97,7 @@ object Ledger {
* words, all AbsoluteContractIds are also NodeIds (but not the
* reverse, node ids might be exercises)
*/
type Node = GenNode[NodeId, AbsoluteContractId, Transaction.Value[AbsoluteContractId]]
type Node = GenNode.WithTxValue[NodeId, AbsoluteContractId]
/** Feature flags that apply across an entire ledger.
* They must be the same across all packages in a single ledger. */
@ -228,7 +228,7 @@ object Ledger {
*/
def translateNode(commitPrefix: String, node: Transaction.Node): Node = {
node match {
case nc: NodeCreate[ContractId, Transaction.Value[ContractId]] =>
case nc: NodeCreate.WithTxValue[ContractId] =>
NodeCreate[AbsoluteContractId, Transaction.Value[AbsoluteContractId]](
coid = contractIdToAbsoluteContractId(commitPrefix, nc.coid),
coinst = nc.coinst.copy(arg = makeAbsolute(commitPrefix, nc.coinst.arg)),
@ -246,7 +246,7 @@ object Ledger {
signatories = nf.signatories,
stakeholders = nf.stakeholders
)
case nex: NodeExercises[Transaction.NodeId, ContractId, Transaction.Value[ContractId]] =>
case nex: NodeExercises.WithTxValue[Transaction.NodeId, ContractId] =>
NodeExercises[NodeId, AbsoluteContractId, Transaction.Value[AbsoluteContractId]](
targetCoid = contractIdToAbsoluteContractId(commitPrefix, nex.targetCoid),
templateId = nex.templateId,
@ -260,8 +260,8 @@ object Ledger {
controllers = nex.controllers,
children = nex.children.map(NodeId(commitPrefix, _))
)
case nlbk: NodeLookupByKey[ContractId, Transaction.Value[ContractId]] =>
NodeLookupByKey[AbsoluteContractId, Transaction.Value[AbsoluteContractId]](
case nlbk: NodeLookupByKey.WithTxValue[ContractId] =>
NodeLookupByKey(
templateId = nlbk.templateId,
optLocation = nlbk.optLocation,
key = nlbk.key.mapValue(makeAbsolute(commitPrefix, _)),
@ -429,7 +429,7 @@ object Ledger {
case None => LookupContractNotFound(coid)
case Some(info) =>
info.node match {
case create: NodeCreate[AbsoluteContractId, Transaction.Value[AbsoluteContractId]] =>
case create: NodeCreate.WithTxValue[AbsoluteContractId] =>
if (info.effectiveAt.compareTo(effectiveAt) > 0)
LookupContractNotEffective(coid, create.coinst.template, info.effectiveAt)
else if (info.consumedBy.nonEmpty)
@ -445,11 +445,7 @@ object Ledger {
else
LookupOk(coid, create.coinst)
case _: NodeExercises[_, _, _] =>
LookupContractNotFound(coid)
case _: NodeFetch[_] =>
LookupContractNotFound(coid)
case _: NodeLookupByKey[_, _] =>
case _: NodeExercises[_, _, _] | _: NodeFetch[_] | _: NodeLookupByKey[_, _] =>
LookupContractNotFound(coid)
}
}
@ -642,7 +638,7 @@ object Ledger {
def authorizeCreate(
nodeId: Transaction.NodeId,
create: NodeCreate[ContractId, Transaction.Value[ContractId]],
create: NodeCreate.WithTxValue[ContractId],
signatories: Set[Party],
authorization: Authorization): EnrichState =
authorization.fold(this)(
@ -664,7 +660,7 @@ object Ledger {
def authorizeExercise(
nodeId: Transaction.NodeId,
ex: NodeExercises[Transaction.NodeId, ContractId, Transaction.Value[ContractId]],
ex: NodeExercises.WithTxValue[Transaction.NodeId, ContractId],
actingParties: Set[Party],
authorization: Authorization,
controllers: Set[Party]): EnrichState = {
@ -793,7 +789,7 @@ object Ledger {
*/
def authorizeLookupByKey(
nodeId: Transaction.NodeId,
lbk: NodeLookupByKey[ContractId, Transaction.Value[ContractId]],
lbk: NodeLookupByKey.WithTxValue[ContractId],
authorization: Authorization): EnrichState = {
authorization.fold(this) { authorizers =>
this.authorize(
@ -859,7 +855,7 @@ object Ledger {
tr.nodes
.getOrElse(nodeId, crash(s"enrichNode - precondition violated: node $nodeId not present"))
node match {
case create: NodeCreate[ContractId, Transaction.Value[ContractId]] =>
case create: NodeCreate.WithTxValue[ContractId] =>
// ------------------------------------------------------------------
// witnesses : stakeholders union witnesses of parent exercise
// node
@ -902,7 +898,7 @@ object Ledger {
authorization = authorization)
else state1
case ex: NodeExercises[Transaction.NodeId, ContractId, Transaction.Value[ContractId]] =>
case ex: NodeExercises.WithTxValue[Transaction.NodeId, ContractId] =>
// ------------------------------------------------------------------
// witnesses:
// | default: stakeholders(targetId) union witnesses of parent exercise node
@ -952,7 +948,7 @@ object Ledger {
childNodeId)
}
case nlbk: NodeLookupByKey[ContractId, Transaction.Value[ContractId]] =>
case nlbk: NodeLookupByKey.WithTxValue[ContractId] =>
// ------------------------------------------------------------------
// witnesses: parent exercise witnesses
//
@ -1162,9 +1158,7 @@ object Ledger {
val idsToProcess = (mbParentId -> restOfNodeIds) :: restENPs
node match {
case nc: NodeCreate[
AbsoluteContractId,
Transaction.Value[AbsoluteContractId]] =>
case nc: NodeCreate.WithTxValue[AbsoluteContractId] =>
val newCache1 =
newCache.markAsActive(nc.coid)
val mbNewCache2 = nc.key match {
@ -1185,10 +1179,7 @@ object Ledger {
processNodes(Right(newCacheP), idsToProcess)
case ex: NodeExercises[
NodeId,
AbsoluteContractId,
Transaction.Value[AbsoluteContractId]] =>
case ex: NodeExercises.WithTxValue[NodeId, AbsoluteContractId] =>
val newCache0 =
newCache.updateNodeInfo(NodeId(ex.targetCoid))(
info =>
@ -1216,9 +1207,7 @@ object Ledger {
Right(newCache1),
(Some(nodeId) -> ex.children.toList) :: idsToProcess)
case nlkup: NodeLookupByKey[
AbsoluteContractId,
Transaction.Value[AbsoluteContractId]] =>
case nlkup: NodeLookupByKey.WithTxValue[AbsoluteContractId] =>
nlkup.result match {
case None =>
processNodes(Right(newCache), idsToProcess)

View File

@ -6,6 +6,7 @@ import com.digitalasset.daml.lf.data.{ImmArray, ScalazEqual}
import com.digitalasset.daml.lf.data.Ref._
import com.digitalasset.daml.lf.value.Value.{AbsoluteContractId, ContractInst, VersionedValue}
import scala.language.higherKinds
import scalaz.Equal
import scalaz.std.option._
import scalaz.syntax.apply.^
@ -23,9 +24,13 @@ object Node {
def mapNodeId[Nid2](f: Nid => Nid2): GenNode[Nid2, Cid, Val]
}
object GenNode extends WithTxValue3[GenNode]
/** A transaction node that can't possibly refer to `Nid`s. */
sealed trait LeafOnlyNode[+Cid, +Val] extends GenNode[Nothing, Cid, Val]
object LeafOnlyNode extends WithTxValue2[LeafOnlyNode]
/** Denotes the creation of a contract instance. */
final case class NodeCreate[+Cid, +Val](
coid: Cid,
@ -43,6 +48,8 @@ object Node {
override def mapNodeId[Nid2](f: Nothing => Nid2): NodeCreate[Cid, Val] = this
}
object NodeCreate extends WithTxValue2[NodeCreate]
/** Denotes that the contract identifier `coid` needs to be active for the transaction to be valid. */
final case class NodeFetch[+Cid](
coid: Cid,
@ -89,6 +96,8 @@ object Node {
)
}
object NodeExercises extends WithTxValue3[NodeExercises]
final case class NodeLookupByKey[+Cid, +Val](
templateId: Identifier,
optLocation: Option[Location],
@ -103,6 +112,8 @@ object Node {
override def mapNodeId[Nid2](f: Nothing => Nid2): NodeLookupByKey[Cid, Val] = this
}
object NodeLookupByKey extends WithTxValue2[NodeLookupByKey]
case class KeyWithMaintainers[+Val](key: Val, maintainers: Set[Party]) {
def mapValue[Val1](f: Val => Val1): KeyWithMaintainers[Val1] = copy(key = f(key))
}
@ -181,4 +192,12 @@ object Node {
* a key.
*/
case class GlobalKey(templateId: Identifier, key: VersionedValue[AbsoluteContractId])
sealed trait WithTxValue2[F[+ _, + _]] {
type WithTxValue[+Cid] = F[Cid, Transaction.Value[Cid]]
}
sealed trait WithTxValue3[F[+ _, + _, + _]] {
type WithTxValue[+Nid, +Cid] = F[Nid, Cid, Transaction.Value[Cid]]
}
}

View File

@ -80,9 +80,9 @@ class TransactionSpec extends FreeSpec with Matchers with GeneratorDrivenPropert
import Node.isReplayedBy
type CidVal[F[_, _]] = F[V.ContractId, V.VersionedValue[V.ContractId]]
val genEmptyNode
: Gen[Node.GenNode[Nothing, V.ContractId, V.VersionedValue[V.ContractId]]] = danglingRefGenNode map {
: Gen[Node.GenNode.WithTxValue[Nothing, V.ContractId]] = danglingRefGenNode map {
case (_, n: CidVal[Node.LeafOnlyNode]) => n
case (_, ne: Node.NodeExercises[_, V.ContractId, V.VersionedValue[V.ContractId]]) =>
case (_, ne: Node.NodeExercises.WithTxValue[_, V.ContractId]) =>
ne copy (children = ImmArray.empty)
}
@ -100,7 +100,7 @@ class TransactionSpec extends FreeSpec with Matchers with GeneratorDrivenPropert
val withoutLocation = n match {
case nc: CidVal[Node.NodeCreate] => nc copy (optLocation = None)
case nf: Node.NodeFetch[V.ContractId] => nf copy (optLocation = None)
case ne: Node.NodeExercises[Nothing, V.ContractId, V.VersionedValue[V.ContractId]] =>
case ne: Node.NodeExercises.WithTxValue[Nothing, V.ContractId] =>
ne copy (optLocation = None)
case nl: CidVal[Node.NodeLookupByKey] => nl copy (optLocation = None)
}