Skip to content

Commit

Permalink
Merge pull request #829 from ScorexFoundation/v5.0-nested-booltosigma…
Browse files Browse the repository at this point in the history
…prop

Allow nested BoolToSigmaProp
  • Loading branch information
aslesarenko authored Dec 23, 2022
2 parents 1c415b0 + c71d165 commit 6a6a510
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 15 deletions.
7 changes: 7 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ lazy val commonSettings = Seq(
organization := "org.scorexfoundation",
crossScalaVersions := Seq(scala212, scala211),
scalaVersion := scala212,
scalacOptions ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 12)) => Seq("-Ywarn-unused:_,imports", "-Ywarn-unused:imports")
case Some((2, 11)) => Seq()
case _ => sys.error("Unsupported scala version")
}
},
resolvers += Resolver.sonatypeRepo("public"),
licenses := Seq("CC0" -> url("https://creativecommons.org/publicdomain/zero/1.0/legalcode")),
homepage := Some(url("https://github.com/ScorexFoundation/sigmastate-interpreter")),
Expand Down
16 changes: 10 additions & 6 deletions sigmastate/src/main/scala/org/ergoplatform/ErgoAddress.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.ergoplatform

import java.util

import com.google.common.primitives.Ints
import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
import scorex.crypto.hash.{Digest32, Blake2b256}
Expand Down Expand Up @@ -108,7 +106,7 @@ class P2PKAddress(val pubkey: ProveDlog,
override def networkPrefix: NetworkPrefix = encoder.networkPrefix

override def equals(obj: Any): Boolean = obj match {
case p2pk: P2PKAddress => util.Arrays.equals(pubkeyBytes, p2pk.pubkeyBytes)
case p2pk: P2PKAddress => java.util.Arrays.equals(pubkeyBytes, p2pk.pubkeyBytes)
case _ => false
}

Expand Down Expand Up @@ -167,7 +165,7 @@ class Pay2SHAddress(val scriptHash: Array[Byte])(implicit val encoder: ErgoAddre
}

override def equals(obj: Any): Boolean = obj match {
case p2sh: Pay2SHAddress => util.Arrays.equals(scriptHash, p2sh.scriptHash)
case p2sh: Pay2SHAddress => java.util.Arrays.equals(scriptHash, p2sh.scriptHash)
case _ => false
}

Expand Down Expand Up @@ -226,7 +224,7 @@ class Pay2SAddress(override val script: ErgoTree,
override def networkPrefix: NetworkPrefix = encoder.networkPrefix

override def equals(obj: Any): Boolean = obj match {
case p2s: Pay2SAddress => util.Arrays.equals(scriptBytes, p2s.scriptBytes)
case p2s: Pay2SAddress => java.util.Arrays.equals(scriptBytes, p2s.scriptBytes)
case _ => false
}

Expand Down Expand Up @@ -289,7 +287,7 @@ case class ErgoAddressEncoder(networkPrefix: NetworkPrefix) {
val addressType = (headByte - networkPrefix).toByte
val (withoutChecksum, checksum) = bytes.splitAt(bytes.length - ChecksumLength)

if (!util.Arrays.equals(hash256(withoutChecksum).take(ChecksumLength), checksum)) {
if (!java.util.Arrays.equals(hash256(withoutChecksum).take(ChecksumLength), checksum)) {
throw new Exception(s"Checksum check fails for $addrBase58Str")
}

Expand Down Expand Up @@ -357,6 +355,12 @@ object ErgoAddressEncoder {
/** Value of the prefix byte used to encode Testnet ErgoAddress. */
val TestnetNetworkPrefix: NetworkPrefix = 16.toByte

/** ErgoAddress encoder for Mainnet. */
val Mainnet: ErgoAddressEncoder = ErgoAddressEncoder(MainnetNetworkPrefix)

/** ErgoAddress encoder for Testnet. */
val Testnet: ErgoAddressEncoder = ErgoAddressEncoder(TestnetNetworkPrefix)

/** Length of the checksum section of encoded ergo address bytes. */
val ChecksumLength = 4

Expand Down
15 changes: 13 additions & 2 deletions sigmastate/src/main/scala/sigmastate/trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,20 @@ case class BoolToSigmaProp(value: BoolValue) extends SigmaPropValue {
override def tpe = SSigmaProp
override def opType = BoolToSigmaProp.OpType
protected final override def eval(env: DataEnv)(implicit E: ErgoTreeEvaluator): Any = {
val v = value.evalTo[Boolean](env)
val v = value.evalTo[Any](env)
addCost(BoolToSigmaProp.costKind)
SigmaDsl.sigmaProp(v)
if (VersionContext.current.isJitActivated) {
SigmaDsl.sigmaProp(v.asInstanceOf[Boolean])
} else {
// before v5.0 is activated we follow the old v4.x semantics to handle cases
// when the value is not a boolean. There are historical transactions with such
// erroneous scripts. See property("BoolToSigmaProp with SigmaProp argument should be deserializable")
v match {
case sp: SigmaProp => sp
case _ =>
SigmaDsl.sigmaProp(v.asInstanceOf[Boolean])
}
}
}
}
object BoolToSigmaProp extends FixedCostValueCompanion {
Expand Down
113 changes: 106 additions & 7 deletions sigmastate/src/test/scala/sigmastate/ErgoTreeSpecification.scala
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
package sigmastate

import org.ergoplatform.ErgoBox
import org.ergoplatform.settings.ErgoAlgos
import org.ergoplatform.validation.{ValidationException, ValidationRules}
import org.ergoplatform.validation.{ValidationRules, ValidationException}
import org.ergoplatform.{ErgoAddressEncoder, ErgoBox, Self, ErgoLikeContext}
import scalan.RType.asType
import scalan.{Nullable, RType}
import sigmastate.SCollection.{SByteArray, SByteArray2, checkValidFlatmap}
import sigmastate.SCollection.{SByteArray, checkValidFlatmap}
import sigmastate.Values._
import sigmastate.VersionContext._
import sigmastate.eval.{Evaluation, Profiler}
import sigmastate.eval.{CostingBox, Evaluation, Profiler}
import sigmastate.helpers.{ErgoLikeContextTesting, SigmaPPrint}
import sigmastate.interpreter.ErgoTreeEvaluator
import sigmastate.interpreter.Interpreter.JitReductionResult
import sigmastate.lang.SourceContext
import sigmastate.lang.Terms._
import sigmastate.lang.exceptions.{CostLimitException, CosterException, InterpreterException}
import sigmastate.lang.exceptions.{InterpreterException, CostLimitException}
import sigmastate.serialization.ErgoTreeSerializer.DefaultSerializer
import sigmastate.utils.Helpers.TryOps
import sigmastate.utxo._
import special.collection._
import special.sigma.SigmaDslTesting
import special.sigma.{ContractsTestkit, SigmaDslTesting}


/** Regression tests with ErgoTree related test vectors.
* This test vectors verify various constants which are consensus critical and should not change.
*/
class ErgoTreeSpecification extends SigmaDslTesting {
class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit {

property("Value.sourceContext") {
val srcCtx = SourceContext.fromParserIndex(0, "")
Expand Down Expand Up @@ -664,4 +667,100 @@ class ErgoTreeSpecification extends SigmaDslTesting {
}

}

// Test vectors for https://github.com/ScorexFoundation/sigmastate-interpreter/issues/828
property("nested BoolToSigmaProp") {
val addr = ErgoAddressEncoder.Mainnet.fromString("Fo6oijFP2JM87ac7w").getOrThrow
val tree = addr.script
tree shouldBe new ErgoTree(
16.toByte,
Vector(TrueLeaf),
Right(BoolToSigmaProp(BoolToSigmaProp(ConstantPlaceholder(0, SBoolean)).asBoolValue))
)

def createCtx: ErgoLikeContext = ErgoLikeContextTesting
.dummy(CostingBox(fakeSelf), VersionContext.current.activatedVersion)
.withErgoTreeVersion(tree.version)

VersionContext.withVersions(activatedVersion = 1, tree.version) {
// v4.x behavior
val res = ErgoTreeEvaluator.evalToCrypto(createCtx, tree, evalSettings)
res shouldBe JitReductionResult(TrivialProp(true), 3)
}

VersionContext.withVersions(activatedVersion = 2, tree.version) {
// v5.0 behavior
assertExceptionThrown(
ErgoTreeEvaluator.evalToCrypto(createCtx, tree, evalSettings),
exceptionLike[ClassCastException]()
)
}
}

object BlockValueWithInvalidBoolToSigmaProp {
def unapply(prop: SigmaPropValue): Option[BoolToSigmaProp] = prop.asValue[SType] match {
case BlockValue(_, b @ BoolToSigmaProp(x)) if x.tpe == SSigmaProp => Some(b)
case _ => None
}
}

property("BoolToSigmaProp with SigmaProp argument should be deserializable") {
{ // Transaction: 5fe235558bd37328c5cc65711e5aff12b6f96d6f5abf062b7e7b994f7981f2ec
val addr = ErgoAddressEncoder.Mainnet.fromString("Fo6oijFP2JM87ac7w").getOrThrow
val tree = addr.script
tree shouldBe new ErgoTree(
16.toByte,
Vector(TrueLeaf),
Right(BoolToSigmaProp(BoolToSigmaProp(ConstantPlaceholder(0, SBoolean)).asBoolValue))
)
}

{ // Transaction: 1b878563f198f622360d88f61a6258aa67dd40875e1b18d1e6ea013cd32afb40
val addr = ErgoAddressEncoder.Mainnet.fromString("3ehvg9kjzVt2ep6VkYbsNZBXVoFjQA3b26LTmCwvE9vTUEU2TG1uKdqh7sb1a23G1HLkXa6rv4NUcR5Ucghp8CTuBnUxJB4qYq61GYNDFmCHdoZJq32vUVJ7Jsq4cFE7zp9ddFnchb8EN2Qkaa9rqzmruj4iKjLu8MMJ3V8ns1tpRF8eSp2KSjPuMYt6ZHysFNGoMt4dQ2P45YoCXbgiJtzcADgjMnr5bkpqKMx2ZEaAUWoZfHN8DUwvNawSCr2yHieHKbWujxeGuPUuGPAdJHQRcC47xpBj7rKExxGE6T117vAAzSwc98UG3CC8Lb8UeoE7WWi9LCTdXqJpJFrwb8Zqc9HnqSVRvAxeaKgcueX36absXAxpqpAGUcH8YwYoeVmSYLsQKQbUAVrFe73eJyRtgxpcVEqrs4rBZ3KeDJUe5J2NJTNYKoUFcruqqu4N1XUFCECWXANsE9TLoQNyqDgNRcnHE4t8nw6THPJXQWCTBHK6mHvkVcj6SvGinvVGfMpeuA8MF1FFtZJTMnM31cuMBexK3m5mDxsbamJngQiPrcyVqK4smDpdiqhds7APGJbwKTHgst2u1P6").getOrThrow
val tree = addr.script
tree match {
case ErgoTree(_, _, Right(BlockValueWithInvalidBoolToSigmaProp(_)), _, _, _) =>
}
}

{ // Transactions:
// 49ede8ab7b5a8ed00ba045f1ec9315de60566e149de5f35987a63c9fe481a13c
// d3f35272c9e32f49b1723450fa6106032bcd1ad2b69dd199a68dbcd069be4baf
// 1040deda322b4187e987b580b9df24c04804ad095dfc6a7e0e08db8e7b51dbfb
// d6ca9f6760ff8d67ed0618c1f293574764813ceda31c51ce17ee10dc9743649b
// 186afd8e39228c5b6e55a6b0d17eb08c62e03b0e82c7d3cc3a11bd51a96d2b92
val addr = ErgoAddressEncoder.Mainnet.fromString("bpn7HXccD8wzY3x8XbymfBCh71aeci1FyM7JJgVx6mVY3vxznf2Pom7gtEgQBxr9UZb8cn9Z6GiXEjV7mB7ypRfH9Qpf3eCsd8qoEGmvsFqW2GyEvxgYWnJGd8QYTYZLBgGkSFcAeerLLDZwS1bos5oV4atMLnPDUJ6bH2EFFwVRdTAQKxaVMAhNtNYZxAcYtWhaYBJqYZM8ne3hGFrkWNTgNy7NxEDQ5LpBEM3rq6EqUENAGhH6THDL7RyU8AMkpr2vhosqEeqp4yXJmK887vU4qbnGGrMLX4w5GrgL9zLk41Vm6vzEUVLvp8XQJ8CULwkHNiKkNHRLeTk6BG4hwJsFoUSJJNWgsfputm8pEbaTuKfNG5u4NFmZ3YLfGsrqpr62c95QuNuD3g3FaoBUhxigkfNhKwFFtpKKsYerJvvp2Suh2eVRptFsCN15pjdkveUakhFsAo9j9YwhYVjjPpCWZgB8Wme8iZLRVfopSuDVdiqGsnmpJcuccmPsebgXPz3XvyjQazYE7WnR3Jrr1mRWHVEnJb3UU89JVPDpJPP1jUaSqmkKCkrPj3WMMQTDg17WW2DkhGKsb").getOrThrow
val tree = addr.script
tree match {
case ErgoTree(_, _, Right(BlockValueWithInvalidBoolToSigmaProp(_)), _, _, _) =>
}
}

{ // Transactions:
// d41cbc4ad342067e2f8945bfde4e04b15eafa200f868a223d131047bc46c52b3
// 4503b5d77cb74b4354771b835cd61e9d5257022a8efff0fddfac249e0c25b492
val addr = ErgoAddressEncoder.Mainnet.fromString("28JURWHTHwTnXJt5F38").getOrThrow
val tree = addr.script
tree shouldBe new ErgoTree(16.toByte, Vector(),
Right(BoolToSigmaProp(
CreateProveDlog(OptionGet(ExtractRegisterAs(Self, ErgoBox.R4, SOption(SGroupElement)))).asBoolValue)
))
}

{ // Transactions:
// 263a441ecb4c2794711d7add8de59a0b0dc9b99e7a2dd3ff949cbafc958157f7
// 5fd5027a70c2d45a853e16eb7a4909cced5d127ba3f87d0fe908f950c2084ec1
// 4503b5d77cb74b4354771b835cd61e9d5257022a8efff0fddfac249e0c25b492
// d4b522f88ff28d9bb686b3e2b346b91f78830279963432fbfbdebfb9e0d43fc6
// d41cbc4ad342067e2f8945bfde4e04b15eafa200f868a223d131047bc46c52b3
val addr = ErgoAddressEncoder.Mainnet.fromString("9drgw9DeDxHwdwYWT11yrYD3qCN3fzgnjA3eS5ZXEkR2Rrpd2x58R3HFViGAs93hYFqroBGShW5DG6h2tU7PqDURegny88hEhNKfLpWKBHpLMmfDwZwTM75MuYKXkmtyUmiMRAfGAVVjaSqThddra5ykZ4UrG8kgqkHSBTxtibVPmNff8Fx7Fy5q82xsZ95RFpjGkAX1QgtirHc3JP6QDZfHUFPx2gnyT9pDpYrKWEhjK8Ake779PoYqGzrL5gtuHyLqsC3WtLFMvP3QNfVtwPaqeCLEmjFmWYU6MV1A8fTJxGWDByiCMnva9wDgZgLh8wrSwttEGE9XHiZaWxWNWqVM8Ypn8aW8x8mKSjxQjF1BNxV41JTeGEMFDvY2HaNYgGbQhBbrTXFq9cvxuzPgXHtfwcbb2kiytr3YBCz8eNmbzp73LSKzRk4AFaTiTdFSSWJe72uLAurQTQBTzAzVgPptGWfrhMWmHCkN5qXQMpUQWNsCzwqRHeZzpSMVtWTyrBCGsbyuPitbukdLHZ8Wee7DtCy8j4Gkhewrwn23jVQu1ApN4uGAFEa29AL26bsMGD7tdu1StE9CKRVzbfEknaReqv6").getOrThrow
val tree = addr.script
tree match {
case ErgoTree(_, _, Right(BlockValueWithInvalidBoolToSigmaProp(_)), _, _, _) =>
}
SigmaPPrint.pprintln(tree, 150, 300)
}

}

}

0 comments on commit 6a6a510

Please sign in to comment.