diff --git a/core/shared/src/main/scala/sigma/VersionContext.scala b/core/shared/src/main/scala/sigma/VersionContext.scala index 6ede0a1556..9efb5911e7 100644 --- a/core/shared/src/main/scala/sigma/VersionContext.scala +++ b/core/shared/src/main/scala/sigma/VersionContext.scala @@ -24,7 +24,10 @@ case class VersionContext(activatedVersion: Byte, ergoTreeVersion: Byte) { /** @return true, if the activated script version of Ergo protocol on the network is * including v6.0 update. */ - def isV6SoftForkActivated: Boolean = activatedVersion >= V6SoftForkVersion + def isV3OrLaterErgoTreeVersion: Boolean = ergoTreeVersion >= V6SoftForkVersion + + def isV6Activated: Boolean = activatedVersion >= V6SoftForkVersion + } object VersionContext { @@ -104,4 +107,8 @@ object VersionContext { } } + def fromBlockVersion(blockVersion: Byte): VersionContext = { + VersionContext((blockVersion - 1).toByte, (blockVersion - 1).toByte) + } + } diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index 3e915cf304..a87b9a8076 100644 --- a/core/shared/src/main/scala/sigma/ast/SType.scala +++ b/core/shared/src/main/scala/sigma/ast/SType.scala @@ -114,7 +114,7 @@ object SType { /** All pre-defined types should be listed here. Note, NoType is not listed. * Should be in sync with sigmastate.lang.Types.predefTypes. */ def allPredefTypes: Seq[SType] = { - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { v6PredefTypes } else { v5PredefTypes @@ -164,7 +164,7 @@ object SType { private val v6TypesMap = v6Types.map { t => (t.typeId, t) }.toMap - def types: Map[Byte, STypeCompanion] = if (VersionContext.current.isV6SoftForkActivated) { + def types: Map[Byte, STypeCompanion] = if (VersionContext.current.isV3OrLaterErgoTreeVersion) { v6TypesMap } else { v5TypesMap @@ -191,7 +191,7 @@ object SType { case SInt => x.isInstanceOf[Int] case SLong => x.isInstanceOf[Long] case SBigInt => x.isInstanceOf[BigInt] - case SUnsignedBigInt if VersionContext.current.isV6SoftForkActivated => x.isInstanceOf[UnsignedBigInt] + case SUnsignedBigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => x.isInstanceOf[UnsignedBigInt] case SGroupElement => x.isInstanceOf[GroupElement] case SSigmaProp => x.isInstanceOf[SigmaProp] case SBox => x.isInstanceOf[Box] @@ -409,8 +409,8 @@ case object SByte extends SPrimType with SEmbeddable with SNumericType with SMon case s: Short => s.toByteExact case i: Int => i.toByteExact case l: Long => l.toByteExact - case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toByte // toByteExact from int is called under the hood - case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toByte // toByteExact from int is called under the hood + case bi: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => bi.toByte // toByteExact from int is called under the hood + case ubi: UnsignedBigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => ubi.toByte // toByteExact from int is called under the hood case _ => sys.error(s"Cannot downcast value $v to the type $this") } } @@ -432,8 +432,8 @@ case object SShort extends SPrimType with SEmbeddable with SNumericType with SMo case s: Short => s case i: Int => i.toShortExact case l: Long => l.toShortExact - case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toShort // toShortExact from int is called under the hood - case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toShort // toShortExact from int is called under the hood + case bi: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => bi.toShort // toShortExact from int is called under the hood + case ubi: UnsignedBigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => ubi.toShort // toShortExact from int is called under the hood case _ => sys.error(s"Cannot downcast value $v to the type $this") } } @@ -457,8 +457,8 @@ case object SInt extends SPrimType with SEmbeddable with SNumericType with SMono case s: Short => s.toInt case i: Int => i case l: Long => l.toIntExact - case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toInt - case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toInt + case bi: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => bi.toInt + case ubi: UnsignedBigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => ubi.toInt case _ => sys.error(s"Cannot downcast value $v to the type $this") } } @@ -484,8 +484,8 @@ case object SLong extends SPrimType with SEmbeddable with SNumericType with SMon case s: Short => s.toLong case i: Int => i.toLong case l: Long => l - case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toLong - case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toLong + case bi: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => bi.toLong + case ubi: UnsignedBigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => ubi.toLong case _ => sys.error(s"Cannot downcast value $v to the type $this") } } @@ -512,7 +512,7 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM case x: Short => CBigInt(BigInteger.valueOf(x.toLong)) case x: Int => CBigInt(BigInteger.valueOf(x.toLong)) case x: Long => CBigInt(BigInteger.valueOf(x)) - case x: BigInt if VersionContext.current.isV6SoftForkActivated => x + case x: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => x case _ => sys.error(s"Cannot upcast value $v to the type $this") } } @@ -524,7 +524,7 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM case x: Short => CBigInt(BigInteger.valueOf(x.toLong)) case x: Int => CBigInt(BigInteger.valueOf(x.toLong)) case x: Long => CBigInt(BigInteger.valueOf(x)) - case x: BigInt if VersionContext.current.isV6SoftForkActivated => x + case x: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => x case _ => sys.error(s"Cannot downcast value $v to the type $this") } } diff --git a/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala b/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala index 2d6a4a5cdf..dbaa430b69 100644 --- a/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala +++ b/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala @@ -150,7 +150,7 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil case obj: CollOverArray[_] if obj.tItem == this.tItem => java.util.Objects.deepEquals(obj.toArray, this.toArray) case obj: PairColl[Any, Any] if obj.tItem == this.tItem => - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { equalsPairCollWithCollOverArray(obj, this.asInstanceOf[CollOverArray[Any]]) } else { false @@ -282,7 +282,7 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R case that: PairColl[_, _] if that.tItem == this.tItem => ls == that.ls && rs == that.rs case that: CollOverArray[Any] if that.tItem == this.tItem => - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { equalsPairCollWithCollOverArray(this.asInstanceOf[PairColl[Any, Any]], that) } else { false diff --git a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala index 175e91fbcb..8884fc8ec7 100644 --- a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala +++ b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala @@ -34,7 +34,7 @@ class CoreDataSerializer { val data = v.asInstanceOf[BigInt].toBigInteger.toByteArray w.putUShort(data.length) w.putBytes(data) - case SUnsignedBigInt if VersionContext.current.isV6SoftForkActivated => + case SUnsignedBigInt if VersionContext.current.isV6Activated => val data = BigIntegers.asUnsignedByteArray(v.asInstanceOf[CUnsignedBigInt].wrappedValue) w.putUShort(data.length) w.putBytes(data) @@ -73,7 +73,7 @@ class CoreDataSerializer { i += 1 } - case SOption(elemType) if VersionContext.current.isV6SoftForkActivated => + case SOption(elemType) if VersionContext.current.isV6Activated => val o = v.asInstanceOf[Option[elemType.WrappedType]] w.putOption(o){case (w, v) => serialize(v, elemType, w) @@ -113,7 +113,7 @@ class CoreDataSerializer { } val valueBytes = r.getBytes(size) CBigInt(new BigInteger(valueBytes)) - case SUnsignedBigInt if VersionContext.current.isV6SoftForkActivated => + case SUnsignedBigInt if VersionContext.current.isV6Activated => val size: Short = r.getUShort().toShort if (size > SBigInt.MaxSizeInBytes) { throw SerializerException(s"BigInt value doesn't not fit into ${SBigInt.MaxSizeInBytes} bytes: $size") @@ -135,7 +135,7 @@ class CoreDataSerializer { }.toArray[Any] val coll = Colls.fromArray(arr)(sigma.AnyType) Evaluation.toDslTuple(coll, tuple) - case tOption: SOption[_] if VersionContext.current.isV6SoftForkActivated => + case tOption: SOption[_] if VersionContext.current.isV6Activated => r.getOption[tOption.ElemWrappedType] { deserialize(tOption.elemType, r).asInstanceOf[tOption.ElemWrappedType] } diff --git a/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala b/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala index aa5d43e229..51f4c834af 100644 --- a/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala +++ b/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala @@ -5,7 +5,7 @@ import sigma.VersionContext import sigma.ast.SCollectionType.{CollectionTypeCode, NestedCollectionTypeCode} import sigma.ast._ import sigma.util.safeNewArray -import sigma.validation.ValidationRules.{CheckPrimitiveTypeCode, CheckTypeCode} +import sigma.validation.ValidationRules.{CheckPrimitiveTypeCode, CheckPrimitiveTypeCodeV6, CheckTypeCode, CheckTypeCodeV6} import java.nio.charset.StandardCharsets @@ -14,7 +14,12 @@ class TypeSerializer { import TypeSerializer._ def getEmbeddableType(code: Int): SType = { - CheckPrimitiveTypeCode(code.toByte) + // todo : add unsigned bit int to embeddable id to type + if (VersionContext.current.isV6Activated) { + CheckPrimitiveTypeCodeV6(code.toByte) + } else { + CheckPrimitiveTypeCode(code.toByte) + } embeddableIdToType(code) } @@ -200,7 +205,7 @@ class TypeSerializer { case SHeader.typeCode => SHeader case SPreHeader.typeCode => SPreHeader case SGlobal.typeCode => SGlobal - case SFunc.FuncTypeCode if VersionContext.current.isV6SoftForkActivated => + case SFunc.FuncTypeCode if VersionContext.current.isV3OrLaterErgoTreeVersion => val tdLength = r.getUByte() val tDom = (1 to tdLength).map { _ => @@ -215,9 +220,13 @@ class TypeSerializer { } SFunc(tDom, tRange, tpeParams) case _ => - // todo: 6.0: replace 1008 check with identical behavior but other opcode, to activate - // ReplacedRule(1008 -> new opcode) during 6.0 activation - CheckTypeCode(c.toByte) + // the #1008 check replaced with one with identical behavior but different opcode (1018), to activate + // ReplacedRule(1008 -> 1018) during 6.0 activation + if (VersionContext.current.isV6Activated) { + CheckTypeCodeV6(c.toByte) + } else { + CheckTypeCode(c.toByte) + } NoType } } @@ -243,7 +252,7 @@ object TypeSerializer extends TypeSerializer { /** The list of embeddable types, i.e. types that can be combined with type constructor for optimized encoding. * For each embeddable type `T`, and type constructor `C`, the type `C[T]` can be represented by single byte. */ def embeddableIdToType = { - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { embeddableV6 } else { embeddableV5 diff --git a/core/shared/src/main/scala/sigma/validation/RuleStatus.scala b/core/shared/src/main/scala/sigma/validation/RuleStatus.scala index 3d0451b240..ae1a380898 100644 --- a/core/shared/src/main/scala/sigma/validation/RuleStatus.scala +++ b/core/shared/src/main/scala/sigma/validation/RuleStatus.scala @@ -32,7 +32,7 @@ case object DisabledRule extends RuleStatus { * @see `ValidationSettings.isSoftFork` * @param newRuleId id of a new rule which replaces the rule marked with this status */ -case class ReplacedRule(newRuleId: Short) extends RuleStatus { +case class ReplacedRule(newRuleId: Short) extends RuleStatus { val statusCode: Byte = RuleStatus.ReplacedRuleCode } diff --git a/core/shared/src/main/scala/sigma/validation/SigmaValidationSettings.scala b/core/shared/src/main/scala/sigma/validation/SigmaValidationSettings.scala index 51fb97c8ad..9063f88bfb 100644 --- a/core/shared/src/main/scala/sigma/validation/SigmaValidationSettings.scala +++ b/core/shared/src/main/scala/sigma/validation/SigmaValidationSettings.scala @@ -1,5 +1,7 @@ package sigma.validation +import sigma.VersionContext + /** * Configuration of validation. Each `ValidationRule` instance should be * implemented as an `object` to facilitate type-safe usage. It then should be @@ -48,7 +50,11 @@ abstract class SigmaValidationSettings extends Iterable[(Short, (ValidationRule, def isSoftFork(ruleId: Short, ve: ValidationException): Boolean = { val infoOpt = get(ruleId) infoOpt match { - case Some((_, ReplacedRule(_))) => true + case Some((vr, ReplacedRule(_))) => if ((vr.id == 1011 || vr.id == 1007 || vr.id == 1008) && VersionContext.current.isV6Activated) { + false + } else { + true + } case Some((rule, status)) => rule.isSoftFork(this, rule.id, status, ve.args) case None => false } diff --git a/core/shared/src/main/scala/sigma/validation/ValidationRules.scala b/core/shared/src/main/scala/sigma/validation/ValidationRules.scala index 249e2fce0a..3cae0a3f27 100644 --- a/core/shared/src/main/scala/sigma/validation/ValidationRules.scala +++ b/core/shared/src/main/scala/sigma/validation/ValidationRules.scala @@ -1,6 +1,6 @@ package sigma.validation -import sigma.SigmaException +import sigma.{SigmaException, VersionContext} import sigma.ast.{SGlobal, SOption, TypeCodes} import sigma.serialization.{ReaderPositionLimitExceeded, SerializerException} import sigma.util.Extensions.toUByte @@ -77,7 +77,7 @@ object ValidationRules { /** The id of the first validation rule. Can be used as the beginning of the rules id range. */ val FirstRuleId = 1000.toShort - object CheckPrimitiveTypeCode extends ValidationRule(1007, + class CheckPrimitiveTypeCodeTemplate(ruleId: Short) extends ValidationRule(ruleId, "Check the primitive type code is supported or is added via soft-fork") with SoftForkWhenCodeAdded { override protected lazy val settings: SigmaValidationSettings = coreSettings @@ -93,10 +93,14 @@ object ValidationRules { } } - object CheckTypeCode extends ValidationRule(1008, + object CheckPrimitiveTypeCode extends CheckPrimitiveTypeCodeTemplate(1007) + + object CheckPrimitiveTypeCodeV6 extends CheckPrimitiveTypeCodeTemplate(1017) + + class CheckTypeCodeTemplate(ruleId: Short) extends ValidationRule(ruleId, "Check the non-primitive type code is supported or is added via soft-fork") with SoftForkWhenCodeAdded { - override protected lazy val settings: SigmaValidationSettings = coreSettings + override protected def settings: SigmaValidationSettings = coreSettings final def apply[T](typeCode: Byte): Unit = { checkRule() @@ -109,10 +113,14 @@ object ValidationRules { } } + object CheckTypeCode extends CheckTypeCodeTemplate(1008) + + object CheckTypeCodeV6 extends CheckTypeCodeTemplate(1018) + object CheckSerializableTypeCode extends ValidationRule(1009, "Check the data values of the type (given by type code) can be serialized") with SoftForkWhenReplaced { - override protected lazy val settings: SigmaValidationSettings = coreSettings + override protected def settings: SigmaValidationSettings = coreSettings /** Creates an exception which is used as a cause when throwing a ValidationException. */ def throwValidationException(typeCode: Byte): Nothing = { @@ -141,7 +149,7 @@ object ValidationRules { object CheckTypeWithMethods extends ValidationRule(1010, "Check the type (given by type code) supports methods") with SoftForkWhenCodeAdded { - override protected lazy val settings: SigmaValidationSettings = coreSettings + override protected def settings: SigmaValidationSettings = coreSettings final def apply[T](typeCode: Byte, cond: Boolean): Unit = { checkRule() @@ -160,7 +168,7 @@ object ValidationRules { */ object CheckPositionLimit extends ValidationRule(1014, "Check that the Reader has not exceeded the position limit.") with SoftForkWhenReplaced { - override protected lazy val settings: SigmaValidationSettings = coreSettings + override protected def settings: SigmaValidationSettings = coreSettings /** Wraps the given cause into [[ValidationException]] and throws it. */ def throwValidationException(cause: ReaderPositionLimitExceeded): Nothing = { @@ -183,7 +191,7 @@ object ValidationRules { } } - private val ruleSpecs: Seq[ValidationRule] = Seq( + private val ruleSpecsV5: Seq[ValidationRule] = Seq( CheckPrimitiveTypeCode, CheckTypeCode, CheckSerializableTypeCode, @@ -191,13 +199,30 @@ object ValidationRules { CheckPositionLimit ) + private val ruleSpecsV6: Seq[ValidationRule] = Seq( + CheckPrimitiveTypeCodeV6, + CheckTypeCodeV6, + CheckSerializableTypeCode, + CheckTypeWithMethods, + CheckPositionLimit + ) + + private def ruleSpecs: Seq[ValidationRule] = { + if(VersionContext.current.isV6Activated) { + ruleSpecsV6 + } else { + ruleSpecsV5 + } + } + /** Validation settings that correspond to the current version of the ErgoScript implementation. * Different version of the code will have a different set of rules here. * This variable is globally available and can be use wherever checking of the rules is necessary. * This is immutable data structure, it can be augmented with RuleStates from block extension * sections of the blockchain, but that augmentation is only available in stateful context. */ - val coreSettings: SigmaValidationSettings = new MapSigmaValidationSettings({ + // todo: versioned cache here for efficiency + def coreSettings: SigmaValidationSettings = new MapSigmaValidationSettings({ val map = ruleSpecs.map(r => r.id -> (r, EnabledRule)).toMap assert(map.size == ruleSpecs.size, s"Duplicate ruleIds ${ruleSpecs.groupBy(_.id).filter(g => g._2.length > 1)}") map diff --git a/data/js/src/main/scala/sigma/Platform.scala b/data/js/src/main/scala/sigma/Platform.scala index 63c2ab5555..9db049b368 100644 --- a/data/js/src/main/scala/sigma/Platform.scala +++ b/data/js/src/main/scala/sigma/Platform.scala @@ -14,33 +14,33 @@ object Platform { private[sigma] def liftToConstant(obj: Any, builder: SigmaBuilder): Nullable[Constant[SType]] = { import builder._ obj match { - case arr: Array[Boolean] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SBoolean.type](arr, SBoolean)) - case arr: Array[Byte] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SByte.type](arr, SByte)) - case arr: Array[Short] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SShort.type](arr, SShort)) - case arr: Array[Int] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SInt.type](arr, SInt)) - case arr: Array[Long] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SLong.type](arr, SLong)) - case arr: Array[BigInteger] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SBigInt.type](arr.map[BigInt](n => CBigInt(n)), SBigInt)) - case arr: Array[String] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SString.type](arr, SString)) + case arr: Array[Boolean] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SBoolean.type](arr, SBoolean)) + case arr: Array[Byte] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SByte.type](arr, SByte)) + case arr: Array[Short] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SShort.type](arr, SShort)) + case arr: Array[Int] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SInt.type](arr, SInt)) + case arr: Array[Long] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SLong.type](arr, SLong)) + case arr: Array[BigInteger] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SBigInt.type](arr.map[BigInt](n => CBigInt(n)), SBigInt)) + case arr: Array[String] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SString.type](arr, SString)) case v: AnyValue => val tpe = Evaluation.rtypeToSType(v.tVal) Nullable(mkConstant[tpe.type](v.value.asInstanceOf[tpe.WrappedType], tpe)) case v: Int => Nullable(mkConstant[SInt.type](v, SInt)) case v: Long => Nullable(mkConstant[SLong.type](v, SLong)) - case v: BigInteger if !VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SBigInt.type](CBigInt(v), SBigInt)) + case v: BigInteger if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SBigInt.type](CBigInt(v), SBigInt)) case n: sigma.BigInt => Nullable(mkConstant[SBigInt.type](n, SBigInt)) case n: sigma.UnsignedBigInt => Nullable(mkConstant[SUnsignedBigInt.type](n, SUnsignedBigInt)) case ge: GroupElement => Nullable(mkConstant[SGroupElement.type](ge, SGroupElement)) case b: Boolean => Nullable(if (b) TrueLeaf else FalseLeaf) - case v: String if !VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SString.type](v, SString)) - case h: Header if VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SHeader.type](h, SHeader)) - case h: PreHeader if VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SPreHeader.type](h, SPreHeader)) + case v: String if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SString.type](v, SString)) + case h: Header if VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SHeader.type](h, SHeader)) + case h: PreHeader if VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SPreHeader.type](h, SPreHeader)) // The Box lifting was broken in v4.x. `SigmaDsl.Box(b)` was missing which means the // isCorrectType requirement would fail in ConstantNode constructor. // This method is used as part of consensus in SubstConstants operation, however // ErgoBox cannot be passed as argument as it is never valid value during evaluation. // Thus we can use activation-based versioning and fix this code when v5.0 is activated. - case b: ErgoBox if !VersionContext.current.isV6SoftForkActivated => + case b: ErgoBox if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SBox.type](CBox(b), SBox)) // fixed in v5.0 // this case is added in v5.0 and it can be useful when the box value comes from a @@ -50,7 +50,7 @@ object Platform { Nullable(mkConstant[SBox.type](b, SBox)) else Nullable.None // return the same result as in v4.x when there was no this case - case avl: AvlTreeData if !VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SAvlTree.type](CAvlTree(avl), SAvlTree)) + case avl: AvlTreeData if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SAvlTree.type](CAvlTree(avl), SAvlTree)) case avl: AvlTree => Nullable(mkConstant[SAvlTree.type](avl, SAvlTree)) case sb: SigmaBoolean => Nullable(mkConstant[SSigmaProp.type](CSigmaProp(sb), SSigmaProp)) case p: SigmaProp => Nullable(mkConstant[SSigmaProp.type](p, SSigmaProp)) diff --git a/data/jvm/src/main/scala/sigma/Platform.scala b/data/jvm/src/main/scala/sigma/Platform.scala index 8fc5019bf9..178ae242c7 100644 --- a/data/jvm/src/main/scala/sigma/Platform.scala +++ b/data/jvm/src/main/scala/sigma/Platform.scala @@ -16,33 +16,33 @@ object Platform { private[sigma] def liftToConstant(obj: Any, builder: SigmaBuilder): Nullable[Constant[SType]] = { import builder._ obj match { - case arr: Array[Boolean] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SBoolean.type](arr, SBoolean)) - case arr: Array[Byte] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SByte.type](arr, SByte)) - case arr: Array[Short] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SShort.type](arr, SShort)) - case arr: Array[Int] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SInt.type](arr, SInt)) - case arr: Array[Long] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SLong.type](arr, SLong)) - case arr: Array[BigInteger] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SBigInt.type](arr.map(SigmaDsl.BigInt(_)), SBigInt)) - case arr: Array[String] if !VersionContext.current.isV6SoftForkActivated => Nullable(mkCollectionConstant[SString.type](arr, SString)) + case arr: Array[Boolean] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SBoolean.type](arr, SBoolean)) + case arr: Array[Byte] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SByte.type](arr, SByte)) + case arr: Array[Short] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SShort.type](arr, SShort)) + case arr: Array[Int] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SInt.type](arr, SInt)) + case arr: Array[Long] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SLong.type](arr, SLong)) + case arr: Array[BigInteger] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SBigInt.type](arr.map(SigmaDsl.BigInt(_)), SBigInt)) + case arr: Array[String] if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkCollectionConstant[SString.type](arr, SString)) case v: Byte => Nullable(mkConstant[SByte.type](v, SByte)) case v: Short => Nullable(mkConstant[SShort.type](v, SShort)) case v: Int => Nullable(mkConstant[SInt.type](v, SInt)) case v: Long => Nullable(mkConstant[SLong.type](v, SLong)) - case v: BigInteger if !VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SBigInt.type](SigmaDsl.BigInt(v), SBigInt)) + case v: BigInteger if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SBigInt.type](SigmaDsl.BigInt(v), SBigInt)) case n: sigma.BigInt => Nullable(mkConstant[SBigInt.type](n, SBigInt)) case ge: GroupElement => Nullable(mkConstant[SGroupElement.type](ge, SGroupElement)) case b: Boolean => Nullable(if (b) TrueLeaf else FalseLeaf) - case h: Header if VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SHeader.type](h, SHeader)) - case h: PreHeader if VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SPreHeader.type](h, SPreHeader)) - case n: sigma.UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SUnsignedBigInt.type](n, SUnsignedBigInt)) + case h: Header if VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SHeader.type](h, SHeader)) + case h: PreHeader if VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SPreHeader.type](h, SPreHeader)) + case n: sigma.UnsignedBigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SUnsignedBigInt.type](n, SUnsignedBigInt)) - case v: String if !VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SString.type](v, SString)) + case v: String if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SString.type](v, SString)) // The Box lifting was broken in v4.x. `SigmaDsl.Box(b)` was missing which means the // isCorrectType requirement would fail in ConstantNode constructor. // This method is used as part of consensus in SubstConstants operation, however // ErgoBox cannot be passed as argument as it is never valid value during evaluation. // Thus we can use activation-based versioning and fix this code when v5.0 is activated. - case b: ErgoBox if !VersionContext.current.isV6SoftForkActivated => + case b: ErgoBox if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SBox.type](SigmaDsl.Box(b), SBox)) // fixed in v5.0 // this case is added in v5.0 and it can be useful when the box value comes from a @@ -52,7 +52,7 @@ object Platform { Nullable(mkConstant[SBox.type](b, SBox)) else Nullable.None // return the same result as in v4.x when there was no this case - case avl: AvlTreeData if !VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SAvlTree.type](SigmaDsl.avlTree(avl), SAvlTree)) + case avl: AvlTreeData if !VersionContext.current.isV3OrLaterErgoTreeVersion => Nullable(mkConstant[SAvlTree.type](SigmaDsl.avlTree(avl), SAvlTree)) case avl: AvlTree => Nullable(mkConstant[SAvlTree.type](avl, SAvlTree)) case sb: SigmaBoolean => Nullable(mkConstant[SSigmaProp.type](SigmaDsl.SigmaProp(sb), SSigmaProp)) case p: SigmaProp => Nullable(mkConstant[SSigmaProp.type](p, SSigmaProp)) diff --git a/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala b/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala index 9d4de47a99..ed461aa2f2 100644 --- a/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala +++ b/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala @@ -1,6 +1,6 @@ package org.ergoplatform.validation -import sigma.SigmaException +import sigma.{SigmaException, VersionContext} import sigma.ast.{DeserializeContext, ErgoTree, MethodsContainer, SMethod} import sigma.ast.TypeCodes.LastConstantCode import sigma.serialization.{InvalidOpCode, SerializerException} @@ -23,7 +23,7 @@ object ValidationRules { object CheckDeserializedScriptType extends ValidationRule(FirstRuleId, "Deserialized script should have expected type") { - override protected lazy val settings: SigmaValidationSettings = currentSettings + override protected def settings: SigmaValidationSettings = currentSettings final def apply[T](d: DeserializeContext[_], script: SValue): Unit = { checkRule() @@ -38,7 +38,7 @@ object ValidationRules { object CheckDeserializedScriptIsSigmaProp extends ValidationRule(1001, "Deserialized script should have SigmaProp type") { - override protected lazy val settings: SigmaValidationSettings = currentSettings + override protected def settings: SigmaValidationSettings = currentSettings /** @param root candidate node before it is added as a root of ErgoTree */ final def apply[T](root: SValue): Unit = { @@ -54,7 +54,7 @@ object ValidationRules { object CheckValidOpCode extends ValidationRule(1002, "Check the opcode is supported by registered serializer or is added via soft-fork") with SoftForkWhenCodeAdded { - override protected lazy val settings: SigmaValidationSettings = currentSettings + override protected def settings: SigmaValidationSettings = currentSettings final def apply[T](ser: ValueSerializer[_], opCode: OpCode): Unit = { checkRule() @@ -69,18 +69,18 @@ object ValidationRules { /** Not used since v5.0.1. */ object CheckIsSupportedIndexExpression extends ValidationRule(1003, "Check the index expression for accessing collection element is supported.") { - override protected lazy val settings: SigmaValidationSettings = currentSettings + override protected def settings: SigmaValidationSettings = currentSettings } /** Not used since v5.0.3 */ object CheckCostFunc extends ValidationRule(1004, "Cost function should contain only operations from specified list.") { - override protected lazy val settings: SigmaValidationSettings = currentSettings + override protected def settings: SigmaValidationSettings = currentSettings } object CheckCalcFunc extends ValidationRule(1005, "If SigmaProp.isProven method calls exists in the given function,\n then it is the last operation") { - override protected lazy val settings: SigmaValidationSettings = currentSettings + override protected def settings: SigmaValidationSettings = currentSettings } /** This rule is not use in v5.x, keep the commented code below as a precise @@ -88,7 +88,7 @@ object ValidationRules { */ object CheckTupleType extends ValidationRule(1006, "Supported tuple type.") with SoftForkWhenReplaced { - override protected lazy val settings: SigmaValidationSettings = currentSettings + override protected def settings: SigmaValidationSettings = currentSettings // final def apply[Ctx <: IRContext, T](ctx: Ctx)(e: ctx.Elem[_]): Unit = { // checkRule() @@ -102,15 +102,16 @@ object ValidationRules { // } } - object CheckAndGetMethod extends ValidationRule(1011, + class CheckAndGetMethodTemplate(ruleId: Short) extends ValidationRule(ruleId, "Check the type has the declared method.") { - override protected lazy val settings: SigmaValidationSettings = currentSettings + override protected def settings: SigmaValidationSettings = currentSettings final def apply[T](objType: MethodsContainer, methodId: Byte): SMethod = { checkRule() val methodOpt = objType.getMethodById(methodId) - if (methodOpt.isDefined) methodOpt.get - else { + if (methodOpt.isDefined) { + methodOpt.get + } else { throwValidationException( new SerializerException(s"The method with code $methodId doesn't declared in the type $objType."), Array[Any](objType, methodId)) @@ -120,17 +121,30 @@ object ValidationRules { override def isSoftFork(vs: SigmaValidationSettings, ruleId: Short, status: RuleStatus, - args: Seq[Any]): Boolean = (status, args) match { - case (ChangedRule(newValue), Seq(objType: MethodsContainer, methodId: Byte)) => - val key = Array(objType.ownerType.typeId, methodId) - newValue.grouped(2).exists(java.util.Arrays.equals(_, key)) - case _ => false + args: Seq[Any]): Boolean = { + (status, args) match { + case (ChangedRule(newValue), Seq(objType: MethodsContainer, methodId: Byte)) => + val key = Array(objType.ownerType.typeId, methodId) + newValue.grouped(2).exists(java.util.Arrays.equals(_, key)) + case _ => false + } + } + } + + object CheckAndGetMethod extends CheckAndGetMethodTemplate(1011) { + override def isSoftFork(vs: SigmaValidationSettings, + ruleId: Short, + status: RuleStatus, + args: Seq[Any]): Boolean = { + false } } + object CheckAndGetMethodV6 extends CheckAndGetMethodTemplate(1016) + object CheckHeaderSizeBit extends ValidationRule(1012, "For version greater then 0, size bit should be set.") with SoftForkWhenReplaced { - override protected lazy val settings: SigmaValidationSettings = currentSettings + override protected def settings: SigmaValidationSettings = currentSettings final def apply(header: HeaderType): Unit = { checkRule() @@ -146,16 +160,16 @@ object ValidationRules { /** Not used since v5.0.3 */ object CheckCostFuncOperation extends ValidationRule(1013, "Check the opcode is allowed in cost function") { - override protected lazy val settings: SigmaValidationSettings = currentSettings + override protected def settings: SigmaValidationSettings = currentSettings } /** Not used since v5.0.1 */ object CheckLoopLevelInCostFunction extends ValidationRule(1015, "Check that loop level is not exceeded.") { - override protected lazy val settings: SigmaValidationSettings = currentSettings + override protected def settings: SigmaValidationSettings = currentSettings } - val ruleSpecs: Seq[ValidationRule] = Seq( + private val ruleSpecsV5: Seq[ValidationRule] = Seq( CheckDeserializedScriptType, CheckDeserializedScriptIsSigmaProp, CheckValidOpCode, @@ -174,13 +188,26 @@ object ValidationRules { CheckLoopLevelInCostFunction ) + // v6 validation rules below + private val ruleSpecsV6: Seq[ValidationRule] = { + ruleSpecsV5.filter(_.id != CheckAndGetMethod.id) ++ Seq(CheckAndGetMethodV6) + } + + def ruleSpecs: Seq[ValidationRule] = { + if (VersionContext.current.isV6Activated) { + ruleSpecsV6 + } else { + ruleSpecsV5 + } + } + /** Validation settings that correspond to the current version of the ErgoScript implementation. * Different version of the code will have a different set of rules here. * This variable is globally available and can be use wherever checking of the rules is necessary. * This is immutable data structure, it can be augmented with RuleStates from block extension * sections of the blockchain, but that augmentation is only available in stateful context. */ - val currentSettings: SigmaValidationSettings = new MapSigmaValidationSettings({ + def currentSettings: SigmaValidationSettings = new MapSigmaValidationSettings({ val map = ruleSpecs.map(r => r.id -> (r, EnabledRule)).toMap assert(map.size == ruleSpecs.size, s"Duplicate ruleIds ${ruleSpecs.groupBy(_.id).filter(g => g._2.length > 1)}") map diff --git a/data/shared/src/main/scala/sigma/ast/ErgoTree.scala b/data/shared/src/main/scala/sigma/ast/ErgoTree.scala index 8d731e1c67..ec902a20eb 100644 --- a/data/shared/src/main/scala/sigma/ast/ErgoTree.scala +++ b/data/shared/src/main/scala/sigma/ast/ErgoTree.scala @@ -375,7 +375,7 @@ object ErgoTree { * 3) write the `tree` to the Writer's buffer obtaining `treeBytes`; * 4) deserialize `tree` with ConstantPlaceholders. * - * @param headerFlags additional header flags to combine with + * @param header additional header flags to combine with * ConstantSegregationHeader flag. * @param prop expression to be transformed into ErgoTree * */ @@ -411,4 +411,5 @@ object ErgoTree { def fromBytes(bytes: Array[Byte]): ErgoTree = { ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes) } + } diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index a69654de7e..e40ec30e7c 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -85,13 +85,17 @@ sealed trait MethodsContainer { /** Lookup method in this type by method's id or throw ValidationException. * This method can be used in trySoftForkable section to either obtain valid method - * or catch ValidatioinException which can be checked for soft-fork condition. + * or catch ValidationException which can be checked for soft-fork condition. * It delegate to getMethodById to lookup method. * * @see getMethodById */ def methodById(methodId: Byte): SMethod = { - ValidationRules.CheckAndGetMethod(this, methodId) + if (VersionContext.current.isV6Activated) { + ValidationRules.CheckAndGetMethodV6(this, methodId) + } else { + ValidationRules.CheckAndGetMethod(this, methodId) + } } /** Finds a method descriptor [[SMethod]] for the given name. */ @@ -132,7 +136,7 @@ object MethodsContainer { private val containersV6 = new SparseArrayContainer[MethodsContainer](methodsV6.map(m => (m.typeId, m))) def contains(typeId: TypeCode): Boolean = { - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { containersV6.contains(typeId) } else { containersV5.contains(typeId) @@ -140,7 +144,7 @@ object MethodsContainer { } def apply(typeId: TypeCode): MethodsContainer = { - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { containersV6(typeId) } else { containersV5(typeId) @@ -157,7 +161,7 @@ object MethodsContainer { case tup: STuple => STupleMethods.getTupleMethod(tup, methodName) case _ => - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { containersV6.get(tpe.typeCode).flatMap(_.method(methodName)) } else { containersV5.get(tpe.typeCode).flatMap(_.method(methodName)) @@ -208,7 +212,7 @@ trait SNumericTypeMethods extends MonoTypeMethods { } protected override def getMethods(): Seq[SMethod] = { - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { super.getMethods() ++ v6Methods } else { super.getMethods() ++ v5Methods @@ -523,7 +527,7 @@ case object SBigIntMethods extends SNumericTypeMethods { ArgInfo("m", "modulo value")) protected override def getMethods(): Seq[SMethod] = { - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { super.getMethods() ++ Seq(ToUnsigned, ToUnsignedMod) } else { super.getMethods() @@ -651,7 +655,7 @@ case object SGroupElementMethods extends MonoTypeMethods { MultiplyMethod, NegateMethod) - super.getMethods() ++ (if (VersionContext.current.isV6SoftForkActivated) { + super.getMethods() ++ (if (VersionContext.current.isV3OrLaterErgoTreeVersion) { v5Methods ++ Seq(ExponentiateUnsignedMethod) } else { v5Methods @@ -1309,7 +1313,7 @@ object SCollectionMethods extends MethodsContainer with MethodByNameUnapply { * Typical override: `super.getMethods() ++ Seq(m1, m2, m3)` */ override protected def getMethods(): Seq[SMethod] = { - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { v6Methods } else { v5Methods @@ -1462,7 +1466,7 @@ case object SBoxMethods extends MonoTypeMethods { // should be lazy to solve recursive initialization protected override def getMethods() = { - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { v6Methods } else { v5Methods @@ -1837,7 +1841,7 @@ case object SContextMethods extends MonoTypeMethods { ) protected override def getMethods(): Seq[SMethod] = { - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { v6Methods } else { v5Methods @@ -1888,7 +1892,7 @@ case object SHeaderMethods extends MonoTypeMethods { private lazy val v6Methods = v5Methods ++ Seq(checkPowMethod) protected override def getMethods() = { - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { v6Methods } else { v5Methods @@ -2061,7 +2065,7 @@ case object SGlobalMethods extends MonoTypeMethods { .withInfo(MethodCall, "Returns empty Option[T] of given type T.") protected override def getMethods() = super.getMethods() ++ { - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { Seq( groupGeneratorMethod, xorMethod, diff --git a/data/shared/src/main/scala/sigma/ast/transformers.scala b/data/shared/src/main/scala/sigma/ast/transformers.scala index 8d7e689a18..9c622ca2da 100644 --- a/data/shared/src/main/scala/sigma/ast/transformers.scala +++ b/data/shared/src/main/scala/sigma/ast/transformers.scala @@ -258,7 +258,7 @@ case class ByIndex[V <: SType](input: Value[SCollection[V]], val indexV = index.evalTo[Int](env) default match { case Some(d) => - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { // lazy evaluation of default in 6.0 addCost(ByIndex.costKind) if (inputV.isDefinedAt(indexV)) { @@ -625,7 +625,7 @@ case class OptionGetOrElse[V <: SType](input: Value[SOption[V]], default: Value[ override val opType = SFunc(IndexedSeq(input.tpe, tpe), tpe) override def tpe: V = input.tpe.elemType protected final override def eval(env: DataEnv)(implicit E: ErgoTreeEvaluator): Any = { - if(VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { // lazy evaluation of default in 6.0 val inputV = input.evalTo[Option[V#WrappedType]](env) addCost(OptionGetOrElse.costKind) diff --git a/data/shared/src/main/scala/sigma/serialization/DataSerializer.scala b/data/shared/src/main/scala/sigma/serialization/DataSerializer.scala index 92a54f9aa4..4046b29a18 100644 --- a/data/shared/src/main/scala/sigma/serialization/DataSerializer.scala +++ b/data/shared/src/main/scala/sigma/serialization/DataSerializer.scala @@ -16,7 +16,7 @@ object DataSerializer extends CoreDataSerializer { case SBox => val b = v.asInstanceOf[CBox] ErgoBox.sigmaSerializer.serialize(b.ebox, w.asInstanceOf[SigmaByteWriter]) - case SHeader if VersionContext.current.isV6SoftForkActivated => + case SHeader if VersionContext.current.isV6Activated => val h = v.asInstanceOf[CHeader] ErgoHeader.sigmaSerializer.serialize(h.ergoHeader, w.asInstanceOf[SigmaByteWriter]) case _ => @@ -36,7 +36,7 @@ object DataSerializer extends CoreDataSerializer { val res = CBox(ErgoBox.sigmaSerializer.parse(r.asInstanceOf[SigmaByteReader])) r.level = r.level - 1 res - case SHeader if VersionContext.current.isV6SoftForkActivated => + case SHeader if VersionContext.current.isV6Activated => val depth = r.level r.level = depth + 1 val res = new CHeader(ErgoHeader.sigmaSerializer.parse(r.asInstanceOf[SigmaByteReader])) diff --git a/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala b/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala index 5122ee940c..5812132e0e 100644 --- a/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala +++ b/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala @@ -3,7 +3,7 @@ package sigma.serialization import org.ergoplatform.validation.ValidationRules.{CheckDeserializedScriptIsSigmaProp, CheckHeaderSizeBit} import sigma.ast.{Constant, DeserializationSigmaBuilder, ErgoTree, SType, UnparsedErgoTree} import sigma.ast.syntax.ValueOps -import sigma.ast.ErgoTree.{EmptyConstants, HeaderType} +import sigma.ast.ErgoTree.{EmptyConstants, HeaderType, getVersion} import sigma.util.safeNewArray import debox.cfor import sigma.VersionContext @@ -103,20 +103,24 @@ class ErgoTreeSerializer { * Doesn't apply any transformations and guarantee to preserve original * structure after deserialization. */ def serializeErgoTree(ergoTree: ErgoTree): Array[Byte] = { - val res = ergoTree.root match { - case Left(UnparsedErgoTree(bytes, _)) => bytes.array.asInstanceOf[Array[Byte]] - case _ => - val bytes = serializeWithoutSize(ergoTree) - if (ergoTree.hasSize) { - val w = SigmaSerializer.startWriter() - val header = bytes(0) - val contentLength = bytes.length - 1 - w.put(header) - w.putUInt(contentLength) - w.putBytes(bytes, 1, contentLength) - w.toBytes - } - else bytes + val treeVersion = ergoTree.version + val scriptVersion = Math.max(VersionContext.current.activatedVersion, treeVersion).toByte + val res = VersionContext.withVersions(scriptVersion, treeVersion) { + ergoTree.root match { + case Left(UnparsedErgoTree(bytes, _)) => bytes.array.asInstanceOf[Array[Byte]] + case _ => + val bytes = serializeWithoutSize(ergoTree) + if (ergoTree.hasSize) { + val w = SigmaSerializer.startWriter() + val header = bytes(0) + val contentLength = bytes.length - 1 + w.put(header) + w.putUInt(contentLength) + w.putBytes(bytes, 1, contentLength) + w.toBytes + } + else bytes + } } res } @@ -140,37 +144,42 @@ class ErgoTreeSerializer { val bodyPos = r.position val tree = try { try { // nested try-catch to intercept size limit exceptions and rethrow them as ValidationExceptions - val cs = deserializeConstants(h, r) - val previousConstantStore = r.constantStore - // reader with constant store attached is required (to get tpe for a constant placeholder) - r.constantStore = new ConstantStore(cs) - val wasDeserialize_saved = r.wasDeserialize - r.wasDeserialize = false + val treeVersion = getVersion(h) + val scriptVersion = Math.max(VersionContext.current.activatedVersion, treeVersion).toByte + VersionContext.withVersions(scriptVersion, treeVersion) { + val cs = deserializeConstants(h, r) + val previousConstantStore = r.constantStore + // reader with constant store attached is required (to get tpe for a constant placeholder) + r.constantStore = new ConstantStore(cs) - val wasUsingBlockchainContext_saved = r.wasUsingBlockchainContext - r.wasUsingBlockchainContext = false + val wasDeserialize_saved = r.wasDeserialize + r.wasDeserialize = false - val root = ValueSerializer.deserialize(r) - val hasDeserialize = r.wasDeserialize // == true if there was deserialization node - r.wasDeserialize = wasDeserialize_saved + val wasUsingBlockchainContext_saved = r.wasUsingBlockchainContext + r.wasUsingBlockchainContext = false - val isUsingBlockchainContext = r.wasUsingBlockchainContext // == true if there was a node using the blockchain context - r.wasUsingBlockchainContext = wasUsingBlockchainContext_saved + val root = ValueSerializer.deserialize(r) + val hasDeserialize = r.wasDeserialize // == true if there was deserialization node + r.wasDeserialize = wasDeserialize_saved - if (checkType) { - CheckDeserializedScriptIsSigmaProp(root) - } + val isUsingBlockchainContext = r.wasUsingBlockchainContext // == true if there was a node using the blockchain context + r.wasUsingBlockchainContext = wasUsingBlockchainContext_saved - r.constantStore = previousConstantStore - // now we know the end position of propositionBytes, read them all at once into array - val treeSize = r.position - startPos - r.position = startPos - val propositionBytes = r.getBytes(treeSize) + if (checkType) { + CheckDeserializedScriptIsSigmaProp(root) + } - new ErgoTree( - h, cs, Right(root.asSigmaProp), - propositionBytes, Some(hasDeserialize), Some(isUsingBlockchainContext)) + r.constantStore = previousConstantStore + // now we know the end position of propositionBytes, read them all at once into array + val treeSize = r.position - startPos + r.position = startPos + val propositionBytes = r.getBytes(treeSize) + + new ErgoTree( + h, cs, Right(root.asSigmaProp), + propositionBytes, Some(hasDeserialize), Some(isUsingBlockchainContext)) + } } catch { case e: ReaderPositionLimitExceeded => @@ -309,83 +318,85 @@ class ErgoTreeSerializer { val (header, _, constants, treeBytes) = deserializeHeaderWithTreeBytes(r) val nConstants = constants.length - val resBytes = if (VersionContext.current.isJitActivated) { - // need to measure the serialized size of the new constants - // by serializing them into a separate writer - val constW = SigmaSerializer.startWriter() - - // The following `constants.length` should not be serialized when segregation is off - // in the `header`, because in this case there is no `constants` section in the - // ErgoTree serialization format. Thus, applying this `substituteConstants` for - // non-segregated trees will return non-parsable ErgoTree bytes (when - // `constants.length` is put in `w`). - if (ErgoTree.isConstantSegregation(header)) { - constW.putUInt(constants.length) - } + val resBytes = { + if (VersionContext.current.isJitActivated) { + // need to measure the serialized size of the new constants + // by serializing them into a separate writer + val constW = SigmaSerializer.startWriter() + + // The following `constants.length` should not be serialized when segregation is off + // in the `header`, because in this case there is no `constants` section in the + // ErgoTree serialization format. Thus, applying this `substituteConstants` for + // non-segregated trees will return non-parsable ErgoTree bytes (when + // `constants.length` is put in `w`). + if (ErgoTree.isConstantSegregation(header)) { + constW.putUInt(constants.length) + } - // The following is optimized O(nConstants + position.length) implementation - if (nConstants > 0) { - val backrefs = getPositionsBackref(positions, nConstants) - cfor(0)(_ < nConstants, _ + 1) { i => - val c = constants(i) - val iPos = backrefs(i) // index to `positions` - if (iPos == -1) { - // no position => no substitution, serialize original constant - constantSerializer.serialize(c, constW) - } else { - require(positions(iPos) == i) // INV: backrefs and positions are mutually inverse - val newConst = newVals(iPos) - require(c.tpe == newConst.tpe, - s"expected new constant to have the same ${c.tpe} tpe, got ${newConst.tpe}") - constantSerializer.serialize(newConst, constW) + // The following is optimized O(nConstants + position.length) implementation + if (nConstants > 0) { + val backrefs = getPositionsBackref(positions, nConstants) + cfor(0)(_ < nConstants, _ + 1) { i => + val c = constants(i) + val iPos = backrefs(i) // index to `positions` + if (iPos == -1) { + // no position => no substitution, serialize original constant + constantSerializer.serialize(c, constW) + } else { + require(positions(iPos) == i) // INV: backrefs and positions are mutually inverse + val newConst = newVals(iPos) + require(c.tpe == newConst.tpe, + s"expected new constant to have the same ${c.tpe} tpe, got ${newConst.tpe}") + constantSerializer.serialize(newConst, constW) + } } } - } - val constBytes = constW.toBytes // nConstants + serialized new constants + val constBytes = constW.toBytes // nConstants + serialized new constants + + // start composing the resulting tree bytes + val w = SigmaSerializer.startWriter() + w.put(header) // header byte - // start composing the resulting tree bytes - val w = SigmaSerializer.startWriter() - w.put(header) // header byte + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { + // fix in v6.0 to save tree size to respect size bit of the original tree + if (ErgoTree.hasSize(header)) { + val size = constBytes.length + treeBytes.length + w.putUInt(size) // tree size + } + } - if (VersionContext.current.isV6SoftForkActivated) { - // fix in v6.0 to save tree size to respect size bit of the original tree - if (ErgoTree.hasSize(header)) { - val size = constBytes.length + treeBytes.length - w.putUInt(size) // tree size + w.putBytes(constBytes) // constants section + w.putBytes(treeBytes) // tree section + w.toBytes + } else { + val w = SigmaSerializer.startWriter() + w.put(header) + + // for v4.x compatibility we save constants.length here (see the above comment to + // understand the consequences) + w.putUInt(constants.length) + + // the following is v4.x O(nConstants * positions.length) inefficient implementation + constants.zipWithIndex.foreach { + case (c, i) if positions.contains(i) => + val newVal = newVals(positions.indexOf(i)) + // we need to get newVal's serialized constant value (see ProveDlogSerializer for example) + val constantStore = new ConstantStore() + val valW = SigmaSerializer.startWriter(Some(constantStore)) + valW.putValue(newVal) + val newConsts = constantStore.getAll + require(newConsts.length == 1) + val newConst = newConsts.head + require(c.tpe == newConst.tpe, s"expected new constant to have the same ${c.tpe} tpe, got ${newConst.tpe}") + constantSerializer.serialize(newConst, w) + case (c, _) => + constantSerializer.serialize(c, w) } - } - w.putBytes(constBytes) // constants section - w.putBytes(treeBytes) // tree section - w.toBytes - } else { - val w = SigmaSerializer.startWriter() - w.put(header) - - // for v4.x compatibility we save constants.length here (see the above comment to - // understand the consequences) - w.putUInt(constants.length) - - // the following is v4.x O(nConstants * positions.length) inefficient implementation - constants.zipWithIndex.foreach { - case (c, i) if positions.contains(i) => - val newVal = newVals(positions.indexOf(i)) - // we need to get newVal's serialized constant value (see ProveDlogSerializer for example) - val constantStore = new ConstantStore() - val valW = SigmaSerializer.startWriter(Some(constantStore)) - valW.putValue(newVal) - val newConsts = constantStore.getAll - require(newConsts.length == 1) - val newConst = newConsts.head - require(c.tpe == newConst.tpe, s"expected new constant to have the same ${c.tpe} tpe, got ${newConst.tpe}") - constantSerializer.serialize(newConst, w) - case (c, _) => - constantSerializer.serialize(c, w) + w.putBytes(treeBytes) + w.toBytes } - - w.putBytes(treeBytes) - w.toBytes } (resBytes, nConstants) diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala index 88d7be4324..369af2a960 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala @@ -248,7 +248,7 @@ trait Interpreter { val context1 = context.withInitCost(currCost).asInstanceOf[CTX] val (propTree, context2) = trySoftForkable[(SigmaPropValue, CTX)](whenSoftFork = (TrueSigmaProp, context1)) { // Before ErgoTree V3 the deserialization cost was not added to the total cost - applyDeserializeContextJITC(if (VersionContext.current.activatedVersion >= VersionContext.V6SoftForkVersion) { + applyDeserializeContextJITC(if (VersionContext.current.isV6Activated) { context1 } else { context @@ -360,7 +360,6 @@ trait Interpreter { case None => // proceed normally } VersionContext.withVersions(context.activatedScriptVersion, ergoTree.version) { - // NOTE, ergoTree.complexity is not acrued to the cost in v5.0 val reduced = fullReduction(ergoTree, context, env) reduced.value match { case TrivialProp.TrueProp => (true, reduced.cost) diff --git a/interpreter/shared/src/test/scala/org/ergoplatform/validation/ValidationSpecification.scala b/interpreter/shared/src/test/scala/org/ergoplatform/validation/ValidationSpecification.scala index b223355c5b..47068a9102 100644 --- a/interpreter/shared/src/test/scala/org/ergoplatform/validation/ValidationSpecification.scala +++ b/interpreter/shared/src/test/scala/org/ergoplatform/validation/ValidationSpecification.scala @@ -3,5 +3,5 @@ package org.ergoplatform.validation import sigma.validation.SigmaValidationSettings trait ValidationSpecification { - implicit val vs: SigmaValidationSettings = ValidationRules.currentSettings + def vs: SigmaValidationSettings = ValidationRules.currentSettings } diff --git a/interpreter/shared/src/test/scala/sigma/ast/SigmaBuilderTest.scala b/interpreter/shared/src/test/scala/sigma/ast/SigmaBuilderTest.scala index ea3fa5d5ec..ce007d0e7f 100644 --- a/interpreter/shared/src/test/scala/sigma/ast/SigmaBuilderTest.scala +++ b/interpreter/shared/src/test/scala/sigma/ast/SigmaBuilderTest.scala @@ -138,7 +138,7 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma val v = true val c = BooleanConstant(v) test[SBoolean.type](v, c) - if (!VersionContext.current.isV6SoftForkActivated) { + if (!VersionContext.current.isV3OrLaterErgoTreeVersion) { testArray[SBoolean.type](v, c) } else { testArrayFailure[SBoolean.type](v, c) @@ -151,7 +151,7 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma val c = ByteConstant(v) testNumeric[SByte.type](v, c) testLiftingOfCAnyValue[SByte.type](v, c) - if (!VersionContext.current.isV6SoftForkActivated) { + if (!VersionContext.current.isV3OrLaterErgoTreeVersion) { testArray[SByte.type](v, c) } else { testArrayFailure[SByte.type](v, c) @@ -164,7 +164,7 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma val c = ShortConstant(v) testNumeric[SShort.type](v, c) testLiftingOfCAnyValue[SShort.type](v, c) - if (!VersionContext.current.isV6SoftForkActivated) { + if (!VersionContext.current.isV3OrLaterErgoTreeVersion) { testArray[SShort.type](v, c) } else { testArrayFailure[SShort.type](v, c) @@ -176,7 +176,7 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma val v = 1 val c = IntConstant(v) test[SInt.type](v, c) - if (!VersionContext.current.isV6SoftForkActivated) { + if (!VersionContext.current.isV3OrLaterErgoTreeVersion) { testArray[SInt.type](v, c) } else { testArrayFailure[SInt.type](v, c) @@ -188,7 +188,7 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma val v = 1L val c = LongConstant(v) test[SLong.type](v, c) - if (!VersionContext.current.isV6SoftForkActivated) { + if (!VersionContext.current.isV3OrLaterErgoTreeVersion) { testArray[SLong.type](v, c) } else { testArrayFailure[SLong.type](v, c) @@ -199,7 +199,7 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma property("liftToConstant String") { val v = "abc" val c = StringConstant(v) - if (!VersionContext.current.isV6SoftForkActivated) { + if (!VersionContext.current.isV3OrLaterErgoTreeVersion) { // v6.0: String should not be liftable at all (not supported in ErgoTree) (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905) test[SString.type](v, c) testArray[SString.type](v, c) @@ -212,13 +212,13 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma property("liftToConstant BigInteger") { val v = BigInteger.valueOf(1L) val c = BigIntConstant(v) - if (!VersionContext.current.isV6SoftForkActivated) { + if (!VersionContext.current.isV3OrLaterErgoTreeVersion) { testSuccess(v, c) } else { testFailure(v) } val arr = Array.fill(10)(v) - if (!VersionContext.current.isV6SoftForkActivated) { + if (!VersionContext.current.isV3OrLaterErgoTreeVersion) { testSuccess(arr, TransformingSigmaBuilder.mkCollectionConstant[SBigInt.type](arr.map(SigmaDsl.BigInt), c.tpe)) } else { testFailure(arr) @@ -244,7 +244,7 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma property("liftToConstant Header") { val h = TestData.h1 val c = HeaderConstant(h) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { testSuccess(h, c) } else { testFailure(h) @@ -256,7 +256,7 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma property("liftToConstant ErgoBox") { val v = TestData.b2.asInstanceOf[CBox].wrappedValue val c = BoxConstant(TestData.b2) - if (!VersionContext.current.isV6SoftForkActivated) { + if (!VersionContext.current.isV3OrLaterErgoTreeVersion) { testSuccess(v, c) } else { testFailure(v) @@ -287,7 +287,7 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma property("liftToConstant AvlTreeData") { val v = TestData.t1.asInstanceOf[CAvlTree].wrappedValue val c = AvlTreeConstant(SigmaDsl.avlTree(v)) - if (!VersionContext.current.isV6SoftForkActivated) { + if (!VersionContext.current.isV3OrLaterErgoTreeVersion) { testSuccess(v, c) } else { testFailure(v) diff --git a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala index 4bfe3c6a25..891d22a78a 100644 --- a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala @@ -38,7 +38,7 @@ class MethodCallSerializerSpecification extends SerializationSpecification { roundTripTest(expr) } - VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) { + VersionContext.withVersions(VersionContext.V6SoftForkVersion, VersionContext.V6SoftForkVersion) { code } @@ -47,6 +47,12 @@ class MethodCallSerializerSpecification extends SerializationSpecification { code } ) + + a[ValidationException] should be thrownBy ( + VersionContext.withVersions(VersionContext.V6SoftForkVersion, (VersionContext.V6SoftForkVersion - 1).toByte) { + code + } + ) } property("MethodCall deserialization round trip for Global.powHit") { @@ -65,15 +71,21 @@ class MethodCallSerializerSpecification extends SerializationSpecification { roundTripTest(expr) } - VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) { + VersionContext.withVersions(VersionContext.V6SoftForkVersion, VersionContext.V6SoftForkVersion) { code } - an[ValidationException] should be thrownBy ( + a[ValidationException] should be thrownBy ( VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) { code } ) + + a[ValidationException] should be thrownBy ( + VersionContext.withVersions(VersionContext.V6SoftForkVersion, (VersionContext.V6SoftForkVersion - 1).toByte) { + code + } + ) } property("MethodCall deserialization round trip for Global.serialize") { @@ -87,15 +99,21 @@ class MethodCallSerializerSpecification extends SerializationSpecification { roundTripTest(expr) } - VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) { + VersionContext.withVersions(VersionContext.V6SoftForkVersion, VersionContext.V6SoftForkVersion) { code } - an[ValidationException] should be thrownBy ( + a[ValidationException] should be thrownBy ( VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) { code } - ) + ) + + a[ValidationException] should be thrownBy ( + VersionContext.withVersions(VersionContext.V6SoftForkVersion, (VersionContext.V6SoftForkVersion - 1).toByte) { + code + } + ) } property("MethodCall deserialization round trip for Global.deserializeTo[]") { @@ -109,16 +127,21 @@ class MethodCallSerializerSpecification extends SerializationSpecification { roundTripTest(expr) } - println(SGlobalMethods.deserializeToMethod.hasExplicitTypeArgs) - - VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) { + VersionContext.withVersions(VersionContext.V6SoftForkVersion, VersionContext.V6SoftForkVersion) { code } - an[Exception] should be thrownBy ( + a[SerializerException] should be thrownBy ( VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) { code - }) + } + ) + + a[ValidationException] should be thrownBy ( + VersionContext.withVersions(VersionContext.V6SoftForkVersion, (VersionContext.V6SoftForkVersion - 1).toByte) { + code + } + ) } property("MethodCall deserialization round trip for Global.encodeNBits") { @@ -133,14 +156,21 @@ class MethodCallSerializerSpecification extends SerializationSpecification { } // should be ok - VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) { + VersionContext.withVersions(VersionContext.V6SoftForkVersion, VersionContext.V6SoftForkVersion) { code } - an[ValidationException] should be thrownBy ( + a[ValidationException] should be thrownBy ( VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) { code - }) + } + ) + + a[ValidationException] should be thrownBy ( + VersionContext.withVersions(VersionContext.V6SoftForkVersion, (VersionContext.V6SoftForkVersion - 1).toByte) { + code + } + ) } property("MethodCall deserialization round trip for Global.decodeNBits") { @@ -154,14 +184,20 @@ class MethodCallSerializerSpecification extends SerializationSpecification { roundTripTest(expr) } - VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) { + VersionContext.withVersions(VersionContext.V6SoftForkVersion, VersionContext.V6SoftForkVersion) { code } - an[ValidationException] should be thrownBy ( + a[ValidationException] should be thrownBy ( VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) { code } ) + + a[ValidationException] should be thrownBy ( + VersionContext.withVersions(VersionContext.V6SoftForkVersion, (VersionContext.V6SoftForkVersion - 1).toByte) { + code + } + ) } } diff --git a/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala b/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala index 1af51d4eee..52bd629e70 100644 --- a/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala +++ b/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala @@ -329,7 +329,7 @@ trait ObjectGenerators extends TypeGenerators longConstGen, booleanConstGen, bigIntConstGen, - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { unsignedBigIntConstGen } else { bigIntConstGen diff --git a/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala b/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala index c27053ebf2..53bb8de156 100644 --- a/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala +++ b/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala @@ -24,7 +24,7 @@ trait TypeGenerators { Gen.oneOf[SPrimType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SUnsignedBigInt, SGroupElement, SSigmaProp, SUnit) implicit val arbPrimType: Arbitrary[SPrimType] = Arbitrary(primTypeGen) implicit val predefTypeGen: Gen[SPredefType] = { - if(VersionContext.current.isV6SoftForkActivated){ + if(VersionContext.current.isV3OrLaterErgoTreeVersion){ Gen.oneOf[SPredefType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SUnsignedBigInt, SGroupElement, SSigmaProp, SUnit, SBox, SAvlTree, SHeader) } else { Gen.oneOf[SPredefType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnit, SBox, SAvlTree) @@ -42,7 +42,7 @@ trait TypeGenerators { intTypeGen, longTypeGen, bigIntTypeGen, - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { unsignedBigIntTypeGen } else { bigIntTypeGen diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index f5235aba5e..df968b010c 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1055,7 +1055,7 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => case (box: Ref[Box]@unchecked, SBoxMethods) => method.name match { case SBoxMethods.tokensMethod.name => box.tokens - case SBoxMethods.getRegMethodV6.name if VersionContext.current.isV6SoftForkActivated => + case SBoxMethods.getRegMethodV6.name if VersionContext.current.isV3OrLaterErgoTreeVersion => val c1 = asRep[Int](argsV(0)) val c2 = stypeToElem(typeSubst.apply(tT)) box.getReg(c1)(c2) @@ -1188,7 +1188,7 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => h.powDistance case SHeaderMethods.votesMethod.name => h.votes - case SHeaderMethods.checkPowMethod.name if VersionContext.current.isV6SoftForkActivated => + case SHeaderMethods.checkPowMethod.name if VersionContext.current.isV3OrLaterErgoTreeVersion => h.checkPow case _ => throwError() } @@ -1199,26 +1199,26 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => val c1 = asRep[Coll[Byte]](argsV(0)) val c2 = asRep[Coll[Byte]](argsV(1)) g.xor(c1, c2) - case SGlobalMethods.encodeNBitsMethod.name if VersionContext.current.isV6SoftForkActivated => + case SGlobalMethods.encodeNBitsMethod.name if VersionContext.current.isV3OrLaterErgoTreeVersion => val c1 = asRep[BigInt](argsV(0)) g.encodeNbits(c1) - case SGlobalMethods.decodeNBitsMethod.name if VersionContext.current.isV6SoftForkActivated => + case SGlobalMethods.decodeNBitsMethod.name if VersionContext.current.isV3OrLaterErgoTreeVersion => val c1 = asRep[Long](argsV(0)) g.decodeNbits(c1) - case SGlobalMethods.powHitMethod.name if VersionContext.current.isV6SoftForkActivated => + case SGlobalMethods.powHitMethod.name if VersionContext.current.isV3OrLaterErgoTreeVersion => val k = asRep[Int](argsV(0)) val msg = asRep[Coll[Byte]](argsV(1)) val nonce = asRep[Coll[Byte]](argsV(2)) val h = asRep[Coll[Byte]](argsV(3)) val N = asRep[Int](argsV(4)) g.powHit(k, msg, nonce, h, N) - case SGlobalMethods.encodeNBitsMethod.name if VersionContext.current.isV6SoftForkActivated => + case SGlobalMethods.encodeNBitsMethod.name if VersionContext.current.isV3OrLaterErgoTreeVersion => val c1 = asRep[BigInt](argsV(0)) g.encodeNbits(c1) - case SGlobalMethods.decodeNBitsMethod.name if VersionContext.current.isV6SoftForkActivated => + case SGlobalMethods.decodeNBitsMethod.name if VersionContext.current.isV3OrLaterErgoTreeVersion => val c1 = asRep[Long](argsV(0)) g.decodeNbits(c1) - case SGlobalMethods.deserializeToMethod.name if VersionContext.current.isV6SoftForkActivated => + case SGlobalMethods.deserializeToMethod.name if VersionContext.current.isV3OrLaterErgoTreeVersion => val c1 = asRep[Coll[Byte]](argsV(0)) val c2 = stypeToElem(method.stype.tRange.withSubstTypes(typeSubst)) g.deserializeTo(c1)(c2) diff --git a/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala b/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala index 4b3aa2eab5..4b9b6e44fd 100644 --- a/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala +++ b/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala @@ -104,7 +104,7 @@ import sigmastate.utils.Helpers.EitherOps // required for Scala 2.11 // We have versioned check here due to fixed collections equality in 6.0.0 // (PairOfColl equal CollOverArray now) // see (https://github.com/ScorexFoundation/sigmastate-interpreter/issues/909) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { val exp = Coll( (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token1).toColl) -> 10000000L, (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token2).toColl) -> 500L diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala index 0bb92f8249..47f174fa2f 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala @@ -4876,7 +4876,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => Vector(), Map() ) - )), + ), activationType = ActivationByScriptVersion), preGeneratedSamples = Some(samples)) // test vectors to reproduce v4.x bug (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/603) @@ -5136,6 +5136,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) ), + activationType = ActivationByScriptVersion, allowNewToSucceed = true ), preGeneratedSamples = Some(ArraySeq.empty)) @@ -6059,7 +6060,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => (x: Coll[Boolean]) => SigmaDsl.xorOf(x), (x: Coll[Boolean]) => SigmaDsl.xorOf(x), "{ (x: Coll[Boolean]) => xorOf(x) }", - FuncValue(Vector((1, SBooleanArray)), XorOf(ValUse(1, SBooleanArray))))) + FuncValue(Vector((1, SBooleanArray)), XorOf(ValUse(1, SBooleanArray))), + activationType = ActivationByScriptVersion + )) } property("LogicalNot equivalence") { @@ -6334,7 +6337,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => (x: (Coll[Byte], Coll[Byte])) => SigmaDsl.xor(x._1, x._2), (x: (Coll[Byte], Coll[Byte])) => SigmaDsl.xor(x._1, x._2), "{ (x: (Coll[Byte], Coll[Byte])) => xor(x._1, x._2) }", - if (lowerMethodCallsInTests) + {if (lowerMethodCallsInTests) FuncValue( Vector((1, STuple(Vector(SByteArray, SByteArray)))), Xor( @@ -6366,7 +6369,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ), Map() ) - ) + )}, + activationType = ActivationByScriptVersion )) } @@ -8060,7 +8064,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) ) - if(!VersionContext.current.isV6SoftForkActivated) { + if(!VersionContext.current.isV3OrLaterErgoTreeVersion) { verifyCases( // (coll, (index, default)) { @@ -8698,7 +8702,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => "{ (x: Option[Long]) => x.isDefined }", FuncValue(Vector((1, SOption(SLong))), OptionIsDefined(ValUse(1, SOption(SLong)))))) - if (!VersionContext.current.isV6SoftForkActivated) { + if (!VersionContext.current.isV3OrLaterErgoTreeVersion) { verifyCases( Seq( (None -> Expected(Success(1L), 1766, costDetails3, 1766, Seq.fill(4)(2006))), @@ -8965,6 +8969,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => LongConstant(5L) ) ), + activationType = ActivationByScriptVersion, allowNewToSucceed = true), preGeneratedSamples = Some(Nil)) } @@ -9538,7 +9543,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ), ConcreteCollection(Array(BoolToSigmaProp(FalseLeaf)), SSigmaProp) ) - ))) + ), activationType = ActivationByScriptVersion)) } // Original issue: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/604 @@ -9687,6 +9692,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) ), + activationType = ActivationByScriptVersion, allowDifferentErrors = true, allowNewToSucceed = true ), diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 29b78d0e97..4ac743e7ca 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -14,27 +14,17 @@ import sigma.ast.syntax.TrueSigmaProp import sigma.ast.{SInt, _} import sigma.data.{AvlTreeData, AvlTreeFlags, CAnyValue, CAvlTree, CBigInt, CBox, CHeader, CSigmaProp, ExactNumeric, ProveDHTuple, RType} import sigma.data.CSigmaDslBuilder -import sigma.data.{AvlTreeData, AvlTreeFlags, CAnyValue, CAvlTree, CBigInt, CBox, CGroupElement, CHeader, CSigmaDslBuilder, CSigmaProp, CUnsignedBigInt, ExactNumeric, PairOfCols, ProveDHTuple, RType} +import sigma.data.{CGroupElement, CUnsignedBigInt} import sigma.crypto.SecP256K1Group -import sigma.data.{CBigInt, CBox, CGroupElement, CHeader, CSigmaDslBuilder, ExactNumeric, RType} -import sigma.data.{CBigInt, CBox, CHeader, CSigmaDslBuilder, ExactNumeric, PairOfCols, RType} import sigma.eval.{CostDetails, SigmaDsl, TracedCost} import sigma.serialization.ValueCodes.OpCode import sigma.util.Extensions.{BooleanOps, IntOps} import sigmastate.eval.{CContext, CPreHeader} -import sigma.util.Extensions.{BooleanOps, IntOps} -import sigma.serialization.ValueCodes.OpCode -import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} -import sigma.util.Extensions.{BooleanOps, IntOps} -import sigma.data.RType -import sigma.serialization.ValueCodes.OpCode -import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} import sigma.pow.Autolykos2PowValidation import sigmastate.exceptions.MethodNotFound import sigmastate.utils.Extensions.ByteOpsForSigma import sigmastate.utils.Helpers import sigma.Extensions.ArrayOps -import sigma.Extensions.{ArrayOps, CollOps} import sigma.crypto.CryptoConstants import sigma.interpreter.{ContextExtension, ProverResult} @@ -937,7 +927,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => property("BigInt - 6.0 features") { import sigma.data.OrderingOps.BigIntOrdering - if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + if (ergoTreeVersionInTests < VersionContext.V6SoftForkVersion) { // The `Upcast(bigInt, SBigInt)` node is never produced by ErgoScript compiler, but is still valid ErgoTree. // Fixed in 6.0 assertExceptionThrown( @@ -1389,18 +1379,24 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => // for tree v0, the result is the same for all versions (Coll(t1.bytes: _*), 0) -> Expected( Success(Helpers.decodeBytes("100108d27300")), - cost = 1793, + costOpt = None, expectedDetails = CostDetails.ZeroCost, - newCost = 2065, + newCostOpt = None, newVersionedResults = expectedSuccessForAllTreeVersions(Helpers.decodeBytes("100108d27300"), 2065, costDetails(1)) ), // for tree version > 0, the result depend on activated version (Coll(t2.bytes: _*), 0) -> Expected( Success(expectedTreeBytes_beforeV6), - cost = 1793, + costOpt = None, expectedDetails = CostDetails.ZeroCost, - newCost = 2065, - newVersionedResults = expectedSuccessForAllTreeVersions(expectedTreeBytes_V6, 2065, costDetails(1))) + newCostOpt = None, + newVersionedResults = Seq( + 0 -> (ExpectedResult(Success(expectedTreeBytes_beforeV6), Some(2015)) -> Some(costDetails(1))), + 1 -> (ExpectedResult(Success(expectedTreeBytes_beforeV6), Some(2015)) -> Some(costDetails(1))), + 2 -> (ExpectedResult(Success(expectedTreeBytes_beforeV6), Some(2015)) -> Some(costDetails(1))), + 3 -> (ExpectedResult(Success(expectedTreeBytes_V6), Some(2065)) -> Some(costDetails(1))) + ) + ) ), changedFeature( changedInVersion = VersionContext.V6SoftForkVersion, @@ -1421,7 +1417,8 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ), ConcreteCollection(Array(BoolToSigmaProp(FalseLeaf)), SSigmaProp) ) - ) + ), + activationType = ActivationByTreeVersion ) ) @@ -1868,14 +1865,19 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => Seq( Some(2L) -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793, newVersionedResults = { - expectedSuccessForAllTreeVersions(2L, 2015, trace) + Seq( + 0 -> (ExpectedResult(Failure(new java.lang.ArithmeticException("/ by zero")), Some(2029)) -> Some(trace)), + 1 -> (ExpectedResult(Failure(new java.lang.ArithmeticException("/ by zero")), Some(2029)) -> Some(trace)), + 2 -> (ExpectedResult(Failure(new java.lang.ArithmeticException("/ by zero")), Some(2029)) -> Some(trace)), + 3 -> (ExpectedResult(Success(2L), Some(2015)) -> Some(trace)) + ) } ), None -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793) ), changedFeature( changedInVersion = VersionContext.V6SoftForkVersion, { (x: Option[Long]) => val default = 1 / 0L; x.getOrElse(default) }, - { (x: Option[Long]) => if (VersionContext.current.isV6SoftForkActivated) {x.getOrElse(1 / 0L)} else {val default = 1 / 0L; x.getOrElse(default)} }, + { (x: Option[Long]) => if (VersionContext.current.isV3OrLaterErgoTreeVersion) {x.getOrElse(1 / 0L)} else {val default = 1 / 0L; x.getOrElse(default)} }, "{ (x: Option[Long]) => x.getOrElse(1 / 0L) }", FuncValue( Array((1, SOption(SLong))), @@ -1905,7 +1907,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) def scalaFuncNew(x: Coll[Int]) = { - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { x.toArray.toIndexedSeq.headOption.getOrElse(1 / 0) } else scalaFuncOld(x) } @@ -1918,7 +1920,12 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => Seq( Coll(1) -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793, newVersionedResults = { - expectedSuccessForAllTreeVersions(1, 2029, trace) + Seq( + 0 -> (ExpectedResult(Failure(new java.lang.ArithmeticException("/ by zero")), Some(2029)) -> Some(trace)), + 1 -> (ExpectedResult(Failure(new java.lang.ArithmeticException("/ by zero")), Some(2029)) -> Some(trace)), + 2 -> (ExpectedResult(Failure(new java.lang.ArithmeticException("/ by zero")), Some(2029)) -> Some(trace)), + 3 -> (ExpectedResult(Success(1), Some(2029)) -> Some(trace)) + ) } ), Coll[Int]() -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793) ), @@ -2448,7 +2455,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => lazy val bitOr = newFeature[(UnsignedBigInt, UnsignedBigInt), UnsignedBigInt]( { (x: (UnsignedBigInt, UnsignedBigInt)) => (x._1 | x._2) }, "{ (x: (UnsignedBigInt, UnsignedBigInt)) => x._1.bitwiseOr(x._2) }", - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { FuncValue( Array((1, SPair(SUnsignedBigInt, SUnsignedBigInt))), MethodCall.typed[Value[SUnsignedBigInt.type]]( @@ -2483,7 +2490,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => lazy val bitNot = newFeature[UnsignedBigInt, UnsignedBigInt]( { (x: UnsignedBigInt) => x.bitwiseInverse() }, "{ (x: UnsignedBigInt) => x.bitwiseInverse }", - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { FuncValue( Array((1, SUnsignedBigInt)), MethodCall.typed[Value[SUnsignedBigInt.type]]( @@ -2849,7 +2856,16 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => lazy val some = newFeature( { (x: Byte) => CSigmaDslBuilder.none[Byte]() }, "{ (x: Byte) => Global.none[Byte]() }", - sinceVersion = V6SoftForkVersion) + FuncValue( + Array((1, SByte)), + MethodCall.typed[Value[SOption[SByte.type]]]( + Global, + SGlobalMethods.noneMethod.withConcreteTypes(Map(STypeVar("T") -> SByte)), + IndexedSeq(), + Map(STypeVar("T") -> SByte) + ) + ), + sinceVersion = V6SoftForkVersion) val cases = Seq( (0.toByte, Success(None)), (1.toByte, Success(None)) diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index 7f3f28b791..90e104defe 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -50,8 +50,12 @@ class SigmaDslTesting extends AnyPropSpec with Matchers with SigmaTestingData with SigmaContractSyntax with CompilerTestingCommons with ObjectGenerators { suite => + override def Coll[T](items: T*)(implicit cT: RType[T]): Coll[T] = super.Coll(items:_*) + protected val ActivationByScriptVersion: Byte = 0.toByte + protected val ActivationByTreeVersion: Byte = 1.toByte + lazy val spec: ContractSpec = TestContractSpec(suite)(new TestingIRContext) override def contractEnv: ScriptEnv = Map() @@ -130,6 +134,9 @@ class SigmaDslTesting extends AnyPropSpec /** Version in which the feature is first implemented of changed. */ def sinceVersion: Byte + /** 0 = script version based activation, 1 = tree version based activation */ + def activationType: Byte + /** Script containing this feature. */ def script: String @@ -329,7 +336,9 @@ class SigmaDslTesting extends AnyPropSpec val pkAlice = prover.pubKeys.head.toSigmaPropValue val env = Map("pkAlice" -> pkAlice) // Compile script the same way it is performed by applications (i.e. via Ergo Appkit) - val prop = compile(env, code)(IR).asSigmaProp + val prop = VersionContext.withVersions(3, 3) { + compile(env, code)(IR).asSigmaProp + } // Add additional operations which are not yet implemented in ErgoScript compiler val multisig = AtLeast( @@ -404,10 +413,13 @@ class SigmaDslTesting extends AnyPropSpec ctx } - val (expectedResult, expectedCost) = if (activatedVersionInTests < sinceVersion) + val (expectedResult, expectedCost) = if ( + (activationType == ActivationByScriptVersion && activatedVersionInTests < sinceVersion) || + (activationType == ActivationByTreeVersion && ergoTreeVersionInTests < sinceVersion) + ) { (expected.oldResult, expected.verificationCostOpt) - else { - val res = expected.newResults(ergoTreeVersionInTests) + } else { + val res = expected.newResults(sinceVersion) (res._1, res._1.verificationCost) } @@ -463,7 +475,8 @@ class SigmaDslTesting extends AnyPropSpec val verificationCost = cost.toIntExact if (expectedCost.isDefined) { assertResult(expectedCost.get, - s"Actual verify() cost $cost != expected ${expectedCost.get} (version: ${VersionContext.current.activatedVersion})")(verificationCost) + s"Actual verify() cost $cost != expected ${expectedCost.get} " + + s"(script version: ${VersionContext.current.activatedVersion}, tree version: ${VersionContext.current.ergoTreeVersion})")(verificationCost) } case Failure(t) => throw t @@ -513,6 +526,8 @@ class SigmaDslTesting extends AnyPropSpec override def sinceVersion: Byte = 0 + override val activationType = ActivationByScriptVersion + override def isSupportedIn(vc: VersionContext): Boolean = true /** in v5.x the old and the new interpreters are the same */ @@ -681,6 +696,7 @@ class SigmaDslTesting extends AnyPropSpec printExpectedExpr: Boolean = true, logScript: Boolean = LogScriptDefault, allowNewToSucceed: Boolean = false, + override val activationType: Byte = ActivationByTreeVersion, override val allowDifferentErrors: Boolean = false )(implicit IR: IRContext, override val evalSettings: EvalSettings, val tA: RType[A], val tB: RType[B]) extends Feature[A, B] { feature => @@ -771,10 +787,16 @@ class SigmaDslTesting extends AnyPropSpec override def checkExpected(input: A, expected: Expected[B]): Unit = { // check the new implementation with Scala semantic function val newRes = VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) { - checkEq(scalaFuncNew)(newF)(input) + checkEq(scalaFuncNew)(newF)(input) + } + + val checkOld = if(changedInVersion < V6SoftForkVersion) { + VersionContext.current.activatedVersion < changedInVersion + } else { + VersionContext.current.ergoTreeVersion < changedInVersion } - if (VersionContext.current.activatedVersion < changedInVersion) { + if (checkOld) { // check the old implementation with Scala semantic val expectedOldRes = expected.value @@ -874,12 +896,13 @@ class SigmaDslTesting extends AnyPropSpec override val scalaFuncNew: A => B, expectedExpr: Option[SValue], printExpectedExpr: Boolean = true, + override val activationType: Byte = ActivationByTreeVersion, logScript: Boolean = LogScriptDefault )(implicit IR: IRContext, override val evalSettings: EvalSettings, val tA: RType[A], val tB: RType[B]) extends Feature[A, B] { override def isSupportedIn(vc: VersionContext): Boolean = - vc.activatedVersion >= sinceVersion + vc.activatedVersion >= sinceVersion && vc.ergoTreeVersion >= sinceVersion override def scalaFunc: A => B = { x => if (isSupportedIn(VersionContext.current)) { @@ -1096,6 +1119,21 @@ class SigmaDslTesting extends AnyPropSpec commonNewResults.updateMany(newVersionedResults).toSeq } } + + def apply[A](value: Try[A], + costOpt: Option[Int], + expectedDetails: CostDetails, + newCostOpt: Option[Int], + newVersionedResults: Seq[(Int, (ExpectedResult[A], Option[CostDetails]))]): Expected[A] = + new Expected[A](ExpectedResult(value, costOpt)) { + override val newResults = { + val commonNewResults = defaultNewResults.map { + case (res, _) => + (ExpectedResult(res.value, newCostOpt), Option(expectedDetails)) + } + commonNewResults.updateMany(newVersionedResults).toSeq + } + } } /** Describes existing language feature which should be equally supported in both @@ -1134,12 +1172,15 @@ class SigmaDslTesting extends AnyPropSpec script: String, expectedExpr: SValue = null, allowNewToSucceed: Boolean = false, - allowDifferentErrors: Boolean = false + allowDifferentErrors: Boolean = false, + activationType: Byte = ActivationByTreeVersion ) (implicit IR: IRContext, evalSettings: EvalSettings): Feature[A, B] = { ChangedFeature(changedInVersion, script, scalaFunc, scalaFuncNew, Option(expectedExpr), allowNewToSucceed = allowNewToSucceed, - allowDifferentErrors = allowDifferentErrors) + allowDifferentErrors = allowDifferentErrors, + activationType = activationType + ) } /** Describes a NEW language feature which must NOT be supported in v4 and diff --git a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala index 0504a79c65..ce125c3be8 100644 --- a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala @@ -316,7 +316,7 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with C */ case class MInfo(methodId: Byte, method: SMethod, isResolvableFromIds: Boolean = true) - def isV6Activated = VersionContext.current.isV6SoftForkActivated + def isV6Activated = VersionContext.current.isV3OrLaterErgoTreeVersion // NOTE, the type code constants are checked above // The methodId codes as checked here, they MUST be PRESERVED. @@ -476,7 +476,7 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with C MInfo(4, MultiplyMethod), MInfo(5, NegateMethod) ) ++ { - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { Seq(MInfo(6, ExponentiateUnsignedMethod)) } else { Seq.empty @@ -550,7 +550,7 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with C MInfo(1, dataInputsMethod), MInfo(2, headersMethod), MInfo(3, preHeaderMethod), MInfo(4, inputsMethod), MInfo(5, outputsMethod), MInfo(6, heightMethod), MInfo(7, selfMethod), MInfo(8, selfBoxIndexMethod), MInfo(9, lastBlockUtxoRootHashMethod), - MInfo(10, minerPubKeyMethod)) ++ (if(VersionContext.current.isV6SoftForkActivated){ + MInfo(10, minerPubKeyMethod)) ++ (if(VersionContext.current.isV3OrLaterErgoTreeVersion){ Seq(MInfo(11, getVarV6Method), MInfo(12, getVarFromInputMethod)) } else { Seq(MInfo(11, getVarV5Method)) diff --git a/sc/shared/src/test/scala/sigmastate/SoftForkabilitySpecification.scala b/sc/shared/src/test/scala/sigmastate/SoftForkabilitySpecification.scala index c8b9f06399..1dfd3a3091 100644 --- a/sc/shared/src/test/scala/sigmastate/SoftForkabilitySpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/SoftForkabilitySpecification.scala @@ -3,7 +3,7 @@ package sigmastate import org.ergoplatform._ import org.ergoplatform.validation.ValidationRules._ import org.scalatest.BeforeAndAfterAll -import sigma.{Colls, SigmaTestingData} +import sigma.{Colls, SigmaTestingData, VersionContext} import sigma.ast._ import sigma.ast.SPrimType.MaxPrimTypeCode import sigma.ast.TypeCodes.LastConstantCode @@ -289,7 +289,7 @@ class SoftForkabilitySpecification extends SigmaTestingData trySoftForkable(false) { action true - } + }(vs) }, { case ve: ValidationException if ve.rule == rule => true case _ => false @@ -340,12 +340,14 @@ class SoftForkabilitySpecification extends SigmaTestingData } property("CheckMethod rule") { - val freeMethodId = 16.toByte - val mcBytes = Array[Byte](OpCodes.PropertyCallCode, SCollection.typeId, freeMethodId, Outputs.opCode) - val v2vs = vs.updated(CheckAndGetMethod.id, ChangedRule(Array(SCollection.typeId, freeMethodId))) - checkRule(CheckAndGetMethod, v2vs, { - ValueSerializer.deserialize(mcBytes) - }) + VersionContext.withVersions(3,0) { + val freeMethodId = 16.toByte + val mcBytes = Array[Byte](OpCodes.PropertyCallCode, SCollection.typeId, freeMethodId, Outputs.opCode) + val v2vs = vs.updated(CheckAndGetMethodV6.id, ChangedRule(Array(SCollection.typeId, freeMethodId))) + checkRule(CheckAndGetMethodV6, v2vs, { + ValueSerializer.deserialize(mcBytes) + }) + } } override protected def afterAll(): Unit = { diff --git a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala index 4075ec5d77..64516b55e6 100644 --- a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala @@ -10,13 +10,9 @@ import org.ergoplatform._ import org.scalatest.BeforeAndAfterAll import scorex.util.encode.{Base16, Base58} import sigma.Colls -import sigma.VersionContext.V6SoftForkVersion -import sigma.VersionContext.V6SoftForkVersion -import sigma.VersionContext +import sigma.VersionContext.{V6SoftForkVersion, withVersions} import sigma.data.{CAND, CAvlTree, CBox, CHeader, ProveDlog, SigmaBoolean, TrivialProp} import sigma.interpreter.ContextExtension -import sigma.data.{AvlTreeData, CAND, ProveDlog, SigmaBoolean, TrivialProp} -import sigma.VersionContext.V6SoftForkVersion import sigma.VersionContext import sigma.util.Extensions.IntOps import sigmastate.helpers.{CompilerTestingCommons, ErgoLikeContextTesting, ErgoLikeTestInterpreter, ErgoLikeTestProvingInterpreter} @@ -244,10 +240,10 @@ class TestingInterpreterSpecification extends CompilerTestingCommons | Global.encodeNbits(b) == 36626176 |} |""".stripMargin - if (activatedVersionInTests < V6SoftForkVersion) { - an [sigmastate.exceptions.MethodNotFound] should be thrownBy testEval(source) - } else { + if (ergoTreeVersionInTests >= V6SoftForkVersion) { testEval(source) + } else { + an [sigmastate.exceptions.MethodNotFound] should be thrownBy testEval(source) } } @@ -267,7 +263,7 @@ class TestingInterpreterSpecification extends CompilerTestingCommons property("BigInt downcasting to byte") { def test() = testEval("{ sigmaProp(0L.toBigInt.toByte <= CONTEXT.preHeader.version) }") - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { test() } else { an[Exception] shouldBe thrownBy(test()) @@ -276,7 +272,7 @@ class TestingInterpreterSpecification extends CompilerTestingCommons property("BigInt downcasting to short") { def test() = testEval("{ sigmaProp(0L.toBigInt.toShort <= CONTEXT.preHeader.version.toShort) }") - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { test() } else { an[Exception] shouldBe thrownBy(test()) @@ -285,7 +281,7 @@ class TestingInterpreterSpecification extends CompilerTestingCommons property("BigInt downcasting to int") { def test() = testEval("{ sigmaProp(1L.toBigInt.toInt < CONTEXT.preHeader.timestamp.toInt) }") - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { test() } else { an[Exception] shouldBe thrownBy(test()) @@ -294,7 +290,7 @@ class TestingInterpreterSpecification extends CompilerTestingCommons property("BigInt downcasting to long") { def test() = testEval("{ sigmaProp(1L.toBigInt.toLong < CONTEXT.preHeader.timestamp) }") - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { test() } else { an[Exception] shouldBe thrownBy(test()) @@ -355,10 +351,10 @@ class TestingInterpreterSpecification extends CompilerTestingCommons | Global.powHit(k, msg, nonce, h, N) <= b // hit == b in this example |} |""".stripMargin - if (activatedVersionInTests < V6SoftForkVersion) { - an [sigmastate.exceptions.MethodNotFound] should be thrownBy testEval(source) - } else { + if (ergoTreeVersionInTests >= V6SoftForkVersion) { testEval(source) + } else { + an [sigmastate.exceptions.MethodNotFound] should be thrownBy testEval(source) } } @@ -516,10 +512,10 @@ class TestingInterpreterSpecification extends CompilerTestingCommons | } | """.stripMargin - if (activatedVersionInTests < V6SoftForkVersion) { - an [Exception] should be thrownBy testEval(source) - } else { + if (ergoTreeVersionInTests >= V6SoftForkVersion) { testEval(source) + } else { + an [Exception] should be thrownBy testEval(source) } } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 2194414ab0..6941be2145 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -127,7 +127,7 @@ class BasicOpsSpecification extends CompilerTestingCommons propExp.asSigmaProp } else { // compile with the latest compiler version, to get validation exception during execution, not compilation error - withVersions(VersionContext.MaxSupportedScriptVersion, ergoTreeVersionInTests) { + withVersions(VersionContext.MaxSupportedScriptVersion, VersionContext.MaxSupportedScriptVersion) { compile(env, script).asBoolValue.toSigmaProp } } @@ -152,7 +152,7 @@ class BasicOpsSpecification extends CompilerTestingCommons val ctx = ErgoLikeContextTesting(currentHeight = 0, lastBlockUtxoRoot = AvlTreeData.dummy, ErgoLikeContextTesting.dummyPubkey, boxesToSpend = IndexedSeq(boxToSpend), - spendingTransaction = tx, self = boxToSpend, activatedVersionInTests) + spendingTransaction = tx, self = boxToSpend, ergoTreeVersionInTests) val pr = prover.prove(env + (ScriptNameProp -> s"${name}_prove"), tree, ctx, fakeMessage).getOrThrow @@ -193,7 +193,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { getVarTest() } else { an[sigma.validation.ValidationException] should be thrownBy getVarTest() @@ -214,7 +214,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { getVarTest() } else { an[sigma.validation.ValidationException] should be thrownBy getVarTest() @@ -232,7 +232,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { getVarTest() } else { an[sigma.validation.ValidationException] should be thrownBy getVarTest() @@ -258,8 +258,8 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy deserTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() } @@ -279,8 +279,8 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy conversionTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy conversionTest() } else { conversionTest() } @@ -297,8 +297,8 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy conversionTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy conversionTest() } else { an[Exception] should be thrownBy conversionTest() } @@ -314,7 +314,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an[Exception] should be thrownBy conversionTest() } else { an[sigma.exceptions.InvalidArguments] should be thrownBy conversionTest() @@ -334,8 +334,8 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy conversionTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy conversionTest() } else { conversionTest() } @@ -354,8 +354,8 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy conversionTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy conversionTest() } else { conversionTest() } @@ -373,8 +373,8 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy conversionTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.serialization.SerializerException] should be thrownBy conversionTest() } else { conversionTest() } @@ -392,8 +392,8 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy conversionTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.serialization.SerializerException] should be thrownBy conversionTest() } else { an[Exception] should be thrownBy conversionTest() } @@ -410,8 +410,8 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy conversionTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy conversionTest() } else { conversionTest() } @@ -427,7 +427,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an[Exception] should be thrownBy conversionTest() } else { val t = Try(conversionTest()) @@ -504,8 +504,8 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy schnorrTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy schnorrTest() } else { schnorrTest() } @@ -525,7 +525,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an[Exception] should be thrownBy miTest() } else { miTest() @@ -545,8 +545,8 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy miTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy miTest() } else { miTest() } @@ -565,8 +565,8 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy miTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy miTest() } else { miTest() } @@ -586,8 +586,8 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy miTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy miTest() } else { miTest() } @@ -607,8 +607,8 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy miTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy miTest() } else { miTest() } @@ -628,8 +628,8 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy miTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy miTest() } else { miTest() } @@ -740,8 +740,8 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy rangeTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy rangeTest() } else { rangeTest() } @@ -799,8 +799,8 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy circuitTest() + if (ergoTreeVersionInTests < V6SoftForkVersion) { + an[sigma.validation.ValidationException] should be thrownBy circuitTest() } else { circuitTest() } @@ -818,7 +818,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { toBitsTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(toBitsTest()) @@ -840,7 +840,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { toBitsTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(toBitsTest()) @@ -857,7 +857,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { toBitsTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(toBitsTest()) @@ -875,7 +875,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { toBitsTest() } else { an[ValidationException] shouldBe thrownBy(toBitsTest()) @@ -892,7 +892,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { toBitsTest() } else { an[ValidationException] shouldBe thrownBy(toBitsTest()) @@ -910,7 +910,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseInverseTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseInverseTest()) @@ -927,7 +927,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseInverseTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseInverseTest()) @@ -944,7 +944,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseInverseTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseInverseTest()) @@ -964,7 +964,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseInverseTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseInverseTest()) @@ -985,7 +985,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseOrTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseOrTest()) @@ -1001,7 +1001,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseOrTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseOrTest()) @@ -1017,7 +1017,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseOrTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseOrTest()) @@ -1035,7 +1035,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseOrTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseOrTest()) @@ -1052,7 +1052,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseAndTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseAndTest()) @@ -1069,7 +1069,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseAndTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseAndTest()) @@ -1089,7 +1089,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseAndTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseAndTest()) @@ -1109,7 +1109,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseAndTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseAndTest()) @@ -1129,7 +1129,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseXorTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseXorTest()) @@ -1149,7 +1149,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { bitwiseAndTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseAndTest()) @@ -1166,7 +1166,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { shiftLeftTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest()) @@ -1183,7 +1183,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { an[IllegalArgumentException] shouldBe thrownBy(shiftLeftTest()) } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest()) @@ -1200,7 +1200,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { shiftLeftTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest()) @@ -1217,7 +1217,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { shiftLeftTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest()) @@ -1234,7 +1234,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { shiftLeftTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest()) @@ -1250,7 +1250,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { an[ArithmeticException] shouldBe thrownBy(shiftLeftTest()) } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest()) @@ -1267,7 +1267,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { an[java.lang.IllegalArgumentException] shouldBe thrownBy(shiftLeftTest()) } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest()) @@ -1283,7 +1283,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { an[ArithmeticException] shouldBe thrownBy(shiftLeftTest()) } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest()) @@ -1300,7 +1300,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { shiftRightTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest()) @@ -1317,7 +1317,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { shiftRightTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest()) @@ -1334,7 +1334,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { an[IllegalArgumentException] shouldBe thrownBy(shiftRightTest()) } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest()) @@ -1352,7 +1352,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { shiftRightTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest()) @@ -1369,7 +1369,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { an[IllegalArgumentException] shouldBe thrownBy(shiftRightTest()) } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest()) @@ -1387,7 +1387,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { shiftRightTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest()) @@ -1405,7 +1405,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { an[IllegalArgumentException] shouldBe thrownBy(shiftRightTest()) } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest()) @@ -1423,7 +1423,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { shiftRightTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest()) @@ -1441,7 +1441,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { an[java.lang.IllegalArgumentException] shouldBe thrownBy(shiftRightTest()) } else { an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest()) @@ -1459,7 +1459,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { getVarTest() } else { an[sigma.validation.ValidationException] should be thrownBy getVarTest() @@ -1480,7 +1480,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { reverseTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest()) @@ -1501,7 +1501,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { reverseTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest()) @@ -1525,7 +1525,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { reverseTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest()) @@ -1549,7 +1549,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { reverseTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest()) @@ -1573,7 +1573,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { reverseTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest()) @@ -1597,7 +1597,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { reverseTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest()) @@ -1615,7 +1615,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { getTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(getTest()) @@ -1631,7 +1631,7 @@ class BasicOpsSpecification extends CompilerTestingCommons |""".stripMargin, null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { fromTest() } else { an[sigma.validation.ValidationException] should be thrownBy(fromTest()) @@ -1647,7 +1647,7 @@ class BasicOpsSpecification extends CompilerTestingCommons |""".stripMargin, null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { fromTest() } else { an[sigma.validation.ValidationException] should be thrownBy(fromTest()) @@ -1663,7 +1663,7 @@ class BasicOpsSpecification extends CompilerTestingCommons |""".stripMargin, null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { fromTest() } else { an[sigma.validation.ValidationException] should be thrownBy(fromTest()) @@ -1680,7 +1680,7 @@ class BasicOpsSpecification extends CompilerTestingCommons |""".stripMargin, null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { fromTest() } else { an[sigma.validation.ValidationException] should be thrownBy(fromTest()) @@ -1700,7 +1700,7 @@ class BasicOpsSpecification extends CompilerTestingCommons |""".stripMargin, null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { fromTest() } else { an[sigma.validation.ValidationException] should be thrownBy(fromTest()) @@ -1717,7 +1717,7 @@ class BasicOpsSpecification extends CompilerTestingCommons |""".stripMargin, null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { fromTest() } else { an[sigma.validation.ValidationException] should be thrownBy(fromTest()) @@ -1736,7 +1736,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { toBytesTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(toBytesTest()) @@ -1755,7 +1755,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { toBytesTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(toBytesTest()) @@ -1774,7 +1774,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { toBytesTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(toBytesTest()) @@ -1791,7 +1791,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { toBytesTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(toBytesTest()) @@ -1806,7 +1806,7 @@ class BasicOpsSpecification extends CompilerTestingCommons def toBytesTest() = test("UnsignedBigInt.toBytes", env, ext, script, null) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { toBytesTest() } else { an[ValidationException] shouldBe thrownBy(toBytesTest()) @@ -1822,7 +1822,7 @@ class BasicOpsSpecification extends CompilerTestingCommons def toBytesTest() = test("UnsignedBigInt.toBytes", env, ext, script, null) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { toBytesTest() } else { an[ValidationException] shouldBe thrownBy(toBytesTest()) @@ -1839,7 +1839,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -1856,7 +1856,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -1873,7 +1873,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -1892,7 +1892,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -1913,7 +1913,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -1934,7 +1934,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -1957,7 +1957,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -1981,7 +1981,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an[sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2003,7 +2003,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an[sigma.validation.ValidationException] should be thrownBy deserTest() } else { // we have wrapped CostLimitException here @@ -2023,7 +2023,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { optTest() } else { assertExceptionThrown(optTest(), _.isInstanceOf[NoSuchElementException]) @@ -2041,7 +2041,7 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { optTest() } else { assertExceptionThrown(optTest(), _.isInstanceOf[NoSuchElementException]) @@ -2088,7 +2088,7 @@ class BasicOpsSpecification extends CompilerTestingCommons testExceededCost = false ) } - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an[sigma.validation.ValidationException] should be thrownBy powTest() } else { powTest() @@ -2120,7 +2120,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an[sigma.validation.ValidationException] should be thrownBy powTest() } else { powTest() @@ -2140,7 +2140,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an[Exception] should be thrownBy deserTest() } else { deserTest() @@ -2157,7 +2157,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2177,7 +2177,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2199,7 +2199,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2217,7 +2217,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2244,7 +2244,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2264,7 +2264,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2285,7 +2285,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2305,7 +2305,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2325,7 +2325,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2348,7 +2348,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an [sigma.validation.ValidationException] should be thrownBy deserTest() } else { an [Exception] should be thrownBy deserTest() @@ -2403,7 +2403,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an[sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2429,7 +2429,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if (activatedVersionInTests < V6SoftForkVersion) { + if (ergoTreeVersionInTests < V6SoftForkVersion) { an[sigma.validation.ValidationException] should be thrownBy deserTest() } else { deserTest() @@ -2752,7 +2752,7 @@ class BasicOpsSpecification extends CompilerTestingCommons true ) - if(VersionContext.current.isV6SoftForkActivated) { + if(VersionContext.current.isV3OrLaterErgoTreeVersion) { holTest() } else { an[sigma.validation.ValidationException] shouldBe thrownBy(holTest()) @@ -3085,7 +3085,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { getRegTest() } else { an[sigma.exceptions.ConstraintFailed] should be thrownBy getRegTest() @@ -3106,7 +3106,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { getRegTest() } else { an[java.nio.BufferUnderflowException] should be thrownBy getRegTest() @@ -3149,7 +3149,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { someTest() } else { an[sigma.validation.ValidationException] should be thrownBy someTest() @@ -3171,7 +3171,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { someTest() } else { an[sigma.validation.ValidationException] should be thrownBy someTest() @@ -3193,7 +3193,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - if (VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV3OrLaterErgoTreeVersion) { someTest() } else { an[sigma.validation.ValidationException] should be thrownBy someTest()