From e7fde10e26f8af36bf3de134b00aa2f5d0dce029 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 6 Aug 2024 23:49:32 +0300 Subject: [PATCH] versioned execution depending on tree version, newFeature test --- .../src/main/scala/sigma/ast/SMethod.scala | 15 ++++- .../src/main/scala/sigma/ast/methods.scala | 8 +-- .../src/main/scala/sigma/ast/values.scala | 3 + .../scala/sigma/eval/ErgoTreeEvaluator.scala | 4 -- .../interpreter/CErgoTreeEvaluator.scala | 8 --- .../scala/sigma/LanguageSpecificationV6.scala | 63 ++++++++++--------- .../test/scala/sigma/SigmaDslTesting.scala | 16 ++++- .../TestingInterpreterSpecification.scala | 6 +- 8 files changed, 70 insertions(+), 53 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/SMethod.scala b/data/shared/src/main/scala/sigma/ast/SMethod.scala index 5a17038c54..600701506e 100644 --- a/data/shared/src/main/scala/sigma/ast/SMethod.scala +++ b/data/shared/src/main/scala/sigma/ast/SMethod.scala @@ -75,7 +75,8 @@ case class SMethod( irInfo: MethodIRInfo, docInfo: Option[OperationInfo], costFunc: Option[MethodCostFunc], - userDefinedInvoke: Option[SMethod.InvokeHandler] + userDefinedInvoke: Option[SMethod.InvokeHandler], + sinceVersion: Byte ) { /** Operation descriptor of this method. */ @@ -314,7 +315,17 @@ object SMethod { ): SMethod = { SMethod( objType, name, stype, methodId, costKind, explicitTypeArgs, - MethodIRInfo(None, None, None), None, None, None) + MethodIRInfo(None, None, None), None, None, None, 0) + } + + /** Convenience factory method. */ + def apply(objType: MethodsContainer, name: String, stype: SFunc, + methodId: Byte, + costKind: CostKind, + sinceVersion: Byte): SMethod = { + SMethod( + objType, name, stype, methodId, costKind, Nil, + MethodIRInfo(None, None, None), None, None, None, sinceVersion) } diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index c299d9f53a..62164f0f24 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -1458,15 +1458,11 @@ case object SHeaderMethods extends MonoTypeMethods { // cost of checkPoW is 700 as about 2*32 hashes required, and 1 hash (id) over short data costs 10 lazy val checkPowMethod = SMethod( - this, "checkPow", SFunc(Array(SHeader), SBoolean), 16, FixedCost(JitCost(700))) + this, "checkPow", SFunc(Array(SHeader), SBoolean), 16, FixedCost(JitCost(700)), + sinceVersion = VersionContext.V6SoftForkVersion) .withIRInfo(MethodCallIrBuilder) .withInfo(MethodCall, "Validate header's proof-of-work") - def checkPow_eval(mc: MethodCall, G: SigmaDslBuilder, header: Header) - (implicit E: ErgoTreeEvaluator): Boolean = { - E.checkPow_eval(mc, header) - } - private lazy val v5Methods = super.getMethods() ++ Seq( idMethod, versionMethod, parentIdMethod, ADProofsRootMethod, stateRootMethod, transactionsRootMethod, timestampMethod, nBitsMethod, heightMethod, extensionRootMethod, minerPkMethod, powOnetimePkMethod, diff --git a/data/shared/src/main/scala/sigma/ast/values.scala b/data/shared/src/main/scala/sigma/ast/values.scala index 87c661a00a..5a372e6c3c 100644 --- a/data/shared/src/main/scala/sigma/ast/values.scala +++ b/data/shared/src/main/scala/sigma/ast/values.scala @@ -1313,6 +1313,9 @@ case class MethodCall( addCost(MethodCall.costKind) // MethodCall overhead method.costKind match { case fixed: FixedCost => + if (method.sinceVersion > 0 && E.context.currentErgoTreeVersion < method.sinceVersion) { + syntax.error(s"Method ${method.name} is not supported in tree version ${E.context.currentErgoTreeVersion}") + } val extra = method.extraDescriptors val extraLen = extra.length val len = args.length diff --git a/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala b/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala index b95c034bd2..6df82125df 100644 --- a/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala +++ b/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala @@ -138,10 +138,6 @@ abstract class ErgoTreeEvaluator { def remove_eval( mc: MethodCall, tree: AvlTree, operations: Coll[Coll[Byte]], proof: Coll[Byte]): Option[AvlTree] - - /** Implements evaluation of Header.checkPow method call ErgoTree node. */ - def checkPow_eval(mc: MethodCall, header: Header): Boolean - } object ErgoTreeEvaluator { diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala index c0759f4a5c..a72510f641 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala @@ -218,14 +218,6 @@ class CErgoTreeEvaluator( } } - /** Implements evaluation of Header.checkPow method call ErgoTree node. */ - override def checkPow_eval(mc: MethodCall, header: Header): Boolean = { - val checkPowCostInfo = OperationCostInfo(checkPowMethod.costKind.asInstanceOf[FixedCost], NamedDesc("Header.checkPow")) - fixedCostOp(checkPowCostInfo){ - header.checkPow - }(this) - } - /** Evaluates the given expression in the given data environment. */ def eval(env: DataEnv, exp: SValue): Any = { VersionContext.checkVersions(context.activatedScriptVersion, context.currentErgoTreeVersion) diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 97ebc575c7..61859a81cc 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -1,10 +1,12 @@ package sigma +import org.ergoplatform.ErgoHeader +import scorex.util.encode.Base16 import sigma.ast.ErgoTree.ZeroHeader import sigma.ast.SCollection.SByteArray import sigma.ast.syntax.TrueSigmaProp import sigma.ast._ -import sigma.data.{CBigInt, ExactNumeric} +import sigma.data.{CBigInt, CHeader, ExactNumeric} import sigma.eval.{CostDetails, SigmaDsl, TracedCost} import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} import sigmastate.exceptions.MethodNotFound @@ -331,34 +333,6 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => } } - property("Header new methods") { - def checkPoW = newFeature({ (x: Header) => x.checkPow}, - "{ (x: Header) => x.checkPow }", - FuncValue( - Array((1, SHeader)), - MethodCall.typed[Value[SBoolean.type]]( - ValUse(1, SHeader), - SHeaderMethods.getMethodByName("checkPow"), - IndexedSeq(), - Map() - ) - ), - sinceVersion = VersionContext.V6SoftForkVersion) - - if (VersionContext.current.isV6SoftForkActivated) { - forAll { x: Header => - Seq(checkPoW).map(_.checkEquality(x)) - } - } else { - an[Exception] shouldBe thrownBy { - forAll { x: Header => - Seq(checkPoW).map(_.checkEquality(x)) - } - } - } - - } - // TODO v6.0: implement Option.fold (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479) property("Option new methods") { val n = ExactNumeric.LongIsExactNumeric @@ -491,4 +465,35 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => tree.root shouldBe t2.root } + property("Header new methods") { + + def checkPoW = { + newFeature( + { (x: Header) => x.checkPow}, + "{ (x: Header) => x.checkPow }", + FuncValue( + Array((1, SHeader)), + MethodCall.typed[Value[SBoolean.type]]( + ValUse(1, SHeader), + SHeaderMethods.checkPowMethod, + IndexedSeq(), + Map() + ) + ), + sinceVersion = VersionContext.V6SoftForkVersion + ) + } + + // bytes of real mainnet block header at height 614,440 + val headerBytes = "02ac2101807f0000ca01ff0119db227f202201007f62000177a080005d440896d05d3f80dcff7f5e7f59007294c180808d0158d1ff6ba10000f901c7f0ef87dcfff17fffacb6ff7f7f1180d2ff7f1e24ffffe1ff937f807f0797b9ff6ebdae007e5c8c00b8403d3701557181c8df800001b6d5009e2201c6ff807d71808c00019780f087adb3fcdbc0b3441480887f80007f4b01cf7f013ff1ffff564a0000b9a54f00770e807f41ff88c00240000080c0250000000003bedaee069ff4829500b3c07c4d5fe6b3ea3d3bf76c5c28c1d4dcdb1bed0ade0c0000000000003105" + val header1 = new CHeader(ErgoHeader.sigmaSerializer.fromBytes(Base16.decode(headerBytes).get)) + + verifyCases( + Seq( + header1 -> new Expected(ExpectedResult(Success(true), None)) + ), + checkPoW + ) + } + } diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index 58873449b4..fa1402030b 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -875,7 +875,11 @@ class SigmaDslTesting extends AnyPropSpec 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") + if (isSupportedIn(VersionContext.current)) { + scalaFuncNew(x) + } else { + sys.error(s"Semantic Scala function is not defined for old implementation: $this") + } } implicit val cs = compilerSettingsInTests @@ -925,8 +929,14 @@ class SigmaDslTesting extends AnyPropSpec printTestCases: Boolean, failOnTestVectors: Boolean): Unit = { val funcRes = checkEquality(input, printTestCases) - funcRes.isFailure shouldBe true - Try(scalaFunc(input)) shouldBe expected.value + if(!isSupportedIn(VersionContext.current)) { + funcRes.isFailure shouldBe true + } + if(isSupportedIn(VersionContext.current)) { + Try(scalaFunc(input)) shouldBe expected.value + } else { + Try(scalaFunc(input)).isFailure shouldBe true + } } } diff --git a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala index 4ba6b1a9f7..1ab6031109 100644 --- a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala @@ -473,7 +473,11 @@ class TestingInterpreterSpecification extends CompilerTestingCommons if (activatedVersionInTests < V6SoftForkVersion) { an [Exception] should be thrownBy testEval(source) } else { - testEval(source) + if(ergoTreeVersionInTests >= V6SoftForkVersion) { + testEval(source) + } else { + an [Exception] should be thrownBy testEval(source) + } } }