LF: Refactor TransactionVersion (#8299)

Simplify transaction version. In particular we drop the dependency to LfVersions abstract class.

CHANGELOG_BEGIN
CHANGELOG_END
This commit is contained in:
Remy 2020-12-16 11:27:54 +01:00 committed by GitHub
parent dd12f03147
commit fe44764e61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 69 additions and 67 deletions

View File

@ -22,12 +22,17 @@ final case class VersionRange[V](
max: V,
)(implicit ordering: Ordering[V]) {
require(min <= max)
def intersect(that: VersionRange[V]): VersionRange[V] =
VersionRange(
min = this.min max that.min,
max = this.max min that.max,
)
def map[W](f: V => W)(implicit ordering: Ordering[W]) =
VersionRange(f(min), f(max))
def contains(v: V): Boolean =
min <= v && v <= max

View File

@ -198,12 +198,12 @@ object Repl {
if (compilerConfig.allowedLanguageVersions.contains(LV.v1_dev))
(
value.ValueVersion.DevOutputVersions,
transaction.TransactionVersion.DevOutputVersions,
transaction.TransactionVersion.DevVersions,
)
else
(
value.ValueVersion.StableOutputVersions,
transaction.TransactionVersion.StableOutputVersions,
transaction.TransactionVersion.StableVersions,
)
def run(expr: Expr): (

View File

@ -193,7 +193,7 @@ object TransactionBuilder {
private val KeyWithMaintainers = Node.KeyWithMaintainers
def apply(): TransactionBuilder =
TransactionBuilder(TransactionVersion.StableOutputVersions.min)
TransactionBuilder(TransactionVersion.StableVersions.min)
def apply(txVersion: TransactionVersion): TransactionBuilder =
new TransactionBuilder(_ => txVersion)

View File

@ -507,12 +507,7 @@ object ValueGenerators {
stringVersionGen.map(ValueVersion(_)).filterNot(ValueVersion.acceptedVersions.contains)
def transactionVersionGen: Gen[TransactionVersion] =
Gen.oneOf(TransactionVersion.acceptedVersions)
def unsupportedTransactionVersionGen: Gen[TransactionVersion] =
stringVersionGen
.map(TransactionVersion(_))
.filterNot(TransactionVersion.acceptedVersions.contains)
Gen.oneOf(TransactionVersion.Values)
object Implicits {
implicit val vdateArb: Arbitrary[Time.Date] = Arbitrary(dateGen)

View File

@ -464,11 +464,7 @@ object TransactionCoder {
}
def decodeVersion(vs: String): Either[DecodeError, TransactionVersion] =
TransactionVersion
.isAcceptedVersion(vs)
.fold[Either[DecodeError, TransactionVersion]](
Left(DecodeError(s"Unsupported transaction version $vs")),
)(v => Right(v))
TransactionVersion.fromString(vs).left.map(DecodeError)
/**
* Reads a [[VersionedTransaction]] from protobuf and checks if

View File

@ -7,50 +7,51 @@ package transaction
import com.daml.lf.data.ImmArray
import com.daml.lf.language.LanguageVersion
import com.daml.lf.value.{Value, ValueVersion}
import scalaz.NonEmptyList
import scala.collection.immutable.HashMap
final case class TransactionVersion(protoValue: String)
sealed abstract class TransactionVersion private (val protoValue: String, private val index: Int)
extends Product
with Serializable
/**
* Currently supported versions of the DAML-LF transaction specification.
*/
object TransactionVersion
extends LfVersions(versionsAscending =
NonEmptyList(new TransactionVersion("10"), new TransactionVersion("dev")))(
_.protoValue,
) {
object TransactionVersion {
private[lf] implicit val Ordering: Ordering[TransactionVersion] = mkOrdering
case object V10 extends TransactionVersion("10", 10)
case object VDev extends TransactionVersion("dev", Int.MaxValue)
private[lf] val List(v10, vDev) = acceptedVersions
val Values = List(V10, VDev)
val minVersion = v10
private[transaction] val minChoiceObservers = vDev
private[transaction] val minNodeVersion = vDev
private[lf] implicit val Ordering: scala.Ordering[TransactionVersion] = scala.Ordering.by(_.index)
// Older versions are deprecated https://github.com/digital-asset/daml/issues/5220
private[lf] val StableOutputVersions: VersionRange[TransactionVersion] =
VersionRange(v10, v10)
private[this] val stringMapping = Values.iterator.map(v => v.protoValue -> v).toMap
private[lf] val DevOutputVersions: VersionRange[TransactionVersion] =
StableOutputVersions.copy(max = acceptedVersions.last)
def fromString(vs: String): Either[String, TransactionVersion] =
stringMapping.get(vs).toRight(s"Unsupported transaction version $vs")
def assertFromString(vs: String): TransactionVersion =
data.assertRight(fromString(vs))
val minVersion = Values.min
private[transaction] val minChoiceObservers = VDev
private[transaction] val minNodeVersion = VDev
private[lf] val assignNodeVersion: LanguageVersion => TransactionVersion = {
import LanguageVersion._
Map(
v1_6 -> v10,
v1_7 -> v10,
v1_8 -> v10,
v1_dev -> vDev,
v1_6 -> V10,
v1_7 -> V10,
v1_8 -> V10,
v1_dev -> VDev,
)
}
private[lf] val assignValueVersion: TransactionVersion => ValueVersion = {
Map(
v10 -> ValueVersion("6"),
vDev -> ValueVersion("dev"),
V10 -> ValueVersion("6"),
VDev -> ValueVersion("dev"),
)
}
@ -66,4 +67,10 @@ object TransactionVersion
VersionedTransaction(txVersion, nodes, roots)
}
private[lf] val StableVersions: VersionRange[TransactionVersion] =
LanguageVersion.StableVersions.map(assignNodeVersion)
private[lf] val DevVersions: VersionRange[TransactionVersion] =
LanguageVersion.DevVersions.map(assignNodeVersion)
}

View File

@ -32,9 +32,9 @@ class TransactionCoderSpec
implicit override val generatorDrivenConfig: PropertyCheckConfiguration =
PropertyCheckConfiguration(minSuccessful = 1000, sizeRange = 10)
import TransactionVersion.{v10, vDev}
import TransactionVersion.{V10, VDev}
private[this] val transactionVersions = Table("transaction version", v10, vDev)
private[this] val transactionVersions = Table("transaction version", V10, VDev)
"encode-decode" should {
@ -221,31 +221,30 @@ class TransactionCoderSpec
"transactions decoding should fail when unsupported transaction version received" in
forAll(noDanglingRefGenTransaction, minSuccessful(50)) { tx =>
forAll(unsupportedTransactionVersionGen, minSuccessful(20)) {
badTxVer: TransactionVersion =>
TransactionVersion.acceptedVersions.contains(badTxVer) shouldEqual false
forAll(stringVersionGen, minSuccessful(20)) { badTxVer =>
whenever(TransactionVersion.fromString(badTxVer).isLeft) {
val encodedTxWithBadTxVer: proto.Transaction = assertRight(
TransactionCoder
.encodeTransactionWithCustomVersion(
TransactionCoder.NidEncoder,
ValueCoder.CidEncoder,
VersionedTransaction(
TransactionVersion.vDev,
tx.nodes.mapValues(_.updateVersion(TransactionVersion.vDev)),
TransactionVersion.VDev,
tx.nodes.mapValues(_.updateVersion(TransactionVersion.VDev)),
tx.roots),
),
).toBuilder.setVersion(badTxVer.protoValue).build()
).toBuilder.setVersion(badTxVer).build()
encodedTxWithBadTxVer.getVersion shouldEqual badTxVer.protoValue
encodedTxWithBadTxVer.getVersion shouldEqual badTxVer
TransactionCoder.decodeTransaction(
TransactionCoder.NidDecoder,
ValueCoder.CidDecoder,
encodedTxWithBadTxVer,
) shouldEqual Left(
DecodeError(s"Unsupported transaction version ${badTxVer.protoValue}"),
DecodeError(s"Unsupported transaction version $badTxVer"),
)
}
}
}
@ -303,7 +302,7 @@ class TransactionCoderSpec
// FIXME: https://github.com/digital-asset/daml/issues/7139
// replace all occurrences of "dev" by "11", once "11" is released
"fail iff try to encode choice observers in version < dev" in {
val normalize = minimalistNode(v10)
val normalize = minimalistNode(V10)
forAll(danglingRefExerciseNodeGen, minSuccessful(10)) { node =>
val shouldFail = node.choiceObservers.nonEmpty
@ -321,7 +320,7 @@ class TransactionCoderSpec
ValueCoder.CidEncoder,
txVersion,
NodeId(0),
normalized.updateVersion(v10),
normalized.updateVersion(V10),
)
result.isLeft shouldBe shouldFail
@ -355,18 +354,18 @@ class TransactionCoderSpec
"decodeVersionedNode" should {
"""ignore field version if enclosing Transaction message is of version 10""" in {
val normalize = minimalistNode(v10)
val normalize = minimalistNode(V10)
forAll(danglingRefGenNode, Gen.asciiStr, minSuccessful(10)) {
case ((nodeId, node), str) =>
val normalizedNode = normalize(node.updateVersion(v10))
val normalizedNode = normalize(node.updateVersion(V10))
val Right(encoded) = for {
encoded <- TransactionCoder
.encodeNode(
TransactionCoder.NidEncoder,
ValueCoder.CidEncoder,
v10,
V10,
nodeId,
normalizedNode
)
@ -375,7 +374,7 @@ class TransactionCoderSpec
TransactionCoder.decodeVersionedNode(
TransactionCoder.NidDecoder,
ValueCoder.CidDecoder,
v10,
V10,
encoded,
) shouldBe Right(nodeId -> normalizedNode)
}
@ -387,8 +386,8 @@ class TransactionCoderSpec
forAll(
danglingRefGenNode,
transactionVersionGen.filter(_ != v10),
transactionVersionGen.filter(_ != v10),
transactionVersionGen.filter(_ != V10),
transactionVersionGen.filter(_ != V10),
minSuccessful(10)) {
case ((nodeId, node), version1, version2) =>
whenever(version1 != version2) {
@ -418,7 +417,7 @@ class TransactionCoderSpec
// FIXME: https://github.com/digital-asset/daml/issues/7139
// replace all occurrences of "dev" by "11", once "11" is released
"ignore field observers in version < dev" in {
val normalize = minimalistNode(v10)
val normalize = minimalistNode(V10)
forAll(
Arbitrary.arbInt.arbitrary,
@ -427,7 +426,7 @@ class TransactionCoderSpec
minSuccessful(50),
) { (nodeIdx, node, strings) =>
val nodeId = NodeId(nodeIdx)
val normalizedNode = normalize(node).updateVersion(v10)
val normalizedNode = normalize(node).updateVersion(V10)
val Right(encoded) =
for {
@ -435,7 +434,7 @@ class TransactionCoderSpec
.encodeNode(
TransactionCoder.NidEncoder,
ValueCoder.CidEncoder,
v10,
V10,
nodeId,
normalizedNode,
)

View File

@ -158,7 +158,7 @@ class TransactionSpec extends AnyFreeSpec with Matchers with ScalaCheckDrivenPro
}
"fail if version is different" in {
val versions = TransactionVersion.acceptedVersions.toIndexedSeq
val versions = TransactionVersion.Values
def diffVersion(v: TransactionVersion) = {
val randomVersion = versions(Random.nextInt(versions.length - 1))
if (randomVersion != v) randomVersion else versions.last

View File

@ -13,16 +13,16 @@ import org.scalatest.wordspec.AnyWordSpec
class TransactionVersionSpec extends AnyWordSpec with Matchers with TableDrivenPropertyChecks {
import LanguageVersion.{v1_6, v1_7, v1_8, v1_dev}
import TransactionVersion.{v10, vDev}
import TransactionVersion.{V10, VDev}
"TransactionVersion.assignNodeVersion" should {
val testCases = Table(
"language version" -> "transaction version",
v1_6 -> v10,
v1_7 -> v10,
v1_8 -> v10,
v1_dev -> vDev,
v1_6 -> V10,
v1_7 -> V10,
v1_8 -> V10,
v1_dev -> VDev,
)
"be stable" in {
@ -38,8 +38,8 @@ class TransactionVersionSpec extends AnyWordSpec with Matchers with TableDrivenP
val testCases = Table(
"input" -> "output",
v10 -> ValueVersion("6"),
vDev -> ValueVersion("dev")
V10 -> ValueVersion("6"),
VDev -> ValueVersion("dev")
)
forEvery(testCases) { (input, expectedOutput) =>