diff --git a/compiler/scenario-service/server/src/main/scala/com/digitalasset/daml/lf/scenario/Conversions.scala b/compiler/scenario-service/server/src/main/scala/com/digitalasset/daml/lf/scenario/Conversions.scala index 3b8228a2ae..7990e11703 100644 --- a/compiler/scenario-service/server/src/main/scala/com/digitalasset/daml/lf/scenario/Conversions.scala +++ b/compiler/scenario-service/server/src/main/scala/com/digitalasset/daml/lf/scenario/Conversions.scala @@ -186,11 +186,6 @@ final class Conversions( sys.error( s"Got unexpected DamlEWronglyTypedContract error in scenario service: $wtc. Note that in the scenario service this error should never surface since contract fetches are all type checked.", ) - - case divv: SError.DamlEDisallowedInputValueVersion => - sys.error( - s"Got unexpected DamlEDisallowedInputVersion error in scenario service: $divv. Note that in the scenario service this error should never surface since its accept all stable versions.", - ) } builder.build } diff --git a/daml-lf/data/src/main/scala/com/digitalasset/daml/lf/VersionRange.scala b/daml-lf/data/src/main/scala/com/digitalasset/daml/lf/VersionRange.scala index e01e63170a..c63e59e0e1 100644 --- a/daml-lf/data/src/main/scala/com/digitalasset/daml/lf/VersionRange.scala +++ b/daml-lf/data/src/main/scala/com/digitalasset/daml/lf/VersionRange.scala @@ -7,15 +7,13 @@ import scala.Ordering.Implicits.infixOrderingOps /** * [[VersionRange]] represents a range of versions of - * [[com.daml.lf.language.LanguageVersion]], - * [[com.daml.lf.transaction.TransactionVersion]], or - * [[com.daml.lf.value.ValueVersion]]. + * [[com.daml.lf.language.LanguageVersion]] or + * [[com.daml.lf.transaction.TransactionVersion]]. * * @param min the minimal version included in the range. * @param max the maximal version included in the range. - * @tparam V either [[com.daml.lf.language.LanguageVersion]], - * [[com.daml.lf.transaction.TransactionVersion]], or - * [[com.daml.lf.value.ValueVersion]]. + * @tparam V either [[com.daml.lf.language.LanguageVersion]] or + * [[com.daml.lf.transaction.TransactionVersion]]. */ final case class VersionRange[V]( min: V, diff --git a/daml-lf/engine/BUILD.bazel b/daml-lf/engine/BUILD.bazel index aba5cdb052..fb5ea1d451 100644 --- a/daml-lf/engine/BUILD.bazel +++ b/daml-lf/engine/BUILD.bazel @@ -52,6 +52,7 @@ da_scala_test_suite( "//daml-lf/language", "//daml-lf/parser", "//daml-lf/transaction", + "//daml-lf/transaction-test-lib", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_storm_enroute_scalameter_core_2_12", "@maven//:org_scalatest_scalatest_2_12", diff --git a/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractDiscriminatorFreshnessCheckSpec.scala b/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractDiscriminatorFreshnessCheckSpec.scala index d1b7b83e6f..4122cf23f0 100644 --- a/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractDiscriminatorFreshnessCheckSpec.scala +++ b/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractDiscriminatorFreshnessCheckSpec.scala @@ -7,8 +7,9 @@ import com.daml.lf.data._ import com.daml.lf.engine.Engine import com.daml.lf.testing.parser.Implicits._ import com.daml.lf.transaction.GlobalKey +import com.daml.lf.transaction.test.TransactionBuilder import com.daml.lf.value.Value.ContractId -import com.daml.lf.value.{Value, ValueVersion} +import com.daml.lf.value.Value import org.scalatest.prop.TableDrivenPropertyChecks import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec @@ -98,7 +99,7 @@ class ContractDiscriminatorFreshnessCheckSpec private def contractInstance(party: Ref.Party, idx: Int, cids: List[ContractId]) = Value.ContractInst( tmplId, - ValueVersion.assertAsVersionedValue(contractRecord(party, idx, cids)), + TransactionBuilder.assertAsVersionedValue(contractRecord(party, idx, cids)), "Agreement", ) diff --git a/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala b/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala index 1005fb2db1..562e67a11f 100644 --- a/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala +++ b/daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/EngineTest.scala @@ -30,7 +30,7 @@ import com.daml.lf.speedy.{InitialSeeding, SValue, svalue} import com.daml.lf.speedy.SValue._ import com.daml.lf.command._ import com.daml.lf.transaction.Node.GenNode -import com.daml.lf.value.ValueVersion.assertAsVersionedValue +import com.daml.lf.transaction.test.TransactionBuilder.assertAsVersionedValue import org.scalactic.Equality import org.scalatest.prop.TableDrivenPropertyChecks import org.scalatest.EitherValues diff --git a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Pretty.scala b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Pretty.scala index 2362b517a1..03f8c1413d 100644 --- a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Pretty.scala +++ b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Pretty.scala @@ -8,7 +8,6 @@ import org.typelevel.paiges.Doc._ import com.daml.lf.ledger.EventId import com.daml.lf.value.Value import Value.{NodeId => _, _} -import com.daml.lf.VersionRange import com.daml.lf.transaction.Node._ import com.daml.lf.ledger._ import com.daml.lf.data.Ref._ @@ -99,12 +98,6 @@ private[lf] object Pretty { prettyTypeConName(tid) / text("The provided key is") & prettyValue(true)(key) - case DamlEDisallowedInputValueVersion(VersionRange(expectedMin, expectedMax), actual) => - text("Update failed due to disallowed value version") / - text("Expected value version between") & text(expectedMin.protoValue) & - text("and") & text(expectedMax.protoValue) & text("but got") & - text(actual.protoValue) - } // A minimal pretty-print of an update transaction node, without recursing into child nodes.. diff --git a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SError.scala b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SError.scala index db637f325e..4504eb77b9 100644 --- a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SError.scala +++ b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SError.scala @@ -3,13 +3,12 @@ package com.daml.lf.speedy -import com.daml.lf.VersionRange import com.daml.lf.data.Ref._ import com.daml.lf.data.Time import com.daml.lf.ledger.EventId import com.daml.lf.ledger.FailedAuthorization import com.daml.lf.transaction.{GlobalKey, NodeId, Transaction => Tx} -import com.daml.lf.value.{Value, ValueVersion} +import com.daml.lf.value.Value import com.daml.lf.value.Value.ContractId import com.daml.lf.scenario.ScenarioLedger @@ -110,14 +109,6 @@ object SError { actual: TypeConName, ) extends SErrorDamlException - /** We tried to fetch data with disallowed value version -- - * see - */ - final case class DamlEDisallowedInputValueVersion( - allowed: VersionRange[ValueVersion], - actual: ValueVersion, - ) extends SErrorDamlException - /** There was an authorization failure during execution. */ final case class DamlEFailedAuthorization( nid: NodeId, diff --git a/daml-lf/repl/src/main/scala/com/digitalasset/daml/lf/repl/testing/Main.scala b/daml-lf/repl/src/main/scala/com/digitalasset/daml/lf/repl/testing/Main.scala index 6294ff45a6..0d170103ac 100644 --- a/daml-lf/repl/src/main/scala/com/digitalasset/daml/lf/repl/testing/Main.scala +++ b/daml-lf/repl/src/main/scala/com/digitalasset/daml/lf/repl/testing/Main.scala @@ -194,17 +194,12 @@ object Repl { private val seed = nextSeed() - val (inputValueVersion, outputTransactionVersions) = - if (compilerConfig.allowedLanguageVersions.contains(LV.v1_dev)) - ( - value.ValueVersion.DevOutputVersions, - transaction.TransactionVersion.DevVersions, - ) - else - ( - value.ValueVersion.StableOutputVersions, - transaction.TransactionVersion.StableVersions, - ) + val transactionVersions = + if (compilerConfig.allowedLanguageVersions.contains(LV.v1_dev)) { + transaction.TransactionVersion.DevVersions + } else { + transaction.TransactionVersion.StableVersions + } def run(expr: Expr): ( Speedy.Machine, diff --git a/daml-lf/transaction-test-lib/src/main/scala/lf/transaction/test/TransactionBuilder.scala b/daml-lf/transaction-test-lib/src/main/scala/lf/transaction/test/TransactionBuilder.scala index 44151e6b50..ad26d322f0 100644 --- a/daml-lf/transaction-test-lib/src/main/scala/lf/transaction/test/TransactionBuilder.scala +++ b/daml-lf/transaction-test-lib/src/main/scala/lf/transaction/test/TransactionBuilder.scala @@ -5,12 +5,13 @@ package com.daml.lf package transaction package test -import com.daml.lf.data.{BackStack, ImmArray, Ref} +import com.daml.lf.data.{BackStack, FrontStack, FrontStackCons, ImmArray, Ref} import com.daml.lf.transaction.{Transaction => Tx} -import com.daml.lf.value.Value.{ContractId, ContractInst} +import com.daml.lf.value.Value.{ContractId, ContractInst, VersionedValue} import com.daml.lf.value.{Value => LfValue} import scala.Ordering.Implicits.infixOrderingOps +import scala.annotation.tailrec import scala.collection.immutable.HashMap final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion = _ => @@ -74,14 +75,11 @@ final class TransactionBuilder(pkgTxVersion: Ref.PackageId => TransactionVersion def newCid: ContractId = ContractId.V1(newHash()) - private[this] def pkgValVersion(pkgId: Ref.PackageId) = - TransactionVersion.assignValueVersion(pkgTxVersion(pkgId)) - def versionContract(contract: ContractInst[Value]): ContractInst[TxValue] = - ContractInst.map1[Value, TxValue](versionValue(contract.template))(contract) + ContractInst.map1[Value, TxValue](transactionValue(contract.template))(contract) - private[this] def versionValue(templateId: Ref.TypeConName): Value => TxValue = - value.Value.VersionedValue(pkgValVersion(templateId.packageId), _) + private[this] def transactionValue(templateId: Ref.TypeConName): Value => TxValue = + value.Value.VersionedValue(pkgTxVersion(templateId.packageId), _) def create( id: String, @@ -247,4 +245,73 @@ object TransactionBuilder { val EmptySubmitted: SubmittedTransaction = SubmittedTransaction(Empty) val EmptyCommitted: CommittedTransaction = CommittedTransaction(Empty) + def assignVersion[Cid]( + v0: Value, + supportedVersions: VersionRange[TransactionVersion] = TransactionVersion.StableVersions + ): Either[String, TransactionVersion] = { + @tailrec + def go( + currentVersion: TransactionVersion, + values0: FrontStack[Value], + ): Either[String, TransactionVersion] = { + import LfValue._ + if (currentVersion >= supportedVersions.max) { + Right(currentVersion) + } else { + values0 match { + case FrontStack() => Right(currentVersion) + case FrontStackCons(value, values) => + value match { + // for things supported since version 1, we do not need to check + case ValueRecord(_, fs) => go(currentVersion, fs.map(v => v._2) ++: values) + case ValueVariant(_, _, arg) => go(currentVersion, arg +: values) + case ValueList(vs) => go(currentVersion, vs.toImmArray ++: values) + case ValueContractId(_) | ValueInt64(_) | ValueText(_) | ValueTimestamp(_) | + ValueParty(_) | ValueBool(_) | ValueDate(_) | ValueUnit | ValueNumeric(_) => + go(currentVersion, values) + case ValueOptional(x) => + go(currentVersion, x.fold(values)(_ +: values)) + case ValueTextMap(map) => + go(currentVersion, map.values ++: values) + case ValueEnum(_, _) => + go(currentVersion, values) + // for things added after version 10, we raise the minimum if present + case ValueGenMap(entries) => + val newValues = entries.iterator.foldLeft(values) { + case (acc, (key, value)) => key +: value +: acc + } + go(currentVersion max TransactionVersion.minGenMap, newValues) + } + } + } + } + + go(supportedVersions.min, FrontStack(v0)) match { + case Right(inferredVersion) if supportedVersions.max < inferredVersion => + Left(s"inferred version $inferredVersion is not supported") + case res => + res + } + + } + @throws[IllegalArgumentException] + def assertAssignVersion( + v0: Value, + supportedVersions: VersionRange[TransactionVersion] = TransactionVersion.DevVersions, + ): TransactionVersion = + data.assertRight(assignVersion(v0, supportedVersions)) + + def asVersionedValue( + value: Value, + supportedVersions: VersionRange[TransactionVersion] = TransactionVersion.DevVersions, + ): Either[String, TxValue] = + assignVersion(value, supportedVersions).map(VersionedValue(_, value)) + + @throws[IllegalArgumentException] + def assertAsVersionedValue( + value: Value, + supportedVersions: VersionRange[TransactionVersion] = TransactionVersion.DevVersions, + ): TxValue = + data.assertRight(asVersionedValue(value, supportedVersions)) + } diff --git a/daml-lf/transaction-test-lib/src/main/scala/lf/value/test/ValueGenerators.scala b/daml-lf/transaction-test-lib/src/main/scala/lf/value/test/ValueGenerators.scala index 124ec331c4..890d0cec2b 100644 --- a/daml-lf/transaction-test-lib/src/main/scala/lf/value/test/ValueGenerators.scala +++ b/daml-lf/transaction-test-lib/src/main/scala/lf/value/test/ValueGenerators.scala @@ -22,6 +22,7 @@ import com.daml.lf.transaction.{ VersionedTransaction, Transaction => Tx } +import com.daml.lf.transaction.test.TransactionBuilder import com.daml.lf.value.Value.{NodeId => _, _} import org.scalacheck.{Arbitrary, Gen} import Arbitrary.arbitrary @@ -249,8 +250,8 @@ object ValueGenerators { def versionedValueGen: Gen[VersionedValue[ContractId]] = for { value <- valueGen - minVersion = ValueVersion.assertAssignVersion(value) - version <- valueVersionGen(minVersion) + minVersion = TransactionBuilder.assertAssignVersion(value) + version <- transactionVersionGen(minVersion) } yield VersionedValue(version, value) private[lf] val genMaybeEmptyParties: Gen[Set[Party]] = Gen.listOf(party).map(_.toSet) @@ -289,7 +290,7 @@ object ValueGenerators { */ val malformedCreateNodeGen: Gen[NodeCreate[Value.ContractId]] = { for { - version <- transactionVersionGen + version <- transactionVersionGen() coid <- coidGen coinst <- contractInstanceGen signatories <- genNonEmptyParties @@ -300,7 +301,7 @@ object ValueGenerators { val fetchNodeGen: Gen[NodeFetch[ContractId]] = { for { - version <- transactionVersionGen + version <- transactionVersionGen() coid <- coidGen templateId <- idGen actingParties <- genNonEmptyParties @@ -324,7 +325,7 @@ object ValueGenerators { /** Makes exercise nodes with some random child IDs. */ val danglingRefExerciseNodeGen: Gen[NodeExercises[NodeId, Value.ContractId]] = { for { - version <- transactionVersionGen + version <- transactionVersionGen() targetCoid <- coidGen templateId <- idGen choiceId <- nameGen @@ -465,8 +466,8 @@ object ValueGenerators { def noDanglingRefGenVersionedTransaction: Gen[VersionedTransaction[NodeId, ContractId]] = { for { tx <- noDanglingRefGenTransaction - txVer <- transactionVersionGen - nodeVersionGen = transactionVersionGen.filterNot(_ < txVer) + txVer <- transactionVersionGen() + nodeVersionGen = transactionVersionGen().filterNot(_ < txVer) nodes <- tx.fold(Gen.const(HashMap.empty[NodeId, GenNode[NodeId, ContractId]])) { case (acc, (nodeId, node)) => for { @@ -500,14 +501,10 @@ object ValueGenerators { Gen.frequency((1, Gen.const("")), (10, g)) } - def valueVersionGen(minVersion: ValueVersion = ValueVersion.minVersion): Gen[ValueVersion] = - Gen.oneOf(ValueVersion.acceptedVersions.filterNot(_ < minVersion).toSeq) - - def unsupportedValueVersionGen: Gen[ValueVersion] = - stringVersionGen.map(ValueVersion(_)).filterNot(ValueVersion.acceptedVersions.contains) - - def transactionVersionGen: Gen[TransactionVersion] = - Gen.oneOf(TransactionVersion.Values) + def transactionVersionGen( + minVersion: TransactionVersion = TransactionVersion.minVersion, + ): Gen[TransactionVersion] = + Gen.oneOf(TransactionVersion.All.filterNot(_ < minVersion)) object Implicits { implicit val vdateArb: Arbitrary[Time.Date] = Arbitrary(dateGen) diff --git a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala index e046526ee3..b21f4ac6e4 100644 --- a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala +++ b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/Node.scala @@ -49,7 +49,7 @@ object Node { private[lf] def updateVersion(version: TransactionVersion): GenNode[Nid, Cid] protected def versionValue[Cid2 >: Cid](v: Value[Cid2]): VersionedValue[Cid2] = - VersionedValue(TransactionVersion.assignValueVersion(version), v) + VersionedValue(version, v) } object GenNode extends CidContainer2[GenNode] { diff --git a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala index 0bf1580f5e..5b500f8941 100644 --- a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala +++ b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionCoder.scala @@ -63,7 +63,7 @@ object TransactionCoder { cidEncoder: ValueCoder.EncodeCid[Cid], value: VersionedValue[Cid], ): Either[EncodeError, ValueOuterClass.VersionedValue] = - ValueCoder.encodeVersionedValueWithCustomVersion(cidEncoder, value) + ValueCoder.encodeVersionedValue(cidEncoder, value) def decodeValue[Cid]( cidDecoder: ValueCoder.DecodeCid[Cid], diff --git a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionVersion.scala b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionVersion.scala index e63cd8627b..d915ada021 100644 --- a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionVersion.scala +++ b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/transaction/TransactionVersion.scala @@ -6,7 +6,7 @@ package transaction import com.daml.lf.data.ImmArray import com.daml.lf.language.LanguageVersion -import com.daml.lf.value.{Value, ValueVersion} +import com.daml.lf.value.Value import scala.collection.immutable.HashMap @@ -22,21 +22,28 @@ object TransactionVersion { case object V10 extends TransactionVersion("10", 10) case object VDev extends TransactionVersion("dev", Int.MaxValue) - val Values = List(V10, VDev) + val All = List(V10, VDev) private[lf] implicit val Ordering: scala.Ordering[TransactionVersion] = scala.Ordering.by(_.index) - private[this] val stringMapping = Values.iterator.map(v => v.protoValue -> v).toMap + private[this] val stringMapping = All.iterator.map(v => v.protoValue -> v).toMap def fromString(vs: String): Either[String, TransactionVersion] = - stringMapping.get(vs).toRight(s"Unsupported transaction version $vs") + stringMapping.get(vs) match { + case Some(value) => Right(value) + case None => + Left(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 + val minVersion: TransactionVersion = All.min + def maxVersion: TransactionVersion = VDev + + private[lf] val minGenMap = VDev + private[lf] val minChoiceObservers = VDev + private[lf] val minNodeVersion = VDev private[lf] val assignNodeVersion: LanguageVersion => TransactionVersion = { import LanguageVersion._ @@ -48,13 +55,6 @@ object TransactionVersion { ) } - private[lf] val assignValueVersion: TransactionVersion => ValueVersion = { - Map( - V10 -> ValueVersion("6"), - VDev -> ValueVersion("dev"), - ) - } - private[lf] def asVersionedTransaction( roots: ImmArray[NodeId], nodes: HashMap[NodeId, Node.GenNode[NodeId, Value.ContractId]], diff --git a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/Value.scala b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/Value.scala index 8ca799d282..57490483d5 100644 --- a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/Value.scala +++ b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/Value.scala @@ -7,6 +7,7 @@ package value import com.daml.lf.crypto.Hash import com.daml.lf.data.Ref.{Identifier, Name} import com.daml.lf.data._ +import com.daml.lf.transaction.TransactionVersion import data.ScalazEqual._ import scala.annotation.tailrec @@ -202,7 +203,7 @@ object Value extends CidContainer1[Value] { */ val MAXIMUM_NESTING: Int = 100 - final case class VersionedValue[+Cid](version: ValueVersion, value: Value[Cid]) + final case class VersionedValue[+Cid](version: TransactionVersion, value: Value[Cid]) extends CidContainer[VersionedValue[Cid]] { override protected def self: this.type = this diff --git a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/ValueCoder.scala b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/ValueCoder.scala index 54fc0240a3..0caed8402e 100644 --- a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/ValueCoder.scala +++ b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/ValueCoder.scala @@ -30,8 +30,6 @@ object ValueCoder { object DecodeError extends (String => DecodeError) { private[lf] def apply(version: TransactionVersion, isTooOldFor: String): DecodeError = DecodeError(s"transaction version ${version.protoValue} is too old to support $isTooOldFor") - private[lf] def apply(version: ValueVersion, isTooOldFor: String): DecodeError = - DecodeError(s"value version ${version.protoValue} is too old to support $isTooOldFor") } /** @@ -43,8 +41,6 @@ object ValueCoder { object EncodeError extends (String => EncodeError) { private[lf] def apply(version: TransactionVersion, isTooOldFor: String): EncodeError = EncodeError(s"transaction version ${version.protoValue} is too old to support $isTooOldFor") - private[lf] def apply(version: ValueVersion, isTooOldFor: String): EncodeError = - EncodeError(s"value version ${version.protoValue} is too old to support $isTooOldFor") } abstract class EncodeCid[-Cid] private[lf] { @@ -129,20 +125,27 @@ object ValueCoder { } yield Identifier(pkgId, QualifiedName(module, name)) - private def decodeVersion(vs: String): Either[DecodeError, ValueVersion] = - ValueVersion - .isAcceptedVersion(vs) - .fold[Either[DecodeError, ValueVersion]](Left(DecodeError(s"Unsupported value version $vs")))( - v => Right(v), - ) + // For backward compatibility reasons, V10 is encoded as "6" when used inside a + // proto.VersionedValue + private[this] def encodeValueVersion(version: TransactionVersion): String = + if (version == TransactionVersion.V10) { + "6" + } else { + version.protoValue + } + + private[this] def decodeValueVersion(vs: String): Either[DecodeError, TransactionVersion] = + vs match { + case "6" => Right(TransactionVersion.V10) + case "10" => Left(DecodeError("Unsupported value version 10")) + case _ => TransactionVersion.fromString(vs).left.map(DecodeError) + } /** * Reads a serialized protobuf versioned value, * checks if the value version is currently supported and * converts the value to the type usable by engine/interpreter. * - * Supported value versions configured in [[ValueVersions]]. - * * @param protoValue0 the value to be read * @param decodeCid a function to decode stringified contract ids * @tparam Cid ContractId type @@ -153,7 +156,7 @@ object ValueCoder { protoValue0: proto.VersionedValue, ): Either[DecodeError, VersionedValue[Cid]] = for { - version <- decodeVersion(protoValue0.getVersion) + version <- decodeValueVersion(protoValue0.getVersion) value <- decodeValue(decodeCid, version, protoValue0.getValue) } yield VersionedValue(version, value) @@ -163,46 +166,6 @@ object ValueCoder { ): Either[DecodeError, Value[Cid]] = decodeVersionedValue(decodeCid, protoValue0) map (_.value) - /** - * Serializes [[Value]] to protobuf, library decides which [[ValueVersion]] to assign. - * See [[ValueVersion.assignVersion]]. - * - * @param value value to be written - * @param encodeCid a function to stringify contractIds (it's better to be invertible) - * @tparam Cid ContractId type - * @return protocol buffer serialized values - */ - def encodeVersionedValue[Cid]( - encodeCid: EncodeCid[Cid], - value: Value[Cid], - supportedVersions: VersionRange[ValueVersion], - ): Either[EncodeError, proto.VersionedValue] = - ValueVersion - .assignVersion(value, supportedVersions) - .fold( - err => Left(EncodeError(err)), - version => encodeVersionedValueWithCustomVersion(encodeCid, VersionedValue(version, value)), - ) - - /** - * Serializes [[VersionedValue]] to protobuf, caller provides the [[ValueVersion]]. - * - * @param versionedValue value to be written - * @param encodeCid a function to stringify contractIds (it's better to be invertible) - * @tparam Cid ContractId type - * @return protocol buffer serialized values - */ - def encodeVersionedValueWithCustomVersion[Cid]( - encodeCid: EncodeCid[Cid], - versionedValue: VersionedValue[Cid], - ): Either[EncodeError, proto.VersionedValue] = - for { - value <- encodeValue(encodeCid, versionedValue.version, versionedValue.value) - } yield { - val builder = proto.VersionedValue.newBuilder() - builder.setVersion(versionedValue.version.protoValue).setValue(value).build() - } - /** * Method to read a serialized protobuf value * to engine/interpreter usable Value type @@ -214,7 +177,7 @@ object ValueCoder { */ def decodeValue[Cid]( decodeCid: DecodeCid[Cid], - valueVersion: ValueVersion, + version: TransactionVersion, protoValue0: proto.Value, ): Either[DecodeError, Value[Cid]] = { case class Err(msg: String) extends Throwable(null, null, true, false) @@ -227,9 +190,9 @@ object ValueCoder { identity, ) - def assertSince(minVersion: ValueVersion, description: => String) = - if (valueVersion < minVersion) - throw Err(s"$description is not supported by value version $valueVersion") + def assertSince(minVersion: TransactionVersion, description: => String) = + if (version < minVersion) + throw Err(s"$description is not supported by value version $version") def go(nesting: Int, protoValue: proto.Value): Value[Cid] = { if (nesting > MAXIMUM_NESTING) { @@ -343,7 +306,7 @@ object ValueCoder { ValueTextMap(map) case proto.Value.SumCase.GEN_MAP => - assertSince(ValueVersion.minGenMap, "Value.SumCase.MAP") + assertSince(TransactionVersion.minGenMap, "Value.SumCase.MAP") val genMap = protoValue.getGenMap.getEntriesList.asScala.map(entry => go(newNesting, entry.getKey) -> go(newNesting, entry.getValue)) ValueGenMap(ImmArray(genMap)) @@ -361,6 +324,32 @@ object ValueCoder { } } + /** + * Serializes [[VersionedValue]] to protobuf. + * + * @param versionedValue value to be written + * @param encodeCid a function to stringify contractIds (it's better to be invertible) + * @tparam Cid ContractId type + * @return protocol buffer serialized values + */ + def encodeVersionedValue[Cid]( + encodeCid: EncodeCid[Cid], + versionedValue: VersionedValue[Cid], + ): Either[EncodeError, proto.VersionedValue] = + encodeVersionedValue(encodeCid, versionedValue.version, versionedValue.value) + + def encodeVersionedValue[Cid]( + encodeCid: EncodeCid[Cid], + version: TransactionVersion, + value: Value[Cid], + ): Either[EncodeError, proto.VersionedValue] = + for { + protoValue <- encodeValue(encodeCid, version, value) + } yield { + val builder = proto.VersionedValue.newBuilder() + builder.setVersion(encodeValueVersion(version)).setValue(protoValue).build() + } + /** * Serialize a Value to protobuf * @@ -372,12 +361,12 @@ object ValueCoder { */ def encodeValue[Cid]( encodeCid: EncodeCid[Cid], - valueVersion: ValueVersion, + valueVersion: TransactionVersion, v0: Value[Cid], ): Either[EncodeError, proto.Value] = { case class Err(msg: String) extends Throwable(null, null, true, false) - def assertSince(minVersion: ValueVersion, description: => String) = + def assertSince(minVersion: TransactionVersion, description: => String) = if (valueVersion < minVersion) throw Err(s"$description is not supported by value version $valueVersion") @@ -469,7 +458,7 @@ object ValueCoder { builder.setMap(protoMap).build() case ValueGenMap(entries) => - assertSince(ValueVersion.minGenMap, "Value.SumCase.MAP") + assertSince(TransactionVersion.minGenMap, "Value.SumCase.MAP") val protoMap = proto.GenMap.newBuilder() entries.foreach { case (key, value) => @@ -494,18 +483,6 @@ object ValueCoder { } } - // The codomain and domain of the below functions are subject to change - // without warning or type change; they are stable with respect to - // each other and nothing else. As such, they are unsafe for - // general usage - - private[value] def valueToBytes[Cid]( - encodeCid: EncodeCid[Cid], - v: Value[Cid], - supportedVersions: VersionRange[ValueVersion] = ValueVersion.DevOutputVersions, - ): Either[EncodeError, Array[Byte]] = - encodeVersionedValue(encodeCid, v, supportedVersions).map(_.toByteArray) - private[value] def valueFromBytes[Cid]( decodeCid: DecodeCid[Cid], bytes: Array[Byte], diff --git a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/ValueVersion.scala b/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/ValueVersion.scala deleted file mode 100644 index f809aa48f6..0000000000 --- a/daml-lf/transaction/src/main/scala/com/digitalasset/daml/lf/value/ValueVersion.scala +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package com.daml.lf -package value - -import com.daml.lf.value.Value._ -import com.daml.lf.data.{FrontStack, FrontStackCons, ImmArray} -import scalaz.NonEmptyList - -import scala.Ordering.Implicits.infixOrderingOps -import scala.annotation.tailrec - -final case class ValueVersion(protoValue: String) - -/** - * Currently supported versions of the DAML-LF value specification. - */ -object ValueVersion - extends LfVersions( - versionsAscending = NonEmptyList(new ValueVersion("6"), new ValueVersion("dev")))( - _.protoValue, - ) { - - private[lf] implicit val Ordering: Ordering[ValueVersion] = mkOrdering - - private[value] val minVersion = ValueVersion("6") - private[value] val minGenMap = ValueVersion("dev") - private[value] val minContractIdV1 = ValueVersion("dev") - - // Older versions are deprecated https://github.com/digital-asset/daml/issues/5220 - private[lf] val StableOutputVersions: VersionRange[ValueVersion] = - VersionRange(ValueVersion("6"), ValueVersion("6")) - - private[lf] val DevOutputVersions: VersionRange[ValueVersion] = - StableOutputVersions.copy(max = acceptedVersions.last) - - private[lf] def assignVersion[Cid]( - v0: Value[Cid], - supportedVersions: VersionRange[ValueVersion] = StableOutputVersions, - ): Either[String, ValueVersion] = { - @tailrec - def go( - currentVersion: ValueVersion, - values0: FrontStack[Value[Cid]], - ): Either[String, ValueVersion] = { - if (currentVersion == maxVersion) { - Right(currentVersion) - } else { - values0 match { - case FrontStack() => Right(currentVersion) - case FrontStackCons(value, values) => - value match { - // for things supported since version 1, we do not need to check - case ValueRecord(_, fs) => go(currentVersion, fs.map(v => v._2) ++: values) - case ValueVariant(_, _, arg) => go(currentVersion, arg +: values) - case ValueList(vs) => go(currentVersion, vs.toImmArray ++: values) - case ValueContractId(_) | ValueInt64(_) | ValueText(_) | ValueTimestamp(_) | - ValueParty(_) | ValueBool(_) | ValueDate(_) | ValueUnit => - go(currentVersion, values) - case ValueNumeric(_) => - go(currentVersion, values) - case ValueOptional(x) => - go(currentVersion, ImmArray(x.toList) ++: values) - case ValueTextMap(map) => - go(currentVersion, map.values ++: values) - // for things added after version 6, we raise the minimum if present - case ValueGenMap(entries) => - val newValues = entries.iterator.foldLeft(values) { - case (acc, (key, value)) => key +: value +: acc - } - go(currentVersion max minGenMap, newValues) - case ValueEnum(_, _) => - go(currentVersion, values) - } - } - } - } - - go(supportedVersions.min, FrontStack(v0)) match { - case Right(inferredVersion) if supportedVersions.max < inferredVersion => - Left(s"inferred version $inferredVersion is not supported") - case res => - res - } - - } - - @throws[IllegalArgumentException] - private[lf] def assertAssignVersion[Cid]( - v0: Value[Cid], - supportedVersions: VersionRange[ValueVersion] = DevOutputVersions, - ): ValueVersion = - data.assertRight(assignVersion(v0, supportedVersions)) - - private[lf] def asVersionedValue[Cid]( - value: Value[Cid], - supportedVersions: VersionRange[ValueVersion] = DevOutputVersions, - ): Either[String, VersionedValue[Cid]] = - assignVersion(value, supportedVersions).map(VersionedValue(_, value)) - - @throws[IllegalArgumentException] - private[lf] def assertAsVersionedValue[Cid]( - value: Value[Cid], - supportedVersions: VersionRange[ValueVersion] = DevOutputVersions, - ): VersionedValue[Cid] = - data.assertRight(asVersionedValue(value, supportedVersions)) -} diff --git a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala index e9b3f79453..e661dc4656 100644 --- a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala +++ b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionCoderSpec.scala @@ -48,7 +48,7 @@ class TransactionCoderSpec } "do NodeCreate" in { - forAll(malformedCreateNodeGen, transactionVersionGen, transactionVersionGen) { + forAll(malformedCreateNodeGen, transactionVersionGen(), transactionVersionGen()) { (createNode, version1, version2) => val (nodeVersion, txVersion) = inIncreasingOrder(version1, version2) val versionedNode = createNode.updateVersion(nodeVersion) @@ -76,7 +76,7 @@ class TransactionCoderSpec } "do NodeFetch" in { - forAll(fetchNodeGen, transactionVersionGen, transactionVersionGen) { + forAll(fetchNodeGen, transactionVersionGen(), transactionVersionGen()) { (fetchNode, version1, version2) => val (nodeVersion, txVersion) = inIncreasingOrder(version1, version2) @@ -107,7 +107,7 @@ class TransactionCoderSpec } "do NodeExercises" in { - forAll(danglingRefExerciseNodeGen, transactionVersionGen, transactionVersionGen) { + forAll(danglingRefExerciseNodeGen, transactionVersionGen(), transactionVersionGen()) { (exerciseNode, version1, version2) => val (nodeVersion, txVersion) = inIncreasingOrder(version1, version2) @@ -176,7 +176,7 @@ class TransactionCoderSpec } forAll(noDanglingRefGenTransaction, minSuccessful(50)) { tx => - forAll(transactionVersionGen, transactionVersionGen, minSuccessful(20)) { + forAll(transactionVersionGen(), transactionVersionGen(), minSuccessful(20)) { (txVer1, txVer2) => import scalaz.std.tuple._ import scalaz.syntax.bifunctor._ @@ -242,7 +242,7 @@ class TransactionCoderSpec ValueCoder.CidDecoder, encodedTxWithBadTxVer, ) shouldEqual Left( - DecodeError(s"Unsupported transaction version $badTxVer"), + DecodeError(s"Unsupported transaction version '$badTxVer'"), ) } } @@ -330,7 +330,11 @@ class TransactionCoderSpec "fail if try to encode a node in a version newer than the transaction" in { - forAll(danglingRefGenNode, transactionVersionGen, transactionVersionGen, minSuccessful(10)) { + forAll( + danglingRefGenNode, + transactionVersionGen(), + transactionVersionGen(), + minSuccessful(10)) { case ((nodeId, node), version1, version2) => whenever(version1 != version2) { val (txVersion, nodeVersion) = inIncreasingOrder(version1, version2) @@ -386,8 +390,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) { diff --git a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala index 1ba77303a3..bdb791b1ee 100644 --- a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala +++ b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionSpec.scala @@ -158,7 +158,7 @@ class TransactionSpec extends AnyFreeSpec with Matchers with ScalaCheckDrivenPro } "fail if version is different" in { - val versions = TransactionVersion.Values + val versions = TransactionVersion.All def diffVersion(v: TransactionVersion) = { val randomVersion = versions(Random.nextInt(versions.length - 1)) if (randomVersion != v) randomVersion else versions.last diff --git a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionVersionSpec.scala b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionVersionSpec.scala index e0f980447b..470147a94a 100644 --- a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionVersionSpec.scala +++ b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/transaction/TransactionVersionSpec.scala @@ -4,7 +4,6 @@ package com.daml.lf package transaction -import value.ValueVersion import com.daml.lf.language.LanguageVersion import org.scalatest.prop.TableDrivenPropertyChecks import org.scalatest.matchers.should.Matchers @@ -32,21 +31,4 @@ class TransactionVersionSpec extends AnyWordSpec with Matchers with TableDrivenP } } - - "TransactionVersion.assignValueVersion" should { - "be stable" in { - - val testCases = Table( - "input" -> "output", - V10 -> ValueVersion("6"), - VDev -> ValueVersion("dev") - ) - - forEvery(testCases) { (input, expectedOutput) => - TransactionVersion.assignValueVersion(input) shouldBe expectedOutput - } - - } - } - } diff --git a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/value/ValueCoderSpec.scala b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/value/ValueCoderSpec.scala index b2844dd2d9..014895226a 100644 --- a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/value/ValueCoderSpec.scala +++ b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/value/ValueCoderSpec.scala @@ -6,8 +6,8 @@ package com.daml.lf.value import com.daml.lf.EitherAssertions import com.daml.lf.data.Ref.Party import com.daml.lf.data._ +import com.daml.lf.transaction.TransactionVersion import com.daml.lf.value.Value._ -import com.daml.lf.value.ValueCoder.DecodeError import com.daml.lf.value.{ValueOuterClass => proto} import org.scalacheck.Shrink import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks @@ -25,13 +25,6 @@ class ValueCoderSpec implicit val noStringShrink: Shrink[String] = Shrink.shrinkAny[String] - private[this] val lastDecimalVersion = ValueVersion("5") - - private[this] val firstNumericVersion = ValueVersion("6") - - private[this] val defaultValueVersion = ValueVersion.acceptedVersions.lastOption getOrElse sys - .error("there are no allowed versions! impossible! but could it be?") - implicit override val generatorDrivenConfig: PropertyCheckConfiguration = PropertyCheckConfiguration(minSuccessful = 1000) @@ -39,38 +32,14 @@ class ValueCoderSpec "do Int" in { forAll("Int64 (Long) invariant") { i: Long => val value = ValueInt64(i) - testRoundTrip(value) + testRoundTrip(TransactionVersion.minVersion, value) } } "do Bool" in { forAll("Bool invariant") { b: Boolean => val value = ValueBool(b) - testRoundTrip(value) - } - } - - "do Decimal" in { - forAll("Decimal (BigDecimal) invariant") { d: BigDecimal => - // we are filtering on decimals invariant under string conversion - whenever(Decimal.fromBigDecimal(d).isRight) { - val Right(dec) = Decimal.fromBigDecimal(d) - val value = ValueNumeric(dec) - val recoveredDecimal = ValueCoder.decodeValue[ContractId]( - ValueCoder.CidDecoder, - lastDecimalVersion, - assertRight( - ValueCoder - .encodeValue[ContractId](ValueCoder.CidEncoder, lastDecimalVersion, value), - ), - ) match { - case Right(ValueNumeric(d)) => d - case x => fail(s"should have got a decimal back, got $x") - } - Numeric.toUnscaledString(value.value) shouldEqual Numeric.toUnscaledString( - recoveredDecimal, - ) - } + testRoundTrip(TransactionVersion.minVersion, value) } } @@ -85,10 +54,13 @@ class ValueCoderSpec val value = ValueNumeric(dec) val recoveredDecimal = ValueCoder.decodeValue[ContractId]( ValueCoder.CidDecoder, - firstNumericVersion, + TransactionVersion.minVersion, assertRight( ValueCoder - .encodeValue[ContractId](ValueCoder.CidEncoder, firstNumericVersion, value), + .encodeValue[ContractId]( + ValueCoder.CidEncoder, + TransactionVersion.minVersion, + value), ), ) match { case Right(ValueNumeric(x)) => x @@ -104,98 +76,77 @@ class ValueCoderSpec "do Text" in { forAll("Text (String) invariant") { t: String => val value = ValueText(t) - testRoundTrip(value) + testRoundTrip(TransactionVersion.minVersion, value) } } "do Party" in { forAll(party) { p: Party => val value = ValueParty(p) - testRoundTrip(value) + testRoundTrip(TransactionVersion.minVersion, value) } } "do TimeStamp" in { forAll(timestampGen) { t: Time.Timestamp => // TODO: fails with Longs - testRoundTrip(ValueTimestamp(t)) + testRoundTrip(TransactionVersion.minVersion, ValueTimestamp(t)) } } "do Date" in { forAll(dateGen) { d: Time.Date => - testRoundTrip(ValueDate(d)) + testRoundTrip(TransactionVersion.minVersion, ValueDate(d)) } } "do ContractId" in { forAll(coidValueGen) { v: Value[ContractId] => - testRoundTrip(v) + testRoundTrip(TransactionVersion.minVersion, v) } } - "do ContractId V0 in any ValueVersion" in forAll(coidValueGen, valueVersionGen())( - testRoundTripWithVersion - ) - - "do ContractId in any ValueVersion" in forAll( - coidValueGen, - valueVersionGen(ValueVersion.minContractIdV1))( + "do ContractId V0 in any ValueVersion" in forAll(coidValueGen, transactionVersionGen())( testRoundTripWithVersion ) "do lists" in { forAll(valueListGen) { v: ValueList[ContractId] => - testRoundTrip(v) + testRoundTrip(TransactionVersion.minVersion, v) } } "do optionals" in { forAll(valueOptionalGen) { v: ValueOptional[ContractId] => - testRoundTrip(v) + testRoundTrip(TransactionVersion.minVersion, v) } } "do maps" in { forAll(valueMapGen) { v: ValueTextMap[ContractId] => - testRoundTrip(v) + testRoundTrip(TransactionVersion.minVersion, v) } } "do genMaps" in { forAll(valueGenMapGen) { v: ValueGenMap[ContractId] => - testRoundTrip(v) + testRoundTrip(TransactionVersion.minGenMap, v) } } "do variant" in { forAll(variantGen) { v: ValueVariant[ContractId] => - testRoundTrip(v) + testRoundTrip(TransactionVersion.minVersion, v) } } "do record" in { forAll(recordGen) { v: ValueRecord[ContractId] => - testRoundTrip(v) + testRoundTrip(TransactionVersion.minVersion, v) } } "do unit" in { - val recovered = ValueCoder.decodeValue( - ValueCoder.CidDecoder, - defaultValueVersion, - assertRight( - ValueCoder.encodeValue[ContractId](ValueCoder.CidEncoder, defaultValueVersion, ValueUnit), - ), - ) - val fromToBytes = ValueCoder.valueFromBytes( - ValueCoder.CidDecoder, - ValueCoder - .valueToBytes(ValueCoder.CidEncoder, ValueUnit) - .toOption - .get, - ) - Right(ValueUnit) shouldEqual fromToBytes - recovered shouldEqual Right(ValueUnit) + testRoundTrip(TransactionVersion.minVersion, ValueUnit) } "do identifier" in { @@ -204,81 +155,45 @@ class ValueCoderSpec } } - "do identifier with supported override version" in forAll(idGen, valueVersionGen()) { (i, _) => - val ei = ValueCoder.encodeIdentifier(i) - ValueCoder.decodeIdentifier(ei) shouldEqual Right(i) + "do identifier with supported override version" in forAll(idGen, transactionVersionGen()) { + (i, _) => + val ei = ValueCoder.encodeIdentifier(i) + ValueCoder.decodeIdentifier(ei) shouldEqual Right(i) } "do versioned value with supported override version" in forAll(versionedValueGen) { case VersionedValue(version, value) => testRoundTripWithVersion(value, version) } - - "do versioned value with assigned version" in forAll(valueGen) { v: Value[ContractId] => - testRoundTripWithVersion(v, ValueVersion.assertAssignVersion(v)) - } - - "versioned value should pass serialization if unsupported override version provided" in - forAll(valueGen, unsupportedValueVersionGen) { - (value: Value[ContractId], badVer: ValueVersion) => - ValueVersion.acceptedVersions.contains(badVer) shouldBe false - - val actual: proto.VersionedValue = assertRight( - ValueCoder - .encodeVersionedValueWithCustomVersion( - ValueCoder.CidEncoder, - VersionedValue(badVer, value), - ), - ) - - actual.getVersion shouldEqual badVer.protoValue - } - - "versioned value should fail deserialization if version is not supported" in - forAll(valueGen, unsupportedValueVersionGen) { - (value: Value[ContractId], badVer: ValueVersion) => - ValueVersion.acceptedVersions.contains(badVer) shouldBe false - - val protoWithUnsupportedVersion: proto.VersionedValue = - assertRight( - ValueCoder.encodeVersionedValueWithCustomVersion( - ValueCoder.CidEncoder, - VersionedValue(badVer, value), - ), - ) - protoWithUnsupportedVersion.getVersion shouldEqual badVer.protoValue - - val actual: Either[DecodeError, VersionedValue[ContractId]] = - ValueCoder.decodeVersionedValue(ValueCoder.CidDecoder, protoWithUnsupportedVersion) - - actual shouldEqual Left(DecodeError(s"Unsupported value version ${badVer.protoValue}")) - } } - def testRoundTrip(value: Value[ContractId]): Assertion = { + def testRoundTrip(version: TransactionVersion, value: Value[ContractId]): Assertion = { val recovered = ValueCoder.decodeValue( ValueCoder.CidDecoder, - defaultValueVersion, - assertRight( - ValueCoder.encodeValue[ContractId](ValueCoder.CidEncoder, defaultValueVersion, value)), + version, + assertRight(ValueCoder.encodeValue[ContractId](ValueCoder.CidEncoder, version, value)), ) + val bytes = + assertRight( + ValueCoder.encodeVersionedValue( + ValueCoder.CidEncoder, + VersionedValue(version, value), + ) + ).toByteArray + val fromToBytes = ValueCoder.valueFromBytes( ValueCoder.CidDecoder, - assertRight( - ValueCoder - .valueToBytes[ContractId](ValueCoder.CidEncoder, value)), + bytes, ) Right(value) shouldEqual recovered Right(value) shouldEqual fromToBytes } - def testRoundTripWithVersion(value0: Value[ContractId], version: ValueVersion): Assertion = { - ValueVersion.acceptedVersions.contains(version) shouldBe true - + def testRoundTripWithVersion( + value0: Value[ContractId], + version: TransactionVersion): Assertion = { val encoded: proto.VersionedValue = assertRight( ValueCoder - .encodeVersionedValueWithCustomVersion( - ValueCoder.CidEncoder, - VersionedValue(version, value0)), + .encodeVersionedValue(ValueCoder.CidEncoder, VersionedValue(version, value0)), ) val decoded: VersionedValue[ContractId] = assertRight( ValueCoder.decodeVersionedValue(ValueCoder.CidDecoder, encoded), diff --git a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/value/ValueSpec.scala b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/value/ValueSpec.scala index c7a7fcc388..a0d1a8cffb 100644 --- a/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/value/ValueSpec.scala +++ b/daml-lf/transaction/src/test/scala/com/digitalasset/daml/lf/value/ValueSpec.scala @@ -7,6 +7,7 @@ package value import data.{Bytes, ImmArray, Ref} import Value._ import Ref.{Identifier, Name} +import com.daml.lf.transaction.TransactionVersion import test.ValueGenerators.{coidGen, idGen, nameGen} import test.TypedValueGenerators.{RNil, genAddend, ValueAddend => VA} import com.daml.scalatest.Unnatural @@ -57,10 +58,10 @@ class ValueSpec "does not bump version when" - { "ensureNoCid is used " in { - val value = VersionedValue[ContractId](ValueVersion.minVersion, ValueUnit) + val value = VersionedValue[ContractId](TransactionVersion.minVersion, ValueUnit) val contract = ContractInst(tmplId, value, "agreed") - value.ensureNoCid.map(_.version) shouldBe Right(ValueVersion.minVersion) - contract.ensureNoCid.map(_.arg.version) shouldBe Right(ValueVersion.minVersion) + value.ensureNoCid.map(_.version) shouldBe Right(TransactionVersion.minVersion) + contract.ensureNoCid.map(_.arg.version) shouldBe Right(TransactionVersion.minVersion) } diff --git a/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V38__Update_value_versions.scala b/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V38__Update_value_versions.scala index f649063d0e..6243e42a43 100644 --- a/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V38__Update_value_versions.scala +++ b/ledger/participant-integration-api/src/main/scala/db/migration/postgres/V38__Update_value_versions.scala @@ -20,7 +20,7 @@ private[migration] final class V38__Update_value_versions extends BaseJavaMigrat private[this] val batchSize = 1000 - private[this] val stableValueVersion = lf.value.ValueVersion("6") + private[this] val stableValueVersion = lf.transaction.TransactionVersion.V10 private[this] val stableValueVersionAsInt = stableValueVersion.protoValue.toInt private[this] val SELECT_EVENTS = diff --git a/ledger/participant-integration-api/src/main/scala/db/migration/translation/ValueSerializer.scala b/ledger/participant-integration-api/src/main/scala/db/migration/translation/ValueSerializer.scala index 45dd242f63..8a96c864a2 100644 --- a/ledger/participant-integration-api/src/main/scala/db/migration/translation/ValueSerializer.scala +++ b/ledger/participant-integration-api/src/main/scala/db/migration/translation/ValueSerializer.scala @@ -17,7 +17,7 @@ private[migration] object ValueSerializer { private[translation] object DeprecatedValueVersionsError { val DeprecatedValueVersions = Set("1", "2", "3", "4", "5") - val UnsupportedErrorMessage = """Unsupported value version (\d)""".r + val UnsupportedErrorMessage = """Unsupported transaction version '(\d)'""".r def unapply[X](arg: Either[ValueCoder.DecodeError, X]): Option[String] = arg match { diff --git a/ledger/participant-integration-api/src/main/scala/platform/store/serialization/ValueSerializer.scala b/ledger/participant-integration-api/src/main/scala/platform/store/serialization/ValueSerializer.scala index 688bc50d50..6346ea4e46 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/store/serialization/ValueSerializer.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/store/serialization/ValueSerializer.scala @@ -16,7 +16,7 @@ private[platform] object ValueSerializer { errorContext: => String, ): Array[Byte] = ValueCoder - .encodeVersionedValueWithCustomVersion(ValueCoder.CidEncoder, value) + .encodeVersionedValue(ValueCoder.CidEncoder, value) .fold(error => sys.error(s"$errorContext (${error.errorMessage})"), _.toByteArray) private def deserializeValueHelper( diff --git a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoDivulgenceSpec.scala b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoDivulgenceSpec.scala index 5c49d62a32..f45e81ca01 100644 --- a/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoDivulgenceSpec.scala +++ b/ledger/participant-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoDivulgenceSpec.scala @@ -11,7 +11,6 @@ import com.daml.lf.transaction.Node.{KeyWithMaintainers, NodeCreate, NodeExercis import com.daml.lf.transaction.TransactionVersion import com.daml.lf.transaction.test.TransactionBuilder import com.daml.lf.value.Value.{ContractInst, ValueParty, VersionedValue} -import com.daml.lf.value.ValueVersion import com.daml.platform.store.entries.LedgerEntry import org.scalatest.{Inside, LoneElement} import org.scalatest.flatspec.AsyncFlatSpec @@ -138,7 +137,7 @@ private[dao] trait JdbcLedgerDaoDivulgenceSpec extends LoneElement with Inside { template = someContractInstance.template, agreementText = someContractInstance.agreementText, arg = VersionedValue( - version = ValueVersion("6"), + version = TransactionVersion.V10, value = someContractInstance.arg ) ) diff --git a/ledger/participant-state/kvutils/tools/codec-benchmark/src/benchmark/scala/com/daml/lf/benchmark/package.scala b/ledger/participant-state/kvutils/tools/codec-benchmark/src/benchmark/scala/com/daml/lf/benchmark/package.scala index bd0516de22..5b9f775c24 100644 --- a/ledger/participant-state/kvutils/tools/codec-benchmark/src/benchmark/scala/com/daml/lf/benchmark/package.scala +++ b/ledger/participant-state/kvutils/tools/codec-benchmark/src/benchmark/scala/com/daml/lf/benchmark/package.scala @@ -10,11 +10,11 @@ import com.daml.lf.transaction.TransactionCoder.{ encodeTransaction } import com.daml.lf.transaction.TransactionOuterClass.Transaction -import com.daml.lf.transaction.{NodeId, VersionedTransaction} +import com.daml.lf.transaction.{NodeId, TransactionVersion, VersionedTransaction} import com.daml.lf.value.Value.ContractId import com.daml.lf.value.ValueCoder._ import com.daml.lf.value.ValueOuterClass.VersionedValue -import com.daml.lf.value.{Value, ValueVersion} +import com.daml.lf.value.Value import com.google.protobuf.ByteString package object benchmark { @@ -32,7 +32,7 @@ package object benchmark { /** * This is the output of a successful call to - * [[com.daml.lf.value.ValueCoder.encodeValue]]. + * [[com.daml.lf.value.ValueCoder.encodeVersionedValue]]. * It's the in-memory representation of the Protobuf message that * describes a value, not its serialized form. */ @@ -89,6 +89,6 @@ package object benchmark { encodeTransaction(NidEncoder, CidEncoder, transaction) private def encode(value: DecodedValue): EncodeResult[EncodedValue] = - encodeVersionedValue(CidEncoder, value, ValueVersion.DevOutputVersions) + encodeVersionedValue(CidEncoder, TransactionVersion.VDev, value) }