From 4fb3daa5e5ad4f83e5f143c85499780f9b83e169 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Sun, 19 May 2024 16:21:50 +0100 Subject: [PATCH] v6.0-serialize: all new features move to LanguageSpecificationV6 --- .../scala/sigmastate/CrossVersionProps.scala | 2 - .../scala/sigma/LanguageSpecificationV5.scala | 225 ------------ .../scala/sigma/LanguageSpecificationV6.scala | 330 +++++++++++++++++- .../test/scala/sigma/SigmaDslTesting.scala | 17 +- .../CompilerCrossVersionProps.scala | 11 +- 5 files changed, 343 insertions(+), 242 deletions(-) diff --git a/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala b/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala index 87101a1f71..e55b874dc3 100644 --- a/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala +++ b/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala @@ -31,9 +31,7 @@ trait CrossVersionProps extends AnyPropSpecLike with TestsBase { System.gc() } forEachScriptAndErgoTreeVersion(activatedVersions, ergoTreeVersions) { - VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) { testFun_Run(testName, testFun) - } } } } diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala index eabbf776aa..700b48fd13 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala @@ -125,17 +125,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => /// Boolean type operations ///----------------------------------------------------- - property("Boolean methods equivalence") { - val toByte = newFeature((x: Boolean) => x.toByte, "{ (x: Boolean) => x.toByte }") - - val cases = Seq( - (true, Success(1.toByte)), - (false, Success(0.toByte)) - ) - - testCases(cases, toByte) - } - property("BinXor(logical XOR) equivalence") { val binXor = existingFeature((x: (Boolean, Boolean)) => x._1 ^ x._2, "{ (x: (Boolean, Boolean)) => x._1 ^ x._2 }", @@ -950,31 +939,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => swapArgs(LE_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GE, SByte)), ">=", GE.apply)(_ >= _) } - - property("Byte methods equivalence (new features)") { - lazy val toBytes = newFeature((x: Byte) => x.toBytes, "{ (x: Byte) => x.toBytes }") - lazy val toAbs = newFeature((x: Byte) => x.toAbs, "{ (x: Byte) => x.toAbs }") - lazy val compareTo = newFeature( - (x: (Byte, Byte)) => x._1.compareTo(x._2), - "{ (x: (Byte, Byte)) => x._1.compareTo(x._2) }") - - lazy val bitOr = newFeature( - { (x: (Byte, Byte)) => (x._1 | x._2).toByteExact }, - "{ (x: (Byte, Byte)) => (x._1 | x._2).toByteExact }") - - lazy val bitAnd = newFeature( - { (x: (Byte, Byte)) => (x._1 & x._2).toByteExact }, - "{ (x: (Byte, Byte)) => (x._1 & x._2).toByteExact }") - - forAll { x: Byte => - Seq(toBytes, toAbs).foreach(f => f.checkEquality(x)) - } - - forAll { x: (Byte, Byte) => - Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) - } - } - property("Short methods equivalence") { SShort.upcast(0.toShort) shouldBe 0.toShort // boundary test case SShort.downcast(0.toShort) shouldBe 0.toShort // boundary test case @@ -1255,29 +1219,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ">=", GE.apply)(_ >= _) } - property("Short methods equivalence (new features)") { - lazy val toBytes = newFeature((x: Short) => x.toBytes, "{ (x: Short) => x.toBytes }") - lazy val toAbs = newFeature((x: Short) => x.toAbs, "{ (x: Short) => x.toAbs }") - - lazy val compareTo = newFeature((x: (Short, Short)) => x._1.compareTo(x._2), - "{ (x: (Short, Short)) => x._1.compareTo(x._2) }") - - lazy val bitOr = newFeature( - { (x: (Short, Short)) => (x._1 | x._2).toShortExact }, - "{ (x: (Short, Short)) => x._1 | x._2 }") - - lazy val bitAnd = newFeature( - { (x: (Short, Short)) => (x._1 & x._2).toShortExact }, - "{ (x: (Short, Short)) => x._1 & x._2 }") - - forAll { x: Short => - Seq(toBytes, toAbs).foreach(_.checkEquality(x)) - } - forAll { x: (Short, Short) => - Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) - } - } - property("Int methods equivalence") { SInt.upcast(0) shouldBe 0 // boundary test case SInt.downcast(0) shouldBe 0 // boundary test case @@ -1558,28 +1499,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ">=", GE.apply)(_ >= _) } - property("Int methods equivalence (new features)") { - lazy val toBytes = newFeature((x: Int) => x.toBytes, "{ (x: Int) => x.toBytes }") - lazy val toAbs = newFeature((x: Int) => x.toAbs, "{ (x: Int) => x.toAbs }") - lazy val compareTo = newFeature((x: (Int, Int)) => x._1.compareTo(x._2), - "{ (x: (Int, Int)) => x._1.compareTo(x._2) }") - - lazy val bitOr = newFeature( - { (x: (Int, Int)) => x._1 | x._2 }, - "{ (x: (Int, Int)) => x._1 | x._2 }") - - lazy val bitAnd = newFeature( - { (x: (Int, Int)) => x._1 & x._2 }, - "{ (x: (Int, Int)) => x._1 & x._2 }") - - forAll { x: Int => - Seq(toBytes, toAbs).foreach(_.checkEquality(x)) - } - forAll { x: (Int, Int) => - Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) - } - } - property("Long downcast and upcast identity") { forAll { x: Long => SLong.upcast(x) shouldBe x // boundary test case @@ -1877,28 +1796,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ">=", GE.apply)(_ >= _) } - property("Long methods equivalence (new features)") { - lazy val toBytes = newFeature((x: Long) => x.toBytes, "{ (x: Long) => x.toBytes }") - lazy val toAbs = newFeature((x: Long) => x.toAbs, "{ (x: Long) => x.toAbs }") - lazy val compareTo = newFeature((x: (Long, Long)) => x._1.compareTo(x._2), - "{ (x: (Long, Long)) => x._1.compareTo(x._2) }") - - lazy val bitOr = newFeature( - { (x: (Long, Long)) => x._1 | x._2 }, - "{ (x: (Long, Long)) => x._1 | x._2 }") - - lazy val bitAnd = newFeature( - { (x: (Long, Long)) => x._1 & x._2 }, - "{ (x: (Long, Long)) => x._1 & x._2 }") - - forAll { x: Long => - Seq(toBytes, toAbs).foreach(_.checkEquality(x)) - } - forAll { x: (Long, Long) => - Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) - } - } - property("BigInt methods equivalence") { verifyCases( { @@ -2157,59 +2054,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ">=", GE.apply)(o.gteq(_, _)) } - property("BigInt methods equivalence (new features)") { - // TODO v6.0: the behavior of `upcast` for BigInt is different from all other Numeric types (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/877) - // The `Upcast(bigInt, SBigInt)` node is never produced by ErgoScript compiler, but is still valid ErgoTree. - // It makes sense to fix this inconsistency as part of upcoming forks - assertExceptionThrown( - SBigInt.upcast(CBigInt(new BigInteger("0", 16)).asInstanceOf[AnyVal]), - _.getMessage.contains("Cannot upcast value") - ) - - // TODO v6.0: the behavior of `downcast` for BigInt is different from all other Numeric types (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/877) - // The `Downcast(bigInt, SBigInt)` node is never produced by ErgoScript compiler, but is still valid ErgoTree. - // It makes sense to fix this inconsistency as part of HF - assertExceptionThrown( - SBigInt.downcast(CBigInt(new BigInteger("0", 16)).asInstanceOf[AnyVal]), - _.getMessage.contains("Cannot downcast value") - ) - - val toByte = newFeature((x: BigInt) => x.toByte, - "{ (x: BigInt) => x.toByte }", - FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SByte))) - - val toShort = newFeature((x: BigInt) => x.toShort, - "{ (x: BigInt) => x.toShort }", - FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SShort))) - - val toInt = newFeature((x: BigInt) => x.toInt, - "{ (x: BigInt) => x.toInt }", - FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SInt))) - - val toLong = newFeature((x: BigInt) => x.toLong, - "{ (x: BigInt) => x.toLong }", - FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SLong))) - - lazy val toBytes = newFeature((x: BigInt) => x.toBytes, "{ (x: BigInt) => x.toBytes }") - lazy val toAbs = newFeature((x: BigInt) => x.toAbs, "{ (x: BigInt) => x.toAbs }") - - lazy val compareTo = newFeature((x: (BigInt, BigInt)) => x._1.compareTo(x._2), - "{ (x: (BigInt, BigInt)) => x._1.compareTo(x._2) }") - - lazy val bitOr = newFeature({ (x: (BigInt, BigInt)) => x._1 | x._2 }, - "{ (x: (BigInt, BigInt)) => x._1 | x._2 }") - - lazy val bitAnd = newFeature({ (x: (BigInt, BigInt)) => x._1 & x._2 }, - "{ (x: (BigInt, BigInt)) => x._1 & x._2 }") - - forAll { x: BigInt => - Seq(toByte, toShort, toInt, toLong, toBytes, toAbs).foreach(_.checkEquality(x)) - } - forAll { x: (BigInt, BigInt) => - Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) - } - } - /** Executed a series of test cases of NEQ operation verify using two _different_ * data instances `x` and `y`. * @param cost the expected cost of `verify` (the same for all cases) @@ -3944,16 +3788,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ))) } - property("Box properties equivalence (new features)") { - // TODO v6.0: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/416 - val getReg = newFeature((x: Box) => x.getReg[Int](1).get, - "{ (x: Box) => x.getReg[Int](1).get }") - - forAll { box: Box => - Seq(getReg).foreach(_.checkEquality(box)) - } - } - property("Conditional access to registers") { def boxWithRegisters(regs: AdditionalRegisters): Box = { SigmaDsl.Box(testBox(20, TrueTree, 0, Seq(), regs)) @@ -7531,36 +7365,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => preGeneratedSamples = Some(samples)) } - // TODO v6.0 (3h): https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479 - property("Coll find method equivalence") { - val find = newFeature((x: Coll[Int]) => x.find({ (v: Int) => v > 0 }), - "{ (x: Coll[Int]) => x.find({ (v: Int) => v > 0} ) }") - forAll { x: Coll[Int] => - find.checkEquality(x) - } - } - - // TODO v6.0 (3h): https://github.com/ScorexFoundation/sigmastate-interpreter/issues/418 - property("Coll bitwise methods equivalence") { - val shiftRight = newFeature( - { (x: Coll[Boolean]) => - if (x.size > 2) x.slice(0, x.size - 2) else Colls.emptyColl[Boolean] - }, - "{ (x: Coll[Boolean]) => x >> 2 }") - forAll { x: Array[Boolean] => - shiftRight.checkEquality(Colls.fromArray(x)) - } - } - - // TODO v6.0 (3h): https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479 - property("Coll diff methods equivalence") { - val diff = newFeature((x: (Coll[Int], Coll[Int])) => x._1.diff(x._2), - "{ (x: (Coll[Int], Coll[Int])) => x._1.diff(x._2) }") - forAll { (x: Coll[Int], y: Coll[Int]) => - diff.checkEquality((x, y)) - } - } - property("Coll fold method equivalence") { val n = ExactNumeric.IntIsExactNumeric val costDetails1 = TracedCost( @@ -8972,17 +8776,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) )) } - // TODO v6.0: implement Option.fold (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479) - property("Option new methods") { - val n = ExactNumeric.LongIsExactNumeric - val fold = newFeature({ (x: Option[Long]) => x.fold(5.toLong)( (v: Long) => n.plus(v, 1) ) }, - "{ (x: Option[Long]) => x.fold(5, { (v: Long) => v + 1 }) }") - - forAll { x: Option[Long] => - Seq(fold).map(_.checkEquality(x)) - } - } - property("Option fold workaround method") { val costDetails1 = TracedCost( traceBase ++ Array( @@ -9418,24 +9211,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => preGeneratedSamples = Some(Seq())) } - // TODO v6.0 (3h): implement allZK func https://github.com/ScorexFoundation/sigmastate-interpreter/issues/543 - property("allZK equivalence") { - lazy val allZK = newFeature((x: Coll[SigmaProp]) => SigmaDsl.allZK(x), - "{ (x: Coll[SigmaProp]) => allZK(x) }") - forAll { x: Coll[SigmaProp] => - allZK.checkEquality(x) - } - } - - // TODO v6.0 (3h): implement anyZK func https://github.com/ScorexFoundation/sigmastate-interpreter/issues/543 - property("anyZK equivalence") { - lazy val anyZK = newFeature((x: Coll[SigmaProp]) => SigmaDsl.anyZK(x), - "{ (x: Coll[SigmaProp]) => anyZK(x) }") - forAll { x: Coll[SigmaProp] => - anyZK.checkEquality(x) - } - } - property("allOf equivalence") { def costDetails(i: Int) = TracedCost(traceBase :+ ast.SeqCostItem(CompanionDesc(AND), PerItemCost(JitCost(10), JitCost(5), 32), i)) verifyCases( diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 16b8fffbf1..20faabe128 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -1,9 +1,12 @@ package sigma -import sigma.ast.{FuncValue, Global, MethodCall, SByte, SCollection, SGlobalMethods, STypeVar, ValUse, Value} -import sigma.data.RType +import sigma.ast.{Downcast, FuncValue, Global, MethodCall, SBigInt, SByte, SGlobalMethods, SInt, SLong, SShort, STypeVar, ValUse} +import sigma.data.{CBigInt, ExactNumeric, RType} import sigma.eval.SigmaDsl +import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} +import sigmastate.exceptions.MethodNotFound +import java.math.BigInteger import scala.util.Success /** This suite tests all operations for v6.0 version of the language. @@ -14,8 +17,6 @@ import scala.util.Success class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => override def languageVersion: Byte = VersionContext.V6SoftForkVersion - import TestData._ - def mkSerializeFeature[A: RType]: Feature[A, Coll[Byte]] = { val tA = RType[A] val tpe = Evaluation.rtypeToSType(tA) @@ -57,4 +58,325 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) testCases(cases, serializeShort) } + + // TODO v6.0: implement serialization roundtrip tests after merge with deserializeTo + + + property("Boolean.toByte") { + val toByte = newFeature((x: Boolean) => x.toByte, "{ (x: Boolean) => x.toByte }", + sinceVersion = VersionContext.V6SoftForkVersion + ) + + val cases = Seq( + (true, Success(1.toByte)), + (false, Success(0.toByte)) + ) + + if (toByte.isSupportedIn(VersionContext.current)) { + // TODO v6.0: implement as part of https://github.com/ScorexFoundation/sigmastate-interpreter/pull/932 + assertExceptionThrown( + testCases(cases, toByte), + rootCauseLike[MethodNotFound]("Cannot find method") + ) + } + else + testCases(cases, toByte) + } + + property("Byte methods equivalence (new features)") { + // TODO v6.0: implement as part of https://github.com/ScorexFoundation/sigmastate-interpreter/issues/474 + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions the new features are not supported + // which is checked below + + lazy val toAbs = newFeature((x: Byte) => x.toAbs, "{ (x: Byte) => x.toAbs }", + sinceVersion = VersionContext.V6SoftForkVersion) + + lazy val compareTo = newFeature( + (x: (Byte, Byte)) => x._1.compareTo(x._2), + "{ (x: (Byte, Byte)) => x._1.compareTo(x._2) }", + sinceVersion = VersionContext.V6SoftForkVersion) + + lazy val bitOr = newFeature( + { (x: (Byte, Byte)) => (x._1 | x._2).toByteExact }, + "{ (x: (Byte, Byte)) => (x._1 | x._2) }", + sinceVersion = VersionContext.V6SoftForkVersion) + + lazy val bitAnd = newFeature( + { (x: (Byte, Byte)) => (x._1 & x._2).toByteExact }, + "{ (x: (Byte, Byte)) => (x._1 & x._2) }", + sinceVersion = VersionContext.V6SoftForkVersion) + + forAll { x: Byte => + Seq(toAbs).foreach(f => f.checkEquality(x)) + } + + forAll { x: (Byte, Byte) => + Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) + } + } + } + + // TODO v6.0: enable as part of https://github.com/ScorexFoundation/sigmastate-interpreter/issues/474 + property("Short methods equivalence (new features)") { + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions the new features are not supported + // which is checked below + + lazy val toAbs = newFeature((x: Short) => x.toAbs, "{ (x: Short) => x.toAbs }", + sinceVersion = VersionContext.V6SoftForkVersion) + + lazy val compareTo = newFeature((x: (Short, Short)) => x._1.compareTo(x._2), + "{ (x: (Short, Short)) => x._1.compareTo(x._2) }", + sinceVersion = VersionContext.V6SoftForkVersion) + + lazy val bitOr = newFeature( + { (x: (Short, Short)) => (x._1 | x._2).toShortExact }, + "{ (x: (Short, Short)) => x._1 | x._2 }", + sinceVersion = VersionContext.V6SoftForkVersion) + + lazy val bitAnd = newFeature( + { (x: (Short, Short)) => (x._1 & x._2).toShortExact }, + "{ (x: (Short, Short)) => x._1 & x._2 }", + sinceVersion = VersionContext.V6SoftForkVersion) + + forAll { x: Short => + Seq(toAbs).foreach(_.checkEquality(x)) + } + forAll { x: (Short, Short) => + Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) + } + } + } + + property("Int methods equivalence (new features)") { + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions the new features are not supported + // which is checked below + lazy val toAbs = newFeature((x: Int) => x.toAbs, "{ (x: Int) => x.toAbs }", + sinceVersion = VersionContext.V6SoftForkVersion) + lazy val compareTo = newFeature((x: (Int, Int)) => x._1.compareTo(x._2), + "{ (x: (Int, Int)) => x._1.compareTo(x._2) }", + sinceVersion = VersionContext.V6SoftForkVersion) + lazy val bitOr = newFeature( + { (x: (Int, Int)) => x._1 | x._2 }, + "{ (x: (Int, Int)) => x._1 | x._2 }", + sinceVersion = VersionContext.V6SoftForkVersion) + lazy val bitAnd = newFeature( + { (x: (Int, Int)) => x._1 & x._2 }, + "{ (x: (Int, Int)) => x._1 & x._2 }", + sinceVersion = VersionContext.V6SoftForkVersion) + forAll { x: Int => + Seq(toAbs).foreach(_.checkEquality(x)) + } + forAll { x: (Int, Int) => + Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) + } + } + } + + property("Long methods equivalence (new features)") { + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions the new features are not supported + // which is checked below + lazy val toAbs = newFeature((x: Long) => x.toAbs, "{ (x: Long) => x.toAbs }", + sinceVersion = VersionContext.V6SoftForkVersion) + lazy val compareTo = newFeature((x: (Long, Long)) => x._1.compareTo(x._2), + "{ (x: (Long, Long)) => x._1.compareTo(x._2) }", + sinceVersion = VersionContext.V6SoftForkVersion) + + lazy val bitOr = newFeature( + { (x: (Long, Long)) => x._1 | x._2 }, + "{ (x: (Long, Long)) => x._1 | x._2 }", + sinceVersion = VersionContext.V6SoftForkVersion) + + lazy val bitAnd = newFeature( + { (x: (Long, Long)) => x._1 & x._2 }, + "{ (x: (Long, Long)) => x._1 & x._2 }", + sinceVersion = VersionContext.V6SoftForkVersion) + + forAll { x: Long => + Seq(toAbs).foreach(_.checkEquality(x)) + } + forAll { x: (Long, Long) => + Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) + } + } + + } + + property("BigInt methods equivalence (new features)") { + // TODO v6.0: the behavior of `upcast` for BigInt is different from all other Numeric types (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/877) + // The `Upcast(bigInt, SBigInt)` node is never produced by ErgoScript compiler, but is still valid ErgoTree. + // It makes sense to fix this inconsistency as part of upcoming forks + assertExceptionThrown( + SBigInt.upcast(CBigInt(new BigInteger("0", 16)).asInstanceOf[AnyVal]), + _.getMessage.contains("Cannot upcast value") + ) + + // TODO v6.0: the behavior of `downcast` for BigInt is different from all other Numeric types (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/877) + // The `Downcast(bigInt, SBigInt)` node is never produced by ErgoScript compiler, but is still valid ErgoTree. + // It makes sense to fix this inconsistency as part of HF + assertExceptionThrown( + SBigInt.downcast(CBigInt(new BigInteger("0", 16)).asInstanceOf[AnyVal]), + _.getMessage.contains("Cannot downcast value") + ) + + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions the new features are not supported + // which is checked below + val toByte = newFeature((x: BigInt) => x.toByte, + "{ (x: BigInt) => x.toByte }", + FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SByte)), + sinceVersion = VersionContext.V6SoftForkVersion) + val toShort = newFeature((x: BigInt) => x.toShort, + "{ (x: BigInt) => x.toShort }", + FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SShort)), + sinceVersion = VersionContext.V6SoftForkVersion) + val toInt = newFeature((x: BigInt) => x.toInt, + "{ (x: BigInt) => x.toInt }", + FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SInt)), + sinceVersion = VersionContext.V6SoftForkVersion) + val toLong = newFeature((x: BigInt) => x.toLong, + "{ (x: BigInt) => x.toLong }", + FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SLong)), + sinceVersion = VersionContext.V6SoftForkVersion) + lazy val toAbs = newFeature((x: BigInt) => x.toAbs, "{ (x: BigInt) => x.toAbs }", + sinceVersion = VersionContext.V6SoftForkVersion) + lazy val compareTo = newFeature((x: (BigInt, BigInt)) => x._1.compareTo(x._2), + "{ (x: (BigInt, BigInt)) => x._1.compareTo(x._2) }", + sinceVersion = VersionContext.V6SoftForkVersion) + lazy val bitOr = newFeature({ (x: (BigInt, BigInt)) => x._1 | x._2 }, + "{ (x: (BigInt, BigInt)) => x._1 | x._2 }", + sinceVersion = VersionContext.V6SoftForkVersion) + lazy val bitAnd = newFeature({ (x: (BigInt, BigInt)) => x._1 & x._2 }, + "{ (x: (BigInt, BigInt)) => x._1 & x._2 }", + sinceVersion = VersionContext.V6SoftForkVersion) + + forAll { x: BigInt => + Seq(toByte, toShort, toInt, toLong, toAbs).foreach(_.checkEquality(x)) + } + forAll { x: (BigInt, BigInt) => + Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) + } + } + } + + property("Box properties equivalence (new features)") { + // TODO v6.0: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/416 + val getReg = newFeature((x: Box) => x.getReg[Int](1).get, + "{ (x: Box) => x.getReg[Int](1).get }", + sinceVersion = VersionContext.V6SoftForkVersion) + + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions getReg is not supported + // which is checked below + + forAll { box: Box => + Seq(getReg).foreach(_.checkEquality(box)) + } + } + } + + // TODO v6.0 (3h): https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479 + property("Coll find method equivalence") { + val find = newFeature((x: Coll[Int]) => x.find({ (v: Int) => v > 0 }), + "{ (x: Coll[Int]) => x.find({ (v: Int) => v > 0} ) }", + sinceVersion = VersionContext.V6SoftForkVersion) + + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions getReg is not supported + // which is checked below + + forAll { x: Coll[Int] => + find.checkEquality(x) + } + } + } + + // TODO v6.0 (3h): https://github.com/ScorexFoundation/sigmastate-interpreter/issues/418 + property("Coll bitwise methods equivalence") { + val shiftRight = newFeature( + { (x: Coll[Boolean]) => + if (x.size > 2) x.slice(0, x.size - 2) else Colls.emptyColl[Boolean] + }, + "{ (x: Coll[Boolean]) => x >> 2 }", + sinceVersion = VersionContext.V6SoftForkVersion) + + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions getReg is not supported + // which is checked below + + forAll { x: Array[Boolean] => + shiftRight.checkEquality(Colls.fromArray(x)) + } + } + } + + // TODO v6.0 (3h): https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479 + property("Coll diff methods equivalence") { + val diff = newFeature((x: (Coll[Int], Coll[Int])) => x._1.diff(x._2), + "{ (x: (Coll[Int], Coll[Int])) => x._1.diff(x._2) }", + sinceVersion = VersionContext.V6SoftForkVersion) + + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions getReg is not supported + // which is checked below + + forAll { (x: Coll[Int], y: Coll[Int]) => + diff.checkEquality((x, y)) + } + } + } + + // TODO v6.0: implement Option.fold (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479) + property("Option new methods") { + val n = ExactNumeric.LongIsExactNumeric + val fold = newFeature({ (x: Option[Long]) => x.fold(5.toLong)( (v: Long) => n.plus(v, 1) ) }, + "{ (x: Option[Long]) => x.fold(5, { (v: Long) => v + 1 }) }", + sinceVersion = VersionContext.V6SoftForkVersion) + + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions getReg is not supported + // which is checked below + + forAll { x: Option[Long] => + Seq(fold).map(_.checkEquality(x)) + } + } + } + + // TODO v6.0 (3h): implement allZK func https://github.com/ScorexFoundation/sigmastate-interpreter/issues/543 + property("allZK equivalence") { + lazy val allZK = newFeature((x: Coll[SigmaProp]) => SigmaDsl.allZK(x), + "{ (x: Coll[SigmaProp]) => allZK(x) }", + sinceVersion = VersionContext.V6SoftForkVersion) + + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions getReg is not supported + // which is checked below + + forAll { x: Coll[SigmaProp] => + allZK.checkEquality(x) + } + } + } + + // TODO v6.0 (3h): implement anyZK func https://github.com/ScorexFoundation/sigmastate-interpreter/issues/543 + property("anyZK equivalence") { + lazy val anyZK = newFeature((x: Coll[SigmaProp]) => SigmaDsl.anyZK(x), + "{ (x: Coll[SigmaProp]) => anyZK(x) }", + sinceVersion = VersionContext.V6SoftForkVersion) + + if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { + // NOTE, for such versions getReg is not supported + // which is checked below + + forAll { x: Coll[SigmaProp] => + anyZK.checkEquality(x) + } + } + } + + } diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index d776238011..28c9c05fec 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -123,6 +123,9 @@ class SigmaDslTesting extends AnyPropSpec /** Type descriptor for type B. */ def tB: RType[B] + /** Checks if this feature is supported in the given version context. */ + def isSupportedIn(vc: VersionContext): Boolean + /** Script containing this feature. */ def script: String @@ -501,6 +504,8 @@ class SigmaDslTesting extends AnyPropSpec implicit val cs = compilerSettingsInTests + override def isSupportedIn(vc: VersionContext): Boolean = true + /** in v5.x the old and the new interpreters are the same */ override val oldImpl = () => funcJit[A, B](script) override val newImpl = () => funcJit[A, B](script) @@ -671,6 +676,8 @@ class SigmaDslTesting extends AnyPropSpec implicit val cs = compilerSettingsInTests + override def isSupportedIn(vc: VersionContext): Boolean = true + /** Apply given function to the context variable 1 */ private def getApplyExpr(funcValue: SValue) = { val sType = Evaluation.rtypeToSType(RType[A]) @@ -852,8 +859,8 @@ class SigmaDslTesting extends AnyPropSpec )(implicit IR: IRContext, override val evalSettings: EvalSettings, val tA: RType[A], val tB: RType[B]) extends Feature[A, B] { - def isFeatureShouldWork: Boolean = - activatedVersionInTests >= sinceVersion && ergoTreeVersionInTests >= sinceVersion + override def isSupportedIn(vc: VersionContext): Boolean = + vc.activatedVersion >= sinceVersion && vc.ergoTreeVersion >= sinceVersion override def scalaFunc: A => B = { x => sys.error(s"Semantic Scala function is not defined for old implementation: $this") @@ -868,7 +875,7 @@ class SigmaDslTesting extends AnyPropSpec * This method also checks the old implementations fails on the new feature. */ override def checkEquality(input: A, logInputOutput: Boolean = false): Try[(B, CostDetails)] = { - if (this.isFeatureShouldWork) { + if (this.isSupportedIn(VersionContext.current)) { checkEq(scalaFuncNew)(newF)(input) } else { val oldRes = Try(oldF(input)) @@ -894,8 +901,8 @@ class SigmaDslTesting extends AnyPropSpec printTestCases: Boolean, failOnTestVectors: Boolean): Unit = { val res = checkEquality(input, printTestCases).map(_._1) - if (this.isFeatureShouldWork) { - res shouldBe expectedResult + if (this.isSupportedIn(VersionContext.current)) { + res shouldBe expectedResult } else res.isFailure shouldBe true Try(scalaFuncNew(input)) shouldBe expectedResult diff --git a/sc/shared/src/test/scala/sigmastate/CompilerCrossVersionProps.scala b/sc/shared/src/test/scala/sigmastate/CompilerCrossVersionProps.scala index 89d15dd4df..4062f13686 100644 --- a/sc/shared/src/test/scala/sigmastate/CompilerCrossVersionProps.scala +++ b/sc/shared/src/test/scala/sigmastate/CompilerCrossVersionProps.scala @@ -12,12 +12,11 @@ trait CompilerCrossVersionProps extends CrossVersionProps with CompilerTestsBase (implicit pos: Position): Unit = { super.property(testName, testTags:_*)(testFun) - val testName2 = s"${testName}_MCLowering" - super.property2(testName2, testTags:_*) { - if (okRunTestsWithoutMCLowering) { - _lowerMethodCalls.withValue(false) { - testFun_Run(testName2, testFun) - } + if (okRunTestsWithoutMCLowering) { + val testName2 = s"${testName}_MCLowering" + _lowerMethodCalls.withValue(false) { + // run testFun for all versions again, but now with this flag + super.property(testName2, testTags:_*)(testFun) } } }