Skip to content

Commit

Permalink
versioned execution depending on tree version, newFeature test
Browse files Browse the repository at this point in the history
  • Loading branch information
kushti committed Aug 6, 2024
1 parent 2e3db09 commit e7fde10
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 53 deletions.
15 changes: 13 additions & 2 deletions data/shared/src/main/scala/sigma/ast/SMethod.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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)
}


Expand Down
8 changes: 2 additions & 6 deletions data/shared/src/main/scala/sigma/ast/methods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions data/shared/src/main/scala/sigma/ast/values.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 0 additions & 4 deletions data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
63 changes: 34 additions & 29 deletions sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
)
}

}
16 changes: 13 additions & 3 deletions sc/shared/src/test/scala/sigma/SigmaDslTesting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}

Expand Down

0 comments on commit e7fde10

Please sign in to comment.