Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[6.0] Revise liftToConstant method #1021

Open
wants to merge 12 commits into
base: v6.0.0
Choose a base branch
from
23 changes: 12 additions & 11 deletions data/js/src/main/scala/sigma/Platform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,31 @@ object Platform {
private[sigma] def liftToConstant(obj: Any, builder: SigmaBuilder): Nullable[Constant[SType]] = {
import builder._
obj match {
case arr: Array[Boolean] => Nullable(mkCollectionConstant[SBoolean.type](arr, SBoolean))
case arr: Array[Byte] => Nullable(mkCollectionConstant[SByte.type](arr, SByte))
case arr: Array[Short] => Nullable(mkCollectionConstant[SShort.type](arr, SShort))
case arr: Array[Int] => Nullable(mkCollectionConstant[SInt.type](arr, SInt))
case arr: Array[Long] => Nullable(mkCollectionConstant[SLong.type](arr, SLong))
case arr: Array[BigInteger] => Nullable(mkCollectionConstant[SBigInt.type](arr.map[BigInt](n => CBigInt(n)), SBigInt))
case arr: Array[String] => Nullable(mkCollectionConstant[SString.type](arr, SString))
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 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 => Nullable(mkConstant[SBigInt.type](CBigInt(v), SBigInt))
case v: BigInteger if !VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SBigInt.type](CBigInt(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 v: String => Nullable(mkConstant[SString.type](v, SString))
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))

// 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 =>
case b: ErgoBox if !VersionContext.current.isV6SoftForkActivated =>
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
Expand All @@ -47,7 +48,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 => Nullable(mkConstant[SAvlTree.type](CAvlTree(avl), SAvlTree))
case avl: AvlTreeData if !VersionContext.current.isV6SoftForkActivated => 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))
Expand Down
26 changes: 15 additions & 11 deletions data/jvm/src/main/scala/sigma/Platform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,33 @@ object Platform {
private[sigma] def liftToConstant(obj: Any, builder: SigmaBuilder): Nullable[Constant[SType]] = {
import builder._
obj match {
case arr: Array[Boolean] => Nullable(mkCollectionConstant[SBoolean.type](arr, SBoolean))
case arr: Array[Byte] => Nullable(mkCollectionConstant[SByte.type](arr, SByte))
case arr: Array[Short] => Nullable(mkCollectionConstant[SShort.type](arr, SShort))
case arr: Array[Int] => Nullable(mkCollectionConstant[SInt.type](arr, SInt))
case arr: Array[Long] => Nullable(mkCollectionConstant[SLong.type](arr, SLong))
case arr: Array[BigInteger] => Nullable(mkCollectionConstant[SBigInt.type](arr.map(SigmaDsl.BigInt(_)), SBigInt))
case arr: Array[String] => Nullable(mkCollectionConstant[SString.type](arr, SString))
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 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 => Nullable(mkConstant[SBigInt.type](SigmaDsl.BigInt(v), SBigInt))
case v: BigInteger if !VersionContext.current.isV6SoftForkActivated => 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 v: String => Nullable(mkConstant[SString.type](v, SString))
case h: Header if VersionContext.current.isV6SoftForkActivated => Nullable(mkConstant[SHeader.type](h, SHeader))

// todo: check UnsignedBigInt

case v: String if !VersionContext.current.isV6SoftForkActivated => 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 =>
case b: ErgoBox if !VersionContext.current.isV6SoftForkActivated =>
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
Expand All @@ -48,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 => Nullable(mkConstant[SAvlTree.type](SigmaDsl.avlTree(avl), SAvlTree))
case avl: AvlTreeData if !VersionContext.current.isV6SoftForkActivated => 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))
Expand Down
84 changes: 72 additions & 12 deletions interpreter/shared/src/test/scala/sigma/ast/SigmaBuilderTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma
testSuccess(arr, TransformingSigmaBuilder.mkCollectionConstant(arr, c.tpe))
}

def testArrayFailure[T <: SType]
(v: T#WrappedType, c: Constant[T])(implicit t: RType[T#WrappedType]) = {
// for any Byte and Short value `v`, lifting of array should succeed
val arr = Array.fill[T#WrappedType](10)(v)(t.classTag)
testFailure(arr)
}

def testColl[T <: SType]
(v: T#WrappedType, c: Constant[T])(implicit t: RType[T#WrappedType]) = {
// for any Byte and Short value `v`, lifting of Coll should succeed
Expand All @@ -134,7 +141,11 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma
val v = true
val c = BooleanConstant(v)
test[SBoolean.type](v, c)
testArray[SBoolean.type](v, c) // TODO v6.0: arrays should not be liftable directly (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905)
if (!VersionContext.current.isV6SoftForkActivated) {
testArray[SBoolean.type](v, c)
} else {
testArrayFailure[SBoolean.type](v, c)
}
testColl[SBoolean.type](v, c)
}

Expand All @@ -143,7 +154,11 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma
val c = ByteConstant(v)
testNumeric[SByte.type](v, c)
testLiftingOfCAnyValue[SByte.type](v, c)
testArray[SByte.type](v, c) // TODO v6.0: arrays should not be liftable directly (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905)
if (!VersionContext.current.isV6SoftForkActivated) {
testArray[SByte.type](v, c)
} else {
testArrayFailure[SByte.type](v, c)
}
testColl[SByte.type](v, c)
}

Expand All @@ -152,40 +167,65 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma
val c = ShortConstant(v)
testNumeric[SShort.type](v, c)
testLiftingOfCAnyValue[SShort.type](v, c)
testArray[SShort.type](v, c) // TODO v6.0: arrays should not be liftable directly (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905)
if (!VersionContext.current.isV6SoftForkActivated) {
testArray[SShort.type](v, c)
} else {
testArrayFailure[SShort.type](v, c)
}
testColl[SShort.type](v, c)
}

property("liftToConstant Int") {
val v = 1
val c = IntConstant(v)
test[SInt.type](v, c)
testArray[SInt.type](v, c) // TODO v6.0: arrays should not be liftable directly (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905)
if (!VersionContext.current.isV6SoftForkActivated) {
testArray[SInt.type](v, c)
} else {
testArrayFailure[SInt.type](v, c)
}
testColl[SInt.type](v, c)
}

property("liftToConstant Long") {
val v = 1L
val c = LongConstant(v)
test[SLong.type](v, c)
testArray[SLong.type](v, c) // TODO v6.0: arrays should not be liftable directly (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905)
if (!VersionContext.current.isV6SoftForkActivated) {
testArray[SLong.type](v, c)
} else {
testArrayFailure[SLong.type](v, c)
}
testColl[SLong.type](v, c)
}

property("liftToConstant String") {
val v = "abc"
val c = StringConstant(v)
test[SString.type](v, c)
testArray[SString.type](v, c) // TODO v6.0: String should be liftable at all (not supported in ErgoTree) (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905)
testColl[SString.type](v, c)
if (!VersionContext.current.isV6SoftForkActivated) {
// v6.0: String should 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)
testColl[SString.type](v, c)
} else {
testFailure(v)
}
}

property("liftToConstant BigInteger") {
val v = BigInteger.valueOf(1L)
val c = BigIntConstant(v)
testSuccess(v, c) // TODO v6.0: both BigInteger and arrays should not be liftable directly (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905)
if (!VersionContext.current.isV6SoftForkActivated) {
testSuccess(v, c)
} else {
testFailure(v)
}
val arr = Array.fill(10)(v)
testSuccess(arr, TransformingSigmaBuilder.mkCollectionConstant[SBigInt.type](arr.map(SigmaDsl.BigInt), c.tpe))
if (!VersionContext.current.isV6SoftForkActivated) {
testSuccess(arr, TransformingSigmaBuilder.mkCollectionConstant[SBigInt.type](arr.map(SigmaDsl.BigInt), c.tpe))
} else {
testFailure(arr)
}
}

property("liftToConstant BigInt") {
Expand All @@ -204,10 +244,26 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma
testColl[SGroupElement.type](v, c)
}

property("liftToConstant Header") {
val h = TestData.h1
val c = HeaderConstant(h)
if (VersionContext.current.isV6SoftForkActivated) {
testSuccess(h, c)
} else {
testFailure(h)
}
testFailure(Array.fill(10)(h))
testColl[SHeader.type](h, c)
}

property("liftToConstant ErgoBox") {
val v = TestData.b2.asInstanceOf[CBox].wrappedValue
val c = BoxConstant(TestData.b2)
testSuccess(v, c) // TODO v6.0: ErgoBox should not be liftable directly (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905)
if (!VersionContext.current.isV6SoftForkActivated) {
testSuccess(v, c)
} else {
testFailure(v)
}
testFailure(Array.fill(10)(v))
}

Expand All @@ -234,7 +290,11 @@ class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Ma
property("liftToConstant AvlTreeData") {
val v = TestData.t1.asInstanceOf[CAvlTree].wrappedValue
val c = AvlTreeConstant(SigmaDsl.avlTree(v))
testSuccess(v, c) // TODO v6.0: AvlTreeData should not be liftable directly (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905)
if (!VersionContext.current.isV6SoftForkActivated) {
testSuccess(v, c)
} else {
testFailure(v)
}
testFailure(Array.fill(10)(v))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.ergoplatform

import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
import sigma.Colls
import sigma.ast.SType
import sigma.ast.syntax.SigmaPropValue
import sigma.ast.Value
Expand Down Expand Up @@ -32,7 +33,7 @@ object ErgoScriptPredef {
networkPrefix: NetworkPrefix)
(implicit IR: IRContext): SigmaPropValue = {
val env = emptyEnv +
("tokenId" -> tokenId, "thresholdAmount" -> thresholdAmount)
("tokenId" -> Colls.fromArray(tokenId), "thresholdAmount" -> thresholdAmount)
val res = compileWithCosting(env,
"""{
| val sumValues = { (xs: Coll[Long]) => xs.fold(0L, { (acc: Long, amt: Long) => acc + amt }) }
Expand Down
24 changes: 12 additions & 12 deletions sc/shared/src/test/scala/org/ergoplatform/ErgoTreePredefSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ class ErgoTreePredefSpec extends CompilerTestingCommons with CompilerCrossVersio
boxesToSpend = inputBoxes,
spendingTransaction,
self = inputBox, activatedVersionInTests)
val pr = prover.prove(emptyEnv + (ScriptNameProp -> "boxCreationHeight_prove"), propTree, ctx, fakeMessage).get
verifier.verify(emptyEnv + (ScriptNameProp -> "boxCreationHeight_verify"), propTree, ctx, pr, fakeMessage).get._1 shouldBe true
val pr = prover.prove(emptyEnv, propTree, ctx, fakeMessage).get
verifier.verify(emptyEnv, propTree, ctx, pr, fakeMessage).get._1 shouldBe true
}

property("collect coins from the founders' box") {
Expand Down Expand Up @@ -118,8 +118,8 @@ class ErgoTreePredefSpec extends CompilerTestingCommons with CompilerCrossVersio
boxesToSpend = inputBoxes,
spendingTransaction,
self = inputBoxes.head, activatedVersionInTests)
val pr = prover.prove(emptyEnv + (ScriptNameProp -> "checkSpending_prove"), prop, ctx, fakeMessage).get
verifier.verify(emptyEnv + (ScriptNameProp -> "checkSpending_verify"), prop, ctx, pr, fakeMessage).get._1 shouldBe true
val pr = prover.prove(emptyEnv, prop, ctx, fakeMessage).get
verifier.verify(emptyEnv, prop, ctx, pr, fakeMessage).get._1 shouldBe true
}
}

Expand Down Expand Up @@ -148,13 +148,13 @@ class ErgoTreePredefSpec extends CompilerTestingCommons with CompilerCrossVersio
self = inputBoxes.head, activatedVersionInTests)

// should not be able to collect before minerRewardDelay
val prove = prover.prove(emptyEnv + (ScriptNameProp -> "rewardOutputScript_prove"), prop, ctx, fakeMessage).get
verifier.verify(emptyEnv + (ScriptNameProp -> "rewardOutputScript_verify"), prop, prevBlockCtx, prove, fakeMessage)
val prove = prover.prove(emptyEnv, prop, ctx, fakeMessage).get
verifier.verify(emptyEnv, prop, prevBlockCtx, prove, fakeMessage)
.getOrThrow should matchPattern { case (false,_) => }

// should be able to collect after minerRewardDelay
val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).getOrThrow
verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true
val pr = prover.prove(emptyEnv, prop, ctx, fakeMessage).getOrThrow
verifier.verify(emptyEnv, prop, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true
}

property("create transaction collecting the emission box") {
Expand Down Expand Up @@ -232,8 +232,8 @@ class ErgoTreePredefSpec extends CompilerTestingCommons with CompilerCrossVersio
self = inputBoxes.head,
activatedVersionInTests).withCostLimit(scriptCostLimitInTests * 10)

val pr = prover.prove(emptyEnv + (ScriptNameProp -> "tokenThresholdScript_prove"), prop, ctx, fakeMessage).getOrThrow
verifier.verify(emptyEnv + (ScriptNameProp -> "tokenThresholdScript_verify"), prop, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true
val pr = prover.prove(emptyEnv, prop, ctx, fakeMessage).getOrThrow
verifier.verify(emptyEnv, prop, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true
}


Expand Down Expand Up @@ -308,8 +308,8 @@ class ErgoTreePredefSpec extends CompilerTestingCommons with CompilerCrossVersio
boxesToSpend = inputBoxes,
spendingTransaction,
self = inputBoxes.head, activatedVersionInTests)
val pr = prover.prove(emptyEnv + (ScriptNameProp -> "checkRewardTx_prove"), prop, ctx, fakeMessage).getOrThrow
verifier.verify(emptyEnv + (ScriptNameProp -> "checkRewardTx_verify"), prop, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true
val pr = prover.prove(emptyEnv, prop, ctx, fakeMessage).getOrThrow
verifier.verify(emptyEnv, prop, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true
spendingTransaction
}

Expand Down
Loading
Loading