diff --git a/.gitignore b/.gitignore
index df18ce8ab1..b67ecf6995 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,7 +8,9 @@
*.fdb_latexmk
*.gz
+yarn.lock
*.log
+yarn.lock
docs/spec/out/
test-out/
flamegraphs/
diff --git a/README.md b/README.md
index 6003daf55a..411c502dd2 100644
--- a/README.md
+++ b/README.md
@@ -97,7 +97,7 @@ This library is
on Maven repository and can be added to the SBT configuration of Scala project.
```scala
-libraryDependencies += "org.scorexfoundation" %% "sigma-state" % "5.0.14"
+libraryDependencies += "org.scorexfoundation" %% "sigma-state" % "6.0.0"
```
## Repository Organization
diff --git a/build.sbt b/build.sbt
index 85c59512d6..ab9d931172 100644
--- a/build.sbt
+++ b/build.sbt
@@ -82,9 +82,9 @@ ThisBuild / dynverSeparator := "-"
val bouncycastleBcprov = "org.bouncycastle" % "bcprov-jdk15on" % "1.66"
-val scrypto = "org.scorexfoundation" %% "scrypto" % "2.3.0-4-a0bc6176-SNAPSHOT"
+val scrypto = "org.scorexfoundation" %% "scrypto" % "3.0.0"
val scryptoDependency =
- libraryDependencies += "org.scorexfoundation" %%% "scrypto" % "2.3.0-4-a0bc6176-SNAPSHOT"
+ libraryDependencies += "org.scorexfoundation" %%% "scrypto" % "3.0.0"
val scorexUtil = "org.scorexfoundation" %% "scorex-util" % "0.2.1"
val scorexUtilDependency =
diff --git a/core/js/src/main/scala/sigma/js/GroupElement.scala b/core/js/src/main/scala/sigma/js/GroupElement.scala
index 21b53b265d..82d8d462d6 100644
--- a/core/js/src/main/scala/sigma/js/GroupElement.scala
+++ b/core/js/src/main/scala/sigma/js/GroupElement.scala
@@ -1,6 +1,6 @@
package sigma.js
-import sigma.Extensions.CoreArrayByteOps
+import scorex.util.encode.Base16
import sigma.crypto.{CryptoFacade, CryptoFacadeJs, Ecp, Platform}
import scala.scalajs.js
@@ -13,7 +13,7 @@ class GroupElement(val point: Ecp) extends js.Object {
* @see CryptoFacade.getASN1Encoding
*/
def toPointHex(): String = {
- CryptoFacade.getASN1Encoding(point, true).toHex
+ Base16.encode(CryptoFacade.getASN1Encoding(point, true))
}
}
diff --git a/core/js/src/main/scala/sigma/js/Isos.scala b/core/js/src/main/scala/sigma/js/Isos.scala
index b28a3337b8..767a358d62 100644
--- a/core/js/src/main/scala/sigma/js/Isos.scala
+++ b/core/js/src/main/scala/sigma/js/Isos.scala
@@ -8,6 +8,9 @@ import scala.reflect.ClassTag
import scala.scalajs.js
import scala.scalajs.js.JSConverters.JSRichOption
+/** Definitions of isomorphisms for sigma-core module.
+ * @see sigma.data.Iso
+ */
object Isos {
implicit def isoUndefOr[A, B](implicit iso: Iso[A, B]): Iso[js.UndefOr[A], Option[B]] = new Iso[js.UndefOr[A], Option[B]] {
diff --git a/core/shared/src/main/scala/sigma/Colls.scala b/core/shared/src/main/scala/sigma/Colls.scala
index 625120deac..d10026066b 100644
--- a/core/shared/src/main/scala/sigma/Colls.scala
+++ b/core/shared/src/main/scala/sigma/Colls.scala
@@ -45,6 +45,19 @@ trait Coll[@specialized A] {
*/
def apply(i: Int): A
+ /** The element at given index or None if there is no such element. Indices start at `0`.
+ *
+ * @param i the index
+ * @return the element at the given index, or None if there is no such element
+ */
+ def get(i: Int): Option[A] = {
+ if (isDefinedAt(i)) {
+ Some(apply(i))
+ } else {
+ None
+ }
+ }
+
/** Tests whether this $coll contains given index.
*
* The implementations of methods `apply` and `isDefinedAt` turn a `Coll[A]` into
@@ -76,6 +89,18 @@ trait Coll[@specialized A] {
* produces a collection ((x0, y0), ..., (xK, yK)) where K = min(N, M) */
def zip[@specialized B](ys: Coll[B]): Coll[(A, B)]
+ /**
+ * @return true if first elements of this collection form given `ys` collection, false otherwise.
+ * E.g. [1,2,3] starts with [1,2]
+ */
+ def startsWith(ys: Coll[A]): Boolean
+
+ /**
+ * @return true if last elements of this collection form given `ys` collection, false otherwise.
+ * E.g. [1,2,3] ends with [2,3]
+ */
+ def endsWith(ys: Coll[A]): Boolean
+
/** Tests whether a predicate holds for at least one element of this collection.
* @param p the predicate used to test elements.
* @return `true` if the given predicate `p` is satisfied by at least one element of this collection, otherwise `false`
diff --git a/core/shared/src/main/scala/sigma/Environment.scala b/core/shared/src/main/scala/sigma/Environment.scala
index 959e02c1fb..432c40110c 100644
--- a/core/shared/src/main/scala/sigma/Environment.scala
+++ b/core/shared/src/main/scala/sigma/Environment.scala
@@ -14,7 +14,7 @@ sealed abstract class Environment {
object Environment {
/** Current runtime environment. */
- implicit val current: Environment = new Environment {
+ val current: Environment = new Environment {
override def isJVM: Boolean = runtimePlatform == RuntimePlatform.JVM
override def isJS: Boolean = runtimePlatform == RuntimePlatform.JS
override def runtimePlatform: RuntimePlatform = sigma.reflection.Platform.runtimePlatform
diff --git a/core/shared/src/main/scala/sigma/Extensions.scala b/core/shared/src/main/scala/sigma/Extensions.scala
index 81976a3c12..0c79df94ea 100644
--- a/core/shared/src/main/scala/sigma/Extensions.scala
+++ b/core/shared/src/main/scala/sigma/Extensions.scala
@@ -9,11 +9,6 @@ import sigma.data.RType
* See `implicit class ...` wrappers below.
*/
object Extensions {
- /** Extension methods for `Array[Byte]` not available for generic `Array[T]`. */
- implicit class CoreArrayByteOps(val arr: Array[Byte]) extends AnyVal {
- /** Encodes array into hex string */
- @inline def toHex: String = Base16.encode(arr)
- }
/** Extension methods for `Array[T]` where implicit descriptor `RType[T]` is also
* required.
diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala
index df2b419273..16331febfd 100644
--- a/core/shared/src/main/scala/sigma/SigmaDsl.scala
+++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala
@@ -1,13 +1,12 @@
package sigma
-import java.math.BigInteger
+import sigma.ast.SType
+import java.math.BigInteger
import sigma.data._
/**
- * All `modQ` operations assume that Q is a global constant (an order of the only one cryptographically strong group
- * which is used for all cryptographic operations).
- * So it is globally and implicitly used in all methods.
+ * Functions defined for 256-bit signed integers
* */
trait BigInt {
/** Convert this BigInt value to Byte.
@@ -154,6 +153,22 @@ trait BigInt {
*/
def or(that: BigInt): BigInt
def |(that: BigInt): BigInt = or(that)
+
+ /**
+ * @return a big integer whose value is `this xor that`.
+ * This method returns a negative BigInteger if and only if exactly one of this and val are negative.
+ */
+ def xor(that: BigInt): BigInt
+
+ /**
+ * @return a 256-bit signed integer whose value is (this << n). `n` should be in 0..255 range (inclusive).
+ */
+ def shiftLeft(n: Int): BigInt
+
+ /**
+ * @return a 256-bit signed integer whose value is (this >> n). `n` should be in 0..255 range (inclusive).
+ */
+ def shiftRight(n: Int): BigInt
}
/** Base class for points on elliptic curves. */
@@ -459,6 +474,23 @@ trait Header {
/** Miner votes for changing system parameters. */
def votes: Coll[Byte] //3 bytes
+
+ /** Bytes which are coming from future versions of the protocol, so
+ * their meaning is not known to current version of Sigma, but they
+ * are stored to get the same id as future version users.
+ */
+ def unparsedBytes: Coll[Byte]
+
+ /**
+ * @return header bytes without proof of work, a PoW is generated over them
+ */
+ def serializeWithoutPoW: Coll[Byte]
+
+ /**
+ * @return result of header's proof-of-work validation
+ */
+ def checkPow: Boolean
+
}
/** Runtime representation of Context ErgoTree type.
@@ -557,6 +589,17 @@ trait Context {
*/
def getVar[T](id: Byte)(implicit cT: RType[T]): Option[T]
+ /**
+ * A variant of `getVar` to extract a context variable by id and type from any input
+ *
+ * @param inputIndex - input index
+ * @param id - context variable id
+ * @tparam T - expected type of the variable
+ * @return Some(value) if the variable is defined in the context AND has the given type.
+ * None otherwise
+ */
+ def getVarFromInput[T](inputIndex: Short, id: Byte)(implicit cT: RType[T]): Option[T]
+
def vars: Coll[AnyValue]
/** Maximum version of ErgoTree currently activated on the network.
@@ -727,7 +770,13 @@ trait SigmaDslBuilder {
/** Construct a new authenticated dictionary with given parameters and tree root digest. */
def avlTree(operationFlags: Byte, digest: Coll[Byte], keyLength: Int, valueLengthOpt: Option[Int]): AvlTree
+ /** Serializes the given `value` into bytes using the default serialization format. */
+ def serialize[T](value: T)(implicit cT: RType[T]): Coll[Byte]
+
/** Returns a byte-wise XOR of the two collections of bytes. */
def xor(l: Coll[Byte], r: Coll[Byte]): Coll[Byte]
+
+ /** Returns a number decoded from provided big-endian bytes array. */
+ def fromBigEndianBytes[T](bytes: Coll[Byte])(implicit cT: RType[T]): T
}
diff --git a/core/shared/src/main/scala/sigma/VersionContext.scala b/core/shared/src/main/scala/sigma/VersionContext.scala
index 67b7079fea..6ede0a1556 100644
--- a/core/shared/src/main/scala/sigma/VersionContext.scala
+++ b/core/shared/src/main/scala/sigma/VersionContext.scala
@@ -1,6 +1,6 @@
package sigma
-import VersionContext.JitActivationVersion
+import VersionContext.{JitActivationVersion, V6SoftForkVersion}
import scala.util.DynamicVariable
@@ -21,6 +21,10 @@ case class VersionContext(activatedVersion: Byte, ergoTreeVersion: Byte) {
/** @return true, if the activated script version of Ergo protocol on the network is
* greater than v1. */
def isJitActivated: Boolean = activatedVersion >= JitActivationVersion
+
+ /** @return true, if the activated script version of Ergo protocol on the network is
+ * including v6.0 update. */
+ def isV6SoftForkActivated: Boolean = activatedVersion >= V6SoftForkVersion
}
object VersionContext {
@@ -31,13 +35,21 @@ object VersionContext {
* - version 3.x this value must be 0
* - in v4.0 must be 1
* - in v5.x must be 2
+ * - in 6.x must be 3
* etc.
*/
- val MaxSupportedScriptVersion: Byte = 2 // supported versions 0, 1, 2
+ val MaxSupportedScriptVersion: Byte = 3 // supported versions 0, 1, 2, 3
- /** The first version of ErgoTree starting from which the JIT costing interpreter is used. */
+ /** The first version of ErgoTree starting from which the JIT costing interpreter must be used.
+ * It must also be used for all subsequent versions (3, 4, etc).
+ */
val JitActivationVersion: Byte = 2
+ /**
+ * The version of ErgoTree corresponding to "evolution" (6.0) soft-fork
+ */
+ val V6SoftForkVersion: Byte = 3
+
private val _defaultContext = VersionContext(
activatedVersion = 1 /* v4.x */,
ergoTreeVersion = 1
diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala
index e9ea0d43f0..d289f4067a 100644
--- a/core/shared/src/main/scala/sigma/ast/SType.scala
+++ b/core/shared/src/main/scala/sigma/ast/SType.scala
@@ -7,7 +7,7 @@ import sigma.data.OverloadHack.Overloaded1
import sigma.data.{CBigInt, Nullable, SigmaConstants}
import sigma.reflection.{RClass, RMethod, ReflectionData}
import sigma.util.Extensions.{IntOps, LongOps, ShortOps}
-import sigma.{AvlTree, BigInt, Box, Coll, Context, Evaluation, GroupElement, Header, PreHeader, SigmaDslBuilder, SigmaProp}
+import sigma.{AvlTree, BigInt, Box, Coll, Context, Evaluation, GroupElement, Header, PreHeader, SigmaDslBuilder, SigmaProp, VersionContext}
import java.math.BigInteger
@@ -94,7 +94,6 @@ object SType {
val paramOV = STypeParam(tOV)
val paramIVSeq: Seq[STypeParam] = Array(paramIV)
- val IndexedSeqOfT1: IndexedSeq[SType] = Array(SType.tT)
val IndexedSeqOfT2: IndexedSeq[SType] = Array(SType.tT, SType.tT)
/** Immutable empty array, can be used to avoid repeated allocations. */
@@ -114,27 +113,48 @@ object SType {
* typeId this map contains a companion object which can be used to access the list of
* corresponding methods.
*
- * NOTE: in the current implementation only monomorphic methods are supported (without
- * type parameters)
+ * @note starting from v6.0 methods with type parameters are also supported.
*
- * NOTE2: in v3.x SNumericType.typeId is silently shadowed by SGlobal.typeId as part of
- * `toMap` operation. As a result, the methods collected into SByte.methods cannot be
+ * @note on versioning:
+ * In v3.x-5.x SNumericType.typeId is silently shadowed by SGlobal.typeId as part of
+ * `toMap` operation. As a result, SNumericTypeMethods container cannot be resolved by
+ * typeId = 106, because SNumericType was being silently removed when `_types` map is
+ * constructed. See `property("SNumericType.typeId resolves to SGlobal")`.
+ * In addition, the methods associated with the concrete numeric types cannot be
* resolved (using SMethod.fromIds()) for all numeric types (SByte, SShort, SInt,
- * SLong, SBigInt). See the corresponding regression `property("MethodCall on numerics")`.
+ * SLong) because these types are not registered in the `_types` map.
+ * See the corresponding property("MethodCall on numerics")`.
* However, this "shadowing" is not a problem since all casting methods are implemented
- * via Downcast, Upcast opcodes and the remaining `toBytes`, `toBits` methods are not
- * implemented at all.
- * In order to allow MethodCalls on numeric types in future versions the SNumericType.typeId
- * should be changed and SGlobal.typeId should be preserved. The regression tests in
- * `property("MethodCall Codes")` should pass.
+ * via lowering to Downcast, Upcast opcodes and the remaining `toBytes`, `toBits`
+ * methods are not implemented at all.
+ *
+ * Starting from v6.0 the SNumericType.typeId is demoted as a receiver object of
+ * method calls and:
+ * 1) numeric type SByte, SShort, SInt, SLong are promoted as receivers and added to
+ * the _types map.
+ * 2) all methods from SNumericTypeMethods are copied to all the concrete numeric types
+ * (SByte, SShort, SInt, SLong, SBigInt) and the generic tNum type parameter is
+ * specialized accordingly.
+ *
+ * This difference in behaviour is tested by `property("MethodCall on numerics")`.
+ *
+ * The regression tests in `property("MethodCall Codes")` should pass.
*/
- // TODO v6.0: should contain all numeric types (including also SNumericType)
- // to support method calls like 10.toByte which encoded as MethodCall with typeId = 4, methodId = 1
- // see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/667
- lazy val types: Map[Byte, STypeCompanion] = Seq(
- SBoolean, SNumericType, SString, STuple, SGroupElement, SSigmaProp, SContext, SGlobal, SHeader, SPreHeader,
+ private val v5Types = Seq(
+ SBoolean, SString, STuple, SGroupElement, SSigmaProp, SContext, SGlobal, SHeader, SPreHeader,
SAvlTree, SBox, SOption, SCollection, SBigInt
- ).map { t => (t.typeId, t) }.toMap
+ )
+ private val v6Types = v5Types ++ Seq(SByte, SShort, SInt, SLong)
+
+ private val v5TypesMap = v5Types.map { t => (t.typeId, t) }.toMap
+
+ private val v6TypesMap = v6Types.map { t => (t.typeId, t) }.toMap
+
+ def types: Map[Byte, STypeCompanion] = if (VersionContext.current.isV6SoftForkActivated) {
+ v6TypesMap
+ } else {
+ v5TypesMap
+ }
/** Checks that the type of the value corresponds to the descriptor `tpe`.
* If the value has complex structure only root type constructor is checked.
@@ -146,7 +166,7 @@ object SType {
* 2) `isValueOfType == true` for each tree leaf
* 3) `isValueOfType == true` for each sub-expression
*
- * @param value value to check type
+ * @param x value to check type
* @param tpe type descriptor to check value against
* @return true if the given `value` is of type tpe`
*/
@@ -376,6 +396,7 @@ case object SByte extends SPrimType with SEmbeddable with SNumericType with SMon
case s: Short => s.toByteExact
case i: Int => i.toByteExact
case l: Long => l.toByteExact
+ case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toByte // toByteExact from int is called under the hood
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
@@ -397,6 +418,7 @@ case object SShort extends SPrimType with SEmbeddable with SNumericType with SMo
case s: Short => s
case i: Int => i.toShortExact
case l: Long => l.toShortExact
+ case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toShort // toShortExact from int is called under the hood
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
@@ -420,6 +442,7 @@ case object SInt extends SPrimType with SEmbeddable with SNumericType with SMono
case s: Short => s.toInt
case i: Int => i
case l: Long => l.toIntExact
+ case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toInt
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
@@ -445,11 +468,12 @@ case object SLong extends SPrimType with SEmbeddable with SNumericType with SMon
case s: Short => s.toLong
case i: Int => i.toLong
case l: Long => l
+ case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toLong
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
-/** Type of 256 bit integet values. Implemented using [[java.math.BigInteger]]. */
+/** Type of 256 bit integer values. Implemented using [[java.math.BigInteger]]. */
case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SMonoType {
override type WrappedType = BigInt
override val typeCode: TypeCode = 6: Byte
@@ -466,24 +490,24 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM
override def numericTypeIndex: Int = 4
override def upcast(v: AnyVal): BigInt = {
- val bi = v match {
- case x: Byte => BigInteger.valueOf(x.toLong)
- case x: Short => BigInteger.valueOf(x.toLong)
- case x: Int => BigInteger.valueOf(x.toLong)
- case x: Long => BigInteger.valueOf(x)
+ v match {
+ case x: Byte => CBigInt(BigInteger.valueOf(x.toLong))
+ case x: Short => CBigInt(BigInteger.valueOf(x.toLong))
+ case x: Int => CBigInt(BigInteger.valueOf(x.toLong))
+ case x: Long => CBigInt(BigInteger.valueOf(x))
+ case x: BigInt if VersionContext.current.isV6SoftForkActivated => x
case _ => sys.error(s"Cannot upcast value $v to the type $this")
}
- CBigInt(bi)
}
override def downcast(v: AnyVal): BigInt = {
- val bi = v match {
- case x: Byte => BigInteger.valueOf(x.toLong)
- case x: Short => BigInteger.valueOf(x.toLong)
- case x: Int => BigInteger.valueOf(x.toLong)
- case x: Long => BigInteger.valueOf(x)
+ v match {
+ case x: Byte => CBigInt(BigInteger.valueOf(x.toLong))
+ case x: Short => CBigInt(BigInteger.valueOf(x.toLong))
+ case x: Int => CBigInt(BigInteger.valueOf(x.toLong))
+ case x: Long => CBigInt(BigInteger.valueOf(x))
+ case x: BigInt if VersionContext.current.isV6SoftForkActivated => x
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
- CBigInt(bi)
}
}
@@ -584,7 +608,7 @@ case class SFunc(tDom: IndexedSeq[SType], tRange: SType, tpeParams: Seq[STypePa
}
object SFunc {
- final val FuncTypeCode: TypeCode = TypeCodes.FirstFuncType
+ final val FuncTypeCode: TypeCode = TypeCodes.FuncType
def apply(tDom: SType, tRange: SType): SFunc = SFunc(Array(tDom), tRange) // HOTSPOT:
val identity = { x: Any => x }
}
@@ -603,7 +627,8 @@ object STypeApply {
/** Type description of optional values. Instances of `Option`
* are either constructed by `Some` or by `None` constructors. */
case class SOption[ElemType <: SType](elemType: ElemType) extends SProduct with SGenericType {
- override type WrappedType = Option[ElemType#WrappedType]
+ type ElemWrappedType = ElemType#WrappedType
+ override type WrappedType = Option[ElemWrappedType]
override val typeCode: TypeCode = SOption.OptionTypeCode
override def toString = s"Option[$elemType]"
override def toTermString: String = s"Option[${elemType.toTermString}]"
@@ -650,7 +675,6 @@ object SOption extends STypeCompanion {
def apply[T <: SType](implicit elemType: T, ov: Overloaded1): SOption[T] = SOption(elemType)
}
-
/** Base class for descriptors of `Coll[T]` ErgoTree type for some elemType T. */
trait SCollection[T <: SType] extends SProduct with SGenericType {
def elemType: T
diff --git a/core/shared/src/main/scala/sigma/ast/STypeParam.scala b/core/shared/src/main/scala/sigma/ast/STypeParam.scala
index 56d89d01f8..08349ae024 100644
--- a/core/shared/src/main/scala/sigma/ast/STypeParam.scala
+++ b/core/shared/src/main/scala/sigma/ast/STypeParam.scala
@@ -2,18 +2,10 @@ package sigma.ast
/** Represents a type parameter in a type system.
*
- * @param ident The identifier for this type parameter.
- * @param upperBound The upper bound of this type parameter, if exists.
- * @param lowerBound The lower bound of this type parameter, if exists.
- * @note Type parameters with bounds are currently not supported.
+ * @param ident The identifier for this type parameter
*/
-case class STypeParam(
- ident: STypeVar,
- upperBound: Option[SType] = None,
- lowerBound: Option[SType] = None) {
- assert(upperBound.isEmpty && lowerBound.isEmpty, s"Type parameters with bounds are not supported, but found $this")
-
- override def toString = ident.toString + upperBound.fold("")(u => s" <: $u") + lowerBound.fold("")(l => s" >: $l")
+case class STypeParam(ident: STypeVar) {
+ override def toString = ident.toString
}
object STypeParam {
diff --git a/core/shared/src/main/scala/sigma/ast/TypeCodes.scala b/core/shared/src/main/scala/sigma/ast/TypeCodes.scala
index 1b7b6121d6..68670449db 100644
--- a/core/shared/src/main/scala/sigma/ast/TypeCodes.scala
+++ b/core/shared/src/main/scala/sigma/ast/TypeCodes.scala
@@ -14,10 +14,8 @@ object TypeCodes {
val LastDataType : TypeCode = TypeCode @@ 111.toByte
- /** SFunc types occupy remaining space of byte values [FirstFuncType .. 255] */
- val FirstFuncType: TypeCode = TypeCode @@ (LastDataType + 1).toByte
-
- val LastFuncType : TypeCode = TypeCode @@ 255.toByte
+ /** SFunc type */
+ val FuncType: TypeCode = TypeCode @@ (LastDataType + 1).toByte
/** We use optimized encoding of constant values to save space in serialization.
* Since Box registers are stored as Constant nodes we save 1 byte for each register.
diff --git a/core/shared/src/main/scala/sigma/ast/package.scala b/core/shared/src/main/scala/sigma/ast/package.scala
index 63a2cfbcba..ec51ca6e3a 100644
--- a/core/shared/src/main/scala/sigma/ast/package.scala
+++ b/core/shared/src/main/scala/sigma/ast/package.scala
@@ -137,6 +137,12 @@ package object ast {
def asNumType: SNumericType = tpe.asInstanceOf[SNumericType]
+ /** Cast this type to numeric type or else throws the given error. */
+ def asNumTypeOrElse(error: => Exception): SNumericType = tpe match {
+ case nt: SNumericType => nt
+ case _ => throw error
+ }
+
def asFunc: SFunc = tpe.asInstanceOf[SFunc]
def asProduct: SProduct = tpe.asInstanceOf[SProduct]
diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala
index bbf1a85e46..ea69174877 100644
--- a/core/shared/src/main/scala/sigma/data/CBigInt.scala
+++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala
@@ -49,4 +49,10 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr
override def and(that: BigInt): BigInt = CBigInt(wrappedValue.and(that.asInstanceOf[CBigInt].wrappedValue))
override def or(that: BigInt): BigInt = CBigInt(wrappedValue.or(that.asInstanceOf[CBigInt].wrappedValue))
+
+ override def xor(that: BigInt): BigInt = CBigInt(wrappedValue.xor(that.asInstanceOf[CBigInt].wrappedValue))
+
+ override def shiftLeft(n: Int): BigInt = CBigInt(wrappedValue.shiftLeft(n).to256BitValueExact)
+
+ override def shiftRight(n: Int): BigInt = CBigInt(wrappedValue.shiftRight(n).to256BitValueExact)
}
diff --git a/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala b/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala
index 2413f7f427..2d6a4a5cdf 100644
--- a/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala
+++ b/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala
@@ -1,6 +1,8 @@
package sigma.data
import debox.{Buffer, cfor}
+import sigma.Evaluation.stypeToRType
+import sigma.data.CollOverArray.equalsPairCollWithCollOverArray
import sigma.data.RType._
import sigma.util.{CollectionUtil, MaxArrayLength, safeConcatArrays_v5}
import sigma.{Coll, CollBuilder, PairColl, VersionContext, requireSameLength}
@@ -12,7 +14,9 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil
s"Cannot create collection with size ${toArray.length} greater than $MaxArrayLength")
override def tItem: RType[A] = tA
+
@inline def length: Int = toArray.length
+
@inline def apply(i: Int): A = toArray.apply(i)
override def isEmpty: Boolean = length == 0
@@ -29,8 +33,11 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil
}
def foreach(f: A => Unit): Unit = toArray.foreach(f)
+
def exists(p: A => Boolean): Boolean = toArray.exists(p)
+
def forall(p: A => Boolean): Boolean = toArray.forall(p)
+
def filter(p: A => Boolean): Coll[A] = builder.fromArray(toArray.filter(p))
def foldLeft[B](zero: B, op: ((B, A)) => B): B = toArray.foldLeft(zero)((b, a) => op((b, a)))
@@ -39,6 +46,10 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil
@inline def zip[@specialized B](ys: Coll[B]): PairColl[A, B] = builder.pairColl(this, ys)
+ @inline def startsWith(ys: Coll[A]): Boolean = toArray.startsWith(ys.toArray)
+
+ @inline def endsWith(ys: Coll[A]): Boolean = toArray.endsWith(ys.toArray)
+
def append(other: Coll[A]): Coll[A] = {
if (toArray.length <= 0) return other
val result = if (VersionContext.current.isJitActivated) {
@@ -113,12 +124,14 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil
override def unionSet(that: Coll[A]): Coll[A] = {
val set = debox.Set.ofSize[A](this.length)
val res = Buffer.ofSize[A](this.length)
+
@inline def addItemToSet(x: A) = {
if (!set(x)) {
set.add(x)
res += x
}
}
+
def addToSet(arr: Array[A]) = {
val limit = arr.length
cfor(0)(_ < limit, _ + 1) { i =>
@@ -135,14 +148,42 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil
override def equals(obj: scala.Any): Boolean = (this eq obj.asInstanceOf[AnyRef]) || (obj match {
case obj: CollOverArray[_] if obj.tItem == this.tItem =>
- java.util.Objects.deepEquals(obj.toArray, toArray)
+ java.util.Objects.deepEquals(obj.toArray, this.toArray)
+ case obj: PairColl[Any, Any] if obj.tItem == this.tItem =>
+ if (VersionContext.current.isV6SoftForkActivated) {
+ equalsPairCollWithCollOverArray(obj, this.asInstanceOf[CollOverArray[Any]])
+ } else {
+ false
+ }
case _ => false
})
- override def hashCode() = CollectionUtil.deepHashCode(toArray)
+ override def hashCode(): Int = CollectionUtil.deepHashCode(toArray)
+}
+
+object CollOverArray {
+
+ // comparing PairColl and CollOverArray instances
+ private[data] def equalsPairCollWithCollOverArray(pc: PairColl[Any, Any], coa: CollOverArray[Any]): Boolean = {
+ val ls = pc.ls
+ val rs = pc.rs
+ val ts = coa.toArray
+ if (ts.length == ls.length && ts.isInstanceOf[Array[(Any, Any)]]) {
+ val ta = ts.asInstanceOf[Array[(Any, Any)]]
+ var eq = true
+ cfor(0)(_ < ta.length && eq, _ + 1) { i =>
+ eq = java.util.Objects.deepEquals(ta(i)._1, ls(i)) && java.util.Objects.deepEquals(ta(i)._2, rs(i))
+ }
+ eq
+ } else {
+ false
+ }
+ }
+
}
-private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
+private[sigma] class CollOverArrayBuilder extends CollBuilder {
+ builder =>
@inline override def pairColl[@specialized A, @specialized B](as: Coll[A], bs: Coll[B]): PairColl[A, B] = {
if (VersionContext.current.isJitActivated) {
@@ -166,12 +207,12 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
}
}
- private def fromBoxedPairs[A, B](seq: Seq[(A, B)])(implicit tA: RType[A], tB: RType[B]): PairColl[A,B] = {
+ private def fromBoxedPairs[A, B](seq: Seq[(A, B)])(implicit tA: RType[A], tB: RType[B]): PairColl[A, B] = {
val len = seq.length
val resA = Array.ofDim[A](len)(tA.classTag)
val resB = Array.ofDim[B](len)(tB.classTag)
cfor(0)(_ < len, _ + 1) { i =>
- val item = seq.apply(i).asInstanceOf[(A,B)]
+ val item = seq.apply(i).asInstanceOf[(A, B)]
resA(i) = item._1
resB(i) = item._2
}
@@ -179,7 +220,7 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
}
override def fromItems[T](items: T*)(implicit cT: RType[T]): Coll[T] = cT match {
- case pt: PairType[a,b] =>
+ case pt: PairType[a, b] =>
val tA = pt.tFst
val tB = pt.tSnd
fromBoxedPairs(items)(tA, tB)
@@ -188,16 +229,16 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
}
override def fromArray[@specialized T: RType](arr: Array[T]): Coll[T] = RType[T] match {
- case pt: PairType[a,b] =>
+ case pt: PairType[a, b] =>
val tA = pt.tFst
val tB = pt.tSnd
- fromBoxedPairs[a,b](arr.asInstanceOf[Array[(a,b)]])(tA, tB)
+ fromBoxedPairs[a, b](arr.asInstanceOf[Array[(a, b)]])(tA, tB)
case _ =>
new CollOverArray(arr, builder)
}
override def replicate[@specialized T: RType](n: Int, v: T): Coll[T] = RType[T] match {
- case pt: PairType[a,b] =>
+ case pt: PairType[a, b] =>
val tA = pt.tFst
val tB = pt.tSnd
val tuple = v.asInstanceOf[(a, b)]
@@ -206,8 +247,8 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
fromArray(Array.fill(n)(v))
}
- override def unzip[@specialized A, @specialized B](xs: Coll[(A,B)]): (Coll[A], Coll[B]) = xs match {
- case pa: PairColl[_,_] => (pa.ls, pa.rs)
+ override def unzip[@specialized A, @specialized B](xs: Coll[(A, B)]): (Coll[A], Coll[B]) = xs match {
+ case pa: PairColl[_, _] => (pa.ls, pa.rs)
case _ =>
val limit = xs.length
implicit val tA = xs.tItem.tFst
@@ -226,7 +267,7 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
left.zip(right).map { case (l, r) => (l ^ r).toByte }
override def emptyColl[T](implicit cT: RType[T]): Coll[T] = cT match {
- case pt: PairType[a,b] =>
+ case pt: PairType[a, b] =>
val ls = emptyColl(pt.tFst)
val rs = emptyColl(pt.tSnd)
pairColl(ls, rs).asInstanceOf[Coll[T]]
@@ -235,15 +276,24 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
}
}
-class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R]) extends PairColl[L,R] {
+class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R]) extends PairColl[L, R] {
- override def equals(that: scala.Any) = (this eq that.asInstanceOf[AnyRef]) || (that match {
- case that: PairColl[_,_] if that.tItem == this.tItem => ls == that.ls && rs == that.rs
+ override def equals(that: scala.Any): Boolean = (this eq that.asInstanceOf[AnyRef]) || (that match {
+ case that: PairColl[_, _] if that.tItem == this.tItem =>
+ ls == that.ls && rs == that.rs
+ case that: CollOverArray[Any] if that.tItem == this.tItem =>
+ if (VersionContext.current.isV6SoftForkActivated) {
+ equalsPairCollWithCollOverArray(this.asInstanceOf[PairColl[Any, Any]], that)
+ } else {
+ false
+ }
case _ => false
})
override def hashCode() = ls.hashCode() * 41 + rs.hashCode()
+
@inline implicit def tL: RType[L] = ls.tItem
+
@inline implicit def tR: RType[R] = rs.tItem
override lazy val tItem: RType[(L, R)] = {
@@ -251,8 +301,11 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R
}
override def builder: CollBuilder = ls.builder
+
override def toArray: Array[(L, R)] = ls.toArray.zip(rs.toArray)
+
@inline override def length: Int = if (ls.length <= rs.length) ls.length else rs.length
+
@inline override def apply(i: Int): (L, R) = (ls(i), rs(i))
override def isEmpty: Boolean = length == 0
@@ -300,7 +353,7 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R
true
}
- override def filter(p: ((L, R)) => Boolean): Coll[(L,R)] = {
+ override def filter(p: ((L, R)) => Boolean): Coll[(L, R)] = {
val len = ls.length
val resL: Buffer[L] = Buffer.empty[L](ls.tItem.classTag)
val resR: Buffer[R] = Buffer.empty[R](rs.tItem.classTag)
@@ -329,9 +382,9 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R
state
}
- override def slice(from: Int, until: Int): PairColl[L,R] = builder.pairColl(ls.slice(from, until), rs.slice(from, until))
+ override def slice(from: Int, until: Int): PairColl[L, R] = builder.pairColl(ls.slice(from, until), rs.slice(from, until))
- def append(other: Coll[(L, R)]): Coll[(L,R)] = {
+ def append(other: Coll[(L, R)]): Coll[(L, R)] = {
val arrs = builder.unzip(other)
builder.pairColl(ls.append(arrs._1), rs.append(arrs._2))
}
@@ -348,7 +401,17 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R
}
}
- def zip[@specialized B](ys: Coll[B]): PairColl[(L,R), B] = builder.pairColl(this, ys)
+ def zip[@specialized B](ys: Coll[B]): PairColl[(L, R), B] = builder.pairColl(this, ys)
+
+ def startsWith(ys: Coll[(L, R)]): Boolean = ys match {
+ case yp: PairOfCols[L, R] => ls.startsWith(yp.ls) && rs.startsWith(yp.rs)
+ case _ => toArray.startsWith(ys.toArray)
+ }
+
+ def endsWith(ys: Coll[(L, R)]): Boolean = ys match {
+ case yp: PairOfCols[L, R] => ls.endsWith(yp.ls) && rs.endsWith(yp.rs)
+ case _ => toArray.endsWith(ys.toArray)
+ }
override def indices: Coll[Int] = if (ls.length <= rs.length) ls.indices else rs.indices
@@ -394,18 +457,20 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R
}
override def unionSet(that: Coll[(L, R)]): Coll[(L, R)] = {
- val set = new java.util.HashSet[(L,R)](32)
+ val set = new java.util.HashSet[(L, R)](32)
implicit val ctL = ls.tItem.classTag
implicit val ctR = rs.tItem.classTag
val resL = Buffer.empty[L]
val resR = Buffer.empty[R]
- def addToSet(item: (L,R)) = {
+
+ def addToSet(item: (L, R)) = {
if (!set.contains(item)) {
set.add(item)
resL += item._1
resR += item._2
}
}
+
var i = 0
val thisLen = math.min(ls.length, rs.length)
while (i < thisLen) {
diff --git a/core/shared/src/main/scala/sigma/data/Iso.scala b/core/shared/src/main/scala/sigma/data/Iso.scala
index 9b90d63bb0..0e463bdd04 100644
--- a/core/shared/src/main/scala/sigma/data/Iso.scala
+++ b/core/shared/src/main/scala/sigma/data/Iso.scala
@@ -7,14 +7,20 @@ import sigma.{Coll, Colls}
/** Type-class of isomorphisms between types.
* Isomorphism between two types `A` and `B` essentially say that both types
* represents the same information (entity) but in a different way.
+ *
+ * Each isomorphism defined by two functions:
+ * - `to: A => B` - conversion from `A` to `B`
+ * - `from: B => A` - conversion from `B` to `A`
+ *
*
- * The information is not lost so that both are true:
+ * such that the information is not lost during conversion, so that both are true:
* 1) a == from(to(a))
* 2) b == to(from(b))
*
* It is used to define type-full conversions:
* - different conversions between Java and Scala data types.
- * - conversion between Ergo representations and generated API representations
+ * - conversion between internal Ergo representations and API representations
+ * - conversions between exported JS classes and internal Ergo representations
*/
abstract class Iso[A, B] {
def to(a: A): B
diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala
index 028e68bf72..3351c5a2c6 100644
--- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala
+++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala
@@ -162,6 +162,9 @@ object ReflectionData {
mkMethod(clazz, "apply", Array[Class[_]](classOf[Int])) { (obj, args) =>
obj.asInstanceOf[Coll[_]].apply(args(0).asInstanceOf[Int])
},
+ mkMethod(clazz, "get", Array[Class[_]](classOf[Int])) { (obj, args) =>
+ obj.asInstanceOf[Coll[_]].get(args(0).asInstanceOf[Int])
+ },
mkMethod(clazz, "append", Array[Class[_]](classOf[Coll[_]])) { (obj, args) =>
obj.asInstanceOf[Coll[Any]].append(args(0).asInstanceOf[Coll[Any]])
},
@@ -170,6 +173,18 @@ object ReflectionData {
},
mkMethod(clazz, "map", Array[Class[_]](classOf[Function1[_, _]], classOf[RType[_]])) { (obj, args) =>
obj.asInstanceOf[Coll[Any]].map(args(0).asInstanceOf[Any => Any])(args(1).asInstanceOf[RType[Any]])
+ },
+ mkMethod(clazz, "reverse", Array[Class[_]]()) { (obj, args) =>
+ obj.asInstanceOf[Coll[Any]].reverse
+ },
+ mkMethod(clazz, "distinct", Array[Class[_]]()) { (obj, args) =>
+ obj.asInstanceOf[Coll[Any]].distinct
+ },
+ mkMethod(clazz, "startsWith", Array[Class[_]](classOf[Coll[_]])) { (obj, args) =>
+ obj.asInstanceOf[Coll[Any]].startsWith(args(0).asInstanceOf[Coll[Any]])
+ },
+ mkMethod(clazz, "endsWith", Array[Class[_]](classOf[Coll[_]])) { (obj, args) =>
+ obj.asInstanceOf[Coll[Any]].endsWith(args(0).asInstanceOf[Coll[Any]])
}
)
)
@@ -273,6 +288,9 @@ object ReflectionData {
mkMethod(clazz, "getVar", Array[Class[_]](classOf[Byte], classOf[RType[_]])) { (obj, args) =>
obj.asInstanceOf[Context].getVar(args(0).asInstanceOf[Byte])(args(1).asInstanceOf[RType[_]])
},
+ mkMethod(clazz, "getVarFromInput", Array[Class[_]](classOf[Short], classOf[Byte], classOf[RType[_]])) { (obj, args) =>
+ obj.asInstanceOf[Context].getVarFromInput(args(0).asInstanceOf[Short], args(1).asInstanceOf[Byte])(args(2).asInstanceOf[RType[_]])
+ },
mkMethod(clazz, "headers", Array[Class[_]]()) { (obj, _) =>
obj.asInstanceOf[Context].headers
}
@@ -346,6 +364,9 @@ object ReflectionData {
},
mkMethod(clazz, "powDistance", Array[Class[_]]()) { (obj, _) =>
obj.asInstanceOf[Header].powDistance
+ },
+ mkMethod(clazz, "checkPow", Array[Class[_]]()) { (obj, _) =>
+ obj.asInstanceOf[Header].checkPow
}
)
)
@@ -441,8 +462,15 @@ object ReflectionData {
mkMethod(clazz, "sha256", Array[Class[_]](cColl)) { (obj, args) =>
obj.asInstanceOf[SigmaDslBuilder].sha256(args(0).asInstanceOf[Coll[Byte]])
},
+ mkMethod(clazz, "serialize", Array[Class[_]](classOf[Object], classOf[RType[_]])) { (obj, args) =>
+ obj.asInstanceOf[SigmaDslBuilder].serialize[Any](
+ args(0).asInstanceOf[Any])(args(1).asInstanceOf[RType[Any]])
+ },
mkMethod(clazz, "decodePoint", Array[Class[_]](cColl)) { (obj, args) =>
obj.asInstanceOf[SigmaDslBuilder].decodePoint(args(0).asInstanceOf[Coll[Byte]])
+ },
+ mkMethod(clazz, "fromBigEndianBytes", Array[Class[_]](cColl, classOf[RType[_]])) { (obj, args) =>
+ obj.asInstanceOf[SigmaDslBuilder].fromBigEndianBytes(args(0).asInstanceOf[Coll[Byte]])(args(1).asInstanceOf[RType[_]])
}
)
)
diff --git a/core/shared/src/main/scala/sigma/serialization/CoreByteReader.scala b/core/shared/src/main/scala/sigma/serialization/CoreByteReader.scala
index 34ed74ac6a..e238829b6c 100644
--- a/core/shared/src/main/scala/sigma/serialization/CoreByteReader.scala
+++ b/core/shared/src/main/scala/sigma/serialization/CoreByteReader.scala
@@ -10,10 +10,6 @@ import sigma.validation.ValidationRules.CheckPositionLimit
* methods.
*
* @param r the underlying reader this reader reads from
- * @param constantStore the store of constants which is used to resolve
- * [[sigma.ast.ConstantPlaceholder]]
- * @param resolvePlaceholdersToConstants if true then resolved constants will be
- * substituted in the tree instead of the placeholder.
* @param maxTreeDepth limit on the tree depth (recursive invocations)
* of the deserializer
*/
diff --git a/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala b/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala
index aa4255449c..92d85ed9d8 100644
--- a/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala
+++ b/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala
@@ -3,9 +3,10 @@ package sigma.serialization
import scorex.util.serialization.Writer.Aux
import scorex.util.serialization.{VLQByteBufferWriter, Writer}
import sigma.ast.SType
-import sigma.serialization.CoreByteWriter.{Bits, DataInfo, U, Vlq, ZigZag}
+import sigma.serialization.CoreByteWriter._
/** Implementation of [[Writer]] provided by `sigma-core` module.
+ *
* @param w destination [[Writer]] to which all the call got delegated.
*/
class CoreByteWriter(val w: Writer) extends Writer {
@@ -15,11 +16,20 @@ class CoreByteWriter(val w: Writer) extends Writer {
@inline override def newWriter(): Aux[CH] = w.newWriter()
- @inline override def putChunk(chunk: CH): this.type = { w.putChunk(chunk); this }
+ @inline override def putChunk(chunk: CH): this.type = {
+ w.putChunk(chunk); this
+ }
@inline override def result(): CH = w.result()
- @inline def put(x: Byte): this.type = { w.put(x); this }
+ @inline override def put(x: Byte): this.type = {
+ w.put(x); this
+ }
+
+ /** Put the given byte into the writer.
+ * @param x the byte to put into the writer
+ * @param info meta information about the data being put into the writer
+ */
@inline def put(x: Byte, info: DataInfo[Byte]): this.type = {
w.put(x); this
}
@@ -27,41 +37,110 @@ class CoreByteWriter(val w: Writer) extends Writer {
override def putUByte(x: Int): this.type = {
super.putUByte(x)
}
+
+ /** Encode integer as an unsigned byte asserting the range check
+ * @param x integer value to encode (should be in the range of unsigned byte)
+ * @param info meta information about the data being put into the writer
+ * @return
+ * @throws AssertionError if x is outside of the unsigned byte range
+ */
def putUByte(x: Int, info: DataInfo[U[Byte]]): this.type = {
super.putUByte(x)
}
- @inline def putBoolean(x: Boolean): this.type = { w.putBoolean(x); this }
+ @inline override def putBoolean(x: Boolean): this.type = {
+ w.putBoolean(x); this
+ }
+
+ /** Encode boolean by delegating to the underlying writer.
+ * @param x boolean value to encode
+ * @param info meta information about the data being put into the writer
+ * @return
+ */
@inline def putBoolean(x: Boolean, info: DataInfo[Boolean]): this.type = {
w.putBoolean(x); this
}
- @inline def putShort(x: Short): this.type = { w.putShort(x); this }
+ @inline override def putShort(x: Short): this.type = {
+ w.putShort(x); this
+ }
+
+ /** Encode signed Short by delegating to the underlying writer.
+ *
+ * Use [[putUShort]] to encode values that are positive.
+ * @param x short value to encode
+ * @param info meta information about the data being put into the writer
+ */
@inline def putShort(x: Short, info: DataInfo[Short]): this.type = {
w.putShort(x); this
}
- @inline def putUShort(x: Int): this.type = { w.putUShort(x); this }
+ @inline override def putUShort(x: Int): this.type = {
+ w.putUShort(x); this
+ }
+
+ /** Encode Short that are positive by delegating to the underlying writer.
+ *
+ * Use [[putShort]] to encode values that might be negative.
+ * @param x unsigned short value (represented as Int) to encode
+ * @param info meta information about the data being put into the writer
+ */
@inline def putUShort(x: Int, info: DataInfo[Vlq[U[Short]]]): this.type = {
w.putUShort(x); this
}
- @inline def putInt(x: Int): this.type = { w.putInt(x); this }
+ @inline override def putInt(x: Int): this.type = {
+ w.putInt(x); this
+ }
+
+ /** Encode signed Int by delegating to the underlying writer.
+ * Use [[putUInt]] to encode values that are positive.
+ *
+ * @param x integer value to encode
+ * @param info meta information about the data being put into the writer
+ */
@inline def putInt(x: Int, info: DataInfo[Int]): this.type = {
w.putInt(x); this
}
- @inline def putUInt(x: Long): this.type = { w.putUInt(x); this }
+ @inline override def putUInt(x: Long): this.type = {
+ w.putUInt(x); this
+ }
+
+ /** Encode Int that are positive by delegating to the underlying writer.
+ * Use [[putInt]] to encode values that might be negative.
+ *
+ * @param x unsigned integer value (represented as Long) to encode
+ * @param info meta information about the data being put into the writer
+ */
@inline def putUInt(x: Long, info: DataInfo[Vlq[U[Int]]]): this.type = {
w.putUInt(x); this
}
- @inline def putLong(x: Long): this.type = { w.putLong(x); this }
+ @inline override def putLong(x: Long): this.type = {
+ w.putLong(x); this
+ }
+
+ /** Encode signed Long by delegating to the underlying writer.
+ * Use [[putULong]] to encode values that are positive.
+ *
+ * @param x long value to encode
+ * @param info meta information about the data being put into the writer
+ */
@inline def putLong(x: Long, info: DataInfo[Vlq[ZigZag[Long]]]): this.type = {
w.putLong(x); this
}
- @inline def putULong(x: Long): this.type = { w.putULong(x); this }
+ @inline override def putULong(x: Long): this.type = {
+ w.putULong(x); this
+ }
+
+ /** Encode Long that are positive by delegating to the underlying writer.
+ * Use [[putLong]] to encode values that might be negative.
+ *
+ * @param x unsigned long value to encode
+ * @param info meta information about the data being put into the writer
+ */
@inline def putULong(x: Long, info: DataInfo[Vlq[U[Long]]]): this.type = {
w.putULong(x); this
}
@@ -71,7 +150,15 @@ class CoreByteWriter(val w: Writer) extends Writer {
length: Int): this.type = {
w.putBytes(xs, offset, length); this
}
- @inline def putBytes(xs: Array[Byte]): this.type = { w.putBytes(xs); this }
+
+ @inline override def putBytes(xs: Array[Byte]): this.type = {
+ w.putBytes(xs); this
+ }
+
+ /** Encode an array of bytes by delegating to the underlying writer.
+ * @param xs array of bytes to encode
+ * @param info meta information about the data being put into the writer
+ */
@inline def putBytes(xs: Array[Byte], info: DataInfo[Array[Byte]]): this.type = {
w.putBytes(xs); this
}
@@ -84,29 +171,51 @@ class CoreByteWriter(val w: Writer) extends Writer {
this
}
- @inline def putBits(xs: Array[Boolean]): this.type = { w.putBits(xs); this }
+ @inline override def putBits(xs: Array[Boolean]): this.type = {
+ w.putBits(xs); this
+ }
+
+ /** Encode an array of boolean values as a bit array (packing bits into bytes)
+ *
+ * @param xs array of boolean values
+ * @param info meta information about the data being put into the writer
+ */
@inline def putBits(xs: Array[Boolean], info: DataInfo[Bits]): this.type = {
- w.putBits(xs);
- this
+ w.putBits(xs); this
}
- @inline def putOption[T](x: Option[T])(putValueC: (this.type, T) => Unit): this.type = {
+ @inline override def putOption[T](x: Option[T])(putValueC: (this.type, T) => Unit): this.type = {
w.putOption(x) { (_, v) =>
putValueC(this, v)
}
this
}
- @inline def putShortString(s: String): this.type = { w.putShortString(s); this }
+ @inline override def putShortString(s: String): this.type = {
+ w.putShortString(s);
+ this
+ }
// TODO refactor: move to Writer
@inline def toBytes: Array[Byte] = w match {
case wr: VLQByteBufferWriter => wr.toBytes
}
- @inline def putType[T <: SType](x: T): this.type = { TypeSerializer.serialize(x, this); this }
+ /** Serialize the given type into the writer using [[TypeSerializer]].
+ * @param x the type to put into the writer
+ */
+ @inline def putType[T <: SType](x: T): this.type = {
+ TypeSerializer.serialize(x, this)
+ this
+ }
+
+ /** Serialize the given type into the writer using [[TypeSerializer]].
+ * @param x the type to put into the writer
+ * @param info meta information about the data being put into the writer
+ */
@inline def putType[T <: SType](x: T, info: DataInfo[SType]): this.type = {
- TypeSerializer.serialize(x, this); this
+ TypeSerializer.serialize(x, this)
+ this
}
}
@@ -226,6 +335,11 @@ object CoreByteWriter {
* @param description argument description. */
case class ArgInfo(name: String, description: String)
+ /** Represents meta information about serialized data.
+ * Passed as additional argument of serializer methods.
+ * Can be used to automatically generate format specifications based on
+ * the actual collected method invocations.
+ */
case class DataInfo[T](info: ArgInfo, format: FormatDescriptor[T])
object DataInfo {
diff --git a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala
index 479b199da5..233494392a 100644
--- a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala
+++ b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala
@@ -68,7 +68,12 @@ class CoreDataSerializer {
i += 1
}
- // TODO v6.0 (3h): support Option[T] (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/659)
+ case SOption(elemType) if VersionContext.current.isV6SoftForkActivated =>
+ val o = v.asInstanceOf[Option[elemType.WrappedType]]
+ w.putOption(o){case (w, v) =>
+ serialize(v, elemType, w)
+ }
+
case _ =>
CheckSerializableTypeCode(tpe.typeCode)
throw new SerializerException(s"Don't know how to serialize ($v, $tpe)")
@@ -118,6 +123,10 @@ class CoreDataSerializer {
}.toArray[Any]
val coll = Colls.fromArray(arr)(sigma.AnyType)
Evaluation.toDslTuple(coll, tuple)
+ case tOption: SOption[_] if VersionContext.current.isV6SoftForkActivated =>
+ r.getOption[tOption.ElemWrappedType] {
+ deserialize(tOption.elemType, r).asInstanceOf[tOption.ElemWrappedType]
+ }
case t =>
CheckSerializableTypeCode(t.typeCode)
throw new SerializerException(s"Not defined DataSerializer for type $t")
diff --git a/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala b/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala
index 9c84de0944..1936bbcd9a 100644
--- a/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala
+++ b/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala
@@ -1,9 +1,9 @@
package sigma.serialization
import debox.cfor
+import sigma.VersionContext
import sigma.ast.SCollectionType.{CollectionTypeCode, NestedCollectionTypeCode}
import sigma.ast._
-import sigma.serialization.{CoreByteReader, CoreByteWriter, InvalidTypePrefix}
import sigma.util.safeNewArray
import sigma.validation.ValidationRules.{CheckPrimitiveTypeCode, CheckTypeCode}
@@ -101,6 +101,17 @@ class TypeSerializer {
// `Tuple` type with more than 4 items `(Int, Byte, Box, Boolean, Int)`
serializeTuple(tup, w)
}
+ case SFunc(tDom, tRange, tpeParams) =>
+ w.put(SFunc.FuncTypeCode)
+ w.putUByte(tDom.length)
+ tDom.foreach { st =>
+ serialize(st, w)
+ }
+ serialize(tRange, w)
+ w.putUByte(tpeParams.length)
+ tpeParams.foreach { tp =>
+ serialize(tp.ident, w)
+ }
case typeIdent: STypeVar => {
w.put(typeIdent.typeCode)
val bytes = typeIdent.name.getBytes(StandardCharsets.UTF_8)
@@ -189,7 +200,23 @@ class TypeSerializer {
case SHeader.typeCode => SHeader
case SPreHeader.typeCode => SPreHeader
case SGlobal.typeCode => SGlobal
+ case SFunc.FuncTypeCode if VersionContext.current.isV6SoftForkActivated =>
+ val tdLength = r.getUByte()
+
+ val tDom = (1 to tdLength).map { _ =>
+ deserialize(r)
+ }
+ val tRange = deserialize(r)
+ val tpeParamsLength = r.getUByte()
+ val tpeParams = (1 to tpeParamsLength).map { _ =>
+ val ident = deserialize(r)
+ require(ident.isInstanceOf[STypeVar])
+ STypeParam(ident.asInstanceOf[STypeVar])
+ }
+ SFunc(tDom, tRange, tpeParams)
case _ =>
+ // todo: 6.0: replace 1008 check with identical behavior but other opcode, to activate
+ // ReplacedRule(1008 -> new opcode) during 6.0 activation
CheckTypeCode(c.toByte)
NoType
}
diff --git a/core/shared/src/main/scala/sigma/util/NBitsUtils.scala b/core/shared/src/main/scala/sigma/util/NBitsUtils.scala
new file mode 100644
index 0000000000..36d526d1d5
--- /dev/null
+++ b/core/shared/src/main/scala/sigma/util/NBitsUtils.scala
@@ -0,0 +1,84 @@
+package sigma.util
+
+import java.math.BigInteger
+
+object NBitsUtils {
+
+ /**
+ *
The "compact" format is a representation of a whole number N using an unsigned 32 bit number similar to a
+ * floating point format. The most significant 8 bits are the unsigned exponent of base 256. This exponent can
+ * be thought of as "number of bytes of N". The lower 23 bits are the mantissa. Bit number 24 (0x800000) represents
+ * the sign of N. Therefore, N = (-1^sign) * mantissa * 256^(exponent-3).
+ *
+ * Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). MPI uses the most significant bit of the
+ * first byte as sign. Thus 0x1234560000 is compact 0x05123456 and 0xc0de000000 is compact 0x0600c0de. Compact
+ * 0x05c0de00 would be -0x40de000000.
+ *
+ * Bitcoin only uses this "compact" format for encoding difficulty targets, which are unsigned 256bit quantities.
+ * Thus, all the complexities of the sign bit and using base 256 are probably an implementation accident.
+ */
+ def decodeCompactBits(compact: Long): BigInt = {
+ val size: Int = (compact >> 24).toInt & 0xFF
+ val bytes: Array[Byte] = new Array[Byte](4 + size)
+ bytes(3) = size.toByte
+ if (size >= 1) bytes(4) = ((compact >> 16) & 0xFF).toByte
+ if (size >= 2) bytes(5) = ((compact >> 8) & 0xFF).toByte
+ if (size >= 3) bytes(6) = (compact & 0xFF).toByte
+ decodeMPI(bytes)
+ }
+
+ /**
+ * @see Utils#decodeCompactBits(long)
+ */
+ def encodeCompactBits(requiredDifficulty: BigInt): Long = {
+ val value = requiredDifficulty.bigInteger
+ var result: Long = 0L
+ var size: Int = value.toByteArray.length
+ if (size <= 3) {
+ result = value.longValue << 8 * (3 - size)
+ } else {
+ result = value.shiftRight(8 * (size - 3)).longValue
+ }
+ // The 0x00800000 bit denotes the sign.
+ // Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
+ if ((result & 0x00800000L) != 0) {
+ result >>= 8
+ size += 1
+ }
+ result |= size << 24
+ val a: Int = if (value.signum == -1) 0x00800000 else 0
+ result |= a
+ result
+ }
+
+
+ /** Parse 4 bytes from the byte array (starting at the offset) as unsigned 32-bit integer in big endian format. */
+ def readUint32BE(bytes: Array[Byte]): Long = ((bytes(0) & 0xffL) << 24) | ((bytes(1) & 0xffL) << 16) | ((bytes(2) & 0xffL) << 8) | (bytes(3) & 0xffL)
+
+ /**
+ * MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of
+ * a 4 byte big endian length field, followed by the stated number of bytes representing
+ * the number in big endian format (with a sign bit).
+ *
+ */
+ private def decodeMPI(mpi: Array[Byte]): BigInteger = {
+
+ val length: Int = readUint32BE(mpi).toInt
+ val buf = new Array[Byte](length)
+ System.arraycopy(mpi, 4, buf, 0, length)
+
+ if (buf.length == 0) {
+ BigInteger.ZERO
+ } else {
+ val isNegative: Boolean = (buf(0) & 0x80) == 0x80
+ if (isNegative) buf(0) = (buf(0) & 0x7f).toByte
+ val result: BigInteger = new BigInteger(buf)
+ if (isNegative) {
+ result.negate
+ } else {
+ result
+ }
+ }
+ }
+
+}
diff --git a/core/shared/src/test/scala/sigma/CollsTests.scala b/core/shared/src/test/scala/sigma/CollsTests.scala
index 4886112742..da427ba576 100644
--- a/core/shared/src/test/scala/sigma/CollsTests.scala
+++ b/core/shared/src/test/scala/sigma/CollsTests.scala
@@ -386,6 +386,32 @@ class CollsTests extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers
}
}
+ property("Coll.startsWith") {
+ val minSuccess = minSuccessful(50)
+ forAll(collGen, minSuccess) { col =>
+ val n = col.length / 2
+ val prefix = col.take(n)
+ val pairs = col.zip(col)
+ pairs.startsWith(prefix.zip(prefix)) shouldBe true
+ col.startsWith(prefix) shouldBe true
+ val pairOfCols = new PairOfCols[Int, Int](col, col)
+ pairOfCols.startsWith(pairOfCols.take(n)) shouldBe true
+ }
+ }
+
+ property("Coll.endsWith") {
+ val minSuccess = minSuccessful(50)
+ forAll(collGen, minSuccess) { col =>
+ val n = col.length / 2
+ val suffix = col.slice(n, col.length)
+ col.endsWith(suffix) shouldBe true
+ val pairs = col.zip(col)
+ pairs.endsWith(suffix.zip(suffix)) shouldBe true
+ val pairOfCols = new PairOfCols[Int, Int](col, col)
+ pairOfCols.endsWith(pairOfCols.slice(n, col.length)) shouldBe true
+ }
+ }
+
property("Coll.equals") {
def checkColls(repl: Coll[_], coll: Coll[_]) = {
assert(coll == repl)
diff --git a/core/shared/src/test/scala/sigma/VersionTesting.scala b/core/shared/src/test/scala/sigma/VersionTesting.scala
index a17fc7a7f9..08053a6c48 100644
--- a/core/shared/src/test/scala/sigma/VersionTesting.scala
+++ b/core/shared/src/test/scala/sigma/VersionTesting.scala
@@ -6,13 +6,11 @@ import scala.util.DynamicVariable
trait VersionTesting {
- /** In v5.x we run test for only one activated version on the network (== 2).
- * In the branch for v6.0 the new version 3 should be added so that the tests run for both.
- */
+ /** Tests run for both version 2 & version 3 */
protected val activatedVersions: Seq[Byte] =
(0 to VersionContext.MaxSupportedScriptVersion).map(_.toByte).toArray[Byte]
- private[sigma] val _currActivatedVersion = new DynamicVariable[Byte](2) // v5.x by default
+ private[sigma] val _currActivatedVersion = new DynamicVariable[Byte](3) // v6.x by default
/** Current activated version used in tests. */
def activatedVersionInTests: Byte = _currActivatedVersion.value
@@ -43,7 +41,6 @@ trait VersionTesting {
// for each tree version up to currently activated, set it up and execute block
_currErgoTreeVersion.withValue(treeVersion)(block)
}
-
}
}
}
diff --git a/data/js/src/main/scala/sigma/data/js/Isos.scala b/data/js/src/main/scala/sigma/data/js/Isos.scala
new file mode 100644
index 0000000000..22300b1fd8
--- /dev/null
+++ b/data/js/src/main/scala/sigma/data/js/Isos.scala
@@ -0,0 +1,152 @@
+package sigma.data.js
+
+import org.ergoplatform.ErgoBox._
+import org.ergoplatform.{ErgoBox, ErgoBoxCandidate}
+import scorex.crypto.authds.ADKey
+import scorex.util.encode.Base16
+import sigma.Extensions._
+import sigma.ast.syntax.GroupElementConstant
+import sigma.ast.{Constant, GroupElementConstant, SType}
+import sigma.data.Iso.isoStringToArray
+import sigma.data.{CGroupElement, Digest32Coll, Iso}
+import sigma.js.GroupElement
+import sigma.serialization.{ErgoTreeSerializer, ValueSerializer}
+import sigma.{Coll, Colls}
+import sigmastate.fleetSdkCommon.distEsmTypesCommonMod.HexString
+import sigmastate.fleetSdkCommon.distEsmTypesRegistersMod.NonMandatoryRegisters
+import sigmastate.fleetSdkCommon.{distEsmTypesBoxesMod => boxesMod, distEsmTypesCommonMod => commonMod, distEsmTypesRegistersMod => registersMod, distEsmTypesTokenMod => tokenMod}
+
+import scala.scalajs.js
+
+/** Definitions of isomorphisms for sigma-data module.
+ * @see sigma.data.Iso
+ */
+object Isos {
+
+ val isoStringToGroupElement: Iso[String, sigma.GroupElement] = new Iso[String, sigma.GroupElement] {
+ override def to(x: String): sigma.GroupElement = {
+ val bytes = Base16.decode(x).get
+ ValueSerializer.deserialize(bytes).asInstanceOf[GroupElementConstant].value
+ }
+ override def from(x: sigma.GroupElement): String = {
+ val bytes = ValueSerializer.serialize(GroupElementConstant(x))
+ Base16.encode(bytes)
+ }
+ }
+
+ val isoGroupElement: Iso[GroupElement, sigma.GroupElement] = new Iso[GroupElement, sigma.GroupElement] {
+ override def to(x: GroupElement): sigma.GroupElement = {
+ CGroupElement(x.point)
+ }
+ override def from(x: sigma.GroupElement): GroupElement = {
+ new GroupElement(x.asInstanceOf[CGroupElement].wrappedValue)
+ }
+ }
+
+ implicit val isoBoxId: Iso[boxesMod.BoxId, ErgoBox.BoxId] = new Iso[boxesMod.BoxId, ErgoBox.BoxId] {
+ override def to(x: boxesMod.BoxId): ErgoBox.BoxId = ADKey @@@ isoStringToArray.to(x)
+
+ override def from(x: ErgoBox.BoxId): boxesMod.BoxId = isoStringToArray.from(x)
+ }
+
+ implicit val isoHexStringToConstant: Iso[HexString, Constant[SType]] = new Iso[HexString, Constant[SType]] {
+ override def to(x: HexString): Constant[SType] = {
+ val bytes = isoStringToArray.to(x)
+ val value = ValueSerializer.deserialize(bytes)
+ value.asInstanceOf[Constant[SType]]
+ }
+ override def from(x: Constant[SType]): HexString = {
+ val bytes = ValueSerializer.serialize(x)
+ isoStringToArray.from(bytes)
+ }
+ }
+
+
+ implicit val isoAmount: Iso[commonMod.Amount, Long] = new Iso[commonMod.Amount, Long] {
+ override def to(x: commonMod.Amount): Long = x.asInstanceOf[Any] match {
+ case s: String => BigInt(s).toLong
+ case _ => java.lang.Long.parseLong(x.asInstanceOf[js.BigInt].toString(10))
+ }
+ override def from(x: Long): commonMod.Amount = x.toString
+ }
+
+ implicit val isoToken: Iso[tokenMod.TokenAmount[commonMod.Amount], Token] =
+ new Iso[tokenMod.TokenAmount[commonMod.Amount], Token] {
+ override def to(x: tokenMod.TokenAmount[commonMod.Amount]): Token =
+ (Digest32Coll @@@ Colls.fromArray(Base16.decode(x.tokenId).get), isoAmount.to(x.amount))
+
+ override def from(x: Token): tokenMod.TokenAmount[commonMod.Amount] =
+ tokenMod.TokenAmount[commonMod.Amount](isoAmount.from(x._2), x._1.toHex)
+ }
+
+ val isoTokenArray: Iso[js.Array[tokenMod.TokenAmount[commonMod.Amount]], Coll[Token]] =
+ new Iso[js.Array[tokenMod.TokenAmount[commonMod.Amount]], Coll[Token]] {
+ override def to(x: js.Array[tokenMod.TokenAmount[commonMod.Amount]]): Coll[Token] = {
+ sigma.js.Isos.isoArrayToColl(isoToken).to(x)
+ }
+ override def from(x: Coll[Token]): js.Array[tokenMod.TokenAmount[commonMod.Amount]] = {
+ sigma.js.Isos.isoArrayToColl(isoToken).from(x)
+ }
+ }
+
+ val isoNonMandatoryRegisters: Iso[registersMod.NonMandatoryRegisters, AdditionalRegisters] =
+ new Iso[registersMod.NonMandatoryRegisters, AdditionalRegisters] {
+ override def to(x: registersMod.NonMandatoryRegisters): AdditionalRegisters = {
+ val regs = Seq(
+ x.R4 -> R4,
+ x.R5 -> R5,
+ x.R6 -> R6,
+ x.R7 -> R7,
+ x.R8 -> R8,
+ x.R9 -> R9
+ ).collect {
+ case (regOpt, id) if regOpt.isDefined => id -> isoHexStringToConstant.to(regOpt.get)
+ }
+ Map(regs:_*)
+ }
+ override def from(regs: AdditionalRegisters): registersMod.NonMandatoryRegisters = {
+ def regHexOpt(t: NonMandatoryRegisterId): Option[HexString] =
+ regs.get(t).map(v => isoHexStringToConstant.from(v.asInstanceOf[Constant[SType]]))
+
+ val resRegs = NonMandatoryRegisters()
+ regHexOpt(R4).foreach(resRegs.setR4(_))
+ regHexOpt(R5).foreach(resRegs.setR5(_))
+ regHexOpt(R6).foreach(resRegs.setR6(_))
+ regHexOpt(R7).foreach(resRegs.setR7(_))
+ regHexOpt(R8).foreach(resRegs.setR8(_))
+ regHexOpt(R9).foreach(resRegs.setR9(_))
+ resRegs
+ }
+ }
+
+ implicit val isoBoxCandidate: Iso[boxesMod.BoxCandidate[commonMod.Amount, NonMandatoryRegisters], ErgoBoxCandidate] = new Iso[boxesMod.BoxCandidate[commonMod.Amount, NonMandatoryRegisters], ErgoBoxCandidate] {
+ override def to(x: boxesMod.BoxCandidate[commonMod.Amount, NonMandatoryRegisters]): ErgoBoxCandidate = {
+ val ergoBoxCandidate = new ErgoBoxCandidate(
+ value = isoAmount.to(x.value),
+ ergoTree = {
+ val bytes = Base16.decode(x.ergoTree).get
+ ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes)
+ },
+ x.creationHeight.toInt,
+ additionalTokens = isoTokenArray.to(x.assets),
+ additionalRegisters = isoNonMandatoryRegisters.to(x.additionalRegisters)
+ )
+ ergoBoxCandidate
+ }
+
+ override def from(x: ErgoBoxCandidate): boxesMod.BoxCandidate[commonMod.Amount, NonMandatoryRegisters] = {
+ val ergoTree = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(x.ergoTree)
+ val ergoTreeStr = Base16.encode(ergoTree)
+ val assets = isoTokenArray.from(x.additionalTokens)
+ boxesMod.BoxCandidate[commonMod.Amount, NonMandatoryRegisters](
+ ergoTree = ergoTreeStr,
+ value = isoAmount.from(x.value),
+ assets = assets,
+ creationHeight = x.creationHeight,
+ additionalRegisters = isoNonMandatoryRegisters.from(x.additionalRegisters)
+ )
+ }
+ }
+
+
+}
diff --git a/data/js/src/main/scala/sigma/js/Box.scala b/data/js/src/main/scala/sigma/js/Box.scala
new file mode 100644
index 0000000000..70155633d5
--- /dev/null
+++ b/data/js/src/main/scala/sigma/js/Box.scala
@@ -0,0 +1,61 @@
+package sigma.js
+
+import org.ergoplatform.ErgoBox
+import scorex.util.ModifierId
+import scorex.util.encode.Base16
+import sigma.data.Iso
+import sigma.data.js.Isos.{isoAmount, isoNonMandatoryRegisters, isoTokenArray}
+import sigma.serialization.ErgoTreeSerializer
+import sigmastate.fleetSdkCommon.distEsmTypesBoxesMod.{Box => FBox}
+import sigmastate.fleetSdkCommon.distEsmTypesCommonMod.Amount
+import sigmastate.fleetSdkCommon.distEsmTypesRegistersMod.NonMandatoryRegisters
+import sigmastate.fleetSdkCommon.{distEsmTypesCommonMod => commonMod}
+
+import scala.scalajs.js
+import scala.scalajs.js.annotation.JSExportTopLevel
+
+/** Equivalent of [[sigma.Box]] available from JS. */
+@JSExportTopLevel("Box")
+class Box(val box: FBox[Amount, NonMandatoryRegisters]) extends js.Object
+
+object Box extends js.Object {
+ /** Represents a box in Fleet SDK. */
+ type FleetBox = FBox[commonMod.Amount, NonMandatoryRegisters]
+
+ /** Converts Fleet box to ErgoBox and back. */
+ val isoBox: Iso[FleetBox, ErgoBox] = new Iso[FleetBox, ErgoBox] {
+ override def to(x: FleetBox): ErgoBox = {
+ val ergoBox = new ErgoBox(
+ value = isoAmount.to(x.value),
+ ergoTree = {
+ val bytes = Base16.decode(x.ergoTree).get
+ ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes)
+ },
+ creationHeight = x.creationHeight.toInt,
+ additionalTokens = isoTokenArray.to(x.assets),
+ additionalRegisters = isoNonMandatoryRegisters.to(x.additionalRegisters),
+ transactionId = ModifierId @@ x.transactionId,
+ index = x.index.toShort
+ )
+ ergoBox
+ }
+
+ override def from(x: ErgoBox): FleetBox = {
+ val ergoTree = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(x.ergoTree)
+ val ergoTreeStr = Base16.encode(ergoTree)
+ val assets = isoTokenArray.from(x.additionalTokens)
+ FBox[commonMod.Amount, NonMandatoryRegisters](
+ boxId = Base16.encode(x.id),
+ ergoTree = ergoTreeStr,
+ value = isoAmount.from(x.value),
+ assets = assets,
+ creationHeight = x.creationHeight,
+ additionalRegisters = isoNonMandatoryRegisters.from(x.additionalRegisters),
+ transactionId = x.transactionId,
+ index = x.index
+ )
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/core/js/src/main/scala/sigma/js/Value.scala b/data/js/src/main/scala/sigma/js/Value.scala
similarity index 92%
rename from core/js/src/main/scala/sigma/js/Value.scala
rename to data/js/src/main/scala/sigma/js/Value.scala
index 13b63c2abc..a65156bd43 100644
--- a/core/js/src/main/scala/sigma/js/Value.scala
+++ b/data/js/src/main/scala/sigma/js/Value.scala
@@ -7,9 +7,10 @@ import sigma.ast.SType
import sigma.crypto.Platform
import sigma.data._
import sigma.js.Value.toRuntimeData
-import sigma.serialization.{CoreDataSerializer, CoreSerializer}
+import sigma.serialization.{DataSerializer, SigmaSerializer}
import sigma.util.Extensions.BigIntOps
import sigma.{Coll, Colls, Evaluation}
+import sigmastate.fleetSdkCommon.distEsmTypesBoxesMod.{Box => FBox}
import java.math.BigInteger
import scala.scalajs.js
@@ -55,9 +56,9 @@ class Value(val data: Any, val tpe: Type) extends js.Object {
def toHex(): String = {
val stype = Evaluation.rtypeToSType(tpe.rtype)
val value = runtimeData.asInstanceOf[SType#WrappedType]
- val w = CoreSerializer.startWriter()
+ val w = SigmaSerializer.startWriter()
w.putType(stype)
- CoreDataSerializer.serialize(value, stype, w)
+ DataSerializer.serialize(value, stype, w)
Base16.encode(w.toBytes)
}
}
@@ -89,6 +90,9 @@ object Value extends js.Object {
case sigma.AvlTreeRType =>
val t = data.asInstanceOf[AvlTree]
AvlTree.isoAvlTree.to(t)
+ case sigma.BoxRType =>
+ val t = data.asInstanceOf[Box]
+ CBox(Box.isoBox.to(t.box))
case ct: CollType[a] =>
val xs = data.asInstanceOf[js.Array[Any]]
implicit val cT = ct.tItem.classTag
@@ -124,6 +128,9 @@ object Value extends js.Object {
new SigmaProp(value.asInstanceOf[CSigmaProp].wrappedValue)
case sigma.AvlTreeRType =>
AvlTree.isoAvlTree.from(value.asInstanceOf[CAvlTree])
+ case sigma.BoxRType =>
+ val fleetBox = Box.isoBox.from(value.asInstanceOf[CBox].wrappedValue)
+ new Box(fleetBox)
case ct: CollType[a] =>
val arr = value.asInstanceOf[Coll[a]].toArray
js.Array(arr.map(x => fromRuntimeData(x, ct.tItem)):_*)
@@ -220,6 +227,13 @@ object Value extends js.Object {
new Value(sp, Type.SigmaProp)
}
+ /** Creates a Value of Box type from a [[FBox]] instance.
+ * @param fleetBox a Fleet box to be wrapped in a [[Value]]
+ */
+ def ofBox(fleetBox: Box.FleetBox): Value = {
+ new Value(new Box(fleetBox), Type.Box)
+ }
+
/** Create Pair value from two values. */
def pairOf(l: Value, r: Value): Value = {
val data = js.Array(l.data, r.data) // the l and r data have been validated
@@ -251,9 +265,9 @@ object Value extends js.Object {
*/
def fromHex(hex: String): Value = {
val bytes = Base16.decode(hex).fold(t => throw t, identity)
- val r = CoreSerializer.startReader(bytes)
+ val r = SigmaSerializer.startReader(bytes)
val stype = r.getType()
- val value = CoreDataSerializer.deserialize(stype, r)
+ val value = DataSerializer.deserialize(stype, r)
val rtype = Evaluation.stypeToRType(stype)
val jsvalue = Value.fromRuntimeData(value, rtype)
new Value(jsvalue, new Type(rtype))
diff --git a/data/shared/src/main/scala/org/ergoplatform/ErgoHeader.scala b/data/shared/src/main/scala/org/ergoplatform/ErgoHeader.scala
new file mode 100644
index 0000000000..2c6a40d46d
--- /dev/null
+++ b/data/shared/src/main/scala/org/ergoplatform/ErgoHeader.scala
@@ -0,0 +1,182 @@
+package org.ergoplatform
+
+import scorex.crypto.authds.ADDigest
+import scorex.crypto.hash.{Blake2b256, Digest32}
+import scorex.util.ModifierId
+import sigma.Colls
+import sigma.crypto.{BigIntegers, CryptoConstants, EcPointType}
+import sigma.serialization.{GroupElementSerializer, SigmaByteReader, SigmaByteWriter, SigmaSerializer}
+
+import scala.runtime.ScalaRunTime
+import scala.util.hashing.MurmurHash3
+
+
+
+/**
+ * Solution for an Autolykos PoW puzzle.
+ *
+ * In Autolykos v.1 all the four fields are used, in Autolykos v.2 only pk and n fields are used.
+ *
+ * @param pk - miner public key. Should be used to collect block rewards
+ * @param w - one-time public key. Prevents revealing of miners secret
+ * @param n - nonce (8 bytes)
+ * @param d - distance between pseudo-random number, corresponding to nonce `n` and a secret,
+ * corresponding to `pk`. The lower `d` is, the harder it was to find this solution.
+ */
+class AutolykosSolution(val pk: EcPointType,
+ val w: EcPointType,
+ val n: Array[Byte],
+ val d: BigInt) {
+
+ val encodedPk: Array[Byte] = GroupElementSerializer.toBytes(pk)
+
+ override def hashCode(): Int = {
+ var h = pk.hashCode()
+ h = h * 31 + w.hashCode()
+ h = h * 31 + MurmurHash3.arrayHash(n)
+ h = h * 31 + d.hashCode()
+ h
+ }
+
+ override def equals(obj: Any): Boolean = {
+ obj match {
+ case other: AutolykosSolution =>
+ this.pk == other.pk &&
+ this.n.sameElements(other.n) &&
+ this.w == other.w &&
+ this.d == other.d
+
+ case _ => false
+ }
+ }
+}
+
+
+object AutolykosSolution {
+ // "pk", "w" and "d" values for Autolykos v2 solution, where they not passed from outside
+ val pkForV2: EcPointType = CryptoConstants.dlogGroup.identity
+ val wForV2: EcPointType = CryptoConstants.dlogGroup.generator
+ val dForV2: BigInt = 0
+
+ object sigmaSerializerV1 extends SigmaSerializer[AutolykosSolution, AutolykosSolution] {
+ override def serialize(s: AutolykosSolution, w: SigmaByteWriter): Unit = {
+ GroupElementSerializer.serialize(s.pk, w)
+ GroupElementSerializer.serialize(s.w, w)
+ require(s.n.length == 8) // non-consensus check on prover side
+ w.putBytes(s.n)
+ val dBytes = BigIntegers.asUnsignedByteArray(s.d.bigInteger)
+ w.putUByte(dBytes.length)
+ w.putBytes(dBytes)
+ }
+
+ override def parse(r: SigmaByteReader): AutolykosSolution = {
+ val pk = GroupElementSerializer.parse(r)
+ val w = GroupElementSerializer.parse(r)
+ val nonce = r.getBytes(8)
+ val dBytesLength = r.getUByte()
+ val d = BigInt(BigIntegers.fromUnsignedByteArray(r.getBytes(dBytesLength)))
+ new AutolykosSolution(pk, w, nonce, d)
+ }
+ }
+
+ object sigmaSerializerV2 extends SigmaSerializer[AutolykosSolution, AutolykosSolution] {
+ override def serialize(s: AutolykosSolution, w: SigmaByteWriter): Unit = {
+ GroupElementSerializer.serialize(s.pk, w)
+ require(s.n.length == 8) // non-consensus check on prover side
+ w.putBytes(s.n)
+ }
+
+ override def parse(r: SigmaByteReader): AutolykosSolution = {
+ val pk = GroupElementSerializer.parse(r)
+ val nonce = r.getBytes(8)
+ new AutolykosSolution(pk, wForV2, nonce, dForV2)
+ }
+ }
+}
+
+/**
+ * Header of a block. It authenticates link to a previous block, other block sections
+ * (transactions, UTXO set transformation proofs, extension), UTXO set, votes for parameters
+ * to be changed and proof-of-work related data.
+ *
+ * @param version - protocol version
+ * @param parentId - id of a parent block header
+ * @param ADProofsRoot - digest of UTXO set transformation proofs
+ * @param stateRoot - AVL+ tree digest of UTXO set (after the block)
+ * @param transactionsRoot - Merkle tree digest of transactions in the block (BlockTransactions section)
+ * @param timestamp - block generation time reported by a miner
+ * @param nBits - difficulty encoded
+ * @param height - height of the block (genesis block height == 1)
+ * @param extensionRoot - Merkle tree digest of the extension section of the block
+ * @param powSolution - solution for the proof-of-work puzzle
+ * @param votes - votes for changing system parameters
+ * @param unparsedBytes - bytes from future versions of the protocol our version can't parse
+ * @param _bytes - serialized bytes of the header when not `null`
+ */
+case class ErgoHeader(override val version: ErgoHeader.Version,
+ override val parentId: ModifierId,
+ override val ADProofsRoot: Digest32,
+ override val stateRoot: ADDigest, //33 bytes! extra byte with tree height here!
+ override val transactionsRoot: Digest32,
+ override val timestamp: ErgoHeader.Timestamp,
+ override val nBits: Long, //actually it is unsigned int
+ override val height: Int,
+ override val extensionRoot: Digest32,
+ powSolution: AutolykosSolution,
+ override val votes: Array[Byte], //3 bytes
+ override val unparsedBytes: Array[Byte],
+ _bytes: Array[Byte]) extends
+ HeaderWithoutPow(version, parentId, ADProofsRoot, stateRoot, transactionsRoot, timestamp,
+ nBits, height, extensionRoot, votes, unparsedBytes) {
+
+ lazy val bytes = if(_bytes != null) {
+ _bytes
+ } else {
+ ErgoHeader.sigmaSerializer.toBytes(this)
+ }
+
+ lazy val serializedId: Array[Byte] = Blake2b256.hash(bytes)
+
+ lazy val id = Colls.fromArray(serializedId)
+
+ override def hashCode(): Int = id.hashCode()
+
+ override def equals(other: Any): Boolean = other match {
+ case h: ErgoHeader => h.id == this.id
+ case _ => false
+ }
+}
+
+
+object ErgoHeader {
+
+ type Timestamp = Long
+
+ type Version = Byte
+
+ object sigmaSerializer extends SigmaSerializer[ErgoHeader, ErgoHeader] {
+ override def serialize(hdr: ErgoHeader, w: SigmaByteWriter): Unit = {
+ HeaderWithoutPowSerializer.serialize(hdr, w)
+ if (hdr.version == 1) {
+ AutolykosSolution.sigmaSerializerV1.serialize(hdr.powSolution, w)
+ } else {
+ AutolykosSolution.sigmaSerializerV2.serialize(hdr.powSolution, w)
+ }
+ }
+
+ override def parse(r: SigmaByteReader): ErgoHeader = {
+ val start = r.position
+ val headerWithoutPow = HeaderWithoutPowSerializer.parse(r)
+ val powSolution = if (headerWithoutPow.version == 1) {
+ AutolykosSolution.sigmaSerializerV1.parse(r)
+ } else {
+ AutolykosSolution.sigmaSerializerV2.parse(r)
+ }
+ val end = r.position
+ val len = end - start
+ r.position = start
+ val headerBytes = r.getBytes(len) // also moves position back to end
+ headerWithoutPow.toHeader(powSolution, headerBytes)
+ }
+ }
+}
\ No newline at end of file
diff --git a/data/shared/src/main/scala/org/ergoplatform/HeaderWithoutPow.scala b/data/shared/src/main/scala/org/ergoplatform/HeaderWithoutPow.scala
new file mode 100644
index 0000000000..21a10a5036
--- /dev/null
+++ b/data/shared/src/main/scala/org/ergoplatform/HeaderWithoutPow.scala
@@ -0,0 +1,145 @@
+package org.ergoplatform
+
+import scorex.crypto.authds.ADDigest
+import scorex.crypto.hash.Digest32
+import scorex.util.{ModifierId, bytesToId, idToBytes}
+import sigma.serialization.{SigmaByteReader, SigmaByteWriter, SigmaSerializer}
+import scorex.util.Extensions._
+
+/**
+ * Header without proof-of-work puzzle solution, see Header class description for details.
+ */
+class HeaderWithoutPow(val version: Byte, // 1 byte
+ val parentId: ModifierId, // 32 bytes
+ val ADProofsRoot: Digest32, // 32 bytes
+ val stateRoot: ADDigest, //33 bytes! extra byte with tree height here!
+ val transactionsRoot: Digest32, // 32 bytes
+ val timestamp: Long,
+ val nBits: Long, //actually it is unsigned int
+ val height: Int,
+ val extensionRoot: Digest32,
+ val votes: Array[Byte], //3 bytes
+ val unparsedBytes: Array[Byte]) {
+ def toHeader(powSolution: AutolykosSolution, bytes: Array[Byte]): ErgoHeader =
+ ErgoHeader(version, parentId, ADProofsRoot, stateRoot, transactionsRoot, timestamp,
+ nBits, height, extensionRoot, powSolution, votes, unparsedBytes, bytes)
+
+ override def toString: String = {
+ s"HeaderWithoutPow($version, $parentId, ${bytesToId(ADProofsRoot)}, ${bytesToId(stateRoot)}, " +
+ s"${bytesToId(transactionsRoot)}, $timestamp, $nBits, $height, ${bytesToId(extensionRoot)}, ${bytesToId(votes)}, " +
+ s"${bytesToId(unparsedBytes)} )"
+ }
+}
+
+object HeaderWithoutPow {
+
+ def apply(version: Byte, parentId: ModifierId, ADProofsRoot: Digest32, stateRoot: ADDigest,
+ transactionsRoot: Digest32, timestamp: Long, nBits: Long, height: Int,
+ extensionRoot: Digest32, votes: Array[Byte], unparsedBytes: Array[Byte]): HeaderWithoutPow = {
+ new HeaderWithoutPow(version, parentId, ADProofsRoot, stateRoot, transactionsRoot, timestamp,
+ nBits, height, extensionRoot, votes, unparsedBytes)
+ }
+
+}
+
+object HeaderWithoutPowSerializer extends SigmaSerializer[HeaderWithoutPow, HeaderWithoutPow] {
+
+ override def serialize(h: HeaderWithoutPow, w: SigmaByteWriter): Unit = {
+ w.put(h.version)
+ w.putBytes(idToBytes(h.parentId))
+ w.putBytes(h.ADProofsRoot)
+ w.putBytes(h.transactionsRoot)
+ w.putBytes(h.stateRoot)
+ w.putULong(h.timestamp)
+ w.putBytes(h.extensionRoot)
+ DifficultySerializer.serialize(h.nBits, w)
+ w.putUInt(h.height.toLong)
+ w.putBytes(h.votes)
+
+ // For block version >= 2, this new byte encodes length of possible new fields.
+ // Set to 0 for now, so no new fields.
+ if (h.version > HeaderVersion.InitialVersion) {
+ w.putUByte(h.unparsedBytes.length)
+ w.putBytes(h.unparsedBytes)
+ }
+ }
+
+ override def parse(r: SigmaByteReader): HeaderWithoutPow = {
+ val version = r.getByte()
+ val parentId = bytesToId(r.getBytes(32))
+ val ADProofsRoot = Digest32 @@ r.getBytes(32)
+ val transactionsRoot = Digest32 @@ r.getBytes(32)
+ val stateRoot = ADDigest @@ r.getBytes(33)
+ val timestamp = r.getULong()
+ val extensionHash = Digest32 @@ r.getBytes(32)
+ val nBits = DifficultySerializer.parse(r)
+ val height = r.getUInt().toIntExact
+ val votes = r.getBytes(3)
+
+ // For block version >= 2, a new byte encodes length of possible new fields.
+ // If this byte > 0, we read new fields but do nothing, as semantics of the fields is not known.
+ val unparsedBytes = if (version > HeaderVersion.InitialVersion) {
+ val newFieldsSize = r.getUByte()
+ if (newFieldsSize > 0 && version > HeaderVersion.Interpreter60Version) {
+ // new bytes could be added only for block version >= 5
+ r.getBytes(newFieldsSize)
+ } else {
+ Array.emptyByteArray
+ }
+ } else {
+ Array.emptyByteArray
+ }
+
+ HeaderWithoutPow(version, parentId, ADProofsRoot, stateRoot, transactionsRoot, timestamp,
+ nBits, height, extensionHash, votes, unparsedBytes)
+ }
+
+}
+
+
+object DifficultySerializer extends SigmaSerializer[Long, Long] {
+
+ /** Parse 4 bytes from the byte array (starting at the offset) as unsigned 32-bit integer in big endian format. */
+ def readUint32BE(bytes: Array[Byte]): Long = ((bytes(0) & 0xffL) << 24) | ((bytes(1) & 0xffL) << 16) | ((bytes(2) & 0xffL) << 8) | (bytes(3) & 0xffL)
+
+ def uint32ToByteArrayBE(value: Long): Array[Byte] = {
+ Array(0xFF & (value >> 24), 0xFF & (value >> 16), 0xFF & (value >> 8), 0xFF & value).map(_.toByte)
+ }
+
+ override def serialize(obj: Long, w: SigmaByteWriter): Unit = {
+ w.putBytes(uint32ToByteArrayBE(obj))
+ }
+
+ override def parse(r: SigmaByteReader): Long = {
+ readUint32BE(r.getBytes(4))
+ }
+
+}
+
+object HeaderVersion {
+ type Value = Byte
+
+ /**
+ * Block version during mainnet launch
+ */
+ val InitialVersion: Value = 1.toByte
+
+ /**
+ * Block version after the Hardening hard-fork
+ * Autolykos v2 PoW, witnesses in transactions Merkle tree
+ */
+ val HardeningVersion: Value = 2.toByte
+
+ /**
+ * Block version after the 5.0 soft-fork
+ * 5.0 interpreter with JITC, monotonic height rule (EIP-39)
+ */
+ val Interpreter50Version: Value = 3.toByte
+
+ /**
+ * Block version after the 6.0 soft-fork
+ * 6.0 interpreter (EIP-50)
+ */
+ val Interpreter60Version: Value = 4.toByte
+
+}
diff --git a/data/shared/src/main/scala/sigma/SigmaDataReflection.scala b/data/shared/src/main/scala/sigma/SigmaDataReflection.scala
index 48939b1460..341ee647b3 100644
--- a/data/shared/src/main/scala/sigma/SigmaDataReflection.scala
+++ b/data/shared/src/main/scala/sigma/SigmaDataReflection.scala
@@ -86,6 +86,14 @@ object SigmaDataReflection {
)
)
+ registerClassEntry(classOf[LongToByteArray],
+ constructors = Array(
+ mkConstructor(Array(classOf[Value[_]])) { args =>
+ new LongToByteArray(args(0).asInstanceOf[Value[SLong.type]])
+ }
+ )
+ )
+
registerClassEntry(classOf[CalcBlake2b256],
constructors = Array(
mkConstructor(Array(classOf[Value[_]])) { args =>
@@ -309,6 +317,22 @@ object SigmaDataReflection {
mkMethod(clazz, "flatMap_eval", Array[Class[_]](classOf[MethodCall], classOf[Coll[_]], classOf[Function1[_,_]], classOf[ErgoTreeEvaluator])) { (obj, args) =>
obj.asInstanceOf[SCollectionMethods.type].flatMap_eval(args(0).asInstanceOf[MethodCall],
args(1).asInstanceOf[Coll[Any]], args(2).asInstanceOf[Any => Coll[Any]])(args(3).asInstanceOf[ErgoTreeEvaluator])
+ },
+ mkMethod(clazz, "reverse_eval", Array[Class[_]](classOf[MethodCall], classOf[Coll[_]], classOf[ErgoTreeEvaluator])) { (obj, args) =>
+ obj.asInstanceOf[SCollectionMethods.type].reverse_eval(args(0).asInstanceOf[MethodCall],
+ args(1).asInstanceOf[Coll[Any]])(args(2).asInstanceOf[ErgoTreeEvaluator])
+ },
+ mkMethod(clazz, "distinct_eval", Array[Class[_]](classOf[MethodCall], classOf[Coll[_]], classOf[ErgoTreeEvaluator])) { (obj, args) =>
+ obj.asInstanceOf[SCollectionMethods.type].distinct_eval(args(0).asInstanceOf[MethodCall],
+ args(1).asInstanceOf[Coll[Any]])(args(2).asInstanceOf[ErgoTreeEvaluator])
+ },
+ mkMethod(clazz, "startsWith_eval", Array[Class[_]](classOf[MethodCall], classOf[Coll[_]], classOf[Coll[_]], classOf[ErgoTreeEvaluator])) { (obj, args) =>
+ obj.asInstanceOf[SCollectionMethods.type].startsWith_eval(args(0).asInstanceOf[MethodCall],
+ args(1).asInstanceOf[Coll[Any]], args(2).asInstanceOf[Coll[Any]])(args(3).asInstanceOf[ErgoTreeEvaluator])
+ },
+ mkMethod(clazz, "endsWith_eval", Array[Class[_]](classOf[MethodCall], classOf[Coll[_]], classOf[Coll[_]], classOf[ErgoTreeEvaluator])) { (obj, args) =>
+ obj.asInstanceOf[SCollectionMethods.type].endsWith_eval(args(0).asInstanceOf[MethodCall],
+ args(1).asInstanceOf[Coll[Any]], args(2).asInstanceOf[Coll[Any]])(args(3).asInstanceOf[ErgoTreeEvaluator])
}
)
)
@@ -322,6 +346,11 @@ object SigmaDataReflection {
args(1).asInstanceOf[SigmaDslBuilder],
args(2).asInstanceOf[Coll[Byte]],
args(3).asInstanceOf[Coll[Byte]])(args(4).asInstanceOf[ErgoTreeEvaluator])
+ },
+ mkMethod(clazz, "serialize_eval", Array[Class[_]](classOf[MethodCall], classOf[SigmaDslBuilder], classOf[Object], classOf[ErgoTreeEvaluator])) { (obj, args) =>
+ obj.asInstanceOf[SGlobalMethods.type].serialize_eval(args(0).asInstanceOf[MethodCall],
+ args(1).asInstanceOf[SigmaDslBuilder],
+ args(2).asInstanceOf[SType#WrappedType])(args(3).asInstanceOf[ErgoTreeEvaluator])
}
)
)
diff --git a/data/shared/src/main/scala/sigma/ast/ErgoTree.scala b/data/shared/src/main/scala/sigma/ast/ErgoTree.scala
index d6ed6118dc..8d731e1c67 100644
--- a/data/shared/src/main/scala/sigma/ast/ErgoTree.scala
+++ b/data/shared/src/main/scala/sigma/ast/ErgoTree.scala
@@ -25,13 +25,13 @@ case class UnparsedErgoTree(bytes: mutable.WrappedArray[Byte], error: Validation
* ErgoTreeSerializer defines top-level serialization format of the scripts.
* The interpretation of the byte array depend on the first `header` byte, which uses VLQ encoding up to 30 bits.
* Currently we define meaning for only first byte, which may be extended in future versions.
- * 7 6 5 4 3 2 1 0
+ * 7 6 5 4 3 2 1 0
* -------------------------
* | | | | | | | | |
* -------------------------
* Bit 7 == 1 if the header contains more than 1 byte (default == 0)
* Bit 6 - reserved for GZIP compression (should be 0)
- * Bit 5 == 1 - reserved for context dependent costing (should be = 0)
+ * Bit 5 == 1 - reserved (should be = 0)
* Bit 4 == 1 if constant segregation is used for this ErgoTree (default = 0)
* (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/264)
* Bit 3 == 1 if size of the whole tree is serialized after the header byte (default = 0)
@@ -381,7 +381,7 @@ object ErgoTree {
* */
def withSegregation(header: HeaderType, prop: SigmaPropValue): ErgoTree = {
val constantStore = new ConstantStore()
- val w = SigmaSerializer.startWriter(constantStore)
+ val w = SigmaSerializer.startWriter(Some(constantStore))
// serialize value and segregate constants into constantStore
ValueSerializer.serialize(prop, w)
val extractedConstants = constantStore.getAll
diff --git a/data/shared/src/main/scala/sigma/ast/SMethod.scala b/data/shared/src/main/scala/sigma/ast/SMethod.scala
index 2d306d8948..e5481cee5b 100644
--- a/data/shared/src/main/scala/sigma/ast/SMethod.scala
+++ b/data/shared/src/main/scala/sigma/ast/SMethod.scala
@@ -50,17 +50,20 @@ case class MethodIRInfo(
/** Represents method descriptor.
*
- * @param objType type or type constructor descriptor
- * @param name method name
- * @param stype method signature type,
- * where `stype.tDom`` - argument type and
- * `stype.tRange` - method result type.
- * @param methodId method code, it should be unique among methods of the same objType.
- * @param costKind cost descriptor for this method
- * @param irInfo meta information connecting SMethod with ErgoTree (see [[MethodIRInfo]])
- * @param docInfo optional human readable method description data
- * @param costFunc optional specification of how the cost should be computed for the
- * given method call (See ErgoTreeEvaluator.calcCost method).
+ * @param objType type or type constructor descriptor
+ * @param name method name
+ * @param stype method signature type,
+ * where `stype.tDom`` - argument type and
+ * `stype.tRange` - method result type.
+ * @param methodId method code, it should be unique among methods of the same objType.
+ * @param costKind cost descriptor for this method
+ * @param explicitTypeArgs list of type parameters which require explicit
+ * serialization in [[MethodCall]]s (i.e for deserialize[T], getVar[T], getReg[T])
+ * @param irInfo meta information connecting SMethod with ErgoTree (see [[MethodIRInfo]])
+ * @param docInfo optional human readable method description data
+ * @param costFunc optional specification of how the cost should be computed for the
+ * given method call (See ErgoTreeEvaluator.calcCost method).
+ * @param userDefinedInvoke optional custom method evaluation function
*/
case class SMethod(
objType: MethodsContainer,
@@ -68,13 +71,21 @@ case class SMethod(
stype: SFunc,
methodId: Byte,
costKind: CostKind,
+ explicitTypeArgs: Seq[STypeVar],
irInfo: MethodIRInfo,
docInfo: Option[OperationInfo],
- costFunc: Option[MethodCostFunc]) {
+ costFunc: Option[MethodCostFunc],
+ userDefinedInvoke: Option[SMethod.InvokeHandler]
+) {
/** Operation descriptor of this method. */
lazy val opDesc = MethodDesc(this)
+ /** Return true if this method has explicit type parameters, which need to be serialized
+ * as part of [[MethodCall]].
+ */
+ def hasExplicitTypeArgs: Boolean = explicitTypeArgs.nonEmpty
+
/** Finds and keeps the [[RMethod]] instance which corresponds to this method descriptor.
* The lazy value is forced only if irInfo.javaMethod == None
*/
@@ -105,8 +116,13 @@ case class SMethod(
/** Invoke this method on the given object with the arguments.
* This is used for methods with FixedCost costKind. */
- def invokeFixed(obj: Any, args: Array[Any])(implicit E: ErgoTreeEvaluator): Any = {
- javaMethod.invoke(obj, args.asInstanceOf[Array[AnyRef]]:_*)
+ def invokeFixed(obj: Any, args: Array[Any]): Any = {
+ userDefinedInvoke match {
+ case Some(h) =>
+ h(this, obj, args)
+ case None =>
+ javaMethod.invoke(obj, args.asInstanceOf[Array[AnyRef]]:_*)
+ }
}
// TODO optimize: avoid lookup when this SMethod is created via `specializeFor`
@@ -146,6 +162,11 @@ case class SMethod(
m
}
+ /** Create a new instance with the given user-defined invoke handler. */
+ def withUserDefinedInvoke(handler: SMethod.InvokeHandler): SMethod = {
+ copy(userDefinedInvoke = Some(handler))
+ }
+
/** Create a new instance with the given stype. */
def withSType(newSType: SFunc): SMethod = copy(stype = newSType)
@@ -255,6 +276,12 @@ object SMethod {
*/
type InvokeDescBuilder = SFunc => Seq[SType]
+ /** Type of user-defined function which is called to handle method invocation.
+ * Instances of this type can be attached to [[SMethod]] instances.
+ * @see SNumericTypeMethods.ToBytesMethod
+ */
+ type InvokeHandler = (SMethod, Any, Array[Any]) => Any
+
/** Return [[Method]] descriptor for the given `methodName` on the given `cT` type.
* @param methodName the name of the method to lookup
* @param cT the class where to search the methodName
@@ -275,6 +302,18 @@ object SMethod {
(implicit cT: ClassTag[T], cA1: ClassTag[A1], cA2: ClassTag[A2]): RMethod =
RClass(cT.runtimeClass).getMethod(methodName, cA1.runtimeClass, cA2.runtimeClass)
+ /** Return [[Method]] descriptor for the given `methodName` on the given `cT` type.
+ * @param methodName the name of the method to lookup
+ * @param cT the class where to search the methodName
+ * @param cA1 the class of the method's first argument
+ * @param cA2 the class of the method's second argument
+ * @param cA3 the class of the method's third argument
+ */
+ def javaMethodOf[T, A1, A2, A3]
+ (methodName: String)
+ (implicit cT: ClassTag[T], cA1: ClassTag[A1], cA2: ClassTag[A2], cA3: ClassTag[A3]): RMethod =
+ RClass(cT.runtimeClass).getMethod(methodName, cA1.runtimeClass, cA2.runtimeClass, cA3.runtimeClass)
+
/** Default fallback method call recognizer which builds MethodCall ErgoTree nodes. */
val MethodCallIrBuilder: PartialFunction[(SigmaBuilder, SValue, SMethod, Seq[SValue], STypeSubst), SValue] = {
case (builder, obj, method, args, tparamSubst) =>
@@ -284,10 +323,12 @@ object SMethod {
/** Convenience factory method. */
def apply(objType: MethodsContainer, name: String, stype: SFunc,
methodId: Byte,
- costKind: CostKind): SMethod = {
+ costKind: CostKind,
+ explicitTypeArgs: Seq[STypeVar] = Nil
+ ): SMethod = {
SMethod(
- objType, name, stype, methodId, costKind,
- MethodIRInfo(None, None, None), None, None)
+ objType, name, stype, methodId, costKind, explicitTypeArgs,
+ MethodIRInfo(None, None, None), None, None, None)
}
diff --git a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala
index 5cdbdedaa8..4f18c170fd 100644
--- a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala
+++ b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala
@@ -5,13 +5,14 @@ import org.ergoplatform.{ErgoAddressEncoder, P2PKAddress}
import scorex.util.encode.{Base16, Base58, Base64}
import sigma.ast.SCollection.{SByteArray, SIntArray}
import sigma.ast.SOption.SIntOption
-import sigma.ast.SigmaPropConstant
import sigma.ast.syntax._
import sigma.data.Nullable
import sigma.exceptions.InvalidArguments
import sigma.serialization.CoreByteWriter.ArgInfo
import sigma.serialization.ValueSerializer
+import java.math.BigInteger
+
object SigmaPredef {
type IrBuilderFunc = PartialFunction[(SValue, Seq[SValue]), SValue]
@@ -145,6 +146,18 @@ object SigmaPredef {
Seq(ArgInfo("varId", "\\lst{Byte} identifier of context variable")))
)
+ val GetVarFromInputFunc = PredefinedFunc("getVarFromInput",
+ Lambda(Array(paramT), Array("inputId" -> SShort, "varId" -> SByte), SOption(tT), None),
+ PredefFuncInfo(
+ { case (Ident(_, SFunc(_, SOption(rtpe), _)), Seq(inputId: Constant[SNumericType]@unchecked, varId: Constant[SNumericType]@unchecked)) =>
+ mkMethodCall(Context, SContextMethods.getVarFromInputMethod, IndexedSeq(SShort.downcast(inputId.value.asInstanceOf[AnyVal]), SByte.downcast(varId.value.asInstanceOf[AnyVal])), Map(tT -> rtpe))
+ }),
+ OperationInfo(MethodCall,
+ "Get context variable with given \\lst{varId} and type.",
+ Seq(ArgInfo("inputId", "\\lst{Byte} index of input to read context variable from"),
+ ArgInfo("varId", "\\lst{Byte} identifier of context variable")))
+ )
+
def PKFunc(networkPrefix: NetworkPrefix) = PredefinedFunc("PK",
Lambda(Array("input" -> SString), SSigmaProp, None),
PredefFuncInfo(
@@ -179,6 +192,17 @@ object SigmaPredef {
Seq(ArgInfo("", "")))
)
+ val BigIntFromStringFunc = PredefinedFunc("bigInt",
+ Lambda(Array("input" -> SString), SBigInt, None),
+ PredefFuncInfo(
+ { case (_, Seq(arg: EvaluatedValue[SString.type]@unchecked)) =>
+ BigIntConstant(new BigInteger(arg.value))
+ }),
+ OperationInfo(Constant,
+ """Parsing string literal argument as a 256-bit signed big integer.""".stripMargin,
+ Seq(ArgInfo("", "")))
+ )
+
val FromBase16Func = PredefinedFunc("fromBase16",
Lambda(Array("input" -> SString), SByteArray, None),
PredefFuncInfo(
@@ -390,6 +414,43 @@ object SigmaPredef {
ArgInfo("default", "optional default value, if register is not available")))
)
+ val SerializeFunc = PredefinedFunc("serialize",
+ Lambda(Seq(paramT), Array("value" -> tT), SByteArray, None),
+ irInfo = PredefFuncInfo(
+ irBuilder = { case (_, args @ Seq(value)) =>
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ Global,
+ SGlobalMethods.serializeMethod.withConcreteTypes(Map(tT -> value.tpe)),
+ args.toIndexedSeq,
+ Map()
+ )
+ }),
+ docInfo = OperationInfo(MethodCall,
+ """Serializes the given `value` into bytes using the default serialization format.
+ """.stripMargin,
+ Seq(ArgInfo("value", "value to serialize"))
+ )
+ )
+
+ val FromBigEndianBytesFunc = PredefinedFunc("fromBigEndianBytes",
+ Lambda(Seq(paramT), Array("bytes" -> SByteArray), tT, None),
+ irInfo = PredefFuncInfo(
+ irBuilder = { case (u, args) =>
+ val resType = u.opType.tRange.asInstanceOf[SFunc].tRange
+ MethodCall(
+ Global,
+ SGlobalMethods.fromBigEndianBytesMethod.withConcreteTypes(Map(tT -> resType)),
+ args.toIndexedSeq,
+ Map(tT -> resType)
+ )
+ }),
+ docInfo = OperationInfo(MethodCall,
+ """Deserializes provided big endian bytes into a numeric value of given type.
+ """.stripMargin,
+ Seq(ArgInfo("bytes", "bytes to deserialize"))
+ )
+ )
+
val globalFuncs: Map[String, PredefinedFunc] = Seq(
AllOfFunc,
AnyOfFunc,
@@ -402,6 +463,7 @@ object SigmaPredef {
SigmaPropFunc,
GetVarFunc,
DeserializeFunc,
+ BigIntFromStringFunc,
FromBase16Func,
FromBase64Func,
FromBase58Func,
@@ -416,7 +478,10 @@ object SigmaPredef {
AvlTreeFunc,
SubstConstantsFunc,
ExecuteFromVarFunc,
- ExecuteFromSelfRegFunc
+ ExecuteFromSelfRegFunc,
+ SerializeFunc,
+ GetVarFromInputFunc,
+ FromBigEndianBytesFunc
).map(f => f.name -> f).toMap
def comparisonOp(symbolName: String, opDesc: ValueCompanion, desc: String, args: Seq[ArgInfo]) = {
@@ -530,7 +595,7 @@ object SigmaPredef {
val funcs: Map[String, PredefinedFunc] = globalFuncs ++ infixFuncs ++ unaryFuncs
- /** WARNING: This operations are not used in frontend, and should be be used.
+ /** WARNING: This operations are not used in frontend, and should not be used.
* They are used in SpecGen only the source of metadata for the corresponding ErgoTree nodes.
*/
val specialFuncs: Map[String, PredefinedFunc] = Seq(
@@ -591,7 +656,7 @@ object SigmaPredef {
).map(f => f.name -> f).toMap
private val funcNameToIrBuilderMap: Map[String, PredefinedFunc] =
- funcs.filter { case (n, f) => f.irInfo.irBuilder != undefined }
+ funcs.filter { case (_, f) => f.irInfo.irBuilder != undefined }
def irBuilderForFunc(name: String): Option[IrBuilderFunc] = funcNameToIrBuilderMap.get(name).map(_.irInfo.irBuilder)
}
diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala
index b637acf792..4cba72e28d 100644
--- a/data/shared/src/main/scala/sigma/ast/methods.scala
+++ b/data/shared/src/main/scala/sigma/ast/methods.scala
@@ -2,20 +2,23 @@ package sigma.ast
import org.ergoplatform._
import org.ergoplatform.validation._
+import sigma.Evaluation.stypeToRType
import sigma._
import sigma.ast.SCollection.{SBooleanArray, SBoxArray, SByteArray, SByteArray2, SHeaderArray}
import sigma.ast.SMethod.{MethodCallIrBuilder, MethodCostFunc, javaMethodOf}
-import sigma.ast.SType.TypeCode
+import sigma.ast.SType.{TypeCode, paramT, tT}
import sigma.ast.syntax.{SValue, ValueOps}
+import sigma.data.ExactIntegral.{ByteIsExactIntegral, IntIsExactIntegral, LongIsExactIntegral, ShortIsExactIntegral}
+import sigma.data.NumericOps.BigIntIsExactIntegral
import sigma.data.OverloadHack.Overloaded1
import sigma.data.{DataValueComparer, KeyValueColl, Nullable, RType, SigmaConstants}
import sigma.eval.{CostDetails, ErgoTreeEvaluator, TracedCost}
import sigma.reflection.RClass
import sigma.serialization.CoreByteWriter.ArgInfo
+import sigma.serialization.{DataSerializer, SigmaByteWriter, SigmaSerializer}
import sigma.utils.SparseArrayContainer
import scala.annotation.unused
-import scala.language.implicitConversions
/** Base type for all companions of AST nodes of sigma lang. */
trait SigmaNodeCompanion
@@ -53,7 +56,7 @@ sealed trait MethodsContainer {
protected def getMethods(): Seq[SMethod] = Nil
/** Returns all the methods of this type. */
- lazy val methods: Seq[SMethod] = {
+ def methods: Seq[SMethod] = { //todo: consider versioned caching
val ms = getMethods().toArray
assert(ms.map(_.name).distinct.length == ms.length, s"Duplicate method names in $this")
ms.groupBy(_.objType).foreach { case (comp, ms) =>
@@ -61,7 +64,7 @@ sealed trait MethodsContainer {
}
ms
}
- private lazy val _methodsMap: Map[Byte, Map[Byte, SMethod]] = methods
+ private def _methodsMap: Map[Byte, Map[Byte, SMethod]] = methods //todo: consider versioned caching
.groupBy(_.objType.typeId)
.map { case (typeId, ms) => (typeId -> ms.map(m => m.methodId -> m).toMap) }
@@ -157,14 +160,34 @@ trait MonoTypeMethods extends MethodsContainer {
trait SNumericTypeMethods extends MonoTypeMethods {
import SNumericTypeMethods.tNum
+
+ private val subst = Map(tNum -> this.ownerType)
+
+ val v5Methods = {
+ SNumericTypeMethods.v5Methods.map { m =>
+ m.copy(stype = applySubst(m.stype, subst).asFunc)
+ }
+ }
+
+ val v6Methods = {
+ SNumericTypeMethods.v6Methods.map { m =>
+ m.copy(
+ objType = this, // associate the method with the concrete numeric type
+ stype = applySubst(m.stype, subst).asFunc
+ )}
+ }
+
protected override def getMethods(): Seq[SMethod] = {
- super.getMethods() ++ SNumericTypeMethods.methods.map {
- m => m.copy(stype = applySubst(m.stype, Map(tNum -> this.ownerType)).asFunc)
+ if (VersionContext.current.isV6SoftForkActivated) {
+ super.getMethods() ++ v6Methods
+ } else {
+ super.getMethods() ++ v5Methods
}
}
}
object SNumericTypeMethods extends MethodsContainer {
+
/** Type for which this container defines methods. */
override def ownerType: STypeCompanion = SNumericType
@@ -217,6 +240,15 @@ object SNumericTypeMethods extends MethodsContainer {
val ToBytesMethod: SMethod = SMethod(
this, "toBytes", SFunc(tNum, SByteArray), 6, ToBytes_CostKind)
.withIRInfo(MethodCallIrBuilder)
+ .withUserDefinedInvoke({ (m: SMethod, obj: Any, _: Array[Any]) =>
+ m.objType match {
+ case SByteMethods => ByteIsExactIntegral.toBigEndianBytes(obj.asInstanceOf[Byte])
+ case SShortMethods => ShortIsExactIntegral.toBigEndianBytes(obj.asInstanceOf[Short])
+ case SIntMethods => IntIsExactIntegral.toBigEndianBytes(obj.asInstanceOf[Int])
+ case SLongMethods => LongIsExactIntegral.toBigEndianBytes(obj.asInstanceOf[Long])
+ case SBigIntMethods => obj.asInstanceOf[BigInt].toBytes
+ }
+ })
.withInfo(PropertyCall,
""" Returns a big-endian representation of this numeric value in a collection of bytes.
| For example, the \lst{Int} value \lst{0x12131415} would yield the
@@ -230,12 +262,124 @@ object SNumericTypeMethods extends MethodsContainer {
val ToBitsMethod: SMethod = SMethod(
this, "toBits", SFunc(tNum, SBooleanArray), 7, ToBits_CostKind)
.withIRInfo(MethodCallIrBuilder)
+ .withUserDefinedInvoke({ (m: SMethod, obj: Any, _: Array[Any]) =>
+ m.objType match {
+ case SByteMethods => ByteIsExactIntegral.toBits(obj.asInstanceOf[Byte])
+ case SShortMethods => ShortIsExactIntegral.toBits(obj.asInstanceOf[Short])
+ case SIntMethods => IntIsExactIntegral.toBits(obj.asInstanceOf[Int])
+ case SLongMethods => LongIsExactIntegral.toBits(obj.asInstanceOf[Long])
+ case SBigIntMethods => BigIntIsExactIntegral.toBits(obj.asInstanceOf[BigInt])
+ }
+ })
.withInfo(PropertyCall,
""" Returns a big-endian representation of this numeric in a collection of Booleans.
| Each boolean corresponds to one bit.
""".stripMargin)
- protected override def getMethods: Seq[SMethod] = Array(
+ /** Cost of inverting bits of a number. */
+ val BitwiseOp_CostKind = FixedCost(JitCost(5))
+
+ val BitwiseInverseMethod: SMethod = SMethod(
+ this, "bitwiseInverse", SFunc(tNum, tNum), 8, BitwiseOp_CostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withUserDefinedInvoke({ (m: SMethod, obj: Any, _: Array[Any]) =>
+ m.objType match {
+ case SByteMethods => ByteIsExactIntegral.bitwiseInverse(obj.asInstanceOf[Byte])
+ case SShortMethods => ShortIsExactIntegral.bitwiseInverse(obj.asInstanceOf[Short])
+ case SIntMethods => IntIsExactIntegral.bitwiseInverse(obj.asInstanceOf[Int])
+ case SLongMethods => LongIsExactIntegral.bitwiseInverse(obj.asInstanceOf[Long])
+ case SBigIntMethods => BigIntIsExactIntegral.bitwiseInverse(obj.asInstanceOf[BigInt])
+ }
+ })
+ .withInfo(PropertyCall, desc = "Returns bitwise inverse of this numeric. ")
+
+ val BitwiseOrMethod: SMethod = SMethod(
+ this, "bitwiseOr", SFunc(Array(tNum, tNum), tNum), 9, BitwiseOp_CostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withUserDefinedInvoke({ (m: SMethod, obj: Any, other: Array[Any]) =>
+ m.objType match {
+ case SByteMethods => ByteIsExactIntegral.bitwiseOr(obj.asInstanceOf[Byte], other.head.asInstanceOf[Byte])
+ case SShortMethods => ShortIsExactIntegral.bitwiseOr(obj.asInstanceOf[Short], other.head.asInstanceOf[Short])
+ case SIntMethods => IntIsExactIntegral.bitwiseOr(obj.asInstanceOf[Int], other.head.asInstanceOf[Int])
+ case SLongMethods => LongIsExactIntegral.bitwiseOr(obj.asInstanceOf[Long], other.head.asInstanceOf[Long])
+ case SBigIntMethods => BigIntIsExactIntegral.bitwiseOr(obj.asInstanceOf[BigInt], other.head.asInstanceOf[BigInt])
+ }
+ })
+ .withInfo(MethodCall,
+ """ Returns bitwise or of this numeric and provided one. """.stripMargin,
+ ArgInfo("that", "A numeric value to calculate or with."))
+
+ val BitwiseAndMethod: SMethod = SMethod(
+ this, "bitwiseAnd", SFunc(Array(tNum, tNum), tNum), 10, BitwiseOp_CostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withUserDefinedInvoke({ (m: SMethod, obj: Any, other: Array[Any]) =>
+ m.objType match {
+ case SByteMethods => ByteIsExactIntegral.bitwiseAnd(obj.asInstanceOf[Byte], other.head.asInstanceOf[Byte])
+ case SShortMethods => ShortIsExactIntegral.bitwiseAnd(obj.asInstanceOf[Short], other.head.asInstanceOf[Short])
+ case SIntMethods => IntIsExactIntegral.bitwiseAnd(obj.asInstanceOf[Int], other.head.asInstanceOf[Int])
+ case SLongMethods => LongIsExactIntegral.bitwiseAnd(obj.asInstanceOf[Long], other.head.asInstanceOf[Long])
+ case SBigIntMethods => BigIntIsExactIntegral.bitwiseAnd(obj.asInstanceOf[BigInt], other.head.asInstanceOf[BigInt])
+ }
+ })
+ .withInfo(MethodCall,
+ """ Returns bitwise and of this numeric and provided one. """.stripMargin,
+ ArgInfo("that", "A numeric value to calculate and with."))
+
+ val BitwiseXorMethod: SMethod = SMethod(
+ this, "bitwiseXor", SFunc(Array(tNum, tNum), tNum), 11, BitwiseOp_CostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withUserDefinedInvoke({ (m: SMethod, obj: Any, other: Array[Any]) =>
+ m.objType match {
+ case SByteMethods => ByteIsExactIntegral.bitwiseXor(obj.asInstanceOf[Byte], other.head.asInstanceOf[Byte])
+ case SShortMethods => ShortIsExactIntegral.bitwiseXor(obj.asInstanceOf[Short], other.head.asInstanceOf[Short])
+ case SIntMethods => IntIsExactIntegral.bitwiseXor(obj.asInstanceOf[Int], other.head.asInstanceOf[Int])
+ case SLongMethods => LongIsExactIntegral.bitwiseXor(obj.asInstanceOf[Long], other.head.asInstanceOf[Long])
+ case SBigIntMethods => BigIntIsExactIntegral.bitwiseXor(obj.asInstanceOf[BigInt], other.head.asInstanceOf[BigInt])
+ }
+ })
+ .withInfo(MethodCall,
+ """ Returns bitwise xor of this numeric and provided one. """.stripMargin,
+ ArgInfo("that", "A numeric value to calculate xor with."))
+
+ val ShiftLeftMethod: SMethod = SMethod(
+ this, "shiftLeft", SFunc(Array(tNum, SInt), tNum), 12, BitwiseOp_CostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withUserDefinedInvoke({ (m: SMethod, obj: Any, other: Array[Any]) =>
+ m.objType match {
+ case SByteMethods => ByteIsExactIntegral.shiftLeft(obj.asInstanceOf[Byte], other.head.asInstanceOf[Int])
+ case SShortMethods => ShortIsExactIntegral.shiftLeft(obj.asInstanceOf[Short], other.head.asInstanceOf[Int])
+ case SIntMethods => IntIsExactIntegral.shiftLeft(obj.asInstanceOf[Int], other.head.asInstanceOf[Int])
+ case SLongMethods => LongIsExactIntegral.shiftLeft(obj.asInstanceOf[Long], other.head.asInstanceOf[Int])
+ case SBigIntMethods => BigIntIsExactIntegral.shiftLeft(obj.asInstanceOf[BigInt], other.head.asInstanceOf[Int])
+ }
+ })
+ .withInfo(MethodCall,
+ """ Returns a big-endian representation of this numeric in a collection of Booleans.
+ | Each boolean corresponds to one bit.
+ """.stripMargin,
+ ArgInfo("bits", "Number of bit to shift to the left. Note, that bits value must be non-negative and less than " +
+ "the size of the number in bits (e.g. 64 for Long, 256 for BigInt)"))
+
+ val ShiftRightMethod: SMethod = SMethod(
+ this, "shiftRight", SFunc(Array(tNum, SInt), tNum), 13, BitwiseOp_CostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withUserDefinedInvoke({ (m: SMethod, obj: Any, other: Array[Any]) =>
+ m.objType match {
+ case SByteMethods => ByteIsExactIntegral.shiftRight(obj.asInstanceOf[Byte], other.head.asInstanceOf[Int])
+ case SShortMethods => ShortIsExactIntegral.shiftRight(obj.asInstanceOf[Short], other.head.asInstanceOf[Int])
+ case SIntMethods => IntIsExactIntegral.shiftRight(obj.asInstanceOf[Int], other.head.asInstanceOf[Int])
+ case SLongMethods => LongIsExactIntegral.shiftRight(obj.asInstanceOf[Long], other.head.asInstanceOf[Int])
+ case SBigIntMethods => BigIntIsExactIntegral.shiftRight(obj.asInstanceOf[BigInt], other.head.asInstanceOf[Int])
+ }
+ })
+ .withInfo(MethodCall,
+ """ Returns a big-endian representation of this numeric in a collection of Booleans.
+ | Each boolean corresponds to one bit.
+ """.stripMargin,
+ ArgInfo("bits", "Number of bit to shift to the right. Note, that bits value must be non-negative and less than " +
+ "the size of the number in bits (e.g. 64 for Long, 256 for BigInt)"))
+
+ lazy val v5Methods = Array(
ToByteMethod, // see Downcast
ToShortMethod, // see Downcast
ToIntMethod, // see Downcast
@@ -245,7 +389,21 @@ object SNumericTypeMethods extends MethodsContainer {
ToBitsMethod
)
+ lazy val v6Methods = v5Methods ++ Array(
+ BitwiseInverseMethod,
+ BitwiseOrMethod,
+ BitwiseAndMethod,
+ BitwiseXorMethod,
+ ShiftLeftMethod,
+ ShiftRightMethod
+ )
+
+ protected override def getMethods(): Seq[SMethod] = {
+ throw new Exception("SNumericTypeMethods.getMethods shouldn't ever be called")
+ }
+
/** Collection of names of numeric casting methods (like `toByte`, `toInt`, etc). */
+ // todo: add unsigned big int
val castMethods: Array[String] =
Array(ToByteMethod, ToShortMethod, ToIntMethod, ToLongMethod, ToBigIntMethod)
.map(_.name)
@@ -310,28 +468,19 @@ case object SBigIntMethods extends SNumericTypeMethods {
/** Type for which this container defines methods. */
override def ownerType: SMonoType = SBigInt
- /** The following `modQ` methods are not fully implemented in v4.x and this descriptors.
- * This descritors are remain here in the code and are waiting for full implementation
- * is upcoming soft-forks at which point the cost parameters should be calculated and
- * changed.
- */
- val ModQMethod = SMethod(this, "modQ", SFunc(this.ownerType, SBigInt), 1, FixedCost(JitCost(1)))
- .withInfo(ModQ, "Returns this \\lst{mod} Q, i.e. remainder of division by Q, where Q is an order of the cryprographic group.")
- val PlusModQMethod = SMethod(this, "plusModQ", SFunc(IndexedSeq(this.ownerType, SBigInt), SBigInt), 2, FixedCost(JitCost(1)))
- .withInfo(ModQArithOp.PlusModQ, "Adds this number with \\lst{other} by module Q.", ArgInfo("other", "Number to add to this."))
- val MinusModQMethod = SMethod(this, "minusModQ", SFunc(IndexedSeq(this.ownerType, SBigInt), SBigInt), 3, FixedCost(JitCost(1)))
- .withInfo(ModQArithOp.MinusModQ, "Subtracts \\lst{other} number from this by module Q.", ArgInfo("other", "Number to subtract from this."))
- val MultModQMethod = SMethod(this, "multModQ", SFunc(IndexedSeq(this.ownerType, SBigInt), SBigInt), 4, FixedCost(JitCost(1)))
- .withIRInfo(MethodCallIrBuilder)
- .withInfo(MethodCall, "Multiply this number with \\lst{other} by module Q.", ArgInfo("other", "Number to multiply with this."))
+ protected override def getMethods(): Seq[SMethod] = {
+ if (VersionContext.current.isV6SoftForkActivated) {
+ super.getMethods()
+ // ModQMethod,
+ // PlusModQMethod,
+ // MinusModQMethod,
+ // TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
+ // MultModQMethod,
+ } else {
+ super.getMethods()
+ }
+ }
- protected override def getMethods() = super.getMethods() ++ Seq(
-// ModQMethod,
-// PlusModQMethod,
-// MinusModQMethod,
- // TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
- // MultModQMethod,
- )
}
/** Methods of type `String`. */
@@ -720,7 +869,7 @@ object SCollectionMethods extends MethodsContainer with MethodByNameUnapply {
* of flatMap. Other bodies are rejected with throwing exception.
*/
val flatMap_BodyPatterns = Array[PartialFunction[SValue, Int]](
- { case MethodCall(ValUse(id, tpe), m, args, _) if args.isEmpty => id },
+ { case MethodCall(ValUse(id, _), _, args, _) if args.isEmpty => id },
{ case ExtractScriptBytes(ValUse(id, _)) => id },
{ case ExtractId(ValUse(id, _)) => id },
{ case SigmaPropBytes(ValUse(id, _)) => id },
@@ -766,7 +915,7 @@ object SCollectionMethods extends MethodsContainer with MethodByNameUnapply {
var res: Nullable[(Int, SValue)] = Nullable.None
E.addFixedCost(MatchSingleArgMethodCall_Info) {
res = mc match {
- case MethodCall(_, m, Seq(FuncValue(args, body)), _) if args.length == 1 =>
+ case MethodCall(_, _, Seq(FuncValue(args, body)), _) if args.length == 1 =>
val id = args(0)._1
Nullable((id, body))
case _ =>
@@ -871,7 +1020,7 @@ object SCollectionMethods extends MethodsContainer with MethodByNameUnapply {
SFunc(Array(ThisType, tIV, SInt), SInt, paramIVSeq),
26, PerItemCost(baseCost = JitCost(20), perChunkCost = JitCost(10), chunkSize = 2))
.withIRInfo(MethodCallIrBuilder, javaMethodOf[Coll[_], Any, Int]("indexOf"))
- .withInfo(MethodCall, "")
+ .withInfo(MethodCall, "Returns index of a collection element, or -1 if not found")
/** Implements evaluation of Coll.indexOf method call ErgoTree node.
* Called via reflection based on naming convention.
@@ -903,8 +1052,7 @@ object SCollectionMethods extends MethodsContainer with MethodByNameUnapply {
baseCost = JitCost(10), perChunkCost = JitCost(1), chunkSize = 10)
val ZipMethod = SMethod(this, "zip",
- SFunc(Array(ThisType, tOVColl), SCollection(STuple(tIV, tOV)), Array[STypeParam](tIV, tOV)),
- 29, Zip_CostKind)
+ SFunc(Array(ThisType, tOVColl), SCollection(STuple(tIV, tOV)), Array[STypeParam](tIV, tOV)), 29, Zip_CostKind)
.withIRInfo(MethodCallIrBuilder)
.withInfo(MethodCall, "")
@@ -920,29 +1068,133 @@ object SCollectionMethods extends MethodsContainer with MethodByNameUnapply {
}
}
+ // ======== 6.0 methods below ===========
+
+ private val reverseCostKind = Append.costKind
+
+ val ReverseMethod = SMethod(this, "reverse",
+ SFunc(Array(ThisType), ThisType, paramIVSeq), 30, reverseCostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall, "")
+
+ /** Implements evaluation of Coll.reverse method call ErgoTree node.
+ * Called via reflection based on naming convention.
+ * @see SMethod.evalMethod
+ */
+ def reverse_eval[A](mc: MethodCall, xs: Coll[A])
+ (implicit E: ErgoTreeEvaluator): Coll[A] = {
+ val m = mc.method
+ E.addSeqCost(m.costKind.asInstanceOf[PerItemCost], xs.length, m.opDesc) { () =>
+ xs.reverse
+ }
+ }
+
+ private val distinctCostKind = PerItemCost(baseCost = JitCost(60), perChunkCost = JitCost(5), chunkSize = 100)
+
+ val DistinctMethod = SMethod(this, "distinct",
+ SFunc(Array(ThisType), ThisType, paramIVSeq), 31, distinctCostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall, "Returns inversed collection.")
+
+ /** Implements evaluation of Coll.reverse method call ErgoTree node.
+ * Called via reflection based on naming convention.
+ * @see SMethod.evalMethod
+ */
+ def distinct_eval[A](mc: MethodCall, xs: Coll[A])
+ (implicit E: ErgoTreeEvaluator): Coll[A] = {
+ val m = mc.method
+ E.addSeqCost(m.costKind.asInstanceOf[PerItemCost], xs.length, m.opDesc) { () =>
+ xs.distinct
+ }
+ }
+
+ private val startsWithCostKind = Zip_CostKind
+
+ val StartsWithMethod = SMethod(this, "startsWith",
+ SFunc(Array(ThisType, ThisType), SBoolean, paramIVSeq), 32, startsWithCostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall, "Returns true if this collection starts with given one, false otherwise.",
+ ArgInfo("prefix", "Collection to be checked for being a prefix of this collection."))
+
+ /** Implements evaluation of Coll.zip method call ErgoTree node.
+ * Called via reflection based on naming convention.
+ * @see SMethod.evalMethod
+ */
+ def startsWith_eval[A](mc: MethodCall, xs: Coll[A], ys: Coll[A])
+ (implicit E: ErgoTreeEvaluator): Boolean = {
+ val m = mc.method
+ E.addSeqCost(m.costKind.asInstanceOf[PerItemCost], xs.length, m.opDesc) { () =>
+ xs.startsWith(ys)
+ }
+ }
+
+ private val endsWithCostKind = Zip_CostKind
+
+ val EndsWithMethod = SMethod(this, "endsWith",
+ SFunc(Array(ThisType, ThisType), SBoolean, paramIVSeq), 33, endsWithCostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall, "Returns true if this collection ends with given one, false otherwise.",
+ ArgInfo("suffix", "Collection to be checked for being a suffix of this collection."))
+
+ /** Implements evaluation of Coll.zip method call ErgoTree node.
+ * Called via reflection based on naming convention.
+ * @see SMethod.evalMethod
+ */
+ def endsWith_eval[A](mc: MethodCall, xs: Coll[A], ys: Coll[A])
+ (implicit E: ErgoTreeEvaluator): Boolean = {
+ val m = mc.method
+ E.addSeqCost(m.costKind.asInstanceOf[PerItemCost], xs.length, m.opDesc) { () =>
+ xs.endsWith(ys)
+ }
+ }
+
+ val GetMethod = SMethod(this, "get",
+ SFunc(Array(ThisType, SInt), SOption(tIV), Array[STypeParam](tIV)), 34, ByIndex.costKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall,
+ "Returns Some(element) if there is an element at given index, None otherwise.",
+ ArgInfo("index", "Index of an element (starting from 0).")
+ )
+
+ private val v5Methods = super.getMethods() ++ Seq(
+ SizeMethod,
+ GetOrElseMethod,
+ MapMethod,
+ ExistsMethod,
+ FoldMethod,
+ ForallMethod,
+ SliceMethod,
+ FilterMethod,
+ AppendMethod,
+ ApplyMethod,
+ IndicesMethod,
+ FlatMapMethod,
+ PatchMethod,
+ UpdatedMethod,
+ UpdateManyMethod,
+ IndexOfMethod,
+ ZipMethod
+ )
+
+ private val v6Methods = v5Methods ++ Seq(
+ ReverseMethod,
+ DistinctMethod,
+ StartsWithMethod,
+ EndsWithMethod,
+ GetMethod
+ )
+
/** This method should be overriden in derived classes to add new methods in addition to inherited.
* Typical override: `super.getMethods() ++ Seq(m1, m2, m3)`
*/
- override protected def getMethods(): Seq[SMethod] = super.getMethods() ++
- Seq(
- SizeMethod,
- GetOrElseMethod,
- MapMethod,
- ExistsMethod,
- FoldMethod,
- ForallMethod,
- SliceMethod,
- FilterMethod,
- AppendMethod,
- ApplyMethod,
- IndicesMethod,
- FlatMapMethod,
- PatchMethod,
- UpdatedMethod,
- UpdateManyMethod,
- IndexOfMethod,
- ZipMethod
- )
+ override protected def getMethods(): Seq[SMethod] = {
+ if (VersionContext.current.isV6SoftForkActivated) {
+ v6Methods
+ } else {
+ v5Methods
+ }
+ }
+
}
object STupleMethods extends MethodsContainer {
@@ -1044,7 +1296,7 @@ case object SBoxMethods extends MonoTypeMethods {
| identifier followed by box index in the transaction outputs.
""".stripMargin ) // see ExtractCreationInfo
- lazy val getRegMethod = SMethod(this, "getReg",
+ lazy val getRegMethodV5 = SMethod(this, "getReg",
SFunc(Array(SBox, SInt), SOption(tT), Array(paramT)), 7, ExtractRegisterAs.costKind)
.withInfo(ExtractRegisterAs,
""" Extracts register by id and type.
@@ -1053,23 +1305,49 @@ case object SBoxMethods extends MonoTypeMethods {
""".stripMargin,
ArgInfo("regId", "zero-based identifier of the register."))
+ lazy val getRegMethodV6 = SMethod(this, "getReg",
+ SFunc(Array(SBox, SInt), SOption(tT), Array(paramT)), 7, ExtractRegisterAs.costKind, Seq(tT))
+ .withIRInfo(MethodCallIrBuilder,
+ javaMethodOf[Box, Int, RType[_]]("getReg"),
+ { mtype => Array(mtype.tRange.asOption[SType].elemType) })
+ .withInfo(MethodCall, """ Extracts register by id and type.
+ | Type param \lst{T} expected type of the register.
+ | Returns \lst{Some(value)} if the register is defined and has given type and \lst{None} otherwise
+ """.stripMargin,
+ ArgInfo("regId", "zero-based identifier of the register."))
+
lazy val tokensMethod = SMethod(
this, "tokens", SFunc(SBox, ErgoBox.STokensRegType), 8, FixedCost(JitCost(15)))
.withIRInfo(MethodCallIrBuilder)
.withInfo(PropertyCall, "Secondary tokens")
-
- // should be lazy to solve recursive initialization
- protected override def getMethods() = super.getMethods() ++ Array(
+ lazy val commonBoxMethods = super.getMethods() ++ Array(
ValueMethod, // see ExtractAmount
PropositionBytesMethod, // see ExtractScriptBytes
BytesMethod, // see ExtractBytes
BytesWithoutRefMethod, // see ExtractBytesWithNoRef
IdMethod, // see ExtractId
creationInfoMethod,
- getRegMethod,
tokensMethod
) ++ registers(8)
+
+ lazy val v5Methods = commonBoxMethods ++ Array(
+ getRegMethodV5
+ )
+
+ lazy val v6Methods = commonBoxMethods ++ Array(
+ getRegMethodV6
+ )
+
+ // should be lazy to solve recursive initialization
+ protected override def getMethods() = {
+ if (VersionContext.current.isV6SoftForkActivated) {
+ v6Methods
+ } else {
+ v5Methods
+ }
+ }
+
}
/** Type descriptor of `AvlTree` type of ErgoTree. */
@@ -1399,16 +1677,52 @@ case object SContextMethods extends MonoTypeMethods {
lazy val selfBoxIndexMethod = propertyCall("selfBoxIndex", SInt, 8, FixedCost(JitCost(20)))
lazy val lastBlockUtxoRootHashMethod = property("LastBlockUtxoRootHash", SAvlTree, 9, LastBlockUtxoRootHash)
lazy val minerPubKeyMethod = property("minerPubKey", SByteArray, 10, MinerPubkey)
- lazy val getVarMethod = SMethod(
+
+ lazy val getVarV5Method = SMethod(
this, "getVar", SFunc(ContextFuncDom, SOption(tT), Array(paramT)), 11, GetVar.costKind)
.withInfo(GetVar, "Get context variable with given \\lst{varId} and type.",
ArgInfo("varId", "\\lst{Byte} identifier of context variable"))
- protected override def getMethods() = super.getMethods() ++ Seq(
+ lazy val getVarV6Method = SMethod(
+ this, "getVar", SFunc(ContextFuncDom, SOption(tT), Array(paramT)), 11, GetVar.costKind, Seq(tT))
+ .withIRInfo(
+ MethodCallIrBuilder,
+ javaMethodOf[Context, Byte, RType[_]]("getVar"),
+ { mtype => Array(mtype.tRange.asOption[SType].elemType) })
+ .withInfo(MethodCall, "Get context variable with given \\lst{varId} and type.")
+
+ lazy val getVarFromInputMethod = SMethod(
+ this, "getVarFromInput", SFunc(Array(SContext, SShort, SByte), SOption(tT), Array(paramT)), 12, GetVar.costKind, Seq(tT))
+ .withIRInfo(
+ MethodCallIrBuilder,
+ javaMethodOf[Context, Short, Byte, RType[_]]("getVarFromInput"),
+ { mtype => Array(mtype.tRange.asOption[SType].elemType) })
+ .withInfo(MethodCall, "Get context variable with given \\lst{varId} and type.",
+ ArgInfo("inputIdx", "Index of input to read variable from."),
+ ArgInfo("varId", "Index of variable.")
+ )
+
+ private lazy val commonMethods = super.getMethods() ++ Array(
dataInputsMethod, headersMethod, preHeaderMethod, inputsMethod, outputsMethod, heightMethod, selfMethod,
- selfBoxIndexMethod, lastBlockUtxoRootHashMethod, minerPubKeyMethod, getVarMethod
+ selfBoxIndexMethod, lastBlockUtxoRootHashMethod, minerPubKeyMethod
+ )
+
+ private lazy val v5Methods = commonMethods ++ Seq(
+ getVarV5Method
+ )
+
+ private lazy val v6Methods = commonMethods ++ Seq(
+ getVarV6Method, getVarFromInputMethod
)
+ protected override def getMethods(): Seq[SMethod] = {
+ if (VersionContext.current.isV6SoftForkActivated) {
+ v6Methods
+ } else {
+ v5Methods
+ }
+ }
+
/** Names of methods which provide blockchain context.
* This value can be reused where necessary to avoid allocations. */
val BlockchainContextMethodNames: IndexedSeq[String] = Array(
@@ -1437,11 +1751,27 @@ case object SHeaderMethods extends MonoTypeMethods {
lazy val powDistanceMethod = propertyCall("powDistance", SBigInt, 14, FixedCost(JitCost(10)))
lazy val votesMethod = propertyCall("votes", SByteArray, 15, FixedCost(JitCost(10)))
- protected override def getMethods() = super.getMethods() ++ Seq(
+ // 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)))
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall, "Validate header's proof-of-work")
+
+ private lazy val v5Methods = super.getMethods() ++ Seq(
idMethod, versionMethod, parentIdMethod, ADProofsRootMethod, stateRootMethod, transactionsRootMethod,
timestampMethod, nBitsMethod, heightMethod, extensionRootMethod, minerPkMethod, powOnetimePkMethod,
- powNonceMethod, powDistanceMethod, votesMethod
- )
+ powNonceMethod, powDistanceMethod, votesMethod)
+
+ // 6.0 : checkPow method added
+ private lazy val v6Methods = v5Methods ++ Seq(checkPowMethod)
+
+ protected override def getMethods() = {
+ if (VersionContext.current.isV6SoftForkActivated) {
+ v6Methods
+ } else {
+ v5Methods
+ }
+ }
}
/** Type descriptor of `PreHeader` type of ErgoTree. */
@@ -1480,7 +1810,7 @@ case object SGlobalMethods extends MonoTypeMethods {
lazy val groupGeneratorMethod = SMethod(
this, "groupGenerator", SFunc(SGlobal, SGroupElement), 1, GroupGenerator.costKind)
- .withIRInfo({ case (builder, obj, method, args, tparamSubst) => GroupGenerator })
+ .withIRInfo({ case (_, _, _, _, _) => GroupGenerator })
.withInfo(GroupGenerator, "")
lazy val xorMethod = SMethod(
@@ -1500,9 +1830,61 @@ case object SGlobalMethods extends MonoTypeMethods {
Xor.xorWithCosting(ls, rs)
}
- protected override def getMethods() = super.getMethods() ++ Seq(
- groupGeneratorMethod,
- xorMethod
- )
+ private val BigEndianBytesCostKind = FixedCost(JitCost(10))
+
+ // id = 4 is reserved for deserializeTo ()
+ lazy val fromBigEndianBytesMethod = SMethod(
+ this, "fromBigEndianBytes", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 5, BigEndianBytesCostKind, Seq(tT))
+ .withIRInfo(MethodCallIrBuilder,
+ javaMethodOf[SigmaDslBuilder, Coll[Byte], RType[_]]("fromBigEndianBytes"),
+ { mtype => Array(mtype.tRange) })
+ .withInfo(MethodCall,
+ "Decode a number from big endian bytes.",
+ ArgInfo("first", "Bytes which are big-endian encoded number."))
+
+ lazy val serializeMethod = SMethod(this, "serialize",
+ SFunc(Array(SGlobal, tT), SByteArray, Array(paramT)), 3, DynamicCost)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall, "Serializes the given `value` into bytes using the default serialization format.",
+ ArgInfo("value", "value to be serialized"))
+
+
+ /** Implements evaluation of Global.serialize method call ErgoTree node.
+ * Called via reflection based on naming convention.
+ * @see SMethod.evalMethod
+ */
+ def serialize_eval(mc: MethodCall, G: SigmaDslBuilder, value: SType#WrappedType)
+ (implicit E: ErgoTreeEvaluator): Coll[Byte] = {
+
+ E.addCost(SigmaByteWriter.StartWriterCost)
+
+ val addFixedCostCallback = { (costInfo: OperationCostInfo[FixedCost]) =>
+ E.addCost(costInfo)
+ }
+ val addPerItemCostCallback = { (info: OperationCostInfo[PerItemCost], nItems: Int) =>
+ E.addSeqCostNoOp(info.costKind, nItems, info.opDesc)
+ }
+ val w = SigmaSerializer.startWriter(None,
+ Some(addFixedCostCallback), Some(addPerItemCostCallback))
+
+ DataSerializer.serialize(value, mc.args(0).tpe, w)
+ Colls.fromArray(w.toBytes)
+ }
+
+ protected override def getMethods() = super.getMethods() ++ {
+ if (VersionContext.current.isV6SoftForkActivated) {
+ Seq(
+ groupGeneratorMethod,
+ xorMethod,
+ serializeMethod,
+ fromBigEndianBytesMethod
+ )
+ } else {
+ Seq(
+ groupGeneratorMethod,
+ xorMethod
+ )
+ }
+ }
}
diff --git a/data/shared/src/main/scala/sigma/ast/transformers.scala b/data/shared/src/main/scala/sigma/ast/transformers.scala
index 939da79d98..8d7e689a18 100644
--- a/data/shared/src/main/scala/sigma/ast/transformers.scala
+++ b/data/shared/src/main/scala/sigma/ast/transformers.scala
@@ -10,7 +10,7 @@ import sigma.eval.ErgoTreeEvaluator.DataEnv
import sigma.serialization.CoreByteWriter.ArgInfo
import sigma.serialization.OpCodes
import sigma.serialization.ValueCodes.OpCode
-import sigma.{Box, Coll, Evaluation}
+import sigma.{Box, Coll, Evaluation, VersionContext}
// TODO refactor: remove this trait as it doesn't have semantic meaning
@@ -258,10 +258,22 @@ case class ByIndex[V <: SType](input: Value[SCollection[V]],
val indexV = index.evalTo[Int](env)
default match {
case Some(d) =>
- val dV = d.evalTo[V#WrappedType](env)
- Value.checkType(d, dV) // necessary because cast to V#WrappedType is erased
- addCost(ByIndex.costKind)
- inputV.getOrElse(indexV, dV)
+ if (VersionContext.current.isV6SoftForkActivated) {
+ // lazy evaluation of default in 6.0
+ addCost(ByIndex.costKind)
+ if (inputV.isDefinedAt(indexV)) {
+ inputV.apply(indexV)
+ } else {
+ val dV = d.evalTo[V#WrappedType](env)
+ Value.checkType(d, dV) // necessary because cast to V#WrappedType is erased
+ inputV.getOrElse(indexV, dV)
+ }
+ } else {
+ val dV = d.evalTo[V#WrappedType](env)
+ Value.checkType(d, dV) // necessary because cast to V#WrappedType is erased
+ addCost(ByIndex.costKind)
+ inputV.getOrElse(indexV, dV)
+ }
case _ =>
addCost(ByIndex.costKind)
inputV.apply(indexV)
@@ -613,11 +625,22 @@ case class OptionGetOrElse[V <: SType](input: Value[SOption[V]], default: Value[
override val opType = SFunc(IndexedSeq(input.tpe, tpe), tpe)
override def tpe: V = input.tpe.elemType
protected final override def eval(env: DataEnv)(implicit E: ErgoTreeEvaluator): Any = {
- val inputV = input.evalTo[Option[V#WrappedType]](env)
- val dV = default.evalTo[V#WrappedType](env) // TODO v6.0: execute lazily (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/906)
- Value.checkType(default, dV) // necessary because cast to V#WrappedType is erased
- addCost(OptionGetOrElse.costKind)
- inputV.getOrElse(dV)
+ if(VersionContext.current.isV6SoftForkActivated) {
+ // lazy evaluation of default in 6.0
+ val inputV = input.evalTo[Option[V#WrappedType]](env)
+ addCost(OptionGetOrElse.costKind)
+ inputV.getOrElse {
+ val dV = default.evalTo[V#WrappedType](env)
+ Value.checkType(default, dV) // necessary because cast to V#WrappedType is erased
+ dV
+ }
+ } else {
+ val inputV = input.evalTo[Option[V#WrappedType]](env)
+ val dV = default.evalTo[V#WrappedType](env)
+ Value.checkType(default, dV) // necessary because cast to V#WrappedType is erased
+ addCost(OptionGetOrElse.costKind)
+ inputV.getOrElse(dV)
+ }
}
}
object OptionGetOrElse extends ValueCompanion with FixedCostValueCompanion {
diff --git a/data/shared/src/main/scala/sigma/ast/trees.scala b/data/shared/src/main/scala/sigma/ast/trees.scala
index 38d4565f30..39e666a389 100644
--- a/data/shared/src/main/scala/sigma/ast/trees.scala
+++ b/data/shared/src/main/scala/sigma/ast/trees.scala
@@ -295,7 +295,6 @@ object AND extends LogicalTransformerCompanion {
def apply(children: Seq[Value[SBoolean.type]]): AND =
AND(ConcreteCollection.fromSeq(children))
-// def apply(head: Value[SBoolean.type], tail: Value[SBoolean.type]*): AND = apply(head +: tail)
def apply(items: Value[SBoolean.type]*)(implicit o1: Overloaded1): AND = apply(items)
}
diff --git a/data/shared/src/main/scala/sigma/ast/values.scala b/data/shared/src/main/scala/sigma/ast/values.scala
index 87c661a00a..ff5da32ec7 100644
--- a/data/shared/src/main/scala/sigma/ast/values.scala
+++ b/data/shared/src/main/scala/sigma/ast/values.scala
@@ -1298,6 +1298,10 @@ case class MethodCall(
method: SMethod,
args: IndexedSeq[Value[SType]],
typeSubst: Map[STypeVar, SType]) extends Value[SType] {
+
+ require(method.explicitTypeArgs.forall(tyArg => typeSubst.contains(tyArg)),
+ s"Generic method call should have concrete type for each explicit type parameter, but was: $this")
+
override def companion = if (args.isEmpty) PropertyCall else MethodCall
override def opType: SFunc = SFunc(obj.tpe +: args.map(_.tpe), tpe)
diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala
index 168b2f8266..8d272439f4 100644
--- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala
+++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala
@@ -2,6 +2,7 @@ package sigma.data
import sigma._
import sigma.eval.Extensions.IntExt
+import sigma.util.Extensions.BigIntOps
import scala.math.{Integral, Ordering}
@@ -89,6 +90,32 @@ object NumericOps {
* NOTE: This method should not be used in v4.x
*/
override def divisionRemainder(x: BigInt, y: BigInt): BigInt = x.mod(y)
+
+ override def toBigEndianBytes(x: BigInt): Coll[Byte] = Colls.fromArray(x.toBigInteger.toByteArray)
+
+ override def bitwiseInverse(x: BigInt): BigInt = CBigInt(x.toBigInteger.not())
+
+ override def bitwiseOr(x: BigInt, y: BigInt): BigInt = x.or(y)
+
+ override def bitwiseAnd(x: BigInt, y: BigInt): BigInt = x.and(y)
+
+ override def bitwiseXor(x: BigInt, y: BigInt): BigInt = x.xor(y)
+
+ override def shiftLeft(x: BigInt, bits: Int): BigInt = {
+ if (bits < 0 || bits >= 256) {
+ throw new IllegalArgumentException(s"Wrong argument in BigInt.shiftRight: bits < 0 || bits >= 256 ($bits)")
+ } else {
+ x.shiftLeft(bits)
+ }
+ }
+
+ override def shiftRight(x: BigInt, bits: Int): BigInt = {
+ if (bits < 0 || bits >= 256) {
+ throw new IllegalArgumentException(s"Wrong argument in BigInt.shiftRight: bits < 0 || bits >= 256 ($bits)")
+ } else {
+ x.shiftRight(bits)
+ }
+ }
}
/** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */
diff --git a/data/shared/src/main/scala/sigma/data/CHeader.scala b/data/shared/src/main/scala/sigma/data/CHeader.scala
new file mode 100644
index 0000000000..aa5a5756d2
--- /dev/null
+++ b/data/shared/src/main/scala/sigma/data/CHeader.scala
@@ -0,0 +1,142 @@
+package sigma.data
+
+import org.ergoplatform.{AutolykosSolution, ErgoHeader, HeaderWithoutPow, HeaderWithoutPowSerializer}
+import scorex.crypto.authds.ADDigest
+import scorex.crypto.hash.Digest32
+import scorex.util.{bytesToId, idToBytes}
+import sigma.pow.Autolykos2PowValidation
+import sigma.{AvlTree, BigInt, Coll, Colls, GroupElement, Header}
+
+/** A default implementation of [[Header]] interface.
+ *
+ * @see [[Header]] for detailed descriptions
+ */
+class CHeader(val ergoHeader: ErgoHeader) extends Header with WrapperOf[ErgoHeader] {
+
+ /** Bytes representation of ModifierId of this Header */
+ override lazy val id: Coll[Byte] = ergoHeader.id
+
+ /** Block version, to be increased on every soft and hardfork. */
+ override def version: Byte = ergoHeader.version
+
+ /** Bytes representation of ModifierId of the parent block */
+ override def parentId: Coll[Byte] = Colls.fromArray(idToBytes(ergoHeader.parentId))
+
+ /** Hash of ADProofs for transactions in a block */
+ override def ADProofsRoot: Coll[Byte] = Colls.fromArray(ergoHeader.ADProofsRoot)
+
+ /** AvlTree of a state after block application */
+ override def stateRoot: AvlTree = CAvlTree(AvlTreeData.avlTreeFromDigest(Colls.fromArray(ergoHeader.stateRoot)))
+
+ /** Root hash (for a Merkle tree) of transactions in a block. */
+ override def transactionsRoot: Coll[Byte] = Colls.fromArray(ergoHeader.transactionsRoot)
+
+ /** Block timestamp (in milliseconds since beginning of Unix Epoch) */
+ override def timestamp: Long = ergoHeader.timestamp
+
+ /** Current difficulty in a compressed view.
+ * NOTE: actually it is unsigned Int */
+ override def nBits: Long = ergoHeader.nBits
+
+ /** Block height */
+ override def height: Int = ergoHeader.height
+
+ /** Root hash of extension section */
+ override def extensionRoot: Coll[Byte] = Colls.fromArray(ergoHeader.extensionRoot)
+
+ /** Miner public key. Should be used to collect block rewards.
+ * Part of Autolykos solution. */
+ override def minerPk: GroupElement = CGroupElement(ergoHeader.powSolution.pk)
+
+ /** One-time public key. Prevents revealing of miners secret. */
+ override def powOnetimePk: GroupElement = CGroupElement(ergoHeader.powSolution.w)
+
+ /** nonce */
+ override def powNonce: Coll[Byte] = Colls.fromArray(ergoHeader.powSolution.n)
+
+ /** Distance between pseudo-random number, corresponding to nonce `powNonce` and a secret,
+ * corresponding to `minerPk`. The lower `powDistance` is, the harder it was to find this solution. */
+ override def powDistance: BigInt = CBigInt(ergoHeader.powSolution.d.bigInteger)
+
+ /** Miner votes for changing system parameters. */
+ override def votes: Coll[Byte] = Colls.fromArray(ergoHeader.votes)
+
+ override def unparsedBytes: Coll[Byte] = Colls.fromArray(ergoHeader.unparsedBytes)
+
+ /** The data value wrapped by this wrapper. */
+ override def wrappedValue: ErgoHeader = ergoHeader
+
+ override def serializeWithoutPoW: Coll[Byte] = {
+ Colls.fromArray(HeaderWithoutPowSerializer.toBytes(ergoHeader))
+ }
+
+ override def checkPow: Boolean = {
+ Autolykos2PowValidation.checkPoWForVersion2(this)
+ }
+
+ override def toString: String =
+ s"""CHeader(
+ | id: ${id},
+ | version: ${version},
+ | tx proofs hash: ${ADProofsRoot},
+ | state root: ${stateRoot.digest},
+ | transactions root: ${transactionsRoot},
+ | time: $timestamp,
+ | nbits: $nBits,
+ | extension root: $extensionRoot,
+ | miner pubkey: $minerPk,
+ | pow one time pubkey(from AL 1): $powOnetimePk,
+ | pow nonce: $powNonce,
+ | pow distance (from AL 1): $powDistance,
+ | votes: $votes,
+ | unparsed bytes: $unparsedBytes
+ |)""".stripMargin
+
+ override def hashCode(): Int = id.hashCode()
+
+ override def equals(other: Any): Boolean = other match {
+ case ch: CHeader => ch.id == this.id
+ case _ => false
+ }
+
+ def copy(): CHeader = new CHeader(ergoHeader.copy()) // used in tests only
+}
+
+object CHeader {
+
+ def apply( version: Byte,
+ parentId: Coll[Byte],
+ ADProofsRoot: Coll[Byte],
+ stateRootDigest: Coll[Byte],
+ transactionsRoot: Coll[Byte],
+ timestamp: Long,
+ nBits: Long,
+ height: Int,
+ extensionRoot: Coll[Byte],
+ minerPk: GroupElement,
+ powOnetimePk: GroupElement,
+ powNonce: Coll[Byte],
+ powDistance: BigInt,
+ votes: Coll[Byte],
+ unparsedBytes: Coll[Byte]): CHeader = {
+
+ val solution = new AutolykosSolution(
+ minerPk.asInstanceOf[CGroupElement].wrappedValue,
+ powOnetimePk.asInstanceOf[CGroupElement].wrappedValue,
+ powNonce.toArray,
+ powDistance.asInstanceOf[CBigInt].wrappedValue)
+
+ val h = ErgoHeader(version, bytesToId(parentId.toArray), Digest32 @@ ADProofsRoot.toArray,
+ ADDigest @@ stateRootDigest.toArray, Digest32 @@ transactionsRoot.toArray, timestamp, nBits, height,
+ Digest32 @@ extensionRoot.toArray, solution, votes.toArray, unparsedBytes.toArray, null)
+
+ new CHeader(h)
+ }
+
+ /** Size of of Header.votes array. */
+ val VotesSize: Int = SigmaConstants.VotesArraySize.value
+
+ /** Size of nonce array from Autolykos POW solution in Header.powNonce array. */
+ val NonceSize: Int = SigmaConstants.AutolykosPowSolutionNonceArraySize.value
+
+}
diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala
index 3938feacd3..2ae4f73703 100644
--- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala
+++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala
@@ -4,14 +4,17 @@ import debox.cfor
import org.ergoplatform.ErgoBox
import org.ergoplatform.validation.ValidationRules
import scorex.crypto.hash.{Blake2b256, Sha256}
+import scorex.utils.{Ints, Longs}
+import sigma.ast.{AtLeast, SBigInt, SubstConstants}
import scorex.utils.Longs
-import sigma.ast.{AtLeast, SubstConstants}
+import sigma.ast.{AtLeast, SType, SubstConstants}
import sigma.crypto.{CryptoConstants, EcPointType, Ecp}
import sigma.eval.Extensions.EvalCollOps
-import sigma.serialization.{GroupElementSerializer, SigmaSerializer}
+import sigma.serialization.{DataSerializer, GroupElementSerializer, SigmaSerializer}
+import sigma.serialization.{GroupElementSerializer, SerializerException, SigmaSerializer}
import sigma.util.Extensions.BigIntegerOps
import sigma.validation.SigmaValidationSettings
-import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext}
+import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, Evaluation, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext}
import java.math.BigInteger
@@ -200,6 +203,48 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl =>
val p = GroupElementSerializer.parse(r)
this.GroupElement(p)
}
+
+ override def fromBigEndianBytes[T](bytes: Coll[Byte])(implicit cT: RType[T]): T = {
+ cT match {
+ case sigma.ByteType => if (bytes.length != 1) {
+ throw new IllegalArgumentException("To deserialize SByte with fromBigEndianBytes, exactly one byte should be provided")
+ } else {
+ bytes.apply(0).asInstanceOf[T]
+ }
+ case sigma.ShortType => if (bytes.length != 2) {
+ throw new IllegalArgumentException("To deserialize SShort with fromBigEndianBytes, exactly two bytes should be provided")
+ } else {
+ val b0 = bytes(0)
+ val b1 = bytes(1)
+ ((b0 & 0xFF) << 8 | (b1 & 0xFF)).toShort.asInstanceOf[T]
+ }
+ case sigma.IntType => if (bytes.length != 4) {
+ throw new IllegalArgumentException("To deserialize SInt with fromBigEndianBytes, exactly four bytes should be provided")
+ } else {
+ Ints.fromByteArray(bytes.toArray).asInstanceOf[T]
+ }
+ case sigma.LongType => if (bytes.length != 8) {
+ throw new IllegalArgumentException("To deserialize SLong with fromBigEndianBytes, exactly eight bytes should be provided")
+ } else {
+ Longs.fromByteArray(bytes.toArray).asInstanceOf[T]
+ }
+ case sigma.BigIntRType =>
+ if (bytes.length > SBigInt.MaxSizeInBytes) {
+ throw SerializerException(s"BigInt value doesn't not fit into ${SBigInt.MaxSizeInBytes} bytes in fromBigEndianBytes")
+ }
+ CBigInt(new BigInteger(bytes.toArray).to256BitValueExact).asInstanceOf[T]
+ // todo: UnsignedBitInt
+ case _ => throw new IllegalArgumentException("Unsupported type provided in fromBigEndianBytes")
+ }
+ }
+
+ /** Serializes the given `value` into bytes using the default serialization format. */
+ override def serialize[T](value: T)(implicit cT: RType[T]): Coll[Byte] = {
+ val tpe = Evaluation.rtypeToSType(cT)
+ val w = SigmaSerializer.startWriter()
+ DataSerializer.serialize(value.asInstanceOf[SType#WrappedType], tpe, w)
+ Colls.fromArray(w.toBytes)
+ }
}
/** Default singleton instance of Global object, which implements global ErgoTree functions. */
diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala
index 34e2f47f63..86a9bfffce 100644
--- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala
+++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala
@@ -1,5 +1,6 @@
package sigma.data
+import sigma.{Coll, Colls}
import sigma.util.Extensions.{ByteOps, ShortOps}
/** Type-class which defines the operations on Integral types (Byte, Short, Int, Long, BigInt)
@@ -37,6 +38,25 @@ object ExactIntegral {
override def plus(x: Byte, y: Byte): Byte = x.addExact(y)
override def minus(x: Byte, y: Byte): Byte = x.subtractExact(y)
override def times(x: Byte, y: Byte): Byte = x.multiplyExact(y)
+ override def toBigEndianBytes(x: Byte): Coll[Byte] = Colls.fromItems(x)
+ override def bitwiseInverse(x: Byte): Byte = (~x).toByte
+ override def bitwiseOr(x: Byte, y: Byte): Byte = (x | y).toByte
+ override def bitwiseAnd(x: Byte, y: Byte): Byte = (x & y).toByte
+ override def bitwiseXor(x: Byte, y: Byte): Byte = (x ^ y).toByte
+ override def shiftLeft(x: Byte, bits: Int): Byte = {
+ if (bits < 0 || bits >= 8) {
+ throw new IllegalArgumentException(s"Wrong argument in Byte.shiftRight: bits < 0 || bits >= 8 ($bits)")
+ } else {
+ (x << bits).toByte
+ }
+ }
+ override def shiftRight(x: Byte, bits: Int): Byte = {
+ if (bits < 0 || bits >= 8) {
+ throw new IllegalArgumentException(s"Wrong argument in Byte.shiftRight: bits < 0 || bits >= 8 ($bits)")
+ } else {
+ (x >> bits).toByte
+ }
+ }
}
implicit object ShortIsExactIntegral extends ExactIntegral[Short] {
@@ -44,6 +64,25 @@ object ExactIntegral {
override def plus(x: Short, y: Short): Short = x.addExact(y)
override def minus(x: Short, y: Short): Short = x.subtractExact(y)
override def times(x: Short, y: Short): Short = x.multiplyExact(y)
+ override def toBigEndianBytes(x: Short): Coll[Byte] = Colls.fromItems((x >> 8).toByte, x.toByte)
+ override def bitwiseInverse(x: Short): Short = (~x).toShort
+ override def bitwiseOr(x: Short, y: Short): Short = (x | y).toShort
+ override def bitwiseAnd(x: Short, y: Short): Short = (x & y).toShort
+ override def bitwiseXor(x: Short, y: Short): Short = (x ^ y).toShort
+ override def shiftLeft(x: Short, bits: Int): Short = {
+ if (bits < 0 || bits >= 16) {
+ throw new IllegalArgumentException(s"Wrong argument in Short.shiftRight: bits < 0 || bits >= 16 ($bits)")
+ } else {
+ (x << bits).toShort
+ }
+ }
+ override def shiftRight(x: Short, bits: Int): Short = {
+ if (bits < 0 || bits >= 16){
+ throw new IllegalArgumentException(s"Wrong argument in Short.shiftRight: bits < 0 || bits >= 16 ($bits)")
+ } else {
+ (x >> bits).toShort
+ }
+ }
}
implicit object IntIsExactIntegral extends ExactIntegral[Int] {
@@ -51,6 +90,28 @@ object ExactIntegral {
override def plus(x: Int, y: Int): Int = java7.compat.Math.addExact(x, y)
override def minus(x: Int, y: Int): Int = java7.compat.Math.subtractExact(x, y)
override def times(x: Int, y: Int): Int = java7.compat.Math.multiplyExact(x, y)
+ override def toBigEndianBytes(x: Int): Coll[Byte] =
+ Colls.fromItems((x >> 24).toByte, (x >> 16).toByte, (x >> 8).toByte, x.toByte)
+ override def bitwiseInverse(x: Int): Int = ~x
+ override def bitwiseOr(x: Int, y: Int): Int = x | y
+ override def bitwiseAnd(x: Int, y: Int): Int = x & y
+ override def bitwiseXor(x: Int, y: Int): Int = x ^ y
+
+ override def shiftLeft(x: Int, bits: Int): Int = {
+ if (bits < 0 || bits >= 32) {
+ throw new IllegalArgumentException(s"Wrong argument in Byte.shiftRight: bits < 0 || bits >= 32 ($bits)")
+ } else {
+ x << bits
+ }
+ }
+
+ override def shiftRight(x: Int, bits: Int): Int = {
+ if (bits < 0 || bits >= 32) {
+ throw new IllegalArgumentException(s"Wrong argument in Int.shiftRight: bits < 0 || bits >= 32 ($bits)")
+ } else {
+ x >> bits
+ }
+ }
}
implicit object LongIsExactIntegral extends ExactIntegral[Long] {
@@ -58,5 +119,27 @@ object ExactIntegral {
override def plus(x: Long, y: Long): Long = java7.compat.Math.addExact(x, y)
override def minus(x: Long, y: Long): Long = java7.compat.Math.subtractExact(x, y)
override def times(x: Long, y: Long): Long = java7.compat.Math.multiplyExact(x, y)
+ override def toBigEndianBytes(x: Long): Coll[Byte] =
+ Colls.fromItems((x >> 56).toByte, (x >> 48).toByte, (x >> 40).toByte, (x >> 32).toByte, (x >> 24).toByte, (x >> 16).toByte, (x >> 8).toByte, x.toByte)
+ override def bitwiseInverse(x: Long): Long = ~x
+ override def bitwiseOr(x: Long, y: Long): Long = x | y
+ override def bitwiseAnd(x: Long, y: Long): Long = x & y
+ override def bitwiseXor(x: Long, y: Long): Long = x ^ y
+
+ override def shiftLeft(x: Long, bits: Int): Long = {
+ if (bits < 0 || bits >= 64) {
+ throw new IllegalArgumentException(s"Wrong argument in Long.shiftRight: bits < 0 || bits >= 64 ($bits)")
+ } else {
+ x << bits
+ }
+ }
+
+ override def shiftRight(x: Long, bits: Int): Long = {
+ if (bits < 0 || bits >= 64) {
+ throw new IllegalArgumentException(s"Wrong argument in Long.shiftRight: bits < 0 || bits >= 64 ($bits)")
+ } else {
+ x >> bits
+ }
+ }
}
}
diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala
index 2e9b799a61..244cc6b7b7 100644
--- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala
+++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala
@@ -1,5 +1,7 @@
package sigma.data
+import debox.cfor
+import sigma.{Coll, Colls}
import sigma.data.ExactIntegral._
/** Numeric operations with overflow checks.
@@ -30,6 +32,63 @@ trait ExactNumeric[T] {
def toInt(x: T): Int = n.toInt(x)
def toLong(x: T): Long = n.toLong(x)
+ /** Returns a big-endian representation of this value in a collection of bytes.
+ * For example, the `Int` value `0x12131415` would yield the
+ * collection of bytes [0x12, 0x13, 0x14, 0x15]
+ */
+ def toBigEndianBytes(x: T): Coll[Byte]
+
+ /**
+ * Returns a big-endian binary representation of this value as boolean array.
+ */
+ def toBits(x: T): Coll[Boolean] = {
+
+ def isBitSet(byte: Byte)(bit: Int): Boolean = ((byte >> bit) & 1) == 1
+
+ val bytes = toBigEndianBytes(x)
+ val l = bytes.length
+ val res = new Array[Boolean](l * 8)
+ cfor(0)(_ < l, _ + 1) { i =>
+ val b = bytes(i)
+ cfor(0)(_ < 8, _ + 1) { bitIdx =>
+ res(i * 8 + (7 - bitIdx)) = isBitSet(b)(bitIdx)
+ }
+ }
+ Colls.fromArray(res)
+ }
+
+ /**
+ * @return a numeric value which is inverse of `x` (every bit, including sign, is flipped)
+ */
+ def bitwiseInverse(x: T): T
+
+ /**
+ * @return a numeric value which is `this | that`
+ */
+ def bitwiseOr(x: T, y: T): T
+
+ /**
+ * @return a numeric value which is `this && that`
+ */
+ def bitwiseAnd(x: T, y: T): T
+
+ /**
+ * @return a numeric value which is `this xor that`
+ */
+ def bitwiseXor(x: T, y: T): T
+
+ /**
+ * @return a value which is (this << n). The shift distance, n, may be negative,
+ * in which case this method performs a right shift. (Computes floor(this * 2n).)
+ */
+ def shiftLeft(x: T, bits: Int): T
+
+ /**
+ * @return a value which is (this >> n). Sign extension is performed. The shift distance, n,
+ * may be negative, in which case this method performs a left shift. (Computes floor(this / 2n).)
+ */
+ def shiftRight(x: T, bits: Int): T
+
/** A value of type T which corresponds to integer 0. */
lazy val zero: T = fromInt(0)
diff --git a/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala b/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala
index 52f839354c..6df82125df 100644
--- a/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala
+++ b/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala
@@ -1,6 +1,6 @@
package sigma.eval
-import sigma.{AvlTree, Coll, Context}
+import sigma.{AvlTree, Coll, Context, Header}
import sigma.ast.{Constant, FixedCost, MethodCall, OperationCostInfo, OperationDesc, PerItemCost, SType, TypeBasedCost}
import sigma.data.KeyValueColl
diff --git a/data/shared/src/main/scala/sigma/interpreter/ContextExtension.scala b/data/shared/src/main/scala/sigma/interpreter/ContextExtension.scala
index e8cdb7d709..f03d076d43 100644
--- a/data/shared/src/main/scala/sigma/interpreter/ContextExtension.scala
+++ b/data/shared/src/main/scala/sigma/interpreter/ContextExtension.scala
@@ -16,8 +16,15 @@ import sigma.serialization.{SigmaByteReader, SigmaByteWriter, SigmaSerializer}
* @param values internal container of the key-value pairs
*/
case class ContextExtension(values: scala.collection.Map[Byte, EvaluatedValue[_ <: SType]]) {
- def add(bindings: VarBinding*): ContextExtension =
+ def add(bindings: VarBinding*): ContextExtension = {
ContextExtension(values ++ bindings)
+ }
+
+ /**
+ * @param varId - index of context variable
+ * @return context variable with provided index or None if it is not there
+ */
+ def get(varId: Byte): Option[EvaluatedValue[_ <: SType]] = values.get(varId)
}
object ContextExtension {
diff --git a/data/shared/src/main/scala/sigma/pow/Autolykos2PowValidation.scala b/data/shared/src/main/scala/sigma/pow/Autolykos2PowValidation.scala
new file mode 100644
index 0000000000..23cf722194
--- /dev/null
+++ b/data/shared/src/main/scala/sigma/pow/Autolykos2PowValidation.scala
@@ -0,0 +1,176 @@
+package sigma.pow
+
+
+import scorex.crypto.hash.Blake2b256
+import scorex.utils.{Bytes, Ints, Longs}
+import sigma.Header
+import sigma.crypto.{BcDlogGroup, BigIntegers, CryptoConstants}
+import sigma.util.NBitsUtils
+
+/**
+ * Functions used to validate Autolykos2 Proof-of-Work.
+ */
+object Autolykos2PowValidation {
+
+ type Height = Int
+
+ /**
+ * k value for k-sum problem Autolykos is based on (find k numbers in table on N size)
+ */
+ private val k = 32
+
+ /**
+ * Initial size of N value for k-sum problem Autolykos is based on (find k numbers in table on N size).
+ * It grows from it since predefined block height in Autolykos 2.
+ */
+ private val NStart = 26
+
+ /**
+ * Group order, used in Autolykos V.1 for non-outsourceability,
+ * and also to obtain target in both Autolykos v1 and v2
+ */
+ private val q: BigInt = CryptoConstants.dlogGroup.order
+
+ /**
+ * Number of elements in a table to find k-sum problem solution on top of
+ */
+ val NBase: Int = Math.pow(2, NStart.toDouble).toInt
+
+ /**
+ * Initial height since which table (`N` value) starting to increase by 5% per `IncreasePeriodForN` blocks
+ */
+ val IncreaseStart: Height = 600 * 1024
+
+ /**
+ * Table size (`N`) increased every 50 * 1024 blocks
+ */
+ val IncreasePeriodForN: Height = 50 * 1024
+
+ /**
+ * On this height, the table (`N` value) will stop to grow.
+ * Max N on and after this height would be 2,143,944,600 which is still less than 2^^31.
+ */
+ val NIncreasementHeightMax: Height = 4198400
+
+ /**
+ * Blake2b256 hash function invocation
+ * @param in - input bit-string
+ * @return - 256 bits (32 bytes) array
+ */
+ def hash(in: Array[Byte]): Array[Byte] = Blake2b256.hash(in)
+
+ /**
+ * Convert byte array to unsigned integer
+ * @param in - byte array
+ * @return - unsigned integer
+ */
+ def toBigInt(in: Array[Byte]): BigInt = BigInt(BigIntegers.fromUnsignedByteArray(in))
+
+ /**
+ * Constant data to be added to hash function to increase its calculation time
+ */
+ val M: Array[Byte] = (0 until 1024).toArray.flatMap(i => Longs.toByteArray(i.toLong))
+
+ /**
+ * Calculates table size (N value) for a given height (moment of time)
+ *
+ * @see papers/yellow/pow/ErgoPow.tex for full description and test vectors
+ * @param headerHeight - height of a header to mine
+ * @return - N value
+ */
+ def calcN(headerHeight: Height): Int = {
+ val height = Math.min(NIncreasementHeightMax, headerHeight)
+ if (height < IncreaseStart) {
+ NBase
+ } else {
+ val itersNumber = (height - IncreaseStart) / IncreasePeriodForN + 1
+ (1 to itersNumber).foldLeft(NBase) { case (step, _) =>
+ step / 100 * 105
+ }
+ }
+ }
+
+ def calcN(header: Header): Int = calcN(header.height)
+
+ /**
+ * Hash function that takes `m` and `nonceBytes` and returns a list of size `k` with numbers in
+ * [0,`N`)
+ */
+ private def genIndexes(k: Int, seed: Array[Byte], N: Int): Seq[Int] = {
+ val hash = Blake2b256(seed)
+ val extendedHash = Bytes.concat(hash, hash.take(3))
+ (0 until k).map { i =>
+ BigInt(1, extendedHash.slice(i, i + 4)).mod(N).toInt
+ }
+ }.ensuring(_.length == k)
+
+ /**
+ * Generate element of Autolykos equation.
+ */
+ private def genElementV2(indexBytes: Array[Byte], heightBytes: => Array[Byte]): BigInt = {
+ // Autolykos v. 2: H(j|h|M) (line 5 from the Algo 2 of the spec)
+ toBigInt(hash(Bytes.concat(indexBytes, heightBytes, M)).drop(1))
+ }
+
+ def hitForVersion2ForMessage(k: Int, msg: Array[Byte], nonce: Array[Byte], h: Array[Byte], N: Int): BigInt = {
+
+ val prei8 = BigIntegers.fromUnsignedByteArray(hash(Bytes.concat(msg, nonce)).takeRight(8))
+ val i = BigIntegers.asUnsignedByteArray(4, prei8.mod(BigInt(N).underlying()))
+ val f = Blake2b256(Bytes.concat(i, h, M)).drop(1) // .drop(1) is the same as takeRight(31)
+ val seed = Bytes.concat(f, msg, nonce) // Autolykos v1, Alg. 2, line4:
+
+ val indexes = genIndexes(k, seed, N)
+ //pk and w not used in v2
+ val elems = indexes.map(idx => genElementV2(Ints.toByteArray(idx), h))
+ val f2 = elems.sum
+
+ // sum as byte array is always about 32 bytes
+ val array: Array[Byte] = BigIntegers.asUnsignedByteArray(32, f2.underlying())
+ val ha = hash(array)
+ toBigInt(ha)
+ }
+
+ /**
+ * Header digest ("message" for default GPU miners) a miner is working on
+ */
+ def msgByHeader(h: Header): Array[Byte] = Blake2b256(h.serializeWithoutPoW.toArray)
+
+ /**
+ * Get hit for Autolykos v2 header (to test it then against PoW target)
+ *
+ * @param header - header to check PoW for
+ * @return PoW hit
+ */
+ def hitForVersion2(header: Header): BigInt = {
+
+ val msg = msgByHeader(header)
+ val nonce = header.powNonce
+
+ val h = Ints.toByteArray(header.height) // used in AL v.2 only
+
+ val N = calcN(header)
+
+ hitForVersion2ForMessage(k, msg, nonce.toArray, h, N)
+ }
+
+ /**
+ * Get target `b` from encoded difficulty `nBits`
+ */
+ def getB(nBits: Long): BigInt = {
+ q / NBitsUtils.decodeCompactBits(nBits)
+ }
+
+ /**
+ * Check PoW for Autolykos v2 header
+ *
+ * @param header - header to check PoW for
+ * @return whether PoW is valid or not
+ */
+ def checkPoWForVersion2(header: Header): Boolean = {
+ val b = getB(header.nBits)
+ // for version 2, we're calculating hit and compare it with target
+ val hit = hitForVersion2(header)
+ hit < b
+ }
+
+}
diff --git a/data/shared/src/main/scala/sigma/serialization/DataSerializer.scala b/data/shared/src/main/scala/sigma/serialization/DataSerializer.scala
index 5f554e96a1..92a54f9aa4 100644
--- a/data/shared/src/main/scala/sigma/serialization/DataSerializer.scala
+++ b/data/shared/src/main/scala/sigma/serialization/DataSerializer.scala
@@ -1,8 +1,9 @@
package sigma.serialization
-import org.ergoplatform.ErgoBox
+import org.ergoplatform.{ErgoBox, ErgoHeader}
+import sigma.VersionContext
import sigma.ast._
-import sigma.data.CBox
+import sigma.data.{CBox, CHeader}
/** This works in tandem with ConstantSerializer, if you change one make sure to check the other.*/
object DataSerializer extends CoreDataSerializer {
@@ -15,6 +16,9 @@ object DataSerializer extends CoreDataSerializer {
case SBox =>
val b = v.asInstanceOf[CBox]
ErgoBox.sigmaSerializer.serialize(b.ebox, w.asInstanceOf[SigmaByteWriter])
+ case SHeader if VersionContext.current.isV6SoftForkActivated =>
+ val h = v.asInstanceOf[CHeader]
+ ErgoHeader.sigmaSerializer.serialize(h.ergoHeader, w.asInstanceOf[SigmaByteWriter])
case _ =>
super.serialize(v, tpe, w)
}
@@ -32,6 +36,12 @@ object DataSerializer extends CoreDataSerializer {
val res = CBox(ErgoBox.sigmaSerializer.parse(r.asInstanceOf[SigmaByteReader]))
r.level = r.level - 1
res
+ case SHeader if VersionContext.current.isV6SoftForkActivated =>
+ val depth = r.level
+ r.level = depth + 1
+ val res = new CHeader(ErgoHeader.sigmaSerializer.parse(r.asInstanceOf[SigmaByteReader]))
+ r.level = r.level - 1
+ res
case t =>
super.deserialize(t, r)
}).asInstanceOf[T#WrappedType]
diff --git a/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala b/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala
index 3d1061d774..5122ee940c 100644
--- a/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala
+++ b/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala
@@ -1,13 +1,13 @@
package sigma.serialization
import org.ergoplatform.validation.ValidationRules.{CheckDeserializedScriptIsSigmaProp, CheckHeaderSizeBit}
-import sigma.ast.{Constant, DeserializationSigmaBuilder, ErgoTree, SType, SubstConstants, UnparsedErgoTree}
+import sigma.ast.{Constant, DeserializationSigmaBuilder, ErgoTree, SType, UnparsedErgoTree}
import sigma.ast.syntax.ValueOps
import sigma.ast.ErgoTree.{EmptyConstants, HeaderType}
import sigma.util.safeNewArray
import debox.cfor
import sigma.VersionContext
-import sigma.validation.{SigmaValidationSettings, ValidationException}
+import sigma.validation.ValidationException
import sigma.validation.ValidationRules.CheckPositionLimit
/**
@@ -287,6 +287,9 @@ class ErgoTreeSerializer {
* allow to use serialized scripts as pre-defined templates.
* See [[SubstConstants]] for details.
*
+ * Note, this operation doesn't require (de)serialization of ErgoTree expression,
+ * thus it is more efficient than serialization roundtrip.
+ *
* @param scriptBytes serialized ErgoTree with ConstantSegregationFlag set to 1.
* @param positions zero based indexes in ErgoTree.constants array which
* should be replaced with new values
@@ -299,26 +302,28 @@ class ErgoTreeSerializer {
*/
def substituteConstants(scriptBytes: Array[Byte],
positions: Array[Int],
- newVals: Array[Constant[SType]])(implicit vs: SigmaValidationSettings): (Array[Byte], Int) = {
+ newVals: Array[Constant[SType]]): (Array[Byte], Int) = {
require(positions.length == newVals.length,
s"expected positions and newVals to have the same length, got: positions: ${positions.toSeq},\n newVals: ${newVals.toSeq}")
val r = SigmaSerializer.startReader(scriptBytes)
val (header, _, constants, treeBytes) = deserializeHeaderWithTreeBytes(r)
- val w = SigmaSerializer.startWriter()
- w.put(header)
+ val nConstants = constants.length
+
+ val resBytes = if (VersionContext.current.isJitActivated) {
+ // need to measure the serialized size of the new constants
+ // by serializing them into a separate writer
+ val constW = SigmaSerializer.startWriter()
- if (VersionContext.current.isJitActivated) {
// The following `constants.length` should not be serialized when segregation is off
// in the `header`, because in this case there is no `constants` section in the
// ErgoTree serialization format. Thus, applying this `substituteConstants` for
// non-segregated trees will return non-parsable ErgoTree bytes (when
// `constants.length` is put in `w`).
if (ErgoTree.isConstantSegregation(header)) {
- w.putUInt(constants.length)
+ constW.putUInt(constants.length)
}
// The following is optimized O(nConstants + position.length) implementation
- val nConstants = constants.length
if (nConstants > 0) {
val backrefs = getPositionsBackref(positions, nConstants)
cfor(0)(_ < nConstants, _ + 1) { i =>
@@ -326,17 +331,38 @@ class ErgoTreeSerializer {
val iPos = backrefs(i) // index to `positions`
if (iPos == -1) {
// no position => no substitution, serialize original constant
- constantSerializer.serialize(c, w)
+ constantSerializer.serialize(c, constW)
} else {
- assert(positions(iPos) == i) // INV: backrefs and positions are mutually inverse
+ require(positions(iPos) == i) // INV: backrefs and positions are mutually inverse
val newConst = newVals(iPos)
require(c.tpe == newConst.tpe,
s"expected new constant to have the same ${c.tpe} tpe, got ${newConst.tpe}")
- constantSerializer.serialize(newConst, w)
+ constantSerializer.serialize(newConst, constW)
}
}
}
+
+ val constBytes = constW.toBytes // nConstants + serialized new constants
+
+ // start composing the resulting tree bytes
+ val w = SigmaSerializer.startWriter()
+ w.put(header) // header byte
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ // fix in v6.0 to save tree size to respect size bit of the original tree
+ if (ErgoTree.hasSize(header)) {
+ val size = constBytes.length + treeBytes.length
+ w.putUInt(size) // tree size
+ }
+ }
+
+ w.putBytes(constBytes) // constants section
+ w.putBytes(treeBytes) // tree section
+ w.toBytes
} else {
+ val w = SigmaSerializer.startWriter()
+ w.put(header)
+
// for v4.x compatibility we save constants.length here (see the above comment to
// understand the consequences)
w.putUInt(constants.length)
@@ -347,7 +373,7 @@ class ErgoTreeSerializer {
val newVal = newVals(positions.indexOf(i))
// we need to get newVal's serialized constant value (see ProveDlogSerializer for example)
val constantStore = new ConstantStore()
- val valW = SigmaSerializer.startWriter(constantStore)
+ val valW = SigmaSerializer.startWriter(Some(constantStore))
valW.putValue(newVal)
val newConsts = constantStore.getAll
require(newConsts.length == 1)
@@ -357,10 +383,12 @@ class ErgoTreeSerializer {
case (c, _) =>
constantSerializer.serialize(c, w)
}
+
+ w.putBytes(treeBytes)
+ w.toBytes
}
- w.putBytes(treeBytes)
- (w.toBytes, constants.length)
+ (resBytes, nConstants)
}
}
diff --git a/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala b/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala
index 319a4284e2..abc12c9c9e 100644
--- a/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala
+++ b/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala
@@ -1,13 +1,15 @@
package sigma.serialization
import sigma.ast.syntax._
-import sigma.ast.{MethodCall, SContextMethods, SMethod, SType, STypeSubst, Value, ValueCompanion}
+import sigma.ast.{MethodCall, SContextMethods, SMethod, SType, STypeSubst, STypeVar, Value, ValueCompanion}
import sigma.util.safeNewArray
import SigmaByteWriter._
import debox.cfor
import sigma.ast.SContextMethods.BlockchainContextMethodNames
import sigma.serialization.CoreByteWriter.{ArgInfo, DataInfo}
+import scala.collection.compat.immutable.ArraySeq
+
case class MethodCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value[SType]], STypeSubst) => Value[SType])
extends ValueSerializer[MethodCall] {
override def opDesc: ValueCompanion = MethodCall
@@ -23,6 +25,10 @@ case class MethodCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value[S
w.putValue(mc.obj, objInfo)
assert(mc.args.nonEmpty)
w.putValues(mc.args, argsInfo, argsItemInfo)
+ mc.method.explicitTypeArgs.foreach { a =>
+ val tpe = mc.typeSubst(a) // existence is checked in MethodCall constructor
+ w.putType(tpe)
+ }
}
/** The SMethod instances in STypeCompanions may have type STypeIdent in methods types,
@@ -43,9 +49,36 @@ case class MethodCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value[S
val obj = r.getValue()
val args = r.getValues()
val method = SMethod.fromIds(typeId, methodId)
- val nArgs = args.length
- val types: Seq[SType] =
+ val explicitTypes = if (method.hasExplicitTypeArgs) {
+ val nTypes = method.explicitTypeArgs.length
+ val res = safeNewArray[SType](nTypes)
+ cfor(0)(_ < nTypes, _ + 1) { i =>
+ res(i) = r.getType()
+ }
+ ArraySeq.unsafeWrapArray(res)
+ } else SType.EmptySeq
+
+ val explicitTypeSubst = method.explicitTypeArgs.zip(explicitTypes).toMap
+ val specMethod = getSpecializedMethodFor(method, explicitTypeSubst, obj, args)
+
+ var isUsingBlockchainContext = specMethod.objType == SContextMethods &&
+ BlockchainContextMethodNames.contains(method.name)
+ r.wasUsingBlockchainContext ||= isUsingBlockchainContext
+
+ cons(obj, specMethod, args, explicitTypeSubst)
+ }
+
+ def getSpecializedMethodFor(
+ methodTemplate: SMethod,
+ explicitTypeSubst: STypeSubst,
+ obj: SValue,
+ args: Seq[SValue]
+ ): SMethod = {
+ // TODO optimize: avoid repeated transformation of method type
+ val method = methodTemplate.withConcreteTypes(explicitTypeSubst)
+ val nArgs = args.length
+ val argTypes: Seq[SType] =
if (nArgs == 0) SType.EmptySeq
else {
val types = safeNewArray[SType](nArgs)
@@ -55,12 +88,6 @@ case class MethodCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value[S
types
}
- val specMethod = method.specializeFor(obj.tpe, types)
-
- var isUsingBlockchainContext = specMethod.objType == SContextMethods &&
- BlockchainContextMethodNames.contains(method.name)
- r.wasUsingBlockchainContext ||= isUsingBlockchainContext
-
- cons(obj, specMethod, args, Map.empty)
+ method.specializeFor(obj.tpe, argTypes)
}
}
diff --git a/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala b/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala
index 35d5e0c9b9..db9312240f 100644
--- a/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala
+++ b/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala
@@ -4,15 +4,52 @@ import scorex.util.serialization.Writer
import sigma.ast.syntax._
import sigma.ast._
import sigma.serialization.CoreByteWriter.{ArgInfo, DataInfo, FormatDescriptor, SeqFmt}
+import SigmaByteWriter._
-class SigmaByteWriter(override val w: Writer,
- val constantExtractionStore: Option[ConstantStore])
- extends CoreByteWriter(w) {
+/** Implementation of [[Writer]] provided by `sigma-data` module.
+ *
+ * @param w destination [[Writer]] to which all the call got delegated.
+ * @param constantExtractionStore optional store to segregate constants to while
+ * replacing them with placeholders.
+ * @param addFixedCostCallbackOpt optional callback to accumulate fixed costs.
+ * @param addPerItemCostCallbackOpt optional callback to accumulate per-item costs.
+ */
+class SigmaByteWriter(
+ override val w: Writer,
+ val constantExtractionStore: Option[ConstantStore],
+ val addFixedCostCallbackOpt: Option[FixedCostCallback],
+ val addPerItemCostCallbackOpt: Option[PerItemCostCallback]
+) extends CoreByteWriter(w) {
import CoreByteWriter._
import ValueSerializer._
+ /** Adds the given cost to the callback if it is defined. */
+ @inline private def addFixedCost(cost: OperationCostInfo[FixedCost]): Unit = {
+ if (addFixedCostCallbackOpt.isDefined)
+ addFixedCostCallbackOpt.get(cost)
+ }
+
+ /** Adds the given cost to the callback if it is defined. */
+ @inline private def addPerItemCost(cost: OperationCostInfo[PerItemCost], nItems: Int): Unit = {
+ if (addPerItemCostCallbackOpt.isDefined)
+ addPerItemCostCallbackOpt.get(cost, nItems)
+ }
+
+ override def putChunk(chunk: w.CH): SigmaByteWriter.this.type = {
+ val start = length()
+ super.putChunk(chunk)
+ addPerItemCost(PutChunkCost, length() - start)
+ this
+ }
+
+ override def put(x: Byte): this.type = {
+ addFixedCost(PutByteCost)
+ super.put(x)
+ }
+
override def put(x: Byte, info: DataInfo[Byte]): this.type = {
ValueSerializer.addArgInfo(info)
+ addFixedCost(PutByteCost)
w.put(x); this
}
@@ -21,68 +58,160 @@ class SigmaByteWriter(override val w: Writer,
super.putUByte(x)
}
- @inline override def putBoolean(x: Boolean, info: DataInfo[Boolean]): this.type = {
+ override def putBoolean(x: Boolean): this.type = {
+ addFixedCost(PutByteCost)
+ super.putBoolean(x)
+ }
+
+ override def putBoolean(x: Boolean, info: DataInfo[Boolean]): this.type = {
ValueSerializer.addArgInfo(info)
+ addFixedCost(PutByteCost)
w.putBoolean(x); this
}
- @inline override def putShort(x: Short, info: DataInfo[Short]): this.type = {
+ override def putShort(x: Short): this.type = {
+ addFixedCost(PutSignedNumericCost)
+ super.putShort(x)
+ }
+
+ override def putShort(x: Short, info: DataInfo[Short]): this.type = {
ValueSerializer.addArgInfo(info)
+ addFixedCost(PutSignedNumericCost)
w.putShort(x); this
}
- @inline override def putUShort(x: Int, info: DataInfo[Vlq[U[Short]]]): this.type = {
+ override def putUShort(x: Int): this.type = {
+ addFixedCost(PutUnsignedNumericCost)
+ super.putUShort(x)
+ }
+
+ override def putUShort(x: Int, info: DataInfo[Vlq[U[Short]]]): this.type = {
ValueSerializer.addArgInfo(info)
+ addFixedCost(PutUnsignedNumericCost)
w.putUShort(x); this
}
- @inline override def putInt(x: Int, info: DataInfo[Int]): this.type = {
+ override def putInt(x: Int): this.type = {
+ addFixedCost(PutSignedNumericCost)
+ super.putInt(x)
+ }
+
+ override def putInt(x: Int, info: DataInfo[Int]): this.type = {
ValueSerializer.addArgInfo(info)
+ addFixedCost(PutSignedNumericCost)
w.putInt(x); this
}
- @inline override def putUInt(x: Long, info: DataInfo[Vlq[U[Int]]]): this.type = {
+ override def putUInt(x: Long): SigmaByteWriter.this.type = {
+ super.putUInt(x)
+ }
+
+ override def putUInt(x: Long, info: DataInfo[Vlq[U[Int]]]): this.type = {
ValueSerializer.addArgInfo(info)
+ addFixedCost(PutUnsignedNumericCost)
w.putUInt(x); this
}
- @inline override def putLong(x: Long, info: DataInfo[Vlq[ZigZag[Long]]]): this.type = {
+ override def putLong(x: Long): SigmaByteWriter.this.type = {
+ addFixedCost(PutSignedNumericCost)
+ super.putLong(x)
+ }
+
+ override def putLong(x: Long, info: DataInfo[Vlq[ZigZag[Long]]]): this.type = {
ValueSerializer.addArgInfo(info)
+ addFixedCost(PutSignedNumericCost)
w.putLong(x); this
}
- @inline override def putULong(x: Long, info: DataInfo[Vlq[U[Long]]]): this.type = {
+ override def putULong(x: Long): SigmaByteWriter.this.type = {
+ addFixedCost(PutUnsignedNumericCost)
+ super.putULong(x)
+ }
+
+ override def putULong(x: Long, info: DataInfo[Vlq[U[Long]]]): this.type = {
ValueSerializer.addArgInfo(info)
+ addFixedCost(PutUnsignedNumericCost)
w.putULong(x); this
}
- @inline override def putBytes(xs: Array[Byte], info: DataInfo[Array[Byte]]): this.type = {
+ override def putBytes(xs: Array[Byte], offset: Int, length: Int): this.type = {
+ addPerItemCost(PutChunkCost, length)
+ super.putBytes(xs, offset, length)
+ }
+
+ override def putBytes(xs: Array[Byte]): SigmaByteWriter.this.type = {
+ addPerItemCost(PutChunkCost, xs.length)
+ super.putBytes(xs)
+ }
+
+ override def putBytes(xs: Array[Byte], info: DataInfo[Array[Byte]]): this.type = {
ValueSerializer.addArgInfo(info)
+ addPerItemCost(PutChunkCost, xs.length)
w.putBytes(xs); this
}
- @inline override def putBits(xs: Array[Boolean], info: DataInfo[Bits]): this.type = {
+ /** Put the two bytes of the big-endian representation of the Short value into the
+ * writer. */
+ override def putShortBytes(value: Short): SigmaByteWriter.this.type = {
+ addPerItemCost(PutChunkCost, 2)
+ super.putShortBytes(value)
+ }
+
+ override def putBits(xs: Array[Boolean]): SigmaByteWriter.this.type = {
+ addPerItemCost(PutChunkCost, xs.length) // number of bits
+ super.putBits(xs)
+ }
+
+ override def putBits(xs: Array[Boolean], info: DataInfo[Bits]): this.type = {
ValueSerializer.addArgInfo(info)
- w.putBits(xs);
- this
+ addPerItemCost(PutChunkCost, xs.length) // number of bits
+ w.putBits(xs); this
}
- @inline override def putType[T <: SType](x: T, info: DataInfo[SType]): this.type = {
+ override def putOption[T](x: Option[T])(putValueC: (this.type, T) => Unit): this.type = {
+ addFixedCost(PutByteCost) // cost of option tag byte
+ super.putOption(x)(putValueC)
+ }
+
+ override def putShortString(s: String): SigmaByteWriter.this.type = {
+ addPerItemCost(PutChunkCost, s.length)
+ super.putShortString(s)
+ }
+
+ override def putType[T <: SType](x: T, info: DataInfo[SType]): this.type = {
ValueSerializer.addArgInfo(info)
- TypeSerializer.serialize(x, this); this
+ TypeSerializer.serialize(x, this); // the cost is added in TypeSerializer
+ this
}
- @inline def putValue[T <: SType](x: Value[T]): this.type = { ValueSerializer.serialize(x, this); this }
- @inline def putValue[T <: SType](x: Value[T], info: DataInfo[SValue]): this.type = {
+ /** Serializes the given expression using [[ValueSerializer]]. */
+ def putValue[T <: SType](x: Value[T]): this.type = {
+ ValueSerializer.serialize(x, this) // the cost is added in ValueSerializer
+ this
+ }
+
+ /** Serializes the given expression using [[ValueSerializer]].
+ * @param x the ErgoTree expression to serialize
+ * @param info meta information about the data being serialized
+ */
+ def putValue[T <: SType](x: Value[T], info: DataInfo[SValue]): this.type = {
ValueSerializer.addArgInfo(info)
- ValueSerializer.serialize(x, this); this
+ ValueSerializer.serialize(x, this); // the cost is added in ValueSerializer
+ this
}
- @inline def putValues[T <: SType](xs: Seq[Value[T]]): this.type = {
+
+ /** Serializes the given sequence of expressions using [[ValueSerializer]]. */
+ def putValues[T <: SType](xs: Seq[Value[T]]): this.type = {
putUInt(xs.length)
xs.foreach(putValue(_))
this
}
- @inline def putValues[T <: SType](xs: Seq[Value[T]], info: DataInfo[Seq[SValue]], itemInfo: DataInfo[SValue]): this.type = {
+
+ /** Serializes the given sequence of expressions using [[ValueSerializer]].
+ * @param xs the sequence of ErgoTree expressions to serialize
+ * @param info additional information about the data being serialized
+ */
+ def putValues[T <: SType](xs: Seq[Value[T]], info: DataInfo[Seq[SValue]], itemInfo: DataInfo[SValue]): this.type = {
putUInt(xs.length, valuesLengthInfo)
foreach("\\#items", xs) { x =>
putValue(x, itemInfo)
@@ -92,6 +221,46 @@ class SigmaByteWriter(override val w: Writer,
}
object SigmaByteWriter {
+
+ /** Callback to accumulate fixed costs. */
+ type FixedCostCallback = OperationCostInfo[FixedCost] => Unit
+
+ /** Callback to accumulate per-item costs (chunked cost). */
+ type PerItemCostCallback = (OperationCostInfo[PerItemCost], Int) => Unit
+
+ /** Cost of instantiating a new serializer.
+ * This also include overhead of method calls.
+ * This is the minimal possible JitCost value
+ */
+ val StartWriterCost = OperationCostInfo(FixedCost(JitCost(10)), NamedDesc("SigmaByteWriter.startWriter"))
+
+ /** Cost of writing single byte without any encoding.
+ * This also include overhead of method calls.
+ * This is the minimal possible JitCost value
+ */
+ val PutByteCost = OperationCostInfo(FixedCost(JitCost(1)), NamedDesc("SigmaByteWriter.put"))
+
+ /** Cost of writing a signed numeric including:
+ * 1) allocation of VLQ buffer array (see putULong in [[scorex.util.serialization.VLQWriter]])
+ * 2) VLQ encoding
+ * 3) overhead of method calls.
+ */
+ val PutUnsignedNumericCost = OperationCostInfo(FixedCost(JitCost(3)), NamedDesc("SigmaByteWriter.putUNumeric"))
+
+ /** Cost of writing a signed numeric including:
+ * 1) ZigZag encoding.
+ * 2) allocation of VLQ buffer array (see putULong in [[scorex.util.serialization.VLQWriter]])
+ * 3) VLQ encoding
+ * 4) overhead of method calls.
+ */
+ val PutSignedNumericCost = OperationCostInfo(FixedCost(JitCost(3)), NamedDesc("SigmaByteWriter.putNumeric"))
+
+ /** Cost of writing a chunk of bytes:
+ * 1) method call overhead
+ * 2) 1 cost unit per byte
+ */
+ val PutChunkCost = OperationCostInfo(PerItemCost(JitCost(3), JitCost(1), 1), NamedDesc("SigmaByteWriter.putChunk"))
+
implicit case object ValueFmt extends FormatDescriptor[SValue] {
override def size: String = "[1, *]"
override def toString: String = "Expr"
diff --git a/data/shared/src/main/scala/sigma/serialization/SigmaSerializer.scala b/data/shared/src/main/scala/sigma/serialization/SigmaSerializer.scala
index cdb28d724b..7da7ec1606 100644
--- a/data/shared/src/main/scala/sigma/serialization/SigmaSerializer.scala
+++ b/data/shared/src/main/scala/sigma/serialization/SigmaSerializer.scala
@@ -4,7 +4,7 @@ import java.nio.ByteBuffer
import scorex.util.ByteArrayBuilder
import scorex.util.serialization._
import sigma.data.SigmaConstants
-import sigma.validation.SigmaValidationSettings
+import sigma.serialization.SigmaByteWriter.{FixedCostCallback, PerItemCostCallback}
import sigma.serialization.ValueCodes.OpCode
object SigmaSerializer {
@@ -35,8 +35,7 @@ object SigmaSerializer {
/** Helper function to be use in serializers. */
def startReader(bytes: Array[Byte],
constantStore: ConstantStore,
- resolvePlaceholdersToConstants: Boolean)
- (implicit vs: SigmaValidationSettings): SigmaByteReader = {
+ resolvePlaceholdersToConstants: Boolean): SigmaByteReader = {
val buf = ByteBuffer.wrap(bytes)
val r = new SigmaByteReader(new VLQByteBufferReader(buf),
constantStore,
@@ -53,14 +52,18 @@ object SigmaSerializer {
def startWriter(): SigmaByteWriter = {
val b = new ByteArrayBuilder()
val wi = new VLQByteBufferWriter(b)
- val w = new SigmaByteWriter(wi, constantExtractionStore = None)
+ val w = new SigmaByteWriter(wi, constantExtractionStore = None, addFixedCostCallbackOpt = None, addPerItemCostCallbackOpt = None)
w
}
- def startWriter(constantExtractionStore: ConstantStore): SigmaByteWriter = {
+ def startWriter(
+ constantExtractionStore: Option[ConstantStore],
+ addFixedCostCallback: Option[FixedCostCallback] = None,
+ addPerItemCostCallback: Option[PerItemCostCallback] = None
+ ): SigmaByteWriter = {
val b = new ByteArrayBuilder()
val wi = new VLQByteBufferWriter(b)
- val w = new SigmaByteWriter(wi, constantExtractionStore = Some(constantExtractionStore))
+ val w = new SigmaByteWriter(wi, constantExtractionStore = constantExtractionStore, addFixedCostCallback, addPerItemCostCallback)
w
}
}
diff --git a/docs/LangSpec.md b/docs/LangSpec.md
index ddbb7bd680..16defff5ff 100644
--- a/docs/LangSpec.md
+++ b/docs/LangSpec.md
@@ -68,7 +68,7 @@ The following sections describe ErgoScript and its operations.
#### Operations and constructs overview
- Binary operations: `>, <, >=, <=, +, -, &&, ||, ==, !=, |, &, *, /, %, ^, ++`
-- predefined primitives: `blake2b256`, `byteArrayToBigInt`, `proveDlog` etc.
+- predefined primitives: `serialize`, `blake2b256`, `byteArrayToBigInt`, `proveDlog` etc.
- val declarations: `val h = blake2b256(pubkey)`
- if-then-else clause: `if (x > 0) 1 else 0`
- collection literals: `Coll(1, 2, 3, 4)`
@@ -249,6 +249,10 @@ class Context {
/** Represents data of the block headers available in scripts. */
class Header {
+
+ /** Validate header's proof-of-work */
+ def checkPow: Boolean
+
/** Bytes representation of ModifierId of this Header */
def id: Coll[Byte]
@@ -915,7 +919,7 @@ def longToByteArray(input: Long): Coll[Byte]
def decodePoint(bytes: Coll[Byte]): GroupElement
-/** Extracts Context variable by id and type.
+/** Extracts Context variable from SELF input by id and type.
* ErgoScript is typed, so accessing a the variables is an operation which involves
* some expected type given in brackets. Thus `getVar[Int](id)` expression should
* evaluate to a valid value of the `Option[Int]` type.
@@ -972,6 +976,18 @@ def decodePoint(bytes: Coll[Byte]): GroupElement
*/
def getVar[T](tag: Int): Option[T]
+/** Extracts Context variable from any input by input index, variable id and variable type.
+ * Unlike getVar, it is not throwing exception when expected type does not match real type of the variable.
+ * Thus it can be used to get context variable from self without exception, using selfBoxIndex, e.g.
+ *
+ * {
+ * val idx = CONTEXT.selfBoxIndex
+ * sigmaProp(CONTEXT.getVarFromInput[Int](idx.toShort, 1.toByte).get == 5)
+ * }
+ *
+ */
+def getVarFromInput[T](inputId: Short, varId: Byte): Option[T]
+
/** Construct a new SigmaProp value representing public key of Diffie Hellman
* signature protocol. When executed as part of Sigma protocol allow to provide
* for a verifier a zero-knowledge proof of secret knowledge.
@@ -985,6 +1001,12 @@ def proveDHTuple(g: GroupElement, h: GroupElement,
*/
def proveDlog(value: GroupElement): SigmaProp
+/** Transforms Base16 encoded string literal into constant of type BigInt.
+ * It is a compile-time operation and only string literal (constant) can be its
+ * argument.
+ */
+def bigInt(input: String): BigInt
+
/** Transforms Base16 encoded string literal into constant of type Coll[Byte].
* It is a compile-time operation and only string literal (constant) can be its
* argument.
diff --git a/interpreter/js/src/main/scala/sigma/interpreter/js/SigmaPropProver.scala b/interpreter/js/src/main/scala/sigma/interpreter/js/SigmaPropProver.scala
index a04d32fa54..414a9d1220 100644
--- a/interpreter/js/src/main/scala/sigma/interpreter/js/SigmaPropProver.scala
+++ b/interpreter/js/src/main/scala/sigma/interpreter/js/SigmaPropProver.scala
@@ -65,7 +65,6 @@ class SigmaPropProver(override val wrappedValue: org.ergoplatform.SigmaPropProve
val realsToExtract = toSigmaBooleanSeq(realSecretsToExtract)
val simsToExtract = toSigmaBooleanSeq(simulatedSecretsToExtract)
val hints = wrappedValue.bagForMultisig(
- context = null,
sigmaTree = sigmaTree.sigmaBoolean, proof.toArray,
realSecretsToExtract = realsToExtract,
simulatedSecretsToExtract = simsToExtract)
diff --git a/interpreter/shared/src/main/scala/org/ergoplatform/ErgoLikeContext.scala b/interpreter/shared/src/main/scala/org/ergoplatform/ErgoLikeContext.scala
index 8468175631..4b1366d9fd 100644
--- a/interpreter/shared/src/main/scala/org/ergoplatform/ErgoLikeContext.scala
+++ b/interpreter/shared/src/main/scala/org/ergoplatform/ErgoLikeContext.scala
@@ -6,7 +6,6 @@ import sigma.ast.SType.{AnyOps, TypeCode}
import sigma.ast._
import sigma.data.{AvlTreeData, CAvlTree, CSigmaDslBuilder, SigmaConstants}
import sigma.eval.Extensions.toAnyValue
-import sigma.exceptions.InterpreterException
import sigma.interpreter.ContextExtension
import sigma.validation.SigmaValidationSettings
import sigma.{AnyValue, Coll, Header, PreHeader}
@@ -169,7 +168,7 @@ class ErgoLikeContext(val lastBlockUtxoRoot: AvlTreeData,
syntax.error(s"Undefined context property: currentErgoTreeVersion"))
CContext(
dataInputs, headers, preHeader, inputs, outputs, preHeader.height, selfBox, selfIndex, avlTree,
- preHeader.minerPk.getEncoded, vars, activatedScriptVersion, ergoTreeVersion)
+ preHeader.minerPk.getEncoded, vars, spendingTransaction, activatedScriptVersion, ergoTreeVersion)
}
diff --git a/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192.scala b/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192.scala
index bb0ad60a84..e63526e854 100644
--- a/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192.scala
+++ b/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192.scala
@@ -30,8 +30,6 @@ package sigmastate.crypto
import debox.cfor
-import java.util
-
class GF2_192 extends AnyRef {
private[crypto] val word: Array[Long] = new Array[Long](3)
diff --git a/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192_Poly.scala b/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192_Poly.scala
index a9212fe565..d2ddc4db48 100644
--- a/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192_Poly.scala
+++ b/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192_Poly.scala
@@ -31,8 +31,6 @@ package sigmastate.crypto
import debox.cfor
-import java.util
-
class GF2_192_Poly {
final private var c: Array[GF2_192] = null // must be not null and of length at least 1
diff --git a/interpreter/shared/src/main/scala/sigmastate/eval/CContext.scala b/interpreter/shared/src/main/scala/sigmastate/eval/CContext.scala
index 2b076403ad..b0e5b01186 100644
--- a/interpreter/shared/src/main/scala/sigmastate/eval/CContext.scala
+++ b/interpreter/shared/src/main/scala/sigmastate/eval/CContext.scala
@@ -1,8 +1,11 @@
package sigmastate.eval
import debox.cfor
+import org.ergoplatform.{ErgoLikeTransactionTemplate, UnsignedInput}
+import sigma.Evaluation.stypeToRType
import sigma.Extensions.ArrayOps
import sigma._
+import sigma.ast.SType
import sigma.data._
import sigma.exceptions.InvalidType
@@ -24,6 +27,7 @@ case class CContext(
lastBlockUtxoRootHash: AvlTree,
_minerPubKey: Coll[Byte],
vars: Coll[AnyValue],
+ spendingTransaction: ErgoLikeTransactionTemplate[_ <: UnsignedInput],
override val activatedScriptVersion: Byte,
override val currentErgoTreeVersion: Byte
) extends Context {
@@ -69,6 +73,14 @@ case class CContext(
} else None
}
+ override def getVarFromInput[T](inputIndex: Short, id: Byte)(implicit tT: RType[T]): Option[T] = {
+ spendingTransaction.inputs.lift(inputIndex).flatMap(_.extension.get(id)) match {
+ case Some(v) if stypeToRType[SType](v.tpe) == tT => Some(v.value.asInstanceOf[T])
+ case _ =>
+ None
+ }
+ }
+
/** Return a new context instance with variables collection updated.
* @param bindings a new binding of the context variables with new values.
* @return a new instance (if `bindings` non-empty) with the specified bindings.
diff --git a/interpreter/shared/src/main/scala/sigmastate/eval/CHeader.scala b/interpreter/shared/src/main/scala/sigmastate/eval/CHeader.scala
deleted file mode 100644
index 7062fa0f0e..0000000000
--- a/interpreter/shared/src/main/scala/sigmastate/eval/CHeader.scala
+++ /dev/null
@@ -1,34 +0,0 @@
-package sigmastate.eval
-
-import sigma.data.SigmaConstants
-import sigma.{AvlTree, BigInt, Coll, GroupElement, Header}
-
-/** A default implementation of [[Header]] interface.
- *
- * @see [[Header]] for detailed descriptions
- */
-case class CHeader(
- id: Coll[Byte],
- version: Byte,
- parentId: Coll[Byte],
- ADProofsRoot: Coll[Byte],
- stateRoot: AvlTree,
- transactionsRoot: Coll[Byte],
- timestamp: Long,
- nBits: Long,
- height: Int,
- extensionRoot: Coll[Byte],
- minerPk: GroupElement,
- powOnetimePk: GroupElement,
- powNonce: Coll[Byte],
- powDistance: BigInt,
- votes: Coll[Byte]
-) extends Header
-
-object CHeader {
- /** Size of of Header.votes array. */
- val VotesSize: Int = SigmaConstants.VotesArraySize.value
-
- /** Size of nonce array from Autolykos POW solution in Header.powNonce array. */
- val NonceSize: Int = SigmaConstants.AutolykosPowSolutionNonceArraySize.value
-}
\ No newline at end of file
diff --git a/interpreter/shared/src/main/scala/sigmastate/eval/CProfiler.scala b/interpreter/shared/src/main/scala/sigmastate/eval/CProfiler.scala
index ced8a357b8..d07153bd51 100644
--- a/interpreter/shared/src/main/scala/sigmastate/eval/CProfiler.scala
+++ b/interpreter/shared/src/main/scala/sigmastate/eval/CProfiler.scala
@@ -280,7 +280,7 @@ class CProfiler extends Profiler {
case ci: TypeBasedCostItem =>
val comment = s"count: $count, suggested: $suggestedCost, actCost: ${ci.cost}$warn"
(ci.opName, time, time, comment)
- case ci @ SeqCostItem(_, costKind, nItems) =>
+ case ci @ SeqCostItem(_, costKind, _) =>
val nChunks = ci.chunks
val timePerChunk = if (nChunks > 0) time / nChunks else time
val name = s"${ci.opName}(nChunks: $nChunks)"
@@ -289,7 +289,7 @@ class CProfiler extends Profiler {
}
}
(name, timePerItem, time, comment)
- }.sortBy({ case (name, tpi, t, c) => (name, tpi)})(Ordering[(String, Long)])
+ }.sortBy({ case (name, tpi, _, _) => (name, tpi)})(Ordering[(String, Long)])
val estLines = estimationCostStat.mapToArray { case (script, stat) =>
val (cost, count) = stat.mean
@@ -302,7 +302,7 @@ class CProfiler extends Profiler {
val rows = opCodeLines
- .map { case (opName, opCode, time, comment) =>
+ .map { case (opName, _, time, comment) =>
val key = s"$opName".padTo(26, ' ')
s"$key -> time: $time ns, $comment "
}
diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala
index de8aa6b620..a72510f641 100644
--- a/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala
+++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala
@@ -5,15 +5,17 @@ import sigma.ast._
import sigma.ast.syntax._
import sigmastate.eval.{CAvlTreeVerifier, CProfiler}
import sigmastate.interpreter.Interpreter.ReductionResult
-import sigma.{AvlTree, Coll, Colls, Context, VersionContext}
+import sigma.{AvlTree, Coll, Colls, Context, Header, VersionContext}
import sigma.util.Extensions._
import debox.{cfor, Buffer => DBuffer}
import scorex.crypto.authds.ADKey
import sigma.ast.SAvlTreeMethods._
+import sigma.ast.SHeaderMethods.checkPowMethod
import sigma.ast.SType
import sigma.data.{CSigmaProp, KeyValueColl, SigmaBoolean}
import sigma.eval.{AvlTreeVerifier, ErgoTreeEvaluator, EvalSettings, Profiler}
import sigma.eval.ErgoTreeEvaluator.DataEnv
+import sigmastate.interpreter.CErgoTreeEvaluator.fixedCostOp
import scala.collection.compat.immutable.ArraySeq
import scala.util.{DynamicVariable, Failure, Success}
@@ -449,7 +451,7 @@ object CErgoTreeEvaluator {
* HOTSPOT: don't beautify the code
* Note, `null` is used instead of Option to avoid allocations.
*/
- def fixedCostOp[R <: AnyRef](costInfo: OperationCostInfo[FixedCost])
+ def fixedCostOp[R](costInfo: OperationCostInfo[FixedCost])
(block: => R)(implicit E: ErgoTreeEvaluator): R = {
if (E != null) {
var res: R = null.asInstanceOf[R]
diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala
index 6b673038c7..6bdf1656dc 100644
--- a/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala
+++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala
@@ -23,7 +23,7 @@ import sigmastate.interpreter.CErgoTreeEvaluator.fixedCostOp
import sigmastate.interpreter.Interpreter._
import sigma.ast.syntax.ValueOps
import sigma.eval.{EvalSettings, SigmaDsl}
-import sigma.exceptions.{CostLimitException, InterpreterException}
+import sigma.exceptions.InterpreterException
import sigma.interpreter.ProverResult
import sigma.util.CollectionUtil
import sigmastate.utils.Helpers._
@@ -164,12 +164,11 @@ trait Interpreter {
* else `exp` is computed in the given context and the resulting SigmaBoolean returned.
*
* @param context the context in which `exp` should be executed
- * @param env environment of system variables used by the interpreter internally
* @param exp expression to be executed in the given `context`
* @return result of script reduction
* @see `ReductionResult`
*/
- protected def reduceToCryptoJITC(context: CTX, env: ScriptEnv, exp: SigmaPropValue): Try[ReductionResult] = Try {
+ protected def reduceToCryptoJITC(context: CTX, exp: SigmaPropValue): Try[ReductionResult] = Try {
implicit val vs = context.validationSettings
trySoftForkable[ReductionResult](whenSoftFork = WhenSoftForkReductionResult(context.initCost)) {
@@ -248,12 +247,17 @@ trait Interpreter {
val currCost = addCostChecked(context.initCost, deserializeSubstitutionCost, context.costLimit)
val context1 = context.withInitCost(currCost).asInstanceOf[CTX]
val (propTree, context2) = trySoftForkable[(SigmaPropValue, CTX)](whenSoftFork = (TrueSigmaProp, context1)) {
- applyDeserializeContextJITC(context, prop)
+ // Before ErgoTree V3 the deserialization cost was not added to the total cost
+ applyDeserializeContextJITC(if (VersionContext.current.activatedVersion >= VersionContext.V6SoftForkVersion) {
+ context1
+ } else {
+ context
+ }, prop)
}
// here we assume that when `propTree` is TrueProp then `reduceToCrypto` always succeeds
// and the rest of the verification is also trivial
- reduceToCryptoJITC(context2, env, propTree).getOrThrow
+ reduceToCryptoJITC(context2, propTree).getOrThrow
}
res
@@ -594,4 +598,4 @@ object Interpreter {
case x => throw new Error(s"Context-dependent pre-processing should produce tree of type Boolean or SigmaProp but was $x")
}
-}
\ No newline at end of file
+}
diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala
index 15daaec382..dc2259b0b7 100644
--- a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala
+++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala
@@ -81,7 +81,7 @@ trait ProverUtils extends Interpreter {
realSecretsToExtract: Seq[SigmaBoolean],
simulatedSecretsToExtract: Seq[SigmaBoolean] = Seq.empty): HintsBag = {
val reduced = fullReduction(ergoTree, context, Interpreter.emptyEnv)
- bagForMultisig(context, reduced.value, proof, realSecretsToExtract, simulatedSecretsToExtract)
+ bagForMultisig(reduced.value, proof, realSecretsToExtract, simulatedSecretsToExtract)
}
/**
@@ -90,15 +90,13 @@ trait ProverUtils extends Interpreter {
*
* See DistributedSigSpecification for examples of usage.
*
- * @param context - context used to reduce the proposition
* @param sigmaTree - public key (in form of a sigma-tree)
* @param proof - signature for the key
* @param realSecretsToExtract - public keys of secrets with real proofs
* @param simulatedSecretsToExtract - public keys of secrets with simulated proofs
* @return - bag of OtherSecretProven and OtherCommitment hints
*/
- def bagForMultisig(context: CTX,
- sigmaTree: SigmaBoolean,
+ def bagForMultisig(sigmaTree: SigmaBoolean,
proof: Array[Byte],
realSecretsToExtract: Seq[SigmaBoolean],
simulatedSecretsToExtract: Seq[SigmaBoolean]): HintsBag = {
diff --git a/interpreter/shared/src/main/scala/sigmastate/utils/Extensions.scala b/interpreter/shared/src/main/scala/sigmastate/utils/Extensions.scala
index 54abc40f4e..2e66eb6b19 100644
--- a/interpreter/shared/src/main/scala/sigmastate/utils/Extensions.scala
+++ b/interpreter/shared/src/main/scala/sigmastate/utils/Extensions.scala
@@ -13,7 +13,7 @@ object Extensions {
* For example, the Byte value {@code 0x12} would yield the
* byte array {@code {0x12}}.
*/
- def toBytes: Coll[Byte] = SigmaDsl.Colls.fromItems(b)
+ def toBigEndianBytes: Coll[Byte] = SigmaDsl.Colls.fromItems(b)
}
@@ -22,7 +22,7 @@ object Extensions {
* For example, the Short value {@code 0x1213} would yield the
* byte array {@code {0x12, 0x13}}.
*/
- def toBytes: Coll[Byte] = Colls.fromArray(Shorts.toByteArray(x))
+ def toBigEndianBytes: Coll[Byte] = Colls.fromArray(Shorts.toByteArray(x))
}
implicit class IntOpsForSigma(val x: Int) extends AnyVal {
@@ -30,7 +30,7 @@ object Extensions {
* For example, the Int value {@code 0x12131415} would yield the
* byte array {@code {0x12, 0x13, 0x14, 0x15}}.
*/
- def toBytes: Coll[Byte] = Colls.fromArray(Ints.toByteArray(x))
+ def toBigEndianBytes: Coll[Byte] = Colls.fromArray(Ints.toByteArray(x))
}
implicit class LongOpsForSigma(val x: Long) extends AnyVal {
@@ -38,7 +38,7 @@ object Extensions {
* For example, the Long value {@code 0x1213141516171819} would yield the
* byte array {@code {0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19}}.
*/
- def toBytes: Coll[Byte] = Colls.fromArray(Longs.toByteArray(x))
+ def toBigEndianBytes: Coll[Byte] = Colls.fromArray(Longs.toByteArray(x))
}
/** Provides extension methods for `ModifierId` instances.
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/ConstantSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/ConstantSerializerSpecification.scala
index 7bc73643f2..c9478c8356 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/ConstantSerializerSpecification.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/ConstantSerializerSpecification.scala
@@ -9,7 +9,7 @@ import sigma.ast.{BigIntConstant, ByteArrayConstant, Constant, DeserializationSi
import sigmastate.eval._
import sigma.Extensions.ArrayOps
import sigma.ast._
-import sigma.{AvlTree, Colls, Evaluation}
+import sigma.{AvlTree, Colls, Evaluation, Header, VersionContext}
import sigma.ast.SType.AnyOps
import scorex.util.encode.Base16
import sigma.ast.BoolArrayConstant.BoolArrayTypeCode
@@ -17,6 +17,7 @@ import sigma.ast.ByteArrayConstant.ByteArrayTypeCode
import sigma.ast.syntax.{BoolValue, SValue}
import sigma.crypto.EcPointType
import sigma.util.Extensions.{BigIntegerOps, EcpOps, SigmaBooleanOps}
+
import scala.annotation.nowarn
class ConstantSerializerSpecification extends TableSerializationSpecification {
@@ -25,22 +26,29 @@ class ConstantSerializerSpecification extends TableSerializationSpecification {
implicit val wWrapped = wrappedTypeGen(tpe)
implicit val tT = Evaluation.stypeToRType(tpe)
implicit val tag = tT.classTag
+
+ val withVersion = if (tpe == SHeader) {
+ Some(VersionContext.V6SoftForkVersion)
+ } else {
+ None
+ }
+
forAll { xs: Array[T#WrappedType] =>
implicit val tAny = sigma.AnyType
- roundTripTest(Constant[SCollection[T]](xs.toColl, SCollection(tpe)))
- roundTripTest(Constant[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe)))) // pairs are special case
+ roundTripTest(Constant[SCollection[T]](xs.toColl, SCollection(tpe)), withVersion)
+ roundTripTest(Constant[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe))), withVersion) // pairs are special case
val triples = xs.toColl.map(x => TupleColl(x, x, x)).asWrappedType
- roundTripTest(Constant[SType](triples, SCollection(STuple(tpe, tpe, tpe))))
+ roundTripTest(Constant[SType](triples, SCollection(STuple(tpe, tpe, tpe))), withVersion)
val quartets = xs.toColl.map(x => TupleColl(x, x, x, x)).asWrappedType
- roundTripTest(Constant[SType](quartets, SCollection(STuple(tpe, tpe, tpe, tpe))))
- roundTripTest(Constant[SCollection[SCollection[T]]](xs.toColl.map(x => Colls.fromItems(x, x)), SCollection(SCollection(tpe))))
+ roundTripTest(Constant[SType](quartets, SCollection(STuple(tpe, tpe, tpe, tpe))), withVersion)
+ roundTripTest(Constant[SCollection[SCollection[T]]](xs.toColl.map(x => Colls.fromItems(x, x)), SCollection(SCollection(tpe))), withVersion)
roundTripTest(Constant[SType](
xs.toColl.map { x =>
val arr = Colls.fromItems(x, x)
(arr, arr)
}.asWrappedType,
SCollection(STuple(SCollection(tpe), SCollection(tpe)))
- ))
+ ), withVersion)
}
}
@@ -49,19 +57,24 @@ class ConstantSerializerSpecification extends TableSerializationSpecification {
implicit val tT = Evaluation.stypeToRType(tpe)
@nowarn implicit val tag = tT.classTag
implicit val tAny: RType[Any] = sigma.AnyType
+ val withVersion = if (tpe == SHeader) {
+ Some(VersionContext.V6SoftForkVersion)
+ } else {
+ None
+ }
forAll { in: (T#WrappedType, T#WrappedType) =>
val (x,y) = (in._1, in._2)
- roundTripTest(Constant[SType]((x, y).asWrappedType, STuple(tpe, tpe)))
- roundTripTest(Constant[SType](TupleColl(x, y, x).asWrappedType, STuple(tpe, tpe, tpe)))
- roundTripTest(Constant[SType](TupleColl(x, y, x, y).asWrappedType, STuple(tpe, tpe, tpe, tpe)))
- roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, (x, y)), STuple(tpe, tpe, STuple(tpe, tpe))))
- roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, x)), STuple(tpe, tpe, STuple(tpe, tpe, tpe))))
- roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, (x, y))), STuple(tpe, tpe, STuple(tpe, tpe, STuple(tpe, tpe)))))
+ roundTripTest(Constant[SType]((x, y).asWrappedType, STuple(tpe, tpe)), withVersion)
+ roundTripTest(Constant[SType](TupleColl(x, y, x).asWrappedType, STuple(tpe, tpe, tpe)), withVersion)
+ roundTripTest(Constant[SType](TupleColl(x, y, x, y).asWrappedType, STuple(tpe, tpe, tpe, tpe)), withVersion)
+ roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, (x, y)), STuple(tpe, tpe, STuple(tpe, tpe))), withVersion)
+ roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, x)), STuple(tpe, tpe, STuple(tpe, tpe, tpe))), withVersion)
+ roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, (x, y))), STuple(tpe, tpe, STuple(tpe, tpe, STuple(tpe, tpe)))), withVersion)
}
}
property("Constant serialization round trip") {
- forAll { x: Unit => roundTripTest(UnitConstant()) }
+ forAll { _: Unit => roundTripTest(UnitConstant()) }
forAll { x: Byte => roundTripTest(Constant[SByte.type](x, SByte)) }
forAll { x: Boolean => roundTripTest(BooleanConstant.fromBoolean(x)) }
forAll { x: Long => roundTripTest(Constant[SLong.type](x, SLong)) }
@@ -71,6 +84,7 @@ class ConstantSerializerSpecification extends TableSerializationSpecification {
forAll { x: SigmaBoolean => roundTripTest(Constant[SSigmaProp.type](x.toSigmaProp, SSigmaProp)) }
forAll { x: ErgoBox => roundTripTest(Constant[SBox.type](x, SBox)) }
forAll { x: AvlTree => roundTripTest(Constant[SAvlTree.type](x, SAvlTree)) }
+ forAll { x: Header => roundTripTest(Constant[SHeader.type](x, SHeader), Some(VersionContext.V6SoftForkVersion)) }
forAll { x: Array[Byte] => roundTripTest(Constant[SByteArray](x.toColl, SByteArray)) }
forAll { t: SPredefType => testCollection(t) }
forAll { t: SPredefType => testTuples(t) }
@@ -88,6 +102,7 @@ class ConstantSerializerSpecification extends TableSerializationSpecification {
testCollection(SUnit)
testCollection(SBox)
testCollection(SAvlTree)
+ testCollection(SHeader)
}
private def caseObjectValue(v: SValue) = (v, Array[Byte](v.opCode))
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/DataSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/DataSerializerSpecification.scala
index ecb2d2ef70..fe6f62dbe0 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/DataSerializerSpecification.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/DataSerializerSpecification.scala
@@ -3,11 +3,10 @@ package sigma.serialization
import java.math.BigInteger
import org.ergoplatform.ErgoBox
import org.scalacheck.Arbitrary._
-import sigma.data.{DataValueComparer, RType, SigmaBoolean, TupleColl}
+import sigma.data.{CBigInt, CHeader, DataValueComparer, OptionType, RType, SigmaBoolean, TupleColl}
import sigma.ast.SCollection.SByteArray
-import sigmastate._
import sigmastate.eval._
-import sigma.{AvlTree, Colls, Evaluation}
+import sigma.{AvlTree, Colls, Evaluation, Header, VersionContext}
import sigma.ast.SType.AnyOps
import sigma.ast._
import org.scalacheck.Gen
@@ -15,7 +14,7 @@ import sigma.Extensions.ArrayOps
import sigma.crypto.EcPointType
import sigma.eval.SigmaDsl
import sigma.util.Extensions.{BigIntegerOps, EcpOps, SigmaBooleanOps}
-import sigmastate.interpreter.{CostAccumulator, CErgoTreeEvaluator}
+import sigmastate.interpreter.{CErgoTreeEvaluator, CostAccumulator}
import sigmastate.interpreter.CErgoTreeEvaluator.DefaultProfiler
import sigmastate.utils.Helpers
@@ -24,29 +23,41 @@ import scala.reflect.ClassTag
class DataSerializerSpecification extends SerializationSpecification {
- def roundtrip[T <: SType](obj: T#WrappedType, tpe: T) = {
- val w = SigmaSerializer.startWriter()
- DataSerializer.serialize(obj, tpe, w)
- val bytes = w.toBytes
- val r = SigmaSerializer.startReader(bytes)
- val res = DataSerializer.deserialize(tpe, r)
- res shouldBe obj
-
- val es = CErgoTreeEvaluator.DefaultEvalSettings
- val accumulator = new CostAccumulator(
- initialCost = JitCost(0),
- costLimit = Some(JitCost.fromBlockCost(es.scriptCostLimitInEvaluator)))
- val evaluator = new CErgoTreeEvaluator(
- context = null,
- constants = ErgoTree.EmptyConstants,
- coster = accumulator, DefaultProfiler, es)
- val ok = DataValueComparer.equalDataValues(res, obj)(evaluator)
- ok shouldBe true
-
- val randomPrefix = arrayGen[Byte].sample.get
- val r2 = SigmaSerializer.startReader(randomPrefix ++ bytes, randomPrefix.length)
- val res2 = DataSerializer.deserialize(tpe, r2)
- res2 shouldBe obj
+ def roundtrip[T <: SType](obj: T#WrappedType, tpe: T, withVersion: Option[Byte] = None) = {
+
+ def test() = {
+ val w = SigmaSerializer.startWriter()
+ DataSerializer.serialize(obj, tpe, w)
+ val bytes = w.toBytes
+ val r = SigmaSerializer.startReader(bytes)
+ val res = DataSerializer.deserialize(tpe, r)
+ res shouldBe obj
+
+ val es = CErgoTreeEvaluator.DefaultEvalSettings
+ val accumulator = new CostAccumulator(
+ initialCost = JitCost(0),
+ costLimit = Some(JitCost.fromBlockCost(es.scriptCostLimitInEvaluator)))
+ val evaluator = new CErgoTreeEvaluator(
+ context = null,
+ constants = ErgoTree.EmptyConstants,
+ coster = accumulator, DefaultProfiler, es)
+ val ok = DataValueComparer.equalDataValues(res, obj)(evaluator)
+ ok shouldBe true
+
+ val randomPrefix = arrayGen[Byte].sample.get
+ val r2 = SigmaSerializer.startReader(randomPrefix ++ bytes, randomPrefix.length)
+ val res2 = DataSerializer.deserialize(tpe, r2)
+ res2 shouldBe obj
+ }
+
+ withVersion match {
+ case Some(ver) =>
+ VersionContext.withVersions(ver, 1) {
+ test()
+ }
+ case None =>
+ test()
+ }
}
def testCollection[T <: SType](tpe: T) = {
@@ -54,25 +65,32 @@ class DataSerializerSpecification extends SerializationSpecification {
implicit val tT = Evaluation.stypeToRType(tpe)
implicit val tagT = tT.classTag
implicit val tAny = sigma.AnyType
+
+ val withVersion = if (tpe == SHeader) {
+ Some(VersionContext.V6SoftForkVersion)
+ } else {
+ None
+ }
forAll { xs: Array[T#WrappedType] =>
- roundtrip[SCollection[T]](xs.toColl, SCollection(tpe))
- roundtrip[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe)))
+ roundtrip[SCollection[T]](xs.toColl, SCollection(tpe), withVersion)
+ roundtrip[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe)), withVersion)
val triples = xs.toColl.map(x => TupleColl(x, x, x)).asWrappedType
- roundtrip(triples, SCollection(STuple(tpe, tpe, tpe)))
+ roundtrip(triples, SCollection(STuple(tpe, tpe, tpe)), withVersion)
val quartets = xs.toColl.map(x => TupleColl(x, x, x, x)).asWrappedType
- roundtrip(quartets, SCollection(STuple(tpe, tpe, tpe, tpe)))
+ roundtrip(quartets, SCollection(STuple(tpe, tpe, tpe, tpe)), withVersion)
val nested = xs.toColl.map(x => Colls.fromItems[T#WrappedType](x, x))
- roundtrip[SCollection[SCollection[T]]](nested, SCollection(SCollection(tpe)))
+ roundtrip[SCollection[SCollection[T]]](nested, SCollection(SCollection(tpe)), withVersion)
roundtrip[SType](
xs.toColl.map { x =>
val arr = Colls.fromItems[T#WrappedType](x, x)
(arr, arr)
}.asWrappedType,
- SCollection(STuple(SCollection(tpe), SCollection(tpe)))
+ SCollection(STuple(SCollection(tpe), SCollection(tpe))),
+ withVersion
)
}
}
@@ -82,14 +100,45 @@ class DataSerializerSpecification extends SerializationSpecification {
val tT = Evaluation.stypeToRType(tpe)
@nowarn implicit val tag: ClassTag[T#WrappedType] = tT.classTag
implicit val tAny : RType[Any] = sigma.AnyType
+ val withVersion = if (tpe == SHeader) {
+ Some(VersionContext.V6SoftForkVersion)
+ } else {
+ None
+ }
forAll { in: (T#WrappedType, T#WrappedType) =>
val (x,y) = (in._1, in._2)
- roundtrip[SType]((x, y).asWrappedType, STuple(tpe, tpe))
- roundtrip[SType](TupleColl(x, y, x).asWrappedType, STuple(tpe, tpe, tpe))
- roundtrip[SType](TupleColl(x, y, x, y).asWrappedType, STuple(tpe, tpe, tpe, tpe))
- roundtrip[STuple](Colls.fromItems[Any](x, y, (x, y)), STuple(tpe, tpe, STuple(tpe, tpe)))
- roundtrip[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, x)), STuple(tpe, tpe, STuple(tpe, tpe, tpe)))
- roundtrip[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, (x, y))), STuple(tpe, tpe, STuple(tpe, tpe, STuple(tpe, tpe))))
+ roundtrip[SType]((x, y).asWrappedType, STuple(tpe, tpe), withVersion)
+ roundtrip[SType](TupleColl(x, y, x).asWrappedType, STuple(tpe, tpe, tpe), withVersion)
+ roundtrip[SType](TupleColl(x, y, x, y).asWrappedType, STuple(tpe, tpe, tpe, tpe), withVersion)
+ roundtrip[STuple](Colls.fromItems[Any](x, y, (x, y)), STuple(tpe, tpe, STuple(tpe, tpe)), withVersion)
+ roundtrip[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, x)), STuple(tpe, tpe, STuple(tpe, tpe, tpe)), withVersion)
+ roundtrip[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, (x, y))), STuple(tpe, tpe, STuple(tpe, tpe, STuple(tpe, tpe))), withVersion)
+ }
+ }
+
+ def testOption[T <: SType](tpe: T) = {
+ implicit val wWrapped: Gen[T#WrappedType] = wrappedTypeGen(tpe)
+ val tT = Evaluation.stypeToRType(tpe)
+
+ an[Exception] should be thrownBy (
+ VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
+ forAll { in: T#WrappedType =>
+ roundtrip[SType](Some(in).asWrappedType, SOption(tpe))
+ roundtrip[SOption[SCollection[T]]](Some(Colls.fromItems(in)(tT)), SOption(SCollectionType(tpe)))
+ }
+ })
+
+ VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
+ forAll { in: T#WrappedType =>
+ roundtrip[SType](Some(in).asWrappedType, SOption(tpe))
+ roundtrip[SOption[T]](None, SOption(tpe))
+ roundtrip[SOption[T]](Some(in), SOption(tpe))
+ roundtrip[SOption[SCollection[T]]](Some(Colls.fromItems(in)(tT)), SOption(SCollectionType(tpe)))
+ roundtrip[SCollection[SOption[T]]](Colls.fromItems(Option(in), None.asInstanceOf[Option[T#WrappedType]])(OptionType(tT)), SCollectionType(SOption(tpe)))
+ roundtrip[SOption[SOption[T]]](None, SOption(SOption(tpe)))
+ roundtrip[SOption[SOption[T]]](Some(Some(in)), SOption(SOption(tpe)))
+ roundtrip[SOption[SOption[T]]](Some(None), SOption(SOption(tpe)))
+ }
}
}
@@ -104,8 +153,10 @@ class DataSerializerSpecification extends SerializationSpecification {
forAll { x: ErgoBox => roundtrip[SBox.type](x, SBox) }
forAll { x: AvlTree => roundtrip[SAvlTree.type](x, SAvlTree) }
forAll { x: Array[Byte] => roundtrip[SByteArray](x.toColl, SByteArray) }
+ forAll { x: Header => roundtrip[SHeader.type](x, SHeader, Some(VersionContext.V6SoftForkVersion)) }
forAll { t: SPredefType => testCollection(t) }
forAll { t: SPredefType => testTuples(t) }
+ forAll { t: SPredefType => testOption(t) }
}
property("Should check limits and fail") {
@@ -133,6 +184,42 @@ class DataSerializerSpecification extends SerializationSpecification {
t.isInstanceOf[SerializerException] &&
t.getMessage.contains(s"BigInt value doesn't not fit into ${SBigInt.MaxSizeInBytes} bytes")
})
+ }
+
+ property("nuanced versioned test for header roundtrip") {
+ VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
+ forAll { x: Header => roundtrip[SHeader.type](x, SHeader) }
+ }
+
+ an[SerializerException] should be thrownBy (
+ VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
+ val h = headerGen.sample.get
+ roundtrip[SHeader.type](h, SHeader)
+ })
+ }
+ property("header vector") {
+ val header = CHeader(
+ 0.toByte,
+ Helpers.decodeBytes("7a7fe5347f09017818010062000001807f86808000ff7f66ffb07f7ad27f3362"),
+ Helpers.decodeBytes("c1d70ad9b1ffc1fb9a715fff19807f2401017fcd8b73db017f1cff77727fff08"),
+ Helpers.decodeBytes("54d23dd080006bdb56800100356080935a80ffb77e90b800057f00661601807f17"),
+ Helpers.decodeBytes("5e7f1164ccd0990080c501fc0e0181cb387fc17f00ff00c7d5ff767f91ff5e68"),
+ -7421721754642387858L,
+ -4826493284887861030L,
+ 10,
+ Helpers.decodeBytes("e580c88001ff6fc89c5501017f80e001ff0101fe48c153ff7f00666b80d780ab"),
+ Helpers.decodeGroupElement("03e7f2875298fddd933c2e0a38968fe85bdeeb70dd8b389559a1d36e2ff1b58fc5"),
+ Helpers.decodeGroupElement("034e2d3b5f9e409e3ae8a2e768340760362ca33764eda5855f7a43487f14883300"),
+ Helpers.decodeBytes("974651c9efff7f00"),
+ CBigInt(new BigInteger("478e827dfa1e4b57", 16)),
+ Helpers.decodeBytes("01ff13"),
+ Colls.emptyColl
+ )
+
+ VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
+ roundtrip[SHeader.type](header, SHeader)
+ }
}
+
}
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala
index ac9c997d98..793d3df959 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala
@@ -1,6 +1,9 @@
package sigma.serialization
+import sigma.VersionContext
+import sigma.ast.SCollection.SByteArray
import sigma.ast._
+import sigma.validation.ValidationException
class MethodCallSerializerSpecification extends SerializationSpecification {
@@ -21,4 +24,48 @@ class MethodCallSerializerSpecification extends SerializationSpecification {
)
roundTripTest(expr)
}
+
+ property("MethodCall deserialization round trip for Header.checkPow") {
+ def code = {
+ val bi = HeaderConstant(headerGen.sample.get)
+ val expr = MethodCall(bi,
+ SHeaderMethods.checkPowMethod,
+ Vector(),
+ Map()
+ )
+ roundTripTest(expr)
+ }
+
+ VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
+ code
+ }
+
+ an[Exception] should be thrownBy (
+ VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
+ code
+ }
+ )
+ }
+
+ property("MethodCall deserialization round trip for Global.serialize") {
+ def code = {
+ val b = ByteArrayConstant(Array(1.toByte, 2.toByte, 3.toByte))
+ val expr = MethodCall(Global,
+ SGlobalMethods.serializeMethod.withConcreteTypes(Map(STypeVar("T") -> SByteArray)),
+ Vector(b),
+ Map()
+ )
+ roundTripTest(expr)
+ }
+
+ VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
+ code
+ }
+
+ an[Exception] should be thrownBy (
+ VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
+ code
+ })
+ }
+
}
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/SerializationSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/SerializationSpecification.scala
index 30ae6af19b..aa7a8722ba 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/SerializationSpecification.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/SerializationSpecification.scala
@@ -8,6 +8,7 @@ import org.scalacheck.Arbitrary._
import org.scalatest.matchers.should.Matchers
import org.scalatest.propspec.AnyPropSpec
import org.scalatestplus.scalacheck.{ScalaCheckDrivenPropertyChecks, ScalaCheckPropertyChecks}
+import sigma.VersionContext
import sigma.ast.SType
import sigma.ast._
import sigmastate.helpers.NegativeTesting
@@ -26,10 +27,20 @@ trait SerializationSpecification extends AnyPropSpec
with ValidationSpecification
with NegativeTesting {
- protected def roundTripTest[V <: Value[_ <: SType]](v: V): Assertion = {
- val bytes = ValueSerializer.serialize(v)
- predefinedBytesTest(v, bytes)
- predefinedBytesTestNotFomZeroElement(bytes, v)
+ protected def roundTripTest[V <: Value[_ <: SType]](v: V, withVersion: Option[Byte] = None): Assertion = {
+ def test() = {
+ val bytes = ValueSerializer.serialize(v)
+ predefinedBytesTest(v, bytes)
+ predefinedBytesTestNotFomZeroElement(bytes, v)
+ }
+ withVersion match {
+ case Some(ver) =>
+ VersionContext.withVersions(ver, 0) {
+ test()
+ }
+ case None =>
+ test()
+ }
}
protected def predefinedBytesTest[V <: Value[_ <: SType]](v: V, bytes: Array[Byte]): Assertion = {
@@ -41,7 +52,7 @@ trait SerializationSpecification extends AnyPropSpec
r.positionLimit shouldBe positionLimitBefore
}
- //check that pos and consumed are being implented correctly
+ //check that pos and consumed are being implemented correctly
protected def predefinedBytesTestNotFomZeroElement[V <: Value[_ <: SType]](bytes: Array[Byte], v: V): Assertion = {
val randomInt = Gen.chooseNum(1, 20).sample.get
val randomBytes = Gen.listOfN(randomInt, arbByte.arbitrary).sample.get.toArray
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala b/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala
index d4971f88c2..db6cd87330 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala
@@ -8,7 +8,6 @@ import org.scalacheck.Arbitrary._
import org.scalacheck.Gen.{choose, frequency}
import org.scalacheck.util.Buildable
import org.scalacheck.{Arbitrary, Gen}
-import sigma.data._
import scorex.crypto.authds.{ADDigest, ADKey}
import scorex.util.encode.{Base58, Base64}
import scorex.util.{ModifierId, bytesToId}
@@ -27,6 +26,7 @@ import sigma.util.Extensions.EcpOps
import sigma.validation.{ChangedRule, DisabledRule, EnabledRule, ReplacedRule, RuleStatus}
import sigma.validation.ValidationRules.FirstRuleId
import ErgoTree.ZeroHeader
+import sigma.data.{AvlTreeData, AvlTreeFlags, CAND, CBox, CHeader, COR, CTHRESHOLD, Digest32Coll, ProveDHTuple, ProveDlog, RType, SigmaBoolean}
import sigma.eval.Extensions.{EvalIterableOps, SigmaBooleanOps}
import sigma.eval.SigmaDsl
import sigma.interpreter.{ContextExtension, ProverResult}
@@ -311,6 +311,7 @@ trait ObjectGenerators extends TypeGenerators
case SAvlTree => arbAvlTree
case SAny => arbAnyVal
case SUnit => arbUnit
+ case SHeader => arbHeader
case opt: SOption[a] =>
Arbitrary(frequency((5, None), (5, for (x <- wrappedTypeGen(opt.elemType)) yield Some(x))))
}).asInstanceOf[Arbitrary[T#WrappedType]].arbitrary
@@ -694,7 +695,6 @@ trait ObjectGenerators extends TypeGenerators
} yield ErgoTree.withSegregation(ZeroHeader, prop)
def headerGen(stateRoot: AvlTree, parentId: Coll[Byte]): Gen[Header] = for {
- id <- modifierIdBytesGen
version <- arbByte.arbitrary
adProofsRoot <- digest32Gen
transactionRoot <- digest32Gen
@@ -707,8 +707,10 @@ trait ObjectGenerators extends TypeGenerators
powNonce <- nonceBytesGen
powDistance <- arbBigInt.arbitrary
votes <- minerVotesGen
- } yield CHeader(id, version, parentId, adProofsRoot, stateRoot, transactionRoot, timestamp, nBits,
- height, extensionRoot, minerPk.toGroupElement, powOnetimePk.toGroupElement, powNonce, powDistance, votes)
+ unparsedBytes <- collOfRange(0, 32, arbByte.arbitrary)
+ } yield CHeader(version, parentId, adProofsRoot, stateRoot.digest, transactionRoot, timestamp, nBits,
+ height, extensionRoot, minerPk.toGroupElement, powOnetimePk.toGroupElement, powNonce, powDistance, votes,
+ if(version > HeaderVersion.Interpreter60Version){ unparsedBytes } else {Colls.emptyColl[Byte]})
lazy val headerGen: Gen[Header] = for {
stateRoot <- avlTreeGen
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala b/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala
index 81073c4849..70a215e831 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala
@@ -16,12 +16,13 @@ trait TypeGenerators {
implicit val boxTypeGen: Gen[SBox.type] = Gen.const(SBox)
implicit val avlTreeTypeGen: Gen[SAvlTree.type] = Gen.const(SAvlTree)
implicit val optionSigmaPropTypeGen: Gen[SOption[SSigmaProp.type]] = Gen.const(SOption(SSigmaProp))
+ implicit val headerTypeGen: Gen[SHeader.type] = Gen.const(SHeader)
implicit val primTypeGen: Gen[SPrimType] =
Gen.oneOf[SPrimType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnit)
implicit val arbPrimType: Arbitrary[SPrimType] = Arbitrary(primTypeGen)
implicit val predefTypeGen: Gen[SPredefType] =
- Gen.oneOf[SPredefType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnit, SBox, SAvlTree)
+ Gen.oneOf[SPredefType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnit, SBox, SAvlTree, SHeader)
implicit val arbPredefType: Arbitrary[SPredefType] = Arbitrary(predefTypeGen)
implicit def genToArbitrary[T: Gen]: Arbitrary[T] = Arbitrary(implicitly[Gen[T]])
diff --git a/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala b/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala
index ba996b0246..e9ba273e17 100644
--- a/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala
+++ b/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala
@@ -3,16 +3,15 @@ package sigmastate.eval
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import sigma.crypto.SecP256K1Group
-import sigma.data.{CSigmaDslBuilder, TrivialProp}
+import sigma.data.{CSigmaDslBuilder => SigmaDsl, TrivialProp}
import sigma.util.Extensions.SigmaBooleanOps
import java.math.BigInteger
-import sigma.{ContractsTestkit, SigmaDslBuilder, SigmaProp}
+import sigma.{ContractsTestkit, SigmaProp}
import scala.language.implicitConversions
class BasicOpsTests extends AnyFunSuite with ContractsTestkit with Matchers {
- override val SigmaDsl: SigmaDslBuilder = CSigmaDslBuilder
implicit def boolToSigma(b: Boolean): SigmaProp = TrivialProp(b).toSigmaProp
@@ -60,7 +59,7 @@ class BasicOpsTests extends AnyFunSuite with ContractsTestkit with Matchers {
}
test("box.creationInfo._1 is Int") {
- val box = newAliceBox(1, 100)
+ val box = newAliceBox(100)
box.creationInfo._1 shouldBe a [Integer]
}
diff --git a/interpreter/shared/src/test/scala/special/sigma/ContractsTestkit.scala b/interpreter/shared/src/test/scala/special/sigma/ContractsTestkit.scala
index 720223ee3a..ba04df1347 100644
--- a/interpreter/shared/src/test/scala/special/sigma/ContractsTestkit.scala
+++ b/interpreter/shared/src/test/scala/special/sigma/ContractsTestkit.scala
@@ -8,43 +8,18 @@ import sigmastate.eval._
import sigmastate.helpers.TestingHelpers._
import sigma.data._
-import scala.annotation.nowarn // imports implicit ClassTag
-
trait ContractsTestkit {
- val R0 = 0.toByte;
- val R1 = 1.toByte;
- val R2 = 2.toByte;
- val R3 = 3.toByte;
- val R4 = 4.toByte;
- val R5 = 5.toByte;
- val R6 = 6.toByte;
- val R7 = 7.toByte;
- val R8 = 8.toByte;
- val R9 = 9.toByte;
+
val Colls = new CollOverArrayBuilder
- val SigmaDsl: SigmaDslBuilder = CSigmaDslBuilder
- val noRegisters = collection[AnyValue]()
- val noBytes = collection[Byte]()
val noInputs = Array[Box]()
val noOutputs = Array[Box]()
val dummyPubkey: Array[Byte] = Array.fill(32)(0: Byte)
- val dummyADDigest: Coll[Byte] = Colls.fromArray(Array.fill(33)(0: Byte))
val emptyAvlTree = new CAvlTree(AvlTreeData.dummy)
val noHeaders = CSigmaDslBuilder.Colls.emptyColl[Header]
val dummyPreHeader: PreHeader = null
/** Create collection from array of items */
- def collection[T: RType](items: T*) = Colls.fromArray(items.toArray)
-
- /** Converts a map of registers to collection of registers. */
- def regs(m: Map[Byte, AnyValue]): Coll[AnyValue] = {
- val res = new Array[AnyValue](10)
- for ( (id, v) <- m ) {
- assert(res(id) == null, s"register $id is defined more then once")
- res(id) = v
- }
- Colls.fromArray(res)
- }
+ def collection[T: RType](items: T*): Coll[T] = Colls.fromArray(items.toArray)
/** Converts a map of context vars to collection of context vars. */
def contextVars(m: Map[Byte, AnyValue]): Coll[AnyValue] = {
@@ -58,9 +33,7 @@ trait ContractsTestkit {
Colls.fromArray(res)
}
- val AliceId = Array[Byte](1) // 0x0001
-
- def newAliceBox(@nowarn id: Byte, value: Long): Box = {
+ def newAliceBox(value: Long): Box = {
val ergoBox = testBox(value,
ErgoTree.fromProposition(TrueSigmaProp),
creationHeight = 0, additionalTokens = Seq(), additionalRegisters = Map())
@@ -74,7 +47,7 @@ trait ContractsTestkit {
new CContext(
noInputs.toColl, noHeaders, dummyPreHeader,
inputs.toColl, outputs.toColl, height, self, inputs.indexOf(self), tree,
- minerPk.toColl, vars.toColl, activatedScriptVersion, currErgoTreeVersion)
+ minerPk.toColl, vars.toColl, null, activatedScriptVersion, currErgoTreeVersion)
def newContext(
height: Int,
@@ -90,8 +63,6 @@ trait ContractsTestkit {
implicit class TestContextOps(ctx: CContext) {
def withInputs(inputs: Box*) = ctx.copy(inputs = inputs.toArray.toColl)
- def withOutputs(outputs: Box*) = ctx.copy(outputs = outputs.toArray.toColl)
-
def withVariables(vars: Map[Int, AnyValue]) =
ctx.copy(vars = contextVars(vars.map { case (k, v) => (k.toByte, v) }))
}
diff --git a/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala b/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala
index d33f09dd80..b8bf76cacf 100644
--- a/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala
+++ b/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala
@@ -12,7 +12,7 @@ import scorex.crypto.hash.{Blake2b256, Digest32}
import scorex.util.ModifierId
import sigma.ast._
import sigma.Extensions.ArrayOps
-import sigmastate.eval.{CHeader, CPreHeader}
+import sigmastate.eval.CPreHeader
import sigmastate.helpers.TestingCommons
import sigma.serialization.ErgoTreeSerializer
import sigma.serialization.generators.ObjectGenerators
@@ -30,13 +30,6 @@ trait SigmaTestingData extends TestingCommons with ObjectGenerators {
def Coll[T](items: T*)(implicit cT: RType[T]): Coll[T] =
CSigmaDslBuilder.Colls.fromItems(items: _*)
- /** Generator of random collection with `n` elements. */
- def collOfN[T: RType : Arbitrary](n: Int)
- (implicit b: Buildable[T, Array[T]]): Gen[Coll[T]] = {
- implicit val g: Gen[T] = Arbitrary.arbitrary[T]
- containerOfN[Array, T](n, g).map(Colls.fromArray(_))
- }
-
val bytesGen: Gen[Array[Byte]] = for {
len <- Gen.choose(0, 100)
arr <- containerOfN[Array, Byte](len, Arbitrary.arbByte.arbitrary)
@@ -54,63 +47,9 @@ trait SigmaTestingData extends TestingCommons with ObjectGenerators {
res
}
- protected def sampleAvlProver = {
- val keys = arrayOfN(100, keyCollGen).sample.get
- val values = arrayOfN(100, bytesCollGen).sample.get
- val (tree, prover) = createAvlTreeAndProver(keys.zip(values): _*)
- (keys, values, tree, prover)
- }
-
- protected def sampleAvlTree: AvlTree = {
- val (_, _, _, avlProver) = sampleAvlProver
- val digest = avlProver.digest.toColl
- val tree = SigmaDsl.avlTree(AvlTreeFlags.ReadOnly.serializeToByte, digest, 32, None)
- tree
- }
-
val tokenId1: Digest32 = Blake2b256("id1")
val tokenId2: Digest32 = Blake2b256("id2")
- val header1: Header = CHeader(Blake2b256("Header.id").toColl,
- 0,
- Blake2b256("Header.parentId").toColl,
- Blake2b256("ADProofsRoot").toColl,
- sampleAvlTree,
- Blake2b256("transactionsRoot").toColl,
- timestamp = 0,
- nBits = 0,
- height = 0,
- extensionRoot = Blake2b256("transactionsRoot").toColl,
- minerPk = SigmaDsl.groupGenerator,
- powOnetimePk = SigmaDsl.groupGenerator,
- powNonce = Colls.fromArray(Array[Byte](0, 1, 2, 3, 4, 5, 6, 7)),
- powDistance = SigmaDsl.BigInt(BigInt("1405498250268750867257727119510201256371618473728619086008183115260323").bigInteger),
- votes = Colls.fromArray(Array[Byte](0, 1, 2))
- )
- val header2: Header = CHeader(Blake2b256("Header2.id").toColl,
- 0,
- header1.id,
- Blake2b256("ADProofsRoot2").toColl,
- sampleAvlTree,
- Blake2b256("transactionsRoot2").toColl,
- timestamp = 2,
- nBits = 0,
- height = 1,
- extensionRoot = Blake2b256("transactionsRoot2").toColl,
- minerPk = SigmaDsl.groupGenerator,
- powOnetimePk = SigmaDsl.groupGenerator,
- powNonce = Colls.fromArray(Array.fill(0.toByte)(8)),
- powDistance = SigmaDsl.BigInt(BigInt("19306206489815517413186395405558417825367537880571815686937307203793939").bigInteger),
- votes = Colls.fromArray(Array[Byte](0, 1, 0))
- )
- val headers = Colls.fromItems(header2, header1)
- val preHeader: PreHeader = CPreHeader(0,
- header2.id,
- timestamp = 3,
- nBits = 0,
- height = 2,
- minerPk = SigmaDsl.groupGenerator,
- votes = Colls.emptyColl[Byte]
- )
+
object TestData {
val BigIntZero: BigInt = CBigInt(new BigInteger("0", 16))
@@ -301,17 +240,16 @@ trait SigmaTestingData extends TestingCommons with ObjectGenerators {
def createAvlTreeData() = AvlTreeData(
ErgoAlgos.decodeUnsafe("010180017f7f7b7f720c00007f7f7f0f01e857a626f37f1483d06af8077a008080").toColl,
- AvlTreeFlags(false, true, false),
- 728138553,
- Some(2147483647)
+ AvlTreeFlags(true, true, true),
+ 32,
+ None
)
val h1_instances = new CloneSet(1000, CHeader(
- Helpers.decodeBytes("957f008001808080ffe4ffffc8f3802401df40006aa05e017fa8d3f6004c804a"),
0.toByte,
Helpers.decodeBytes("0180dd805b0000ff5400b997fd7f0b9b00de00fb03c47e37806a8186b94f07ff"),
Helpers.decodeBytes("01f07f60d100ffb970c3007f60ff7f24d4070bb8fffa7fca7f34c10001ffe39d"),
- CAvlTree(createAvlTreeData()),
+ CAvlTree(createAvlTreeData()).digest,
Helpers.decodeBytes("804101ff01000080a3ffbd006ac080098df132a7017f00649311ec0e00000100"),
1L,
-1L,
@@ -321,14 +259,15 @@ trait SigmaTestingData extends TestingCommons with ObjectGenerators {
Helpers.decodeGroupElement("0361299207fa392231e23666f6945ae3e867b978e021d8d702872bde454e9abe9c"),
Helpers.decodeBytes("7f4f09012a807f01"),
CBigInt(new BigInteger("-e24990c47e15ed4d0178c44f1790cc72155d516c43c3e8684e75db3800a288", 16)),
- Helpers.decodeBytes("7f0180")
+ Helpers.decodeBytes("7f0180"),
+ Colls.emptyColl[Byte]
))
def create_h1(): Header = h1_instances.getNext
val h1: Header = create_h1()
- val h2: Header = create_h1().asInstanceOf[CHeader].copy(height = 2)
+ val h2: Header = new CHeader(h1.asInstanceOf[CHeader].wrappedValue.copy(height = 2))
val dlog_instances = new CloneSet(1000, ProveDlog(
SigmaDsl.toECPoint(create_ge1()).asInstanceOf[EcPointType]
diff --git a/parsers/shared/src/main/scala/sigmastate/lang/ContractParser.scala b/parsers/shared/src/main/scala/sigmastate/lang/ContractParser.scala
index 87dd20ab0c..a192a789b9 100644
--- a/parsers/shared/src/main/scala/sigmastate/lang/ContractParser.scala
+++ b/parsers/shared/src/main/scala/sigmastate/lang/ContractParser.scala
@@ -3,7 +3,7 @@ package sigmastate.lang
import fastparse._
import fastparse.NoWhitespace._
import SigmaParser._
-import sigma.ast.SType
+import sigma.ast.{Constant, SType}
import sigma.ast.syntax.SValue
import sigmastate.lang.parsers.Basic
@@ -187,9 +187,9 @@ object ContractParser {
def annotation[_: P] = P("@contract")
- def paramDefault[_: P] = P(WL.? ~ `=` ~ WL.? ~ ExprLiteral).map(s => s.asWrappedType)
+ def paramDefault[_: P] = P(WL.? ~ `=` ~ WL.? ~ ExprLiteral)
- def param[_: P] = P(WL.? ~ Id.! ~ ":" ~ Type ~ paramDefault.?).map(s => ContractParam(s._1, s._2, s._3))
+ def param[_: P] = P(WL.? ~ Id.! ~ ":" ~ Type ~ paramDefault.?).map(s => ContractParam(s._1, s._2, s._3.map(_.value)))
def params[_: P] = P("(" ~ param.rep(1, ",").? ~ ")")
}
diff --git a/sc/shared/src/test/scala/sigmastate/helpers/SigmaPPrint.scala b/parsers/shared/src/test/scala/sigmastate/helpers/SigmaPPrint.scala
similarity index 98%
rename from sc/shared/src/test/scala/sigmastate/helpers/SigmaPPrint.scala
rename to parsers/shared/src/test/scala/sigmastate/helpers/SigmaPPrint.scala
index 1b0f7b112d..11381e1ac3 100644
--- a/sc/shared/src/test/scala/sigmastate/helpers/SigmaPPrint.scala
+++ b/parsers/shared/src/test/scala/sigmastate/helpers/SigmaPPrint.scala
@@ -5,15 +5,13 @@ import org.ergoplatform.ErgoBox.RegisterId
import org.ergoplatform.settings.ErgoAlgos
import pprint.{PPrinter, Tree}
import sigma.ast.SCollection.{SBooleanArray, SByteArray, SByteArray2}
-import sigma.ast._
+import sigma.ast.{ConstantNode, FuncValue, MethodCall, ValueCompanion, _}
import sigma.crypto.EcPointType
import sigma.data.{AvlTreeData, AvlTreeFlags, CollType, PrimitiveType, TrivialProp}
import sigma.serialization.GroupElementSerializer
import sigma.{Coll, GroupElement}
-import sigma.ast.{ConstantNode, FuncValue, ValueCompanion}
-import sigmastate._
import sigmastate.crypto.GF2_192_Poly
-import sigma.ast.MethodCall
+
import java.math.BigInteger
import scala.collection.compat.immutable.ArraySeq
import scala.collection.mutable
@@ -54,6 +52,8 @@ object SigmaPPrint extends PPrinter {
s"SOption[${typeName(ot.elemType)}]"
case _: STuple =>
"STuple"
+ case _: SFunc =>
+ s"SFunc"
case _ =>
sys.error(s"Cannot get typeName($tpe)")
}
diff --git a/parsers/shared/src/test/scala/sigmastate/lang/ContractParserSpec.scala b/parsers/shared/src/test/scala/sigmastate/lang/ContractParserSpec.scala
index 9a412b7100..bce252d866 100644
--- a/parsers/shared/src/test/scala/sigmastate/lang/ContractParserSpec.scala
+++ b/parsers/shared/src/test/scala/sigmastate/lang/ContractParserSpec.scala
@@ -3,6 +3,7 @@ package sigmastate.lang
import org.scalatest.matchers.should.Matchers
import org.scalatest.propspec.AnyPropSpec
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
+import sigma.ast.SType.AnyOps
import sigma.ast._
class ContractParserSpec extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers {
@@ -34,8 +35,8 @@ class ContractParserSpec extends AnyPropSpec with ScalaCheckPropertyChecks with
parsed.name shouldBe "contractName"
parsed.params should contain theSameElementsInOrderAs Seq(
- ContractParam("p1", SInt, Some(IntConstant(5).asWrappedType)),
- ContractParam("p2", SString, Some(StringConstant("default string").asWrappedType)),
+ ContractParam("p1", SInt, Some(5.asWrappedType)),
+ ContractParam("p2", SString, Some("default string".asWrappedType)),
ContractParam("param3", SLong, None)
)
}
diff --git a/parsers/shared/src/test/scala/sigmastate/lang/LangTests.scala b/parsers/shared/src/test/scala/sigmastate/lang/LangTests.scala
index 498c3934bf..de83070ac3 100644
--- a/parsers/shared/src/test/scala/sigmastate/lang/LangTests.scala
+++ b/parsers/shared/src/test/scala/sigmastate/lang/LangTests.scala
@@ -1,16 +1,15 @@
package sigmastate.lang
import org.scalatest.matchers.should.Matchers
-import sigma.{Coll, _}
import sigma.ast.SCollection.SByteArray
import sigma.ast.syntax.{SValue, ValueOps}
import sigma.ast._
import sigma.crypto.CryptoConstants
import sigma.data.{CAnyValue, CSigmaDslBuilder, ProveDHTuple, ProveDlog, SigmaBoolean}
import sigma.util.Extensions.BigIntegerOps
+import sigma._
import sigmastate.helpers.NegativeTesting
import sigmastate.interpreter.Interpreter.ScriptEnv
-import sigma.ast.{Ident, MethodCallLike}
import java.math.BigInteger
@@ -80,4 +79,10 @@ trait LangTests extends Matchers with NegativeTesting {
node
}))(tree)
}
+
+ /** Execute the given `block` having `version` as both activated and ErgoTree version. */
+ def runWithVersion[T](version: Byte)(block: => T): T = {
+ VersionContext.withVersions(version, version)(block)
+ }
+
}
diff --git a/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala b/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala
index 7213088a05..5a0f2b3465 100644
--- a/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala
+++ b/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala
@@ -14,6 +14,7 @@ import SigmaPredef.PredefinedFuncRegistry
import sigma.ast.syntax._
import sigmastate.lang.parsers.ParserException
import sigma.serialization.OpCodes
+import sigmastate.helpers.SigmaPPrint
class SigmaParserTest extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers with LangTests {
import StdSigmaBuilder._
@@ -34,6 +35,17 @@ class SigmaParserTest extends AnyPropSpec with ScalaCheckPropertyChecks with Mat
}
}
+ /** Checks parsing result, printing the actual value as a test vector if expected value
+ * is not equal to actual.
+ */
+ def checkParsed(x: String, expected: SValue) = {
+ val parsed = parse(x)
+ if (expected != parsed) {
+ SigmaPPrint.pprintln(parsed, width = 100)
+ }
+ parsed shouldBe expected
+ }
+
def parseWithException(x: String): SValue = {
SigmaParser(x) match {
case Parsed.Success(v, _) => v
@@ -615,6 +627,11 @@ class SigmaParserTest extends AnyPropSpec with ScalaCheckPropertyChecks with Mat
MethodCallLike(StringConstant("hello"), "+", IndexedSeq(StringConstant("hello")))
}
+ property("bigInt string decoding") {
+ parse("""bigInt("32667486267383620946248345338628674027033885928301927616853987602485119134400")""") shouldBe
+ Apply(BigIntFromStringFunc.symNoType, IndexedSeq(StringConstant("32667486267383620946248345338628674027033885928301927616853987602485119134400")))
+ }
+
property("fromBaseX string decoding") {
parse("""fromBase16("1111")""") shouldBe Apply(FromBase16Func.symNoType, IndexedSeq(StringConstant("1111")))
parse("""fromBase58("111")""") shouldBe Apply(FromBase58Func.symNoType, IndexedSeq(StringConstant("111")))
@@ -889,6 +906,17 @@ class SigmaParserTest extends AnyPropSpec with ScalaCheckPropertyChecks with Mat
)
}
+ property("serialize") {
+ checkParsed("serialize(1)", Apply(Ident("serialize", NoType), Array(IntConstant(1))))
+ checkParsed("serialize((1, 2L))",
+ Apply(Ident("serialize", NoType), Array(Tuple(Vector(IntConstant(1), LongConstant(2L))))))
+ checkParsed("serialize(Coll(1, 2, 3))",
+ Apply(
+ Ident("serialize", NoType),
+ Array(Apply(Ident("Coll", NoType), Array(IntConstant(1), IntConstant(2), IntConstant(3))))
+ ))
+ }
+
property("single name pattern fail") {
fail("{val (a,b) = (1,2)}", 1, 6)
}
diff --git a/sc/js/src/main/scala/sigmastate/lang/js/SigmaCompiler.scala b/sc/js/src/main/scala/sigmastate/lang/js/SigmaCompiler.scala
index 8fe26a30b0..2fc7556875 100644
--- a/sc/js/src/main/scala/sigmastate/lang/js/SigmaCompiler.scala
+++ b/sc/js/src/main/scala/sigmastate/lang/js/SigmaCompiler.scala
@@ -9,13 +9,13 @@ import scala.scalajs.js
import scala.scalajs.js.annotation.JSExportTopLevel
import sigma.js.Value
import sigma.ast.ErgoTree.HeaderType
-import sigmastate.eval.CompiletimeIRContext
+import sigma.compiler.ir.CompiletimeIRContext
import sigma.ast.syntax.ValueOps
/** Wrapper exported to JS. */
@JSExportTopLevel("SigmaCompiler")
-class SigmaCompiler(_compiler: sigmastate.lang.SigmaCompiler) extends js.Object {
+class SigmaCompiler(_compiler: sigma.compiler.SigmaCompiler) extends js.Object {
/** Compiles ErgoScript code to ErgoTree.
*
@@ -59,7 +59,7 @@ object SigmaCompiler extends js.Object {
* @return SigmaCompiler instance
*/
private def create(networkPrefix: Byte): SigmaCompiler = {
- val compiler = sigmastate.lang.SigmaCompiler(networkPrefix)
+ val compiler = sigma.compiler.SigmaCompiler(networkPrefix)
new SigmaCompiler(compiler)
}
}
diff --git a/sc/js/src/test/scala/scalan/Platform.scala b/sc/js/src/test/scala/scalan/Platform.scala
index 5f938111d2..697453a5d2 100644
--- a/sc/js/src/test/scala/scalan/Platform.scala
+++ b/sc/js/src/test/scala/scalan/Platform.scala
@@ -1,14 +1,16 @@
package scalan
+import sigma.compiler.ir.IRContext
+
import scala.annotation.unused
object Platform {
/** In JS tests do nothing. The corresponding JVM method outputs graphs into files. */
- def stage[Ctx <: Scalan](scalan: Ctx)(
+ def stage[Ctx <: IRContext](ctx: Ctx)(
@unused prefix: String,
@unused testName: String,
@unused name: String,
- @unused sfs: Seq[() => scalan.Sym]): Unit = {
+ @unused sfs: Seq[() => ctx.Sym]): Unit = {
}
/** On JS it is no-operation. */
diff --git a/sc/jvm/src/test/scala/scalan/Platform.scala b/sc/jvm/src/test/scala/scalan/Platform.scala
index 43041a92c6..7c9d48b135 100644
--- a/sc/jvm/src/test/scala/scalan/Platform.scala
+++ b/sc/jvm/src/test/scala/scalan/Platform.scala
@@ -3,22 +3,23 @@ package scalan
import scalan.compilation.GraphVizExport
import sigma.util.FileUtil
import org.scalatest.Assertions
+import sigma.compiler.ir.IRContext
object Platform {
/** Output graph given by symbols in `sfs` to files.
- * @param scalan The Scalan context
+ * @param ctx The Scalan context
* @param prefix The prefix of the directory where the graphs will be stored.
* @param testName The name of the test.
* @param name The name of the graph.
* @param sfs A sequence of functions that return symbols of the graph roots.
*/
- def stage[Ctx <: Scalan](scalan: Ctx)
- (prefix: String, testName: String, name: String, sfs: Seq[() => scalan.Sym]): Unit = {
+ def stage[Ctx <: IRContext](ctx: Ctx)
+ (prefix: String, testName: String, name: String, sfs: Seq[() => ctx.Sym]): Unit = {
val directory = FileUtil.file(prefix, testName)
- val gv = new GraphVizExport(scalan)
+ val gv = new GraphVizExport(ctx)
implicit val graphVizConfig = gv.defaultGraphVizConfig
try {
- val ss = sfs.map(_.apply()).asInstanceOf[Seq[gv.scalan.Sym]]
+ val ss = sfs.map(_.apply()).asInstanceOf[Seq[gv.ctx.Sym]]
gv.emitDepGraph(ss, directory, name)(graphVizConfig)
} catch {
case e: Exception =>
diff --git a/sc/jvm/src/test/scala/scalan/compilation/GraphVizExport.scala b/sc/jvm/src/test/scala/scalan/compilation/GraphVizExport.scala
index 8568e6c1db..020e066080 100644
--- a/sc/jvm/src/test/scala/scalan/compilation/GraphVizExport.scala
+++ b/sc/jvm/src/test/scala/scalan/compilation/GraphVizExport.scala
@@ -2,8 +2,8 @@ package scalan.compilation
import java.awt.Desktop
import java.io.{File, PrintWriter}
-import scalan.Scalan
import scalan.core.ScalaNameUtil
+import sigma.compiler.ir.IRContext
import sigma.util.{FileUtil, ProcessUtil, StringUtil}
import scala.annotation.unused
@@ -12,8 +12,8 @@ import scala.collection.immutable.StringOps
// TODO implement this outside of the cake
/** Implementation of Graphviz's dot file generator. */
-class GraphVizExport[Ctx <: Scalan](val scalan: Ctx) {
- import scalan._
+class GraphVizExport[Ctx <: IRContext](val ctx: Ctx) {
+ import ctx._
case class GraphFile(file: File, fileType: String) {
def open() = {
Desktop.getDesktop.open(file)
diff --git a/sc/jvm/src/test/scala/sigmastate/InterpreterReflectionGeneratorTests.scala b/sc/jvm/src/test/scala/sigmastate/InterpreterReflectionGeneratorTests.scala
index aaa1d6c424..c10c0123b0 100644
--- a/sc/jvm/src/test/scala/sigmastate/InterpreterReflectionGeneratorTests.scala
+++ b/sc/jvm/src/test/scala/sigmastate/InterpreterReflectionGeneratorTests.scala
@@ -2,7 +2,7 @@ package sigmastate
import org.scalatest.matchers.should.Matchers
import org.scalatest.propspec.AnyPropSpec
-import scalan.TypeDescs
+import sigma.compiler.ir.{IRContext, TypeDescs}
import sigma.reflection.ReflectionData.registerClassEntry
import sigma.reflection.SRConstructor
@@ -37,7 +37,7 @@ class InterpreterReflectionGeneratorTests extends AnyPropSpec with Matchers {
}
property("inner class") {
- val ctx = null.asInstanceOf[scalan.Library] // ok! type level only
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
val clazz = classOf[ctx.Coll.CollElem[_, _]]
registerClassEntry(clazz,
constructors = Array(
diff --git a/sc/jvm/src/test/scala/sigmastate/ReflectionGenerator.scala b/sc/jvm/src/test/scala/sigmastate/ReflectionGenerator.scala
index 1375b48d99..dd5262e700 100644
--- a/sc/jvm/src/test/scala/sigmastate/ReflectionGenerator.scala
+++ b/sc/jvm/src/test/scala/sigmastate/ReflectionGenerator.scala
@@ -1,10 +1,21 @@
package sigmastate
-import scalan.{Base, TypeDescs}
+import sigma.compiler.ir.{Base, TypeDescs}
import sigma.reflection._
import scala.annotation.unused
import scala.collection.mutable
+/** Generates code for registering classes in the ReflectionData.
+ * It is not used in the runtime.
+ *
+ * The generated invocations of `registerClassEntry`, `mkMethod`, `mkConstructor` may
+ * require manual adjustments.
+ *
+ * It uses [[sigma.reflection.Platform.unknownClasses]] to collect classes which were
+ * accessed during runtime
+ *
+ * @see [[ReflectionData]]
+ */
object ReflectionGenerator {
def normalizeName(name: String): String = {
@@ -30,17 +41,17 @@ object ReflectionGenerator {
}
val knownPackages = Array(
- "scalan.primitives.",
+ "sigma.compiler.ir.primitives.",
"sigma.",
"sigma.",
- "special.wrappers.",
+ "sigma.compiler.ir.wrappers.",
"sigma.ast.",
"sigmastate.lang.Terms.",
"sigmastate.interpreter.",
"sigmastate.utxo.",
"sigmastate.",
- "wrappers.scala.",
- "scalan.",
+ "sigma.compiler.ir.wrappers.scala.",
+ "sigma.compiler.ir.",
"scala.collection.",
"scala."
)
diff --git a/sc/jvm/src/test/scala/sigmastate/helpers/SigmaPPrintSpec.scala b/sc/jvm/src/test/scala/sigmastate/helpers/SigmaPPrintSpec.scala
index 54c0f652dc..ffd591b0df 100644
--- a/sc/jvm/src/test/scala/sigmastate/helpers/SigmaPPrintSpec.scala
+++ b/sc/jvm/src/test/scala/sigmastate/helpers/SigmaPPrintSpec.scala
@@ -8,7 +8,6 @@ import sigma.SigmaDslTesting
import sigma.ast._
import sigma.data.{AvlTreeData, AvlTreeFlags, CBox, CollType, Digest32Coll}
import ErgoTree.HeaderType
-import sigmastate.eval._
import sigma.ast.MethodCall
import sigma.serialization.OpCodes
import sigmastate.utils.Helpers
diff --git a/sc/shared/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala b/sc/shared/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala
index faded6e28c..9eec42a4fb 100644
--- a/sc/shared/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala
+++ b/sc/shared/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala
@@ -1,12 +1,12 @@
package org.ergoplatform
-import sigmastate.lang.SigmaCompiler
-import sigmastate.eval.IRContext
import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
import sigma.ast.SType
import sigma.ast.syntax.SigmaPropValue
import sigma.ast.Value
import sigma.ast.syntax.ValueOps
+import sigma.compiler.SigmaCompiler
+import sigma.compiler.ir.IRContext
object ErgoScriptPredef {
import sigmastate.interpreter.Interpreter._
diff --git a/sc/shared/src/main/scala/org/ergoplatform/dsl/ContractSpec.scala b/sc/shared/src/main/scala/org/ergoplatform/dsl/ContractSpec.scala
index 484b9e2728..ffe7239c62 100644
--- a/sc/shared/src/main/scala/org/ergoplatform/dsl/ContractSpec.scala
+++ b/sc/shared/src/main/scala/org/ergoplatform/dsl/ContractSpec.scala
@@ -5,11 +5,11 @@ import sigma.interpreter.{CostedProverResult, ProverResult}
import sigma.data.{CSigmaDslBuilder, RType}
import org.ergoplatform.{ErgoBox, ErgoLikeContext}
import sigma.{Coll, SigmaDslBuilder, SigmaProp}
-import sigmastate.eval.IRContext
import scala.util.Try
import org.ergoplatform.dsl.ContractSyntax.{ErgoScript, Proposition, Token}
import sigma.ast.{ErgoTree, EvaluatedValue, SType}
+import sigma.compiler.ir.IRContext
import scala.language.implicitConversions
diff --git a/sc/shared/src/main/scala/org/ergoplatform/dsl/ErgoContractSpec.scala b/sc/shared/src/main/scala/org/ergoplatform/dsl/ErgoContractSpec.scala
index 2c31304b70..2511bef439 100644
--- a/sc/shared/src/main/scala/org/ergoplatform/dsl/ErgoContractSpec.scala
+++ b/sc/shared/src/main/scala/org/ergoplatform/dsl/ErgoContractSpec.scala
@@ -1,9 +1,9 @@
package org.ergoplatform.dsl
import sigma.Coll
-import sigmastate.eval.IRContext
import org.ergoplatform.dsl.ContractSyntax.{ErgoScript, Proposition, Token}
import org.ergoplatform.ErgoBox.{BoxId, NonMandatoryRegisterId, TokenId}
+import sigma.compiler.ir.IRContext
import sigma.interpreter.CostedProverResult
class ErgoContractSpec(implicit val IR: IRContext) extends ContractSpec {
diff --git a/sc/shared/src/main/scala/scalan/Scalan.scala b/sc/shared/src/main/scala/scalan/Scalan.scala
deleted file mode 100644
index c2e9359261..0000000000
--- a/sc/shared/src/main/scala/scalan/Scalan.scala
+++ /dev/null
@@ -1,36 +0,0 @@
-package scalan
-
-import scalan.primitives._
-import scalan.staged.Transforming
-
-/** Aggregate cake with all inter-dependent modules assembled together.
- * Each instance of this class contains independent IR context, thus many
- * instances can be created simultaneously.
- * However, the inner types declared in the traits are path-dependant.
- * This in particular means that ctx1.Ref[_] and ctx2.Ref[_] are different types.
- * The typical usage is to create `val ctx = new Scalan` and then import inner
- * declarations using `import ctx._`.
- * This way the declaration will be directly available as if they were global
- * declarations.
- * At the same time cake design pattern allow to `override` many methods and values
- * in classed derived from `Scalan`, this is significant benefit over
- * *everything is global* design.
- */
-class Scalan
- extends TypeDescs
- with MethodCalls
- with Tuples
- with NumericOps
- with UnBinOps
- with LogicalOps
- with OrderingOps
- with Equal
- with UniversalOps
- with Functions
- with IfThenElse
- with Transforming
- with Thunks
- with Entities
- with Modules
- with DefRewriting
-
diff --git a/sc/shared/src/main/scala/scalan/meta/SSymName.scala b/sc/shared/src/main/scala/scalan/meta/SSymName.scala
deleted file mode 100644
index ea9b1546ba..0000000000
--- a/sc/shared/src/main/scala/scalan/meta/SSymName.scala
+++ /dev/null
@@ -1,22 +0,0 @@
-package scalan.meta
-
-import sigma.util.StringUtil.StringUtilExtensions
-
-case class ImportItem(packageName: String, importedNames: List[String])
-
-case class SSymName(packageName: String, name: String) {
- import SSymName._
- def this(name: String) = this("", name)
- def mkFullName = fullNameString(packageName, name)
- def isImportedBy(item: ImportItem): Boolean = {
- if (packageName != item.packageName) return false
- item.importedNames.contains(SSymName.ImportAllWildcard) || item.importedNames.contains(name)
- }
-}
-
-object SSymName {
- /** Wildcard character used to signify imporing all names from namespace */
- val ImportAllWildcard = "*"
- def fullNameString(packageName: String, name: String): String =
- if (packageName.isNullOrEmpty) name else s"$packageName.$name"
-}
\ No newline at end of file
diff --git a/sc/shared/src/main/scala/scalan/primitives/UniversalOps.scala b/sc/shared/src/main/scala/scalan/primitives/UniversalOps.scala
deleted file mode 100644
index eaca5821ce..0000000000
--- a/sc/shared/src/main/scala/scalan/primitives/UniversalOps.scala
+++ /dev/null
@@ -1,92 +0,0 @@
-package scalan.primitives
-
-import scalan.{Base, Scalan}
-
-trait UniversalOps extends Base { scalan: Scalan =>
- case class HashCode[A]() extends UnOp[A, Int]("hashCode") {
- override def applySeq(x: A): Int = x.hashCode
- }
-
- case class ToString[A]() extends UnOp[A, String]("toString") {
- override def applySeq(x: A): String = x.toString
- }
-
- /** Represents calculation of size in bytes of the given value.
- * The descriptor value.elem can be used to decompose value into components.
- */
- case class SizeOf[T](value: Ref[T]) extends BaseDef[Long] {
- override def transform(t: Transformer) = SizeOf(t(value))
- }
-
- def sizeOf[T](value: Ref[T]): Ref[Long] = SizeOf(value)
-
- /** Special graph node to represent accumulation of the operation costs.
- * In general, due to node sharing it is incorrect to just sum up all the `args` costs
- * and add `resCost` to that value.
- * Example:
- *
- * val x = ..
- * val y = op1(x)
- * val z = op2(x)
- * val res = op3(y, z)
- *
- * The naive summation will lead to the cost of x` is accumulated both into `cost of y`
- * and into `cost of z`, so in the `cost of res` it is accumulated twice.
- * To avoid this problem OpCost nodes require special handling in during evaluation.
- *
- * @param lambdaVar the variable of the lambda in which scope this node is created.
- * This makes this node belong to the lambda body, even if it doesn't
- * otherwise depend on lambda argument.
- * @param costedValueId The id of the node for which this node represents cost
- * @param args costs of the arguments, which are here represent dependency information.
- * @param opCost operation cost, which should be added to the current scope accumulated cost
- */
- case class OpCost(lambdaVar: Sym, costedValueId: Int, args: Seq[Ref[Int]], opCost: Ref[Int]) extends BaseDef[Int] {
- /** When this node is mirrored (as part of mirrorLambda) we apply transformer t for all arguments
- * with standard data flow semantics.
- * However this is not correct to do for lambdaVar.
- * Instead we use current lambda from the top of the stack, which is always points to the most nested
- * lambda.
- */
- override def transform(t: Transformer) = OpCost(lambdaStack.head.x, costedValueId, t(args), t(opCost))
- }
-
- def opCost(costedValue: Sym, args: Seq[Ref[Int]], opCost: Ref[Int]): Ref[Int] = {
- val id = costedValue.node.nodeId
- val lamVar = lambdaStack.head.x
- OpCost(lamVar, id, args, opCost)
- }
-
- def assertValueIdForOpCost[A,B](value: Ref[A], cost: Ref[B]): Unit = {
- assert(if (cost.node.isInstanceOf[OpCost]) value.node.nodeId == cost.node.asInstanceOf[OpCost].costedValueId else true,
- s"${value.node} value node id (${value.node.nodeId}) is not equal to OpCost.costedValueId (${cost.node.asInstanceOf[OpCost].costedValueId})")
- }
-
- case class Downcast[From, To](input: Ref[From], eTo: Elem[To]) extends BaseDef[To]()(eTo) {
- override def transform(t: Transformer) = Downcast(t(input), eTo)
- }
- case class Upcast[From, To](input: Ref[From], eTo: Elem[To]) extends BaseDef[To]()(eTo) {
- override def transform(t: Transformer) = Upcast(t(input), eTo)
- }
-
- def downcast[To:Elem](value: Ref[_]): Ref[To] = Downcast(value, element[To])
- def upcast[To:Elem](value: Ref[_]): Ref[To] = Upcast(value, element[To])
-
- implicit class RepUniversalOps[A](x: Ref[A]) {
- def hashCodeRep: Ref[Int] = HashCode[A]().apply(x)
- def toStringRep = ToString[A]().apply(x)
- }
-
- case class Convert[From,To](eFrom: Elem[From], eTo: Elem[To], x: Ref[Def[_]], conv: Ref[From => To])
- extends BaseDef[To]()(eTo) {
- override def transform(t: Transformer) = Convert(eFrom, eTo, t(x), t(conv))
- }
-
- def tryConvert[From, To](eFrom: Elem[From], eTo: Elem[To], x: Ref[Def[_]], conv: Ref[From => To]): Ref[To] = {
- if (x.elem <:< eFrom)
- conv(asRep[From](x))
- else
- Convert(eFrom, eTo, x, conv)
- }
-
-}
diff --git a/sc/shared/src/main/scala/scalan/Exceptions.scala b/sc/shared/src/main/scala/sigma/compiler/Exceptions.scala
similarity index 93%
rename from sc/shared/src/main/scala/scalan/Exceptions.scala
rename to sc/shared/src/main/scala/sigma/compiler/Exceptions.scala
index 8ab128a06e..75b1ecb6a3 100644
--- a/sc/shared/src/main/scala/scalan/Exceptions.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/Exceptions.scala
@@ -1,4 +1,4 @@
-package scalan
+package sigma.compiler
/**
* Can be thrown in staged method body to prevent body unfolding.
diff --git a/sc/shared/src/main/scala/sigmastate/lang/SigmaCompiler.scala b/sc/shared/src/main/scala/sigma/compiler/SigmaCompiler.scala
similarity index 92%
rename from sc/shared/src/main/scala/sigmastate/lang/SigmaCompiler.scala
rename to sc/shared/src/main/scala/sigma/compiler/SigmaCompiler.scala
index 849167e159..942154409b 100644
--- a/sc/shared/src/main/scala/sigmastate/lang/SigmaCompiler.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/SigmaCompiler.scala
@@ -1,12 +1,10 @@
-package sigmastate.lang
+package sigma.compiler
import fastparse.Parsed
import fastparse.Parsed.Success
import sigma.kiama.rewriting.Rewriter.{everywherebu, rewrite, rule}
import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
-import scalan.GraphIRReflection
import sigma.ast.{Exponentiate, MultiplyGroup, SCollectionMethods, SGlobalMethods, SGroupElementMethods, Value, Xor}
-import sigmastate.eval.IRContext
import sigmastate.interpreter.Interpreter.ScriptEnv
import sigma.ast.SigmaPredef.PredefinedFuncRegistry
import sigma.ast.MethodCall
@@ -14,7 +12,10 @@ import sigmastate.lang.parsers.ParserException
import sigma.ast._
import sigma.ast.syntax.SValue
import SCollectionMethods.{ExistsMethod, ForallMethod, MapMethod}
+import sigma.compiler.ir.{GraphIRReflection, IRContext}
+import sigma.compiler.phases.{SigmaBinder, SigmaTyper}
import sigmastate.InterpreterReflection
+import sigmastate.lang.SigmaParser
/**
* @param networkPrefix network prefix to decode an ergo address from string (PK op)
@@ -72,7 +73,8 @@ class SigmaCompiler private(settings: CompilerSettings) {
val predefinedFuncRegistry = new PredefinedFuncRegistry(builder)
val binder = new SigmaBinder(env, builder, networkPrefix, predefinedFuncRegistry)
val bound = binder.bind(parsed)
- val typer = new SigmaTyper(builder, predefinedFuncRegistry, settings.lowerMethodCalls)
+ val typeEnv = env.collect { case (k, v: SType) => k -> v }
+ val typer = new SigmaTyper(builder, predefinedFuncRegistry, typeEnv, settings.lowerMethodCalls)
val typed = typer.typecheck(bound)
typed
}
@@ -91,7 +93,12 @@ class SigmaCompiler private(settings: CompilerSettings) {
/** Compiles the given typed expression. */
def compileTyped(env: ScriptEnv, typedExpr: SValue)(implicit IR: IRContext): CompilerResult[IR.type] = {
- val compiledGraph = IR.buildGraph(env, typedExpr)
+ val placeholdersEnv = env
+ .collect { case (name, t: SType) => name -> t }
+ .zipWithIndex
+ .map { case ((name, t), index) => name -> ConstantPlaceholder(index, t) }
+ .toMap
+ val compiledGraph = IR.buildGraph(env ++ placeholdersEnv, typedExpr)
val compiledTree = IR.buildTree(compiledGraph)
CompilerResult(env, "", compiledGraph, compiledTree)
}
diff --git a/sc/shared/src/main/scala/sigmastate/lang/SigmaTemplateCompiler.scala b/sc/shared/src/main/scala/sigma/compiler/SigmaTemplateCompiler.scala
similarity index 78%
rename from sc/shared/src/main/scala/sigmastate/lang/SigmaTemplateCompiler.scala
rename to sc/shared/src/main/scala/sigma/compiler/SigmaTemplateCompiler.scala
index ec94bdfd3a..0b30f9830a 100644
--- a/sc/shared/src/main/scala/sigmastate/lang/SigmaTemplateCompiler.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/SigmaTemplateCompiler.scala
@@ -1,12 +1,11 @@
-package sigmastate.lang
+package sigma.compiler
import fastparse.Parsed
-import org.ergoplatform.sdk.ContractTemplate
-import sigmastate.eval.CompiletimeIRContext
-import org.ergoplatform.sdk.Parameter
+import org.ergoplatform.sdk.{ContractTemplate, Parameter}
import sigma.ast.SourceContext
import sigma.ast.syntax.SValue
-import sigmastate.interpreter.Interpreter.ScriptEnv
+import sigma.compiler.ir.CompiletimeIRContext
+import sigmastate.lang.{ContractParser, ParsedContractTemplate}
import sigmastate.lang.parsers.ParserException
/** Compiler which compiles Ergo contract templates into a [[ContractTemplate]]. */
@@ -19,13 +18,14 @@ class SigmaTemplateCompiler(networkPrefix: Byte) {
* @param source The ErgoScript contract source code.
* @return The contract template.
*/
- def compile(env: ScriptEnv, source: String): ContractTemplate = {
+ def compile(source: String): ContractTemplate = {
ContractParser.parse(source) match {
- case Parsed.Success(template, _) => {
+ case Parsed.Success(parsedTemplate, _) =>
implicit val ir = new CompiletimeIRContext
- val result = sigmaCompiler.compileParsed(env, template.body)
- assemble(template, result.buildTree)
- }
+ val parEnv = parsedTemplate.signature.params.map { p => p.name -> p.tpe }.toMap
+ val result = sigmaCompiler.compileParsed(parEnv, parsedTemplate.body)
+ assemble(parsedTemplate, result.buildTree)
+
case f: Parsed.Failure =>
throw new ParserException(s"Contract template syntax error: $f", Some(SourceContext.fromParserFailure(f)))
}
diff --git a/sc/shared/src/main/scala/scalan/staged/AstGraphs.scala b/sc/shared/src/main/scala/sigma/compiler/ir/AstGraphs.scala
similarity index 96%
rename from sc/shared/src/main/scala/scalan/staged/AstGraphs.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/AstGraphs.scala
index 7ad5c24f17..79a078ad19 100644
--- a/sc/shared/src/main/scala/scalan/staged/AstGraphs.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/AstGraphs.scala
@@ -1,13 +1,15 @@
-package scalan.staged
+package sigma.compiler.ir
-import scala.collection._
-import scalan.Scalan
-import debox.cfor
-import debox.{Buffer => DBuffer, Map => DMap, Set => DSet}
+import debox.{cfor, Buffer => DBuffer, Map => DMap, Set => DSet}
import sigma.data.emptyDBufferOfInt
+import scala.collection._
+
-trait AstGraphs extends Transforming { self: Scalan =>
+/** Defines reusable abstraction of AstGraph, the base class for [[ProgramGraph]],
+ * [[Lambda]] and [[ThunkDef]].
+ */
+trait AstGraphs extends Transforming { self: IRContext =>
/** GraphNode is created for each symbol of the AstGraph and represents graph linking structure */
case class GraphNode(
diff --git a/sc/shared/src/main/scala/scalan/Base.scala b/sc/shared/src/main/scala/sigma/compiler/ir/Base.scala
similarity index 97%
rename from sc/shared/src/main/scala/scalan/Base.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/Base.scala
index cc29af45b9..48e3e5d09e 100644
--- a/sc/shared/src/main/scala/scalan/Base.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/Base.scala
@@ -1,14 +1,15 @@
-package scalan
+package sigma.compiler.ir
import debox.{cfor, Buffer => DBuffer}
-import sigma.data.{AVHashMap, Nullable, RType}
+import sigma.compiler.ir.core.MutableLazy
import sigma.data.OverloadHack.Overloaded1
-import sigma.util.StringUtil
+import sigma.data.{AVHashMap, Nullable, RType}
import sigma.reflection.RConstructor
+import sigma.util.StringUtil
import java.util.Arrays
-import scala.annotation.{implicitNotFound, unused}
import scala.annotation.unchecked.uncheckedVariance
+import scala.annotation.{implicitNotFound, unused}
import scala.collection.compat.immutable.ArraySeq
import scala.collection.mutable
import scala.language.implicitConversions
@@ -17,7 +18,7 @@ import scala.language.implicitConversions
* The Base trait houses common AST nodes. It also manages a list of encountered definitions which
* allows for common sub-expression elimination (CSE).
*/
-abstract class Base { scalan: Scalan =>
+abstract class Base { thisIR: IRContext =>
type |[+A, +B] = Either[A, B]
type RFunc[-A,+B] = Ref[Function1[A,B]]
type RPair[+A, +B] = Ref[(A,B)]
@@ -51,7 +52,7 @@ abstract class Base { scalan: Scalan =>
/** Base class for all IR nodes/operations/definitions. */
abstract class Node extends Product {
- private[scalan] var _nodeId: Int = freshId
+ private[compiler] var _nodeId: Int = freshId
/** Unique id of the graph node assigned for each new instance using
* `freshId` generator.
@@ -365,8 +366,8 @@ abstract class Base { scalan: Scalan =>
/** Most of the references are initialized when created.
* These methods are used in core to assign new value for the reference.*/
- private[scalan] def assignDef[B >: T](d: Def[B]): Unit
- private[scalan] def assignDefFrom[B >: T](ref: Ref[B]): Unit
+ private[compiler] def assignDef[B >: T](d: Def[B]): Unit
+ private[compiler] def assignDefFrom[B >: T](ref: Ref[B]): Unit
/** Whether the underlying node is Placeholder. */
@inline final def isPlaceholder: Boolean = node.isInstanceOf[Placeholder[_]]
@@ -550,10 +551,10 @@ abstract class Base { scalan: Scalan =>
}
/** Prepend owner parameter depending on its kind. */
- private[scalan] def addOwnerParameter(ownerType: OwnerKind, params: Seq[Any]): Seq[AnyRef] = {
+ private[compiler] def addOwnerParameter(ownerType: OwnerKind, params: Seq[Any]): Seq[AnyRef] = {
val finalParams = (ownerType match {
case EntityObjectOwner(obj) => obj +: params
- case ScalanOwner => scalan +: params
+ case ScalanOwner => thisIR +: params
case NoOwner => params
})
finalParams.asInstanceOf[Seq[AnyRef]]
@@ -601,7 +602,7 @@ abstract class Base { scalan: Scalan =>
override def elem: Elem[T @uncheckedVariance] = _node.resultType
override def node: Def[T] = _node
- private[scalan] def assignDefInternal[B >: T](d: Def[B]): Unit = {
+ private[compiler] def assignDefInternal[B >: T](d: Def[B]): Unit = {
assert(_node.isInstanceOf[Placeholder[_]])
assert(_node.nodeId > 0)
val tab = _symbolTable
@@ -612,12 +613,12 @@ abstract class Base { scalan: Scalan =>
_node = d.asInstanceOf[Def[T]]
}
- private[scalan] def assignDef[B >: T](d: Def[B]): Unit = {
+ private[compiler] def assignDef[B >: T](d: Def[B]): Unit = {
assignDefInternal(d)
updateSymbolTable(this, d)
}
- private[scalan] def assignDefFrom[B >: T](sym: Ref[B]): Unit = {
+ private[compiler] def assignDefFrom[B >: T](sym: Ref[B]): Unit = {
assignDefInternal(sym.node)
}
@@ -670,7 +671,7 @@ abstract class Base { scalan: Scalan =>
}
/** Should be invoked to reset IR global node counter. */
- @inline final private[scalan] def resetIdCounter() = { currId = 0 }
+ @inline final private[compiler] def resetIdCounter() = { currId = 0 }
/** Create or find symbol (node Ref) which refers to the given node in the table of all created symbols.
* The d.nodeId is the index in the _symbolTable which is DBuffer (backed by Array)
@@ -825,7 +826,7 @@ abstract class Base { scalan: Scalan =>
* @tparam T
* @return The symbol of the graph which is semantically(up to rewrites) equivalent to d
*/
- protected[scalan] def toExp[T](d: Def[T], newSym: => Ref[T]): Ref[T] = {
+ protected[compiler] def toExp[T](d: Def[T], newSym: => Ref[T]): Ref[T] = {
var res = findOrCreateDefinition(d, newSym)
var currSym = res
var currDef = d
diff --git a/sc/shared/src/main/scala/scalan/DefRewriting.scala b/sc/shared/src/main/scala/sigma/compiler/ir/DefRewriting.scala
similarity index 94%
rename from sc/shared/src/main/scala/scalan/DefRewriting.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/DefRewriting.scala
index 114fb1b0e6..62deffad31 100644
--- a/sc/shared/src/main/scala/scalan/DefRewriting.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/DefRewriting.scala
@@ -1,8 +1,14 @@
-package scalan
+package sigma.compiler.ir
+import sigma.compiler.DelayInvokeException
import sigma.data.ExactNumeric
-trait DefRewriting { scalan: Scalan =>
+/** Defines methods to implement graph rewriting optimization rules.
+ * The rules are defines as a series of pattern matching with stackable overriding.
+ * Can be mixed in into traits to add new rules (pattern cases) and call `super`
+ * implementation as a fallback case.
+ */
+trait DefRewriting { scalan: IRContext =>
/** Rewrites given node to another equivalent node and returns its reference.
* @param d node to be matched against rewrite patterns
diff --git a/sc/shared/src/main/scala/scalan/Entities.scala b/sc/shared/src/main/scala/sigma/compiler/ir/Entities.scala
similarity index 96%
rename from sc/shared/src/main/scala/scalan/Entities.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/Entities.scala
index 8a32dcde10..dfaeff207c 100644
--- a/sc/shared/src/main/scala/scalan/Entities.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/Entities.scala
@@ -1,7 +1,7 @@
-package scalan
+package sigma.compiler.ir
/** A slice in the Scalan cake with base classes for various descriptors. */
-trait Entities extends TypeDescs { self: Scalan =>
+trait Entities extends TypeDescs { self: IRContext =>
/** Base class for all descriptors of staged traits.
* See derived classes in `impl` packages.
diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala
similarity index 89%
rename from sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala
index 9c9fa5ffe1..37550e3430 100644
--- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala
@@ -1,21 +1,23 @@
-package sigmastate.eval
+package sigma.compiler.ir
import org.ergoplatform._
-import scalan.MutableLazy
-import sigma.{SigmaException, ast}
+import sigma.ast.SType.tT
+import sigma.Evaluation.stypeToRType
+import sigma.ast.SType.tT
import sigma.ast.TypeCodes.LastConstantCode
import sigma.ast.Value.Typed
-import sigma.ast._
import sigma.ast.syntax.{SValue, ValueOps}
+import sigma.ast._
+import sigma.compiler.ir.core.MutableLazy
import sigma.crypto.EcPointType
import sigma.data.ExactIntegral.{ByteIsExactIntegral, IntIsExactIntegral, LongIsExactIntegral, ShortIsExactIntegral}
import sigma.data.ExactOrdering.{ByteIsExactOrdering, IntIsExactOrdering, LongIsExactOrdering, ShortIsExactOrdering}
import sigma.data.{CSigmaDslBuilder, ExactIntegral, ExactNumeric, ExactOrdering, Lazy, Nullable}
-import sigma.util.Extensions.ByteOps
-import sigmastate.interpreter.Interpreter.ScriptEnv
-import sigma.ast.{Ident, Select, Val}
import sigma.exceptions.GraphBuildingException
import sigma.serialization.OpCodes
+import sigma.util.Extensions.ByteOps
+import sigma.{SigmaException, VersionContext, ast}
+import sigmastate.interpreter.Interpreter.ScriptEnv
import scala.collection.mutable.ArrayBuffer
@@ -27,7 +29,7 @@ import scala.collection.mutable.ArrayBuffer
* CSE however means the original structure of source code may not be preserved in the
* resulting ErgoTree.
* */
-trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
+trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
import AvlTree._
import BigInt._
import Box._
@@ -42,8 +44,8 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
import SigmaProp._
import WOption._
- /** Should be specified in the final cake */
- val builder: SigmaBuilder
+ /** Builder used to create ErgoTree nodes. */
+ val builder = TransformingSigmaBuilder
import builder._
val okMeasureOperationTime: Boolean = false
@@ -52,10 +54,6 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
this.keepOriginalFunc = false // original lambda of Lambda node contains invocations of evalNode and we don't want that
this.useAlphaEquality = false
- /** Whether to create CostOf nodes or substutute costs from CostTable as constants in the graph.
- * true - substitute; false - create CostOf nodes */
- var substFromCostTable: Boolean = true
-
/** Whether to save calcF and costF graphs in the file given by ScriptNameProp environment variable */
var saveGraphsInFile: Boolean = false
@@ -380,13 +378,23 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
case _ => error(s"Cannot find BinOp for opcode newOpCode(${opCode.toUByte - LastConstantCode}) and type $eA")
}
- import sigmastate._
-
protected implicit def groupElementToECPoint(g: sigma.GroupElement): EcPointType = CSigmaDslBuilder.toECPoint(g).asInstanceOf[EcPointType]
def error(msg: String) = throw new GraphBuildingException(msg, None)
def error(msg: String, srcCtx: Option[SourceContext]) = throw new GraphBuildingException(msg, srcCtx)
+ /** Graph node to represent a placeholder of a constant in ErgoTree.
+ * @param id Zero based index in ErgoTree.constants array.
+ * @param resultType type descriptor of the constant value.
+ */
+ case class ConstantPlaceholder[T](id: Int, resultType: Elem[T]) extends Def[T]
+
+ /** Smart constructor method for [[ConstantPlaceholder]], should be used instead of the
+ * class constructor.
+ */
+ @inline def constantPlaceholder[T](id: Int, eT: Elem[T]): Ref[T] = ConstantPlaceholder(id, eT)
+
+
/** Translates the given typed expression to IR graph representing a function from
* Context to some type T.
* @param env contains values for each named constant used
@@ -432,11 +440,11 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
}
Nullable(res)
}}
- def throwError =
- error(s"Don't know how to buildNode($node)", node.sourceContext.toOption)
+ def throwError(clue: String = "") =
+ error((if (clue.nonEmpty) clue + ": " else "") + s"Don't know how to buildNode($node)", node.sourceContext.toOption)
val res: Ref[Any] = node match {
- case c @ Constant(v, tpe) => v match {
+ case Constant(v, tpe) => v match {
case p: SSigmaProp =>
assert(tpe == SSigmaProp)
val resV = liftConst(p)
@@ -471,6 +479,8 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
val resV = toRep(v)(e)
resV
}
+ case sigma.ast.ConstantPlaceholder(id, tpe) =>
+ constantPlaceholder(id, stypeToElem(tpe))
case sigma.ast.Context => ctx
case Global => sigmaDslBuilder
case Height => ctx.HEIGHT
@@ -887,7 +897,7 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
f
}
- case l @ FuncValue(Seq((n, argTpe)), body) =>
+ case FuncValue(Seq((n, argTpe)), body) =>
val eArg = stypeToElem(argTpe).asInstanceOf[Elem[Any]]
val f = fun { x: Ref[Any] =>
buildNode(ctx, env + (n -> x), body)
@@ -921,7 +931,7 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
sigmaDslBuilder.decodePoint(bytes)
// fallback rule for MethodCall, should be the last case in the list
- case sigma.ast.MethodCall(obj, method, args, _) =>
+ case sigma.ast.MethodCall(obj, method, args, typeSubst) =>
val objV = eval(obj)
val argsV = args.map(eval)
(objV, method.objType) match {
@@ -978,7 +988,20 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
val i = asRep[Int](argsV(0))
val d = asRep[t](argsV(1))
xs.getOrElse(i, d)
- case _ => throwError
+ case SCollectionMethods.ReverseMethod.name =>
+ xs.reverse
+ case SCollectionMethods.DistinctMethod.name =>
+ xs.distinct
+ case SCollectionMethods.StartsWithMethod.name =>
+ val ys = asRep[Coll[t]](argsV(0))
+ xs.startsWith(ys)
+ case SCollectionMethods.EndsWithMethod.name =>
+ val ys = asRep[Coll[t]](argsV(0))
+ xs.endsWith(ys)
+ case SCollectionMethods.GetMethod.name =>
+ val idx = asRep[Int](argsV(0))
+ xs.get(idx)
+ case _ => throwError()
}
case (opt: ROption[t]@unchecked, SOptionMethods) => method.name match {
case SOptionMethods.GetMethod.name =>
@@ -992,7 +1015,7 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
opt.map(asRep[t => Any](argsV(0)))
case SOptionMethods.FilterMethod.name =>
opt.filter(asRep[t => Boolean](argsV(0)))
- case _ => throwError
+ case _ => throwError()
}
case (ge: Ref[GroupElement]@unchecked, SGroupElementMethods) => method.name match {
case SGroupElementMethods.GetEncodedMethod.name =>
@@ -1005,12 +1028,16 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
case SGroupElementMethods.ExponentiateMethod.name =>
val k = asRep[BigInt](argsV(0))
ge.exp(k)
- case _ => throwError
+ case _ => throwError()
}
case (box: Ref[Box]@unchecked, SBoxMethods) => method.name match {
case SBoxMethods.tokensMethod.name =>
box.tokens
- case _ => throwError
+ case SBoxMethods.getRegMethodV6.name if VersionContext.current.isV6SoftForkActivated =>
+ val c1 = asRep[Int](argsV(0))
+ val c2 = stypeToElem(typeSubst.apply(tT))
+ box.getReg(c1)(c2)
+ case _ => throwError()
}
case (ctx: Ref[Context]@unchecked, SContextMethods) => method.name match {
case SContextMethods.dataInputsMethod.name =>
@@ -1033,7 +1060,16 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
ctx.LastBlockUtxoRootHash
case SContextMethods.minerPubKeyMethod.name =>
ctx.minerPubKey
- case _ => throwError
+ case SContextMethods.getVarV6Method.name =>
+ val c2 = asRep[Byte](argsV(0))
+ val c3 = stypeToElem(typeSubst.apply(tT))
+ ctx.getVar(c2)(c3)
+ case SContextMethods.getVarFromInputMethod.name =>
+ val c1 = asRep[Short](argsV(0))
+ val c2 = asRep[Byte](argsV(1))
+ val c3 = stypeToElem(typeSubst.apply(tT))
+ ctx.getVarFromInput(c1, c2)(c3)
+ case _ => throwError()
}
case (tree: Ref[AvlTree]@unchecked, SAvlTreeMethods) => method.name match {
case SAvlTreeMethods.digestMethod.name =>
@@ -1080,7 +1116,7 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
val operations = asRep[Coll[(Coll[Byte], Coll[Byte])]](argsV(0))
val proof = asRep[Coll[Byte]](argsV(1))
tree.update(operations, proof)
- case _ => throwError
+ case _ => throwError()
}
case (ph: Ref[PreHeader]@unchecked, SPreHeaderMethods) => method.name match {
case SPreHeaderMethods.versionMethod.name =>
@@ -1097,7 +1133,7 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
ph.minerPk
case SPreHeaderMethods.votesMethod.name =>
ph.votes
- case _ => throwError
+ case _ => throwError()
}
case (h: Ref[Header]@unchecked, SHeaderMethods) => method.name match {
case SHeaderMethods.idMethod.name =>
@@ -1130,7 +1166,9 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
h.powDistance
case SHeaderMethods.votesMethod.name =>
h.votes
- case _ => throwError
+ case SHeaderMethods.checkPowMethod.name if VersionContext.current.isV6SoftForkActivated =>
+ h.checkPow
+ case _ => throwError()
}
case (g: Ref[SigmaDslBuilder]@unchecked, SGlobalMethods) => method.name match {
case SGlobalMethods.groupGeneratorMethod.name =>
@@ -1139,13 +1177,52 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext =>
val c1 = asRep[Coll[Byte]](argsV(0))
val c2 = asRep[Coll[Byte]](argsV(1))
g.xor(c1, c2)
- case _ => throwError
+ case SGlobalMethods.serializeMethod.name =>
+ val value = asRep[Any](argsV(0))
+ g.serialize(value)
+ case SGlobalMethods.fromBigEndianBytesMethod.name =>
+ val bytes = asRep[Coll[Byte]](argsV(0))
+ val cT = stypeToElem(method.stype.tRange.withSubstTypes(typeSubst))
+ g.fromBigEndianBytes(bytes)(cT)
+ case _ => throwError()
+ }
+ case (x: Ref[tNum], _: SNumericTypeMethods) => method.name match {
+ case SNumericTypeMethods.ToBytesMethod.name =>
+ val op = NumericToBigEndianBytes(elemToExactNumeric(x.elem))
+ ApplyUnOp(op, x)
+ case SNumericTypeMethods.ToBitsMethod.name =>
+ val op = NumericToBits(elemToExactNumeric(x.elem))
+ ApplyUnOp(op, x)
+ case SNumericTypeMethods.BitwiseInverseMethod.name =>
+ val op = NumericBitwiseInverse(elemToExactNumeric(x.elem))(x.elem)
+ ApplyUnOp(op, x)
+ case SNumericTypeMethods.BitwiseOrMethod.name =>
+ val y = asRep[tNum](argsV(0))
+ val op = NumericBitwiseOr(elemToExactNumeric(x.elem))(x.elem)
+ ApplyBinOp(op, x, y)
+ case SNumericTypeMethods.BitwiseAndMethod.name =>
+ val y = asRep[tNum](argsV(0))
+ val op = NumericBitwiseAnd(elemToExactNumeric(x.elem))(x.elem)
+ ApplyBinOp(op, x, y)
+ case SNumericTypeMethods.BitwiseXorMethod.name =>
+ val y = asRep[tNum](argsV(0))
+ val op = NumericBitwiseXor(elemToExactNumeric(x.elem))(x.elem)
+ ApplyBinOp(op, x, y)
+ case SNumericTypeMethods.ShiftLeftMethod.name =>
+ val y = asRep[Int](argsV(0))
+ val op = NumericShiftLeft(elemToExactNumeric(x.elem))(x.elem)
+ ApplyBinOpDiffArgs(op, x, y)
+ case SNumericTypeMethods.ShiftRightMethod.name =>
+ val y = asRep[Int](argsV(0))
+ val op = NumericShiftRight(elemToExactNumeric(x.elem))(x.elem)
+ ApplyBinOpDiffArgs(op, x, y)
+ case _ => throwError()
}
- case _ => throwError
+ case _ => throwError(s"Type ${stypeToRType(obj.tpe).name} doesn't have methods")
}
case _ =>
- throwError
+ throwError()
}
val resC = asRep[T#WrappedType](res)
resC
diff --git a/sc/shared/src/main/scala/scalan/GraphIRReflection.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphIRReflection.scala
similarity index 87%
rename from sc/shared/src/main/scala/scalan/GraphIRReflection.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/GraphIRReflection.scala
index 0eaba9d8a3..8f461e502e 100644
--- a/sc/shared/src/main/scala/scalan/GraphIRReflection.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphIRReflection.scala
@@ -1,14 +1,12 @@
-package scalan
+package sigma.compiler.ir
-import scalan.primitives.Thunks
+import sigma.ast.SType
+import sigma.compiler.ir.primitives.Thunks
+import sigma.data.RType
import sigma.reflection.ReflectionData.registerClassEntry
import sigma.reflection.{ReflectionData, mkConstructor, mkMethod}
-import sigmastate.eval.SigmaLibrary
-import sigma.Colls
-import sigma.SigmaDsl
-import sigma.data.RType
-import special.wrappers.{OptionWrapSpec, RTypeWrapSpec}
-import wrappers.scalan.WRTypes
+import sigma.compiler.ir.wrappers.{OptionWrapSpec, RTypeWrapSpec}
+import sigma.compiler.ir.wrappers.sigma.{SigmaDsl, WRTypes}
/** Registrations of reflection metadata for graph-ir module (see README.md).
* Such metadata is only used on JS platform to support reflection-like interfaces of
@@ -23,8 +21,8 @@ object GraphIRReflection {
/** Forces initialization of reflection data. */
val reflection = ReflectionData
- { val clazz = classOf[wrappers.scala.WOptions#WOption[_]]
- val ctx = null.asInstanceOf[scalan.Library] // ok! type level only
+ { val clazz = classOf[sigma.compiler.ir.wrappers.scala.WOptions#WOption[_]]
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
registerClassEntry(clazz,
methods = Map(
mkMethod(clazz, "filter", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
@@ -48,8 +46,8 @@ object GraphIRReflection {
registerClassEntry(classOf[TypeDescs#FuncElem[_,_]],
constructors = Array(
- mkConstructor(Array(classOf[Scalan], classOf[TypeDescs#Elem[_]], classOf[TypeDescs#Elem[_]])) { args =>
- val ctx = args(0).asInstanceOf[Scalan]
+ mkConstructor(Array(classOf[IRContext], classOf[TypeDescs#Elem[_]], classOf[TypeDescs#Elem[_]])) { args =>
+ val ctx = args(0).asInstanceOf[IRContext]
new ctx.FuncElem(args(1).asInstanceOf[ctx.Elem[_]], args(2).asInstanceOf[ctx.Elem[_]])
}
)
@@ -57,8 +55,8 @@ object GraphIRReflection {
registerClassEntry(classOf[TypeDescs#PairElem[_,_]],
constructors = Array(
- mkConstructor(Array(classOf[Scalan], classOf[TypeDescs#Elem[_]], classOf[TypeDescs#Elem[_]])) { args =>
- val ctx = args(0).asInstanceOf[Scalan]
+ mkConstructor(Array(classOf[IRContext], classOf[TypeDescs#Elem[_]], classOf[TypeDescs#Elem[_]])) { args =>
+ val ctx = args(0).asInstanceOf[IRContext]
new ctx.PairElem(args(1).asInstanceOf[ctx.Elem[_]], args(2).asInstanceOf[ctx.Elem[_]])
}
)
@@ -66,14 +64,14 @@ object GraphIRReflection {
registerClassEntry(classOf[Thunks#ThunkElem[_]],
constructors = Array(
- mkConstructor(Array(classOf[Scalan], classOf[TypeDescs#Elem[_]])) { args =>
- val ctx = args(0).asInstanceOf[Scalan]
+ mkConstructor(Array(classOf[IRContext], classOf[TypeDescs#Elem[_]])) { args =>
+ val ctx = args(0).asInstanceOf[IRContext]
new ctx.ThunkElem(args(1).asInstanceOf[ctx.Elem[_]])
}
)
)
- { val clazz = classOf[sigma.SigmaDsl#SigmaProp]
+ { val clazz = classOf[sigma.compiler.ir.wrappers.sigma.SigmaDsl#SigmaProp]
val ctx = null.asInstanceOf[SigmaDsl] // ok! type level only
registerClassEntry(clazz,
methods = Map(
@@ -122,8 +120,8 @@ object GraphIRReflection {
)
}
- { val clazz = classOf[Colls#CollBuilder]
- val ctx = null.asInstanceOf[Library] // ok! type level only
+ { val clazz = classOf[sigma.compiler.ir.wrappers.sigma.Colls#CollBuilder]
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
registerClassEntry(clazz,
methods = Map(
mkMethod(clazz, "xor", Array[Class[_]](classOf[Base#Ref[_]], classOf[Base#Ref[_]])) { (obj, args) =>
@@ -144,8 +142,8 @@ object GraphIRReflection {
}
{
- val clazz = classOf[Colls#Coll[_]]
- val ctx = null.asInstanceOf[Library] // ok! type level only
+ val clazz = classOf[sigma.compiler.ir.wrappers.sigma.Colls#Coll[_]]
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
registerClassEntry(clazz,
methods = Map(
mkMethod(clazz, "append", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
@@ -205,13 +203,29 @@ object GraphIRReflection {
},
mkMethod(clazz, "exists", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
obj.asInstanceOf[ctx.Coll[Any]].exists(args(0).asInstanceOf[ctx.Ref[Any => Boolean]])
+ },
+ // V6 methods
+ mkMethod(clazz, "reverse", Array[Class[_]]()) { (obj, _) =>
+ obj.asInstanceOf[ctx.Coll[Any]].reverse
+ },
+ mkMethod(clazz, "distinct", Array[Class[_]]()) { (obj, _) =>
+ obj.asInstanceOf[ctx.Coll[Any]].distinct
+ },
+ mkMethod(clazz, "startsWith", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.Coll[Any]].startsWith(args(0).asInstanceOf[ctx.Ref[ctx.Coll[Any]]])
+ },
+ mkMethod(clazz, "endsWith", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.Coll[Any]].endsWith(args(0).asInstanceOf[ctx.Ref[ctx.Coll[Any]]])
+ },
+ mkMethod(clazz, "get", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.Coll[_]].apply(args(0).asInstanceOf[ctx.Ref[Int]])
}
)
)
}
{
val clazz = classOf[SigmaDsl#AvlTree]
- val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
registerClassEntry(clazz,
methods = Map(
mkMethod(clazz, "updateOperations", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
@@ -269,7 +283,7 @@ object GraphIRReflection {
}
{ val clazz = classOf[SigmaDsl#Box]
- val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
registerClassEntry(clazz,
methods = Map(
mkMethod(clazz, "value", Array[Class[_]]()) { (obj, _) =>
@@ -302,7 +316,7 @@ object GraphIRReflection {
{
val clazz = classOf[SigmaDsl#Context]
- val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
registerClassEntry(clazz,
methods = Map(
mkMethod(clazz, "LastBlockUtxoRootHash", Array[Class[_]]()) { (obj, args) =>
@@ -335,6 +349,9 @@ object GraphIRReflection {
mkMethod(clazz, "getVar", Array[Class[_]](classOf[Base#Ref[_]], classOf[TypeDescs#Elem[_]])) { (obj, args) =>
obj.asInstanceOf[ctx.Context].getVar(args(0).asInstanceOf[ctx.Ref[Byte]])(args(1).asInstanceOf[ctx.Elem[_]])
},
+ mkMethod(clazz, "getVarFromInput", Array[Class[_]](classOf[Base#Ref[_]], classOf[Base#Ref[_]], classOf[TypeDescs#Elem[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.Context].getVarFromInput(args(0).asInstanceOf[ctx.Ref[Short]], args(1).asInstanceOf[ctx.Ref[Byte]])(args(2).asInstanceOf[ctx.Elem[_]])
+ },
mkMethod(clazz, "headers", Array[Class[_]]()) { (obj, args) =>
obj.asInstanceOf[ctx.Context].headers
}
@@ -343,7 +360,7 @@ object GraphIRReflection {
}
{ val clazz = classOf[SigmaDsl#GroupElement]
- val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
registerClassEntry(clazz,
methods = Map(
mkMethod(clazz, "exp", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
@@ -363,7 +380,7 @@ object GraphIRReflection {
}
{ val clazz = classOf[SigmaDsl#Header]
- val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
registerClassEntry(clazz,
methods = Map(
mkMethod(clazz, "minerPk", Array[Class[_]]()) { (obj, args) =>
@@ -410,13 +427,16 @@ object GraphIRReflection {
},
mkMethod(clazz, "powDistance", Array[Class[_]]()) { (obj, args) =>
obj.asInstanceOf[ctx.Header].powDistance
+ },
+ mkMethod(clazz, "checkPow", Array[Class[_]]()) { (obj, args) =>
+ obj.asInstanceOf[ctx.Header].checkPow
}
)
)
}
{ val clazz = classOf[SigmaDsl#PreHeader]
- val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
registerClassEntry(clazz,
methods = Map(
mkMethod(clazz, "minerPk", Array[Class[_]]()) { (obj, _) =>
@@ -445,7 +465,7 @@ object GraphIRReflection {
}
{ val clazz = classOf[SigmaDsl#SigmaDslBuilder]
- val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
registerClassEntry(clazz,
methods = Map(
mkMethod(clazz, "byteArrayToLong", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
@@ -507,12 +527,18 @@ object GraphIRReflection {
},
mkMethod(clazz, "decodePoint", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
obj.asInstanceOf[ctx.SigmaDslBuilder].decodePoint(args(0).asInstanceOf[ctx.Ref[ctx.Coll[Byte]]])
+ },
+ mkMethod(clazz, "serialize", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.SigmaDslBuilder].serialize(args(0).asInstanceOf[ctx.Ref[Any]])
+ },
+ mkMethod(clazz, "fromBigEndianBytes", Array[Class[_]](classOf[Base#Ref[_]], classOf[TypeDescs#Elem[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.SigmaDslBuilder].fromBigEndianBytes(args(0).asInstanceOf[ctx.Ref[ctx.Coll[Byte]]])(args(1).asInstanceOf[ctx.Elem[SType]])
}
)
)
}
- { val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
+ { val ctx = null.asInstanceOf[IRContext] // ok! type level only
val clazz = classOf[ctx.WOption.WOptionElem[_, _]]
registerClassEntry(clazz,
constructors = Array(
@@ -525,7 +551,7 @@ object GraphIRReflection {
}
{ val clazz = classOf[WRTypes#WRType[_]]
- val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
+ val ctx = null.asInstanceOf[IRContext] // ok! type level only
registerClassEntry(clazz,
methods = Map(
mkMethod(clazz, "name", Array[Class[_]]()) { (obj, _) =>
@@ -535,7 +561,7 @@ object GraphIRReflection {
)
}
- { val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
+ { val ctx = null.asInstanceOf[IRContext] // ok! type level only
val clazz = classOf[ctx.WRType.WRTypeElem[_, _]]
registerClassEntry(clazz,
constructors = Array(
@@ -547,7 +573,7 @@ object GraphIRReflection {
)
}
- { val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
+ { val ctx = null.asInstanceOf[IRContext] // ok! type level only
val clazz = classOf[ctx.Coll.CollElem[_, _]]
registerClassEntry(clazz,
constructors = Array(
@@ -559,16 +585,6 @@ object GraphIRReflection {
)
}
- { val clazz = classOf[wrappers.special.WSpecialPredefs#WSpecialPredefCompanion]
- val ctx = null.asInstanceOf[SigmaLibrary] // ok! type level only
- registerClassEntry(clazz,
- methods = Map(
- mkMethod(clazz, "some", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
- obj.asInstanceOf[ctx.WSpecialPredefCompanion].some(args(0).asInstanceOf[ctx.Ref[Any]])
- }
- )
- )
- }
{
val clazz = classOf[OptionWrapSpec]
registerClassEntry(clazz,
diff --git a/sc/shared/src/main/scala/scalan/Library.scala b/sc/shared/src/main/scala/sigma/compiler/ir/IRContext.scala
similarity index 57%
rename from sc/shared/src/main/scala/scalan/Library.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/IRContext.scala
index ee1ff80ad3..a22962f987 100644
--- a/sc/shared/src/main/scala/scalan/Library.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/IRContext.scala
@@ -1,19 +1,65 @@
-package scalan
+package sigma.compiler.ir
-import scala.language.implicitConversions
-import sigma._
+import sigma.compiler.ir.core.MutableLazy
+import sigma.compiler.ir.primitives._
import sigma.data.{Nullable, RType}
-import special.wrappers.WrappersModule
import sigma.util.MemoizedFunc
-
-trait Library extends Scalan
- with WrappersModule
+import sigma.compiler.ir.wrappers.scala.WOptionsModule
+import sigma.compiler.ir.wrappers.sigma.{CollsModule, SigmaDslModule, WRTypesModule}
+
+/** Aggregate cake with all inter-dependent modules assembled together.
+ * Each instance of this class contains independent IR context, thus many
+ * instances can be created simultaneously.
+ * However, the inner types declared in the traits are path-dependant.
+ * This in particular means that ctx1.Ref[_] and ctx2.Ref[_] are different types.
+ * The typical usage is to create `val ctx = new Scalan` and then import inner
+ * declarations using `import ctx._`.
+ * This way the declaration will be directly available as if they were global
+ * declarations.
+ * At the same time cake design pattern allow to `override` many methods and values
+ * in classed derived from `Scalan`, this is significant benefit over
+ * *everything is global* design.
+ *
+ * It is not used in v5.0 interpreter and thus not part of consensus.
+ * Used in ErgoScript compiler only.
+ *
+ * @see CompiletimeIRContext
+ */
+trait IRContext
+ extends TypeDescs
+ with MethodCalls
+ with Tuples
+ with NumericOps
+ with UnBinOps
+ with LogicalOps
+ with OrderingOps
+ with Equal
+ with MiscOps
+ with Functions
+ with IfThenElse
+ with Transforming
+ with Thunks
+ with Entities
+ with Modules
+ with DefRewriting
with CollsModule
-{
+ with SigmaDslModule
+ with TreeBuilding
+ with GraphBuilding
+ with WOptionsModule
+ with WRTypesModule {
+
+ import Coll._
+ import CollBuilder._
import WOption._
import WRType._
- import Coll._; import CollBuilder._;
- import WSpecialPredef._
+
+ /** Pass configuration which is used to turn-off constant propagation.
+ * USED IN TESTS ONLY.
+ * @see `beginPass(noCostPropagationPass)` */
+ lazy val noConstPropagationPass = new DefaultPass(
+ "noCostPropagationPass",
+ Pass.defaultPassConfig.copy(constantPropagation = false))
type LazyRep[T] = MutableLazy[Ref[T]]
@@ -26,11 +72,7 @@ trait Library extends Scalan
_liftElemMemo(eT).asInstanceOf[Ref[WRType[T]]] // asRep cannot be used for AnyRef
}
- private val _specialPredef: LazyRep[WSpecialPredefCompanionCtor] = MutableLazy(RWSpecialPredef.value)
- def specialPredef: Ref[WSpecialPredefCompanionCtor] = _specialPredef.value
-
override protected def onReset(): Unit = {
- _specialPredef.reset()
_liftElemMemo.reset()
super.onReset()
}
@@ -38,10 +80,15 @@ trait Library extends Scalan
val CM = CollMethods
private val CBM = CollBuilderMethods
private val WOptionM = WOptionMethods
- private val SPCM = WSpecialPredefCompanionMethods
def colBuilder: Ref[CollBuilder]
+ /** Type descriptor for [[WRType]] */
+ implicit lazy val wRTypeAnyElement: Elem[WRType[Any]] = wRTypeElement(AnyElement)
+
+ /** During compilation represent a global value Global, see also SGlobal type. */
+ def sigmaDslBuilder: Ref[SigmaDslBuilder]
+
object IsNumericToInt {
def unapply(d: Def[_]): Nullable[Ref[A] forSome {type A}] = d match {
case ApplyUnOp(_: NumericToInt[_], x) => Nullable(x.asInstanceOf[Ref[A] forSome {type A}])
@@ -96,8 +143,6 @@ trait Library extends Scalan
}
case WOptionM.getOrElse(opt, _) => opt.node match {
- // Rule: Some(x).getOrElse(_) ==> x
- case SPCM.some(x) => x
case WOptionConst(Some(x), lA) => lA.lift(x)
case _ => super.rewriteDef(d)
}
@@ -107,8 +152,8 @@ trait Library extends Scalan
override def invokeUnlifted(e: Elem[_], mc: MethodCall, dataEnv: DataEnv): Any = e match {
case _: CollElem[_,_] => mc match {
- case CollMethods.map(xs, f) =>
- val newMC = mc.copy(args = mc.args :+ f.elem.eRange)(mc.resultType, mc.isAdapterCall)
+ case CollMethods.map(_, f) =>
+ val newMC = mc.copy(args = mc.args :+ f.elem.eRange)(mc.resultType, mc.isAdapterCall, mc.typeSubst)
super.invokeUnlifted(e, newMC, dataEnv)
case _ =>
super.invokeUnlifted(e, mc, dataEnv)
@@ -118,3 +163,6 @@ trait Library extends Scalan
}
}
+
+/** IR context to be used by script development tools to compile ErgoScript into ErgoTree bytecode. */
+class CompiletimeIRContext extends IRContext
diff --git a/sc/shared/src/main/scala/scalan/MethodCalls.scala b/sc/shared/src/main/scala/sigma/compiler/ir/MethodCalls.scala
similarity index 82%
rename from sc/shared/src/main/scala/scalan/MethodCalls.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/MethodCalls.scala
index af3c3201ef..089b76cae4 100644
--- a/sc/shared/src/main/scala/scalan/MethodCalls.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/MethodCalls.scala
@@ -1,13 +1,17 @@
-package scalan
+package sigma.compiler.ir
-import scala.annotation.{tailrec, unused}
-import scala.reflect.ClassTag
-import debox.{Buffer => DBuffer}
-import debox.cfor
+import debox.{cfor, Buffer => DBuffer}
+import sigma.ast.{SType, STypeVar}
+import sigma.compiler.DelayInvokeException
import sigma.reflection.RMethod
import sigma.util.CollectionUtil.TraversableOps
-trait MethodCalls extends Base { self: Scalan =>
+import scala.annotation.{tailrec, unused}
+
+/** Defines graph-ir representation of method calls, new object creation as well as the
+ * related utility methods.
+ */
+trait MethodCalls extends Base { self: IRContext =>
def delayInvoke = throw new DelayInvokeException
@@ -23,7 +27,9 @@ trait MethodCalls extends Base { self: Scalan =>
* given `method`.
*/
case class MethodCall private[MethodCalls](receiver: Sym, method: RMethod, args: Seq[AnyRef], neverInvoke: Boolean)
- (val resultType: Elem[Any], val isAdapterCall: Boolean = false) extends Def[Any] {
+ (val resultType: Elem[Any],
+ val isAdapterCall: Boolean = false,
+ val typeSubst: Map[STypeVar, SType]) extends Def[Any] {
override def mirror(t: Transformer): Ref[Any] = {
val len = args.length
@@ -96,14 +102,14 @@ trait MethodCalls extends Base { self: Scalan =>
}
/** Creates new MethodCall node and returns its node ref. */
- def mkMethodCall(receiver: Sym, method: RMethod, args: Seq[AnyRef],
- neverInvoke: Boolean, isAdapterCall: Boolean, resultElem: Elem[_]): Sym = {
- reifyObject(MethodCall(receiver, method, args, neverInvoke)(asElem[Any](resultElem), isAdapterCall))
- }
-
- /** Creates new NewObject node and returns its node ref. */
- def newObjEx[A](args: Any*)(implicit eA: Elem[A]): Ref[A] = {
- reifyObject(NewObject[A](eA, args))
+ def mkMethodCall(receiver: Sym,
+ method: RMethod,
+ args: Seq[AnyRef],
+ neverInvoke: Boolean,
+ isAdapterCall: Boolean,
+ resultElem: Elem[_],
+ typeSubst: Map[STypeVar, SType] = Map.empty): Sym = {
+ reifyObject(MethodCall(receiver, method, args, neverInvoke)(asElem[Any](resultElem), isAdapterCall, typeSubst))
}
@tailrec
@@ -120,23 +126,8 @@ trait MethodCalls extends Base { self: Scalan =>
* point we know that the first RW set didn't triggered any rewrite. */
def rewriteNonInvokableMethodCall(@unused mc: MethodCall): Ref[_] = null
- /** Create delegate instance suitable for method invocation.
- * It is used when T is a class or a trait and the node referred by x doesn't conform to T.
- * This method returns dynamically constructed instance, which conforms to T.
- * Whenever a method of T is called on that instance, the call is intercepted and
- * `DelegatedInterceptionHandler.invoke` method is called, then a new MethodCall can
- * be constructed (which is befavior by default).
- */
- protected def unrefDelegate[T <: AnyRef](x: Ref[T])(implicit ct: ClassTag[T]): T = {
- val d = x.node
- if (d.isInstanceOf[Const[_]])
- d.asInstanceOf[Const[T]@unchecked].x
- else
- !!!(s"Cannot do undefDelegate($x -> ${x.node})")
- }
-
/** Generic helper to call the given method on the given receiver node. */
- private[scalan] def invokeMethod[A](receiver: Sym, m: RMethod, args: Array[AnyRef],
+ private[compiler] def invokeMethod[A](receiver: Sym, m: RMethod, args: Array[AnyRef],
onInvokeSuccess: Any => A,
onInvokeException: Throwable => A,
onInvokeImpossible: => A): A = {
@@ -148,9 +139,9 @@ trait MethodCalls extends Base { self: Scalan =>
} catch {
case e: Exception => onInvokeException(baseCause(e))
}
- }
- else
+ } else {
onInvokeImpossible
+ }
}
/** Method invocation enabler.
diff --git a/sc/shared/src/main/scala/scalan/Modules.scala b/sc/shared/src/main/scala/sigma/compiler/ir/Modules.scala
similarity index 70%
rename from sc/shared/src/main/scala/scalan/Modules.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/Modules.scala
index 989f2c524c..b58bacb5fb 100644
--- a/sc/shared/src/main/scala/scalan/Modules.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/Modules.scala
@@ -1,6 +1,11 @@
-package scalan
+package sigma.compiler.ir
-trait Modules extends Base { self: Scalan =>
+import sigma.compiler.ir.meta.ModuleInfo
+
+/** Defines registration of IR modules.
+ * @see ModuleInfo
+ */
+trait Modules extends Base { self: IRContext =>
/** Whether staged modules should be registered when cake is constructed and initialized. */
def okRegisterModules: Boolean = false
diff --git a/sc/shared/src/main/scala/scalan/staged/ProgramGraphs.scala b/sc/shared/src/main/scala/sigma/compiler/ir/ProgramGraphs.scala
similarity index 92%
rename from sc/shared/src/main/scala/scalan/staged/ProgramGraphs.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/ProgramGraphs.scala
index ccb351e7a2..6f447d97f9 100644
--- a/sc/shared/src/main/scala/scalan/staged/ProgramGraphs.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/ProgramGraphs.scala
@@ -1,13 +1,13 @@
-package scalan.staged
+package sigma.compiler.ir
-import scalan.Scalan
-import debox.{Buffer => DBuffer}
-import sigma.util.GraphUtil
-import debox.cfor
+import debox.{cfor, Buffer => DBuffer}
import sigma.data.{DFunc, Nullable}
+import sigma.util.GraphUtil
+
import scala.collection.compat.immutable.ArraySeq
-trait ProgramGraphs extends AstGraphs { self: Scalan =>
+/** Defines implementation of [[ProgramGraph]] and related utilities. */
+trait ProgramGraphs extends AstGraphs { self: IRContext =>
type PGraph = ProgramGraph
diff --git a/sc/shared/src/main/scala/scalan/staged/Transforming.scala b/sc/shared/src/main/scala/sigma/compiler/ir/Transforming.scala
similarity index 97%
rename from sc/shared/src/main/scala/scalan/staged/Transforming.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/Transforming.scala
index cd1fac9fd0..876f2b5db1 100644
--- a/sc/shared/src/main/scala/scalan/staged/Transforming.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/Transforming.scala
@@ -1,14 +1,18 @@
-package scalan.staged
+package sigma.compiler.ir
-import java.util
-import scala.language.existentials
-import scalan.Scalan
-import debox.{Buffer => DBuffer}
-import debox.cfor
+import debox.{cfor, Buffer => DBuffer}
import sigma.data.{Lazy, Nullable}
import sigma.reflection.RMethod
-trait Transforming { self: Scalan =>
+import java.util
+import scala.language.existentials
+
+/** Implements utilites for graph transformation and rewriting.
+ * @see Pass
+ * @see MapTransformer
+ * @see Rewriter
+ */
+trait Transforming { self: IRContext =>
/** Descriptor of a current compiler pass.
* Compiler can be configured to perform one pass after another.
@@ -47,9 +51,6 @@ trait Transforming { self: Scalan =>
constantPropagation: Boolean = true,
/** Used in SlicingPass */
shouldSlice: Boolean = false)
- {
- def withConstantPropagation(value: Boolean) = this.copy(constantPropagation = value)
- }
/** Default pass to be used when IR is used without special compiler configuration. */
class DefaultPass(val name: String, override val config: PassConfig = PassConfig()) extends Pass
diff --git a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala
similarity index 81%
rename from sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala
index 26bc33956f..37ec47f2dc 100644
--- a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala
@@ -1,16 +1,17 @@
-package sigmastate.eval
+package sigma.compiler.ir
-
-import sigma.ast._
import org.ergoplatform._
-import sigma.ast.syntax.ValueOps
-import sigma.serialization.OpCodes._
-import sigma.serialization.ConstantStore
-import sigma.ast.syntax._
+import sigma.VersionContext
+import sigma.Evaluation.{rtypeToSType, stypeToRType}
+import sigma.ast.SType.tT
+import sigma.ast._
+import sigma.ast.syntax.{ValueOps, _}
import sigma.data.{ProveDHTuple, ProveDlog}
+import sigma.serialization.ConstantStore
+import sigma.serialization.OpCodes._
+import sigma.serialization.ValueCodes.OpCode
import scala.collection.mutable.ArrayBuffer
-import sigma.serialization.ValueCodes.OpCode
/** Implementation of IR-graph to ErgoTree expression translation.
* This, in a sense, is inverse to [[GraphBuilding]], however roundtrip identity is not
@@ -24,17 +25,17 @@ import sigma.serialization.ValueCodes.OpCode
*
* @see buildTree method
* */
-trait TreeBuilding extends SigmaLibrary { IR: IRContext =>
- import Liftables._
- import Context._
- import SigmaProp._
- import Coll._
+trait TreeBuilding extends Base { IR: IRContext =>
+ import BigInt._
import Box._
+ import Coll._
import CollBuilder._
+ import Context._
+ import GroupElement._
+ import Liftables._
import SigmaDslBuilder._
- import BigInt._
+ import SigmaProp._
import WOption._
- import GroupElement._
/** Convenience synonyms for easier pattern matching. */
private val ContextM = ContextMethods
@@ -108,6 +109,27 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext =>
object IsNumericUnOp {
def unapply(op: UnOp[_,_]): Option[SValue => SValue] = op match {
case NumericNegate(_) => Some({ v: SValue => builder.mkNegation(v.asNumValue) })
+ case _: NumericToBigEndianBytes[_] =>
+ val mkNode = { v: SValue =>
+ val receiverType = v.tpe.asNumTypeOrElse(error(s"Expected numeric type, got: ${v.tpe}"))
+ val m = SMethod.fromIds(receiverType.typeId, SNumericTypeMethods.ToBytesMethod.methodId)
+ builder.mkMethodCall(v.asNumValue, m, IndexedSeq.empty)
+ }
+ Some(mkNode)
+ case _: NumericToBits[_] =>
+ val mkNode = { v: SValue =>
+ val receiverType = v.tpe.asNumTypeOrElse(error(s"Expected numeric type, got: ${v.tpe}"))
+ val m = SMethod.fromIds(receiverType.typeId, SNumericTypeMethods.ToBitsMethod.methodId)
+ builder.mkMethodCall(v.asNumValue, m, IndexedSeq.empty)
+ }
+ Some(mkNode)
+ case _: NumericBitwiseInverse[_] =>
+ val mkNode = { v: SValue =>
+ val receiverType = v.tpe.asNumTypeOrElse(error(s"Expected numeric type, got: ${v.tpe}"))
+ val m = SMethod.fromIds(receiverType.typeId, SNumericTypeMethods.BitwiseInverseMethod.methodId)
+ builder.mkMethodCall(v.asNumValue, m, IndexedSeq.empty)
+ }
+ Some(mkNode)
case _ => None
}
}
@@ -130,7 +152,7 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext =>
*/
object IsInternalDef {
def unapply(d: Def[_]): Option[Def[_]] = d match {
- case _: SigmaDslBuilder | _: CollBuilder | _: WSpecialPredefCompanion => Some(d)
+ case _: SigmaDslBuilder | _: CollBuilder => Some(d)
case _ => None
}
}
@@ -161,7 +183,7 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext =>
case _ if env.contains(s) =>
val (id, tpe) = env(s)
ValUse(id, tpe) // recursion base
- case Def(Lambda(lam, _, x, y)) =>
+ case Def(Lambda(lam, _, x, _)) =>
val varId = defId + 1 // arguments are treated as ValDefs and occupy id space
val env1 = env + (x -> (varId, elemToSType(x.elem)))
val block = processAstGraph(ctx, mainG, env1, lam, varId + 1, constantsProcessing)
@@ -170,7 +192,7 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext =>
case Def(Apply(fSym, xSym, _)) =>
val Seq(f, x) = Seq(fSym, xSym).map(recurse)
builder.mkApply(f, Array(x))
- case Def(th @ ThunkDef(root, _)) =>
+ case Def(th @ ThunkDef(_, _)) =>
val block = processAstGraph(ctx, mainG, env, th, defId, constantsProcessing)
block
case Def(Const(x)) =>
@@ -181,8 +203,16 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext =>
.asInstanceOf[ConstantNode[SType]]
s.put(constant)(builder)
case None =>
- mkConstant[tpe.type](x.asInstanceOf[tpe.WrappedType], tpe)
+ if(x.isInstanceOf[CollConst[_, _]]) { // hack used to process NumericToBigEndianBytes only
+ mkConstant[tpe.type](x.asInstanceOf[CollConst[_, _]].constValue.asInstanceOf[tpe.WrappedType], tpe)
+ } else {
+ mkConstant[tpe.type](x.asInstanceOf[tpe.WrappedType], tpe)
+ }
}
+ case Def(IR.ConstantPlaceholder(id, elem)) =>
+ val tpe = elemToSType(elem)
+ mkConstantPlaceholder[tpe.type](id, tpe)
+
case Def(wc: LiftedConst[a,_]) =>
val tpe = elemToSType(s.elem)
mkConstant[tpe.type](wc.constValue.asInstanceOf[tpe.WrappedType], tpe)
@@ -190,6 +220,37 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext =>
case Def(IsContextProperty(v)) => v
case s if s == sigmaDslBuilder => Global
+ case Def(ApplyBinOp(op, xSym, ySym)) if op.isInstanceOf[NumericBitwiseOr[_]] =>
+ val Seq(x, y) = Seq(xSym, ySym).map(recurse)
+ val receiverType = x.asNumValue.tpe.asNumTypeOrElse(error(s"Expected numeric type, got: ${x.tpe}"))
+ val m = SMethod.fromIds(receiverType.typeId, SNumericTypeMethods.BitwiseOrMethod.methodId)
+ builder.mkMethodCall(x.asNumValue, m, IndexedSeq(y))
+
+ case Def(ApplyBinOp(op, xSym, ySym)) if op.isInstanceOf[NumericBitwiseAnd[_]] =>
+ val Seq(x, y) = Seq(xSym, ySym).map(recurse)
+ val receiverType = x.asNumValue.tpe.asNumTypeOrElse(error(s"Expected numeric type, got: ${x.tpe}"))
+ val m = SMethod.fromIds(receiverType.typeId, SNumericTypeMethods.BitwiseAndMethod.methodId)
+ builder.mkMethodCall(x.asNumValue, m, IndexedSeq(y))
+
+ case Def(ApplyBinOp(op, xSym, ySym)) if op.isInstanceOf[NumericBitwiseXor[_]] =>
+ val Seq(x, y) = Seq(xSym, ySym).map(recurse)
+ val receiverType = x.asNumValue.tpe.asNumTypeOrElse(error(s"Expected numeric type, got: ${x.tpe}"))
+ val m = SMethod.fromIds(receiverType.typeId, SNumericTypeMethods.BitwiseXorMethod.methodId)
+ builder.mkMethodCall(x.asNumValue, m, IndexedSeq(y))
+
+ case Def(ApplyBinOpDiffArgs(op, xSym, ySym)) if op.isInstanceOf[NumericShiftLeft[_]] =>
+ val Seq(x, y) = Seq(xSym, ySym).map(recurse)
+ val receiverType = x.asNumValue.tpe.asNumTypeOrElse(error(s"Expected numeric type, got: ${x.tpe}"))
+ val m = SMethod.fromIds(receiverType.typeId, SNumericTypeMethods.ShiftLeftMethod.methodId)
+ builder.mkMethodCall(x.asNumValue, m, IndexedSeq(y))
+
+ case Def(ApplyBinOpDiffArgs(op, xSym, ySym)) if op.isInstanceOf[NumericShiftRight[_]] =>
+ val Seq(x, y) = Seq(xSym, ySym).map(recurse)
+ val receiverType = x.asNumValue.tpe.asNumTypeOrElse(error(s"Expected numeric type, got: ${x.tpe}"))
+ val m = SMethod.fromIds(receiverType.typeId, SNumericTypeMethods.ShiftRightMethod.methodId)
+ builder.mkMethodCall(x.asNumValue, m, IndexedSeq(y))
+
+
case Def(ApplyBinOp(IsArithOp(opCode), xSym, ySym)) =>
val Seq(x, y) = Seq(xSym, ySym).map(recurse)
mkArith(x.asNumValue, y.asNumValue, opCode)
@@ -288,13 +349,10 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext =>
mkExtractAmount(box.asBox)
case BoxM.propositionBytes(In(box)) =>
mkExtractScriptBytes(box.asBox)
- case BoxM.getReg(In(box), regId, _) =>
+ case BoxM.getReg(In(box), regId, _) if regId.isConst =>
val tpe = elemToSType(s.elem).asOption
- if (regId.isConst)
- mkExtractRegisterAs(box.asBox, ErgoBox.allRegisters(valueFromRep(regId)), tpe)
- else
- error(s"Non constant expressions (${regId.node}) are not supported in getReg")
- case BoxM.creationInfo(In(box)) =>
+ mkExtractRegisterAs(box.asBox, ErgoBox.allRegisters(valueFromRep(regId)), tpe)
+ case BoxM.creationInfo(In(box)) =>
mkExtractCreationInfo(box.asBox)
case BoxM.id(In(box)) =>
mkExtractId(box.asBox)
@@ -397,13 +455,14 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext =>
mkMultiplyGroup(obj.asGroupElement, arg.asGroupElement)
// Fallback MethodCall rule: should be the last in this list of cases
- case Def(MethodCall(objSym, m, argSyms, _)) =>
+ case Def(mc @ MethodCall(objSym, m, argSyms, _)) =>
val obj = recurse[SType](objSym)
val args = argSyms.collect { case argSym: Sym => recurse[SType](argSym) }
MethodsContainer.getMethod(obj.tpe, m.getName) match {
case Some(method) =>
- val specMethod = method.specializeFor(obj.tpe, args.map(_.tpe))
- builder.mkMethodCall(obj, specMethod, args.toIndexedSeq, Map())
+ val typeSubst = mc.typeSubst
+ val specMethod = method.specializeFor(obj.tpe, args.map(_.tpe)).withConcreteTypes(typeSubst)
+ builder.mkMethodCall(obj, specMethod, args.toIndexedSeq, typeSubst)
case None =>
error(s"Cannot find method ${m.getName} in object $obj")
}
@@ -449,7 +508,7 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext =>
(valdefs.toArray[BlockItem], rhs) match {
// simple optimization to avoid producing block sub-expressions like:
// `{ val idNew = id; idNew }` which this rules rewrites to just `id`
- case (Array(ValDef(idNew, _, source @ ValUse(id, tpe))), ValUse(idUse, tpeUse))
+ case (Array(ValDef(idNew, _, source @ ValUse(_, tpe))), ValUse(idUse, tpeUse))
if idUse == idNew && tpeUse == tpe => source
case (items, _) =>
BlockValue(items, rhs)
diff --git a/sc/shared/src/main/scala/scalan/TypeDescs.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TypeDescs.scala
similarity index 97%
rename from sc/shared/src/main/scala/scalan/TypeDescs.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/TypeDescs.scala
index fdef77a108..366107edca 100644
--- a/sc/shared/src/main/scala/scalan/TypeDescs.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/TypeDescs.scala
@@ -1,18 +1,22 @@
-package scalan
+package sigma.compiler.ir
-import scala.language.implicitConversions
-import scala.annotation.implicitNotFound
-import scala.collection.immutable.ListMap
-
-import scala.collection.mutable
import debox.cfor
import scalan.core.{Contravariant, Covariant, Variance}
import sigma.data.{AVHashMap, Lazy, Nullable, RType}
import sigma.reflection.{RClass, RConstructor, RMethod}
import sigma.util.CollectionUtil
-import special.wrappers.WrapSpec
+import sigma.compiler.ir.wrappers.WrapSpec
+
+import scala.annotation.implicitNotFound
+import scala.collection.immutable.ListMap
+import scala.collection.mutable
+import scala.language.implicitConversions
-abstract class TypeDescs extends Base { self: Scalan =>
+/** Defines [[Elem]] descriptor of types in IRContext together with related utilities.
+ * @see MethodDesc
+ * @see TypeDesc
+ */
+abstract class TypeDescs extends Base { self: IRContext =>
/** Helper type case method. */
@inline final def asElem[T](d: TypeDesc): Elem[T] = d.asInstanceOf[Elem[T]]
@@ -267,7 +271,7 @@ abstract class TypeDescs extends Base { self: Scalan =>
e.invokeUnlifted(mc, dataEnv)
/** Get first (and the only) constructor of the `clazz`. */
- private[scalan] final def getConstructor(clazz: RClass[_]): RConstructor[_] = {
+ private[compiler] final def getConstructor(clazz: RClass[_]): RConstructor[_] = {
val constructors = clazz.getConstructors()
if (constructors.length != 1)
!!!(s"Element class $clazz has ${constructors.length} constructors, 1 expected")
@@ -297,7 +301,7 @@ abstract class TypeDescs extends Base { self: Scalan =>
protected val elemCache = AVHashMap[RClass[_], ElemCacheEntry](1000)
- private[scalan] final def cachedElem0(clazz: RClass[_], optConstructor: Nullable[RConstructor[_]], args: Seq[AnyRef]): Elem[_] = {
+ private[compiler] final def cachedElem0(clazz: RClass[_], optConstructor: Nullable[RConstructor[_]], args: Seq[AnyRef]): Elem[_] = {
val entry = elemCache.get(clazz) match {
case Nullable(entry) => entry
case _ =>
diff --git a/sc/shared/src/main/scala/scalan/MutableLazy.scala b/sc/shared/src/main/scala/sigma/compiler/ir/core/MutableLazy.scala
similarity index 96%
rename from sc/shared/src/main/scala/scalan/MutableLazy.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/core/MutableLazy.scala
index 5b6a579476..efaab623a3 100644
--- a/sc/shared/src/main/scala/scalan/MutableLazy.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/core/MutableLazy.scala
@@ -1,4 +1,4 @@
-package scalan
+package sigma.compiler.ir.core
import scala.language.implicitConversions
diff --git a/sc/shared/src/main/scala/scalan/core/Variance.scala b/sc/shared/src/main/scala/sigma/compiler/ir/core/Variance.scala
similarity index 100%
rename from sc/shared/src/main/scala/scalan/core/Variance.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/core/Variance.scala
diff --git a/sc/shared/src/main/scala/scalan/ModuleInfo.scala b/sc/shared/src/main/scala/sigma/compiler/ir/meta/ModuleInfo.scala
similarity index 90%
rename from sc/shared/src/main/scala/scalan/ModuleInfo.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/meta/ModuleInfo.scala
index 86fce48ce6..3ccdca18ac 100644
--- a/sc/shared/src/main/scala/scalan/ModuleInfo.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/meta/ModuleInfo.scala
@@ -1,6 +1,4 @@
-package scalan
-
-import scalan.meta.SSymName
+package sigma.compiler.ir.meta
/** Information about generated Special library module.
* Instances are created in generated code.
diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/meta/SSymName.scala b/sc/shared/src/main/scala/sigma/compiler/ir/meta/SSymName.scala
new file mode 100644
index 0000000000..944b505250
--- /dev/null
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/meta/SSymName.scala
@@ -0,0 +1,13 @@
+package sigma.compiler.ir.meta
+
+import sigma.util.StringUtil.StringUtilExtensions
+
+case class SSymName(packageName: String, name: String) {
+ import SSymName._
+ def mkFullName = fullNameString(packageName, name)
+}
+
+object SSymName {
+ def fullNameString(packageName: String, name: String): String =
+ if (packageName.isNullOrEmpty) name else s"$packageName.$name"
+}
\ No newline at end of file
diff --git a/sc/shared/src/main/scala/scalan/primitives/Equal.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/Equal.scala
similarity index 84%
rename from sc/shared/src/main/scala/scalan/primitives/Equal.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/primitives/Equal.scala
index 4d64e94383..ec27fff12b 100644
--- a/sc/shared/src/main/scala/scalan/primitives/Equal.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/Equal.scala
@@ -1,10 +1,11 @@
-package scalan.primitives
+package sigma.compiler.ir.primitives
-import scalan.{Base, Scalan}
+import sigma.compiler.ir.{Base, IRContext}
import scala.annotation.unused
-trait Equal extends Base { self: Scalan =>
+/** Defines IR representation of equality operations. */
+trait Equal extends Base { self: IRContext =>
/** Binary operation representing structural equality between arguments. */
case class Equals[A: Elem]() extends BinOp[A, Boolean]("==") {
override def applySeq(x: A, y: A): Boolean = equalValues[A](x, y)
diff --git a/sc/shared/src/main/scala/scalan/primitives/Functions.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/Functions.scala
similarity index 96%
rename from sc/shared/src/main/scala/scalan/primitives/Functions.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/primitives/Functions.scala
index 31a6ca8d81..cd028de9b6 100644
--- a/sc/shared/src/main/scala/scalan/primitives/Functions.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/Functions.scala
@@ -1,27 +1,20 @@
-package scalan.primitives
+package sigma.compiler.ir.primitives
-import java.util
-import scalan.staged.ProgramGraphs
-import scalan.{Base, Scalan}
-import debox.{Buffer => DBuffer}
-
-import scala.language.implicitConversions
-import debox.cfor
+import debox.{cfor, Buffer => DBuffer}
+import sigma.compiler.ir.{Base, IRContext, ProgramGraphs}
import sigma.data.{Lazy, Nullable, emptyDBufferOfInt}
import sigma.util.GraphUtil
-trait Functions extends Base with ProgramGraphs { self: Scalan =>
+import java.util
+import scala.language.implicitConversions
+
+/** Defines IR representation of functions (Lambdas) and function application. */
+trait Functions extends Base with ProgramGraphs { self: IRContext =>
implicit class LambdaOps[A,B](f: Ref[A => B]) {
/** Apply given function symbol to the given argument symbol.
* @return symbol representing result of function application */
final def apply(x: Ref[A]): Ref[B] = mkApply(f, x)
-
- /** Build new function which applies `f` and then `g`*/
- final def >>[C](g: Ref[B => C]): Ref[A => C] = compose(g, f)
-
- /** Build new function which applies `g` and then `f`*/
- final def <<[C](g: Ref[C => A]): Ref[C => B] = compose(f, g)
}
/** Global lambda equality mode used by default. It is used in `fun` and `fun2` lambda builders.
@@ -151,10 +144,6 @@ trait Functions extends Base with ProgramGraphs { self: Scalan =>
// emitDepGraph(roots, FileUtil.file(cwd, dir), "nested_lambda")(defaultGraphVizConfig)
assert(false, s"Invalid nested lambda $l inside $this")
}
- case op @ OpCost(_, _, args, opCost) =>
- if (args.contains(opCost)) {
- !!!(s"Invalid OpCost($op)")
- }
case _ =>
}
}
diff --git a/sc/shared/src/main/scala/scalan/primitives/IfThenElse.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/IfThenElse.scala
similarity index 90%
rename from sc/shared/src/main/scala/scalan/primitives/IfThenElse.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/primitives/IfThenElse.scala
index 22fd2095d7..0ce94a83c1 100644
--- a/sc/shared/src/main/scala/scalan/primitives/IfThenElse.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/IfThenElse.scala
@@ -1,8 +1,9 @@
-package scalan.primitives
+package sigma.compiler.ir.primitives
-import scalan.{Base, Scalan}
+import sigma.compiler.ir.{Base, IRContext}
-trait IfThenElse extends Base { self: Scalan =>
+/** Defines IR representation of conditional expressions `if (c) t else e`. */
+trait IfThenElse extends Base { self: IRContext =>
/** If c then t else e construction with standard lazy evaluation of branches.
* The representation uses Thunk for each branch */
diff --git a/sc/shared/src/main/scala/scalan/primitives/LogicalOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/LogicalOps.scala
similarity index 91%
rename from sc/shared/src/main/scala/scalan/primitives/LogicalOps.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/primitives/LogicalOps.scala
index e81b546139..183b4a8e84 100644
--- a/sc/shared/src/main/scala/scalan/primitives/LogicalOps.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/LogicalOps.scala
@@ -1,9 +1,9 @@
-package scalan.primitives
+package sigma.compiler.ir.primitives
-import scalan.{Base, Scalan}
+import sigma.compiler.ir.{Base, IRContext}
-/** Slice in Scala cake with definitions of logical operations. */
-trait LogicalOps extends Base { self: Scalan =>
+/** Slice in IRContext cake with definitions of logical operations. */
+trait LogicalOps extends Base { self: IRContext =>
/** Logical AND binary operation. */
val And = new EndoBinOp[Boolean]("&&") {
override def applySeq(x: Boolean, y: Boolean): Boolean = x && y
diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/MiscOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/MiscOps.scala
new file mode 100644
index 0000000000..58382a279c
--- /dev/null
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/MiscOps.scala
@@ -0,0 +1,44 @@
+package sigma.compiler.ir.primitives
+
+import sigma.compiler.ir.{Base, IRContext}
+
+/** Defines IR representation of miscellaneous operations that doesn't fit into any
+ * specific category.
+ */
+trait MiscOps extends Base { self: IRContext =>
+ case class HashCode[A]() extends UnOp[A, Int]("hashCode") {
+ override def applySeq(x: A): Int = x.hashCode
+ }
+
+ case class ToString[A]() extends UnOp[A, String]("toString") {
+ override def applySeq(x: A): String = x.toString
+ }
+
+ case class Downcast[From, To](input: Ref[From], eTo: Elem[To]) extends BaseDef[To]()(eTo) {
+ override def transform(t: Transformer) = Downcast(t(input), eTo)
+ }
+ case class Upcast[From, To](input: Ref[From], eTo: Elem[To]) extends BaseDef[To]()(eTo) {
+ override def transform(t: Transformer) = Upcast(t(input), eTo)
+ }
+
+ def downcast[To:Elem](value: Ref[_]): Ref[To] = Downcast(value, element[To])
+ def upcast[To:Elem](value: Ref[_]): Ref[To] = Upcast(value, element[To])
+
+ implicit class RepUniversalOps[A](x: Ref[A]) {
+ def hashCodeRep: Ref[Int] = HashCode[A]().apply(x)
+ def toStringRep = ToString[A]().apply(x)
+ }
+
+ case class Convert[From,To](eFrom: Elem[From], eTo: Elem[To], x: Ref[Def[_]], conv: Ref[From => To])
+ extends BaseDef[To]()(eTo) {
+ override def transform(t: Transformer) = Convert(eFrom, eTo, t(x), t(conv))
+ }
+
+ def tryConvert[From, To](eFrom: Elem[From], eTo: Elem[To], x: Ref[Def[_]], conv: Ref[From => To]): Ref[To] = {
+ if (x.elem <:< eFrom)
+ conv(asRep[From](x))
+ else
+ Convert(eFrom, eTo, x, conv)
+ }
+
+}
diff --git a/sc/shared/src/main/scala/scalan/primitives/NumericOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala
similarity index 63%
rename from sc/shared/src/main/scala/scalan/primitives/NumericOps.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala
index 3c3d80e94d..5b858d8586 100644
--- a/sc/shared/src/main/scala/scalan/primitives/NumericOps.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala
@@ -1,10 +1,10 @@
-package scalan.primitives
+package sigma.compiler.ir.primitives
-import scalan.{Base, Scalan}
+import sigma.compiler.ir.{Base, IRContext}
import sigma.data.{ExactIntegral, ExactNumeric}
-/** Slice in Scala cake with definitions of numeric operations. */
-trait NumericOps extends Base { self: Scalan =>
+/** Slice in IRContext cake with definitions of numeric operations. */
+trait NumericOps extends Base { self: IRContext =>
/** Extension methods over `Ref[T]` where T is instance of ExactNumeric type-class. */
implicit class NumericOpsCls[T](x: Ref[T])(implicit val n: ExactNumeric[T]) {
@@ -14,6 +14,7 @@ trait NumericOps extends Base { self: Scalan =>
def unary_- : Ref[T] = NumericNegate(n)(x.elem).apply(x)
def toInt: Ref[Int] = NumericToInt(n).apply(x)
def toLong: Ref[Long] = NumericToLong(n).apply(x)
+ def toBigEndianBytes: Ref[Coll[Byte]] = NumericToBigEndianBytes(n).apply(x)
}
/** Extension methods over `Ref[T]` where T is instance of ExactIntegral type-class. */
@@ -46,6 +47,27 @@ trait NumericOps extends Base { self: Scalan =>
override def applySeq(x: T, y: T): T = n.times(x, y)
}
+ /** Descriptor of unary `ToBits` conversion operation. */
+ case class NumericBitwiseOr[T: Elem](n: ExactNumeric[T]) extends EndoBinOp[T]("|") {
+ override def applySeq(x: T, y: T): T = n.bitwiseOr(x, y)
+ }
+
+ case class NumericBitwiseAnd[T: Elem](n: ExactNumeric[T]) extends EndoBinOp[T]("&") {
+ override def applySeq(x: T, y: T): T = n.bitwiseAnd(x, y)
+ }
+
+ case class NumericBitwiseXor[T: Elem](n: ExactNumeric[T]) extends EndoBinOp[T]("^") {
+ override def applySeq(x: T, y: T): T = n.bitwiseXor(x, y)
+ }
+
+ case class NumericShiftLeft[T: Elem](n: ExactNumeric[T]) extends BinDiffArgsOp[T, Int]("<<") {
+ override def applySeq(x: T, y: Int): T = n.shiftLeft(x, y)
+ }
+
+ case class NumericShiftRight[T: Elem](n: ExactNumeric[T]) extends BinDiffArgsOp[T, Int](">>") {
+ override def applySeq(x: T, y: Int): T = n.shiftRight(x, y)
+ }
+
/** Base class for descriptors of binary division operations. */
abstract class DivOp[T: Elem](opName: String, n: ExactIntegral[T]) extends EndoBinOp[T](opName) {
override def shouldPropagate(lhs: T, rhs: T) = rhs != n.zero
@@ -66,6 +88,28 @@ trait NumericOps extends Base { self: Scalan =>
override def applySeq(x: T): Long = n.toLong(x)
}
+ import Coll._
+ /** Descriptor of unary `ToBigEndianBytes` conversion operation. */
+ case class NumericToBigEndianBytes[T](n: ExactNumeric[T])
+ extends UnOp[T, Coll[Byte]]("ToBigEndianBytes")(element[Coll[Byte]]) {
+ override def applySeq(x: T): Coll[Byte] = {
+ liftableColl(Liftables.ByteIsLiftable).lift(n.toBigEndianBytes(x))
+ }
+ }
+
+ /** Descriptor of unary `ToBits` conversion operation. */
+ case class NumericToBits[T](n: ExactNumeric[T])
+ extends UnOp[T, Coll[Boolean]]("ToBits")(element[Coll[Boolean]]) {
+ override def applySeq(x: T): Coll[Boolean] = {
+ liftableColl(Liftables.BooleanIsLiftable).lift(n.toBits(x))
+ }
+ }
+
+ /** Descriptor of unary `BitwiseInverse` conversion operation. */
+ case class NumericBitwiseInverse[T: Elem](n: ExactNumeric[T]) extends UnOp[T, T]("~") {
+ override def applySeq(x: T): T = n.bitwiseInverse(x)
+ }
+
/** Descriptor of binary `/` operation (integral division). */
case class IntegralDivide[T](i: ExactIntegral[T])(implicit elem: Elem[T]) extends DivOp[T]("/", i) {
override def applySeq(x: T, y: T): T = i.quot(x, y)
diff --git a/sc/shared/src/main/scala/scalan/primitives/OrderingOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/OrderingOps.scala
similarity index 91%
rename from sc/shared/src/main/scala/scalan/primitives/OrderingOps.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/primitives/OrderingOps.scala
index 8e6f5e0134..be8f934706 100644
--- a/sc/shared/src/main/scala/scalan/primitives/OrderingOps.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/OrderingOps.scala
@@ -1,12 +1,12 @@
-package scalan.primitives
+package sigma.compiler.ir.primitives
-import scalan.{Base, Scalan}
+import sigma.compiler.ir.{Base, IRContext}
import sigma.data.ExactOrdering
import scala.language.implicitConversions
-/** Slice in Scala cake with definitions of comparison operations. */
-trait OrderingOps extends Base { self: Scalan =>
+/** Slice in IRContext cake with definitions of comparison operations. */
+trait OrderingOps extends Base { self: IRContext =>
implicit def repOrderingToOrderingOps[T](x: Ref[T])(implicit n: ExactOrdering[T]) = new OrderingOpsCls(x)
implicit def OrderingToOrderingOps[T](x: T)(implicit n: ExactOrdering[T], et: Elem[T]) = new OrderingOpsCls(toRep(x))
diff --git a/sc/shared/src/main/scala/scalan/primitives/Thunks.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/Thunks.scala
similarity index 98%
rename from sc/shared/src/main/scala/scalan/primitives/Thunks.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/primitives/Thunks.scala
index f9f843664d..8674918907 100644
--- a/sc/shared/src/main/scala/scalan/primitives/Thunks.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/Thunks.scala
@@ -1,22 +1,22 @@
-package scalan.primitives
+package sigma.compiler.ir.primitives
-import scala.language.{existentials, implicitConversions}
-import scalan._
-import debox.{Buffer => DBuffer, Set => DSet}
-import debox.cfor
+import debox.{cfor, Buffer => DBuffer, Set => DSet}
import scalan.core.Covariant
+import sigma.compiler.ir.IRContext
import sigma.data.{AVHashMap, DFunc, Lazy, Nullable, RType}
import sigma.reflection.RClass
import sigma.util.GraphUtil
import scala.collection.Seq
+import scala.language.{existentials, implicitConversions}
-/** Slice in the [[Scalan]] cake with definitions of Thunk operations.
+/** Slice in the [[IRContext]] cake with definitions of Thunk operations.
* See https://en.wikipedia.org/wiki/Thunk.
* Thunks are used to represent lazy operations in the graph IR.
+ *
* @see ApplyBinOpLazy, IfThenElseLazy
*/
-trait Thunks extends Functions { self: Scalan =>
+trait Thunks extends Functions { self: IRContext =>
type Th[+T] = Ref[Thunk[T]]
diff --git a/sc/shared/src/main/scala/scalan/primitives/Tuples.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/Tuples.scala
similarity index 92%
rename from sc/shared/src/main/scala/scalan/primitives/Tuples.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/primitives/Tuples.scala
index fd201b9574..59a5d810b9 100644
--- a/sc/shared/src/main/scala/scalan/primitives/Tuples.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/Tuples.scala
@@ -2,13 +2,15 @@
* Author: Alexander Slesarenko
* Date: 7/25/12
*/
-package scalan.primitives
+package sigma.compiler.ir.primitives
+
+import sigma.compiler.ir.{Base, IRContext}
+import sigma.data.AVHashMap
-import scalan.{Base, Scalan}
import scala.language.implicitConversions
-import sigma.data.{AVHashMap}
-trait Tuples extends Base { self: Scalan =>
+/** Slice in [[IRContext]] cake with definitions of pairs and tuples. */
+trait Tuples extends Base { self: IRContext =>
object Pair {
def apply[A, B](a: Ref[A], b: Ref[B]) = zipPair[A, B]((a, b))
def unapply[A, B](p: Ref[(A, B)]) = Some(unzipPair[A, B](p))
diff --git a/sc/shared/src/main/scala/scalan/primitives/UnBinOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/UnBinOps.scala
similarity index 61%
rename from sc/shared/src/main/scala/scalan/primitives/UnBinOps.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/primitives/UnBinOps.scala
index 749556bf0e..b55596052e 100644
--- a/sc/shared/src/main/scala/scalan/primitives/UnBinOps.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/UnBinOps.scala
@@ -1,8 +1,9 @@
-package scalan.primitives
+package sigma.compiler.ir.primitives
-import scalan.{Scalan, Base}
+import sigma.compiler.ir.{Base, IRContext}
-trait UnBinOps extends Base { self: Scalan =>
+/** Defines IR representation of unary and binary operations. */
+trait UnBinOps extends Base { self: IRContext =>
/** Base class for descriptors of unary operations. */
abstract class UnOp[A, R](val opName: String)(implicit val eResult: Elem[R]) {
@@ -44,6 +45,30 @@ trait UnBinOps extends Base { self: Scalan =>
def shouldPropagate(lhs: A, rhs: A) = true
}
+ /** Base class for descriptors of binary operations where arguments are of different types. */
+ abstract class BinDiffArgsOp[A, B](val opName: String)(implicit val eResult: Elem[A]) {
+ override def toString = opName
+
+ /** Called as part of graph interpretation to execute the given binary operation.
+ * @param x operation argument
+ * @param y operation argument
+ * @return result of applying this operation to (x, y)
+ */
+ def applySeq(x: A, y: B): A
+
+ /** Builds a new graph node by applying this operation to the given arguments. */
+ def apply(lhs: Ref[A], rhs: Ref[B]) = ApplyBinOpDiffArgs(this, lhs, rhs)
+
+ /** Builds a new graph node by applying this operation to the given arguments.
+ * This is a short-cuting (aka lazy) version of the operation, where the lazyness is
+ * represented by Thunk.
+ */
+ def applyLazy(lhs: Ref[A], rhs: Ref[Thunk[B]]) = ApplyBinOpDiffArgsLazy(this, lhs, rhs)
+
+ /** Whether the constants should be propagated through this operations by rewriting. */
+ def shouldPropagate(lhs: A, rhs: B) = true
+ }
+
type EndoUnOp[A] = UnOp[A, A]
type EndoBinOp[A] = BinOp[A, A]
@@ -67,6 +92,19 @@ trait UnBinOps extends Base { self: Scalan =>
override def transform(t: Transformer): Def[R] = ApplyBinOpLazy[A,R](op, t(lhs), t(rhs))
}
+ /** Graph node which represents application of the given binary operation to the given arguments of different types
+ * where the second argument is lazy. */
+ case class ApplyBinOpDiffArgsLazy[A, B](op: BinDiffArgsOp[A, B], lhs: Ref[A], rhs: Ref[Thunk[B]]) extends BaseDef[A]()(op.eResult) {
+ override def toString = s"$lhs $op { $rhs }"
+ override def transform(t: Transformer): Def[A] = ApplyBinOpDiffArgsLazy[A, B](op, t(lhs), t(rhs))
+ }
+
+ /** Graph node which represents application of the given binary operation to the given arguments of different types. */
+ case class ApplyBinOpDiffArgs[A, B](op: BinDiffArgsOp[A, B], lhs: Ref[A], rhs: Ref[B]) extends BaseDef[A]()(op.eResult) {
+ override def toString = s"$op($lhs, $rhs)"
+ override def transform(t: Transformer): Def[A] = ApplyBinOpDiffArgs[A, B](op, t(lhs), t(rhs))
+ }
+
/** Overridable constructor of an unary operation node. */
def applyUnOp[A, R](op: UnOp[A, R], arg: Ref[A]): Ref[R] = ApplyUnOp(op, arg)
diff --git a/sc/shared/src/main/scala/special/wrappers/WrapSpec.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/WrapSpec.scala
similarity index 76%
rename from sc/shared/src/main/scala/special/wrappers/WrapSpec.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/wrappers/WrapSpec.scala
index dd07f1144c..b9c21227b2 100644
--- a/sc/shared/src/main/scala/special/wrappers/WrapSpec.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/WrapSpec.scala
@@ -1,4 +1,4 @@
-package special.wrappers
+package sigma.compiler.ir.wrappers
/** Base type for all wrapper specification classes.
* @see OptionWrapSpec as an example */
diff --git a/sc/shared/src/main/scala/special/wrappers/WrappersSpec.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/WrappersSpec.scala
similarity index 91%
rename from sc/shared/src/main/scala/special/wrappers/WrappersSpec.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/wrappers/WrappersSpec.scala
index d520ce9006..4c0c5f05eb 100644
--- a/sc/shared/src/main/scala/special/wrappers/WrappersSpec.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/WrappersSpec.scala
@@ -1,7 +1,5 @@
-package special.wrappers
-
-import sigma.data.RType
-
+package sigma.compiler.ir.wrappers
+import _root_.sigma.data.RType
/** Base class for wrappers of such types as WOption, WRType etc.
* Used in graph IR to implement method invocation.
*/
diff --git a/sc/shared/src/main/scala/wrappers/scala/WOptions.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/scala/WOptions.scala
similarity index 64%
rename from sc/shared/src/main/scala/wrappers/scala/WOptions.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/wrappers/scala/WOptions.scala
index 4bd314c1de..2ed1237e6b 100644
--- a/sc/shared/src/main/scala/wrappers/scala/WOptions.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/scala/WOptions.scala
@@ -1,9 +1,8 @@
-package wrappers.scala {
- import scalan._
+package sigma.compiler.ir.wrappers.scala {
+ import sigma.compiler.ir.{Base, IRContext}
- import special.wrappers.WrappersModule
-
- trait WOptions extends Base { self: WrappersModule =>
+ /** Defines IR representation of Option type. */
+ trait WOptions extends Base { self: IRContext =>
trait WOption[A] extends Def[WOption[A]] {
implicit def eA: Elem[A];
def isDefined: Ref[Boolean];
diff --git a/sc/shared/src/main/scala/wrappers/scala/impl/WOptionsImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/scala/impl/WOptionsImpl.scala
similarity index 93%
rename from sc/shared/src/main/scala/wrappers/scala/impl/WOptionsImpl.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/wrappers/scala/impl/WOptionsImpl.scala
index 45d0a91ad6..514415d2bd 100644
--- a/sc/shared/src/main/scala/wrappers/scala/impl/WOptionsImpl.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/scala/impl/WOptionsImpl.scala
@@ -1,18 +1,21 @@
-package wrappers.scala
+package sigma.compiler.ir.wrappers.scala
+
+import scala.language.{existentials, implicitConversions}
+import sigma.compiler.ir.IRContext
+import sigma.compiler.ir.wrappers.OptionWrapSpec
-import scala.language.{existentials,implicitConversions}
-import scalan._
-import special.wrappers.WrappersModule
-import special.wrappers.OptionWrapSpec
import scala.collection.compat.immutable.ArraySeq
package impl {
+ import sigma.compiler.ir.meta.ModuleInfo
+ import sigma.compiler.ir.{Base, GraphIRReflection, IRContext}
import sigma.data.{Nullable, RType}
import sigma.reflection.{RClass, RMethod}
// Abs -----------------------------------
-trait WOptionsDefs extends scalan.Scalan with WOptions {
- self: WrappersModule =>
+/** IR representation of Option type and methods. */
+trait WOptionsDefs extends Base with WOptions {
+ self: IRContext =>
class WOptionCls extends EntityObject("WOption") {
// entityConst: single const for each entity
@@ -235,9 +238,9 @@ class WOptionCls extends EntityObject("WOption") {
registerEntityObject("WOption", WOption)
}
-object WOptionsModule extends scalan.ModuleInfo("wrappers.scala", "WOptions") {
+object WOptionsModule extends ModuleInfo("sigma.compiler.ir.wrappers.scala", "WOptions") {
val reflection = GraphIRReflection
}
}
-trait WOptionsModule extends wrappers.scala.impl.WOptionsDefs {self: WrappersModule =>}
+trait WOptionsModule extends sigma.compiler.ir.wrappers.scala.impl.WOptionsDefs {self: IRContext =>}
diff --git a/sc/shared/src/main/scala/special/collection/CollsUnit.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/CollsUnit.scala
similarity index 83%
rename from sc/shared/src/main/scala/special/collection/CollsUnit.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/CollsUnit.scala
index 19ae1f5e48..fdc9fadcba 100644
--- a/sc/shared/src/main/scala/special/collection/CollsUnit.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/CollsUnit.scala
@@ -1,5 +1,6 @@
-package sigma {
- import scalan._
+package sigma.compiler.ir.wrappers.sigma
+
+import sigma.compiler.ir.{Base, IRContext}
/** Staged version of collection interfaces which is used in graph-based IR to represent
* methods of Coll and CollBuilder.
@@ -8,11 +9,12 @@ package sigma {
* The semantics of each method is the same as in the original class, please look there
* for details.
*/
- trait Colls extends Base { self: Library =>
+ trait Colls extends Base { self: IRContext =>
trait Coll[A] extends Def[Coll[A]] {
implicit def eA: Elem[A];
def length: Ref[Int];
def apply(i: Ref[Int]): Ref[A];
+ def get(index: Ref[Int]): Ref[WOption[A]];
def getOrElse(index: Ref[Int], default: Ref[A]): Ref[A];
def map[B](f: Ref[scala.Function1[A, B]]): Ref[Coll[B]];
def zip[B](ys: Ref[Coll[B]]): Ref[Coll[scala.Tuple2[A, B]]];
@@ -28,13 +30,14 @@ package sigma {
def updateMany(indexes: Ref[Coll[Int]], values: Ref[Coll[A]]): Ref[Coll[A]];
def slice(from: Ref[Int], until: Ref[Int]): Ref[Coll[A]];
def append(other: Ref[Coll[A]]): Ref[Coll[A]];
+ def reverse: Ref[Coll[A]]
+ def distinct: Ref[Coll[A]]
+ def startsWith(ys: Ref[Coll[A]]): Ref[Boolean];
+ def endsWith(ys: Ref[Coll[A]]): Ref[Boolean];
};
trait CollBuilder extends Def[CollBuilder] {
def fromItems[T](items: Ref[T]*)(implicit cT: Elem[T]): Ref[Coll[T]];
def xor(left: Ref[Coll[Byte]], right: Ref[Coll[Byte]]): Ref[Coll[Byte]];
def replicate[T](n: Ref[Int], v: Ref[T]): Ref[Coll[T]];
};
- trait CollCompanion;
- trait CollBuilderCompanion
- }
-}
\ No newline at end of file
+ }
\ No newline at end of file
diff --git a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala
similarity index 91%
rename from sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala
index 48548226a5..a90583a4a4 100644
--- a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala
@@ -1,8 +1,10 @@
-package sigma {
- import scalan._
- import sigmastate.eval.SigmaLibrary
+package sigma.compiler.ir.wrappers.sigma
- trait SigmaDsl extends Base { self: SigmaLibrary =>
+import scalan._
+ import sigma.compiler.ir.{Base, IRContext}
+
+ /** IR representation of ErgoScript (Sigma) language types and methods. */
+ trait SigmaDsl extends Base { self: IRContext =>
trait BigInt extends Def[BigInt] {
def add(that: Ref[BigInt]): Ref[BigInt];
def subtract(that: Ref[BigInt]): Ref[BigInt];
@@ -76,6 +78,7 @@ package sigma {
def powNonce: Ref[Coll[Byte]];
def powDistance: Ref[BigInt];
def votes: Ref[Coll[Byte]]
+ def checkPow: Ref[Boolean]
};
trait Context extends Def[Context] {
def OUTPUTS: Ref[Coll[Box]];
@@ -89,6 +92,7 @@ package sigma {
def preHeader: Ref[PreHeader];
def minerPubKey: Ref[Coll[Byte]];
def getVar[T](id: Ref[Byte])(implicit cT: Elem[T]): Ref[WOption[T]];
+ def getVarFromInput[T](inputId: Ref[Short], id: Ref[Byte])(implicit cT: Elem[T]): Ref[WOption[T]];
};
trait SigmaDslBuilder extends Def[SigmaDslBuilder] {
def Colls: Ref[CollBuilder];
@@ -112,6 +116,8 @@ package sigma {
/** This method will be used in v6.0 to handle CreateAvlTree operation in GraphBuilding */
def avlTree(operationFlags: Ref[Byte], digest: Ref[Coll[Byte]], keyLength: Ref[Int], valueLengthOpt: Ref[WOption[Int]]): Ref[AvlTree];
def xor(l: Ref[Coll[Byte]], r: Ref[Coll[Byte]]): Ref[Coll[Byte]]
+ def serialize[T](value: Ref[T]): Ref[Coll[Byte]]
+ def fromBigEndianBytes[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T]
};
trait CostModelCompanion;
trait BigIntCompanion;
@@ -124,5 +130,4 @@ package sigma {
trait ContextCompanion;
trait SigmaContractCompanion;
trait SigmaDslBuilderCompanion
- }
-}
\ No newline at end of file
+ }
\ No newline at end of file
diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/WRTypes.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/WRTypes.scala
new file mode 100644
index 0000000000..0bd2b47e5b
--- /dev/null
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/WRTypes.scala
@@ -0,0 +1,13 @@
+package sigma.compiler.ir.wrappers.sigma
+
+import sigma.compiler.ir.{Base, IRContext}
+
+
+ /** IR representation of RType. */
+ trait WRTypes extends Base { self: IRContext =>
+ trait WRType[A] extends Def[WRType[A]] {
+ implicit def eA: Elem[A];
+ def name: Ref[String]
+ };
+ trait WRTypeCompanion
+ }
\ No newline at end of file
diff --git a/sc/shared/src/main/scala/special/collection/impl/CollsImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/CollsImpl.scala
similarity index 90%
rename from sc/shared/src/main/scala/special/collection/impl/CollsImpl.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/CollsImpl.scala
index 239bfff4e5..04a7070acf 100644
--- a/sc/shared/src/main/scala/special/collection/impl/CollsImpl.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/CollsImpl.scala
@@ -1,16 +1,21 @@
-package sigma
+package sigma.compiler.ir.wrappers.sigma
+
+import scala.language.{existentials, implicitConversions}
+import sigma.compiler.ir.IRContext
+import sigma.compiler.ir.wrappers.sigma.impl.CollsDefs
-import scala.language.{existentials,implicitConversions}
-import scalan._
import scala.collection.compat.immutable.ArraySeq
package impl {
+ import sigma.compiler.ir.meta.ModuleInfo
+ import sigma.compiler.ir.{Base, GraphIRReflection, IRContext}
import sigma.data.{Nullable, RType}
import sigma.reflection.{RClass, RMethod}
- // Abs -----------------------------------
-trait CollsDefs extends scalan.Scalan with Colls {
- self: Library =>
+// Abs -----------------------------------
+/** Implementation part of IR represenation related to Coll type and methods. */
+trait CollsDefs extends Base with Colls {
+ self: IRContext =>
registerModule(CollsModule)
@@ -58,6 +63,14 @@ class CollCls extends EntityObject("Coll") {
true, false, element[A]))
}
+ override def get(index: Ref[Int]): Ref[WOption[A]] = {
+ asRep[WOption[A]](mkMethodCall(self,
+ CollClass.getMethod("get", classOf[Sym]),
+ Array[AnyRef](index),
+ true, false, element[WOption[A]]))
+ }
+
+
override def map[B](f: Ref[A => B]): Ref[Coll[B]] = {
implicit val eB = f.elem.eRange
asRep[Coll[B]](mkMethodCall(self,
@@ -159,6 +172,34 @@ class CollCls extends EntityObject("Coll") {
Array[AnyRef](other),
true, false, element[Coll[A]]))
}
+
+ override def reverse: Ref[Coll[A]] = {
+ asRep[Coll[A]](mkMethodCall(self,
+ CollClass.getMethod("reverse"),
+ Array[AnyRef](),
+ true, false, element[Coll[A]]))
+ }
+
+ override def distinct: Ref[Coll[A]] = {
+ asRep[Coll[A]](mkMethodCall(self,
+ CollClass.getMethod("distinct"),
+ Array[AnyRef](),
+ true, false, element[Coll[A]]))
+ }
+
+ def startsWith(ys: Ref[Coll[A]]): Ref[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ CollClass.getMethod("startsWith", classOf[Sym]),
+ Array[AnyRef](ys),
+ true, false, element[Boolean]))
+ }
+
+ def endsWith(ys: Ref[Coll[A]]): Ref[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ CollClass.getMethod("endsWith", classOf[Sym]),
+ Array[AnyRef](ys),
+ true, false, element[Boolean]))
+ }
}
case class LiftableColl[SA, A](lA: Liftable[SA, A])
@@ -205,6 +246,13 @@ class CollCls extends EntityObject("Coll") {
true, true, element[A]))
}
+ def get(index: Ref[Int]): Ref[WOption[A]] = {
+ asRep[WOption[A]](mkMethodCall(source,
+ CollClass.getMethod("get", classOf[Sym]),
+ Array[AnyRef](index),
+ true, true, element[WOption[A]]))
+ }
+
def map[B](f: Ref[A => B]): Ref[Coll[B]] = {
implicit val eB = f.elem.eRange
asRep[Coll[B]](mkMethodCall(source,
@@ -306,6 +354,34 @@ class CollCls extends EntityObject("Coll") {
Array[AnyRef](other),
true, true, element[Coll[A]]))
}
+
+ def reverse: Ref[Coll[A]] = {
+ asRep[Coll[A]](mkMethodCall(source,
+ CollClass.getMethod("reverse"),
+ Array[AnyRef](),
+ true, true, element[Coll[A]]))
+ }
+
+ def distinct: Ref[Coll[A]] = {
+ asRep[Coll[A]](mkMethodCall(source,
+ CollClass.getMethod("distinct"),
+ Array[AnyRef](),
+ true, true, element[Coll[A]]))
+ }
+
+ def startsWith(ys: Ref[Coll[A]]): Ref[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ CollClass.getMethod("startsWith", classOf[Sym]),
+ Array[AnyRef](ys),
+ true, true, element[Boolean]))
+ }
+
+ def endsWith(ys: Ref[Coll[A]]): Ref[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ CollClass.getMethod("endsWith", classOf[Sym]),
+ Array[AnyRef](ys),
+ true, true, element[Boolean]))
+ }
}
// entityUnref: single unref method for each type family
@@ -634,9 +710,9 @@ object CollBuilder extends EntityObject("CollBuilder") {
}
-object CollsModule extends scalan.ModuleInfo("sigma", "Colls") {
+object CollsModule extends ModuleInfo("sigma", "Colls") {
val reflection = GraphIRReflection
}
}
-trait CollsModule extends sigma.impl.CollsDefs {self: Library =>}
+trait CollsModule extends CollsDefs {self: IRContext =>}
diff --git a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala
similarity index 95%
rename from sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala
index 037505b531..0ce72d2314 100644
--- a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala
@@ -1,19 +1,25 @@
-package sigma
+package sigma.compiler.ir.wrappers.sigma
import scala.language.{existentials, implicitConversions}
import scalan._
-import sigmastate.eval.SigmaLibrary
+import sigma.compiler.ir.IRContext
+import sigma.compiler.ir.wrappers.sigma.impl.SigmaDslDefs
import scala.collection.compat.immutable.ArraySeq
package impl {
+ import sigma.Evaluation
+ import sigma.ast.SType.tT
+ import sigma.compiler.ir.meta.ModuleInfo
+ import sigma.compiler.ir.wrappers.sigma.SigmaDsl
+ import sigma.compiler.ir.{Base, GraphIRReflection, IRContext}
import sigma.data.{Nullable, RType}
import sigma.reflection.{RClass, RMethod}
- import sigmastate.eval.SigmaLibrary
+/** Implementation part of IR represenation related to Sigma types and methods. */
// Abs -----------------------------------
-trait SigmaDslDefs extends scalan.Scalan with SigmaDsl {
- self: SigmaLibrary =>
+trait SigmaDslDefs extends Base with SigmaDsl {
+ self: IRContext =>
registerModule(SigmaDslModule)
@@ -616,10 +622,11 @@ object Box extends EntityObject("Box") {
}
override def getReg[T](i: Ref[Int])(implicit cT: Elem[T]): Ref[WOption[T]] = {
+ val st = Evaluation.rtypeToSType(cT.sourceType)
asRep[WOption[T]](mkMethodCall(self,
BoxClass.getMethod("getReg", classOf[Sym], classOf[Elem[_]]),
Array[AnyRef](i, cT),
- true, false, element[WOption[T]]))
+ true, false, element[WOption[T]], Map(tT -> st) ))
}
override def tokens: Ref[Coll[(Coll[Byte], Long)]] = {
@@ -691,10 +698,11 @@ object Box extends EntityObject("Box") {
}
def getReg[T](i: Ref[Int])(implicit cT: Elem[T]): Ref[WOption[T]] = {
+ val st = Evaluation.rtypeToSType(cT.sourceType)
asRep[WOption[T]](mkMethodCall(source,
BoxClass.getMethod("getReg", classOf[Sym], classOf[Elem[_]]),
Array[AnyRef](i, cT),
- true, true, element[WOption[T]]))
+ true, true, element[WOption[T]], Map(tT -> st)))
}
def tokens: Ref[Coll[(Coll[Byte], Long)]] = {
@@ -1364,6 +1372,13 @@ object Header extends EntityObject("Header") {
ArraySeq.empty,
true, false, element[Coll[Byte]]))
}
+
+ override def checkPow: Ref[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ HeaderClass.getMethod("checkPow"),
+ ArraySeq.empty,
+ true, false, element[Boolean]))
+ }
}
implicit object LiftableHeader
@@ -1488,6 +1503,13 @@ object Header extends EntityObject("Header") {
ArraySeq.empty,
true, true, element[Coll[Byte]]))
}
+
+ def checkPow: Ref[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ HeaderClass.getMethod("checkPow"),
+ ArraySeq.empty,
+ true, true, element[Boolean]))
+ }
}
// entityUnref: single unref method for each type family
@@ -1505,7 +1527,7 @@ object Header extends EntityObject("Header") {
override protected def collectMethods: Map[RMethod, MethodDesc] = {
super.collectMethods ++
Elem.declaredMethods(RClass(classOf[Header]), RClass(classOf[SHeader]), Set(
- "id", "version", "parentId", "ADProofsRoot", "stateRoot", "transactionsRoot", "timestamp", "nBits", "height", "extensionRoot", "minerPk", "powOnetimePk", "powNonce", "powDistance", "votes"
+ "id", "version", "parentId", "ADProofsRoot", "stateRoot", "transactionsRoot", "timestamp", "nBits", "height", "extensionRoot", "minerPk", "powOnetimePk", "powNonce", "powDistance", "votes", "checkPow"
))
}
}
@@ -1604,10 +1626,19 @@ object Context extends EntityObject("Context") {
}
override def getVar[T](id: Ref[Byte])(implicit cT: Elem[T]): Ref[WOption[T]] = {
+ val st = Evaluation.rtypeToSType(cT.sourceType)
asRep[WOption[T]](mkMethodCall(self,
ContextClass.getMethod("getVar", classOf[Sym], classOf[Elem[_]]),
Array[AnyRef](id, cT),
- true, false, element[WOption[T]]))
+ true, false, element[WOption[T]], Map(tT -> st)))
+ }
+
+ override def getVarFromInput[T](inputId: Ref[Short], varId: Ref[Byte])(implicit cT: Elem[T]): Ref[WOption[T]] = {
+ val st = Evaluation.rtypeToSType(cT.sourceType)
+ asRep[WOption[T]](mkMethodCall(self,
+ ContextClass.getMethod("getVarFromInput", classOf[Sym], classOf[Sym], classOf[Elem[_]]),
+ Array[AnyRef](inputId, varId, cT),
+ true, false, element[WOption[T]], Map(tT -> st)))
}
}
@@ -1701,10 +1732,19 @@ object Context extends EntityObject("Context") {
}
def getVar[T](id: Ref[Byte])(implicit cT: Elem[T]): Ref[WOption[T]] = {
+ val st = Evaluation.rtypeToSType(cT.sourceType)
asRep[WOption[T]](mkMethodCall(source,
ContextClass.getMethod("getVar", classOf[Sym], classOf[Elem[_]]),
Array[AnyRef](id, cT),
- true, true, element[WOption[T]]))
+ true, true, element[WOption[T]], Map(tT -> st)))
+ }
+
+ def getVarFromInput[T](inputId: Ref[Short], varId: Ref[Byte])(implicit cT: Elem[T]): Ref[WOption[T]] = {
+ val st = Evaluation.rtypeToSType(cT.sourceType)
+ asRep[WOption[T]](mkMethodCall(source,
+ ContextClass.getMethod("getVarFromInput", classOf[Sym], classOf[Sym], classOf[Elem[_]]),
+ Array[AnyRef](inputId, varId, cT),
+ true, true, element[WOption[T]], Map(tT -> st)))
}
}
@@ -1723,7 +1763,7 @@ object Context extends EntityObject("Context") {
override protected def collectMethods: Map[RMethod, MethodDesc] = {
super.collectMethods ++
Elem.declaredMethods(RClass(classOf[Context]), RClass(classOf[SContext]), Set(
- "OUTPUTS", "INPUTS", "dataInputs", "HEIGHT", "SELF", "selfBoxIndex", "LastBlockUtxoRootHash", "headers", "preHeader", "minerPubKey", "getVar", "vars"
+ "OUTPUTS", "INPUTS", "dataInputs", "HEIGHT", "SELF", "selfBoxIndex", "LastBlockUtxoRootHash", "headers", "preHeader", "minerPubKey", "getVar", "getVarFromInput", "vars"
))
}
}
@@ -1915,7 +1955,6 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") {
}
override def substConstants[T](scriptBytes: Ref[Coll[Byte]], positions: Ref[Coll[Int]], newValues: Ref[Coll[T]]): Ref[Coll[Byte]] = {
- implicit val eT = newValues.eA
asRep[Coll[Byte]](mkMethodCall(self,
SigmaDslBuilderClass.getMethod("substConstants", classOf[Sym], classOf[Sym], classOf[Sym]),
Array[AnyRef](scriptBytes, positions, newValues),
@@ -1942,6 +1981,21 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") {
Array[AnyRef](l, r),
true, false, element[Coll[Byte]]))
}
+
+ def serialize[T](value: Ref[T]): Ref[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("serialize", classOf[Sym]),
+ Array[AnyRef](value),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def fromBigEndianBytes[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = {
+ asRep[T](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("fromBigEndianBytes", classOf[Sym], classOf[Elem[T]]),
+ Array[AnyRef](bytes, cT, Map(tT -> Evaluation.rtypeToSType(cT.sourceType))),
+ true, false, cT))
+ }
+
}
implicit object LiftableSigmaDslBuilder
@@ -2075,7 +2129,6 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") {
}
def substConstants[T](scriptBytes: Ref[Coll[Byte]], positions: Ref[Coll[Int]], newValues: Ref[Coll[T]]): Ref[Coll[Byte]] = {
- implicit val eT = newValues.eA
asRep[Coll[Byte]](mkMethodCall(source,
SigmaDslBuilderClass.getMethod("substConstants", classOf[Sym], classOf[Sym], classOf[Sym]),
Array[AnyRef](scriptBytes, positions, newValues),
@@ -2102,6 +2155,20 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") {
Array[AnyRef](l, r),
true, true, element[Coll[Byte]]))
}
+
+ def serialize[T](value: Ref[T]): Ref[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ SigmaDslBuilderClass.getMethod("serialize", classOf[Sym]),
+ Array[AnyRef](value),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def fromBigEndianBytes[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = {
+ asRep[T](mkMethodCall(source,
+ SigmaDslBuilderClass.getMethod("fromBigEndianBytes", classOf[Sym], classOf[Elem[T]]),
+ Array[AnyRef](bytes, cT),
+ true, true, cT, Map(tT -> Evaluation.rtypeToSType(cT.sourceType))))
+ }
}
// entityUnref: single unref method for each type family
@@ -2119,7 +2186,9 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") {
override protected def collectMethods: Map[RMethod, MethodDesc] = {
super.collectMethods ++
Elem.declaredMethods(RClass(classOf[SigmaDslBuilder]), RClass(classOf[SSigmaDslBuilder]), Set(
- "Colls", "verifyZK", "atLeast", "allOf", "allZK", "anyOf", "anyZK", "xorOf", "sigmaProp", "blake2b256", "sha256", "byteArrayToBigInt", "longToByteArray", "byteArrayToLong", "proveDlog", "proveDHTuple", "groupGenerator", "substConstants", "decodePoint", "avlTree", "xor"
+ "Colls", "verifyZK", "atLeast", "allOf", "allZK", "anyOf", "anyZK", "xorOf", "sigmaProp", "blake2b256", "sha256",
+ "byteArrayToBigInt", "longToByteArray", "byteArrayToLong", "proveDlog", "proveDHTuple", "groupGenerator", "substConstants",
+ "decodePoint", "avlTree", "xor", "serialize", "fromBigEndianBytes"
))
}
}
@@ -2278,16 +2347,6 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") {
def unapply(exp: Sym): Nullable[(Ref[SigmaDslBuilder], Ref[GroupElement], Ref[GroupElement], Ref[GroupElement], Ref[GroupElement])] = unapply(exp.node)
}
- object groupGenerator {
- def unapply(d: Def[_]): Nullable[Ref[SigmaDslBuilder]] = d match {
- case MethodCall(receiver, method, _, _) if method.getName == "groupGenerator" && receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] =>
- val res = receiver
- Nullable(res).asInstanceOf[Nullable[Ref[SigmaDslBuilder]]]
- case _ => Nullable.None
- }
- def unapply(exp: Sym): Nullable[Ref[SigmaDslBuilder]] = unapply(exp.node)
- }
-
object substConstants {
def unapply(d: Def[_]): Nullable[(Ref[SigmaDslBuilder], Ref[Coll[Byte]], Ref[Coll[Int]], Ref[Coll[T]]) forSome {type T}] = d match {
case MethodCall(receiver, method, args, _) if method.getName == "substConstants" && receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] =>
@@ -2333,9 +2392,9 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") {
registerEntityObject("SigmaDslBuilder", SigmaDslBuilder)
}
-object SigmaDslModule extends scalan.ModuleInfo("sigma", "SigmaDsl") {
+object SigmaDslModule extends ModuleInfo("sigma", "SigmaDsl") {
val reflection = GraphIRReflection
}
}
-trait SigmaDslModule extends sigma.impl.SigmaDslDefs {self: SigmaLibrary =>}
+trait SigmaDslModule extends SigmaDslDefs {self: IRContext =>}
diff --git a/sc/shared/src/main/scala/wrappers/scalan/impl/WRTypesImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/WRTypesImpl.scala
similarity index 84%
rename from sc/shared/src/main/scala/wrappers/scalan/impl/WRTypesImpl.scala
rename to sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/WRTypesImpl.scala
index 9b2676f70d..beddba3085 100644
--- a/sc/shared/src/main/scala/wrappers/scalan/impl/WRTypesImpl.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/WRTypesImpl.scala
@@ -1,18 +1,22 @@
-package wrappers.scalan
+package sigma.compiler.ir.wrappers.sigma
-import scala.language.{existentials,implicitConversions}
+import sigma.compiler.ir.IRContext
+import scala.language.{existentials, implicitConversions}
import sigma.data.RType
-import special.wrappers.WrappersModule
-import special.wrappers.RTypeWrapSpec
+import sigma.compiler.ir.wrappers.RTypeWrapSpec
+
import scala.collection.compat.immutable.ArraySeq
package impl {
- import scalan.GraphIRReflection
+ import sigma.compiler.ir.meta.ModuleInfo
+ import sigma.compiler.ir.wrappers.sigma.WRTypes
+ import sigma.compiler.ir.{Base, GraphIRReflection, IRContext}
import sigma.reflection.{RClass, RMethod}
+/** Implementation of IR nodes related to [[RType]]. */
// Abs -----------------------------------
-trait WRTypesDefs extends scalan.Scalan with WRTypes {
- self: WrappersModule =>
+trait WRTypesDefs extends Base with WRTypes {
+ self: IRContext =>
registerModule(WRTypesModule)
@@ -111,9 +115,9 @@ registerEntityObject("WRType", WRType)
}
-object WRTypesModule extends scalan.ModuleInfo("wrappers.scalan", "WRTypes") {
+object WRTypesModule extends ModuleInfo("wrappers.scalan", "WRTypes") {
val reflection = GraphIRReflection
}
}
-trait WRTypesModule extends wrappers.scalan.impl.WRTypesDefs {self: WrappersModule =>}
+trait WRTypesModule extends sigma.compiler.ir.wrappers.sigma.impl.WRTypesDefs {self: IRContext =>}
diff --git a/sc/shared/src/main/scala/sigmastate/lang/SigmaBinder.scala b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala
similarity index 95%
rename from sc/shared/src/main/scala/sigmastate/lang/SigmaBinder.scala
rename to sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala
index f93e31703d..d4943ef892 100644
--- a/sc/shared/src/main/scala/sigmastate/lang/SigmaBinder.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala
@@ -1,7 +1,6 @@
-package sigmastate.lang
+package sigma.compiler.phases
import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
-import org.ergoplatform._
import sigma.ast.NoType
import sigma.data.Nullable
import sigma.kiama.rewriting.CallbackRewriter
@@ -106,6 +105,9 @@ class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder,
case a @ Apply(PKFunc.symNoType, args) =>
Some(PKFunc.irInfo.irBuilder(PKFunc.sym, args).withPropagatedSrcCtx(a.sourceContext))
+ case a @ Apply(predefFuncRegistry.SerializeFunc.symNoType, args) =>
+ Some(predefFuncRegistry.SerializeFunc.irInfo.irBuilder(PKFunc.sym, args).withPropagatedSrcCtx(a.sourceContext))
+
case sel @ Select(obj, "isEmpty", _) =>
Some(mkLogicalNot(mkSelect(obj, "isDefined").asBoolValue).withPropagatedSrcCtx(sel.sourceContext))
diff --git a/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala
similarity index 92%
rename from sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala
rename to sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala
index 7fd6dadd45..833bd413b9 100644
--- a/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala
@@ -1,24 +1,26 @@
-package sigmastate.lang
+package sigma.compiler.phases
-import org.ergoplatform._
import sigma.ast.SCollection.{SBooleanArray, SByteArray}
+import sigma.ast.SigmaPredef._
import sigma.ast._
-import sigma.ast.syntax.SValue
+import sigma.ast.syntax.{SValue, _}
import sigma.data.{Nullable, SigmaBoolean}
-import sigma.util.Extensions.Ensuring
-import sigmastate.exceptions._
-import SigmaPredef._
-import sigma.ast.syntax._
import sigma.exceptions.TyperException
import sigma.serialization.OpCodes
+import sigma.util.Extensions.Ensuring
+import sigmastate.exceptions._
import scala.collection.mutable.ArrayBuffer
-/**
- * Type inference and analysis for Sigma expressions.
+/** Type inference and analysis for Sigma expressions.
+ * @param builder SigmaBuilder instance to create new nodes
+ * @param predefFuncRegistry predefined functions registry used to resolve names
+ * @param typeEnv environment with types of variables/names
+ * @param lowerMethodCalls if true, then MethodCall nodes are lowered to the corresponding ErgoTree nodes
*/
class SigmaTyper(val builder: SigmaBuilder,
predefFuncRegistry: PredefinedFuncRegistry,
+ typeEnv: Map[String, SType],
lowerMethodCalls: Boolean) {
import SigmaTyper._
import builder._
@@ -28,8 +30,10 @@ class SigmaTyper(val builder: SigmaBuilder,
import SType.tT
- private val predefinedEnv: Map[String, SType] =
- predefFuncRegistry.funcs.map { case (k, f) => k -> f.declaration.tpe }.toMap
+ private val predefinedEnv: Map[String, SType] = {
+ val predefFuncs = predefFuncRegistry.funcs.map { case (k, f) => k -> f.declaration.tpe }.toMap
+ predefFuncs ++ typeEnv
+ }
private def processGlobalMethod(srcCtx: Nullable[SourceContext],
method: SMethod,
@@ -130,12 +134,24 @@ class SigmaTyper(val builder: SigmaBuilder,
res
case Apply(ApplyTypes(sel @ Select(obj, n, _), Seq(rangeTpe)), args) =>
+ // downcast getVarFromInput arguments to short and byte
+ val nArgs = if (n == SContextMethods.getVarFromInputMethod.name &&
+ args.length == 2 &&
+ args(0).isInstanceOf[Constant[_]] &&
+ args(1).isInstanceOf[Constant[_]] &&
+ args(0).tpe.isNumType &&
+ args(1).tpe.isNumType) {
+ IndexedSeq(ShortConstant(SShort.downcast(args(0).asInstanceOf[Constant[SNumericType]].value.asInstanceOf[AnyVal])).withSrcCtx(args(0).sourceContext),
+ ByteConstant(SByte.downcast(args(1).asInstanceOf[Constant[SNumericType]].value.asInstanceOf[AnyVal])).withSrcCtx(args(1).sourceContext))
+ } else args
+
val newObj = assignType(env, obj)
- val newArgs = args.map(assignType(env, _))
- obj.tpe match {
+ val newArgs = nArgs.map(assignType(env, _))
+ newObj.tpe match {
case p: SProduct =>
MethodsContainer.getMethod(p, n) match {
- case Some(method @ SMethod(_, _, genFunTpe @ SFunc(_, _, _), _, _, _, _, _)) =>
+ case Some(method: SMethod) =>
+ val genFunTpe = method.stype
val subst = Map(genFunTpe.tpeParams.head.ident -> rangeTpe)
val concrFunTpe = applySubst(genFunTpe, subst)
val expectedArgs = concrFunTpe.asFunc.tDom.tail
@@ -150,15 +166,15 @@ class SigmaTyper(val builder: SigmaBuilder,
.getOrElse(mkMethodCall(newObj, method, newArgs, subst))
} else {
val newSelect = mkSelect(newObj, n, Some(concrFunTpe)).withSrcCtx(sel.sourceContext)
- mkApply(newSelect, newArgs.toArray[SValue])
+ mkApply(newSelect, newArgs)
}
case Some(method) =>
error(s"Don't know how to handle method $method in obj $p", sel.sourceContext)
case None =>
- throw new MethodNotFound(s"Cannot find method '$n' in in the object $obj of Product type $p", obj.sourceContext.toOption)
+ throw new MethodNotFound(s"Cannot find method '$n' in in the object $newObj of Product type $p", newObj.sourceContext.toOption)
}
case _ =>
- error(s"Cannot get field '$n' in in the object $obj of non-product type ${obj.tpe}", sel.sourceContext)
+ error(s"Cannot get field '$n' in in the object $newObj of non-product type ${newObj.tpe}", sel.sourceContext)
}
case app @ Apply(sel @ Select(obj, n, _), args) =>
@@ -216,6 +232,11 @@ class SigmaTyper(val builder: SigmaBuilder,
case (Ident(GetVarFunc.name | ExecuteFromVarFunc.name, _), Seq(id: Constant[SNumericType]@unchecked))
if id.tpe.isNumType =>
Seq(ByteConstant(SByte.downcast(id.value.asInstanceOf[AnyVal])).withSrcCtx(id.sourceContext))
+ case (Ident(SContextMethods.getVarFromInputMethod.name, _),
+ Seq(inputId: Constant[SNumericType]@unchecked, varId: Constant[SNumericType]@unchecked))
+ if inputId.tpe.isNumType && varId.tpe.isNumType =>
+ Seq(ShortConstant(SShort.downcast(inputId.value.asInstanceOf[AnyVal])).withSrcCtx(inputId.sourceContext),
+ ByteConstant(SByte.downcast(varId.value.asInstanceOf[AnyVal])).withSrcCtx(varId.sourceContext))
case _ => typedArgs
}
val actualTypes = adaptedTypedArgs.map(_.tpe)
@@ -404,11 +425,6 @@ class SigmaTyper(val builder: SigmaBuilder,
error(s"Invalid application of type arguments $app: function $input doesn't have type parameters", input.sourceContext)
}
-// case app @ ApplyTypes(in, targs) =>
-// val newIn = assignType(env, in)
-// ApplyTypes(newIn, targs)
-// error(s"Invalid application of type arguments $app: expression doesn't have type parameters")
-
case If(c, t, e) =>
val c1 = assignType(env, c).asValue[SBoolean.type]
val t1 = assignType(env, t)
@@ -507,6 +523,7 @@ class SigmaTyper(val builder: SigmaBuilder,
case v: SigmaBoolean => v
case v: Upcast[_, _] => v
case v @ Select(_, _, Some(_)) => v
+ case v @ MethodCall(_, _, _, _) => v
case v =>
error(s"Don't know how to assignType($v)", v.sourceContext)
}).ensuring(v => v.tpe != NoType,
diff --git a/sc/shared/src/main/scala/sigmastate/eval/IRContext.scala b/sc/shared/src/main/scala/sigmastate/eval/IRContext.scala
deleted file mode 100644
index b84098f2e7..0000000000
--- a/sc/shared/src/main/scala/sigmastate/eval/IRContext.scala
+++ /dev/null
@@ -1,65 +0,0 @@
-package sigmastate.eval
-
-import sigma.ast.TransformingSigmaBuilder
-import sigma.data.CSigmaDslBuilder
-
-import java.util.concurrent.locks.ReentrantLock
-import scala.util.Try
-
-/** Main interface of graph IR context which contain both GraphBuilding and TreeBuilding
- * methods.
- * It is not used in v5.0 interpreter and thus not part of consensus.
- *
- * @see RuntimeIRContext, CompiletimeIRContext
- */
-trait IRContext extends TreeBuilding with GraphBuilding {
- import SigmaProp._
-
- private val SigmaM = SigmaPropMethods
-
- override val builder = TransformingSigmaBuilder
-
- /** Can be used to synchronize access to this IR object from multiple threads. */
- val lock = new ReentrantLock()
-
- /** Pass configuration which is used to turn-off constant propagation.
- * @see `beginPass(noCostPropagationPass)` */
- lazy val noConstPropagationPass = new DefaultPass(
- "noCostPropagationPass",
- Pass.defaultPassConfig.copy(constantPropagation = false))
-
- /** The value of Global ErgoTree operation */
- val sigmaDslBuilderValue = CSigmaDslBuilder
-
- /** Finds SigmaProp.isProven method calls in the given Lambda `f` */
- def findIsProven[T](f: Ref[Context => T]): Option[Sym] = {
- val Def(Lambda(lam,_,_,_)) = f
- val s = lam.flatSchedule.find(sym => sym.node match {
- case SigmaM.isValid(_) => true
- case _ => false
- })
- s
- }
-
- /** Checks that if SigmaProp.isProven method calls exists in the given Lambda's schedule,
- * then it is the last operation. */
- def verifyIsProven[T](f: Ref[Context => T]): Try[Unit] = {
- val isProvenOpt = findIsProven(f)
- Try {
- isProvenOpt match {
- case Some(s) =>
- if (f.getLambda.y != s) !!!(s"Sigma.isProven found in none-root position", s)
- case None =>
- }
- }
- }
-}
-
-/** IR context to be used by blockchain nodes to validate transactions. */
-class RuntimeIRContext extends IRContext {
-}
-
-/** IR context to be used by script development tools to compile ErgoScript into ErgoTree bytecode. */
-class CompiletimeIRContext extends IRContext {
-}
-
diff --git a/sc/shared/src/main/scala/sigmastate/eval/SigmaLibrary.scala b/sc/shared/src/main/scala/sigmastate/eval/SigmaLibrary.scala
deleted file mode 100644
index be17179cbf..0000000000
--- a/sc/shared/src/main/scala/sigmastate/eval/SigmaLibrary.scala
+++ /dev/null
@@ -1,17 +0,0 @@
-package sigmastate.eval
-
-import scalan.Library
-import sigma.SigmaDslModule
-
-/** Main trait which represents sigma operations in graph IR cake. */
-trait SigmaLibrary extends Library
- with sigma.wrappers.WrappersModule
- with SigmaDslModule
-{
- import WRType._
-
- implicit lazy val wRTypeAnyElement = wRTypeElement(AnyElement)
-
- /** During compilation represent a global value Global, see also SGlobal type. */
- def sigmaDslBuilder: Ref[SigmaDslBuilder]
-}
diff --git a/sc/shared/src/main/scala/special/sigma/wrappers/WrappersModule.scala b/sc/shared/src/main/scala/special/sigma/wrappers/WrappersModule.scala
deleted file mode 100644
index 6696788621..0000000000
--- a/sc/shared/src/main/scala/special/sigma/wrappers/WrappersModule.scala
+++ /dev/null
@@ -1,4 +0,0 @@
-package sigma.wrappers
-
-trait WrappersModule
- extends special.wrappers.WrappersModule
diff --git a/sc/shared/src/main/scala/special/wrappers/WrappersModule.scala b/sc/shared/src/main/scala/special/wrappers/WrappersModule.scala
deleted file mode 100644
index b74bec314e..0000000000
--- a/sc/shared/src/main/scala/special/wrappers/WrappersModule.scala
+++ /dev/null
@@ -1,10 +0,0 @@
-package special.wrappers
-
-import wrappers.scala.WOptionsModule
-import wrappers.scalan.WRTypesModule
-import wrappers.special.WSpecialPredefsModule
-
-trait WrappersModule
- extends WSpecialPredefsModule
- with WOptionsModule
- with WRTypesModule
\ No newline at end of file
diff --git a/sc/shared/src/main/scala/wrappers/scalan/WRTypes.scala b/sc/shared/src/main/scala/wrappers/scalan/WRTypes.scala
deleted file mode 100644
index 8c6bc48f8e..0000000000
--- a/sc/shared/src/main/scala/wrappers/scalan/WRTypes.scala
+++ /dev/null
@@ -1,13 +0,0 @@
-package wrappers.scalan {
- import scalan._
- import special.wrappers.WrappersModule
-
-
- trait WRTypes extends Base { self: WrappersModule =>
- trait WRType[A] extends Def[WRType[A]] {
- implicit def eA: Elem[A];
- def name: Ref[String]
- };
- trait WRTypeCompanion
- }
-}
\ No newline at end of file
diff --git a/sc/shared/src/main/scala/wrappers/special/WSpecialPredefs.scala b/sc/shared/src/main/scala/wrappers/special/WSpecialPredefs.scala
deleted file mode 100644
index 5abbab95e2..0000000000
--- a/sc/shared/src/main/scala/wrappers/special/WSpecialPredefs.scala
+++ /dev/null
@@ -1,12 +0,0 @@
-package wrappers.special {
- import scalan._
-
- import special.wrappers.WrappersModule
-
- trait WSpecialPredefs extends Base { self: WrappersModule =>
- trait WSpecialPredef extends Def[WSpecialPredef];
- trait WSpecialPredefCompanion {
- def some[A](x: Ref[A]): Ref[WOption[A]];
- }
- }
-}
\ No newline at end of file
diff --git a/sc/shared/src/main/scala/wrappers/special/impl/WSpecialPredefsImpl.scala b/sc/shared/src/main/scala/wrappers/special/impl/WSpecialPredefsImpl.scala
deleted file mode 100644
index 1f80e71676..0000000000
--- a/sc/shared/src/main/scala/wrappers/special/impl/WSpecialPredefsImpl.scala
+++ /dev/null
@@ -1,69 +0,0 @@
-package wrappers.special
-
-import scala.language.{existentials,implicitConversions}
-import scalan._
-import special.wrappers.WrappersModule
-
-package impl {
- import sigma.data.Nullable
- import sigma.reflection.RClass
-
- // Abs -----------------------------------
-trait WSpecialPredefsDefs extends scalan.Scalan with WSpecialPredefs {
- self: WrappersModule =>
-
- registerModule(WSpecialPredefsModule)
-
-import WOption._
-import WSpecialPredef._
-
-object WSpecialPredef extends EntityObject("WSpecialPredef") {
-
- implicit case object WSpecialPredefCompanionElem extends CompanionElem[WSpecialPredefCompanionCtor]
-
- abstract class WSpecialPredefCompanionCtor extends CompanionDef[WSpecialPredefCompanionCtor] with WSpecialPredefCompanion {
- def resultType = WSpecialPredefCompanionElem
- override def toString = "WSpecialPredef"
- }
- implicit final def unrefWSpecialPredefCompanionCtor(p: Ref[WSpecialPredefCompanionCtor]): WSpecialPredefCompanionCtor =
- p.node.asInstanceOf[WSpecialPredefCompanionCtor]
-
- lazy val RWSpecialPredef: MutableLazy[WSpecialPredefCompanionCtor] = MutableLazy(new WSpecialPredefCompanionCtor {
- private val thisClass = RClass(classOf[WSpecialPredefCompanion])
-
- def some[A](x: Ref[A]): Ref[WOption[A]] = {
- implicit val eA = x.elem
- asRep[WOption[A]](mkMethodCall(self,
- thisClass.getMethod("some", classOf[Sym]),
- Array[AnyRef](x),
- true, false, element[WOption[A]]))
- }
- })
-
- object WSpecialPredefCompanionMethods {
- object some {
- def unapply(d: Def[_]): Nullable[Ref[A] forSome {type A}] = d match {
- case MethodCall(receiver, method, args, _) if method.getName == "some" && receiver.elem == WSpecialPredefCompanionElem =>
- val res = args(0)
- Nullable(res).asInstanceOf[Nullable[Ref[A] forSome {type A}]]
- case _ => Nullable.None
- }
- def unapply(exp: Sym): Nullable[Ref[A] forSome {type A}] = unapply(exp.node)
- }
- }
-} // of object WSpecialPredef
- registerEntityObject("WSpecialPredef", WSpecialPredef)
-
- override def resetContext(): Unit = {
- super.resetContext()
- RWSpecialPredef.reset()
- }
-
-}
-
-object WSpecialPredefsModule extends scalan.ModuleInfo("wrappers.special", "WSpecialPredefs") {
- val reflection = GraphIRReflection
-}
-}
-
-trait WSpecialPredefsModule extends wrappers.special.impl.WSpecialPredefsDefs {self: WrappersModule =>}
diff --git a/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala b/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala
index 6a7ef5a512..4b3aa2eab5 100644
--- a/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala
+++ b/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala
@@ -7,8 +7,7 @@ import org.ergoplatform.settings.ErgoAlgos
import scorex.util.encode.Base16
import scorex.util.{ModifierId, Random}
import sigma.Extensions._
-import sigma.SigmaDslTesting
-import sigma.ast.SCollection.SByteArray
+import sigma.{SigmaDslTesting, VersionContext}
import sigma.ast.SType._
import sigma.ast.syntax.{ErgoBoxCandidateRType, TrueSigmaProp}
import sigma.ast._
@@ -20,9 +19,11 @@ import sigmastate.helpers.TestingHelpers.copyTransaction
import sigmastate.utils.Helpers
import sigma.SigmaDslTesting
import sigma.Extensions._
+import sigma.ast.SCollection.SByteArray
+import sigmastate.CrossVersionProps
import sigmastate.utils.Helpers.EitherOps // required for Scala 2.11
-class ErgoLikeTransactionSpec extends SigmaDslTesting with JsonCodecs {
+ class ErgoLikeTransactionSpec extends SigmaDslTesting with CrossVersionProps with JsonCodecs {
property("ErgoBox test vectors") {
val token1 = "6e789ab7b2fffff12280a6cd01557f6fb22b7f80ff7aff8e1f7f15973d7f0001"
@@ -99,14 +100,24 @@ class ErgoLikeTransactionSpec extends SigmaDslTesting with JsonCodecs {
{ // test case for R2
val res = b1.get(ErgoBox.R2).get
- val exp = Coll(
- (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token1).toColl) -> 10000000L,
- (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token2).toColl) -> 500L
- ).map(identity).toConstant
- // TODO v6.0 (16h): fix collections equality and remove map(identity)
- // (PairOfColl should be equal CollOverArray but now it is not)
+
+ // We have versioned check here due to fixed collections equality in 6.0.0
+ // (PairOfColl equal CollOverArray now)
// see (https://github.com/ScorexFoundation/sigmastate-interpreter/issues/909)
- res shouldBe exp
+ if(VersionContext.current.isV6SoftForkActivated) {
+ val exp = Coll(
+ (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token1).toColl) -> 10000000L,
+ (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token2).toColl) -> 500L
+ ).toConstant
+ res shouldBe exp
+ exp shouldBe res
+ } else {
+ val exp = Coll(
+ (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token1).toColl) -> 10000000L,
+ (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token2).toColl) -> 500L
+ ).map(identity).toConstant
+ res shouldBe exp
+ }
}
{ // test case for R3
@@ -470,7 +481,6 @@ class ErgoLikeTransactionSpec extends SigmaDslTesting with JsonCodecs {
// test equivalence of "from Json" and "from bytes" deserialization
tx2.id shouldBe tx.id
tx2.id shouldBe "d5c0a7908bbb8eefe72ad70a9f668dd47b748239fd34378d3588d5625dd75c82"
- println(tx2.id)
}
property("Tuple in register test vector") {
diff --git a/sc/shared/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala b/sc/shared/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala
index 26e8b08b14..0216f71f21 100644
--- a/sc/shared/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala
+++ b/sc/shared/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala
@@ -4,6 +4,7 @@ import sigmastate.interpreter.Interpreter.ScriptNameProp
import scala.collection.mutable
import sigma.interpreter.{CostedProverResult, ProverResult}
+
import scala.collection.mutable.ArrayBuffer
import org.ergoplatform.ErgoBox.{NonMandatoryRegisterId, TokenId}
import sigma.data.{AvlTreeData, CAnyValue, CSigmaProp, Nullable}
@@ -14,12 +15,12 @@ import org.ergoplatform.dsl.ContractSyntax.{ErgoScript, Proposition, Token}
import sigma.ast.{ErgoTree, SType}
import sigma.ast.EvaluatedValue
import sigma.interpreter.ContextExtension
-import sigmastate.eval.IRContext
import sigmastate.helpers.{CompilerTestingCommons, ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestInterpreter}
import sigmastate.helpers.TestingHelpers._
import sigma.ast.syntax.ValueOps
import sigma.{AnyValue, Evaluation, SigmaProp}
import ErgoTree.ZeroHeader
+import sigma.compiler.ir.IRContext
case class TestContractSpec(testSuite: CompilerTestingCommons)(implicit val IR: IRContext) extends ContractSpec {
diff --git a/sc/shared/src/test/scala/scalan/BaseLiftableTests.scala b/sc/shared/src/test/scala/scalan/BaseLiftableTests.scala
index 3d437a2f1d..a9da1792ec 100644
--- a/sc/shared/src/test/scala/scalan/BaseLiftableTests.scala
+++ b/sc/shared/src/test/scala/scalan/BaseLiftableTests.scala
@@ -1,8 +1,10 @@
package scalan
+import sigma.compiler.ir.IRContext
+
trait BaseLiftableTests { self: BaseCtxTests =>
- trait LiftableTestKit { scalan: Scalan =>
+ trait LiftableTestKit { scalan: IRContext =>
import Liftables._
/** Check the MethodCall reified in f can be mapped to unlifted method which can be invoked.*/
diff --git a/sc/shared/src/test/scala/scalan/LibraryTests.scala b/sc/shared/src/test/scala/scalan/LibraryTests.scala
index e082e9154d..b21bd2daf1 100644
--- a/sc/shared/src/test/scala/scalan/LibraryTests.scala
+++ b/sc/shared/src/test/scala/scalan/LibraryTests.scala
@@ -1,14 +1,15 @@
package scalan
+import sigma.compiler.ir.IRContext
import sigma.util.BenchmarkUtil.{measure, measureTime}
-class Benchmark[T <: Scalan](createContext: => T) {
+class Benchmark[T <: IRContext](createContext: => T) {
val printDebugInfo: Boolean = false
def run() = {
val (ctx, total) = measureTime {
var ctx = createContext
- measure(10000, okShowIterTime = printDebugInfo, okShowTotalTime = printDebugInfo) { i =>
+ measure(10000, okShowIterTime = printDebugInfo, okShowTotalTime = printDebugInfo) { _ =>
ctx = createContext
}
ctx
diff --git a/sc/shared/src/test/scala/scalan/TestContexts.scala b/sc/shared/src/test/scala/scalan/TestContexts.scala
index a86bf42276..82a6d6b21c 100644
--- a/sc/shared/src/test/scala/scalan/TestContexts.scala
+++ b/sc/shared/src/test/scala/scalan/TestContexts.scala
@@ -1,11 +1,12 @@
package scalan
+import sigma.compiler.ir.{GraphIRReflection, IRContext}
import sigma.reflection.RMethod
import sigma.{BaseNestedTests, BaseShouldTests, BaseTests, TestUtils}
trait TestContexts extends TestUtils {
- trait TestContextApi { scalan: Scalan =>
+ trait TestContextApi { ctx: IRContext =>
def invokeAll: Boolean
def isInvokeEnabled(d: Def[_], m: RMethod): Boolean
def shouldUnpack(e: Elem[_]): Boolean
@@ -19,7 +20,7 @@ trait TestContexts extends TestUtils {
emitF(testName, Seq(() => s1) ++ s2.map((s: Ref[_]) => () => s): _*)
}
}
- abstract class TestContext(val testName: String) extends Scalan with TestContextApi {
+ abstract class TestContext(val testName: String) extends IRContext with TestContextApi {
def this() = this(currentTestNameAsFileName)
override val invokeAll = true
diff --git a/sc/shared/src/test/scala/scalan/TestLibrary.scala b/sc/shared/src/test/scala/scalan/TestLibrary.scala
index efbce25e68..cb3608d4c3 100644
--- a/sc/shared/src/test/scala/scalan/TestLibrary.scala
+++ b/sc/shared/src/test/scala/scalan/TestLibrary.scala
@@ -1,7 +1,9 @@
package scalan
-trait TestLibrary extends Library {
+import sigma.compiler.ir.{GraphIRReflection, IRContext}
+
+trait TestLibrary extends IRContext {
import CollBuilder._
+ import SigmaDslBuilder._
val reflection = (GraphIRReflection)
- lazy val colBuilder: Ref[CollBuilder] = variable[CollBuilder]
}
diff --git a/sc/shared/src/test/scala/sigma/CollsStagingTests.scala b/sc/shared/src/test/scala/sigma/CollsStagingTests.scala
index 3b56920c8d..b26c7d4119 100644
--- a/sc/shared/src/test/scala/sigma/CollsStagingTests.scala
+++ b/sc/shared/src/test/scala/sigma/CollsStagingTests.scala
@@ -3,6 +3,7 @@ package sigma
import scala.language.reflectiveCalls
import special.wrappers.WrappersTests
import scalan._
+import sigma.compiler.ir.IRContext
import sigma.data.CollOverArrayBuilder
class CollsStagingTests extends WrappersTests {
@@ -41,7 +42,7 @@ class CollsStagingTests extends WrappersTests {
}
test("invokeUnlifted for Col") {
- val ctx = new WrappersCtx with Library
+ val ctx = new WrappersCtx with IRContext
import ctx._
import Coll._
import CollBuilder._
@@ -59,7 +60,7 @@ class CollsStagingTests extends WrappersTests {
}
test("invokeUnlifted for method of Ctor") {
- val ctx = new WrappersCtx with Library
+ val ctx = new WrappersCtx with IRContext
import ctx._
import Coll._
import CollBuilder._
diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationBase.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationBase.scala
new file mode 100644
index 0000000000..7be79546e7
--- /dev/null
+++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationBase.scala
@@ -0,0 +1,146 @@
+package sigma
+
+import org.scalatest.BeforeAndAfterAll
+import sigma.ast.{Apply, FixedCostItem, FuncValue, GetVar, JitCost, OptionGet, ValUse}
+import sigma.eval.{CostDetails, EvalSettings, Profiler}
+import sigmastate.CompilerCrossVersionProps
+import sigmastate.interpreter.CErgoTreeEvaluator
+
+import scala.util.Success
+
+/** Base class for language test suites (one suite for each language version: 5.0, 6.0, etc.)
+ * Each suite tests every method of every SigmaDsl type to be equivalent to
+ * the evaluation of the corresponding ErgoScript operation.
+ *
+ * The properties of this suite exercise two interpreters: the current (aka `old`
+ * interpreter) and the new interpreter for a next soft-fork. After the soft-fork is
+ * released, the new interpreter becomes current at which point the `old` and `new`
+ * interpreters in this suite should be equivalent. This change is reflected in this
+ * suite by commiting changes in expected values.
+ * The `old` and `new` interpreters are compared like the following:
+ * 1) for existingFeature the interpreters should be equivalent
+ * 2) for changedFeature the test cases contain different expected values
+ * 3) for newFeature the old interpreter should throw and the new interpreter is checked
+ * against expected values.
+ *
+ * This suite can be used for Cost profiling, i.e. measurements of operations times and
+ * comparing them with cost parameters of the operations.
+ *
+ * The following settings should be specified for profiling:
+ * isMeasureOperationTime = true
+ * isMeasureScriptTime = true
+ * isLogEnabled = false
+ * printTestVectors = false
+ * costTracingEnabled = false
+ * isTestRun = true
+ * perTestWarmUpIters = 1
+ * nBenchmarkIters = 1
+ */
+abstract class LanguageSpecificationBase extends SigmaDslTesting
+ with CompilerCrossVersionProps
+ with BeforeAndAfterAll { suite =>
+
+ /** Version of the language (ErgoScript/ErgoTree) which is specified by this suite. */
+ def languageVersion: Byte
+
+ /** Use VersionContext so that each property in this suite runs under correct
+ * parameters.
+ */
+ protected override def testFun_Run(testName: String, testFun: => Any): Unit = {
+ VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) {
+ super.testFun_Run(testName, testFun)
+ }
+ }
+
+ implicit override val generatorDrivenConfig: PropertyCheckConfiguration = PropertyCheckConfiguration(minSuccessful = 30)
+
+ val evalSettingsInTests = CErgoTreeEvaluator.DefaultEvalSettings.copy(
+ isMeasureOperationTime = true,
+ isMeasureScriptTime = true,
+ isLogEnabled = false, // don't commit the `true` value (travis log is too high)
+ printTestVectors = false, // don't commit the `true` value (travis log is too high)
+
+ /** Should always be enabled in tests (and false by default)
+ * Should be disabled for cost profiling, which case the new costs are not checked.
+ */
+ costTracingEnabled = true,
+ profilerOpt = Some(CErgoTreeEvaluator.DefaultProfiler),
+ isTestRun = true
+ )
+
+ def warmupSettings(p: Profiler) = evalSettingsInTests.copy(
+ isLogEnabled = false,
+ printTestVectors = false,
+ profilerOpt = Some(p)
+ )
+
+ implicit override def evalSettings: EvalSettings = {
+ warmupProfiler match {
+ case Some(p) => warmupSettings(p)
+ case _ => evalSettingsInTests
+ }
+ }
+
+ override val perTestWarmUpIters = 0
+
+ override val nBenchmarkIters = 0
+
+ override val okRunTestsWithoutMCLowering: Boolean = true
+
+ implicit def IR = createIR()
+
+ def testCases[A, B](cases: Seq[(A, Expected[B])], f: Feature[A, B]) = {
+ val table = Table(("x", "y"), cases: _*)
+ forAll(table) { (x, expectedRes) =>
+ val res = f.checkEquality(x)
+ val resValue = res.map(_._1)
+ val (expected, expDetailsOpt) = expectedRes.newResults(ergoTreeVersionInTests)
+ checkResult(resValue, expected.value, failOnTestVectors = true,
+ "SigmaDslSpecifiction#testCases: compare expected new result with res = f.checkEquality(x)")
+ res match {
+ case Success((value, details)) =>
+ details.cost shouldBe JitCost(expected.verificationCost.get)
+ expDetailsOpt.foreach(expDetails =>
+ if (details.trace != expDetails.trace) {
+ printCostDetails(f.script, details)
+ details.trace shouldBe expDetails.trace
+ }
+ )
+ }
+ }
+ }
+
+ override protected def beforeAll(): Unit = {
+ prepareSamples[BigInt]
+ prepareSamples[GroupElement]
+ prepareSamples[AvlTree]
+ prepareSamples[Box]
+ prepareSamples[PreHeader]
+ prepareSamples[Header]
+ prepareSamples[(BigInt, BigInt)]
+ prepareSamples[(GroupElement, GroupElement)]
+ prepareSamples[(AvlTree, AvlTree)]
+ prepareSamples[(Box, Box)]
+ prepareSamples[(PreHeader, PreHeader)]
+ prepareSamples[(Header, Header)]
+ }
+
+ ///=====================================================
+ /// CostDetails shared among test cases
+ ///-----------------------------------------------------
+ val traceBase = Array(
+ FixedCostItem(Apply),
+ FixedCostItem(FuncValue),
+ FixedCostItem(GetVar),
+ FixedCostItem(OptionGet),
+ FixedCostItem(FuncValue.AddToEnvironmentDesc, FuncValue.AddToEnvironmentDesc_CostKind),
+ FixedCostItem(ValUse)
+ )
+
+ /** Helper method to create the given expected results for all tree versions. */
+ def expectedSuccessForAllTreeVersions[A](value: A, cost: Int, costDetails: CostDetails) = {
+ val res = ExpectedResult(Success(value), Some(cost)) -> Some(costDetails)
+ Seq(0, 1, 2, 3).map(version => version -> res)
+ }
+
+}
diff --git a/sc/shared/src/test/scala/sigma/SigmaDslSpecification.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala
similarity index 87%
rename from sc/shared/src/test/scala/sigma/SigmaDslSpecification.scala
rename to sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala
index 4dd576f03a..0bb92f8249 100644
--- a/sc/shared/src/test/scala/sigma/SigmaDslSpecification.scala
+++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala
@@ -5,31 +5,30 @@ import org.ergoplatform._
import org.ergoplatform.settings.ErgoAlgos
import org.scalacheck.Arbitrary._
import org.scalacheck.{Arbitrary, Gen}
-import org.scalatest.BeforeAndAfterAll
import scorex.crypto.authds.avltree.batch._
import scorex.crypto.authds.{ADKey, ADValue}
import scorex.crypto.hash.{Blake2b256, Digest32}
import scorex.util.ModifierId
import sigma.Extensions.{ArrayOps, CollOps}
+import sigma.VersionContext.V6SoftForkVersion
+import sigma.VersionContext.JitActivationVersion
+import sigma.ast.ErgoTree.{HeaderType, ZeroHeader}
import sigma.ast.SCollection._
-import sigma.ast._
import sigma.ast.syntax._
+import sigma.ast.{Apply, MethodCall, PropertyCall, _}
+import sigma.data.OrderingOps._
import sigma.data.RType._
import sigma.data._
+import sigma.eval.Extensions.{ByteExt, IntExt, LongExt, ShortExt}
+import sigma.eval.{CostDetails, EvalSettings, SigmaDsl, TracedCost}
+import sigma.exceptions.InvalidType
+import sigma.serialization.ValueCodes.OpCode
import sigma.util.Extensions.{BooleanOps, IntOps, LongOps}
import sigma.{VersionContext, ast, data, _}
-import ErgoTree.{HeaderType, ZeroHeader}
-import sigma.eval.{CostDetails, EvalSettings, Profiler, SigmaDsl, TracedCost}
-import sigmastate._
import sigmastate.eval.Extensions.AvlTreeOps
-import sigma.eval.Extensions.{ByteExt, IntExt, LongExt, ShortExt}
-import OrderingOps._
import sigmastate.eval._
import sigmastate.helpers.TestingHelpers._
import sigmastate.interpreter._
-import sigma.ast.{Apply, MethodCall, PropertyCall}
-import sigma.exceptions.InvalidType
-import sigma.serialization.ValueCodes.OpCode
import sigmastate.utils.Extensions._
import sigmastate.utils.Helpers
import sigmastate.utils.Helpers._
@@ -38,133 +37,18 @@ import java.math.BigInteger
import scala.collection.compat.immutable.ArraySeq
import scala.util.{Failure, Success}
-/** This suite tests every method of every SigmaDsl type to be equivalent to
- * the evaluation of the corresponding ErgoScript operation.
- *
- * The properties of this suite excercise two interpreters: the current (aka `old`
- * interpreter) and the new interpreter for a next soft-fork. After the soft-fork is
- * released, the new interpreter becomes current at which point the `old` and `new`
- * interpreters in this suite should be equivalent. This change is reflected in this
- * suite by commiting changes in expected values.
- * The `old` and `new` interpreters are compared like the following:
- * 1) for existingFeature the interpreters should be equivalent
- * 2) for changedFeature the test cases contain different expected values
- * 3) for newFeature the old interpreter should throw and the new interpreter is checked
- * against expected values.
- *
- * This suite can be used for Cost profiling, i.e. measurements of operations times and
- * comparing them with cost parameteres of the operations.
+
+/** This suite tests all operations for v5.0 version of the language.
+ * The base classes establish the infrastructure for the tests.
*
- * The following settings should be specified for profiling:
- * isMeasureOperationTime = true
- * isMeasureScriptTime = true
- * isLogEnabled = false
- * printTestVectors = false
- * costTracingEnabled = false
- * isTestRun = true
- * perTestWarmUpIters = 1
- * nBenchmarkIters = 1
+ * @see SigmaDslSpecificationBase
*/
-class SigmaDslSpecification extends SigmaDslTesting
- with CompilerCrossVersionProps
- with BeforeAndAfterAll { suite =>
-
- /** Use VersionContext so that each property in this suite runs under correct
- * parameters.
- */
- protected override def testFun_Run(testName: String, testFun: => Any): Unit = {
- VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) {
- super.testFun_Run(testName, testFun)
- }
- }
-
- implicit override val generatorDrivenConfig = PropertyCheckConfiguration(minSuccessful = 30)
-
- val evalSettingsInTests = CErgoTreeEvaluator.DefaultEvalSettings.copy(
- isMeasureOperationTime = true,
- isMeasureScriptTime = true,
- isLogEnabled = false, // don't commit the `true` value (travis log is too high)
- printTestVectors = false, // don't commit the `true` value (travis log is too high)
-
- /** Should always be enabled in tests (and false by default)
- * Should be disabled for cost profiling, which case the new costs are not checked.
- */
- costTracingEnabled = true,
+class LanguageSpecificationV5 extends LanguageSpecificationBase { suite =>
- profilerOpt = Some(CErgoTreeEvaluator.DefaultProfiler),
- isTestRun = true
- )
-
- def warmupSettings(p: Profiler) = evalSettingsInTests.copy(
- isLogEnabled = false,
- printTestVectors = false,
- profilerOpt = Some(p)
- )
-
- implicit override def evalSettings: EvalSettings = {
- warmupProfiler match {
- case Some(p) => warmupSettings(p)
- case _ => evalSettingsInTests
- }
- }
-
- override val perTestWarmUpIters = 0
-
- override val nBenchmarkIters = 0
-
- override val okRunTestsWithoutMCLowering: Boolean = true
-
- implicit def IR = createIR()
-
- def testCases[A, B](cases: Seq[(A, Expected[B])], f: Feature[A, B]) = {
- val table = Table(("x", "y"), cases:_*)
- forAll(table) { (x, expectedRes) =>
- val res = f.checkEquality(x)
- val resValue = res.map(_._1)
- val (expected, expDetailsOpt) = expectedRes.newResults(ergoTreeVersionInTests)
- checkResult(resValue, expected.value, failOnTestVectors = true,
- "SigmaDslSpecifiction#testCases: compare expected new result with res = f.checkEquality(x)")
- res match {
- case Success((value, details)) =>
- details.cost shouldBe JitCost(expected.verificationCost.get)
- expDetailsOpt.foreach(expDetails =>
- if (details.trace != expDetails.trace) {
- printCostDetails(f.script, details)
- details.trace shouldBe expDetails.trace
- }
- )
- }
- }
- }
+ override def languageVersion: Byte = VersionContext.JitActivationVersion
import TestData._
- override protected def beforeAll(): Unit = {
- prepareSamples[BigInt]
- prepareSamples[GroupElement]
- prepareSamples[AvlTree]
- prepareSamples[Box]
- prepareSamples[PreHeader]
- prepareSamples[Header]
- prepareSamples[(BigInt, BigInt)]
- prepareSamples[(GroupElement, GroupElement)]
- prepareSamples[(AvlTree, AvlTree)]
- prepareSamples[(Box, Box)]
- prepareSamples[(PreHeader, PreHeader)]
- prepareSamples[(Header, Header)]
- }
-
- ///=====================================================
- /// CostDetails shared among test cases
- ///-----------------------------------------------------
- val traceBase = Array(
- FixedCostItem(Apply),
- FixedCostItem(FuncValue),
- FixedCostItem(GetVar),
- FixedCostItem(OptionGet),
- FixedCostItem(FuncValue.AddToEnvironmentDesc, FuncValue.AddToEnvironmentDesc_CostKind),
- FixedCostItem(ValUse)
- )
def upcastCostDetails(tpe: SType) = TracedCost(traceBase :+ TypeBasedCostItem(Upcast, tpe))
def downcastCostDetails(tpe: SType) = TracedCost(traceBase :+ TypeBasedCostItem(Downcast, tpe))
def arithOpsCostDetails(tpe: SType) = CostDetails(
@@ -232,17 +116,6 @@ class SigmaDslSpecification extends SigmaDslTesting
/// 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 }",
@@ -262,7 +135,9 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
val newCost = 1768
- def success(b: Boolean) = Expected(Success(b), 1768, newDetails, newCost)
+
+ def success(b: Boolean) = Expected(Success(b), 1768, newDetails, newCost, Seq.fill(4)(2012))
+
val cases = Seq(
(true, true) -> success(false),
(true, false) -> success(true),
@@ -291,14 +166,14 @@ class SigmaDslSpecification extends SigmaDslTesting
val expectedCost = 1768
val newCost = 1768
val cases = Seq(
- (true, true) -> Expected(Success(false), expectedCost, newDetails, newCost)
+ (true, true) -> Expected(Success(false), expectedCost, newDetails, newCost, Seq.fill(4)(2012))
)
verifyCases(cases, feature)
val initCost = 100
initialCostInTests.withValue(initCost) {
val cases = Seq(
- (true, true) -> Expected(Success(false), expectedCost + initCost, newDetails, newCost + initCost)
+ (true, true) -> Expected(Success(false), expectedCost + initCost, newDetails, newCost + initCost, Seq.fill(4)(2012 + initCost))
)
verifyCases(cases, feature)
}
@@ -327,7 +202,9 @@ class SigmaDslSpecification extends SigmaDslTesting
FixedCostItem(BinXor)
)
)
- def success(b: Boolean) = Expected(Success(b), 1769, newDetails, 1769)
+
+ def success(b: Boolean) = Expected(Success(b), 1769, newDetails, 1769, Seq.fill(4)(2027))
+
val cases = Seq(
(1095564593, true) -> success(true),
(-901834021, true) -> success(true),
@@ -364,10 +241,10 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
val cases = Seq(
- (false, true) -> Expected(Success(false), 1766, newDetails1, 1766),
- (false, false) -> Expected(Success(false), 1766, newDetails1, 1766),
- (true, true) -> Expected(Success(true), 1768, newDetails2, 1768),
- (true, false) -> Expected(Success(false), 1768, newDetails2, 1768)
+ (false, true) -> Expected(Success(false), 1766, newDetails1, 1766, Seq.fill(4)(2010)),
+ (false, false) -> Expected(Success(false), 1766, newDetails1, 1766, Seq.fill(4)(2010)),
+ (true, true) -> Expected(Success(true), 1768, newDetails2, 1768, Seq.fill(4)(2012)),
+ (true, false) -> Expected(Success(false), 1768, newDetails2, 1768, Seq.fill(4)(2012))
)
verifyCases(cases, eq)
}
@@ -397,10 +274,10 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
val cases = Seq(
- (true, false) -> Expected(Success(true), 1766, newDetails1, 1766),
- (true, true) -> Expected(Success(true), 1766, newDetails1, 1766),
- (false, false) -> Expected(Success(false), 1768, newDetails2, 1768),
- (false, true) -> Expected(Success(true), 1768, newDetails2, 1768)
+ (true, false) -> Expected(Success(true), 1766, newDetails1, 1766, Seq.fill(4)(2010)),
+ (true, true) -> Expected(Success(true), 1766, newDetails1, 1766, Seq.fill(4)(2010)),
+ (false, false) -> Expected(Success(false), 1768, newDetails2, 1768, Seq.fill(4)(2012)),
+ (false, true) -> Expected(Success(true), 1768, newDetails2, 1768, Seq.fill(4)(2012))
)
verifyCases(cases, eq)
}
@@ -445,7 +322,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
Seq(
- (true, Expected(Success(true), 1765, newDetails1, 1765)),
+ (true, Expected(Success(true), 1765, newDetails1, 1765, Seq.fill(4)(2027))),
(false, Expected(new ArithmeticException("/ by zero")))
),
existingFeature((x: Boolean) => x || (1 / 0 == 1),
@@ -461,7 +338,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
(true, Expected(new ArithmeticException("/ by zero"))),
- (false, Expected(Success(false), 1765, newDetails2, 1765))
+ (false, Expected(Success(false), 1765, newDetails2, 1765, Seq.fill(4)(2027)))
),
existingFeature((x: Boolean) => x && (1 / 0 == 1),
"{ (x: Boolean) => x && (1 / 0 == 1) }",
@@ -475,8 +352,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
- (false, Expected(Success(false), 1765, newDetails2, 1765)),
- (true, Expected(Success(true), 1768, newDetails3, 1768))
+ (false, Expected(Success(false), 1765, newDetails2, 1765, Seq.fill(4)(2033))),
+ (true, Expected(Success(true), 1768, newDetails3, 1768, Seq.fill(4)(2036)))
),
existingFeature((x: Boolean) => x && (x || (1 / 0 == 1)),
"{ (x: Boolean) => x && (x || (1 / 0 == 1)) }",
@@ -493,8 +370,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
- (false, Expected(Success(false), 1765, newDetails2, 1765)),
- (true, Expected(Success(true), 1770, newDetails4, 1770))
+ (false, Expected(Success(false), 1765, newDetails2, 1765, Seq.fill(4)(2039))),
+ (true, Expected(Success(true), 1770, newDetails4, 1770, Seq.fill(4)(2044)))
),
existingFeature((x: Boolean) => x && (x && (x || (1 / 0 == 1))),
"{ (x: Boolean) => x && (x && (x || (1 / 0 == 1))) }",
@@ -514,8 +391,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
- (false, Expected(Success(false), 1765, newDetails2, 1765)),
- (true, Expected(Success(true), 1773, newDetails5, 1773))
+ (false, Expected(Success(false), 1765, newDetails2, 1765, Seq.fill(4)(2045))),
+ (true, Expected(Success(true), 1773, newDetails5, 1773, Seq.fill(4)(2053)))
),
existingFeature((x: Boolean) => x && (x && (x && (x || (1 / 0 == 1)))),
"{ (x: Boolean) => x && (x && (x && (x || (1 / 0 == 1)))) }",
@@ -549,7 +426,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
(false, Expected(new ArithmeticException("/ by zero"))),
- (true, Expected(Success(true), 1773, newDetails6, 1773))
+ (true, Expected(Success(true), 1773, newDetails6, 1773, Seq.fill(4)(2075)))
),
existingFeature((x: Boolean) => !(!x && (1 / 0 == 1)) && (x || (1 / 0 == 1)),
"{ (x: Boolean) => !(!x && (1 / 0 == 1)) && (x || (1 / 0 == 1)) }",
@@ -578,7 +455,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
Seq(
- (true, Expected(Success(true), 1768, newDetails7, 1768)),
+ (true, Expected(Success(true), 1768, newDetails7, 1768, Seq.fill(4)(2036))),
(false, Expected(new ArithmeticException("/ by zero")))
),
existingFeature((x: Boolean) => (x || (1 / 0 == 1)) && x,
@@ -604,7 +481,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
Seq(
- (true, Expected(Success(true), 1770, newDetails8, 1770)),
+ (true, Expected(Success(true), 1770, newDetails8, 1770, Seq.fill(4)(2068))),
(false, Expected(new ArithmeticException("/ by zero")))
),
existingFeature((x: Boolean) => (x || (1 / 0 == 1)) && (x || (1 / 0 == 1)),
@@ -636,7 +513,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
Seq(
- (true, Expected(Success(true), 1775, newDetails9, 1775)),
+ (true, Expected(Success(true), 1775, newDetails9, 1775, Seq.fill(4)(2107))),
(false, Expected(new ArithmeticException("/ by zero")))
),
existingFeature(
@@ -686,7 +563,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
(false, Expected(new ArithmeticException("/ by zero"))),
- (true, Expected(Success(true), 1780, newDetails10, 1780))
+ (true, Expected(Success(true), 1780, newDetails10, 1780, Seq.fill(4)(2156)))
),
existingFeature(
(x: Boolean) => (!(!x && (1 / 0 == 1)) || (1 / 0 == 0)) && (!(!x && (1 / 0 == 1)) || (1 / 0 == 1)),
@@ -729,7 +606,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def expect(v: Byte) = Expected(Success(v), 1763, TracedCost(traceBase), 1763)
+ def expect(v: Byte) = Expected(Success(v), 1763, TracedCost(traceBase), 1763, Seq.fill(4)(1993))
+
Seq(
(0.toByte, expect(0.toByte)),
(1.toByte, expect(1.toByte)),
@@ -746,7 +624,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def expected(v: Short) = Expected(Success(v), 1764, upcastCostDetails(SShort), 1764)
+ def expected(v: Short) = Expected(Success(v), 1764, upcastCostDetails(SShort), 1764, Seq.fill(4)(1998))
+
Seq(
(0.toByte, expected(0.toShort)),
(1.toByte, expected(1.toShort)),
@@ -763,7 +642,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def expected(v: Int) = Expected(Success(v), 1764, upcastCostDetails(SInt), 1764)
+ def expected(v: Int) = Expected(Success(v), 1764, upcastCostDetails(SInt), 1764, Seq.fill(4)(1998))
+
Seq(
(0.toByte, expected(0)),
(1.toByte, expected(1)),
@@ -780,7 +660,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def expected(v: Long) = Expected(Success(v), 1764, upcastCostDetails(SLong), 1764)
+ def expected(v: Long) = Expected(Success(v), 1764, upcastCostDetails(SLong), 1764, Seq.fill(4)(1998))
+
Seq(
(0.toByte, expected(0L)),
(1.toByte, expected(1L)),
@@ -797,7 +678,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def expected(v: BigInt) = Expected(Success(v), 1767, upcastCostDetails(SBigInt), 1767)
+ def expected(v: BigInt) = Expected(Success(v), 1767, upcastCostDetails(SBigInt), 1767, Seq.fill(4)(2001))
+
Seq(
(0.toByte, expected(CBigInt(new BigInteger("0", 16)))),
(1.toByte, expected(CBigInt(new BigInteger("1", 16)))),
@@ -815,7 +697,8 @@ class SigmaDslSpecification extends SigmaDslTesting
val n = ExactIntegral.ByteIsExactIntegral
verifyCases(
{
- def success[T](v: (T, (T, (T, (T, T))))) = Expected(Success(v), 1788, arithOpsCostDetails(SByte), 1788)
+ def success[T](v: (T, (T, (T, (T, T))))) = Expected(Success(v), 1788, arithOpsCostDetails(SByte), 1788, Seq.fill(4)(2116))
+
Seq(
((-128.toByte, -128.toByte), Expected(new ArithmeticException("Byte overflow"))),
((-128.toByte, 0.toByte), Expected(new ArithmeticException("/ by zero"))),
@@ -914,6 +797,12 @@ class SigmaDslSpecification extends SigmaDslTesting
((y, x), Expected(res.value, cost, newCostDetails, cost))
}
+ def swapArgs[A](cases: Seq[((A, A), Expected[Boolean])], cost: Int, newCostDetails: CostDetails,
+ expectedV3Costs: Seq[Int]) =
+ cases.map { case ((x, y), res) =>
+ ((y, x), Expected(res.value, cost, newCostDetails, cost, expectedV3Costs))
+ }
+
def newCasesFrom[A, R](
cases: Seq[(A, A)]
)(
@@ -932,12 +821,19 @@ class SigmaDslSpecification extends SigmaDslTesting
((x, y), Expected(Success(getExpectedRes(x, y)), cost = cost, expectedDetails = newCostDetails, expectedNewCost = cost))
}
- def verifyOp[A: Ordering: Arbitrary]
- (cases: Seq[((A, A), Expected[Boolean])],
- opName: String,
- op: (SValue, SValue) => SValue)
- (expectedFunc: (A, A) => Boolean, generateCases: Boolean = true)
- (implicit tA: RType[A], sampled: Sampled[(A, A)], evalSettings: EvalSettings) = {
+ def newCasesFrom3[A, R](cases: Seq[(A, A)])
+ (getExpectedRes: (A, A) => R, cost: Int, newCostDetails: CostDetails,
+ expectedV3Costs: Seq[Int]) =
+ cases.map { case (x, y) =>
+ ((x, y), Expected(Success(getExpectedRes(x, y)), cost = cost, expectedDetails = newCostDetails, expectedNewCost = cost, expectedV3Costs))
+ }
+
+ def verifyOp[A: Ordering : Arbitrary]
+ (cases: Seq[((A, A), Expected[Boolean])],
+ opName: String,
+ op: (SValue, SValue) => SValue)
+ (expectedFunc: (A, A) => Boolean, generateCases: Boolean = true)
+ (implicit tA: RType[A], sampled: Sampled[(A, A)], evalSettings: EvalSettings) = {
val nameA = RType[A].name
val tpeA = Evaluation.rtypeToSType(tA)
verifyCases(cases,
@@ -962,7 +858,9 @@ class SigmaDslSpecification extends SigmaDslTesting
property("Byte LT, GT, NEQ") {
val o = ExactOrdering.ByteIsExactOrdering
- def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LT, SByte), 1768)
+
+ def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LT, SByte), 1768, Seq.fill(4)(2012))
+
val LT_cases: Seq[((Byte, Byte), Expected[Boolean])] = Seq(
(-128.toByte, -128.toByte) -> expect(false),
(-128.toByte, -127.toByte) -> expect(true),
@@ -1003,16 +901,18 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyOp(LT_cases, "<", LT.apply)(_ < _)
verifyOp(
- swapArgs(LT_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GT, SByte)),
+ swapArgs(LT_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GT, SByte), expectedV3Costs = Seq.fill(4)(2012)),
">", GT.apply)(_ > _)
- val neqCases = newCasesFrom2(LT_cases.map(_._1))(_ != _, cost = 1766, newCostDetails = costNEQ(constNeqCost))
+ val neqCases = newCasesFrom3(LT_cases.map(_._1))(_ != _, cost = 1766, newCostDetails = costNEQ(constNeqCost), expectedV3Costs = Seq.fill(4)(2010))
verifyOp(neqCases, "!=", NEQ.apply)(_ != _)
}
property("Byte LE, GE") {
val o = ExactOrdering.ByteIsExactOrdering
- def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LE, SByte), 1768)
+
+ def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LE, SByte), 1768, Seq.fill(4)(2012))
+
val LE_cases: Seq[((Byte, Byte), Expected[Boolean])] = Seq(
(-128.toByte, -128.toByte) -> expect(true),
(-128.toByte, -127.toByte) -> expect(true),
@@ -1054,41 +954,18 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyOp(LE_cases, "<=", LE.apply)(_ <= _)
verifyOp(
- swapArgs(LE_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GE, SByte)),
+ swapArgs(LE_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GE, SByte), expectedV3Costs = Seq.fill(4)(2012)),
">=", 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
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SByte), 1764)
+ def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SByte), 1764, Seq.fill(4)(1998))
+
Seq(
(Short.MinValue, Expected(new ArithmeticException("Byte overflow"))),
(-21626.toShort, Expected(new ArithmeticException("Byte overflow"))),
@@ -1107,7 +984,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1763, TracedCost(traceBase), 1763)
+ def success[T](v: T) = Expected(Success(v), 1763, TracedCost(traceBase), 1763, Seq.fill(4)(1993))
+
Seq(
(-32768.toShort, success(-32768.toShort)),
(-27798.toShort, success(-27798.toShort)),
@@ -1124,7 +1002,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1764, upcastCostDetails(SInt), 1764)
+ def success[T](v: T) = Expected(Success(v), 1764, upcastCostDetails(SInt), 1764, Seq.fill(4)(1998))
+
Seq(
(-32768.toShort, success(-32768)),
(-21064.toShort, success(-21064)),
@@ -1141,7 +1020,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1764, upcastCostDetails(SLong), 1764)
+ def success[T](v: T) = Expected(Success(v), 1764, upcastCostDetails(SLong), 1764, Seq.fill(4)(1998))
+
Seq(
(-32768.toShort, success(-32768L)),
(-23408.toShort, success(-23408L)),
@@ -1158,7 +1038,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success(v: BigInt) = Expected(Success(v), 1767, upcastCostDetails(SBigInt), 1767)
+ def success(v: BigInt) = Expected(Success(v), 1767, upcastCostDetails(SBigInt), 1767, Seq.fill(4)(2001))
+
Seq(
(-32768.toShort, success(CBigInt(new BigInteger("-8000", 16)))),
(-26248.toShort, success(CBigInt(new BigInteger("-6688", 16)))),
@@ -1176,7 +1057,8 @@ class SigmaDslSpecification extends SigmaDslTesting
val n = ExactIntegral.ShortIsExactIntegral
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1788, arithOpsCostDetails(SShort), 1788)
+ def success[T](v: T) = Expected(Success(v), 1788, arithOpsCostDetails(SShort), 1788, Seq.fill(4)(2116))
+
Seq(
((-32768.toShort, 1.toShort), Expected(new ArithmeticException("Short overflow"))),
((-32768.toShort, 4006.toShort), Expected(new ArithmeticException("Short overflow"))),
@@ -1268,7 +1150,9 @@ class SigmaDslSpecification extends SigmaDslTesting
property("Short LT, GT, NEQ") {
val o = ExactOrdering.ShortIsExactOrdering
- def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LT, SShort), 1768)
+
+ def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LT, SShort), 1768, Seq.fill(4)(2012))
+
val LT_cases: Seq[((Short, Short), Expected[Boolean])] = Seq(
(Short.MinValue, Short.MinValue) -> expect(false),
(Short.MinValue, (Short.MinValue + 1).toShort) -> expect(true),
@@ -1308,15 +1192,17 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyOp(LT_cases, "<", LT.apply)(_ < _)
- verifyOp(swapArgs(LT_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GT, SShort)), ">", GT.apply)(_ > _)
+ verifyOp(swapArgs(LT_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GT, SShort), expectedV3Costs = Seq.fill(4)(2012)), ">", GT.apply)(_ > _)
- val neqCases = newCasesFrom2(LT_cases.map(_._1))(_ != _, cost = 1766, newCostDetails = costNEQ(constNeqCost))
+ val neqCases = newCasesFrom3(LT_cases.map(_._1))(_ != _, cost = 1766, newCostDetails = costNEQ(constNeqCost), expectedV3Costs = Seq.fill(4)(2010))
verifyOp(neqCases, "!=", NEQ.apply)(_ != _)
}
property("Short LE, GE") {
val o = ExactOrdering.ShortIsExactOrdering
- def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LE, SShort), 1768)
+
+ def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LE, SShort), 1768, Seq.fill(4)(2012))
+
val LE_cases: Seq[((Short, Short), Expected[Boolean])] = Seq(
(Short.MinValue, Short.MinValue) -> expect(true),
(Short.MinValue, (Short.MinValue + 1).toShort) -> expect(true),
@@ -1358,40 +1244,18 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyOp(LE_cases, "<=", LE.apply)(_ <= _)
verifyOp(
- swapArgs(LE_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GE, SShort)),
+ swapArgs(LE_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GE, SShort), expectedV3Costs = Seq.fill(4)(2012)),
">=", 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
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SByte), 1764)
+ def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SByte), 1764, Seq.fill(4)(1998))
+
Seq(
(Int.MinValue, Expected(new ArithmeticException("Byte overflow"))),
(-2014394379, Expected(new ArithmeticException("Byte overflow"))),
@@ -1410,7 +1274,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SShort), 1764)
+ def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SShort), 1764, Seq.fill(4)(1998))
+
Seq(
(Int.MinValue, Expected(new ArithmeticException("Short overflow"))),
(Short.MinValue - 1, Expected(new ArithmeticException("Short overflow"))),
@@ -1429,7 +1294,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1763, TracedCost(traceBase), 1763)
+ def success[T](v: T) = Expected(Success(v), 1763, TracedCost(traceBase), 1763, Seq.fill(4)(1993))
+
Seq(
(Int.MinValue, success(Int.MinValue)),
(-1, success(-1)),
@@ -1444,7 +1310,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1764, upcastCostDetails(SLong), 1764)
+ def success[T](v: T) = Expected(Success(v), 1764, upcastCostDetails(SLong), 1764, Seq.fill(4)(1998))
+
Seq(
(Int.MinValue, success(Int.MinValue.toLong)),
(-1, success(-1L)),
@@ -1459,7 +1326,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success(v: BigInt) = Expected(Success(v), 1767, upcastCostDetails(SBigInt), 1767)
+ def success(v: BigInt) = Expected(Success(v), 1767, upcastCostDetails(SBigInt), 1767, Seq.fill(4)(2001))
+
Seq(
(Int.MinValue, success(CBigInt(new BigInteger("-80000000", 16)))),
(-1937187314, success(CBigInt(new BigInteger("-737721f2", 16)))),
@@ -1476,57 +1344,59 @@ class SigmaDslSpecification extends SigmaDslTesting
val n = ExactNumeric.IntIsExactNumeric
verifyCases(
- {
- def success[T](v: T) = Expected(Success(v), 1788, arithOpsCostDetails(SInt), 1788)
- Seq(
- ((Int.MinValue, 449583993), Expected(new ArithmeticException("integer overflow"))),
- ((-1589633733, 2147483647), Expected(new ArithmeticException("integer overflow"))),
- ((-1585471506, -1), success((-1585471507, (-1585471505, (1585471506, (1585471506, 0)))))),
- ((-1569005179, 1230236634), Expected(new ArithmeticException("integer overflow"))),
- ((-1493733356, -1319619597), Expected(new ArithmeticException("integer overflow"))),
- ((-1100263120, -880052091), Expected(new ArithmeticException("integer overflow"))),
- ((-1055955857, 309147303), Expected(new ArithmeticException("integer overflow"))),
- ((-569807371, 0), Expected(new ArithmeticException("/ by zero"))),
- ((-522264843, 2147483647), Expected(new ArithmeticException("integer overflow"))),
- ((-109552389, 0), Expected(new ArithmeticException("/ by zero"))),
- ((-1, -2147483648), Expected(new ArithmeticException("integer overflow"))),
- ((-1, -1), success((-2, (0, (1, (1, 0)))))),
- ((-1, 0), Expected(new ArithmeticException("/ by zero"))),
- ((0, -2147483648), Expected(new ArithmeticException("integer overflow"))),
- ((1, -1525049432), success((-1525049431, (1525049433, (-1525049432, (0, 1)))))),
- ((1, 0), Expected(new ArithmeticException("/ by zero"))),
- ((1, 805353746), success((805353747, (-805353745, (805353746, (0, 1)))))),
- ((1, 2147483647), Expected(new ArithmeticException("integer overflow"))),
- ((475797978, 0), Expected(new ArithmeticException("/ by zero"))),
- ((782343922, -1448560539), Expected(new ArithmeticException("integer overflow"))),
- ((928769361, 542647292), Expected(new ArithmeticException("integer overflow"))),
- ((1568062151, 0), Expected(new ArithmeticException("/ by zero"))),
- ((1698252401, -1), success((1698252400, (1698252402, (-1698252401, (-1698252401, 0)))))),
- ((1949795740, -1575667037), Expected(new ArithmeticException("integer overflow"))),
- ((Int.MaxValue, -1), Expected(new ArithmeticException("integer overflow"))),
- ((Int.MaxValue, 1), Expected(new ArithmeticException("integer overflow"))),
- ((Int.MaxValue, 1738276576), Expected(new ArithmeticException("integer overflow")))
- )
- },
- existingFeature(
- { (x: (Int, Int)) =>
- val a = x._1; val b = x._2
- val plus = n.plus(a, b)
- val minus = n.minus(a, b)
- val mul = n.times(a, b)
- val div = a / b
- val mod = a % b
- (plus, (minus, (mul, (div, mod))))
+ {
+ def success[T](v: T) = Expected(Success(v), 1788, arithOpsCostDetails(SInt), 1788, Seq.fill(4)(2116))
+
+ Seq(
+ ((Int.MinValue, 449583993), Expected(new ArithmeticException("integer overflow"))),
+ ((-1589633733, 2147483647), Expected(new ArithmeticException("integer overflow"))),
+ ((-1585471506, -1), success((-1585471507, (-1585471505, (1585471506, (1585471506, 0)))))),
+ ((-1569005179, 1230236634), Expected(new ArithmeticException("integer overflow"))),
+ ((-1493733356, -1319619597), Expected(new ArithmeticException("integer overflow"))),
+ ((-1100263120, -880052091), Expected(new ArithmeticException("integer overflow"))),
+ ((-1055955857, 309147303), Expected(new ArithmeticException("integer overflow"))),
+ ((-569807371, 0), Expected(new ArithmeticException("/ by zero"))),
+ ((-522264843, 2147483647), Expected(new ArithmeticException("integer overflow"))),
+ ((-109552389, 0), Expected(new ArithmeticException("/ by zero"))),
+ ((-1, -2147483648), Expected(new ArithmeticException("integer overflow"))),
+ ((-1, -1), success((-2, (0, (1, (1, 0)))))),
+ ((-1, 0), Expected(new ArithmeticException("/ by zero"))),
+ ((0, -2147483648), Expected(new ArithmeticException("integer overflow"))),
+ ((1, -1525049432), success((-1525049431, (1525049433, (-1525049432, (0, 1)))))),
+ ((1, 0), Expected(new ArithmeticException("/ by zero"))),
+ ((1, 805353746), success((805353747, (-805353745, (805353746, (0, 1)))))),
+ ((1, 2147483647), Expected(new ArithmeticException("integer overflow"))),
+ ((475797978, 0), Expected(new ArithmeticException("/ by zero"))),
+ ((782343922, -1448560539), Expected(new ArithmeticException("integer overflow"))),
+ ((928769361, 542647292), Expected(new ArithmeticException("integer overflow"))),
+ ((1568062151, 0), Expected(new ArithmeticException("/ by zero"))),
+ ((1698252401, -1), success((1698252400, (1698252402, (-1698252401, (-1698252401, 0)))))),
+ ((1949795740, -1575667037), Expected(new ArithmeticException("integer overflow"))),
+ ((Int.MaxValue, -1), Expected(new ArithmeticException("integer overflow"))),
+ ((Int.MaxValue, 1), Expected(new ArithmeticException("integer overflow"))),
+ ((Int.MaxValue, 1738276576), Expected(new ArithmeticException("integer overflow")))
+ )
},
- """{ (x: (Int, Int)) =>
- | val a = x._1; val b = x._2
- | val plus = a + b
- | val minus = a - b
- | val mul = a * b
- | val div = a / b
- | val mod = a % b
- | (plus, (minus, (mul, (div, mod))))
- |}""".stripMargin,
+ existingFeature(
+ { (x: (Int, Int)) =>
+ val a = x._1;
+ val b = x._2
+ val plus = n.plus(a, b)
+ val minus = n.minus(a, b)
+ val mul = n.times(a, b)
+ val div = a / b
+ val mod = a % b
+ (plus, (minus, (mul, (div, mod))))
+ },
+ """{ (x: (Int, Int)) =>
+ | val a = x._1; val b = x._2
+ | val plus = a + b
+ | val minus = a - b
+ | val mul = a * b
+ | val div = a / b
+ | val mod = a % b
+ | (plus, (minus, (mul, (div, mod))))
+ |}""".stripMargin,
FuncValue(
Vector((1, STuple(Vector(SInt, SInt)))),
BlockValue(
@@ -1569,7 +1439,9 @@ class SigmaDslSpecification extends SigmaDslTesting
property("Int LT, GT, NEQ") {
val o = ExactOrdering.IntIsExactOrdering
- def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LT, SInt), 1768)
+
+ def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LT, SInt), 1768, Seq.fill(4)(2012))
+
val LT_cases: Seq[((Int, Int), Expected[Boolean])] = Seq(
(Int.MinValue, Int.MinValue) -> expect(false),
(Int.MinValue, (Int.MinValue + 1).toInt) -> expect(true),
@@ -1610,16 +1482,16 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyOp(LT_cases, "<", LT.apply)(_ < _)
verifyOp(
- swapArgs(LT_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GT, SInt)),
+ swapArgs(LT_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GT, SInt), expectedV3Costs = Seq.fill(4)(2012)),
">", GT.apply)(_ > _)
- val neqCases = newCasesFrom2(LT_cases.map(_._1))(_ != _, cost = 1766, newCostDetails = costNEQ(constNeqCost))
+ val neqCases = newCasesFrom3(LT_cases.map(_._1))(_ != _, cost = 1766, newCostDetails = costNEQ(constNeqCost), expectedV3Costs = Seq.fill(4)(2010))
verifyOp(neqCases, "!=", NEQ.apply)(_ != _)
}
property("Int LE, GE") {
val o = ExactOrdering.IntIsExactOrdering
- def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LE, SInt), 1768)
+ def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LE, SInt), 1768, Seq.fill(4)(2012))
val LE_cases: Seq[((Int, Int), Expected[Boolean])] = Seq(
(Int.MinValue, Int.MinValue) -> expect(true),
(Int.MinValue, (Int.MinValue + 1).toInt) -> expect(true),
@@ -1661,32 +1533,10 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyOp(LE_cases, "<=", LE.apply)(_ <= _)
verifyOp(
- swapArgs(LE_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GE, SInt)),
+ swapArgs(LE_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GE, SInt), expectedV3Costs = Seq.fill(4)(2012)),
">=", 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
@@ -1697,7 +1547,7 @@ class SigmaDslSpecification extends SigmaDslTesting
property("Long.toByte method") {
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SByte), 1764)
+ def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SByte), 1764, Seq.fill(4)(1998))
Seq(
(Long.MinValue, Expected(new ArithmeticException("Byte overflow"))),
(Byte.MinValue.toLong - 1, Expected(new ArithmeticException("Byte overflow"))),
@@ -1718,7 +1568,7 @@ class SigmaDslSpecification extends SigmaDslTesting
property("Long.toShort method") {
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SShort), 1764)
+ def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SShort), 1764, Seq.fill(4)(1998))
Seq(
(Long.MinValue, Expected(new ArithmeticException("Short overflow"))),
(Short.MinValue.toLong - 1, Expected(new ArithmeticException("Short overflow"))),
@@ -1739,7 +1589,8 @@ class SigmaDslSpecification extends SigmaDslTesting
property("Long.toInt method") {
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SInt), 1764)
+ def success[T](v: T) = Expected(Success(v), 1764, downcastCostDetails(SInt), 1764, Seq.fill(4)(1998))
+
Seq(
(Long.MinValue, Expected(new ArithmeticException("Int overflow"))),
(Int.MinValue.toLong - 1, Expected(new ArithmeticException("Int overflow"))),
@@ -1760,7 +1611,7 @@ class SigmaDslSpecification extends SigmaDslTesting
property("Long.toLong method") {
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1763, TracedCost(traceBase), 1763)
+ def success[T](v: T) = Expected(Success(v), 1763, TracedCost(traceBase), 1763, Seq.fill(4)(1993))
Seq(
(Long.MinValue, success(Long.MinValue)),
(-1L, success(-1L)),
@@ -1777,7 +1628,7 @@ class SigmaDslSpecification extends SigmaDslTesting
property("Long.toBigInt method") {
verifyCases(
{
- def success(v: BigInt) = Expected(Success(v), 1767, upcastCostDetails(SBigInt), 1767)
+ def success(v: BigInt) = Expected(Success(v), 1767, upcastCostDetails(SBigInt), 1767, Seq.fill(4)(2001))
Seq(
(Long.MinValue, success(CBigInt(new BigInteger("-8000000000000000", 16)))),
(-1074651039980347209L, success(CBigInt(new BigInteger("-ee9ed6d57885f49", 16)))),
@@ -1797,83 +1648,85 @@ class SigmaDslSpecification extends SigmaDslTesting
val n = ExactNumeric.LongIsExactNumeric
verifyCases(
- {
- def success[T](v: T) = Expected(Success(v), 1788, arithOpsCostDetails(SLong), 1788)
- Seq(
- ((Long.MinValue, -4677100190307931395L), Expected(new ArithmeticException("long overflow"))),
- ((Long.MinValue, -1L), Expected(new ArithmeticException("long overflow"))),
- ((Long.MinValue, 1L), Expected(new ArithmeticException("long overflow"))),
- ((-9223372036854775808L, 0L), Expected(new ArithmeticException("/ by zero"))),
- ((-5828066432064138816L, 9105034716270510411L), Expected(new ArithmeticException("long overflow"))),
- ((-4564956247298949325L, -1L), success(
- (-4564956247298949326L, (-4564956247298949324L, (4564956247298949325L, (4564956247298949325L, 0L))))
- )),
- ((-1499553565058783253L, -3237683216870282569L), Expected(new ArithmeticException("long overflow"))),
- ((-1368457031689886112L, 9223372036854775807L), Expected(new ArithmeticException("long overflow"))),
- ((-1L, -4354407074688367443L), success((-4354407074688367444L, (4354407074688367442L, (4354407074688367443L, (0L, -1L)))))),
- ((-1L, -1L), success((-2L, (0L, (1L, (1L, 0L)))))),
- ((-1L, 5665019549505434695L), success((5665019549505434694L, (-5665019549505434696L, (-5665019549505434695L, (0L, -1L)))))),
- ((0L, -1L), success((-1L, (1L, (0L, (0L, 0L)))))),
- ((0L, 0L), Expected(new ArithmeticException("/ by zero"))),
- ((0L, 2112386634269044172L), success((2112386634269044172L, (-2112386634269044172L, (0L, (0L, 0L)))))),
- ((2254604056782701370L, -5878231674026236574L), Expected(new ArithmeticException("long overflow"))),
- ((2903872550238813643L, 1L), success(
- (2903872550238813644L, (2903872550238813642L, (2903872550238813643L, (2903872550238813643L, 0L))))
- )),
- ((5091129735284641762L, -427673944382373638L), Expected(new ArithmeticException("long overflow"))),
- ((6029085020194630780L, 2261786144956037939L), Expected(new ArithmeticException("long overflow"))),
- ((8126382074515995418L, -4746652047588907829L), Expected(new ArithmeticException("long overflow"))),
- ((Long.MaxValue, 1L), Expected(new ArithmeticException("long overflow"))),
- ((Long.MaxValue, -1L), Expected(new ArithmeticException("long overflow")))
- )
- },
- existingFeature(
- { (x: (Long, Long)) =>
- val a = x._1; val b = x._2
- val plus = n.plus(a, b)
- val minus = n.minus(a, b)
- val mul = n.times(a, b)
- val div = a / b
- val mod = a % b
- (plus, (minus, (mul, (div, mod))))
+ {
+ def success[T](v: T) = Expected(Success(v), 1788, arithOpsCostDetails(SLong), 1788, Seq.fill(4)(2116))
+ Seq(
+ ((Long.MinValue, -4677100190307931395L), Expected(new ArithmeticException("long overflow"))),
+ ((Long.MinValue, -1L), Expected(new ArithmeticException("long overflow"))),
+ ((Long.MinValue, 1L), Expected(new ArithmeticException("long overflow"))),
+ ((-9223372036854775808L, 0L), Expected(new ArithmeticException("/ by zero"))),
+ ((-5828066432064138816L, 9105034716270510411L), Expected(new ArithmeticException("long overflow"))),
+ ((-4564956247298949325L, -1L), success(
+ (-4564956247298949326L, (-4564956247298949324L, (4564956247298949325L, (4564956247298949325L, 0L))))
+ )),
+ ((-1499553565058783253L, -3237683216870282569L), Expected(new ArithmeticException("long overflow"))),
+ ((-1368457031689886112L, 9223372036854775807L), Expected(new ArithmeticException("long overflow"))),
+ ((-1L, -4354407074688367443L), success((-4354407074688367444L, (4354407074688367442L, (4354407074688367443L, (0L, -1L)))))),
+ ((-1L, -1L), success((-2L, (0L, (1L, (1L, 0L)))))),
+ ((-1L, 5665019549505434695L), success((5665019549505434694L, (-5665019549505434696L, (-5665019549505434695L, (0L, -1L)))))),
+ ((0L, -1L), success((-1L, (1L, (0L, (0L, 0L)))))),
+ ((0L, 0L), Expected(new ArithmeticException("/ by zero"))),
+ ((0L, 2112386634269044172L), success((2112386634269044172L, (-2112386634269044172L, (0L, (0L, 0L)))))),
+ ((2254604056782701370L, -5878231674026236574L), Expected(new ArithmeticException("long overflow"))),
+ ((2903872550238813643L, 1L), success(
+ (2903872550238813644L, (2903872550238813642L, (2903872550238813643L, (2903872550238813643L, 0L))))
+ )),
+ ((5091129735284641762L, -427673944382373638L), Expected(new ArithmeticException("long overflow"))),
+ ((6029085020194630780L, 2261786144956037939L), Expected(new ArithmeticException("long overflow"))),
+ ((8126382074515995418L, -4746652047588907829L), Expected(new ArithmeticException("long overflow"))),
+ ((Long.MaxValue, 1L), Expected(new ArithmeticException("long overflow"))),
+ ((Long.MaxValue, -1L), Expected(new ArithmeticException("long overflow")))
+ )
},
- """{ (x: (Long, Long)) =>
- | val a = x._1; val b = x._2
- | val plus = a + b
- | val minus = a - b
- | val mul = a * b
- | val div = a / b
- | val mod = a % b
- | (plus, (minus, (mul, (div, mod))))
- |}""".stripMargin,
- FuncValue(
- Vector((1, STuple(Vector(SLong, SLong)))),
- BlockValue(
- Vector(
- ValDef(
- 3,
- List(),
- SelectField.typed[LongValue](ValUse(1, STuple(Vector(SLong, SLong))), 1.toByte)
- ),
- ValDef(
- 4,
- List(),
- SelectField.typed[LongValue](ValUse(1, STuple(Vector(SLong, SLong))), 2.toByte)
- )
- ),
- Tuple(
+ existingFeature(
+ { (x: (Long, Long)) =>
+ val a = x._1;
+ val b = x._2
+ val plus = n.plus(a, b)
+ val minus = n.minus(a, b)
+ val mul = n.times(a, b)
+ val div = a / b
+ val mod = a % b
+ (plus, (minus, (mul, (div, mod))))
+ },
+ """{ (x: (Long, Long)) =>
+ | val a = x._1; val b = x._2
+ | val plus = a + b
+ | val minus = a - b
+ | val mul = a * b
+ | val div = a / b
+ | val mod = a % b
+ | (plus, (minus, (mul, (div, mod))))
+ |}""".stripMargin,
+ FuncValue(
+ Vector((1, STuple(Vector(SLong, SLong)))),
+ BlockValue(
Vector(
- ArithOp(ValUse(3, SLong), ValUse(4, SLong), OpCode @@ (-102.toByte)),
- Tuple(
- Vector(
- ArithOp(ValUse(3, SLong), ValUse(4, SLong), OpCode @@ (-103.toByte)),
- Tuple(
- Vector(
- ArithOp(ValUse(3, SLong), ValUse(4, SLong), OpCode @@ (-100.toByte)),
- Tuple(
- Vector(
- ArithOp(ValUse(3, SLong), ValUse(4, SLong), OpCode @@ (-99.toByte)),
- ArithOp(ValUse(3, SLong), ValUse(4, SLong), OpCode @@ (-98.toByte))
+ ValDef(
+ 3,
+ List(),
+ SelectField.typed[LongValue](ValUse(1, STuple(Vector(SLong, SLong))), 1.toByte)
+ ),
+ ValDef(
+ 4,
+ List(),
+ SelectField.typed[LongValue](ValUse(1, STuple(Vector(SLong, SLong))), 2.toByte)
+ )
+ ),
+ Tuple(
+ Vector(
+ ArithOp(ValUse(3, SLong), ValUse(4, SLong), OpCode @@ (-102.toByte)),
+ Tuple(
+ Vector(
+ ArithOp(ValUse(3, SLong), ValUse(4, SLong), OpCode @@ (-103.toByte)),
+ Tuple(
+ Vector(
+ ArithOp(ValUse(3, SLong), ValUse(4, SLong), OpCode @@ (-100.toByte)),
+ Tuple(
+ Vector(
+ ArithOp(ValUse(3, SLong), ValUse(4, SLong), OpCode @@ (-99.toByte)),
+ ArithOp(ValUse(3, SLong), ValUse(4, SLong), OpCode @@ (-98.toByte))
+ )
)
)
)
@@ -1882,13 +1735,12 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
)
- )
- )))
+ )))
}
property("Long LT, GT, NEQ") {
val o = ExactOrdering.LongIsExactOrdering
- def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LT, SLong), 1768)
+ def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LT, SLong), 1768, Seq.fill(4)(2012))
val LT_cases: Seq[((Long, Long), Expected[Boolean])] = Seq(
(Long.MinValue, Long.MinValue) -> expect(false),
(Long.MinValue, (Long.MinValue + 1).toLong) -> expect(true),
@@ -1929,16 +1781,16 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyOp(LT_cases, "<", LT.apply)(_ < _)
verifyOp(
- swapArgs(LT_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GT, SLong)),
+ swapArgs(LT_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GT, SLong), expectedV3Costs = Seq.fill(4)(2012)),
">", GT.apply)(_ > _)
- val neqCases = newCasesFrom2(LT_cases.map(_._1))(_ != _, cost = 1766, newCostDetails = costNEQ(constNeqCost))
+ val neqCases = newCasesFrom3(LT_cases.map(_._1))(_ != _, cost = 1766, newCostDetails = costNEQ(constNeqCost), Seq.fill(4)(2010))
verifyOp(neqCases, "!=", NEQ.apply)(_ != _)
}
property("Long LE, GE") {
val o = ExactOrdering.LongIsExactOrdering
- def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LE, SLong), 1768)
+ def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LE, SLong), 1768, Seq.fill(4)(2012))
val LE_cases: Seq[((Long, Long), Expected[Boolean])] = Seq(
(Long.MinValue, Long.MinValue) -> expect(true),
(Long.MinValue, (Long.MinValue + 1).toLong) -> expect(true),
@@ -1980,36 +1832,14 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyOp(LE_cases, "<=", LE.apply)(_ <= _)
verifyOp(
- swapArgs(LE_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GE, SLong)),
+ swapArgs(LE_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GE, SLong), expectedV3Costs = Seq.fill(4)(2012)),
">=", 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(
{
- def success(v: BigInt) = Expected(Success(v), 1764, TracedCost(traceBase), 1764)
+ def success(v: BigInt) = Expected(Success(v), 1764, TracedCost(traceBase), 1764, Seq.fill(4)(1994))
Seq(
(CBigInt(new BigInteger("-85102d7f884ca0e8f56193b46133acaf7e4681e1757d03f191ae4f445c8e0", 16)), success(
CBigInt(new BigInteger("-85102d7f884ca0e8f56193b46133acaf7e4681e1757d03f191ae4f445c8e0", 16))
@@ -2030,11 +1860,11 @@ class SigmaDslSpecification extends SigmaDslTesting
val n = NumericOps.BigIntIsExactIntegral
verifyCases(
- {
- def success(v: (BigInt, (BigInt, (BigInt, (BigInt, BigInt))))) =
- Expected(Success(v), 1793, arithOpsCostDetails(SBigInt), 1793)
- Seq(
- ((CBigInt(new BigInteger("-8683d1cd99d5fcf0e6eff6295c285c36526190e13dbde008c49e5ae6fddc1c", 16)),
+ {
+ def success(v: (BigInt, (BigInt, (BigInt, (BigInt, BigInt))))) =
+ Expected(Success(v), 1793, arithOpsCostDetails(SBigInt), 1793, Seq.fill(4)(2121))
+ Seq(
+ ((CBigInt(new BigInteger("-8683d1cd99d5fcf0e6eff6295c285c36526190e13dbde008c49e5ae6fddc1c", 16)),
CBigInt(new BigInteger("-2ef55db3f245feddacf0182e299dd", 16))),
Expected(new ArithmeticException("BigInteger out of 256 bit range"))),
@@ -2156,8 +1986,7 @@ class SigmaDslSpecification extends SigmaDslTesting
property("BigInt LT, GT, NEQ") {
val o = NumericOps.BigIntIsExactOrdering
- def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LT, SBigInt), 1768)
-
+ def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LT, SBigInt), 1768, Seq.fill(4)(2012))
val LT_cases: Seq[((BigInt, BigInt), Expected[Boolean])] = Seq(
(BigIntMinValue, BigIntMinValue) -> expect(false),
(BigIntMinValue, BigIntMinValue.add(1.toBigInt)) -> expect(true),
@@ -2200,11 +2029,11 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyOp(LT_cases, "<", LT.apply)(o.lt(_, _))
verifyOp(
- swapArgs(LT_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GT, SBigInt)),
+ swapArgs(LT_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GT, SBigInt), expectedV3Costs = Seq.fill(4)(2012)),
">", GT.apply)(o.gt(_, _))
val constBigIntCost = Array[CostItem](FixedCostItem(NamedDesc("EQ_BigInt"), FixedCost(JitCost(5))))
- val neqCases = newCasesFrom2(LT_cases.map(_._1))(_ != _, cost = 1766, newCostDetails = costNEQ(constBigIntCost))
+ val neqCases = newCasesFrom3(LT_cases.map(_._1))(_ != _, cost = 1766, newCostDetails = costNEQ(constBigIntCost), expectedV3Costs = Seq.fill(4)(2010))
verifyOp(neqCases, "!=", NEQ.apply)(_ != _)
}
@@ -2215,8 +2044,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val BigIntMaxValue = CBigInt(new BigInteger("7F" + "ff" * 31, 16))
val BigIntOverlimit = CBigInt(new BigInteger("7F" + "ff" * 33, 16))
- def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LE, SBigInt), 1768)
-
+ def expect(v: Boolean) = Expected(Success(v), 1768, binaryRelationCostDetails(LE, SBigInt), 1768, Seq.fill(4)(2012))
val LE_cases: Seq[((BigInt, BigInt), Expected[Boolean])] = Seq(
(BigIntMinValue, BigIntMinValue) -> expect(true),
(BigIntMinValue, BigIntMinValue.add(1.toBigInt)) -> expect(true),
@@ -2260,74 +2088,21 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyOp(LE_cases, "<=", LE.apply)(o.lteq(_, _))
verifyOp(
- swapArgs(LE_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GE, SBigInt)),
+ swapArgs(LE_cases, cost = 1768, newCostDetails = binaryRelationCostDetails(GE, SBigInt), expectedV3Costs = Seq.fill(4)(2012)),
">=", 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)
*/
def verifyNeq[A: Ordering: Arbitrary: RType]
- (x: A, y: A, cost: Int, neqCost: Seq[CostItem] = ArraySeq.empty, newCost: Int)
+ (x: A, y: A, cost: Int, neqCost: Seq[CostItem] = ArraySeq.empty, newCost: Int, expectedV3Costs: Seq[Int])
(copy: A => A, generateCases: Boolean = true)
(implicit sampled: Sampled[(A, A)], evalSettings: EvalSettings) = {
val copied_x = copy(x)
val newCostDetails = if (neqCost.isEmpty) CostDetails.ZeroCost else costNEQ(neqCost)
- def expected(v: Boolean) = Expected(Success(v), cost, newCostDetails, newCost)
+ def expected(v: Boolean) = Expected(Success(v), cost, newCostDetails, newCost, expectedV3Costs)
def expectedNoCost(v: Boolean) = new Expected(ExpectedResult(Success(v), None))
verifyOp(Seq(
(x, y) -> expected(true), // check cost only for this test case, because the trace depends in x and y
@@ -2340,11 +2115,11 @@ class SigmaDslSpecification extends SigmaDslTesting
}
property("NEQ of pre-defined types") {
- verifyNeq(ge1, ge2, 1783, Array[CostItem](FixedCostItem(NamedDesc("EQ_GroupElement"), FixedCost(JitCost(172)))), 1783)(_.asInstanceOf[CGroupElement].copy())
- verifyNeq(t1, t2, 1767, Array[CostItem](FixedCostItem(NamedDesc("EQ_AvlTree"), FixedCost(JitCost(6)))), 1767)(_.asInstanceOf[CAvlTree].copy())
- verifyNeq(b1, b2, 1767, Array[CostItem](), 1767)(_.asInstanceOf[CBox].copy())
- verifyNeq(preH1, preH2, 1766, Array[CostItem](FixedCostItem(NamedDesc("EQ_PreHeader"), FixedCost(JitCost(4)))), 1766)(_.asInstanceOf[CPreHeader].copy())
- verifyNeq(h1, h2, 1767, Array[CostItem](FixedCostItem(NamedDesc("EQ_Header"), FixedCost(JitCost(6)))), 1767)(_.asInstanceOf[CHeader].copy())
+ verifyNeq(ge1, ge2, 1783, Array[CostItem](FixedCostItem(NamedDesc("EQ_GroupElement"), FixedCost(JitCost(172)))), 1783, Seq.fill(4)(2027))(_.asInstanceOf[CGroupElement].copy())
+ verifyNeq(t1, t2, 1767, Array[CostItem](FixedCostItem(NamedDesc("EQ_AvlTree"), FixedCost(JitCost(6)))), 1767, Seq.fill(4)(2019))(_.asInstanceOf[CAvlTree].copy())
+ verifyNeq(b1, b2, 1767, Array[CostItem](), 1767, Seq.fill(4)(2019))(_.asInstanceOf[CBox].copy())
+ verifyNeq(preH1, preH2, 1766, Array[CostItem](FixedCostItem(NamedDesc("EQ_PreHeader"), FixedCost(JitCost(4)))), 1766, Seq.fill(4)(2018))(_.asInstanceOf[CPreHeader].copy())
+ verifyNeq(h1, h2, 1767, Array[CostItem](FixedCostItem(NamedDesc("EQ_Header"), FixedCost(JitCost(6)))), 1767, Seq.fill(4)(2019))(_.asInstanceOf[CHeader].copy())
}
property("NEQ of tuples of numerics") {
@@ -2352,14 +2127,14 @@ class SigmaDslSpecification extends SigmaDslTesting
FixedCostItem(NamedDesc("EQ_Tuple"), FixedCost(JitCost(4))),
FixedCostItem(NamedDesc("EQ_Prim"), FixedCost(JitCost(3)))
)
- verifyNeq((0.toByte, 1.toByte), (1.toByte, 1.toByte), 1767, tuplesNeqCost, 1767)(_.copy())
- verifyNeq((0.toShort, 1.toByte), (1.toShort, 1.toByte), 1767, tuplesNeqCost, 1767)(_.copy())
- verifyNeq((0, 1.toByte), (1, 1.toByte), 1767, tuplesNeqCost, 1767)(_.copy())
- verifyNeq((0.toLong, 1.toByte), (1.toLong, 1.toByte), 1767, tuplesNeqCost, 1767)(_.copy())
+ verifyNeq((0.toByte, 1.toByte), (1.toByte, 1.toByte), 1767, tuplesNeqCost, 1767, Seq.fill(4)(2019))(_.copy())
+ verifyNeq((0.toShort, 1.toByte), (1.toShort, 1.toByte), 1767, tuplesNeqCost, 1767, Seq.fill(4)(2029))(_.copy())
+ verifyNeq((0, 1.toByte), (1, 1.toByte), 1767, tuplesNeqCost, 1767, Seq.fill(4)(2029))(_.copy())
+ verifyNeq((0.toLong, 1.toByte), (1.toLong, 1.toByte), 1767, tuplesNeqCost, 1767, Seq.fill(4)(2029))(_.copy())
verifyNeq((0.toBigInt, 1.toByte), (1.toBigInt, 1.toByte), 1767, Array(
FixedCostItem(NamedDesc("EQ_Tuple"), FixedCost(JitCost(4))),
FixedCostItem(NamedDesc("EQ_BigInt"), FixedCost(JitCost(5)))
- ), 1767)(_.copy())
+ ), 1767, Seq.fill(4)(2029))(_.copy())
}
property("NEQ of tuples of pre-defined types") {
@@ -2368,30 +2143,29 @@ class SigmaDslSpecification extends SigmaDslTesting
FixedCostItem(NamedDesc("EQ_GroupElement"), FixedCost(JitCost(172))),
FixedCostItem(NamedDesc("EQ_GroupElement"), FixedCost(JitCost(172)))
)
- verifyNeq((ge1, ge1), (ge1, ge2), 1801, groupNeqCost, 1801)(_.copy())
+ verifyNeq((ge1, ge1), (ge1, ge2), 1801, groupNeqCost, 1801, Seq.fill(4)(2053))(_.copy())
val treeNeqCost = Array(
FixedCostItem(NamedDesc("EQ_Tuple"), FixedCost(JitCost(4))),
FixedCostItem(NamedDesc("EQ_AvlTree"), FixedCost(JitCost(6))),
FixedCostItem(NamedDesc("EQ_AvlTree"), FixedCost(JitCost(6)))
)
- verifyNeq((t1, t1), (t1, t2), 1768, treeNeqCost, 1768)(_.copy())
-
- verifyNeq((b1, b1), (b1, b2), 1768, Array[CostItem](), 1768)(_.copy())
+ verifyNeq((t1, t1), (t1, t2), 1768, treeNeqCost, 1768, Seq.fill(4)(2038))(_.copy())
+ verifyNeq((b1, b1), (b1, b2), 1768, Array[CostItem](), 1768, Seq.fill(4)(2038))(_.copy())
val preHeaderNeqCost = Array(
FixedCostItem(NamedDesc("EQ_Tuple"), FixedCost(JitCost(4))),
FixedCostItem(NamedDesc("EQ_PreHeader"), FixedCost(JitCost(4))),
FixedCostItem(NamedDesc("EQ_PreHeader"), FixedCost(JitCost(4)))
)
- verifyNeq((preH1, preH1), (preH1, preH2), 1767, preHeaderNeqCost, 1767)(_.copy())
+ verifyNeq((preH1, preH1), (preH1, preH2), 1767, preHeaderNeqCost, 1767, Seq.fill(4)(2037))(_.copy())
val headerNeqCost = Array(
FixedCostItem(NamedDesc("EQ_Tuple"), FixedCost(JitCost(4))),
FixedCostItem(NamedDesc("EQ_Header"), FixedCost(JitCost(6))),
FixedCostItem(NamedDesc("EQ_Header"), FixedCost(JitCost(6)))
)
- verifyNeq((h1, h1), (h1, h2), 1768, headerNeqCost, 1768)(_.copy())
+ verifyNeq((h1, h1), (h1, h2), 1768, headerNeqCost, 1768, Seq.fill(4)(2038))(_.copy())
}
property("NEQ of nested tuples") {
@@ -2475,15 +2249,15 @@ class SigmaDslSpecification extends SigmaDslTesting
FixedCostItem(NamedDesc("EQ_Header"), FixedCost(JitCost(6))),
FixedCostItem(NamedDesc("EQ_Header"), FixedCost(JitCost(6)))
)
- verifyNeq((ge1, (t1, t1)), (ge1, (t1, t2)), 1785, nestedTuplesNeqCost1, 1785)(_.copy())
- verifyNeq((ge1, (t1, (b1, b1))), (ge1, (t1, (b1, b2))), 1786, nestedTuplesNeqCost2, 1786)(_.copy())
- verifyNeq((ge1, (t1, (b1, (preH1, preH1)))), (ge1, (t1, (b1, (preH1, preH2)))), 1787, nestedTuplesNeqCost3, 1787)(_.copy())
- verifyNeq((ge1, (t1, (b1, (preH1, (h1, h1))))), (ge1, (t1, (b1, (preH1, (h1, h2))))), 1788, nestedTuplesNeqCost4, 1788)(_.copy())
+ verifyNeq((ge1, (t1, t1)), (ge1, (t1, t2)), 1785, nestedTuplesNeqCost1, 1785, Seq.fill(4)(2063))(_.copy())
+ verifyNeq((ge1, (t1, (b1, b1))), (ge1, (t1, (b1, b2))), 1786, nestedTuplesNeqCost2, 1786, Seq.fill(4)(2080))(_.copy())
+ verifyNeq((ge1, (t1, (b1, (preH1, preH1)))), (ge1, (t1, (b1, (preH1, preH2)))), 1787, nestedTuplesNeqCost3, 1787, Seq.fill(4)(2097))(_.copy())
+ verifyNeq((ge1, (t1, (b1, (preH1, (h1, h1))))), (ge1, (t1, (b1, (preH1, (h1, h2))))), 1788, nestedTuplesNeqCost4, 1788, Seq.fill(4)(2114))(_.copy())
- verifyNeq(((ge1, t1), t1), ((ge1, t1), t2), 1785, nestedTuplesNeqCost5, 1785)(_.copy())
- verifyNeq((((ge1, t1), b1), b1), (((ge1, t1), b1), b2), 1786, nestedTuplesNeqCost6, 1786)(_.copy())
- verifyNeq((((ge1, t1), b1), (preH1, preH1)), (((ge1, t1), b1), (preH1, preH2)), 1787, nestedTuplesNeqCost7, 1787)(_.copy())
- verifyNeq((((ge1, t1), b1), (preH1, (h1, h1))), (((ge1, t1), b1), (preH1, (h1, h2))), 1788, nestedTuplesNeqCost8, 1788)(_.copy())
+ verifyNeq(((ge1, t1), t1), ((ge1, t1), t2), 1785, nestedTuplesNeqCost5, 1785, Seq.fill(4)(2063))(_.copy())
+ verifyNeq((((ge1, t1), b1), b1), (((ge1, t1), b1), b2), 1786, nestedTuplesNeqCost6, 1786, Seq.fill(4)(2080))(_.copy())
+ verifyNeq((((ge1, t1), b1), (preH1, preH1)), (((ge1, t1), b1), (preH1, preH2)), 1787, nestedTuplesNeqCost7, 1787, Seq.fill(4)(2097))(_.copy())
+ verifyNeq((((ge1, t1), b1), (preH1, (h1, h1))), (((ge1, t1), b1), (preH1, (h1, h2))), 1788, nestedTuplesNeqCost8, 1788, Seq.fill(4)(2114))(_.copy())
}
property("NEQ of collections of pre-defined types") {
@@ -2495,63 +2269,71 @@ class SigmaDslSpecification extends SigmaDslTesting
ast.SeqCostItem(NamedDesc("EQ_COA_Box"), PerItemCost(JitCost(15), JitCost(5), 1), 0)
)
implicit val evalSettings = suite.evalSettings.copy(isMeasureOperationTime = false)
- verifyNeq(Coll[Byte](), Coll(1.toByte), 1766, collNeqCost1, 1766)(cloneColl(_))
+ verifyNeq(Coll[Byte](), Coll(1.toByte), 1766, collNeqCost1, 1766, Seq.fill(4)(2018))(cloneColl(_))
verifyNeq(Coll[Byte](0, 1), Coll(1.toByte, 1.toByte), 1768,
Array(
FixedCostItem(NamedDesc("MatchType"), FixedCost(JitCost(1))),
ast.SeqCostItem(NamedDesc("EQ_COA_Byte"), PerItemCost(JitCost(15), JitCost(2), 128), 1)),
- 1768
+ 1768,
+ Seq.fill(4)(2020)
)(cloneColl(_))
- verifyNeq(Coll[Short](), Coll(1.toShort), 1766, collNeqCost1, 1766)(cloneColl(_))
+ verifyNeq(Coll[Short](), Coll(1.toShort), 1766, collNeqCost1, 1766, Seq.fill(4)(2018))(cloneColl(_))
verifyNeq(Coll[Short](0), Coll(1.toShort), 1768,
Array(
FixedCostItem(NamedDesc("MatchType"), FixedCost(JitCost(1))),
ast.SeqCostItem(NamedDesc("EQ_COA_Short"), PerItemCost(JitCost(15), JitCost(2), 96), 1)),
- 1768
+ 1768,
+ Seq.fill(4)(2020)
)(cloneColl(_))
- verifyNeq(Coll[Int](), Coll(1), 1766, collNeqCost1, 1766)(cloneColl(_))
+ verifyNeq(Coll[Int](), Coll(1), 1766, collNeqCost1, 1766, Seq.fill(4)(2018))(cloneColl(_))
verifyNeq(Coll[Int](0), Coll(1), 1768,
Array(
FixedCostItem(NamedDesc("MatchType"), FixedCost(JitCost(1))),
ast.SeqCostItem(NamedDesc("EQ_COA_Int"), PerItemCost(JitCost(15), JitCost(2), 64), 1)),
- 1768
+ 1768,
+ Seq.fill(4)(2020)
)(cloneColl(_))
- verifyNeq(Coll[Long](), Coll(1.toLong), 1766, collNeqCost1, 1766)(cloneColl(_))
+ verifyNeq(Coll[Long](), Coll(1.toLong), 1766, collNeqCost1, 1766, Seq.fill(4)(2018))(cloneColl(_))
verifyNeq(Coll[Long](0), Coll(1.toLong), 1768,
Array(
FixedCostItem(NamedDesc("MatchType"), FixedCost(JitCost(1))),
ast.SeqCostItem(NamedDesc("EQ_COA_Long"), PerItemCost(JitCost(15), JitCost(2), 48), 1)),
- 1768
+ 1768,
+ Seq.fill(4)(2020)
)(cloneColl(_))
prepareSamples[Coll[BigInt]]
- verifyNeq(Coll[BigInt](), Coll(1.toBigInt), 1766, collNeqCost1, 1766)(cloneColl(_))
+ verifyNeq(Coll[BigInt](), Coll(1.toBigInt), 1766, collNeqCost1, 1766, Seq.fill(4)(2018))(cloneColl(_))
verifyNeq(Coll[BigInt](0.toBigInt), Coll(1.toBigInt), 1768,
Array(
FixedCostItem(NamedDesc("MatchType"), FixedCost(JitCost(1))),
ast.SeqCostItem(NamedDesc("EQ_COA_BigInt"), PerItemCost(JitCost(15), JitCost(7), 5), 1)),
- 1768
+ 1768,
+ Seq.fill(4)(2020)
)(cloneColl(_))
prepareSamples[Coll[GroupElement]]
- verifyNeq(Coll[GroupElement](), Coll(ge1), 1766, collNeqCost1, 1766)(cloneColl(_))
+ verifyNeq(Coll[GroupElement](), Coll(ge1), 1766, collNeqCost1, 1766, Seq.fill(4)(2018))(cloneColl(_))
verifyNeq(Coll[GroupElement](ge1), Coll(ge2), 1768,
Array(
FixedCostItem(NamedDesc("MatchType"), FixedCost(JitCost(1))),
ast.SeqCostItem(NamedDesc("EQ_COA_GroupElement"), PerItemCost(JitCost(15), JitCost(5), 1), 1)),
- 1768
+ 1768,
+ Seq.fill(4)(2020)
)(cloneColl(_))
prepareSamples[Coll[AvlTree]]
- verifyNeq(Coll[AvlTree](), Coll(t1), 1766, collNeqCost1, 1766)(cloneColl(_))
+ verifyNeq(Coll[AvlTree](), Coll(t1), 1766, collNeqCost1, 1766, Seq.fill(4)(2028))(cloneColl(_))
+
verifyNeq(Coll[AvlTree](t1), Coll(t2), 1768,
Array(
FixedCostItem(NamedDesc("MatchType"), FixedCost(JitCost(1))),
ast.SeqCostItem(NamedDesc("EQ_COA_AvlTree"), PerItemCost(JitCost(15), JitCost(5), 2), 1)),
- 1768
+ 1768,
+ Seq.fill(4)(2030)
)(cloneColl(_))
{ // since SBox.isConstantSize = false, the cost is different among cases
@@ -2560,38 +2342,40 @@ class SigmaDslSpecification extends SigmaDslTesting
val y = Coll(b1)
val copied_x = cloneColl(x)
verifyOp(Seq(
- (x, x) -> Expected(Success(false), 1768, costNEQ(collNeqCost2), 1768),
- (x, copied_x) -> Expected(Success(false), 1768, costNEQ(collNeqCost2), 1768),
- (copied_x, x) -> Expected(Success(false), 1768, costNEQ(collNeqCost2), 1768),
- (x, y) -> Expected(Success(true), 1766, costNEQ(collNeqCost1), 1766),
- (y, x) -> Expected(Success(true), 1766, costNEQ(collNeqCost1), 1766)
- ),
+ (x, x) -> Expected(Success(false), 1768, costNEQ(collNeqCost2), 1768, Seq.fill(4)(2030)),
+ (x, copied_x) -> Expected(Success(false), 1768, costNEQ(collNeqCost2), 1768, Seq.fill(4)(2030)),
+ (copied_x, x) -> Expected(Success(false), 1768, costNEQ(collNeqCost2), 1768, Seq.fill(4)(2030)),
+ (x, y) -> Expected(Success(true), 1766, costNEQ(collNeqCost1), 1766, Seq.fill(4)(2028)),
+ (y, x) -> Expected(Success(true), 1766, costNEQ(collNeqCost1), 1766, Seq.fill(4)(2028))
+ ),
"!=", NEQ.apply)(_ != _, generateCases = false)
verifyNeq(Coll[Box](b1), Coll(b2), 1768,
Array(
FixedCostItem(NamedDesc("MatchType"), FixedCost(JitCost(1))),
ast.SeqCostItem(NamedDesc("EQ_COA_Box"), PerItemCost(JitCost(15), JitCost(5), 1), 1)),
- 1768
+ 1768,
+ Seq.fill(4)(2030)
)(cloneColl(_), generateCases = false)
}
prepareSamples[Coll[PreHeader]]
- verifyNeq(Coll[PreHeader](), Coll(preH1), 1766, collNeqCost1, 1766)(cloneColl(_))
+ verifyNeq(Coll[PreHeader](), Coll(preH1), 1766, collNeqCost1, 1766, Seq.fill(4)(2028))(cloneColl(_))
verifyNeq(Coll[PreHeader](preH1), Coll(preH2), 1768,
Array(
FixedCostItem(NamedDesc("MatchType"), FixedCost(JitCost(1))),
ast.SeqCostItem(NamedDesc("EQ_COA_PreHeader"), PerItemCost(JitCost(15), JitCost(3), 1), 1)),
- 1768
+ 1768,
+ Seq.fill(4)(2030)
)(cloneColl(_))
prepareSamples[Coll[Header]]
- verifyNeq(Coll[Header](), Coll(h1), 1766, collNeqCost1, 1766)(cloneColl(_))
+ verifyNeq(Coll[Header](), Coll(h1), 1766, collNeqCost1, 1766, Seq.fill(4)(2028))(cloneColl(_))
verifyNeq(Coll[Header](h1), Coll(h2), 1768,
Array(
FixedCostItem(NamedDesc("MatchType"), FixedCost(JitCost(1))),
ast.SeqCostItem(NamedDesc("EQ_COA_Header"), PerItemCost(JitCost(15), JitCost(5), 1), 1)),
- 1768
+ 1768, Seq.fill(4)(2030)
)(cloneColl(_))
}
@@ -2615,10 +2399,10 @@ class SigmaDslSpecification extends SigmaDslTesting
ast.SeqCostItem(NamedDesc("EQ_COA_Int"), PerItemCost(JitCost(15), JitCost(2), 64), 1),
ast.SeqCostItem(NamedDesc("EQ_Coll"), PerItemCost(JitCost(10), JitCost(2), 1), 1)
)
- verifyNeq(Coll[Coll[Int]](), Coll(Coll[Int]()), 1766, nestedNeq1, 1766)(cloneColl(_))
- verifyNeq(Coll(Coll[Int]()), Coll(Coll[Int](1)), 1767, nestedNeq2, 1767)(cloneColl(_))
- verifyNeq(Coll(Coll[Int](1)), Coll(Coll[Int](2)), 1769, nestedNeq3, 1769)(cloneColl(_))
- verifyNeq(Coll(Coll[Int](1)), Coll(Coll[Int](1, 2)), 1767, nestedNeq2, 1767)(cloneColl(_))
+ verifyNeq(Coll[Coll[Int]](), Coll(Coll[Int]()), 1766, nestedNeq1, 1766, Seq.fill(4)(2018))(cloneColl(_))
+ verifyNeq(Coll(Coll[Int]()), Coll(Coll[Int](1)), 1767, nestedNeq2, 1767, Seq.fill(4)(2019))(cloneColl(_))
+ verifyNeq(Coll(Coll[Int](1)), Coll(Coll[Int](2)), 1769, nestedNeq3, 1769, Seq.fill(4)(2021))(cloneColl(_))
+ verifyNeq(Coll(Coll[Int](1)), Coll(Coll[Int](1, 2)), 1767, nestedNeq2, 1767, Seq.fill(4)(2019))(cloneColl(_))
prepareSamples[Coll[(Int, BigInt)]]
prepareSamples[Coll[Coll[(Int, BigInt)]]]
@@ -2661,8 +2445,8 @@ class SigmaDslSpecification extends SigmaDslTesting
ast.SeqCostItem(NamedDesc("EQ_Coll"), PerItemCost(JitCost(10), JitCost(2), 1), 1),
ast.SeqCostItem(NamedDesc("EQ_Coll"), PerItemCost(JitCost(10), JitCost(2), 1), 1)
)
- verifyNeq(Coll(Coll((1, 10.toBigInt))), Coll(Coll((1, 11.toBigInt))), 1770, nestedNeq4, 1770)(cloneColl(_))
- verifyNeq(Coll(Coll(Coll((1, 10.toBigInt)))), Coll(Coll(Coll((1, 11.toBigInt)))), 1771, nestedNeq5, 1771)(cloneColl(_))
+ verifyNeq(Coll(Coll((1, 10.toBigInt))), Coll(Coll((1, 11.toBigInt))), 1770, nestedNeq4, 1770, Seq.fill(4)(2048))(cloneColl(_))
+ verifyNeq(Coll(Coll(Coll((1, 10.toBigInt)))), Coll(Coll(Coll((1, 11.toBigInt)))), 1771, nestedNeq5, 1771, Seq.fill(4)(2057))(cloneColl(_))
verifyNeq(
(Coll(
(Coll(
@@ -2676,14 +2460,15 @@ class SigmaDslSpecification extends SigmaDslTesting
), preH1),
1774,
nestedNeq6,
- 1774
+ 1774,
+ Seq.fill(4)(2100)
)(x => (cloneColl(x._1), x._2))
}
property("GroupElement.getEncoded equivalence") {
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1790, methodCostDetails(SGroupElementMethods.GetEncodedMethod, 250), 1790)
+ def success[T](v: T) = Expected(Success(v), 1790, methodCostDetails(SGroupElementMethods.GetEncodedMethod, 250), 1790, Seq.fill(4)(2026))
Seq(
(ge1, success(Helpers.decodeBytes(ge1str))),
(ge2, success(Helpers.decodeBytes(ge2str))),
@@ -2714,7 +2499,7 @@ class SigmaDslSpecification extends SigmaDslTesting
FixedCostItem(NamedDesc("EQ_GroupElement"), FixedCost(JitCost(172)))
)
)
- def success[T](v: T) = Expected(Success(v), 1837, costDetails, 1837)
+ def success[T](v: T) = Expected(Success(v), 1837, costDetails, 1837, Seq.fill(4)(2081))
Seq(
(ge1, success(true)),
(ge2, success(true)),
@@ -2744,7 +2529,7 @@ class SigmaDslSpecification extends SigmaDslTesting
property("GroupElement.negate equivalence") {
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1785, methodCostDetails(SGroupElementMethods.NegateMethod, 45), 1785)
+ def success[T](v: T) = Expected(Success(v), 1785, methodCostDetails(SGroupElementMethods.NegateMethod, 45), 1785, Seq.fill(4)(2021))
Seq(
(ge1, success(Helpers.decodeGroupElement("02358d53f01276211f92d0aefbd278805121d4ff6eb534b777af1ee8abae5b2056"))),
(ge2, success(Helpers.decodeGroupElement("03dba7b94b111f3894e2f9120b577da595ec7d58d488485adf73bf4e153af63575"))),
@@ -2762,8 +2547,9 @@ class SigmaDslSpecification extends SigmaDslTesting
}
property("GroupElement.exp equivalence") {
- def cases(cost: Int, details: CostDetails) = {
- def success[T](v: T) = Expected(Success(v), cost, details, cost)
+ def cases(cost: Int, details: CostDetails, expectedV3Costs: Seq[Int]) = {
+ def success[T](v: T) = Expected(Success(v), cost, details, cost, expectedV3Costs)
+
Seq(
((ge1, CBigInt(new BigInteger("-25c80b560dd7844e2efd10f80f7ee57d", 16))),
success(Helpers.decodeGroupElement("023a850181b7b73f92a5bbfa0bfc78f5bbb6ff00645ddde501037017e1a2251e2e"))),
@@ -2786,7 +2572,7 @@ class SigmaDslSpecification extends SigmaDslTesting
FixedCostItem(Exponentiate)
)
)
- verifyCases(cases(1873, costDetails),
+ verifyCases(cases(1873, costDetails, Seq.fill(4)(2121)),
existingFeature(
scalaFunc,
script,
@@ -2813,7 +2599,7 @@ class SigmaDslSpecification extends SigmaDslTesting
FixedCostItem(SGroupElementMethods.ExponentiateMethod, FixedCost(JitCost(900)))
)
)
- verifyCases(cases(1873, costDetails),
+ verifyCases(cases(1873, costDetails, Seq.fill(4)(2121)),
existingFeature(
scalaFunc,
script,
@@ -2860,7 +2646,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
)
- def success[T](v: T) = Expected(Success(v), 1787, costDetails, 1787)
+ def success[T](v: T) = Expected(Success(v), 1787, costDetails, 1787, Seq.fill(4)(2031))
Seq(
((ge1, Helpers.decodeGroupElement("03e132ca090614bd6c9f811e91f6daae61f16968a1e6c694ed65aacd1b1092320e")),
success(Helpers.decodeGroupElement("02bc48937b4a66f249a32dfb4d2efd0743dc88d46d770b8c5d39fd03325ba211df"))),
@@ -2923,7 +2709,7 @@ class SigmaDslSpecification extends SigmaDslTesting
}
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1767, methodCostDetails(SAvlTreeMethods.digestMethod, 15), 1767)
+ def success[T](v: T) = Expected(Success(v), 1767, methodCostDetails(SAvlTreeMethods.digestMethod, 15), 1767, Seq.fill(4)(2003))
Seq(
(t1, success(Helpers.decodeBytes("000183807f66b301530120ff7fc6bd6601ff01ff7f7d2bedbbffff00187fe89094"))),
(t2, success(Helpers.decodeBytes("ff000d937f80ffd731ed802d24358001ff8080ff71007f00ad37e0a7ae43fff95b"))),
@@ -2936,7 +2722,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1765, methodCostDetails(SAvlTreeMethods.enabledOperationsMethod, 15), 1765)
+ def success[T](v: T) = Expected(Success(v), 1765, methodCostDetails(SAvlTreeMethods.enabledOperationsMethod, 15), 1765, Seq.fill(4)(2001))
Seq(
(t1, success(6.toByte)),
(t2, success(0.toByte)),
@@ -2949,7 +2735,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1765, methodCostDetails(SAvlTreeMethods.keyLengthMethod, 15), 1765)
+ def success[T](v: T) = Expected(Success(v), 1765, methodCostDetails(SAvlTreeMethods.keyLengthMethod, 15), 1765, Seq.fill(4)(2001))
Seq(
(t1, success(1)),
(t2, success(32)),
@@ -2962,11 +2748,11 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T, newCost: Int) = Expected(Success(v), newCost, methodCostDetails(SAvlTreeMethods.valueLengthOptMethod, 15), newCost)
+ def success[T](v: T, newCost: Int, expectedV3Costs: Seq[Int]) = Expected(Success(v), newCost, methodCostDetails(SAvlTreeMethods.valueLengthOptMethod, 15), newCost, expectedV3Costs)
Seq(
- (t1, success(Some(1), 1766)),
- (t2, success(Some(64), 1766)),
- (t3, success(None, 1765))
+ (t1, success(Some(1), 1766, Seq.fill(4)(2002))),
+ (t2, success(Some(64), 1766, Seq.fill(4)(2002))),
+ (t3, success(None, 1765, Seq.fill(4)(2001)))
)
},
existingFeature((t: AvlTree) => t.valueLengthOpt,
@@ -2975,7 +2761,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1765, methodCostDetails(SAvlTreeMethods.isInsertAllowedMethod, 15), 1765)
+ def success[T](v: T) = Expected(Success(v), 1765, methodCostDetails(SAvlTreeMethods.isInsertAllowedMethod, 15), 1765, Seq.fill(4)(2001))
Seq(
(t1, success(false)),
(t2, success(false)),
@@ -2988,7 +2774,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1765, methodCostDetails(SAvlTreeMethods.isUpdateAllowedMethod, 15), 1765)
+ def success[T](v: T) = Expected(Success(v), 1765, methodCostDetails(SAvlTreeMethods.isUpdateAllowedMethod, 15), 1765, Seq.fill(4)(2001))
Seq(
(t1, success(true)),
(t2, success(false)),
@@ -3001,7 +2787,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1765, methodCostDetails(SAvlTreeMethods.isRemoveAllowedMethod, 15), 1765)
+ def success[T](v: T) = Expected(Success(v), 1765, methodCostDetails(SAvlTreeMethods.isRemoveAllowedMethod, 15), 1765, Seq.fill(4)(2001))
Seq(
(t1, success(true)),
(t2, success(false)),
@@ -3256,7 +3042,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
- getMany.checkExpected(input, Expected(Success(expRes), 1845, costDetails, 1845))
+ getMany.checkExpected(input, Expected(Success(expRes), 1845, costDetails, 1845, Seq.fill(4)(2139)))
}
val key = Colls.fromArray(Array[Byte](-16,-128,99,86,1,-128,-36,-83,109,72,-124,-114,1,-32,15,127,-30,125,127,1,-102,-53,-53,-128,-107,0,64,8,1,127,22,1))
@@ -3334,8 +3120,9 @@ class SigmaDslSpecification extends SigmaDslTesting
// positive test
{
val input = (tree, (key, proof))
- contains.checkExpected(input, Expected(Success(okContains), 1790, costDetails(105 + additionalDetails), 1790))
- get.checkExpected(input, Expected(Success(valueOpt), 1790 + additionalCost, costDetails(105 + additionalDetails), 1790 + additionalCost))
+ val expectedV3Costs: Seq[Int] = Seq.fill(4)(2082)
+ contains.checkExpected(input, Expected(Success(okContains), 1790, costDetails(105 + additionalDetails), 1790, expectedV3Costs))
+ get.checkExpected(input, Expected(Success(valueOpt), 1790 + additionalCost, costDetails(105 + additionalDetails), 1790 + additionalCost, expectedV3Costs.map(additionalCost + _)))
}
val keys = Colls.fromItems(key)
@@ -3343,14 +3130,15 @@ class SigmaDslSpecification extends SigmaDslTesting
{
val input = (tree, (keys, proof))
- getMany.checkExpected(input, Expected(Success(expRes), 1791 + additionalCost, costDetails(105 + additionalDetails), 1791 + additionalCost))
+ val expectedV3Costs: Seq[Int] = Seq.fill(4)(2085 + additionalCost)
+ getMany.checkExpected(input, Expected(Success(expRes), 1791 + additionalCost, costDetails(105 + additionalDetails), 1791 + additionalCost, expectedV3Costs))
}
{
val input = (tree, digest)
val (res, _) = updateDigest.checkEquality(input).getOrThrow
res.digest shouldBe digest
- updateDigest.checkExpected(input, Expected(Success(res), 1771, updateDigestCostDetails, 1771))
+ updateDigest.checkExpected(input, Expected(Success(res), 1771, updateDigestCostDetails, 1771, Seq.fill(4)(2029)))
}
val newOps = 1.toByte
@@ -3359,7 +3147,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val input = (tree, newOps)
val (res,_) = updateOperations.checkEquality(input).getOrThrow
res.enabledOperations shouldBe newOps
- updateOperations.checkExpected(input, Expected(Success(res), 1771, updateOperationsCostDetails, 1771))
+ updateOperations.checkExpected(input, Expected(Success(res), 1771, updateOperationsCostDetails, 1771, Seq.fill(4)(2025)))
}
// negative tests: invalid proof
@@ -3369,7 +3157,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val input = (tree, (key, invalidProof))
val (res, _) = contains.checkEquality(input).getOrThrow
res shouldBe false
- contains.checkExpected(input, Expected(Success(res), 1790, costDetails(105 + additionalDetails), 1790))
+ contains.checkExpected(input, Expected(Success(res), 1790, costDetails(105 + additionalDetails), 1790, Seq.fill(4)(2082)))
}
{
@@ -3522,7 +3310,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val input = (preInsertTree, (kvs, insertProof))
val (res, _) = insert.checkEquality(input).getOrThrow
res.isDefined shouldBe true
- insert.checkExpected(input, Expected(Success(res), 1796, costDetails2, 1796))
+ insert.checkExpected(input, Expected(Success(res), 1796, costDetails2, 1796, Seq.fill(4)(2102)))
}
{ // negative: readonly tree
@@ -3530,7 +3318,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val input = (readonlyTree, (kvs, insertProof))
val (res, _) = insert.checkEquality(input).getOrThrow
res.isDefined shouldBe false
- insert.checkExpected(input, Expected(Success(res), 1772, costDetails1, 1772))
+ insert.checkExpected(input, Expected(Success(res), 1772, costDetails1, 1772, Seq.fill(4)(2078)))
}
{ // negative: invalid key
@@ -3540,7 +3328,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val input = (tree, (invalidKvs, insertProof))
val (res, _) = insert.checkEquality(input).getOrThrow
res.isDefined shouldBe true // TODO v6.0: should it really be true? (looks like a bug) (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/908)
- insert.checkExpected(input, Expected(Success(res), 1796, costDetails2, 1796))
+ insert.checkExpected(input, Expected(Success(res), 1796, costDetails2, 1796, Seq.fill(4)(2102)))
}
{ // negative: invalid proof
@@ -3670,7 +3458,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val endTree = preUpdateTree.updateDigest(endDigest)
val input = (preUpdateTree, (kvs, updateProof))
val res = Some(endTree)
- update.checkExpected(input, Expected(Success(res), 1805, costDetails2, 1805))
+ update.checkExpected(input, Expected(Success(res), 1805, costDetails2, 1805, Seq.fill(4)(2111)))
}
{ // positive: update to the same value (identity operation)
@@ -3678,13 +3466,13 @@ class SigmaDslSpecification extends SigmaDslTesting
val keys = Colls.fromItems((key -> value))
val input = (tree, (keys, updateProof))
val res = Some(tree)
- update.checkExpected(input, Expected(Success(res), 1805, costDetails2, 1805))
+ update.checkExpected(input, Expected(Success(res), 1805, costDetails2, 1805, Seq.fill(4)(2111)))
}
{ // negative: readonly tree
val readonlyTree = createTree(preUpdateDigest)
val input = (readonlyTree, (kvs, updateProof))
- update.checkExpected(input, Expected(Success(None), 1772, costDetails1, 1772))
+ update.checkExpected(input, Expected(Success(None), 1772, costDetails1, 1772, Seq.fill(4)(2078)))
}
{ // negative: invalid key
@@ -3692,7 +3480,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val invalidKey = key.map(x => (-x).toByte) // any other different from key
val invalidKvs = Colls.fromItems((invalidKey -> newValue))
val input = (tree, (invalidKvs, updateProof))
- update.checkExpected(input, Expected(Success(None), 1801, costDetails3, 1801))
+ update.checkExpected(input, Expected(Success(None), 1801, costDetails3, 1801, Seq.fill(4)(2107)))
}
{ // negative: invalid value (different from the value in the proof)
@@ -3701,15 +3489,15 @@ class SigmaDslSpecification extends SigmaDslTesting
val invalidKvs = Colls.fromItems((key -> invalidValue))
val input = (tree, (invalidKvs, updateProof))
val (res, _) = update.checkEquality(input).getOrThrow
- res.isDefined shouldBe true // TODO v6.0: should it really be true? (looks like a bug) (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/908)
- update.checkExpected(input, Expected(Success(res), 1805, costDetails2, 1805))
+ res.isDefined shouldBe true // TODO v6.0: should it really be true? (looks like a bug) (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/908)
+ update.checkExpected(input, Expected(Success(res), 1805, costDetails2, 1805, Seq.fill(4)(2111)))
}
{ // negative: invalid proof
val tree = createTree(preUpdateDigest, updateAllowed = true)
val invalidProof = updateProof.map(x => (-x).toByte) // any other different from proof
val input = (tree, (kvs, invalidProof))
- update.checkExpected(input, Expected(Success(None), 1801, costDetails3, 1801))
+ update.checkExpected(input, Expected(Success(None), 1801, costDetails3, 1801, Seq.fill(4)(2107)))
}
}
@@ -3820,7 +3608,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val endTree = preRemoveTree.updateDigest(endDigest)
val input = (preRemoveTree, (Colls.fromArray(keysToRemove), removeProof))
val res = Some(endTree)
- remove.checkExpected(input, Expected(Success(res), 1832, costDetails1, 1832))
+ remove.checkExpected(input, Expected(Success(res), 1832, costDetails1, 1832, Seq.fill(4)(2126)))
}
{
@@ -3837,13 +3625,13 @@ class SigmaDslSpecification extends SigmaDslTesting
val endTree = preRemoveTree.updateDigest(endDigest)
val input = (preRemoveTree, (keys, removeProof))
val res = Some(endTree)
- remove.checkExpected(input, Expected(Success(res), 1806, costDetails2, 1806))
+ remove.checkExpected(input, Expected(Success(res), 1806, costDetails2, 1806, Seq.fill(4)(2100)))
}
{ // negative: readonly tree
val readonlyTree = createTree(preRemoveDigest)
val input = (readonlyTree, (keys, removeProof))
- remove.checkExpected(input, Expected(Success(None), 1772, costDetails3, 1772))
+ remove.checkExpected(input, Expected(Success(None), 1772, costDetails3, 1772, Seq.fill(4)(2066)))
}
{ // negative: invalid key
@@ -3851,14 +3639,14 @@ class SigmaDslSpecification extends SigmaDslTesting
val invalidKey = key.map(x => (-x).toByte) // any other different from `key`
val invalidKeys = Colls.fromItems(invalidKey)
val input = (tree, (invalidKeys, removeProof))
- remove.checkExpected(input, Expected(Success(None), 1802, costDetails4, 1802))
+ remove.checkExpected(input, Expected(Success(None), 1802, costDetails4, 1802, Seq.fill(4)(2096)))
}
{ // negative: invalid proof
val tree = createTree(preRemoveDigest, removeAllowed = true)
val invalidProof = removeProof.map(x => (-x).toByte) // any other different from `removeProof`
val input = (tree, (keys, invalidProof))
- remove.checkExpected(input, Expected(Success(None), 1802, costDetails4, 1802))
+ remove.checkExpected(input, Expected(Success(None), 1802, costDetails4, 1802, Seq.fill(4)(2096)))
}
}
}
@@ -3867,7 +3655,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val costDetails = CostDetails(traceBase :+ FixedCostItem(CompanionDesc(LongToByteArray), FixedCost(JitCost(17))))
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1767, costDetails, 1767)
+ def success[T](v: T) = Expected(Success(v), 1767, costDetails, 1767, Seq.fill(4)(1999))
Seq(
(-9223372036854775808L, success(Helpers.decodeBytes("8000000000000000"))),
(-1148502660425090565L, success(Helpers.decodeBytes("f00fb2ea55c579fb"))),
@@ -3887,20 +3675,20 @@ class SigmaDslSpecification extends SigmaDslTesting
val costDetails = CostDetails(traceBase :+ FixedCostItem(CompanionDesc(ByteArrayToBigInt), FixedCost(JitCost(30))))
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1767, costDetails, 1767)
+ def success[T](v: T) = Expected(Success(v), 1767, costDetails, 1767, Seq.fill(4)(1999))
Seq(
(Helpers.decodeBytes(""),
Expected(new NumberFormatException("Zero length BigInteger"))),
(Helpers.decodeBytes("00"),
- success(CBigInt(new BigInteger("0", 16)))),
+ success(CBigInt(new BigInteger("0", 16)))),
(Helpers.decodeBytes("01"),
- success(CBigInt(new BigInteger("1", 16)))),
+ success(CBigInt(new BigInteger("1", 16)))),
(Helpers.decodeBytes("ff"),
- success(CBigInt(new BigInteger("-1", 16)))),
+ success(CBigInt(new BigInteger("-1", 16)))),
(Helpers.decodeBytes("80d6c201"),
- Expected(Success(CBigInt(new BigInteger("-7f293dff", 16))), 1767, costDetails, 1767)),
+ Expected(Success(CBigInt(new BigInteger("-7f293dff", 16))), 1767, costDetails, 1767, Seq.fill(4)(1999))),
(Helpers.decodeBytes("70d6c20170d6c201"),
- Expected(Success(CBigInt(new BigInteger("70d6c20170d6c201", 16))), 1767, costDetails, 1767)),
+ Expected(Success(CBigInt(new BigInteger("70d6c20170d6c201", 16))), 1767, costDetails, 1767, Seq.fill(4)(1999))),
(Helpers.decodeBytes(
"80e0ff7f02807fff72807f0a00ff7fb7c57f75c11ba2802970fd250052807fc37f6480ffff007fff18eeba44"
), Expected(new ArithmeticException("BigInteger out of 256 bit range")))
@@ -3915,7 +3703,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val costDetails = CostDetails(traceBase :+ FixedCostItem(CompanionDesc(ByteArrayToLong), FixedCost(JitCost(16))))
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1765, costDetails, 1765)
+ def success[T](v: T) = Expected(Success(v), 1765, costDetails, 1765, Seq.fill(4)(1997))
Seq(
(Helpers.decodeBytes(""), Expected(new IllegalArgumentException("array too small: 0 < 8"))),
(Helpers.decodeBytes("81"), Expected(new IllegalArgumentException("array too small: 1 < 8"))),
@@ -3937,7 +3725,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
val costDetails = CostDetails(traceBase :+ FixedCostItem(CompanionDesc(ExtractId), FixedCost(JitCost(12))))
- def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766)
+ def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766, Seq.fill(4)(1998))
Seq(
(b1, success(Helpers.decodeBytes("5ee78f30ae4e770e44900a46854e9fecb6b12e8112556ef1cd19aef633b4421e"))),
(b2, success(Helpers.decodeBytes("3a0089be265460e29ca47d26e5b55a6f3e3ffaf5b4aed941410a2437913848ad")))
@@ -3950,7 +3738,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
val costDetails = CostDetails(traceBase :+ FixedCostItem(CompanionDesc(ExtractAmount), FixedCost(JitCost(8))))
- def success[T](v: T) = Expected(Success(v), 1764, costDetails, 1764)
+ def success[T](v: T) = Expected(Success(v), 1764, costDetails, 1764, Seq.fill(4)(1996))
Seq(
(b1, success(9223372036854775807L)),
(b2, success(12345L))
@@ -3963,7 +3751,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
val costDetails = CostDetails(traceBase :+ FixedCostItem(CompanionDesc(ExtractScriptBytes), FixedCost(JitCost(10))))
- def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766)
+ def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766, Seq.fill(4)(1998))
Seq(
(b1, success(Helpers.decodeBytes(
"100108cd0297c44a12f4eb99a85d298fa3ba829b5b42b9f63798c980ece801cc663cc5fc9e7300"
@@ -3978,7 +3766,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
val costDetails = CostDetails(traceBase :+ FixedCostItem(CompanionDesc(ExtractBytes), FixedCost(JitCost(12))))
- def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766)
+ def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766, Seq.fill(4)(1998))
Seq(
(b1, success(Helpers.decodeBytes(
"ffffffffffffffff7f100108cd0297c44a12f4eb99a85d298fa3ba829b5b42b9f63798c980ece801cc663cc5fc9e73009fac29026e789ab7b2fffff12280a6cd01557f6fb22b7f80ff7aff8e1f7f15973d7f000180ade204a3ff007f00057600808001ff8f8000019000ffdb806fff7cc0b6015eb37fa600f4030201000e067fc87f7f01ff218301ae8000018008637f0021fb9e00018055486f0b514121016a00ff718080bcb001"
@@ -3995,7 +3783,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
val costDetails = CostDetails(traceBase :+ FixedCostItem(CompanionDesc(ExtractBytesWithNoRef), FixedCost(JitCost(12))))
- def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766)
+ def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766, Seq.fill(4)(1998))
Seq(
(b1, success(Helpers.decodeBytes(
"ffffffffffffffff7f100108cd0297c44a12f4eb99a85d298fa3ba829b5b42b9f63798c980ece801cc663cc5fc9e73009fac29026e789ab7b2fffff12280a6cd01557f6fb22b7f80ff7aff8e1f7f15973d7f000180ade204a3ff007f00057600808001ff8f8000019000ffdb806fff7cc0b6015eb37fa600f4030201000e067fc87f7f01ff"
@@ -4012,7 +3800,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
val costDetails = CostDetails(traceBase :+ FixedCostItem(CompanionDesc(ExtractCreationInfo), FixedCost(JitCost(16))))
- def success[T](v: T) = Expected(Success(v), 1767, costDetails, 1767)
+ def success[T](v: T) = Expected(Success(v), 1767, costDetails, 1767, Seq.fill(4)(2001))
Seq(
(b1, success((
677407,
@@ -4035,8 +3823,8 @@ class SigmaDslSpecification extends SigmaDslTesting
b1 -> Expected(Success(Coll[(Coll[Byte], Long)](
(Helpers.decodeBytes("6e789ab7b2fffff12280a6cd01557f6fb22b7f80ff7aff8e1f7f15973d7f0001"), 10000000L),
(Helpers.decodeBytes("a3ff007f00057600808001ff8f8000019000ffdb806fff7cc0b6015eb37fa600"), 500L)
- ).map(identity)), 1772, methodCostDetails(SBoxMethods.tokensMethod, 15), 1772),
- b2 -> Expected(Success(Coll[(Coll[Byte], Long)]().map(identity)), 1766, methodCostDetails(SBoxMethods.tokensMethod, 15), 1766)
+ ).map(identity)), 1772, methodCostDetails(SBoxMethods.tokensMethod, 15), 1772, Seq.fill(4)(2012)),
+ b2 -> Expected(Success(Coll[(Coll[Byte], Long)]().map(identity)), 1766, methodCostDetails(SBoxMethods.tokensMethod, 15), 1766, Seq.fill(4)(2006))
),
existingFeature({ (x: Box) => x.tokens },
"{ (x: Box) => x.tokens }",
@@ -4051,16 +3839,6 @@ class SigmaDslSpecification extends SigmaDslTesting
)))
}
- 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))
@@ -4115,11 +3893,11 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
- (box1, Expected(Success(1024.toShort), 1774, expCostDetails1, 1774)),
+ (box1, Expected(Success(1024.toShort), 1774, expCostDetails1, 1774, Seq.fill(4)(2042))),
(box2, Expected(
new InvalidType("Cannot getReg[Short](5): invalid type of value TestValue(1048576) at id=5")
)),
- (box3, Expected(Success(0.toShort), 1772, expCostDetails2, 1772))
+ (box3, Expected(Success(0.toShort), 1772, expCostDetails2, 1772, Seq.fill(4)(2040)))
),
existingFeature(
{ (x: Box) =>
@@ -4244,10 +4022,10 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
- (box1, Expected(Success(1024), cost = 1785, expCostDetails3, 1785)),
- (box2, Expected(Success(1024 * 1024), cost = 1786, expCostDetails4, 1786)),
- (box3, Expected(Success(0), cost = 1779, expCostDetails5, 1779)),
- (box4, Expected(Success(-1), cost = 1772, expCostDetails2, 1772))
+ (box1, Expected(Success(1024), cost = 1785, expCostDetails3, 1785, Seq.fill(4)(2129))),
+ (box2, Expected(Success(1024 * 1024), cost = 1786, expCostDetails4, 1786, Seq.fill(4)(2130))),
+ (box3, Expected(Success(0), cost = 1779, expCostDetails5, 1779, Seq.fill(4)(2123))),
+ (box4, Expected(Success(-1), cost = 1772, expCostDetails2, 1772, Seq.fill(4)(2116)))
),
existingFeature(
{ (x: Box) =>
@@ -4341,7 +4119,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
Seq(
- (box1, Expected(Success(1.toByte), cost = 1770, expCostDetails, 1770)),
+ (box1, Expected(Success(1.toByte), cost = 1770, expCostDetails, 1770, Seq.fill(4)(2008))),
(box2, Expected(new InvalidType("Cannot getReg[Byte](4): invalid type of value Value(Coll(1)) at id=4")))
),
existingFeature((x: Box) => x.R4[Byte].get,
@@ -4353,7 +4131,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
- (box1, Expected(Success(1024.toShort), cost = 1770, expCostDetails, 1770)),
+ (box1, Expected(Success(1024.toShort), cost = 1770, expCostDetails, 1770, Seq.fill(4)(2008))),
(box2, Expected(new NoSuchElementException("None.get")))
),
existingFeature((x: Box) => x.R5[Short].get,
@@ -4365,7 +4143,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
- (box1, Expected(Success(1024 * 1024), cost = 1770, expCostDetails, 1770))
+ (box1, Expected(Success(1024 * 1024), cost = 1770, expCostDetails, 1770, Seq.fill(4)(2008)))
),
existingFeature((x: Box) => x.R6[Int].get,
"{ (x: Box) => x.R6[Int].get }",
@@ -4376,7 +4154,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
- (box1, Expected(Success(1024.toLong), cost = 1770, expCostDetails, 1770))
+ (box1, Expected(Success(1024.toLong), cost = 1770, expCostDetails, 1770, Seq.fill(4)(2008)))
),
existingFeature((x: Box) => x.R7[Long].get,
"{ (x: Box) => x.R7[Long].get }",
@@ -4387,7 +4165,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
- (box1, Expected(Success(CBigInt(BigInteger.valueOf(222L))), cost = 1770, expCostDetails, 1770))
+ (box1, Expected(Success(CBigInt(BigInteger.valueOf(222L))), cost = 1770, expCostDetails, 1770, Seq.fill(4)(2008)))
),
existingFeature((x: Box) => x.R8[BigInt].get,
"{ (x: Box) => x.R8[BigInt].get }",
@@ -4406,10 +4184,10 @@ class SigmaDslSpecification extends SigmaDslTesting
None
)
)),
- cost = 1770,
- expCostDetails,
- 1770)
- )),
+ cost = 1770,
+ expCostDetails,
+ 1770, Seq.fill(4)(2008))
+ )),
existingFeature((x: Box) => x.R9[AvlTree].get,
"{ (x: Box) => x.R9[AvlTree].get }",
FuncValue(
@@ -4481,117 +4259,117 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
- Seq((preH1, Expected(Success(0.toByte), cost = 1765, methodCostDetails(SPreHeaderMethods.versionMethod, 10), 1765))),
+ Seq((preH1, Expected(Success(0.toByte), cost = 1765, methodCostDetails(SPreHeaderMethods.versionMethod, 10), 1765, Seq.fill(4)(2001)))),
existingPropTest("version", { (x: PreHeader) => x.version }))
verifyCases(
Seq((preH1, Expected(Success(
Helpers.decodeBytes("7fff7fdd6f62018bae0001006d9ca888ff7f56ff8006573700a167f17f2c9f40")),
- cost = 1766, methodCostDetails(SPreHeaderMethods.parentIdMethod, 10), 1766))),
+ cost = 1766, methodCostDetails(SPreHeaderMethods.parentIdMethod, 10), 1766, Seq.fill(4)(2002)))),
existingPropTest("parentId", { (x: PreHeader) => x.parentId }))
verifyCases(
- Seq((preH1, Expected(Success(6306290372572472443L), cost = 1765, methodCostDetails(SPreHeaderMethods.timestampMethod, 10), 1765))),
+ Seq((preH1, Expected(Success(6306290372572472443L), cost = 1765, methodCostDetails(SPreHeaderMethods.timestampMethod, 10), 1765, Seq.fill(4)(2001)))),
existingPropTest("timestamp", { (x: PreHeader) => x.timestamp }))
verifyCases(
- Seq((preH1, Expected(Success(-3683306095029417063L), cost = 1765, methodCostDetails(SPreHeaderMethods.nBitsMethod, 10), 1765))),
+ Seq((preH1, Expected(Success(-3683306095029417063L), cost = 1765, methodCostDetails(SPreHeaderMethods.nBitsMethod, 10), 1765, Seq.fill(4)(2001)))),
existingPropTest("nBits", { (x: PreHeader) => x.nBits }))
verifyCases(
- Seq((preH1, Expected(Success(1), cost = 1765, methodCostDetails(SPreHeaderMethods.heightMethod, 10), 1765))),
+ Seq((preH1, Expected(Success(1), cost = 1765, methodCostDetails(SPreHeaderMethods.heightMethod, 10), 1765, Seq.fill(4)(2001)))),
existingPropTest("height", { (x: PreHeader) => x.height }))
verifyCases(
Seq((preH1, Expected(Success(
Helpers.decodeGroupElement("026930cb9972e01534918a6f6d6b8e35bc398f57140d13eb3623ea31fbd069939b")),
- cost = 1782, methodCostDetails(SPreHeaderMethods.minerPkMethod, 10), 1782))),
+ cost = 1782, methodCostDetails(SPreHeaderMethods.minerPkMethod, 10), 1782, Seq.fill(4)(2018)))),
existingPropTest("minerPk", { (x: PreHeader) => x.minerPk }))
verifyCases(
- Seq((preH1, Expected(Success(Helpers.decodeBytes("ff8087")), cost = 1766, methodCostDetails(SPreHeaderMethods.votesMethod,10), 1766))),
+ Seq((preH1, Expected(Success(Helpers.decodeBytes("ff8087")), cost = 1766, methodCostDetails(SPreHeaderMethods.votesMethod, 10), 1766, Seq.fill(4)(2002)))),
existingPropTest("votes", { (x: PreHeader) => x.votes }))
}
property("Header properties equivalence") {
verifyCases(
Seq((h1, Expected(Success(
- Helpers.decodeBytes("957f008001808080ffe4ffffc8f3802401df40006aa05e017fa8d3f6004c804a")),
- cost = 1766, methodCostDetails(SHeaderMethods.idMethod, 10), 1766))),
+ Helpers.decodeBytes("cea31f0e0a794b103f65f8296a22ac8ff214e1bc75442186b90df4844c978e81")),
+ cost = 1766, methodCostDetails(SHeaderMethods.idMethod, 10), 1766, Seq.fill(4)(2002)))),
existingPropTest("id", { (x: Header) => x.id }))
verifyCases(
- Seq((h1, Expected(Success(0.toByte), cost = 1765, methodCostDetails(SHeaderMethods.versionMethod, 10), 1765))),
+ Seq((h1, Expected(Success(0.toByte), cost = 1765, methodCostDetails(SHeaderMethods.versionMethod, 10), 1765, Seq.fill(4)(2001)))),
existingPropTest("version", { (x: Header) => x.version }))
verifyCases(
Seq((h1, Expected(Success(
Helpers.decodeBytes("0180dd805b0000ff5400b997fd7f0b9b00de00fb03c47e37806a8186b94f07ff")),
- cost = 1766, methodCostDetails(SHeaderMethods.parentIdMethod, 10), 1766))),
+ cost = 1766, methodCostDetails(SHeaderMethods.parentIdMethod, 10), 1766, Seq.fill(4)(2002)))),
existingPropTest("parentId", { (x: Header) => x.parentId }))
verifyCases(
Seq((h1, Expected(Success(
Helpers.decodeBytes("01f07f60d100ffb970c3007f60ff7f24d4070bb8fffa7fca7f34c10001ffe39d")),
- cost = 1766, methodCostDetails(SHeaderMethods.ADProofsRootMethod, 10), 1766))),
- existingPropTest("ADProofsRoot", { (x: Header) => x.ADProofsRoot}))
+ cost = 1766, methodCostDetails(SHeaderMethods.ADProofsRootMethod, 10), 1766, Seq.fill(4)(2002)))),
+ existingPropTest("ADProofsRoot", { (x: Header) => x.ADProofsRoot }))
verifyCases(
- Seq((h1, Expected(Success(CAvlTree(createAvlTreeData())), cost = 1765, methodCostDetails(SHeaderMethods.stateRootMethod, 10), 1765))),
+ Seq((h1, Expected(Success(CAvlTree(createAvlTreeData())), cost = 1765, methodCostDetails(SHeaderMethods.stateRootMethod, 10), 1765, Seq.fill(4)(2001)))),
existingPropTest("stateRoot", { (x: Header) => x.stateRoot }))
verifyCases(
Seq((h1, Expected(Success(
Helpers.decodeBytes("804101ff01000080a3ffbd006ac080098df132a7017f00649311ec0e00000100")),
- cost = 1766, methodCostDetails(SHeaderMethods.transactionsRootMethod, 10), 1766))),
+ cost = 1766, methodCostDetails(SHeaderMethods.transactionsRootMethod, 10), 1766, Seq.fill(4)(2002)))),
existingPropTest("transactionsRoot", { (x: Header) => x.transactionsRoot }))
verifyCases(
- Seq((h1, Expected(Success(1L), cost = 1765, methodCostDetails(SHeaderMethods.timestampMethod, 10), 1765))),
+ Seq((h1, Expected(Success(1L), cost = 1765, methodCostDetails(SHeaderMethods.timestampMethod, 10), 1765, Seq.fill(4)(2001)))),
existingPropTest("timestamp", { (x: Header) => x.timestamp }))
verifyCases(
- Seq((h1, Expected(Success(-1L), cost = 1765, methodCostDetails(SHeaderMethods.nBitsMethod, 10), 1765))),
+ Seq((h1, Expected(Success(-1L), cost = 1765, methodCostDetails(SHeaderMethods.nBitsMethod, 10), 1765, Seq.fill(4)(2001)))),
existingPropTest("nBits", { (x: Header) => x.nBits }))
verifyCases(
- Seq((h1, Expected(Success(1), cost = 1765, methodCostDetails(SHeaderMethods.heightMethod, 10), 1765))),
+ Seq((h1, Expected(Success(1), cost = 1765, methodCostDetails(SHeaderMethods.heightMethod, 10), 1765, Seq.fill(4)(2001)))),
existingPropTest("height", { (x: Header) => x.height }))
verifyCases(
Seq((h1, Expected(Success(
Helpers.decodeBytes("e57f80885601b8ff348e01808000bcfc767f2dd37f0d01015030ec018080bc62")),
- cost = 1766, methodCostDetails(SHeaderMethods.extensionRootMethod, 10), 1766))),
+ cost = 1766, methodCostDetails(SHeaderMethods.extensionRootMethod, 10), 1766, Seq.fill(4)(2002)))),
existingPropTest("extensionRoot", { (x: Header) => x.extensionRoot }))
verifyCases(
Seq((h1, Expected(Success(
Helpers.decodeGroupElement("039bdbfa0b49cc6bef58297a85feff45f7bbeb500a9d2283004c74fcedd4bd2904")),
- cost = 1782, methodCostDetails(SHeaderMethods.minerPkMethod, 10), 1782))),
+ cost = 1782, methodCostDetails(SHeaderMethods.minerPkMethod, 10), 1782, Seq.fill(4)(2018)))),
existingPropTest("minerPk", { (x: Header) => x.minerPk }))
verifyCases(
Seq((h1, Expected(Success(
Helpers.decodeGroupElement("0361299207fa392231e23666f6945ae3e867b978e021d8d702872bde454e9abe9c")),
- cost = 1782, methodCostDetails(SHeaderMethods.powOnetimePkMethod, 10), 1782))),
+ cost = 1782, methodCostDetails(SHeaderMethods.powOnetimePkMethod, 10), 1782, Seq.fill(4)(2018)))),
existingPropTest("powOnetimePk", { (x: Header) => x.powOnetimePk }))
verifyCases(
Seq((h1, Expected(Success(
Helpers.decodeBytes("7f4f09012a807f01")),
- cost = 1766, methodCostDetails(SHeaderMethods.powNonceMethod, 10), 1766))),
+ cost = 1766, methodCostDetails(SHeaderMethods.powNonceMethod, 10), 1766, Seq.fill(4)(2002)))),
existingPropTest("powNonce", { (x: Header) => x.powNonce }))
verifyCases(
Seq((h1, Expected(Success(
CBigInt(new BigInteger("-e24990c47e15ed4d0178c44f1790cc72155d516c43c3e8684e75db3800a288", 16))),
- cost = 1765, methodCostDetails(SHeaderMethods.powDistanceMethod, 10), 1765))),
+ cost = 1765, methodCostDetails(SHeaderMethods.powDistanceMethod, 10), 1765, Seq.fill(4)(2001)))),
existingPropTest("powDistance", { (x: Header) => x.powDistance }))
verifyCases(
Seq((h1, Expected(Success(
Helpers.decodeBytes("7f0180")),
- cost = 1766, methodCostDetails(SHeaderMethods.votesMethod, 10), 1766))),
+ cost = 1766, methodCostDetails(SHeaderMethods.votesMethod, 10), 1766, Seq.fill(4)(2002)))),
existingPropTest("votes", { (x: Header) => x.votes }))
}
@@ -4654,18 +4432,10 @@ class SigmaDslSpecification extends SigmaDslTesting
)
val header = CHeader(
- Helpers.decodeBytes("1c597f88969600d2fffffdc47f00d8ffc555a9e85001000001c505ff80ff8f7f"),
0.toByte,
Helpers.decodeBytes("7a7fe5347f09017818010062000001807f86808000ff7f66ffb07f7ad27f3362"),
Helpers.decodeBytes("c1d70ad9b1ffc1fb9a715fff19807f2401017fcd8b73db017f1cff77727fff08"),
- CAvlTree(
- AvlTreeData(
- ErgoAlgos.decodeUnsafe("54d23dd080006bdb56800100356080935a80ffb77e90b800057f00661601807f17").toColl,
- AvlTreeFlags(true, true, false),
- 2147483647,
- None
- )
- ),
+ Helpers.decodeBytes("54d23dd080006bdb56800100356080935a80ffb77e90b800057f00661601807f17"),
Helpers.decodeBytes("5e7f1164ccd0990080c501fc0e0181cb387fc17f00ff00c7d5ff767f91ff5e68"),
-7421721754642387858L,
-4826493284887861030L,
@@ -4675,7 +4445,8 @@ class SigmaDslSpecification extends SigmaDslTesting
Helpers.decodeGroupElement("034e2d3b5f9e409e3ae8a2e768340760362ca33764eda5855f7a43487f14883300"),
Helpers.decodeBytes("974651c9efff7f00"),
CBigInt(new BigInteger("478e827dfa1e4b57", 16)),
- Helpers.decodeBytes("01ff13")
+ Helpers.decodeBytes("01ff13"),
+ Colls.emptyColl
)
val ctx = CContext(
@@ -4683,7 +4454,7 @@ class SigmaDslSpecification extends SigmaDslTesting
headers = Coll[Header](header),
preHeader = CPreHeader(
0.toByte,
- Helpers.decodeBytes("1c597f88969600d2fffffdc47f00d8ffc555a9e85001000001c505ff80ff8f7f"),
+ header.id,
-755484979487531112L,
9223372036854775807L,
11,
@@ -4762,6 +4533,7 @@ class SigmaDslSpecification extends SigmaDslTesting
.append(Coll[AnyValue](
CAnyValue(Helpers.decodeBytes("00")),
CAnyValue(true))),
+ spendingTransaction = null,
activatedScriptVersion = activatedVersionInTests,
currentErgoTreeVersion = ergoTreeVersionInTests
)
@@ -4805,7 +4577,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val costDetails = TracedCost(testTraceBase)
verifyCases(
Seq(
- (ctx, Expected(Success(dataBox), cost = 1769, costDetails, 1769)),
+ (ctx, Expected(Success(dataBox), cost = 1769, costDetails, 1769, Seq.fill(4)(2017))),
(ctx.copy(_dataInputs = Coll()), Expected(new ArrayIndexOutOfBoundsException("0")))
),
existingFeature({ (x: Context) => x.dataInputs(0) },
@@ -4830,7 +4602,7 @@ class SigmaDslSpecification extends SigmaDslTesting
Seq(
(ctx, Expected(Success(
Helpers.decodeBytes("7da4b55971f19a78d007638464580f91a020ab468c0dbe608deb1f619e245bc3")),
- cost = 1772, idCostDetails, 1772))
+ cost = 1772, idCostDetails, 1772, Seq.fill(4)(2022)))
),
existingFeature({ (x: Context) => x.dataInputs(0).id },
"{ (x: Context) => x.dataInputs(0).id }",
@@ -4891,7 +4663,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
verifyCases(
- Seq(ctx -> Expected(Success(ctx.HEIGHT), cost = 1766, heightCostDetails, 1766)),
+ Seq(ctx -> Expected(Success(ctx.HEIGHT), cost = 1766, heightCostDetails, 1766, Seq.fill(4)(1994))),
existingFeature(
{ (x: Context) => x.HEIGHT },
"{ (x: Context) => x.HEIGHT }",
@@ -4928,7 +4700,7 @@ class SigmaDslSpecification extends SigmaDslTesting
))
verifyCases(
- Seq((ctx, Expected(Success(Coll[Long](80946L)), cost = 1770, inputsCostDetails1, 1770))),
+ Seq((ctx, Expected(Success(Coll[Long](80946L)), cost = 1770, inputsCostDetails1, 1770, Seq.fill(4)(2014)))),
existingFeature(
{ (x: Context) => x.INPUTS.map { (b: Box) => b.value } },
"{ (x: Context) => x.INPUTS.map { (b: Box) => b.value } }",
@@ -4988,7 +4760,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
verifyCases(
- Seq((ctx, Expected(Success(Coll((80946L, 80946L))), cost = 1774, inputsCostDetails2, 1774))),
+ Seq((ctx, Expected(Success(Coll((80946L, 80946L))), cost = 1774, inputsCostDetails2, 1774, Seq.fill(4)(2042)))),
existingFeature(
{ (x: Context) => x.INPUTS.map { (b: Box) => (b.value, b.value) } },
"""{ (x: Context) =>
@@ -5080,11 +4852,20 @@ class SigmaDslSpecification extends SigmaDslTesting
expectedDetails = CostDetails.ZeroCost,
newCost = 1766,
newVersionedResults = {
+ val expectedV3Costs = Seq.fill(4)(2002)
+ // V3 activation will have different costs due to deserialization cost
+ val costs = if (activatedVersionInTests >= V6SoftForkVersion) {
+ expectedV3Costs
+ } else {
+ Seq.fill(4)(1766)
+ }
val res = (ExpectedResult(Success(0), Some(1766)) -> Some(selfCostDetails))
- Seq(0, 1, 2).map(version => version -> res)
+ Seq(0, 1, 2, 3).map(version => version -> (ExpectedResult(Success(0), Some(costs(version))) -> Some(selfCostDetails)))
}))
),
- changedFeature({ (x: Context) => x.selfBoxIndex },
+ changedFeature(
+ changedInVersion = VersionContext.JitActivationVersion,
+ { (x: Context) => x.selfBoxIndex },
{ (x: Context) => x.selfBoxIndex }, // see versioning in selfBoxIndex implementation
"{ (x: Context) => x.selfBoxIndex }",
FuncValue(
@@ -5110,7 +4891,7 @@ class SigmaDslSpecification extends SigmaDslTesting
}
verifyCases(
- Seq(ctx -> Expected(Success(ctx.LastBlockUtxoRootHash), cost = 1766, methodCostDetails(SContextMethods.lastBlockUtxoRootHashMethod, 15), 1766)),
+ Seq(ctx -> Expected(Success(ctx.LastBlockUtxoRootHash), cost = 1766, methodCostDetails(SContextMethods.lastBlockUtxoRootHashMethod, 15), 1766, Seq.fill(4)(2002))),
existingPropTest("LastBlockUtxoRootHash", { (x: Context) => x.LastBlockUtxoRootHash }),
preGeneratedSamples = Some(samples))
@@ -5123,7 +4904,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
verifyCases(
- Seq(ctx -> Expected(Success(ctx.LastBlockUtxoRootHash.isUpdateAllowed), cost = 1767, isUpdateAllowedCostDetails, 1767)),
+ Seq(ctx -> Expected(Success(ctx.LastBlockUtxoRootHash.isUpdateAllowed), cost = 1767, isUpdateAllowedCostDetails, 1767, Seq.fill(4)(2009))),
existingFeature(
{ (x: Context) => x.LastBlockUtxoRootHash.isUpdateAllowed },
"{ (x: Context) => x.LastBlockUtxoRootHash.isUpdateAllowed }",
@@ -5144,7 +4925,7 @@ class SigmaDslSpecification extends SigmaDslTesting
preGeneratedSamples = Some(samples))
verifyCases(
- Seq(ctx -> Expected(Success(ctx.minerPubKey), cost = 1767, methodCostDetails(SContextMethods.minerPubKeyMethod, 20), 1767)),
+ Seq(ctx -> Expected(Success(ctx.minerPubKey), cost = 1767, methodCostDetails(SContextMethods.minerPubKeyMethod, 20), 1767, Seq.fill(4)(2003))),
existingPropTest("minerPubKey", { (x: Context) => x.minerPubKey }),
preGeneratedSamples = Some(samples))
@@ -5184,7 +4965,7 @@ class SigmaDslSpecification extends SigmaDslTesting
FixedCostItem(GetVar),
FixedCostItem(OptionGet)))
verifyCases(
- Seq((ctx, Expected(Success(true), cost = 1765, getVarCostDetails, 1765))),
+ Seq((ctx, Expected(Success(true), cost = 1765, getVarCostDetails, 1765, Seq.fill(4)(1999)))),
existingFeature((x: Context) => x.getVar[Boolean](11).get,
"{ (x: Context) => getVar[Boolean](11).get }",
FuncValue(Vector((1, SContext)), OptionGet(GetVar(11.toByte, SOption(SBoolean))))),
@@ -5218,7 +4999,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
Seq(
- ctx -> Expected(Success(-135729055492651903L), 1779, registerIsDefinedCostDetails, 1779)
+ ctx -> Expected(Success(-135729055492651903L), 1779, registerIsDefinedCostDetails, 1779, Seq.fill(4)(2065))
),
existingFeature(
{ (x: Context) =>
@@ -5280,11 +5061,19 @@ class SigmaDslSpecification extends SigmaDslTesting
Seq(
ctx -> Expected(Failure(expectedError), 0, CostDetails.ZeroCost, 1793,
newVersionedResults = {
- Seq.tabulate(3)(v => v -> (ExpectedResult(Success(true), Some(1793)) -> None))
+ val expectedV3Costs = Seq.fill(4)(2121)
+ // V3 activation will have different costs due to deserialization cost
+ val costs = if (activatedVersionInTests >= V6SoftForkVersion) {
+ expectedV3Costs
+ } else {
+ Seq.fill(4)(1793)
+ }
+ Seq.tabulate(4)(v => v -> (ExpectedResult(Success(true), Some(costs(v))) -> None))
}
)
),
changedFeature(
+ changedInVersion = VersionContext.JitActivationVersion,
scalaFunc = { (x: Context) =>
// this error is expected in v3.x, v4.x
throw expectedError
@@ -5446,12 +5235,12 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
Seq(
- ctx -> Expected(Success(5008366408131208436L), 1791, registerTagCostDetails1, 1791),
+ ctx -> Expected(Success(5008366408131208436L), 1791, registerTagCostDetails1, 1791, Seq.fill(4)(2153)),
ctxWithRegsInOutput(ctx, Map(
ErgoBox.R5 -> LongConstant(0L),
- ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(10L), 1790, registerTagCostDetails2, 1790),
+ ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(10L), 1790, registerTagCostDetails2, 1790, Seq.fill(4)(2152)),
ctxWithRegsInOutput(ctx, Map(
- ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(-1L), 1777, registerTagCostDetails3, 1777)
+ ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(-1L), 1777, registerTagCostDetails3, 1777, Seq.fill(4)(2139))
),
existingFeature(
{ (x: Context) =>
@@ -5654,22 +5443,22 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
// case 1L
- ctx -> Expected(Success(5008366408131289382L), 1794, tagRegisterCostDetails1, 1794),
+ ctx -> Expected(Success(5008366408131289382L), 1794, tagRegisterCostDetails1, 1794, Seq.fill(4)(2168)),
// case 0L
ctxWithRegsInOutput(ctx, Map(
ErgoBox.R5 -> LongConstant(0L),
- ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(80956L), 1793, tagRegisterCostDetails2, 1793),
+ ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(80956L), 1793, tagRegisterCostDetails2, 1793, Seq.fill(4)(2167)),
// case returning 0L
ctxWithRegsInOutput(ctx, Map(
ErgoBox.R5 -> LongConstant(2L),
// note R4 is required to avoid
// "RuntimeException: Set of non-mandatory indexes is not densely packed"
- ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(0L), 1784, tagRegisterCostDetails3, 1784),
+ ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(0L), 1784, tagRegisterCostDetails3, 1784, Seq.fill(4)(2158)),
// case returning -1L
ctxWithRegsInOutput(ctx, Map(
- ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(-1L), 1777, tagRegisterCostDetails4, 1777)
+ ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(-1L), 1777, tagRegisterCostDetails4, 1777, Seq.fill(4)(2151))
),
existingFeature(
{ (x: Context) =>
@@ -5887,15 +5676,15 @@ class SigmaDslSpecification extends SigmaDslTesting
Seq(
ctxWithRegsInDataInput(ctx, Map(
ErgoBox.R5 -> LongConstant(1L),
- ErgoBox.R4 -> LongConstant(10))) -> Expected(Success(10L), 1792, tagRegisterCostDetails1, 1792),
+ ErgoBox.R4 -> LongConstant(10))) -> Expected(Success(10L), 1792, tagRegisterCostDetails1, 1792, Seq.fill(4)(2162)),
ctxWithRegsInDataInput(ctx, Map(
ErgoBox.R5 -> LongConstant(0L),
- ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(10L), 1791, tagRegisterCostDetails2, 1791),
+ ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(10L), 1791, tagRegisterCostDetails2, 1791, Seq.fill(4)(2161)),
ctxWithRegsInDataInput(ctx, Map(
ErgoBox.R5 -> LongConstant(2L),
- ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(0L), 1786, tagRegisterCostDetails3, 1786),
+ ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(0L), 1786, tagRegisterCostDetails3, 1786, Seq.fill(4)(2156)),
ctxWithRegsInDataInput(ctx, Map(
- ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(-1L), 1779, tagRegisterCostDetails4, 1779)
+ ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(-1L), 1779, tagRegisterCostDetails4, 1779, Seq.fill(4)(2149))
),
existingFeature(
{ (x: Context) =>
@@ -6120,15 +5909,15 @@ class SigmaDslSpecification extends SigmaDslTesting
Seq(
ctxWithRegsInDataInput(ctx, Map(
ErgoBox.R5 -> LongConstant(1L),
- ErgoBox.R4 -> LongConstant(10))) -> Expected(Success(80956L), 1796, costDetails1, 1796),
+ ErgoBox.R4 -> LongConstant(10))) -> Expected(Success(80956L), 1796, costDetails1, 1796, Seq.fill(4)(2178)),
ctxWithRegsInDataInput(ctx, Map(
ErgoBox.R5 -> LongConstant(0L),
- ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(80956L), 1794, costDetails2, 1794),
+ ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(80956L), 1794, costDetails2, 1794, Seq.fill(4)(2176)),
ctxWithRegsInDataInput(ctx, Map(
ErgoBox.R5 -> LongConstant(2L),
- ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(0L), 1786, costDetails3, 1786),
+ ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(0L), 1786, costDetails3, 1786, Seq.fill(4)(2168)),
ctxWithRegsInDataInput(ctx, Map(
- ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(-1L), 1779, costDetails4, 1779)
+ ErgoBox.R4 -> ShortConstant(10))) -> Expected(Success(-1L), 1779, costDetails4, 1779, Seq.fill(4)(2161))
),
existingFeature(
{ (x: Context) =>
@@ -6233,7 +6022,15 @@ class SigmaDslSpecification extends SigmaDslTesting
cost = c,
expectedDetails = CostDetails.ZeroCost,
newCost = 1766,
- newVersionedResults = Seq(0, 1, 2).map(i => i -> (ExpectedResult(Success(newV), Some(1766)) -> Some(cd)))
+ newVersionedResults = {
+ val costs = if (activatedVersionInTests >= V6SoftForkVersion) {
+ Seq.fill(4)(1998)
+ }
+ else {
+ Seq.fill(4)(1766)
+ }
+ Seq.tabulate(4)(i => i -> (ExpectedResult(Success(newV), Some(costs(i))) -> Some(cd)))
+ }
)
Seq(
(Coll[Boolean](), successNew(false, 1766, newV = false, costDetails(0))),
@@ -6258,6 +6055,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
},
changedFeature(
+ changedInVersion = VersionContext.JitActivationVersion,
(x: Coll[Boolean]) => SigmaDsl.xorOf(x),
(x: Coll[Boolean]) => SigmaDsl.xorOf(x),
"{ (x: Coll[Boolean]) => xorOf(x) }",
@@ -6268,8 +6066,8 @@ class SigmaDslSpecification extends SigmaDslTesting
val costDetails = TracedCost(traceBase :+ FixedCostItem(LogicalNot))
verifyCases(
Seq(
- (true, Expected(Success(false), 1765, costDetails, 1765)),
- (false, Expected(Success(true), 1765, costDetails, 1765))),
+ (true, Expected(Success(false), 1765, costDetails, 1765, Seq.fill(4)(1997))),
+ (false, Expected(Success(true), 1765, costDetails, 1765, Seq.fill(4)(1997)))),
existingFeature((x: Boolean) => !x,
"{ (x: Boolean) => !x }",
FuncValue(Vector((1, SBoolean)), LogicalNot(ValUse(1, SBoolean)))))
@@ -6279,7 +6077,8 @@ class SigmaDslSpecification extends SigmaDslTesting
val costDetails = TracedCost(traceBase :+ FixedCostItem(Negation))
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766)
+ def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766, Seq.fill(4)(1998))
+
Seq(
(Byte.MinValue, success(Byte.MinValue)), // !!!
((Byte.MinValue + 1).toByte, success(Byte.MaxValue)),
@@ -6298,7 +6097,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766)
+ def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766, Seq.fill(4)(1998))
Seq(
(Short.MinValue, success(Short.MinValue)), // special case!
((Short.MinValue + 1).toShort, success(Short.MaxValue)),
@@ -6316,7 +6115,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766)
+ def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766, Seq.fill(4)(1998))
+
Seq(
(Int.MinValue, success(Int.MinValue)), // special case!
(Int.MinValue + 1, success(Int.MaxValue)),
@@ -6333,7 +6133,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766)
+ def success[T](v: T) = Expected(Success(v), 1766, costDetails, 1766, Seq.fill(4)(1998))
+
Seq(
(Long.MinValue, success(Long.MinValue)), // special case!
(Long.MinValue + 1, success(Long.MaxValue)),
@@ -6350,7 +6151,8 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1767, costDetails, 1767)
+ def success[T](v: T) = Expected(Success(v), 1767, costDetails, 1767, Seq.fill(4)(1999))
+
Seq(
(CBigInt(new BigInteger("-1655a05845a6ad363ac88ea21e88b97e436a1f02c548537e12e2d9667bf0680", 16)), success(CBigInt(new BigInteger("1655a05845a6ad363ac88ea21e88b97e436a1f02c548537e12e2d9667bf0680", 16)))),
(CBigInt(new BigInteger("-1b24ba8badba8abf347cce054d9b9f14f229321507245b8", 16)), success(CBigInt(new BigInteger("1b24ba8badba8abf347cce054d9b9f14f229321507245b8", 16)))),
@@ -6388,7 +6190,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1782, costDetails, 1782)
+ def success[T](v: T) = Expected(Success(v), 1782, costDetails, 1782, Seq.fill(4)(2016))
Seq(
(-1, success(Helpers.decodeGroupElement("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"))),
(1, success(Helpers.decodeGroupElement("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"))))
@@ -6407,7 +6209,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1782, costDetails, 1782)
+ def success[T](v: T) = Expected(Success(v), 1782, costDetails, 1782, Seq.fill(4)(2016))
Seq(
(-1, success(Helpers.decodeGroupElement("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"))),
(1, success(Helpers.decodeGroupElement("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"))))
@@ -6432,37 +6234,38 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
verifyCases(
- {
- def success[T](v: T) = Expected(Success(v), 1872, expCostDetails, 1872)
- Seq(
- (CBigInt(new BigInteger("-e5c1a54694c85d644fa30a6fc5f3aa209ed304d57f72683a0ebf21038b6a9d", 16)), success(Helpers.decodeGroupElement("023395bcba3d7cf21d73c50f8af79d09a8c404c15ce9d04f067d672823bae91a54"))),
- (CBigInt(new BigInteger("-bc2d08f935259e0eebf272c66c6e1dbd484c6706390215", 16)), success(Helpers.decodeGroupElement("02ddcf4c48105faf3c16f7399b5dbedd82ab0bb50ae292d8f88f49a3f86e78974e"))),
- (CBigInt(new BigInteger("-35cbe9a7a652e5fe85f735ee9909fdd8", 16)), success(Helpers.decodeGroupElement("03b110ec9c7a8c20ed873818e976a0e96e5a17be979d3422d59b362de2a3ae043e"))),
- (CBigInt(new BigInteger("-3f05ffca6bd4b15c", 16)), success(Helpers.decodeGroupElement("02acf2657d0714cef8d65ae15c362faa09c0934c0bce872a23398e564c090b85c8"))),
- (CBigInt(new BigInteger("-80000001", 16)), success(Helpers.decodeGroupElement("0391b418fd1778356ce947a5cbb46539fd29842aea168486fae91fc5317177a575"))),
- (CBigInt(new BigInteger("-80000000", 16)), success(Helpers.decodeGroupElement("025318f9b1a2697010c5ac235e9af475a8c7e5419f33d47b18d33feeb329eb99a4"))),
- (CBigInt(new BigInteger("-1", 16)), success(Helpers.decodeGroupElement("0379be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"))),
- (CBigInt(new BigInteger("0", 16)), success(Helpers.decodeGroupElement("000000000000000000000000000000000000000000000000000000000000000000"))),
- (CBigInt(new BigInteger("1", 16)), success(Helpers.decodeGroupElement("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"))),
- (CBigInt(new BigInteger("80000000", 16)), success(Helpers.decodeGroupElement("035318f9b1a2697010c5ac235e9af475a8c7e5419f33d47b18d33feeb329eb99a4"))),
- (CBigInt(new BigInteger("1251b7fcd8a01e95", 16)), success(Helpers.decodeGroupElement("030fde7238b8dddfafab8f5481dc17b880505d6bacbe3cdf2ce975afdcadf66354"))),
- (CBigInt(new BigInteger("12f6bd76d8fe1d035bdb14bf2f696e52", 16)), success(Helpers.decodeGroupElement("028f2ccf13669461cb3cfbea281e2db08fbb67b38493a1628855203d3f69b82763"))),
- (CBigInt(new BigInteger("102bb404f5e36bdba004fdefa34df8cfa02e7912f3caf79", 16)), success(Helpers.decodeGroupElement("03ce82f431d115d45ad555084f8b2861ce5c4561d154e931e9f778594896e46a25"))))
- },
- existingFeature({ (n: BigInt) => SigmaDsl.groupGenerator.exp(n) },
- "{ (n: BigInt) => groupGenerator.exp(n) }",
- FuncValue(
- Vector((1, SBigInt)),
- Exponentiate(
- MethodCall.typed[Value[SGroupElement.type]](
- Global,
- SGlobalMethods.getMethodByName("groupGenerator"),
- Vector(),
- Map()
- ),
- ValUse(1, SBigInt)
- )
- )))
+ {
+ def success[T](v: T) = Expected(Success(v), 1872, expCostDetails, 1872, Seq.fill(4)(2112))
+
+ Seq(
+ (CBigInt(new BigInteger("-e5c1a54694c85d644fa30a6fc5f3aa209ed304d57f72683a0ebf21038b6a9d", 16)), success(Helpers.decodeGroupElement("023395bcba3d7cf21d73c50f8af79d09a8c404c15ce9d04f067d672823bae91a54"))),
+ (CBigInt(new BigInteger("-bc2d08f935259e0eebf272c66c6e1dbd484c6706390215", 16)), success(Helpers.decodeGroupElement("02ddcf4c48105faf3c16f7399b5dbedd82ab0bb50ae292d8f88f49a3f86e78974e"))),
+ (CBigInt(new BigInteger("-35cbe9a7a652e5fe85f735ee9909fdd8", 16)), success(Helpers.decodeGroupElement("03b110ec9c7a8c20ed873818e976a0e96e5a17be979d3422d59b362de2a3ae043e"))),
+ (CBigInt(new BigInteger("-3f05ffca6bd4b15c", 16)), success(Helpers.decodeGroupElement("02acf2657d0714cef8d65ae15c362faa09c0934c0bce872a23398e564c090b85c8"))),
+ (CBigInt(new BigInteger("-80000001", 16)), success(Helpers.decodeGroupElement("0391b418fd1778356ce947a5cbb46539fd29842aea168486fae91fc5317177a575"))),
+ (CBigInt(new BigInteger("-80000000", 16)), success(Helpers.decodeGroupElement("025318f9b1a2697010c5ac235e9af475a8c7e5419f33d47b18d33feeb329eb99a4"))),
+ (CBigInt(new BigInteger("-1", 16)), success(Helpers.decodeGroupElement("0379be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"))),
+ (CBigInt(new BigInteger("0", 16)), success(Helpers.decodeGroupElement("000000000000000000000000000000000000000000000000000000000000000000"))),
+ (CBigInt(new BigInteger("1", 16)), success(Helpers.decodeGroupElement("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"))),
+ (CBigInt(new BigInteger("80000000", 16)), success(Helpers.decodeGroupElement("035318f9b1a2697010c5ac235e9af475a8c7e5419f33d47b18d33feeb329eb99a4"))),
+ (CBigInt(new BigInteger("1251b7fcd8a01e95", 16)), success(Helpers.decodeGroupElement("030fde7238b8dddfafab8f5481dc17b880505d6bacbe3cdf2ce975afdcadf66354"))),
+ (CBigInt(new BigInteger("12f6bd76d8fe1d035bdb14bf2f696e52", 16)), success(Helpers.decodeGroupElement("028f2ccf13669461cb3cfbea281e2db08fbb67b38493a1628855203d3f69b82763"))),
+ (CBigInt(new BigInteger("102bb404f5e36bdba004fdefa34df8cfa02e7912f3caf79", 16)), success(Helpers.decodeGroupElement("03ce82f431d115d45ad555084f8b2861ce5c4561d154e931e9f778594896e46a25"))))
+ },
+ existingFeature({ (n: BigInt) => SigmaDsl.groupGenerator.exp(n) },
+ "{ (n: BigInt) => groupGenerator.exp(n) }",
+ FuncValue(
+ Vector((1, SBigInt)),
+ Exponentiate(
+ MethodCall.typed[Value[SGroupElement.type]](
+ Global,
+ SGlobalMethods.getMethodByName("groupGenerator"),
+ Vector(),
+ Map()
+ ),
+ ValUse(1, SBigInt)
+ )
+ )))
}
}
@@ -6498,7 +6301,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T, cd: CostDetails) = Expected(Success(v), 1769, cd, 1769)
+ def success[T](v: T, cd: CostDetails) = Expected(Success(v), 1769, cd, 1769, Seq.fill(4)(2021))
Seq(
((Helpers.decodeBytes(""), Helpers.decodeBytes("")), success(Helpers.decodeBytes(""), costDetails(0))),
((Helpers.decodeBytes("01"), Helpers.decodeBytes("01")), success(Helpers.decodeBytes("00"), costDetails(1))),
@@ -6509,9 +6312,16 @@ class SigmaDslSpecification extends SigmaDslTesting
cost = 0,
expectedDetails = CostDetails.ZeroCost,
newCost = 1769,
- newVersionedResults = {
- val res = (ExpectedResult(Success(Helpers.decodeBytes("00")), Some(1769)), Some(costDetails(1)))
- Seq(0, 1, 2).map(version => version -> res)
+ newVersionedResults = {
+ val costs = if (activatedVersionInTests >= V6SoftForkVersion) {
+ Seq.fill(4)(2021)
+ } else {
+ Seq.fill(4)(1769)
+ }
+ Seq.tabulate(4) { version =>
+ val res = (ExpectedResult(Success(Helpers.decodeBytes("00")), Some(costs(version))), Some(costDetails(1)))
+ version -> res
+ }
}
)),
((Helpers.decodeBytes("800136fe89afff802acea67128a0ff007fffe3498c8001806080012b"),
@@ -6520,6 +6330,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
},
changedFeature(
+ changedInVersion = VersionContext.JitActivationVersion,
(x: (Coll[Byte], Coll[Byte])) => SigmaDsl.xor(x._1, x._2),
(x: (Coll[Byte], Coll[Byte])) => SigmaDsl.xor(x._1, x._2),
"{ (x: (Coll[Byte], Coll[Byte])) => xor(x._1, x._2) }",
@@ -6653,11 +6464,11 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
{
- def success[T](v: T, c: Int, costDetails: CostDetails, newCost: Int) = Expected(Success(v), c, costDetails, newCost)
+ def success[T](v: T, c: Int, costDetails: CostDetails, newCost: Int, expectedV3Costs: Seq[Int]) = Expected(Success(v), c, costDetails, newCost, expectedV3Costs)
Seq(
- (Coll[Box](), success(Coll[Box](), 1767, costDetails, 1767)),
- (Coll[Box](b1), success(Coll[Box](), 1772, costDetails2, 1772)),
- (Coll[Box](b1, b2), success(Coll[Box](b2), 1776, costDetails3, 1776))
+ (Coll[Box](), success(Coll[Box](), 1767, costDetails, 1767, Seq.fill(4)(2031))),
+ (Coll[Box](b1), success(Coll[Box](), 1772, costDetails2, 1772, Seq.fill(4)(2036))),
+ (Coll[Box](b1, b2), success(Coll[Box](b2), 1776, costDetails3, 1776, Seq.fill(4)(2040)))
)
},
existingFeature({ (x: Coll[Box]) => x.filter({ (b: Box) => b.value > 1 }) },
@@ -6710,13 +6521,13 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
Seq(
- (Coll[Box](), Expected(Success(Coll[Byte]()), 1773, costDetails1, 1773)),
+ (Coll[Box](), Expected(Success(Coll[Byte]()), 1773, costDetails1, 1773, Seq.fill(4)(2029))),
(Coll[Box](b1), Expected(Success(Helpers.decodeBytes(
"0008ce02c1a9311ecf1e76c787ba4b1c0e10157b4f6d1e4db3ef0d84f411c99f2d4d2c5b027d1bd9a437e73726ceddecc162e5c85f79aee4798505bc826b8ad1813148e4190257cff6d06fe15d1004596eeb97a7f67755188501e36adc49bd807fe65e9d8281033c6021cff6ba5fdfc4f1742486030d2ebbffd9c9c09e488792f3102b2dcdabd5"
- )), 1791, costDetails2, 1791)),
+ )), 1791, costDetails2, 1791, Seq.fill(4)(2047))),
(Coll[Box](b1, b2), Expected(Success(Helpers.decodeBytes(
"0008ce02c1a9311ecf1e76c787ba4b1c0e10157b4f6d1e4db3ef0d84f411c99f2d4d2c5b027d1bd9a437e73726ceddecc162e5c85f79aee4798505bc826b8ad1813148e4190257cff6d06fe15d1004596eeb97a7f67755188501e36adc49bd807fe65e9d8281033c6021cff6ba5fdfc4f1742486030d2ebbffd9c9c09e488792f3102b2dcdabd500d197830201010096850200"
- )), 1795, costDetails3, 1795))
+ )), 1795, costDetails3, 1795, Seq.fill(4)(2051)))
)
},
existingFeature({ (x: Coll[Box]) => x.flatMap({ (b: Box) => b.propositionBytes }) },
@@ -6749,11 +6560,12 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T, c: Int, cd: CostDetails, nc: Int) = Expected(Success(v), c, cd, nc)
+ def success[T](v: T, c: Int, cd: CostDetails, nc: Int, v3Costs: Seq[Int]) = Expected(Success(v), c, cd, nc, v3Costs)
+
Seq(
- (Coll[Box](), success(Coll[(Box, Box)](), 1766, costDetails(0), 1766)),
- (Coll[Box](b1), success(Coll[(Box, Box)]((b1, b1)), 1768, costDetails(1), 1768)),
- (Coll[Box](b1, b2), success(Coll[(Box, Box)]((b1, b1), (b2, b2)), 1770, costDetails(2), 1770))
+ (Coll[Box](), success(Coll[(Box, Box)](), 1766, costDetails(0), 1766, Seq.fill(4)(2018))),
+ (Coll[Box](b1), success(Coll[(Box, Box)]((b1, b1)), 1768, costDetails(1), 1768, Seq.fill(4)(2020))),
+ (Coll[Box](b1, b2), success(Coll[(Box, Box)]((b1, b1), (b2, b2)), 1770, costDetails(2), 1770, Seq.fill(4)(2022)))
)
},
existingFeature({ (x: Coll[Box]) => x.zip(x) },
@@ -6779,7 +6591,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val costDetails = TracedCost(traceBase :+ FixedCostItem(SizeOf))
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1765, costDetails, 1765)
+ def success[T](v: T) = Expected(Success(v), 1765, costDetails, 1765, Seq.fill(4)(2001))
Seq(
(Coll[Box](), success(0)),
(Coll[Box](b1), success(1)),
@@ -6804,7 +6616,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
{
- def success[T](v: T, i: Int) = Expected(Success(v), 1768, costDetails(i), 1768)
+ def success[T](v: T, i: Int) = Expected(Success(v), 1768, costDetails(i), 1768, Seq.fill(4)(2008))
Seq(
(Coll[Box](), success(Coll[Int](), 0)),
(Coll[Box](b1), success(Coll[Int](0), 1)),
@@ -6860,9 +6672,9 @@ class SigmaDslSpecification extends SigmaDslTesting
)
def cases = {
Seq(
- (Coll[Box](), Expected(Success(true), 1764, costDetails1, 1764)),
- (Coll[Box](b1), Expected(Success(false), 1769, costDetails2, 1769)),
- (Coll[Box](b1, b2), Expected(Success(false), 1769, costDetails3, 1769))
+ (Coll[Box](), Expected(Success(true), 1764, costDetails1, 1764, Seq.fill(4)(2026))),
+ (Coll[Box](b1), Expected(Success(false), 1769, costDetails2, 1769, Seq.fill(4)(2031))),
+ (Coll[Box](b1, b2), Expected(Success(false), 1769, costDetails3, 1769, Seq.fill(4)(2031)))
)
}
if (lowerMethodCallsInTests) {
@@ -6939,9 +6751,9 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
Seq(
- (Coll[Box](), Expected(Success(false), 1764, costDetails1, 1764)),
- (Coll[Box](b1), Expected(Success(false), 1769, costDetails2, 1769)),
- (Coll[Box](b1, b2), Expected(Success(true), 1773, costDetails3, 1773))
+ (Coll[Box](), Expected(Success(false), 1764, costDetails1, 1764, Seq.fill(4)(2026))),
+ (Coll[Box](b1), Expected(Success(false), 1769, costDetails2, 1769, Seq.fill(4)(2031))),
+ (Coll[Box](b1, b2), Expected(Success(true), 1773, costDetails3, 1773, Seq.fill(4)(2035)))
)
},
existingFeature({ (x: Coll[Box]) => x.exists({ (b: Box) => b.value > 1 }) },
@@ -7032,11 +6844,11 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
Seq(
- (Coll[BigInt](), Expected(Success(false), 1764, costDetails1, 1764)),
- (Coll[BigInt](BigIntZero), Expected(Success(false), 1769, costDetails2, 1769)),
- (Coll[BigInt](BigIntOne), Expected(Success(true), 1772, costDetails3, 1772)),
- (Coll[BigInt](BigIntZero, BigIntOne), Expected(Success(true), 1777, costDetails4, 1777)),
- (Coll[BigInt](BigIntZero, BigInt10), Expected(Success(false), 1777, costDetails4, 1777))
+ (Coll[BigInt](), Expected(Success(false), 1764, costDetails1, 1764, Seq.fill(4)(2048))),
+ (Coll[BigInt](BigIntZero), Expected(Success(false), 1769, costDetails2, 1769, Seq.fill(4)(2053))),
+ (Coll[BigInt](BigIntOne), Expected(Success(true), 1772, costDetails3, 1772, Seq.fill(4)(2056))),
+ (Coll[BigInt](BigIntZero, BigIntOne), Expected(Success(true), 1777, costDetails4, 1777, Seq.fill(4)(2061))),
+ (Coll[BigInt](BigIntZero, BigInt10), Expected(Success(false), 1777, costDetails4, 1777, Seq.fill(4)(2061)))
)
},
existingFeature(
@@ -7147,11 +6959,11 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
Seq(
- (Coll[BigInt](), Expected(Success(true), 1764, costDetails1, 1764)),
- (Coll[BigInt](BigIntMinusOne), Expected(Success(false), 1769, costDetails2, 1769)),
- (Coll[BigInt](BigIntOne), Expected(Success(true), 1772, costDetails3, 1772)),
- (Coll[BigInt](BigIntZero, BigIntOne), Expected(Success(true), 1779, costDetails4, 1779)),
- (Coll[BigInt](BigIntZero, BigInt11), Expected(Success(false), 1779, costDetails4, 1779))
+ (Coll[BigInt](), Expected(Success(true), 1764, costDetails1, 1764, Seq.fill(4)(2048))),
+ (Coll[BigInt](BigIntMinusOne), Expected(Success(false), 1769, costDetails2, 1769, Seq.fill(4)(2053))),
+ (Coll[BigInt](BigIntOne), Expected(Success(true), 1772, costDetails3, 1772, Seq.fill(4)(2056))),
+ (Coll[BigInt](BigIntZero, BigIntOne), Expected(Success(true), 1779, costDetails4, 1779, Seq.fill(4)(2063))),
+ (Coll[BigInt](BigIntZero, BigInt11), Expected(Success(false), 1779, costDetails4, 1779, Seq.fill(4)(2063)))
)
},
existingFeature(
@@ -7281,28 +7093,34 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T, c: Int, cd: CostDetails, newCost: Int) = Expected(Success(v), c, cd, newCost)
+ def success[T](v: T, c: Int, cd: CostDetails, newCost: Int, expectedV3Costs: Seq[Int]) = Expected(Success(v), c, cd, newCost, expectedV3Costs)
+
Seq(
- Coll[GroupElement]() -> Expected(Success(Coll[Byte]()), 1773, CostDetails.ZeroCost, 1773,
- newVersionedResults = {
- val res = ExpectedResult(Success(Coll[Byte]()), Some(1773))
- Seq.tabulate(3)(v =>
- v -> (res -> Some(costDetails0))
- )
- }),
+ Coll[GroupElement]() -> Expected(Success(Coll[Byte]()), 1773, CostDetails.ZeroCost, 1773,
+ newVersionedResults = {
+ val costs = if (activatedVersionInTests >= V6SoftForkVersion) {
+ Seq.fill(4)(2029)
+ }
+ else {
+ Seq.fill(4)(1773)
+ }
+ Seq.tabulate(4)(v =>
+ v -> (ExpectedResult(Success(Coll[Byte]()), Some(costs(v))) -> Some(costDetails0))
+ )
+ }),
Coll[GroupElement](
Helpers.decodeGroupElement("02d65904820f8330218cf7318b3810d0c9ab9df86f1ee6100882683f23c0aee587"),
Helpers.decodeGroupElement("0390e9daa9916f30d0bc61a8e381c6005edfb7938aee5bb4fc9e8a759c7748ffaa")) ->
- success(Helpers.decodeBytes(
- "02d65904820f8330218cf7318b3810d0c9ab9df86f1ee6100882683f23c0aee5870390e9daa9916f30d0bc61a8e381c6005edfb7938aee5bb4fc9e8a759c7748ffaa"
- ), 1834, costDetails2, 1834),
+ success(Helpers.decodeBytes(
+ "02d65904820f8330218cf7318b3810d0c9ab9df86f1ee6100882683f23c0aee5870390e9daa9916f30d0bc61a8e381c6005edfb7938aee5bb4fc9e8a759c7748ffaa"
+ ), 1834, costDetails2, 1834, Seq.fill(4)(2090)),
Coll[GroupElement](
Helpers.decodeGroupElement("02d65904820f8330218cf7318b3810d0c9ab9df86f1ee6100882683f23c0aee587"),
Helpers.decodeGroupElement("0390e9daa9916f30d0bc61a8e381c6005edfb7938aee5bb4fc9e8a759c7748ffaa"),
Helpers.decodeGroupElement("03bd839b969b02d218fd1192f2c80cbda9c6ce9c7ddb765f31b748f4666203df85")) ->
- success(Helpers.decodeBytes(
- "02d65904820f8330218cf7318b3810d0c9ab9df86f1ee6100882683f23c0aee5870390e9daa9916f30d0bc61a8e381c6005edfb7938aee5bb4fc9e8a759c7748ffaa03bd839b969b02d218fd1192f2c80cbda9c6ce9c7ddb765f31b748f4666203df85"
- ), 1864, costDetails3, 1864)
+ success(Helpers.decodeBytes(
+ "02d65904820f8330218cf7318b3810d0c9ab9df86f1ee6100882683f23c0aee5870390e9daa9916f30d0bc61a8e381c6005edfb7938aee5bb4fc9e8a759c7748ffaa03bd839b969b02d218fd1192f2c80cbda9c6ce9c7ddb765f31b748f4666203df85"
+ ), 1864, costDetails3, 1864, Seq.fill(4)(2120))
)
},
existingFeature(
@@ -7340,11 +7158,17 @@ class SigmaDslSpecification extends SigmaDslTesting
) -> Expected(res, 1840,
expectedDetails = CostDetails.ZeroCost,
newCost = 1840,
- newVersionedResults = (0 to 2).map(version =>
+ newVersionedResults = (0 to 3).map({ version =>
+ val costs = if (activatedVersionInTests >= V6SoftForkVersion) {
+ Seq.fill(4)(2104)
+ }
+ else {
+ Seq.fill(4)(1840)
+ }
// successful result for each version
version -> (ExpectedResult(res,
- verificationCost = Some(1840)) -> Some(costDetails4))
- ))
+ verificationCost = Some(costs(version))) -> Some(costDetails4))
+ }))
)
}
val f = existingFeature(
@@ -7410,7 +7234,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T, cd: CostDetails) = Expected(Success(v), 1776, cd, 1776)
+ def success[T](v: T, cd: CostDetails) = Expected(Success(v), 1776, cd, 1776, Seq.fill(4)(2072))
Seq(
((Coll[Int](), (0, 0)), success(Coll[Int](), costDetails(0))),
((Coll[Int](1), (0, 0)), success(Coll[Int](1, 1), costDetails(2))),
@@ -7499,7 +7323,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
// (coll, (index, elem))
{
- def success[T](v: T, cd: CostDetails) = Expected(Success(v), 1774, cd, 1774)
+ def success[T](v: T, cd: CostDetails) = Expected(Success(v), 1774, cd, 1774, Seq.fill(4)(2058))
Seq(
((Coll[Int](), (0, 0)), Expected(new IndexOutOfBoundsException("0"))),
((Coll[Int](1), (0, 0)), success(Coll[Int](0), costDetails(1))),
@@ -7576,7 +7400,7 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
// (coll, (indexes, values))
{
- def success[T](v: T, i: Int) = Expected(Success(v), 1774, costDetails(i), 1774)
+ def success[T](v: T, i: Int) = Expected(Success(v), 1774, costDetails(i), 1774, Seq.fill(4)(2066))
Seq(
((Coll[Int](), (Coll(0), Coll(0))), Expected(new IndexOutOfBoundsException("0"))),
((Coll[Int](), (Coll(0, 1), Coll(0, 0))), Expected(new IndexOutOfBoundsException("0"))),
@@ -7638,36 +7462,6 @@ class SigmaDslSpecification extends SigmaDslTesting
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(
@@ -7753,15 +7547,15 @@ class SigmaDslSpecification extends SigmaDslTesting
// (coll, initState)
{
Seq(
- ((Coll[Byte](), 0), Expected(Success(0), 1767, costDetails1, 1767)),
- ((Coll[Byte](), Int.MaxValue), Expected(Success(Int.MaxValue), 1767, costDetails1, 1767)),
- ((Coll[Byte](1), Int.MaxValue - 1), Expected(Success(Int.MaxValue), 1773, costDetails2, 1773)),
- ((Coll[Byte](1), Int.MaxValue), Expected(new ArithmeticException("integer overflow"))),
- ((Coll[Byte](-1), Int.MinValue + 1), Expected(Success(Int.MinValue), 1773, costDetails2, 1773)),
- ((Coll[Byte](-1), Int.MinValue), Expected(new ArithmeticException("integer overflow"))),
- ((Coll[Byte](1, 2), 0), Expected(Success(3), 1779, costDetails3, 1779)),
- ((Coll[Byte](1, -1), 0), Expected(Success(0), 1779, costDetails3, 1779)),
- ((Coll[Byte](1, -1, 1), 0), Expected(Success(1), 1785, costDetails4, 1785))
+ ((Coll[Byte](), 0), Expected(Success(0), 1767, costDetails1, 1767, Seq.fill(4)(2049))),
+ ((Coll[Byte](), Int.MaxValue), Expected(Success(Int.MaxValue), 1767, costDetails1, 1767, Seq.fill(4)(2049))),
+ ((Coll[Byte](1), Int.MaxValue - 1), Expected(Success(Int.MaxValue), 1773, costDetails2, 1773, Seq.fill(4)(2055))),
+ ((Coll[Byte](1), Int.MaxValue), Expected(new ArithmeticException("integer overflow"))),
+ ((Coll[Byte](-1), Int.MinValue + 1), Expected(Success(Int.MinValue), 1773, costDetails2, 1773, Seq.fill(4)(2055))),
+ ((Coll[Byte](-1), Int.MinValue), Expected(new ArithmeticException("integer overflow"))),
+ ((Coll[Byte](1, 2), 0), Expected(Success(3), 1779, costDetails3, 1779, Seq.fill(4)(2061))),
+ ((Coll[Byte](1, -1), 0), Expected(Success(0), 1779, costDetails3, 1779, Seq.fill(4)(2061))),
+ ((Coll[Byte](1, -1, 1), 0), Expected(Success(1), 1785, costDetails4, 1785, Seq.fill(4)(2067)))
)
},
existingFeature(
@@ -8014,15 +7808,15 @@ class SigmaDslSpecification extends SigmaDslTesting
// (coll, initState)
{
Seq(
- ((Coll[Byte](), 0), Expected(Success(0), 1767, costDetails1, 1767)),
- ((Coll[Byte](), Int.MaxValue), Expected(Success(Int.MaxValue), 1767, costDetails1, 1767)),
- ((Coll[Byte](1), Int.MaxValue - 1), Expected(Success(Int.MaxValue), 1779, costDetails2, 1779)),
- ((Coll[Byte](1), Int.MaxValue), Expected(new ArithmeticException("integer overflow"))),
- ((Coll[Byte](-1), Int.MinValue + 1), Expected(Success(Int.MinValue + 1), 1777, costDetails3, 1777)),
- ((Coll[Byte](-1), Int.MinValue), Expected(Success(Int.MinValue), 1777, costDetails3, 1777)),
- ((Coll[Byte](1, 2), 0), Expected(Success(3), 1791, costDetails4, 1791)),
- ((Coll[Byte](1, -1), 0), Expected(Success(1), 1789, costDetails5, 1789)),
- ((Coll[Byte](1, -1, 1), 0), Expected(Success(2), 1801, costDetails6, 1801))
+ ((Coll[Byte](), 0), Expected(Success(0), 1767, costDetails1, 1767, Seq.fill(4)(2089))),
+ ((Coll[Byte](), Int.MaxValue), Expected(Success(Int.MaxValue), 1767, costDetails1, 1767, Seq.fill(4)(2089))),
+ ((Coll[Byte](1), Int.MaxValue - 1), Expected(Success(Int.MaxValue), 1779, costDetails2, 1779, Seq.fill(4)(2101))),
+ ((Coll[Byte](1), Int.MaxValue), Expected(new ArithmeticException("integer overflow"))),
+ ((Coll[Byte](-1), Int.MinValue + 1), Expected(Success(Int.MinValue + 1), 1777, costDetails3, 1777, Seq.fill(4)(2099))),
+ ((Coll[Byte](-1), Int.MinValue), Expected(Success(Int.MinValue), 1777, costDetails3, 1777, Seq.fill(4)(2099))),
+ ((Coll[Byte](1, 2), 0), Expected(Success(3), 1791, costDetails4, 1791, Seq.fill(4)(2113))),
+ ((Coll[Byte](1, -1), 0), Expected(Success(1), 1789, costDetails5, 1789, Seq.fill(4)(2111))),
+ ((Coll[Byte](1, -1, 1), 0), Expected(Success(2), 1801, costDetails6, 1801, Seq.fill(4)(2123)))
)
},
existingFeature(
@@ -8133,11 +7927,16 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
// (coll, (elem: Byte, from: Int))
{
- def success0[T](v: T) = Expected(Success(v), 1773, costDetails(0), 1773)
- def success1[T](v: T) = Expected(Success(v), 1773, costDetails(1), 1773)
- def success2[T](v: T) = Expected(Success(v), 1774, costDetails(2), 1774)
- def success3[T](v: T) = Expected(Success(v), 1775, costDetails(3), 1775)
- def success12[T](v: T) = Expected(Success(v), 1782, costDetails(12), 1782)
+ def success0[T](v: T) = Expected(Success(v), 1773, costDetails(0), 1773, Seq.fill(4)(2061))
+
+ def success1[T](v: T) = Expected(Success(v), 1773, costDetails(1), 1773, Seq.fill(4)(2061))
+
+ def success2[T](v: T) = Expected(Success(v), 1774, costDetails(2), 1774, Seq.fill(4)(2062))
+
+ def success3[T](v: T) = Expected(Success(v), 1775, costDetails(3), 1775, Seq.fill(4)(2063))
+
+ def success12[T](v: T) = Expected(Success(v), 1782, costDetails(12), 1782, Seq.fill(4)(2070))
+
Seq(
((Coll[Byte](), (0.toByte, 0)), success0(-1)),
((Coll[Byte](), (0.toByte, -1)), success0(-1)),
@@ -8199,7 +7998,8 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1769, costDetails, 1769)
+ def success[T](v: T) = Expected(Success(v), 1769, costDetails, 1769, Seq.fill(4)(2019))
+
Seq(
((Coll[Int](), 0), Expected(new ArrayIndexOutOfBoundsException("0"))),
((Coll[Int](), -1), Expected(new ArrayIndexOutOfBoundsException("-1"))),
@@ -8260,10 +8060,11 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
)
+ if(!VersionContext.current.isV6SoftForkActivated) {
verifyCases(
// (coll, (index, default))
{
- def success[T](v: T) = Expected(Success(v), 1773, costDetails, 1773)
+ def success[T](v: T) = Expected(Success(v), 1773, costDetails, 1773, Seq.fill(4)(2053))
Seq(
((Coll[Int](), (0, default)), success(default)),
((Coll[Int](), (-1, default)), success(default)),
@@ -8330,7 +8131,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
)
- ))
+ ))}
}
property("Tuple size method equivalence") {
@@ -8346,7 +8147,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
{
- def success[T](v: T) = Expected(Success(v), 1763, costDetails, 1763)
+ def success[T](v: T) = Expected(Success(v), 1763, costDetails, 1763, Seq.fill(4)(1997))
Seq(
((0, 0), success(2)),
((1, 2), success(2))
@@ -8361,7 +8162,7 @@ class SigmaDslSpecification extends SigmaDslTesting
val samples = genSamples[(Int, Int)](DefaultMinSuccessful)
val costDetails = TracedCost(traceBase :+ FixedCostItem(SelectField))
verifyCases(
- Seq(((1, 2), Expected(Success(1), cost = 1764, costDetails, 1764))),
+ Seq(((1, 2), Expected(Success(1), cost = 1764, costDetails, 1764, Seq.fill(4)(1998)))),
existingFeature((x: (Int, Int)) => x._1,
"{ (x: (Int, Int)) => x(0) }",
FuncValue(
@@ -8370,7 +8171,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)),
preGeneratedSamples = Some(samples))
verifyCases(
- Seq(((1, 2), Expected(Success(2), cost = 1764, costDetails, 1764))),
+ Seq(((1, 2), Expected(Success(2), cost = 1764, costDetails, 1764, Seq.fill(4)(1998)))),
existingFeature((x: (Int, Int)) => x._2,
"{ (x: (Int, Int)) => x(1) }",
FuncValue(
@@ -8412,9 +8213,9 @@ class SigmaDslSpecification extends SigmaDslTesting
{
def success[T](v: T, c: Int) = Expected(Success(v), c)
Seq(
- (Coll[Int](), Expected(Success(Coll[Int]()), 1768, costDetails(0), 1768)),
- (Coll[Int](1), Expected(Success(Coll[Int](2)), 1771, costDetails(1), 1771)),
- (Coll[Int](1, 2), Expected(Success(Coll[Int](2, 3)), 1774, costDetails(2), 1774)),
+ (Coll[Int](), Expected(Success(Coll[Int]()), 1768, costDetails(0), 1768, Seq.fill(4)(2022))),
+ (Coll[Int](1), Expected(Success(Coll[Int](2)), 1771, costDetails(1), 1771, Seq.fill(4)(2025))),
+ (Coll[Int](1, 2), Expected(Success(Coll[Int](2, 3)), 1774, costDetails(2), 1774, Seq.fill(4)(2028))),
(Coll[Int](1, 2, Int.MaxValue), Expected(new ArithmeticException("integer overflow")))
)
},
@@ -8508,10 +8309,10 @@ class SigmaDslSpecification extends SigmaDslTesting
{
def success[T](v: T, c: Int) = Expected(Success(v), c)
Seq(
- (Coll[Int](), Expected(Success(Coll[Int]()), 1768, costDetails1, 1768)),
- (Coll[Int](1), Expected(Success(Coll[Int](2)), 1775, costDetails2, 1775)),
- (Coll[Int](-1), Expected(Success(Coll[Int](1)), 1775, costDetails3, 1775)),
- (Coll[Int](1, -2), Expected(Success(Coll[Int](2, 2)), 1782, costDetails4, 1782)),
+ (Coll[Int](), Expected(Success(Coll[Int]()), 1768, costDetails1, 1768, Seq.fill(4)(2054))),
+ (Coll[Int](1), Expected(Success(Coll[Int](2)), 1775, costDetails2, 1775, Seq.fill(4)(2061))),
+ (Coll[Int](-1), Expected(Success(Coll[Int](1)), 1775, costDetails3, 1775, Seq.fill(4)(2061))),
+ (Coll[Int](1, -2), Expected(Success(Coll[Int](2, 2)), 1782, costDetails4, 1782, Seq.fill(4)(2068))),
(Coll[Int](1, 2, Int.MaxValue), Expected(new ArithmeticException("integer overflow"))),
(Coll[Int](1, 2, Int.MinValue), Expected(new ArithmeticException("integer overflow")))
)
@@ -8559,24 +8360,24 @@ class SigmaDslSpecification extends SigmaDslTesting
val o = ExactOrdering.IntIsExactOrdering
verifyCases(
- {
- Seq(
- (Coll[Int](), Expected(Success(Coll[Int]()), 1768, costDetails(0), 1768)),
- (Coll[Int](1), Expected(Success(Coll[Int](1)), 1771, costDetails(1), 1771)),
- (Coll[Int](1, 2), Expected(Success(Coll[Int](1, 2)), 1775, costDetails(2), 1775)),
- (Coll[Int](1, 2, -1), Expected(Success(Coll[Int](1, 2)), 1778, costDetails(3), 1778)),
- (Coll[Int](1, -1, 2, -2), Expected(Success(Coll[Int](1, 2)), 1782, costDetails(4), 1782))
- )
- },
- existingFeature((x: Coll[Int]) => x.filter({ (v: Int) => o.gt(v, 0) }),
- "{ (x: Coll[Int]) => x.filter({ (v: Int) => v > 0 }) }",
- FuncValue(
- Array((1, SCollectionType(SInt))),
- Filter(
- ValUse(1, SCollectionType(SInt)),
- FuncValue(Array((3, SInt)), GT(ValUse(3, SInt), IntConstant(0)))
+ {
+ Seq(
+ (Coll[Int](), Expected(Success(Coll[Int]()), 1768, costDetails(0), 1768, Seq.fill(4)(2022))),
+ (Coll[Int](1), Expected(Success(Coll[Int](1)), 1771, costDetails(1), 1771, Seq.fill(4)(2025))),
+ (Coll[Int](1, 2), Expected(Success(Coll[Int](1, 2)), 1775, costDetails(2), 1775, Seq.fill(4)(2029))),
+ (Coll[Int](1, 2, -1), Expected(Success(Coll[Int](1, 2)), 1778, costDetails(3), 1778, Seq.fill(4)(2032))),
+ (Coll[Int](1, -1, 2, -2), Expected(Success(Coll[Int](1, 2)), 1782, costDetails(4), 1782, Seq.fill(4)(2036)))
)
- )))
+ },
+ existingFeature((x: Coll[Int]) => x.filter({ (v: Int) => o.gt(v, 0) }),
+ "{ (x: Coll[Int]) => x.filter({ (v: Int) => v > 0 }) }",
+ FuncValue(
+ Array((1, SCollectionType(SInt))),
+ Filter(
+ ValUse(1, SCollectionType(SInt)),
+ FuncValue(Array((3, SInt)), GT(ValUse(3, SInt), IntConstant(0)))
+ )
+ )))
}
property("Coll filter with nested If") {
@@ -8634,29 +8435,30 @@ class SigmaDslSpecification extends SigmaDslTesting
val o = ExactOrdering.IntIsExactOrdering
verifyCases(
- {
- def success[T](v: T, c: Int) = Expected(Success(v), c)
- Seq(
- (Coll[Int](), Expected(Success(Coll[Int]()), 1768, costDetails(0), 1768)),
- (Coll[Int](1), Expected(Success(Coll[Int](1)), 1775, costDetails(1), 1775)),
- (Coll[Int](10), Expected(Success(Coll[Int]()), 1775, costDetails(1), 1775)),
- (Coll[Int](1, 2), Expected(Success(Coll[Int](1, 2)), 1783, costDetails(2), 1783)),
- (Coll[Int](1, 2, 0), Expected(Success(Coll[Int](1, 2)), 1788, costDetails3, 1788)),
- (Coll[Int](1, -1, 2, -2, 11), Expected(Success(Coll[Int](1, 2)), 1800, costDetails5, 1800))
- )
- },
- existingFeature((x: Coll[Int]) => x.filter({ (v: Int) => if (o.gt(v, 0)) v < 10 else false }),
- "{ (x: Coll[Int]) => x.filter({ (v: Int) => if (v > 0) v < 10 else false }) }",
- FuncValue(
- Array((1, SCollectionType(SInt))),
- Filter(
- ValUse(1, SCollectionType(SInt)),
- FuncValue(
- Array((3, SInt)),
- If(GT(ValUse(3, SInt), IntConstant(0)), LT(ValUse(3, SInt), IntConstant(10)), FalseLeaf)
- )
+ {
+ def success[T](v: T, c: Int) = Expected(Success(v), c)
+
+ Seq(
+ (Coll[Int](), Expected(Success(Coll[Int]()), 1768, costDetails(0), 1768, Seq.fill(4)(2048))),
+ (Coll[Int](1), Expected(Success(Coll[Int](1)), 1775, costDetails(1), 1775, Seq.fill(4)(2055))),
+ (Coll[Int](10), Expected(Success(Coll[Int]()), 1775, costDetails(1), 1775, Seq.fill(4)(2055))),
+ (Coll[Int](1, 2), Expected(Success(Coll[Int](1, 2)), 1783, costDetails(2), 1783, Seq.fill(4)(2063))),
+ (Coll[Int](1, 2, 0), Expected(Success(Coll[Int](1, 2)), 1788, costDetails3, 1788, Seq.fill(4)(2068))),
+ (Coll[Int](1, -1, 2, -2, 11), Expected(Success(Coll[Int](1, 2)), 1800, costDetails5, 1800, Seq.fill(4)(2080)))
)
- )))
+ },
+ existingFeature((x: Coll[Int]) => x.filter({ (v: Int) => if (o.gt(v, 0)) v < 10 else false }),
+ "{ (x: Coll[Int]) => x.filter({ (v: Int) => if (v > 0) v < 10 else false }) }",
+ FuncValue(
+ Array((1, SCollectionType(SInt))),
+ Filter(
+ ValUse(1, SCollectionType(SInt)),
+ FuncValue(
+ Array((3, SInt)),
+ If(GT(ValUse(3, SInt), IntConstant(0)), LT(ValUse(3, SInt), IntConstant(10)), FalseLeaf)
+ )
+ )
+ )))
}
property("Coll slice method equivalence") {
@@ -8683,48 +8485,49 @@ class SigmaDslSpecification extends SigmaDslTesting
val samples = genSamples(collWithRangeGen, DefaultMinSuccessful)
if (lowerMethodCallsInTests) {
verifyCases(
- {
- val cost = 1772
- val newCost = 1772
- Seq(
- // (coll, (from, until))
- ((Coll[Int](), (-1, 0)), Expected(Success(Coll[Int]()), cost, costDetails(1), newCost)),
- ((Coll[Int](), (0, 0)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost)),
- ((Coll[Int](1), (0, 0)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost)),
- ((Coll[Int](1), (0, -1)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost)),
- ((Coll[Int](1), (1, 1)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost)),
- ((Coll[Int](1), (-1, 1)), Expected(Success(Coll[Int](1)), cost, costDetails(2), newCost)),
- ((Coll[Int](1, 2), (1, 1)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost)),
- ((Coll[Int](1, 2), (1, 0)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost)),
- ((Coll[Int](1, 2), (1, 2)), Expected(Success(Coll[Int](2)), cost, costDetails(1), newCost)),
- ((Coll[Int](1, 2, 3, 4), (1, 3)), Expected(Success(Coll[Int](2, 3)), cost, costDetails(2), newCost))
- )
- },
- existingFeature((x: (Coll[Int], (Int, Int))) => x._1.slice(x._2._1, x._2._2),
- "{ (x: (Coll[Int], (Int, Int))) => x._1.slice(x._2._1, x._2._2) }",
- FuncValue(
- Vector((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))),
- BlockValue(
- Vector(
- ValDef(
- 3,
- List(),
- SelectField.typed[Value[STuple]](
- ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))),
- 2.toByte
+ {
+ val cost = 1772
+ val newCost = 1772
+ val v3Costs = Seq.fill(4)(2050)
+ Seq(
+ // (coll, (from, until))
+ ((Coll[Int](), (-1, 0)), Expected(Success(Coll[Int]()), cost, costDetails(1), newCost, v3Costs)),
+ ((Coll[Int](), (0, 0)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost, v3Costs)),
+ ((Coll[Int](1), (0, 0)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost, v3Costs)),
+ ((Coll[Int](1), (0, -1)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost, v3Costs)),
+ ((Coll[Int](1), (1, 1)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost, v3Costs)),
+ ((Coll[Int](1), (-1, 1)), Expected(Success(Coll[Int](1)), cost, costDetails(2), newCost, v3Costs)),
+ ((Coll[Int](1, 2), (1, 1)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost, v3Costs)),
+ ((Coll[Int](1, 2), (1, 0)), Expected(Success(Coll[Int]()), cost, costDetails(0), newCost, v3Costs)),
+ ((Coll[Int](1, 2), (1, 2)), Expected(Success(Coll[Int](2)), cost, costDetails(1), newCost, v3Costs)),
+ ((Coll[Int](1, 2, 3, 4), (1, 3)), Expected(Success(Coll[Int](2, 3)), cost, costDetails(2), newCost, v3Costs))
+ )
+ },
+ existingFeature((x: (Coll[Int], (Int, Int))) => x._1.slice(x._2._1, x._2._2),
+ "{ (x: (Coll[Int], (Int, Int))) => x._1.slice(x._2._1, x._2._2) }",
+ FuncValue(
+ Vector((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))),
+ BlockValue(
+ Vector(
+ ValDef(
+ 3,
+ List(),
+ SelectField.typed[Value[STuple]](
+ ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))),
+ 2.toByte
+ )
)
- )
- ),
- Slice(
- SelectField.typed[Value[SCollection[SInt.type]]](
- ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))),
- 1.toByte
),
- SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte),
- SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte)
+ Slice(
+ SelectField.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))),
+ 1.toByte
+ ),
+ SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte),
+ SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte)
+ )
)
- )
- )),
+ )),
preGeneratedSamples = Some(samples))
} else {
def error = new java.lang.NoSuchMethodException("sigmastate.SCollection$.slice_eval(sigmastate.lang.Terms$MethodCall,sigma.Coll,int,int,sigmastate.interpreter.ErgoTreeEvaluator))")
@@ -8774,37 +8577,38 @@ class SigmaDslSpecification extends SigmaDslTesting
)
if (lowerMethodCallsInTests) {
verifyCases(
- {
- def success[T](v: T, size: Int) = Expected(Success(v), 1770, costDetails(size), 1770)
- val arr1 = Gen.listOfN(100, arbitrary[Int]).map(_.toArray).sample.get
- val arr2 = Gen.listOfN(200, arbitrary[Int]).map(_.toArray).sample.get
- Seq(
- (Coll[Int](), Coll[Int]()) -> success(Coll[Int](), 0),
- (Coll[Int](), Coll[Int](1)) -> success(Coll[Int](1), 1),
- (Coll[Int](1), Coll[Int]()) -> success(Coll[Int](1), 1),
- (Coll[Int](1), Coll[Int](2)) -> success(Coll[Int](1, 2), 2),
- (Coll[Int](1), Coll[Int](2, 3)) -> success(Coll[Int](1, 2, 3), 3),
- (Coll[Int](1, 2), Coll[Int](3)) -> success(Coll[Int](1, 2, 3), 3),
- (Coll[Int](1, 2), Coll[Int](3, 4)) -> success(Coll[Int](1, 2, 3, 4), 4),
- (Coll[Int](arr1:_*), Coll[Int](arr2:_*)) -> Expected(Success(Coll[Int](arr1 ++ arr2:_*)), 1771, costDetails(300), 1771)
- )
- },
- existingFeature(
- { (x: (Coll[Int], Coll[Int])) => x._1.append(x._2) },
- "{ (x: (Coll[Int], Coll[Int])) => x._1.append(x._2) }",
- FuncValue(
- Vector((1, SPair(SCollectionType(SInt), SCollectionType(SInt)))),
- Append(
- SelectField.typed[Value[SCollection[SInt.type]]](
- ValUse(1, SPair(SCollectionType(SInt), SCollectionType(SInt))),
- 1.toByte
- ),
- SelectField.typed[Value[SCollection[SInt.type]]](
- ValUse(1, SPair(SCollectionType(SInt), SCollectionType(SInt))),
- 2.toByte
- )
+ {
+ def success[T](v: T, size: Int) = Expected(Success(v), 1770, costDetails(size), 1770, Seq.fill(4)(2022))
+
+ val arr1 = Gen.listOfN(100, arbitrary[Int]).map(_.toArray).sample.get
+ val arr2 = Gen.listOfN(200, arbitrary[Int]).map(_.toArray).sample.get
+ Seq(
+ (Coll[Int](), Coll[Int]()) -> success(Coll[Int](), 0),
+ (Coll[Int](), Coll[Int](1)) -> success(Coll[Int](1), 1),
+ (Coll[Int](1), Coll[Int]()) -> success(Coll[Int](1), 1),
+ (Coll[Int](1), Coll[Int](2)) -> success(Coll[Int](1, 2), 2),
+ (Coll[Int](1), Coll[Int](2, 3)) -> success(Coll[Int](1, 2, 3), 3),
+ (Coll[Int](1, 2), Coll[Int](3)) -> success(Coll[Int](1, 2, 3), 3),
+ (Coll[Int](1, 2), Coll[Int](3, 4)) -> success(Coll[Int](1, 2, 3, 4), 4),
+ (Coll[Int](arr1: _*), Coll[Int](arr2: _*)) -> Expected(Success(Coll[Int](arr1 ++ arr2: _*)), 1771, costDetails(300), 1771, Seq.fill(4)(2023))
)
- )))
+ },
+ existingFeature(
+ { (x: (Coll[Int], Coll[Int])) => x._1.append(x._2) },
+ "{ (x: (Coll[Int], Coll[Int])) => x._1.append(x._2) }",
+ FuncValue(
+ Vector((1, SPair(SCollectionType(SInt), SCollectionType(SInt)))),
+ Append(
+ SelectField.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SPair(SCollectionType(SInt), SCollectionType(SInt))),
+ 1.toByte
+ ),
+ SelectField.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SPair(SCollectionType(SInt), SCollectionType(SInt))),
+ 2.toByte
+ )
+ )
+ )))
} else {
def error = new java.lang.NoSuchMethodException("sigmastate.SCollection$.append_eval(sigmastate.lang.Terms$MethodCall,sigma.Coll,sigma.Coll,sigmastate.interpreter.ErgoTreeEvaluator))")
verifyCases(
@@ -8881,33 +8685,35 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
(None -> Expected(new NoSuchElementException("None.get"))),
- (Some(10L) -> Expected(Success(10L), 1765, costDetails1, 1765))),
+ (Some(10L) -> Expected(Success(10L), 1765, costDetails1, 1765, Seq.fill(4)(1997)))),
existingFeature({ (x: Option[Long]) => x.get },
"{ (x: Option[Long]) => x.get }",
FuncValue(Vector((1, SOption(SLong))), OptionGet(ValUse(1, SOption(SLong))))))
verifyCases(
Seq(
- (None -> Expected(Success(false), 1764, costDetails2, 1764)),
- (Some(10L) -> Expected(Success(true), 1764, costDetails2, 1764))),
+ (None -> Expected(Success(false), 1764, costDetails2, 1764, Seq.fill(4)(1996))),
+ (Some(10L) -> Expected(Success(true), 1764, costDetails2, 1764, Seq.fill(4)(1996)))),
existingFeature({ (x: Option[Long]) => x.isDefined },
"{ (x: Option[Long]) => x.isDefined }",
FuncValue(Vector((1, SOption(SLong))), OptionIsDefined(ValUse(1, SOption(SLong))))))
- verifyCases(
- Seq(
- (None -> Expected(Success(1L), 1766, costDetails3, 1766)),
- (Some(10L) -> Expected(Success(10L), 1766, costDetails3, 1766))),
- existingFeature({ (x: Option[Long]) => x.getOrElse(1L) },
- "{ (x: Option[Long]) => x.getOrElse(1L) }",
- FuncValue(Vector((1, SOption(SLong))), OptionGetOrElse(ValUse(1, SOption(SLong)), LongConstant(1L)))))
+ if (!VersionContext.current.isV6SoftForkActivated) {
+ verifyCases(
+ Seq(
+ (None -> Expected(Success(1L), 1766, costDetails3, 1766, Seq.fill(4)(2006))),
+ (Some(10L) -> Expected(Success(10L), 1766, costDetails3, 1766, Seq.fill(4)(2006)))),
+ existingFeature({ (x: Option[Long]) => x.getOrElse(1L) },
+ "{ (x: Option[Long]) => x.getOrElse(1L) }",
+ FuncValue(Vector((1, SOption(SLong))), OptionGetOrElse(ValUse(1, SOption(SLong)), LongConstant(1L)))))
+ }
verifyCases(
Seq(
- (None -> Expected(Success(None), 1766, costDetails4, 1766)),
- (Some(10L) -> Expected(Success(None), 1768, costDetails5, 1768)),
- (Some(1L) -> Expected(Success(Some(1L)), 1769, costDetails5, 1769))),
- existingFeature({ (x: Option[Long]) => x.filter({ (v: Long) => v == 1} ) },
+ (None -> Expected(Success(None), 1766, costDetails4, 1766, Seq.fill(4)(2028))),
+ (Some(10L) -> Expected(Success(None), 1768, costDetails5, 1768, Seq.fill(4)(2030))),
+ (Some(1L) -> Expected(Success(Some(1L)), 1769, costDetails5, 1769, Seq.fill(4)(2031)))),
+ existingFeature({ (x: Option[Long]) => x.filter({ (v: Long) => v == 1 }) },
"{ (x: Option[Long]) => x.filter({ (v: Long) => v == 1 }) }",
FuncValue(
Vector((1, SOption(SLong))),
@@ -8922,8 +8728,8 @@ class SigmaDslSpecification extends SigmaDslTesting
val n = ExactNumeric.LongIsExactNumeric
verifyCases(
Seq(
- (None -> Expected(Success(None), 1766, costDetails6, 1766)),
- (Some(10L) -> Expected(Success(Some(11L)), 1770, costDetails7, 1770)),
+ (None -> Expected(Success(None), 1766, costDetails6, 1766, Seq.fill(4)(2028))),
+ (Some(10L) -> Expected(Success(Some(11L)), 1770, costDetails7, 1770, Seq.fill(4)(2032))),
(Some(Long.MaxValue) -> Expected(new ArithmeticException("long overflow")))),
existingFeature({ (x: Option[Long]) => x.map( (v: Long) => n.plus(v, 1) ) },
"{ (x: Option[Long]) => x.map({ (v: Long) => v + 1 }) }",
@@ -8985,10 +8791,10 @@ class SigmaDslSpecification extends SigmaDslTesting
val o = ExactOrdering.LongIsExactOrdering
verifyCases(
Seq(
- (None -> Expected(Success(None), 1766, costDetails1, 1766)),
- (Some(0L) -> Expected(Success(None), 1771, costDetails2, 1771)),
- (Some(10L) -> Expected(Success(Some(10L)), 1774, costDetails3, 1774)),
- (Some(11L) -> Expected(Success(None), 1774, costDetails3, 1774))),
+ (None -> Expected(Success(None), 1766, costDetails1, 1766, Seq.fill(4)(2052))),
+ (Some(0L) -> Expected(Success(None), 1771, costDetails2, 1771, Seq.fill(4)(2057))),
+ (Some(10L) -> Expected(Success(Some(10L)), 1774, costDetails3, 1774, Seq.fill(4)(2060))),
+ (Some(11L) -> Expected(Success(None), 1774, costDetails3, 1774, Seq.fill(4)(2060)))),
existingFeature(
{ (x: Option[Long]) => x.filter({ (v: Long) => if (o.gt(v, 0L)) v <= 10 else false } ) },
"{ (x: Option[Long]) => x.filter({ (v: Long) => if (v > 0) v <= 10 else false }) }",
@@ -9049,10 +8855,10 @@ class SigmaDslSpecification extends SigmaDslTesting
val n = ExactNumeric.LongIsExactNumeric
verifyCases(
Seq(
- (None -> Expected(Success(None), 1766, costDetails4, 1766)),
- (Some(0L) -> Expected(Success(Some(0L)), 1772, costDetails5, 1772)),
- (Some(10L) -> Expected(Success(Some(10L)), 1772, costDetails5, 1772)),
- (Some(-1L) -> Expected(Success(Some(-2L)), 1774, costDetails6, 1774)),
+ (None -> Expected(Success(None), 1766, costDetails4, 1766, Seq.fill(4)(2048))),
+ (Some(0L) -> Expected(Success(Some(0L)), 1772, costDetails5, 1772, Seq.fill(4)(2054))),
+ (Some(10L) -> Expected(Success(Some(10L)), 1772, costDetails5, 1772, Seq.fill(4)(2054))),
+ (Some(-1L) -> Expected(Success(Some(-2L)), 1774, costDetails6, 1774, Seq.fill(4)(2056))),
(Some(Long.MinValue) -> Expected(new ArithmeticException("long overflow")))),
existingFeature(
{ (x: Option[Long]) => x.map( (v: Long) => if (o.lt(v, 0)) n.minus(v, 1) else v ) },
@@ -9079,17 +8885,6 @@ class SigmaDslSpecification extends SigmaDslTesting
) ))
}
- // 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(
@@ -9116,20 +8911,30 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
Seq(
(None -> Expected(
- value = Failure(new NoSuchElementException("None.get")),
- cost = 0,
- expectedDetails = CostDetails.ZeroCost,
- newCost = 1766,
- newVersionedResults = Seq.tabulate(3)(v => v -> (ExpectedResult(Success(5L), Some(1766)) -> Some(costDetails1)))
- )),
+ value = Failure(new NoSuchElementException("None.get")),
+ cost = 0,
+ expectedDetails = CostDetails.ZeroCost,
+ newCost = 1766,
+ newVersionedResults = Seq.tabulate(4)({ v =>
+ val costs = if (activatedVersionInTests >= V6SoftForkVersion) {
+ Seq.fill(4)(2042)
+ }
+ else {
+ Seq.fill(4)(1766)
+ }
+ v -> (ExpectedResult(Success(5L), Some(costs(v))) -> Some(costDetails1))
+ })
+ )),
(Some(0L) -> Expected(
Success(1L),
cost = 1774,
expectedDetails = costDetails2,
- expectedNewCost = 1774)),
+ expectedNewCost = 1774,
+ expectedV3Costs = Seq.fill(4)(2050))),
(Some(Long.MaxValue) -> Expected(new ArithmeticException("long overflow")))
),
changedFeature(
+ changedInVersion = VersionContext.JitActivationVersion,
scalaFunc = { (x: Option[Long]) =>
def f(opt: Long): Long = n.plus(opt, 1)
if (x.isDefined) f(x.get)
@@ -9194,19 +8999,22 @@ class SigmaDslSpecification extends SigmaDslTesting
Success(Helpers.decodeBytes("0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8")),
1768,
costDetailsBlake(0),
- 1768
+ 1768,
+ Seq.fill(4)(2000)
),
Helpers.decodeBytes("e0ff0105ffffac31010017ff33") -> Expected(
Success(Helpers.decodeBytes("33707eed9aab64874ff2daa6d6a378f61e7da36398fb36c194c7562c9ff846b5")),
1768,
costDetailsBlake(13),
- 1768
+ 1768,
+ Seq.fill(4)(2000)
),
Colls.replicate(1024, 1.toByte) -> Expected(
Success(Helpers.decodeBytes("45d8456fc5d41d1ec1124cb92e41192c1c3ec88f0bf7ae2dc6e9cf75bec22045")),
1773,
costDetailsBlake(1024),
- 1773
+ 1773,
+ Seq.fill(4)(2005)
)
),
existingFeature((x: Coll[Byte]) => SigmaDsl.blake2b256(x),
@@ -9219,19 +9027,22 @@ class SigmaDslSpecification extends SigmaDslTesting
Success(Helpers.decodeBytes("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")),
1774,
costDetailsSha(0),
- 1774
+ 1774,
+ Seq.fill(4)(2006)
),
Helpers.decodeBytes("e0ff0105ffffac31010017ff33") -> Expected(
Success(Helpers.decodeBytes("367d0ec2cdc14aac29d5beb60c2bfc86d5a44a246308659af61c1b85fa2ca2cc")),
1774,
costDetailsSha(13),
- 1774
+ 1774,
+ Seq.fill(4)(2006)
),
Colls.replicate(1024, 1.toByte) -> Expected(
Success(Helpers.decodeBytes("5a648d8015900d89664e00e125df179636301a2d8fa191c1aa2bd9358ea53a69")),
1786,
costDetailsSha(1024),
- 1786
+ 1786,
+ Seq.fill(4)(2018)
)
),
existingFeature((x: Coll[Byte]) => SigmaDsl.sha256(x),
@@ -9241,10 +9052,11 @@ class SigmaDslSpecification extends SigmaDslTesting
property("sigmaProp equivalence") {
val costDetails = TracedCost(traceBase :+ FixedCostItem(BoolToSigmaProp))
+ val v3Costs = Seq.fill(4)(1997)
verifyCases(
Seq(
- (false, Expected(Success(CSigmaProp(TrivialProp.FalseProp)), 1765, costDetails, 1765)),
- (true, Expected(Success(CSigmaProp(TrivialProp.TrueProp)), 1765, costDetails, 1765))),
+ (false, Expected(Success(CSigmaProp(TrivialProp.FalseProp)), 1765, costDetails, 1765, v3Costs)),
+ (true, Expected(Success(CSigmaProp(TrivialProp.TrueProp)), 1765, costDetails, 1765, v3Costs))),
existingFeature((x: Boolean) => sigmaProp(x),
"{ (x: Boolean) => sigmaProp(x) }",
FuncValue(Vector((1, SBoolean)), BoolToSigmaProp(ValUse(1, SBoolean)))))
@@ -9271,7 +9083,7 @@ class SigmaDslSpecification extends SigmaDslTesting
Helpers.decodeECPoint("02614b14a8c6c6b4b7ce017d72fbca7f9218b72c16bdd88f170ffb300b106b9014"),
Helpers.decodeECPoint("034cc5572276adfa3e283a3f1b0f0028afaadeaa362618c5ec43262d8cefe7f004")
)
- )) -> Expected(Success(CSigmaProp(TrivialProp.TrueProp)), 1770, costDetails(1), 1770),
+ )) -> Expected(Success(CSigmaProp(TrivialProp.TrueProp)), 1770, costDetails(1), 1770, Seq.fill(4)(2018)),
Coll[SigmaProp](
CSigmaProp(
ProveDHTuple(
@@ -9299,7 +9111,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
)
)
- ), 1873, costDetails(3), 1873),
+ ), 1873, costDetails(3), 1873, Seq.fill(4)(2121)),
Colls.replicate[SigmaProp](AtLeast.MaxChildrenCount + 1, CSigmaProp(TrivialProp.TrueProp)) ->
Expected(new IllegalArgumentException("Expected input elements count should not exceed 255, actual: 256"))
),
@@ -9331,31 +9143,32 @@ class SigmaDslSpecification extends SigmaDslTesting
verifyCases(
{
- def success[T](v: T, newCost: Int) = Expected(Success(v), newCost, costDetails1, newCost)
+ def success[T](v: T, newCost: Int, expectedV3Costs: Seq[Int]) = Expected(Success(v), newCost, costDetails1, newCost, expectedV3Costs)
+
Seq(
(CSigmaProp(ProveDlog(Helpers.decodeECPoint("02ea9bf6da7f512386c6ca509d40f8c5e7e0ffb3eea5dc3c398443ea17f4510798"))),
- CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
- success(
- CSigmaProp(
- CAND(
- Seq(
- ProveDlog(Helpers.decodeECPoint("02ea9bf6da7f512386c6ca509d40f8c5e7e0ffb3eea5dc3c398443ea17f4510798")),
- ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))
- )
+ CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
+ success(
+ CSigmaProp(
+ CAND(
+ Seq(
+ ProveDlog(Helpers.decodeECPoint("02ea9bf6da7f512386c6ca509d40f8c5e7e0ffb3eea5dc3c398443ea17f4510798")),
+ ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))
)
- ), 1802),
+ )
+ ), 1802, Seq.fill(4)(2048)),
(CSigmaProp(TrivialProp.TrueProp),
- CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
- success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), 1784),
+ CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
+ success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), 1784, Seq.fill(4)(2030)),
(CSigmaProp(TrivialProp.FalseProp),
- CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
- success(CSigmaProp(TrivialProp.FalseProp), 1767),
+ CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
+ success(CSigmaProp(TrivialProp.FalseProp), 1767, Seq.fill(4)(2013)),
(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))),
- CSigmaProp(TrivialProp.TrueProp)) ->
- success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), 1784),
+ CSigmaProp(TrivialProp.TrueProp)) ->
+ success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), 1784, Seq.fill(4)(2030)),
(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))),
- CSigmaProp(TrivialProp.FalseProp)) ->
- success(CSigmaProp(TrivialProp.FalseProp), 1767)
+ CSigmaProp(TrivialProp.FalseProp)) ->
+ success(CSigmaProp(TrivialProp.FalseProp), 1767, Seq.fill(4)(2013))
)
},
existingFeature(
@@ -9375,9 +9188,9 @@ class SigmaDslSpecification extends SigmaDslTesting
{
Seq(
(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), true) ->
- Expected(Success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))), 1786, costDetails2, 1786),
+ Expected(Success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))), 1786, costDetails2, 1786, Seq.fill(4)(2038)),
(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), false) ->
- Expected(Success(CSigmaProp(TrivialProp.FalseProp)), 1769, costDetails2, 1769)
+ Expected(Success(CSigmaProp(TrivialProp.FalseProp)), 1769, costDetails2, 1769, Seq.fill(4)(2021))
)
},
existingFeature(
@@ -9406,32 +9219,33 @@ class SigmaDslSpecification extends SigmaDslTesting
val costDetails1 = TracedCost(testTraceBase :+ ast.SeqCostItem(CompanionDesc(SigmaOr), PerItemCost(JitCost(10), JitCost(2), 1), 2))
verifyCases(
{
- def success[T](v: T, newCost: Int) = Expected(Success(v), newCost, costDetails1, newCost)
+ def success[T](v: T, newCost: Int, v3Costs: Seq[Int]) = Expected(Success(v), newCost, costDetails1, newCost, v3Costs)
+
Seq(
(CSigmaProp(ProveDlog(Helpers.decodeECPoint("02ea9bf6da7f512386c6ca509d40f8c5e7e0ffb3eea5dc3c398443ea17f4510798"))),
- CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
- success(
- CSigmaProp(
- COR(
- Seq(
- ProveDlog(Helpers.decodeECPoint("02ea9bf6da7f512386c6ca509d40f8c5e7e0ffb3eea5dc3c398443ea17f4510798")),
- ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))
- )
+ CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
+ success(
+ CSigmaProp(
+ COR(
+ Seq(
+ ProveDlog(Helpers.decodeECPoint("02ea9bf6da7f512386c6ca509d40f8c5e7e0ffb3eea5dc3c398443ea17f4510798")),
+ ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))
)
- ),
- 1802),
+ )
+ ),
+ 1802, Seq.fill(4)(2048)),
(CSigmaProp(TrivialProp.FalseProp),
- CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
- success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), 1784),
+ CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
+ success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), 1784, Seq.fill(4)(2030)),
(CSigmaProp(TrivialProp.TrueProp),
- CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
- success(CSigmaProp(TrivialProp.TrueProp), 1767),
+ CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606")))) ->
+ success(CSigmaProp(TrivialProp.TrueProp), 1767, Seq.fill(4)(2013)),
(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))),
- CSigmaProp(TrivialProp.FalseProp)) ->
- success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), 1784),
+ CSigmaProp(TrivialProp.FalseProp)) ->
+ success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), 1784, Seq.fill(4)(2030)),
(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))),
- CSigmaProp(TrivialProp.TrueProp)) ->
- success(CSigmaProp(TrivialProp.TrueProp), 1767)
+ CSigmaProp(TrivialProp.TrueProp)) ->
+ success(CSigmaProp(TrivialProp.TrueProp), 1767, Seq.fill(4)(2013))
)
},
existingFeature(
@@ -9455,12 +9269,13 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
{
- def success[T](v: T, newCost: Int) = Expected(Success(v), newCost, costDetails2, newCost)
+ def success[T](v: T, newCost: Int, v3Costs: Seq[Int]) = Expected(Success(v), newCost, costDetails2, newCost, v3Costs)
+
Seq(
(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), false) ->
- success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), 1786),
+ success(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), 1786, Seq.fill(4)(2038)),
(CSigmaProp(ProveDlog(Helpers.decodeECPoint("03a426a66fc1af2792b35d9583904c3fb877b49ae5cea45b7a2aa105ffa4c68606"))), true) ->
- success(CSigmaProp(TrivialProp.TrueProp), 1769)
+ success(CSigmaProp(TrivialProp.TrueProp), 1769, Seq.fill(4)(2021))
)
},
existingFeature(
@@ -9498,25 +9313,25 @@ class SigmaDslSpecification extends SigmaDslTesting
Helpers.decodeBytes(
"0008ce03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d0303d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b0441"
)
- ), cost = 1771, newDetails(4), expectedNewCost = 1771),
+ ), cost = 1771, newDetails(4), expectedNewCost = 1771, Seq.fill(4)(2003)),
CSigmaProp(pk) -> Expected(Success(
Helpers.decodeBytes("0008cd039d0b1e46c21540d033143440d2fb7dd5d650cf89981c99ee53c6e0374d2b1b6f")),
- cost = 1769, newDetails(1), expectedNewCost = 1769),
+ cost = 1769, newDetails(1), expectedNewCost = 1769, Seq.fill(4)(2001)),
CSigmaProp(and) -> Expected(Success(
Helpers.decodeBytes(
"00089602cd039d0b1e46c21540d033143440d2fb7dd5d650cf89981c99ee53c6e0374d2b1b6fce03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d0303d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b0441"
)
- ), cost = 1772, newDetails(6), expectedNewCost = 1772),
+ ), cost = 1772, newDetails(6), expectedNewCost = 1772, Seq.fill(4)(2004)),
CSigmaProp(threshold) -> Expected(Success(
Helpers.decodeBytes(
"0008980204cd039d0b1e46c21540d033143440d2fb7dd5d650cf89981c99ee53c6e0374d2b1b6fce03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d0303d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b04419702cd039d0b1e46c21540d033143440d2fb7dd5d650cf89981c99ee53c6e0374d2b1b6fce03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d0303d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b04419602cd039d0b1e46c21540d033143440d2fb7dd5d650cf89981c99ee53c6e0374d2b1b6fce03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d0303d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b0441"
)
- ), cost = 1780, newDetails(18), expectedNewCost = 1780),
+ ), cost = 1780, newDetails(18), expectedNewCost = 1780, Seq.fill(4)(2012)),
CSigmaProp(data.COR(Array(pk, dht, and, or, threshold))) -> Expected(Success(
Helpers.decodeBytes(
"00089705cd039d0b1e46c21540d033143440d2fb7dd5d650cf89981c99ee53c6e0374d2b1b6fce03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d0303d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b04419602cd039d0b1e46c21540d033143440d2fb7dd5d650cf89981c99ee53c6e0374d2b1b6fce03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d0303d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b04419702cd039d0b1e46c21540d033143440d2fb7dd5d650cf89981c99ee53c6e0374d2b1b6fce03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d0303d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b0441980204cd039d0b1e46c21540d033143440d2fb7dd5d650cf89981c99ee53c6e0374d2b1b6fce03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d0303d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b04419702cd039d0b1e46c21540d033143440d2fb7dd5d650cf89981c99ee53c6e0374d2b1b6fce03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d0303d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b04419602cd039d0b1e46c21540d033143440d2fb7dd5d650cf89981c99ee53c6e0374d2b1b6fce03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d0303d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b0441"
)
- ), cost = 1791, newDetails(36), expectedNewCost = 1791)
+ ), cost = 1791, newDetails(36), expectedNewCost = 1791, Seq.fill(4)(2023))
)
},
existingFeature((x: SigmaProp) => x.propBytes,
@@ -9525,39 +9340,22 @@ class SigmaDslSpecification extends SigmaDslTesting
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))
+ val v3Costs = Seq.fill(4)(1997)
verifyCases(
Seq(
- (Coll[Boolean]() -> Expected(Success(true), 1765, costDetails(0), 1765)),
- (Coll[Boolean](true) -> Expected(Success(true), 1765, costDetails(1), 1765)),
- (Coll[Boolean](false) -> Expected(Success(false), 1765, costDetails(1), 1765)),
- (Coll[Boolean](false, false) -> Expected(Success(false), 1765, costDetails(1), 1765)),
- (Coll[Boolean](false, true) -> Expected(Success(false), 1765, costDetails(1), 1765)),
- (Coll[Boolean](true, false) -> Expected(Success(false), 1765, costDetails(2), 1765)),
- (Coll[Boolean](true, true) -> Expected(Success(true), 1765, costDetails(2), 1765)),
- (Coll[Boolean](true, false, false) -> Expected(Success(false), 1765, costDetails(2), 1765)),
- (Coll[Boolean](true, false, true) -> Expected(Success(false), 1765, costDetails(2), 1765)),
- (Coll[Boolean](true, true, false) -> Expected(Success(false), 1765, costDetails(3), 1765)),
- (Coll[Boolean](true, true, true) -> Expected(Success(true), 1765, costDetails(3), 1765))
+ (Coll[Boolean]() -> Expected(Success(true), 1765, costDetails(0), 1765, v3Costs)),
+ (Coll[Boolean](true) -> Expected(Success(true), 1765, costDetails(1), 1765, v3Costs)),
+ (Coll[Boolean](false) -> Expected(Success(false), 1765, costDetails(1), 1765, v3Costs)),
+ (Coll[Boolean](false, false) -> Expected(Success(false), 1765, costDetails(1), 1765, v3Costs)),
+ (Coll[Boolean](false, true) -> Expected(Success(false), 1765, costDetails(1), 1765, v3Costs)),
+ (Coll[Boolean](true, false) -> Expected(Success(false), 1765, costDetails(2), 1765, v3Costs)),
+ (Coll[Boolean](true, true) -> Expected(Success(true), 1765, costDetails(2), 1765, v3Costs)),
+ (Coll[Boolean](true, false, false) -> Expected(Success(false), 1765, costDetails(2), 1765, v3Costs)),
+ (Coll[Boolean](true, false, true) -> Expected(Success(false), 1765, costDetails(2), 1765, v3Costs)),
+ (Coll[Boolean](true, true, false) -> Expected(Success(false), 1765, costDetails(3), 1765, v3Costs)),
+ (Coll[Boolean](true, true, true) -> Expected(Success(true), 1765, costDetails(3), 1765, v3Costs))
),
existingFeature((x: Coll[Boolean]) => SigmaDsl.allOf(x),
"{ (x: Coll[Boolean]) => allOf(x) }",
@@ -9566,19 +9364,20 @@ class SigmaDslSpecification extends SigmaDslTesting
property("anyOf equivalence") {
def costDetails(i: Int) = TracedCost(traceBase :+ ast.SeqCostItem(CompanionDesc(OR), PerItemCost(JitCost(5), JitCost(5), 64), i))
+ val v3Costs = Seq.fill(4)(1996)
verifyCases(
Seq(
- (Coll[Boolean]() -> Expected(Success(false), 1764, costDetails(0), 1764)),
- (Coll[Boolean](true) -> Expected(Success(true), 1764, costDetails(1), 1764)),
- (Coll[Boolean](false) -> Expected(Success(false), 1764, costDetails(1), 1764)),
- (Coll[Boolean](false, false) -> Expected(Success(false), 1764, costDetails(2), 1764)),
- (Coll[Boolean](false, true) -> Expected(Success(true), 1764, costDetails(2), 1764)),
- (Coll[Boolean](true, false) -> Expected(Success(true), 1764, costDetails(1), 1764)),
- (Coll[Boolean](true, true) -> Expected(Success(true), 1764, costDetails(1), 1764)),
- (Coll[Boolean](true, false, false) -> Expected(Success(true), 1764, costDetails(1), 1764)),
- (Coll[Boolean](true, false, true) -> Expected(Success(true), 1764, costDetails(1), 1764)),
- (Coll[Boolean](true, true, false) -> Expected(Success(true), 1764, costDetails(1), 1764)),
- (Coll[Boolean](true, true, true) -> Expected(Success(true), 1764, costDetails(1), 1764))
+ (Coll[Boolean]() -> Expected(Success(false), 1764, costDetails(0), 1764, v3Costs)),
+ (Coll[Boolean](true) -> Expected(Success(true), 1764, costDetails(1), 1764, v3Costs)),
+ (Coll[Boolean](false) -> Expected(Success(false), 1764, costDetails(1), 1764, v3Costs)),
+ (Coll[Boolean](false, false) -> Expected(Success(false), 1764, costDetails(2), 1764, v3Costs)),
+ (Coll[Boolean](false, true) -> Expected(Success(true), 1764, costDetails(2), 1764, v3Costs)),
+ (Coll[Boolean](true, false) -> Expected(Success(true), 1764, costDetails(1), 1764, v3Costs)),
+ (Coll[Boolean](true, true) -> Expected(Success(true), 1764, costDetails(1), 1764, v3Costs)),
+ (Coll[Boolean](true, false, false) -> Expected(Success(true), 1764, costDetails(1), 1764, v3Costs)),
+ (Coll[Boolean](true, false, true) -> Expected(Success(true), 1764, costDetails(1), 1764, v3Costs)),
+ (Coll[Boolean](true, true, false) -> Expected(Success(true), 1764, costDetails(1), 1764, v3Costs)),
+ (Coll[Boolean](true, true, true) -> Expected(Success(true), 1764, costDetails(1), 1764, v3Costs))
),
existingFeature((x: Coll[Boolean]) => SigmaDsl.anyOf(x),
"{ (x: Coll[Boolean]) => anyOf(x) }",
@@ -9591,10 +9390,11 @@ class SigmaDslSpecification extends SigmaDslTesting
Seq(
(Helpers.decodeGroupElement("02288f0e55610c3355c89ed6c5de43cf20da145b8c54f03a29f481e540d94e9a69")
-> Expected(Success(
- CSigmaProp(ProveDlog(Helpers.decodeECPoint("02288f0e55610c3355c89ed6c5de43cf20da145b8c54f03a29f481e540d94e9a69")))),
- cost = 1782,
- costDetails,
- 1782))
+ CSigmaProp(ProveDlog(Helpers.decodeECPoint("02288f0e55610c3355c89ed6c5de43cf20da145b8c54f03a29f481e540d94e9a69")))),
+ cost = 1782,
+ costDetails,
+ 1782,
+ Seq.fill(4)(2014)))
),
existingFeature({ (x: GroupElement) => SigmaDsl.proveDlog(x) },
"{ (x: GroupElement) => proveDlog(x) }",
@@ -9614,18 +9414,19 @@ class SigmaDslSpecification extends SigmaDslTesting
Seq(
(Helpers.decodeGroupElement("039c15221a318d27c186eba84fa8d986c1f63bbd9f8060380c9bfc2ef455d8346a")
-> Expected(Success(
- CSigmaProp(
- ProveDHTuple(
- Helpers.decodeECPoint("039c15221a318d27c186eba84fa8d986c1f63bbd9f8060380c9bfc2ef455d8346a"),
- Helpers.decodeECPoint("039c15221a318d27c186eba84fa8d986c1f63bbd9f8060380c9bfc2ef455d8346a"),
- Helpers.decodeECPoint("039c15221a318d27c186eba84fa8d986c1f63bbd9f8060380c9bfc2ef455d8346a"),
- Helpers.decodeECPoint("039c15221a318d27c186eba84fa8d986c1f63bbd9f8060380c9bfc2ef455d8346a")
- )
- )),
- cost = 1836,
- costDetails,
- 1836
- ))
+ CSigmaProp(
+ ProveDHTuple(
+ Helpers.decodeECPoint("039c15221a318d27c186eba84fa8d986c1f63bbd9f8060380c9bfc2ef455d8346a"),
+ Helpers.decodeECPoint("039c15221a318d27c186eba84fa8d986c1f63bbd9f8060380c9bfc2ef455d8346a"),
+ Helpers.decodeECPoint("039c15221a318d27c186eba84fa8d986c1f63bbd9f8060380c9bfc2ef455d8346a"),
+ Helpers.decodeECPoint("039c15221a318d27c186eba84fa8d986c1f63bbd9f8060380c9bfc2ef455d8346a")
+ )
+ )),
+ cost = 1836,
+ costDetails,
+ 1836,
+ Seq.fill(4)(2080)
+ ))
),
existingFeature({ (x: GroupElement) => SigmaDsl.proveDHTuple(x, x, x, x) },
"{ (x: GroupElement) => proveDHTuple(x, x, x, x) }",
@@ -9666,7 +9467,7 @@ class SigmaDslSpecification extends SigmaDslTesting
)
verifyCases(
{
- def success[T](v: T, cd: CostDetails, cost: Int) = Expected(Success(v), cost, cd, cost)
+ def success[T](v: T, cd: CostDetails, cost: Int, expectedV3Costs: Seq[Int]) = Expected(Success(v), cost, cd, cost, expectedV3Costs)
Seq(
(Helpers.decodeBytes(""), 0) -> Expected(new java.nio.BufferUnderflowException()),
@@ -9678,8 +9479,16 @@ class SigmaDslSpecification extends SigmaDslTesting
expectedDetails = CostDetails.ZeroCost,
newCost = 1783,
newVersionedResults = {
- val res = (ExpectedResult(Success(Helpers.decodeBytes("0008d3")), Some(1783)) -> Some(costDetails(0)))
- Seq(0, 1, 2).map(version => version -> res)
+ val costs = if (activatedVersionInTests >= V6SoftForkVersion) {
+ Seq.fill(4)(2055)
+ }
+ else {
+ Seq.fill(4)(1783)
+ }
+ Seq(0, 1, 2, 3).map({ version =>
+ val res = (ExpectedResult(Success(Helpers.decodeBytes("0008d3")), Some(costs(version))) -> Some(costDetails(0)))
+ version -> res
+ })
}),
(Helpers.decodeBytes("000008d3"), 0) -> Expected(
@@ -9688,21 +9497,30 @@ class SigmaDslSpecification extends SigmaDslTesting
expectedDetails = CostDetails.ZeroCost,
newCost = 1783,
newVersionedResults = {
- // since the tree without constant segregation, substitution has no effect
- val res = (ExpectedResult(Success(Helpers.decodeBytes("000008d3")), Some(1783)) -> Some(costDetails(0)))
- Seq(0, 1, 2).map(version => version -> res)
+ val costs = if (activatedVersionInTests >= V6SoftForkVersion) {
+ Seq.fill(4)(2055)
+ }
+ else {
+ Seq.fill(4)(1783)
+ }
+ Seq(0, 1, 2, 3).map({ version =>
+ // since the tree without constant segregation, substitution has no effect
+ val res = (ExpectedResult(Success(Helpers.decodeBytes("000008d3")), Some(costs(version))) -> Some(costDetails(0)))
+ version -> res
+ })
}),
// tree with segregation flag, empty constants array
- (Coll(t2.bytes:_*), 0) -> success(Helpers.decodeBytes("100008d3"), costDetails(0), 1783),
- (Helpers.decodeBytes("100008d3"), 0) -> success(Helpers.decodeBytes("100008d3"), costDetails(0), 1783),
+ (Coll(t2.bytes: _*), 0) -> success(Helpers.decodeBytes("100008d3"), costDetails(0), 1783, Seq.fill(4)(2055)),
+ (Helpers.decodeBytes("100008d3"), 0) -> success(Helpers.decodeBytes("100008d3"), costDetails(0), 1783, Seq.fill(4)(2055)),
// tree with one segregated constant
- (Coll(t3.bytes:_*), 0) -> success(Helpers.decodeBytes("100108d27300"), costDetails(1), 1793),
- (Helpers.decodeBytes("100108d37300"), 0) -> success(Helpers.decodeBytes("100108d27300"), costDetails(1), 1793),
- (Coll(t3.bytes:_*), 1) -> success(Helpers.decodeBytes("100108d37300"), costDetails(1), 1793),
- (Coll(t4.bytes:_*), 0) -> Expected(new IllegalArgumentException("requirement failed: expected new constant to have the same SInt$ tpe, got SSigmaProp"))
+ (Coll(t3.bytes: _*), 0) -> success(Helpers.decodeBytes("100108d27300"), costDetails(1), 1793, Seq.fill(4)(2065)),
+ (Helpers.decodeBytes("100108d37300"), 0) -> success(Helpers.decodeBytes("100108d27300"), costDetails(1), 1793, Seq.fill(4)(2065)),
+ (Coll(t3.bytes: _*), 1) -> success(Helpers.decodeBytes("100108d37300"), costDetails(1), 1793, Seq.fill(4)(2065)),
+ (Coll(t4.bytes: _*), 0) -> Expected(new IllegalArgumentException("requirement failed: expected new constant to have the same SInt$ tpe, got SSigmaProp"))
)
},
changedFeature(
+ changedInVersion = VersionContext.JitActivationVersion,
{ (x: (Coll[Byte], Int)) =>
SigmaDsl.substConstants(x._1, Coll[Int](x._2), Coll[Any](SigmaDsl.sigmaProp(false))(sigma.AnyType))
},
@@ -9754,6 +9572,12 @@ class SigmaDslSpecification extends SigmaDslTesting
if (lowerMethodCallsInTests) {
val error = new RuntimeException("any exception")
+ val costs = if (activatedVersionInTests >= V6SoftForkVersion) {
+ Seq.fill(4)(2144)
+ }
+ else {
+ Seq.fill(4)(1776)
+ }
verifyCases(
Seq(
ctx -> Expected(
@@ -9761,107 +9585,110 @@ class SigmaDslSpecification extends SigmaDslTesting
cost = 1776,
expectedDetails = CostDetails.ZeroCost,
newCost = 1776,
- newVersionedResults = (0 to 2).map(i => i -> (ExpectedResult(Success(true), Some(1776)) -> Some(costDetails)))
+ newVersionedResults = (0 to 3).map({ i =>
+ i -> (ExpectedResult(Success(true), Some(costs(i))) -> Some(costDetails))
+ })
)
),
changedFeature(
- { (x: Context) =>
- throw error
- true
- },
- { (x: Context) =>
- val headers = x.headers
- val ids = headers.map({ (h: Header) => h.id })
- val parentIds = headers.map({ (h: Header) => h.parentId })
- headers.indices.slice(0, headers.size - 1).forall({ (i: Int) =>
- val parentId = parentIds(i)
- val id = ids(i + 1)
- parentId == id
- })
- },
- """{
- |(x: Context) =>
- | val headers = x.headers
- | val ids = headers.map({(h: Header) => h.id })
- | val parentIds = headers.map({(h: Header) => h.parentId })
- | headers.indices.slice(0, headers.size - 1).forall({ (i: Int) =>
- | val parentId = parentIds(i)
- | val id = ids(i + 1)
- | parentId == id
- | })
- |}""".stripMargin,
- FuncValue(
- Array((1, SContext)),
- BlockValue(
- Array(
- ValDef(
- 3,
- List(),
- MethodCall.typed[Value[SCollection[SHeader.type]]](
- ValUse(1, SContext),
- SContextMethods.getMethodByName("headers"),
- Vector(),
- Map()
- )
- )
- ),
- ForAll(
- Slice(
- MethodCall.typed[Value[SCollection[SInt.type]]](
- ValUse(3, SCollectionType(SHeader)),
- SCollectionMethods.getMethodByName("indices").withConcreteTypes(Map(STypeVar("IV") -> SHeader)),
- Vector(),
- Map()
- ),
- IntConstant(0),
- ArithOp(
- SizeOf(ValUse(3, SCollectionType(SHeader))),
- IntConstant(1),
- OpCode @@ (-103.toByte)
+ changedInVersion = VersionContext.JitActivationVersion,
+ { (x: Context) =>
+ throw error
+ true
+ },
+ { (x: Context) =>
+ val headers = x.headers
+ val ids = headers.map({ (h: Header) => h.id })
+ val parentIds = headers.map({ (h: Header) => h.parentId })
+ headers.indices.slice(0, headers.size - 1).forall({ (i: Int) =>
+ val parentId = parentIds(i)
+ val id = ids(i + 1)
+ parentId == id
+ })
+ },
+ """{
+ |(x: Context) =>
+ | val headers = x.headers
+ | val ids = headers.map({(h: Header) => h.id })
+ | val parentIds = headers.map({(h: Header) => h.parentId })
+ | headers.indices.slice(0, headers.size - 1).forall({ (i: Int) =>
+ | val parentId = parentIds(i)
+ | val id = ids(i + 1)
+ | parentId == id
+ | })
+ |}""".stripMargin,
+ FuncValue(
+ Array((1, SContext)),
+ BlockValue(
+ Array(
+ ValDef(
+ 3,
+ List(),
+ MethodCall.typed[Value[SCollection[SHeader.type]]](
+ ValUse(1, SContext),
+ SContextMethods.getMethodByName("headers"),
+ Vector(),
+ Map()
+ )
)
),
- FuncValue(
- Array((4, SInt)),
- EQ(
- ByIndex(
- MapCollection(
- ValUse(3, SCollectionType(SHeader)),
- FuncValue(
- Array((6, SHeader)),
- MethodCall.typed[Value[SCollection[SByte.type]]](
- ValUse(6, SHeader),
- SHeaderMethods.getMethodByName("parentId"),
- Vector(),
- Map()
- )
- )
- ),
- ValUse(4, SInt),
- None
+ ForAll(
+ Slice(
+ MethodCall.typed[Value[SCollection[SInt.type]]](
+ ValUse(3, SCollectionType(SHeader)),
+ SCollectionMethods.getMethodByName("indices").withConcreteTypes(Map(STypeVar("IV") -> SHeader)),
+ Vector(),
+ Map()
),
- ByIndex(
- MapCollection(
- ValUse(3, SCollectionType(SHeader)),
- FuncValue(
- Array((6, SHeader)),
- MethodCall.typed[Value[SCollection[SByte.type]]](
- ValUse(6, SHeader),
- SHeaderMethods.getMethodByName("id"),
- Vector(),
- Map()
+ IntConstant(0),
+ ArithOp(
+ SizeOf(ValUse(3, SCollectionType(SHeader))),
+ IntConstant(1),
+ OpCode @@ (-103.toByte)
+ )
+ ),
+ FuncValue(
+ Array((4, SInt)),
+ EQ(
+ ByIndex(
+ MapCollection(
+ ValUse(3, SCollectionType(SHeader)),
+ FuncValue(
+ Array((6, SHeader)),
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ ValUse(6, SHeader),
+ SHeaderMethods.getMethodByName("parentId"),
+ Vector(),
+ Map()
+ )
)
- )
+ ),
+ ValUse(4, SInt),
+ None
),
- ArithOp(ValUse(4, SInt), IntConstant(1), OpCode @@ (-102.toByte)),
- None
+ ByIndex(
+ MapCollection(
+ ValUse(3, SCollectionType(SHeader)),
+ FuncValue(
+ Array((6, SHeader)),
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ ValUse(6, SHeader),
+ SHeaderMethods.getMethodByName("id"),
+ Vector(),
+ Map()
+ )
+ )
+ ),
+ ArithOp(ValUse(4, SInt), IntConstant(1), OpCode @@ (-102.toByte)),
+ None
+ )
)
)
)
)
- )
- ),
- allowDifferentErrors = true,
- allowNewToSucceed = true
+ ),
+ allowDifferentErrors = true,
+ allowNewToSucceed = true
),
preGeneratedSamples = Some(ArraySeq.empty)
)
@@ -9872,8 +9699,8 @@ class SigmaDslSpecification extends SigmaDslTesting
property("nested loops: map inside fold") {
val keys = Colls.fromArray(Array(Coll[Byte](1, 2, 3, 4, 5)))
val initial = Coll[Byte](0, 0, 0, 0, 0)
- val cases = Seq(
- (keys, initial) -> Expected(Success(Coll[Byte](1, 2, 3, 4, 5)), cost = 1801, expectedDetails = CostDetails.ZeroCost, 1801)
+ val cases = Seq(
+ (keys, initial) -> Expected(Success(Coll[Byte](1, 2, 3, 4, 5)), cost = 1801, expectedDetails = CostDetails.ZeroCost, 1801, Seq.fill(4)(2119))
)
val scalaFunc = { (x: (Coll[Coll[Byte]], Coll[Byte])) =>
x._1.foldLeft(x._2, { (a: (Coll[Byte], Coll[Byte])) =>
@@ -9999,30 +9826,6 @@ class SigmaDslSpecification extends SigmaDslTesting
}
}
- property("higher order lambdas") {
- val f = existingFeature(
- { (xs: Coll[Int]) =>
- val inc = { (x: Int) => x + 1 }
-
- def apply(in: (Int => Int, Int)) = in._1(in._2)
-
- xs.map { (x: Int) => apply((inc, x)) }
- },
- """{(xs: Coll[Int]) =>
- | val inc = { (x: Int) => x + 1 }
- | def apply(in: (Int => Int, Int)) = in._1(in._2)
- | xs.map { (x: Int) => apply((inc, x)) }
- | }
- |""".stripMargin
- )
-
- // TODO v6.0: Add support of SFunc in TypeSerializer (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/847)
- assertExceptionThrown(
- f.verifyCase(Coll[Int](), Expected(Success(Coll[Int]()), 0)),
- exceptionLike[MatchError]("(SInt$) => SInt$ (of class sigma.ast.SFunc)")
- )
- }
-
override protected def afterAll(): Unit = {
printDebug(CErgoTreeEvaluator.DefaultProfiler.generateReport)
printDebug("==========================================================")
diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala
new file mode 100644
index 0000000000..15ce673332
--- /dev/null
+++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala
@@ -0,0 +1,1953 @@
+package sigma
+
+import org.ergoplatform.{ErgoBox, ErgoHeader, ErgoLikeTransaction, Input}
+import scorex.util.encode.Base16
+import sigma.VersionContext.V6SoftForkVersion
+import org.ergoplatform.ErgoBox.Token
+import org.ergoplatform.settings.ErgoAlgos
+import scorex.util.ModifierId
+import scorex.utils.{Ints, Longs, Shorts}
+import sigma.ast.ErgoTree.{HeaderType, ZeroHeader}
+import sigma.ast.SCollection.SByteArray
+import sigma.ast.syntax.TrueSigmaProp
+import sigma.ast.{SInt, _}
+import sigma.data.{AvlTreeData, AvlTreeFlags, CAnyValue, CAvlTree, CBigInt, CBox, CHeader, CSigmaProp, ExactNumeric, ProveDHTuple, RType}
+import sigma.data.{CBigInt, CBox, CHeader, CSigmaDslBuilder, ExactNumeric, PairOfCols, RType}
+import sigma.eval.{CostDetails, SigmaDsl, TracedCost}
+import sigma.serialization.ValueCodes.OpCode
+import sigma.util.Extensions.{BooleanOps, IntOps}
+import sigmastate.eval.{CContext, CPreHeader}
+import sigma.util.Extensions.{BooleanOps, IntOps}
+import sigma.data.{RType}
+import sigma.serialization.ValueCodes.OpCode
+import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps}
+import sigmastate.exceptions.MethodNotFound
+import sigmastate.utils.Extensions.ByteOpsForSigma
+import sigmastate.utils.Helpers
+import sigma.Extensions.{ArrayOps, CollOps}
+import sigma.interpreter.{ContextExtension, ProverResult}
+
+import java.math.BigInteger
+import scala.util.{Failure, Success}
+
+/** This suite tests all operations for v6.0 version of the language.
+ * The base classes establish the infrastructure for the tests.
+ *
+ * @see SigmaDslSpecificationBase
+ */
+class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
+ override def languageVersion: Byte = VersionContext.V6SoftForkVersion
+
+ implicit override def evalSettings = super.evalSettings.copy(printTestVectors = true)
+
+ def mkSerializeFeature[A: RType]: Feature[A, Coll[Byte]] = {
+ val tA = RType[A]
+ val tpe = Evaluation.rtypeToSType(tA)
+ newFeature(
+ (x: A) => SigmaDsl.serialize(x),
+ s"{ (x: ${tA.name}) => serialize(x) }",
+ expectedExpr = FuncValue(
+ Array((1, tpe)),
+ MethodCall(
+ Global,
+ SGlobalMethods.serializeMethod.withConcreteTypes(Map(STypeVar("T") -> tpe)),
+ Array(ValUse(1, tpe)),
+ Map()
+ )
+ ),
+ sinceVersion = VersionContext.V6SoftForkVersion)
+ }
+
+ val baseTrace = Array(
+ FixedCostItem(Apply),
+ FixedCostItem(FuncValue),
+ FixedCostItem(GetVar),
+ FixedCostItem(OptionGet),
+ FixedCostItem(FuncValue.AddToEnvironmentDesc, FixedCost(JitCost(5)))
+ )
+
+ property("Global.serialize[Byte]") {
+ lazy val serializeByte = mkSerializeFeature[Byte]
+ val expectedCostTrace = TracedCost(
+ baseTrace ++ Array(
+ FixedCostItem(Global),
+ FixedCostItem(MethodCall),
+ FixedCostItem(ValUse),
+ FixedCostItem(NamedDesc("SigmaByteWriter.startWriter"), FixedCost(JitCost(10))),
+ FixedCostItem(NamedDesc("SigmaByteWriter.put"), FixedCost(JitCost(1)))
+ )
+ )
+ val cases = Seq(
+ (-128.toByte, Expected(Success(Coll(-128.toByte)), expectedCostTrace)),
+ (-1.toByte, Expected(Success(Coll(-1.toByte)), expectedCostTrace)),
+ (0.toByte, Expected(Success(Coll(0.toByte)), expectedCostTrace)),
+ (1.toByte, Expected(Success(Coll(1.toByte)), expectedCostTrace)),
+ (127.toByte, Expected(Success(Coll(127.toByte)), expectedCostTrace))
+ )
+ verifyCases(cases, serializeByte, preGeneratedSamples = None)
+ }
+
+ property("Global.serialize[Short]") {
+ lazy val serializeShort = mkSerializeFeature[Short]
+ val expectedCostTrace = TracedCost(
+ baseTrace ++ Array(
+ FixedCostItem(Global),
+ FixedCostItem(MethodCall),
+ FixedCostItem(ValUse),
+ FixedCostItem(NamedDesc("SigmaByteWriter.startWriter"), FixedCost(JitCost(10))),
+ FixedCostItem(NamedDesc("SigmaByteWriter.putNumeric"), FixedCost(JitCost(3)))
+ )
+ )
+ val cases = Seq(
+ (Short.MinValue, Expected(Success(Coll[Byte](0xFF.toByte, 0xFF.toByte, 0x03.toByte)), expectedCostTrace)),
+ (-1.toShort, Expected(Success(Coll(1.toByte)), expectedCostTrace)),
+ (0.toShort, Expected(Success(Coll(0.toByte)), expectedCostTrace)),
+ (1.toShort, Expected(Success(Coll(2.toByte)), expectedCostTrace)),
+ (Short.MaxValue, Expected(Success(Coll(-2.toByte, -1.toByte, 3.toByte)), expectedCostTrace))
+ )
+ verifyCases(cases, serializeShort, preGeneratedSamples = None)
+ }
+
+ // 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 = 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 - 6.0 features") {
+
+ lazy val bitOr = newFeature(
+ { (x: (Byte, Byte)) => (x._1 | x._2).toByteExact },
+ "{ (x: (Byte, Byte)) => x._1.bitwiseOr(x._2) }",
+ FuncValue(
+ Array((1, SPair(SByte, SByte))),
+ MethodCall.typed[Value[SByte.type]](
+ SelectField.typed[Value[SByte.type]](ValUse(1, SPair(SByte, SByte)), 1.toByte),
+ SByteMethods.v6Methods.find(_.name == "bitwiseOr").get,
+ Vector(SelectField.typed[Value[SByte.type]](ValUse(1, SPair(SByte, SByte)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (1.toByte, 2.toByte) -> new Expected(ExpectedResult(Success(3.toByte), None))
+ ),
+ bitOr
+ )
+
+ lazy val bitNot = newFeature(
+ { (x: Byte) => (~x).toByteExact },
+ "{ (x: Byte) => x.bitwiseInverse }",
+ FuncValue(
+ Array((1, SByte)),
+ MethodCall.typed[Value[SByte.type]](
+ ValUse(1, SByte),
+ SByteMethods.v6Methods.find(_.name == "bitwiseInverse").get,
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 1.toByte -> new Expected(ExpectedResult(Success((-2).toByte), None))
+ ),
+ bitNot
+ )
+
+ lazy val bitAnd = newFeature(
+ { (x: (Byte, Byte)) => (x._1 & x._2).toByteExact },
+ "{ (x: (Byte, Byte)) => x._1.bitwiseAnd(x._2) }",
+ FuncValue(
+ Array((1, SPair(SByte, SByte))),
+ MethodCall.typed[Value[SByte.type]](
+ SelectField.typed[Value[SByte.type]](ValUse(1, SPair(SByte, SByte)), 1.toByte),
+ SByteMethods.v6Methods.find(_.name == "bitwiseAnd").get,
+ Vector(SelectField.typed[Value[SByte.type]](ValUse(1, SPair(SByte, SByte)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3.toByte, 5.toByte) -> new Expected(ExpectedResult(Success(1.toByte), None))
+ ),
+ bitAnd
+ )
+
+ lazy val bitXor = newFeature(
+ { (x: (Byte, Byte)) => (x._1 ^ x._2).toByteExact },
+ "{ (x: (Byte, Byte)) => x._1.bitwiseXor(x._2) }",
+ FuncValue(
+ Array((1, SPair(SByte, SByte))),
+ MethodCall.typed[Value[SByte.type]](
+ SelectField.typed[Value[SByte.type]](ValUse(1, SPair(SByte, SByte)), 1.toByte),
+ SByteMethods.v6Methods.find(_.name == "bitwiseXor").get,
+ Vector(SelectField.typed[Value[SByte.type]](ValUse(1, SPair(SByte, SByte)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3.toByte, 5.toByte) -> new Expected(ExpectedResult(Success(6.toByte), None))
+ ),
+ bitXor
+ )
+
+ lazy val toBigEndianBytes = newFeature(
+ { x: Byte => Coll(x) },
+ "{ (x: Byte) => x.toBytes }",
+ FuncValue(
+ Array((1, SByte)),
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ ValUse(1, SByte),
+ SByteMethods.getMethodByName("toBytes"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 127.toByte -> new Expected(ExpectedResult(Success(Coll(127.toByte)), None))
+ ),
+ toBigEndianBytes
+ )
+
+ def byte2Bools(b: Byte): Seq[Boolean] =
+ (0 to 7 map isBitSet(b)).reverse
+
+ def isBitSet(byte: Byte)(bit: Int): Boolean =
+ ((byte >> bit) & 1) == 1
+
+ lazy val toBits = newFeature[Byte, Coll[Boolean]](
+ { x: Byte => Colls.fromArray(byte2Bools(x).toArray) },
+ "{ (x: Byte) => x.toBits }",
+ FuncValue(
+ Array((1, SByte)),
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ ValUse(1, SByte),
+ SByteMethods.getMethodByName("toBits"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 83.toByte -> new Expected(ExpectedResult(Success(Coll(false, true, false, true, false, false, true, true)), None)),
+ -55.toByte -> new Expected(ExpectedResult(Success(Coll(true, true, false, false, true, false, false, true)), None)),
+ -1.toByte -> new Expected(ExpectedResult(Success(Coll(true, true, true, true, true, true, true, true)), None))
+ ),
+ toBits
+ )
+
+ lazy val shiftLeft = newFeature(
+ { (x: (Byte, Int)) => if(x._2 < 0 || x._2 >= 8) throw new IllegalArgumentException() else (x._1 << x._2).toByte },
+ "{ (x: (Byte, Int)) => x._1.shiftLeft(x._2) }",
+ FuncValue(
+ Array((1, SPair(SByte, SInt))),
+ MethodCall.typed[Value[SByte.type]](
+ SelectField.typed[Value[SByte.type]](ValUse(1, SPair(SByte, SInt)), 1.toByte),
+ SByteMethods.v6Methods.find(_.name == "shiftLeft").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SByte, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3.toByte, 3) -> new Expected(ExpectedResult(Success(24.toByte), None)),
+ (3.toByte, 0) -> new Expected(ExpectedResult(Success(3.toByte), None)),
+ (3.toByte, -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)),
+ (3.toByte, 8) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None))
+ ),
+ shiftLeft,
+ preGeneratedSamples = Some(Seq())
+ )
+
+ lazy val shiftRight = newFeature(
+ { (x: (Byte, Int)) => if(x._2 < 0 || x._2 >= 8) throw new IllegalArgumentException() else (x._1 >> x._2).toByte },
+ "{ (x: (Byte, Int)) => x._1.shiftRight(x._2) }",
+ FuncValue(
+ Array((1, SPair(SByte, SInt))),
+ MethodCall.typed[Value[SByte.type]](
+ SelectField.typed[Value[SByte.type]](ValUse(1, SPair(SByte, SInt)), 1.toByte),
+ SByteMethods.v6Methods.find(_.name == "shiftRight").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SByte, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (24.toByte, 3) -> new Expected(ExpectedResult(Success(3.toByte), None)),
+ (24.toByte, 0) -> new Expected(ExpectedResult(Success(24.toByte), None)),
+ (24.toByte, -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)),
+ (24.toByte, 8) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None))
+ ),
+ shiftRight,
+ preGeneratedSamples = Some(Seq())
+ )
+ }
+
+ property("Short - 6.0 methods") {
+
+ lazy val bitOr = newFeature(
+ { (x: (Short, Short)) => (x._1 | x._2).toShortExact },
+ "{ (x: (Short, Short)) => x._1.bitwiseOr(x._2) }",
+ FuncValue(
+ Array((1, SPair(SShort, SShort))),
+ MethodCall.typed[Value[SShort.type]](
+ SelectField.typed[Value[SShort.type]](ValUse(1,SPair(SShort, SShort)), 1.toByte),
+ SShortMethods.v6Methods.find(_.name == "bitwiseOr").get,
+ Vector(SelectField.typed[Value[SShort.type]](ValUse(1, SPair(SShort, SShort)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (1.toShort, 2.toShort) -> new Expected(ExpectedResult(Success(3.toShort), None)),
+ (1001.toShort, 2002.toShort) -> new Expected(ExpectedResult(Success(2043.toShort), None))
+ ),
+ bitOr
+ )
+
+ lazy val bitNot = newFeature(
+ { (x: Short) => (~x).toShortExact },
+ "{ (x: Short) => x.bitwiseInverse }",
+ FuncValue(
+ Array((1, SShort)),
+ MethodCall.typed[Value[SShort.type]](
+ ValUse(1, SShort),
+ SShortMethods.v6Methods.find(_.name == "bitwiseInverse").get,
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 1.toShort -> new Expected(ExpectedResult(Success((-2).toShort), None)),
+ 10001.toShort -> new Expected(ExpectedResult(Success((-10002).toShort), None))
+ ),
+ bitNot
+ )
+
+ lazy val bitAnd = newFeature(
+ { (x: (Short, Short)) => (x._1 & x._2).toShortExact },
+ "{ (x: (Short, Short)) => x._1.bitwiseAnd(x._2) }",
+ FuncValue(
+ Array((1, SPair(SShort, SShort))),
+ MethodCall.typed[Value[SShort.type]](
+ SelectField.typed[Value[SShort.type]](ValUse(1, SPair(SShort, SShort)), 1.toByte),
+ SShortMethods.v6Methods.find(_.name == "bitwiseAnd").get,
+ Vector(SelectField.typed[Value[SShort.type]](ValUse(1, SPair(SShort, SShort)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3.toShort, 5.toShort) -> new Expected(ExpectedResult(Success(1.toShort), None)),
+ (10001.toShort, 2202.toShort) -> new Expected(ExpectedResult(Success(16.toShort), None))
+ ),
+ bitAnd
+ )
+
+ lazy val bitXor = newFeature(
+ { (x: (Short, Short)) => (x._1 ^ x._2).toShortExact },
+ "{ (x: (Short, Short)) => x._1.bitwiseXor(x._2) }",
+ FuncValue(
+ Array((1, SPair(SShort, SShort))),
+ MethodCall.typed[Value[SShort.type]](
+ SelectField.typed[Value[SShort.type]](ValUse(1, SPair(SShort, SShort)), 1.toByte),
+ SShortMethods.v6Methods.find(_.name == "bitwiseXor").get,
+ Vector(SelectField.typed[Value[SShort.type]](ValUse(1, SPair(SShort, SShort)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3.toShort, 5.toShort) -> new Expected(ExpectedResult(Success(6.toShort), None)),
+ (10001.toShort, 2202.toShort) -> new Expected(ExpectedResult(Success(12171.toShort), None))
+ ),
+ bitXor
+ )
+
+ lazy val toBigEndianBytes = newFeature[Short, Coll[Byte]](
+ { x: Short => Colls.fromArray(Shorts.toByteArray(x)) },
+ "{ (x: Short) => x.toBytes }",
+ FuncValue(
+ Array((1, SShort)),
+ MethodCall.typed[Value[SCollection[SShort.type]]](
+ ValUse(1, SShort),
+ SShortMethods.getMethodByName("toBytes"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 127.toShort -> new Expected(ExpectedResult(Success(Coll(0.toByte, 127.toByte)), None)),
+ Short.MaxValue -> new Expected(ExpectedResult(Success(Coll(127.toByte, (-1).toByte)), None)),
+ Short.MinValue -> new Expected(ExpectedResult(Success(Coll((-128).toByte, 0.toByte)), None))
+ ),
+ toBigEndianBytes
+ )
+
+ def byte2Bools(b: Byte): Seq[Boolean] =
+ (0 to 7 map isBitSet(b)).reverse
+
+ def isBitSet(byte: Byte)(bit: Int): Boolean =
+ ((byte >> bit) & 1) == 1
+
+ lazy val toBits = newFeature[Short, Coll[Boolean]](
+ { x: Short => Colls.fromArray(Shorts.toByteArray(x)).flatMap(b => Colls.fromArray(byte2Bools(b).toArray)) },
+ "{ (x: Short) => x.toBits }",
+ FuncValue(
+ Array((1, SShort)),
+ MethodCall.typed[Value[SCollection[SShort.type]]](
+ ValUse(1, SShort),
+ SShortMethods.getMethodByName("toBits"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 83.toShort -> new Expected(ExpectedResult(Success(Coll(false, false, false, false, false, false, false, false, false, true, false, true, false, false, true, true)), None)),
+ -55.toShort -> new Expected(ExpectedResult(Success(Coll(true, true, true, true, true, true, true, true, true, true, false, false, true, false, false, true)), None)),
+ -1.toShort-> new Expected(ExpectedResult(Success(Coll(true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true)), None)),
+ -10001.toShort-> new Expected(ExpectedResult(Success(Coll(true, true, false, true, true, false, false, false, true, true, true, false, true, true, true, true)), None))
+ ),
+ toBits
+ )
+
+ lazy val shiftLeft = newFeature(
+ { (x: (Short, Int)) => if(x._2 < 0 || x._2 >= 16) throw new IllegalArgumentException() else (x._1 << x._2).toShort },
+ "{ (x: (Short, Int)) => x._1.shiftLeft(x._2) }",
+ FuncValue(
+ Array((1, SPair(SShort, SInt))),
+ MethodCall.typed[Value[SShort.type]](
+ SelectField.typed[Value[SShort.type]](ValUse(1, SPair(SShort, SInt)), 1.toByte),
+ SShortMethods.v6Methods.find(_.name == "shiftLeft").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SShort, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3.toShort, 3) -> new Expected(ExpectedResult(Success(24.toShort), None)),
+ (3.toShort, 8) -> new Expected(ExpectedResult(Success(768.toShort), None)),
+ ((-2).toShort, 10) -> new Expected(ExpectedResult(Success((-2048).toShort), None)),
+ ((-2).toShort, 20) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)),
+ (3.toShort, -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None))
+ ),
+ shiftLeft,
+ preGeneratedSamples = Some(Seq())
+ )
+
+ lazy val shiftRight = newFeature(
+ { (x: (Short, Int)) => if(x._2 < 0 || x._2 >= 16) throw new IllegalArgumentException() else (x._1 >> x._2).toShort },
+ "{ (x: (Short, Int)) => x._1.shiftRight(x._2) }",
+ FuncValue(
+ Array((1, SPair(SShort, SInt))),
+ MethodCall.typed[Value[SShort.type]](
+ SelectField.typed[Value[SShort.type]](ValUse(1, SPair(SShort, SInt)), 1.toByte),
+ SShortMethods.v6Methods.find(_.name == "shiftRight").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SShort, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (24.toShort, 3) -> new Expected(ExpectedResult(Success(3.toShort), None)),
+ (1600.toShort, 8) -> new Expected(ExpectedResult(Success(6.toShort), None)),
+ ((-3200).toShort, 8) -> new Expected(ExpectedResult(Success((-13).toShort), None)),
+ (3.toShort, -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)),
+ (3.toShort, 16) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None))
+ ),
+ shiftRight,
+ preGeneratedSamples = Some(Seq())
+ )
+ }
+
+ property("Int - 6.0 methods") {
+
+ lazy val bitOr = newFeature(
+ { (x: (Int, Int)) => (x._1 | x._2)},
+ "{ (x: (Int, Int)) => x._1.bitwiseOr(x._2) }",
+ FuncValue(
+ Array((1, SPair(SInt, SInt))),
+ MethodCall.typed[Value[SInt.type]](
+ SelectField.typed[Value[SInt.type]](ValUse(1,SPair(SInt, SInt)), 1.toByte),
+ SIntMethods.v6Methods.find(_.name == "bitwiseOr").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SInt, SInt)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (1, 2) -> new Expected(ExpectedResult(Success(3), None)),
+ (1001, 2002) -> new Expected(ExpectedResult(Success(2043), None)),
+ (100001, 20002) -> new Expected(ExpectedResult(Success(118435), None))
+ ),
+ bitOr
+ )
+
+ lazy val bitNot = newFeature(
+ { (x: Int) => ~x },
+ "{ (x: Int) => x.bitwiseInverse }",
+ FuncValue(
+ Array((1, SInt)),
+ MethodCall.typed[Value[SInt.type]](
+ ValUse(1, SInt),
+ SIntMethods.v6Methods.find(_.name == "bitwiseInverse").get,
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 1 -> new Expected(ExpectedResult(Success(-2), None)),
+ 10001 -> new Expected(ExpectedResult(Success(-10002), None)),
+ Int.MinValue -> new Expected(ExpectedResult(Success(Int.MaxValue), None))
+ ),
+ bitNot
+ )
+
+ lazy val bitAnd = newFeature(
+ { (x: (Int, Int)) => x._1 & x._2 },
+ "{ (x: (Int, Int)) => x._1.bitwiseAnd(x._2) }",
+ FuncValue(
+ Array((1, SPair(SInt, SInt))),
+ MethodCall.typed[Value[SInt.type]](
+ SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SInt, SInt)), 1.toByte),
+ SIntMethods.v6Methods.find(_.name == "bitwiseAnd").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SInt, SInt)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3, 5) -> new Expected(ExpectedResult(Success(1), None)),
+ (10001, 2202) -> new Expected(ExpectedResult(Success(16), None)),
+ (-10001, 200202) -> new Expected(ExpectedResult(Success(198666), None))
+ ),
+ bitAnd
+ )
+
+ lazy val bitXor = newFeature(
+ { (x: (Int, Int)) => (x._1 ^ x._2) },
+ "{ (x: (Int, Int)) => x._1.bitwiseXor(x._2) }",
+ FuncValue(
+ Array((1, SPair(SInt, SInt))),
+ MethodCall.typed[Value[SInt.type]](
+ SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SInt, SInt)), 1.toByte),
+ SIntMethods.v6Methods.find(_.name == "bitwiseXor").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SInt, SInt)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3, 5) -> new Expected(ExpectedResult(Success(6), None)),
+ (10001, 2202) -> new Expected(ExpectedResult(Success(12171), None)),
+ (-10001, 200202) -> new Expected(ExpectedResult(Success(-207131), None))
+ ),
+ bitXor
+ )
+
+ lazy val toBigEndianBytes = newFeature[Int, Coll[Byte]](
+ { x: Int => Colls.fromArray(Ints.toByteArray(x)) },
+ "{ (x: Int) => x.toBytes }",
+ FuncValue(
+ Array((1, SInt)),
+ MethodCall.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SInt),
+ SIntMethods.getMethodByName("toBytes"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 127 -> new Expected(ExpectedResult(Success(Coll(0.toByte, 0.toByte, 0.toByte, 127.toByte)), None)),
+ Short.MaxValue.toInt -> new Expected(ExpectedResult(Success(Coll(0.toByte, 0.toByte, 127.toByte, (-1).toByte)), None)),
+ Short.MinValue.toInt -> new Expected(ExpectedResult(Success(Coll((-1).toByte, (-1).toByte, (-128).toByte, 0.toByte)), None)),
+ Int.MaxValue.toInt -> new Expected(ExpectedResult(Success(Coll(127.toByte, (-1).toByte, (-1).toByte, (-1).toByte)), None))
+ ),
+ toBigEndianBytes
+ )
+
+ def byte2Bools(b: Byte): Seq[Boolean] =
+ (0 to 7 map isBitSet(b)).reverse
+
+ def isBitSet(byte: Byte)(bit: Int): Boolean =
+ ((byte >> bit) & 1) == 1
+
+ lazy val toBits = newFeature[Int, Coll[Boolean]](
+ { x: Int => Colls.fromArray(Ints.toByteArray(x)).flatMap(b => Colls.fromArray(byte2Bools(b).toArray)) },
+ "{ (x: Int) => x.toBits }",
+ FuncValue(
+ Array((1, SInt)),
+ MethodCall.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SInt),
+ SIntMethods.getMethodByName("toBits"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 83 -> new Expected(ExpectedResult(Success(Coll(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true, false, false, true, true)), None)),
+ -55 -> new Expected(ExpectedResult(Success(Coll(true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, true, false, false, true)), None)),
+ -1 -> new Expected(ExpectedResult(Success(Coll(true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true)), None)),
+ -10001 -> new Expected(ExpectedResult(Success(Coll(true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, false, false, false, true, true, true, false, true, true, true, true)), None))
+ ),
+ toBits
+ )
+
+ lazy val shiftLeft = newFeature(
+ { (x: (Int, Int)) => if(x._2 < 0 || x._2 >= 32) throw new IllegalArgumentException() else (x._1 << x._2) },
+ "{ (x: (Int, Int)) => x._1.shiftLeft(x._2) }",
+ FuncValue(
+ Array((1, SPair(SInt, SInt))),
+ MethodCall.typed[Value[SInt.type]](
+ SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SInt, SInt)), 1.toByte),
+ SIntMethods.v6Methods.find(_.name == "shiftLeft").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SInt, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3, 3) -> new Expected(ExpectedResult(Success(24), None)),
+ (3, 8) -> new Expected(ExpectedResult(Success(768), None)),
+ (-2, 10) -> new Expected(ExpectedResult(Success(-2048), None)),
+ (-222, 10) -> new Expected(ExpectedResult(Success(-227328), None)),
+ (-222, 32) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)),
+ (-222, -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None))
+ ),
+ shiftLeft,
+ preGeneratedSamples = Some(Seq())
+ )
+
+ lazy val shiftRight = newFeature(
+ { (x: (Int, Int)) => if(x._2 < 0 || x._2 >= 32) throw new IllegalArgumentException() else (x._1 >> x._2) },
+ "{ (x: (Int, Int)) => x._1.shiftRight(x._2) }",
+ FuncValue(
+ Array((1, SPair(SInt, SInt))),
+ MethodCall.typed[Value[SInt.type]](
+ SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SInt, SInt)), 1.toByte),
+ SIntMethods.v6Methods.find(_.name == "shiftRight").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SInt, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (24, 3) -> new Expected(ExpectedResult(Success(3), None)),
+ (1600, 8) -> new Expected(ExpectedResult(Success(6), None)),
+ (-3200, 8) -> new Expected(ExpectedResult(Success(-13), None)),
+ (-320019, 18) -> new Expected(ExpectedResult(Success(-2), None)),
+ (-320019, 32) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)),
+ (-320019, -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None))
+ ),
+ shiftRight,
+ preGeneratedSamples = Some(Seq())
+ )
+ }
+
+ property("Long - 6.0 methods") {
+
+ lazy val bitOr = newFeature(
+ { (x: (Long, Long)) => (x._1 | x._2)},
+ "{ (x: (Long, Long)) => x._1.bitwiseOr(x._2) }",
+ FuncValue(
+ Array((1, SPair(SLong, SLong))),
+ MethodCall.typed[Value[SLong.type]](
+ SelectField.typed[Value[SLong.type]](ValUse(1,SPair(SLong, SLong)), 1.toByte),
+ SLongMethods.v6Methods.find(_.name == "bitwiseOr").get,
+ Vector(SelectField.typed[Value[SLong.type]](ValUse(1, SPair(SLong, SLong)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (1L, 2L) -> new Expected(ExpectedResult(Success(3L), None)),
+ (1001L, 2002L) -> new Expected(ExpectedResult(Success(2043L), None)),
+ (100001L, 20002L) -> new Expected(ExpectedResult(Success(118435L), None)),
+ (1000010111L, -22L) -> new Expected(ExpectedResult(Success(-1L), None))
+ ),
+ bitOr
+ )
+
+ lazy val bitNot = newFeature(
+ { (x: Long) => ~x },
+ "{ (x: Long) => x.bitwiseInverse }",
+ FuncValue(
+ Array((1, SLong)),
+ MethodCall.typed[Value[SLong.type]](
+ ValUse(1, SLong),
+ SLongMethods.v6Methods.find(_.name == "bitwiseInverse").get,
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 1L -> new Expected(ExpectedResult(Success(-2L), None)),
+ 10001L -> new Expected(ExpectedResult(Success(-10002L), None)),
+ Int.MinValue.toLong -> new Expected(ExpectedResult(Success(Int.MaxValue.toLong), None)),
+ Long.MinValue -> new Expected(ExpectedResult(Success(Long.MaxValue), None)),
+ Long.MaxValue -> new Expected(ExpectedResult(Success(Long.MinValue), None))
+ ),
+ bitNot
+ )
+
+ lazy val bitAnd = newFeature(
+ { (x: (Long, Long)) => x._1 & x._2 },
+ "{ (x: (Long, Long)) => x._1.bitwiseAnd(x._2) }",
+ FuncValue(
+ Array((1, SPair(SLong, SLong))),
+ MethodCall.typed[Value[SLong.type]](
+ SelectField.typed[Value[SLong.type]](ValUse(1, SPair(SLong, SLong)), 1.toByte),
+ SLongMethods.v6Methods.find(_.name == "bitwiseAnd").get,
+ Vector(SelectField.typed[Value[SLong.type]](ValUse(1, SPair(SLong, SLong)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3L, 5L) -> new Expected(ExpectedResult(Success(1L), None)),
+ (10001L, 2202L) -> new Expected(ExpectedResult(Success(16L), None)),
+ (-10001L, 200202L) -> new Expected(ExpectedResult(Success(198666L), None)),
+ (1000010111L, -22L) -> new Expected(ExpectedResult(Success(1000010090L), None))
+ ),
+ bitAnd
+ )
+
+ lazy val bitXor = newFeature(
+ { (x: (Long, Long)) => (x._1 ^ x._2) },
+ "{ (x: (Long, Long)) => x._1.bitwiseXor(x._2) }",
+ FuncValue(
+ Array((1, SPair(SLong, SLong))),
+ MethodCall.typed[Value[SLong.type]](
+ SelectField.typed[Value[SLong.type]](ValUse(1, SPair(SLong, SLong)), 1.toByte),
+ SLongMethods.v6Methods.find(_.name == "bitwiseXor").get,
+ Vector(SelectField.typed[Value[SLong.type]](ValUse(1, SPair(SLong, SLong)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3L, 5L) -> new Expected(ExpectedResult(Success(6L), None)),
+ (10001L, 2202L) -> new Expected(ExpectedResult(Success(12171L), None)),
+ (-10001L, 200202L) -> new Expected(ExpectedResult(Success(-207131L), None)),
+ (1000010111L, -22L) -> new Expected(ExpectedResult(Success(-1000010091L), None))
+ ),
+ bitXor
+ )
+
+ lazy val toBigEndianBytes = newFeature[Long, Coll[Byte]](
+ { x: Long => Colls.fromArray(Longs.toByteArray(x)) },
+ "{ (x: Long) => x.toBytes }",
+ FuncValue(
+ Array((1, SLong)),
+ MethodCall.typed[Value[SCollection[SLong.type]]](
+ ValUse(1, SLong),
+ SLongMethods.getMethodByName("toBytes"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 127L -> new Expected(ExpectedResult(Success(Coll(0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 127.toByte)), None)),
+ Short.MaxValue.toLong -> new Expected(ExpectedResult(Success(Coll(0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 127.toByte, (-1).toByte)), None)),
+ Short.MinValue.toLong -> new Expected(ExpectedResult(Success(Coll((-1).toByte, (-1).toByte, (-1).toByte, (-1).toByte, (-1).toByte, (-1).toByte, (-128).toByte, 0.toByte)), None)),
+ Int.MaxValue.toLong -> new Expected(ExpectedResult(Success(Coll(0.toByte, 0.toByte, 0.toByte, 0.toByte, 127.toByte, (-1).toByte, (-1).toByte, (-1).toByte)), None))
+ ),
+ toBigEndianBytes
+ )
+
+ def byte2Bools(b: Byte): Seq[Boolean] =
+ (0 to 7 map isBitSet(b)).reverse
+
+ def isBitSet(byte: Byte)(bit: Int): Boolean =
+ ((byte >> bit) & 1) == 1
+
+ lazy val toBits = newFeature[Long, Coll[Boolean]](
+ { x: Long => Colls.fromArray(Longs.toByteArray(x)).flatMap(b => Colls.fromArray(byte2Bools(b).toArray)) },
+ "{ (x: Long) => x.toBits }",
+ FuncValue(
+ Array((1, SLong)),
+ MethodCall.typed[Value[SCollection[SLong.type]]](
+ ValUse(1, SLong),
+ SLongMethods.getMethodByName("toBits"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ 83L -> new Expected(ExpectedResult(Success(Colls.fromArray(Array.fill(57)(false)).append(Coll(true, false, true, false, false, true, true))), None)),
+ -55L -> new Expected(ExpectedResult(Success(Colls.fromArray(Array.fill(58)(true)).append(Coll(false, false, true, false, false, true))), None)),
+ -1L -> new Expected(ExpectedResult(Success(Colls.fromArray(Array.fill(64)(true))), None)),
+ -10001L -> new Expected(ExpectedResult(Success(Colls.fromArray(Array.fill(50)(true)).append(Coll( false, true, true, false, false, false, true, true, true, false, true, true, true, true))), None))
+ ),
+ toBits
+ )
+
+ lazy val shiftLeft = newFeature(
+ { (x: (Long, Int)) => if(x._2 < 0 || x._2 >= 32) throw new IllegalArgumentException() else (x._1 << x._2) },
+ "{ (x: (Long, Int)) => x._1.shiftLeft(x._2) }",
+ FuncValue(
+ Array((1, SPair(SLong, SInt))),
+ MethodCall.typed[Value[SLong.type]](
+ SelectField.typed[Value[SLong.type]](ValUse(1, SPair(SLong, SInt)), 1.toByte),
+ SLongMethods.v6Methods.find(_.name == "shiftLeft").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SLong, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (3L, 3) -> new Expected(ExpectedResult(Success(24L), None)),
+ (3L, 8) -> new Expected(ExpectedResult(Success(768L), None)),
+ (-2L, 10) -> new Expected(ExpectedResult(Success(-2048L), None)),
+ (-222L, 10) -> new Expected(ExpectedResult(Success(-227328L), None)),
+ (-222L, -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)),
+ (-222L, 64) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None))
+ ),
+ shiftLeft,
+ preGeneratedSamples = Some(Seq())
+ )
+
+ lazy val shiftRight = newFeature(
+ { (x: (Long, Int)) => if(x._2 < 0 || x._2 >= 64) throw new IllegalArgumentException() else (x._1 >> x._2) },
+ "{ (x: (Long, Int)) => x._1.shiftRight(x._2) }",
+ FuncValue(
+ Array((1, SPair(SLong, SInt))),
+ MethodCall.typed[Value[SLong.type]](
+ SelectField.typed[Value[SLong.type]](ValUse(1, SPair(SLong, SInt)), 1.toByte),
+ SLongMethods.v6Methods.find(_.name == "shiftRight").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SLong, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (24L, 3) -> new Expected(ExpectedResult(Success(3L), None)),
+ (1600L, 8) -> new Expected(ExpectedResult(Success(6L), None)),
+ (-3200L, 8) -> new Expected(ExpectedResult(Success(-13L), None)),
+ (-320019L, 18) -> new Expected(ExpectedResult(Success(-2L), None)),
+ (-320019L, 63) -> new Expected(ExpectedResult(Success(-1L), None)),
+ (24L, -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None))
+ ),
+ shiftRight,
+ preGeneratedSamples = Some(Seq())
+ )
+ }
+
+ property("BigInt - 6.0 features") {
+ import sigma.data.OrderingOps.BigIntOrdering
+
+ if (activatedVersionInTests < VersionContext.V6SoftForkVersion) {
+ // The `Upcast(bigInt, SBigInt)` node is never produced by ErgoScript compiler, but is still valid ErgoTree.
+ // Fixed in 6.0
+ assertExceptionThrown(
+ SBigInt.upcast(CBigInt(new BigInteger("0", 16)).asInstanceOf[AnyVal]),
+ _.getMessage.contains("Cannot upcast value")
+ )
+
+ // The `Downcast(bigInt, SBigInt)` node is never produced by ErgoScript compiler, but is still valid ErgoTree.
+ // Fixed in 6.0
+ assertExceptionThrown(
+ SBigInt.downcast(CBigInt(new BigInteger("0", 16)).asInstanceOf[AnyVal]),
+ _.getMessage.contains("Cannot downcast value")
+ )
+
+ forAll { x: Long =>
+ assertExceptionThrown(
+ SLong.downcast(CBigInt(new BigInteger(x.toString)).asInstanceOf[AnyVal]),
+ _.getMessage.contains("Cannot downcast value")
+ )
+ }
+ forAll { x: Int =>
+ assertExceptionThrown(
+ SInt.downcast(CBigInt(new BigInteger(x.toString)).asInstanceOf[AnyVal]),
+ _.getMessage.contains("Cannot downcast value")
+ )
+ }
+ forAll { x: Byte =>
+ assertExceptionThrown(
+ SByte.downcast(CBigInt(new BigInteger(x.toString)).asInstanceOf[AnyVal]),
+ _.getMessage.contains("Cannot downcast value")
+ )
+ }
+ forAll { x: Short =>
+ assertExceptionThrown(
+ SShort.downcast(CBigInt(new BigInteger(x.toString)).asInstanceOf[AnyVal]),
+ _.getMessage.contains("Cannot downcast value")
+ )
+ }
+ } else {
+ forAll { x: BigInteger =>
+ SBigInt.upcast(CBigInt(x).asInstanceOf[AnyVal]) shouldBe CBigInt(x)
+ SBigInt.downcast(CBigInt(x).asInstanceOf[AnyVal]) shouldBe CBigInt(x)
+ }
+ forAll { x: Long =>
+ SLong.downcast(CBigInt(new BigInteger(x.toString)).asInstanceOf[AnyVal]) shouldBe x
+ }
+ forAll { x: Int =>
+ SInt.downcast(CBigInt(new BigInteger(x.toString)).asInstanceOf[AnyVal]) shouldBe x
+ }
+ forAll { x: Byte =>
+ SByte.downcast(CBigInt(new BigInteger(x.toString)).asInstanceOf[AnyVal]) shouldBe x
+ }
+ forAll { x: Short =>
+ SShort.downcast(CBigInt(new BigInteger(x.toString)).asInstanceOf[AnyVal]) shouldBe x
+ }
+ }
+
+ lazy val bitOr = newFeature[(BigInt, BigInt), BigInt](
+ { (x: (BigInt, BigInt)) => (x._1 | x._2)},
+ "{ (x: (BigInt, BigInt)) => x._1.bitwiseOr(x._2) }",
+ FuncValue(
+ Array((1, SPair(SBigInt, SBigInt))),
+ MethodCall.typed[Value[SBigInt.type]](
+ SelectField.typed[Value[SBigInt.type]](ValUse(1,SPair(SBigInt, SBigInt)), 1.toByte),
+ SBigIntMethods.v6Methods.find(_.name == "bitwiseOr").get,
+ Vector(SelectField.typed[Value[SBigInt.type]](ValUse(1, SPair(SBigInt, SBigInt)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CBigInt(BigInteger.valueOf(1)), CBigInt(BigInteger.valueOf(2))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(3))), None)),
+ (CBigInt(BigInteger.valueOf(1001)), CBigInt(BigInteger.valueOf(2002))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(2043))), None)),
+ (CBigInt(BigInteger.valueOf(100001)), CBigInt(BigInteger.valueOf(20002))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(118435))), None)),
+ (CBigInt(BigInteger.valueOf(1000010111)), CBigInt(BigInteger.valueOf(-22))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(-1))), None))
+ ),
+ bitOr
+ )
+
+ lazy val bitNot = newFeature[BigInt, BigInt](
+ { (x: BigInt) => CBigInt(x.asInstanceOf[CBigInt].wrappedValue.not()) },
+ "{ (x: BigInt) => x.bitwiseInverse }",
+ FuncValue(
+ Array((1, SBigInt)),
+ MethodCall.typed[Value[SBigInt.type]](
+ ValUse(1, SBigInt),
+ SBigIntMethods.v6Methods.find(_.name == "bitwiseInverse").get,
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ CBigInt(BigInteger.valueOf(1)) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(-2))), None)),
+ CBigInt(BigInteger.valueOf(10001)) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(-10002))), None)),
+ CBigInt(BigInteger.valueOf(Int.MinValue)) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(Int.MaxValue))), None)),
+ CBigInt(BigInteger.valueOf(Long.MinValue)) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(Long.MaxValue))), None)),
+ CBigInt(BigInteger.valueOf(Long.MaxValue)) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(Long.MinValue))), None))
+ ),
+ bitNot
+ )
+
+ lazy val bitAnd = newFeature(
+ { (x: (BigInt, BigInt)) => x._1.asInstanceOf[CBigInt].and(x._2.asInstanceOf[CBigInt]) },
+ "{ (x: (BigInt, BigInt)) => x._1.bitwiseAnd(x._2) }",
+ FuncValue(
+ Array((1, SPair(SBigInt, SBigInt))),
+ MethodCall.typed[Value[SBigInt.type]](
+ SelectField.typed[Value[SBigInt.type]](ValUse(1, SPair(SBigInt, SBigInt)), 1.toByte),
+ SBigIntMethods.v6Methods.find(_.name == "bitwiseAnd").get,
+ Vector(SelectField.typed[Value[SBigInt.type]](ValUse(1, SPair(SBigInt, SBigInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CBigInt(BigInteger.valueOf(3)), CBigInt(BigInteger.valueOf(5))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(1))), None)),
+ (CBigInt(BigInteger.valueOf(10001)), CBigInt(BigInteger.valueOf(2202))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(16))), None)),
+ (CBigInt(BigInteger.valueOf(-10001)), CBigInt(BigInteger.valueOf(200202))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(198666))), None)),
+ (CBigInt(BigInteger.valueOf(1000010111)), CBigInt(BigInteger.valueOf(-22))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(1000010090))), None))
+ ),
+ bitAnd
+ )
+
+ lazy val bitXor = newFeature(
+ { (x: (BigInt, BigInt)) => x._1.asInstanceOf[CBigInt].xor(x._2.asInstanceOf[CBigInt]) },
+ "{ (x: (BigInt, BigInt)) => x._1.bitwiseXor(x._2) }",
+ FuncValue(
+ Array((1, SPair(SBigInt, SBigInt))),
+ MethodCall.typed[Value[SBigInt.type]](
+ SelectField.typed[Value[SBigInt.type]](ValUse(1, SPair(SBigInt, SBigInt)), 1.toByte),
+ SBigIntMethods.v6Methods.find(_.name == "bitwiseXor").get,
+ Vector(SelectField.typed[Value[SBigInt.type]](ValUse(1, SPair(SBigInt, SBigInt)),2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CBigInt(BigInteger.valueOf(3)), CBigInt(BigInteger.valueOf(5))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(6))), None)),
+ (CBigInt(BigInteger.valueOf(10001)), CBigInt(BigInteger.valueOf(2202))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(12171))), None)),
+ (CBigInt(BigInteger.valueOf(-10001)), CBigInt(BigInteger.valueOf(200202))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(-207131))), None)),
+ (CBigInt(BigInteger.valueOf(1000010111)), CBigInt(BigInteger.valueOf(-22))) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(-1000010091))), None))
+ ),
+ bitXor
+ )
+
+ lazy val toBigEndianBytes = newFeature[BigInt, Coll[Byte]](
+ { x: BigInt => x.toBytes },
+ "{ (x: BigInt) => x.toBytes }",
+ FuncValue(
+ Array((1, SBigInt)),
+ MethodCall.typed[Value[SCollection[SBigInt.type]]](
+ ValUse(1, SBigInt),
+ SBigIntMethods.getMethodByName("toBytes"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ CBigInt(BigInteger.valueOf(127)) -> new Expected(ExpectedResult(Success(Coll(127.toByte)), None)),
+ CBigInt(BigInteger.valueOf(Short.MaxValue)) -> new Expected(ExpectedResult(Success(Coll(127.toByte, (-1).toByte)), None)),
+ CBigInt(BigInteger.valueOf(Short.MinValue)) -> new Expected(ExpectedResult(Success(Coll((-128).toByte, 0.toByte)), None)),
+ CBigInt(BigInteger.valueOf(Int.MaxValue)) -> new Expected(ExpectedResult(Success(Coll(127.toByte, (-1).toByte, (-1).toByte, (-1).toByte)), None))
+ ),
+ toBigEndianBytes
+ )
+
+ def byte2Bools(b: Byte): Seq[Boolean] =
+ (0 to 7 map isBitSet(b)).reverse
+
+ def isBitSet(byte: Byte)(bit: Int): Boolean =
+ ((byte >> bit) & 1) == 1
+
+ lazy val toBits = newFeature[BigInt, Coll[Boolean]](
+ { x: BigInt => x.toBytes.flatMap(b => Colls.fromArray(byte2Bools(b).toArray)) },
+ "{ (x: BigInt) => x.toBits }",
+ FuncValue(
+ Array((1, SBigInt)),
+ MethodCall.typed[Value[SCollection[SBigInt.type]]](
+ ValUse(1, SBigInt),
+ SBigIntMethods.getMethodByName("toBits"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ CBigInt(BigInteger.valueOf(83)) -> new Expected(ExpectedResult(Success(Coll(false, true, false, true, false, false, true, true)), None)),
+ CBigInt(BigInteger.valueOf(-55)) -> new Expected(ExpectedResult(Success(Coll(true, true, false, false, true, false, false, true)), None)),
+ CBigInt(BigInteger.valueOf(-1L)) -> new Expected(ExpectedResult(Success(Colls.fromArray(Array.fill(8)(true))), None)),
+ CBigInt(BigInteger.valueOf(-10001L)) -> new Expected(ExpectedResult(Success(Coll(true,true,false,true,true,false,false,false,true,true,true,false,true,true,true,true)), None))
+ ),
+ toBits
+ )
+
+ lazy val shiftLeft = newFeature(
+ { (x: (BigInt, Int)) => if(x._2 < 0 || x._2 >= 256) throw new IllegalArgumentException() else (x._1.asInstanceOf[BigInt].shiftLeft(x._2)) },
+ "{ (x: (BigInt, Int)) => x._1.shiftLeft(x._2) }",
+ FuncValue(
+ Array((1, SPair(SBigInt, SInt))),
+ MethodCall.typed[Value[SBigInt.type]](
+ SelectField.typed[Value[SBigInt.type]](ValUse(1, SPair(SBigInt, SInt)), 1.toByte),
+ SBigIntMethods.v6Methods.find(_.name == "shiftLeft").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SBigInt, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CBigInt(BigInteger.valueOf(3)), 3) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(24))), None)),
+ (CBigInt(BigInteger.valueOf(3)), 8) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(768))), None)),
+ (CBigInt(BigInteger.valueOf(-2)), 10) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(-2048))), None)),
+ (CBigInt(BigInteger.valueOf(-222)), 10) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(-227328L))), None)),
+ (CBigInt(BigInteger.valueOf(-222)), -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)),
+ (CBigInt(BigInteger.valueOf(-222)), 256) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None))
+ ),
+ shiftLeft,
+ preGeneratedSamples = Some(Seq())
+ )
+
+ lazy val shiftRight = newFeature(
+ { (x: (BigInt, Int)) => if(x._2 < 0 || x._2 >= 256) throw new IllegalArgumentException() else (x._1.asInstanceOf[BigInt].shiftRight(x._2)) },
+ "{ (x: (BigInt, Int)) => x._1.shiftRight(x._2) }",
+ FuncValue(
+ Array((1, SPair(SBigInt, SInt))),
+ MethodCall.typed[Value[SBigInt.type]](
+ SelectField.typed[Value[SBigInt.type]](ValUse(1, SPair(SBigInt, SInt)), 1.toByte),
+ SBigIntMethods.v6Methods.find(_.name == "shiftRight").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SBigInt, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CBigInt(BigInteger.valueOf(24)), 3) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(3))), None)),
+ (CBigInt(BigInteger.valueOf(1600)), 8) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(6))), None)),
+ (CBigInt(BigInteger.valueOf(-3200)), 8) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(-13))), None)),
+ (CBigInt(BigInteger.valueOf(-320019)), 18) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(-2))), None)),
+ (CBigInt(BigInteger.valueOf(-320019)), 63) -> new Expected(ExpectedResult(Success(CBigInt(BigInteger.valueOf(-1))), None)),
+ (CBigInt(BigInteger.valueOf(24)), -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)),
+ (CBigInt(BigInteger.valueOf(24)), 256) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None))
+ ),
+ shiftRight,
+ preGeneratedSamples = Some(Seq())
+ )
+ }
+
+ property("Box properties equivalence (new features)") {
+ // related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/416
+ def getReg = newFeature((x: Box) => x.getReg[Long](0).get,
+ "{ (x: Box) => x.getReg[Long](0).get }",
+ FuncValue(
+ Array((1, SBox)),
+ OptionGet(ExtractRegisterAs(ValUse(1, SBox), ErgoBox.R0, SOption(SLong)))
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ // NOTE, for such versions getReg is not supported
+ // which is checked below
+
+ forAll { box: Box =>
+ Seq(getReg).foreach(_.checkEquality(box))
+ }
+ } else {
+ val value = 10L
+ val box = CBox(new ErgoBox(value, TrueTree, Colls.emptyColl[Token], Map.empty,
+ ModifierId @@ Base16.encode(Array.fill(32)(0)), 0, 0))
+ verifyCases(
+ Seq(
+ box -> new Expected(ExpectedResult(Success(value), None))
+ ),
+ getReg
+ )
+ }
+ }
+
+ // 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 = 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 = 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 = 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 = 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 = 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 = V6SoftForkVersion)
+
+ if (activatedVersionInTests < VersionContext.V6SoftForkVersion) {
+ // NOTE, for such versions getReg is not supported
+ // which is checked below
+
+ forAll { x: Coll[SigmaProp] =>
+ anyZK.checkEquality(x)
+ }
+ }
+ }
+
+ property("Numeric.toBytes methods equivalence") {
+ lazy val toBytes = newFeature(
+ { (x: Byte) => x.toBigEndianBytes },
+ "{ (x: Byte) => x.toBytes }",
+ FuncValue(
+ Array((1, SByte)),
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ ValUse(1, SByte),
+ SByteMethods.getMethodByName("toBytes"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+ val cases = Seq(
+ (0.toByte, Success(Coll(0.toByte))),
+ (1.toByte, Success(Coll(1.toByte)))
+ )
+
+ testCases(cases, toBytes)
+ }
+
+ property("Fix substConstants in v6.0 for ErgoTree version > 0") {
+ // tree with one segregated constant and v0
+ val t1 = ErgoTree(
+ header = ErgoTree.setConstantSegregation(ZeroHeader),
+ constants = Vector(TrueSigmaProp),
+ ConstantPlaceholder(0, SSigmaProp))
+
+ // tree with one segregated constant and max supported version
+ val t2 = ErgoTree(
+ header = ErgoTree.setConstantSegregation(
+ ErgoTree.headerWithVersion(ZeroHeader, VersionContext.MaxSupportedScriptVersion)
+ ),
+ Vector(TrueSigmaProp),
+ ConstantPlaceholder(0, SSigmaProp))
+
+ def costDetails(nItems: Int) = TracedCost(
+ traceBase ++ Array(
+ FixedCostItem(SelectField),
+ FixedCostItem(ConcreteCollection),
+ FixedCostItem(ValUse),
+ FixedCostItem(SelectField),
+ FixedCostItem(ConcreteCollection),
+ FixedCostItem(Constant),
+ FixedCostItem(BoolToSigmaProp),
+ ast.SeqCostItem(CompanionDesc(SubstConstants), PerItemCost(JitCost(100), JitCost(100), 1), nItems)
+ )
+ )
+ val expectedTreeBytes_beforeV6 = Helpers.decodeBytes("1b0108d27300")
+ val expectedTreeBytes_V6 = Helpers.decodeBytes("1b050108d27300")
+
+ verifyCases(
+ Seq(
+ // for tree v0, the result is the same for all versions
+ (Coll(t1.bytes: _*), 0) -> Expected(
+ Success(Helpers.decodeBytes("100108d27300")),
+ cost = 1793,
+ expectedDetails = CostDetails.ZeroCost,
+ newCost = 2065,
+ newVersionedResults = expectedSuccessForAllTreeVersions(Helpers.decodeBytes("100108d27300"), 2065, costDetails(1))
+ ),
+ // for tree version > 0, the result depend on activated version
+ (Coll(t2.bytes: _*), 0) -> Expected(
+ Success(expectedTreeBytes_beforeV6),
+ cost = 1793,
+ expectedDetails = CostDetails.ZeroCost,
+ newCost = 2065,
+ newVersionedResults = expectedSuccessForAllTreeVersions(expectedTreeBytes_V6, 2065, costDetails(1)))
+ ),
+ changedFeature(
+ changedInVersion = VersionContext.V6SoftForkVersion,
+ { (x: (Coll[Byte], Int)) =>
+ SigmaDsl.substConstants(x._1, Coll[Int](x._2), Coll[Any](SigmaDsl.sigmaProp(false))(sigma.AnyType))
+ },
+ { (x: (Coll[Byte], Int)) =>
+ SigmaDsl.substConstants(x._1, Coll[Int](x._2), Coll[Any](SigmaDsl.sigmaProp(false))(sigma.AnyType))
+ },
+ "{ (x: (Coll[Byte], Int)) => substConstants[Any](x._1, Coll[Int](x._2), Coll[Any](sigmaProp(false))) }",
+ FuncValue(
+ Vector((1, SPair(SByteArray, SInt))),
+ SubstConstants(
+ SelectField.typed[Value[SCollection[SByte.type]]](ValUse(1, SPair(SByteArray, SInt)), 1.toByte),
+ ConcreteCollection(
+ Array(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SByteArray, SInt)), 2.toByte)),
+ SInt
+ ),
+ ConcreteCollection(Array(BoolToSigmaProp(FalseLeaf)), SSigmaProp)
+ )
+ )
+ )
+ )
+
+ // before v6.0 the expected tree is not parsable
+ ErgoTree.fromBytes(expectedTreeBytes_beforeV6.toArray).isRightParsed shouldBe false
+
+ // in v6.0 the expected tree should be parsable and similar to the original tree
+ val tree = ErgoTree.fromBytes(expectedTreeBytes_V6.toArray)
+ tree.isRightParsed shouldBe true
+ tree.header shouldBe t2.header
+ tree.constants.length shouldBe t2.constants.length
+ 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
+ )
+ }
+
+ property("higher order lambdas") {
+ val f = newFeature[Coll[Int], Coll[Int]](
+ { (xs: Coll[Int]) =>
+ val inc = { (x: Int) => x + 1 }
+
+ def apply(in: (Int => Int, Int)) = in._1(in._2)
+
+ xs.map { (x: Int) => apply((inc, x)) }
+ },
+ """{(xs: Coll[Int]) =>
+ | val inc = { (x: Int) => x + 1 }
+ | def apply(in: (Int => Int, Int)) = in._1(in._2)
+ | xs.map { (x: Int) => apply((inc, x)) }
+ | }
+ |""".stripMargin,
+ FuncValue(
+ Array((1, SCollectionType(SInt))),
+ MapCollection(
+ ValUse(1, SCollectionType(SInt)),
+ FuncValue(
+ Array((3, SInt)),
+ Apply(
+ FuncValue(
+ Array((5, SPair(SFunc(Array(SInt), SInt, List()), SInt))),
+ Apply(
+ SelectField.typed[Value[SFunc]](
+ ValUse(5, SPair(SFunc(Array(SInt), SInt, List()), SInt)),
+ 1.toByte
+ ),
+ Array(
+ SelectField.typed[Value[SInt.type]](
+ ValUse(5, SPair(SFunc(Array(SInt), SInt, List()), SInt)),
+ 2.toByte
+ )
+ )
+ )
+ ),
+ Array(
+ Tuple(
+ Vector(
+ FuncValue(
+ Array((5, SInt)),
+ ArithOp(ValUse(5, SInt), IntConstant(1), OpCode @@ (-102.toByte))
+ ),
+ ValUse(3, SInt)
+ )
+ )
+ )
+ )
+ )
+ )
+ ),
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+
+ verifyCases(
+ Seq(
+ Coll(1, 2) -> Expected(
+ Success(Coll(2, 3)),
+ cost = 1793,
+ expectedDetails = CostDetails.ZeroCost
+ )
+ ),
+ f,
+ preGeneratedSamples = Some(Seq(
+ Coll(Int.MinValue, Int.MaxValue - 1),
+ Coll(0, 1, 2, 3, 100, 1000)
+ ))
+ )
+ }
+
+ private def contextData() = {
+ val input = CBox(
+ new ErgoBox(
+ 80946L,
+ new ErgoTree(
+ HeaderType @@ 16.toByte,
+ Vector(
+ SigmaPropConstant(
+ CSigmaProp(
+ ProveDHTuple(
+ Helpers.decodeECPoint("03c046fccb95549910767d0543f5e8ce41d66ae6a8720a46f4049cac3b3d26dafb"),
+ Helpers.decodeECPoint("023479c9c3b86a0d3c8be3db0a2d186788e9af1db76d55f3dad127d15185d83d03"),
+ Helpers.decodeECPoint("03d7898641cb6653585a8e1dabfa7f665e61e0498963e329e6e3744bd764db2d72"),
+ Helpers.decodeECPoint("037ae057d89ec0b46ff8e9ff4c37e85c12acddb611c3f636421bef1542c11b0441")
+ )
+ )
+ )
+ ),
+ Right(ConstantPlaceholder(0, SSigmaProp))
+ ),
+ Coll(),
+ Map(
+ ErgoBox.R4 -> ByteArrayConstant(Helpers.decodeBytes("34")),
+ ErgoBox.R5 -> TrueLeaf
+ ),
+ ModifierId @@ ("0000bfe96a7c0001e7a5ee00aafb80ff057fbe7f8c6680e33a3dc18001820100"),
+ 1.toShort,
+ 5
+ )
+ )
+
+ val tx = ErgoLikeTransaction(
+ IndexedSeq(),
+ IndexedSeq(input.wrappedValue)
+ )
+
+ val tx2 = ErgoLikeTransaction(
+ IndexedSeq(Input(input.ebox.id, ProverResult(Array.emptyByteArray, ContextExtension(Map(11.toByte -> BooleanConstant(true)))))),
+ IndexedSeq(input.wrappedValue)
+ )
+
+ val tx3 = ErgoLikeTransaction(
+ IndexedSeq(Input(input.ebox.id, ProverResult(Array.emptyByteArray, ContextExtension(Map(11.toByte -> IntConstant(0)))))),
+ IndexedSeq(input.wrappedValue)
+ )
+
+ val tx4 = ErgoLikeTransaction(
+ IndexedSeq(Input(input.ebox.id, ProverResult(Array.emptyByteArray, ContextExtension(Map(11.toByte -> BooleanConstant(false)))))),
+ IndexedSeq(input.wrappedValue)
+ )
+
+ val ctx = CContext(
+ _dataInputs = Coll[Box](),
+ headers = Coll[Header](),
+ preHeader = CPreHeader(
+ 0.toByte,
+ Colls.fromArray(Array.fill(32)(0.toByte)),
+ -755484979487531112L,
+ 9223372036854775807L,
+ 11,
+ Helpers.decodeGroupElement("0227a58e9b2537103338c237c52c1213bf44bdb344fa07d9df8ab826cca26ca08f"),
+ Helpers.decodeBytes("007f00")
+ ),
+ inputs = Coll[Box](input),
+ outputs = Coll[Box](),
+ height = 11,
+ selfBox = input.copy(), // in 3.x, 4.x implementation selfBox is never the same instance as input (see toSigmaContext)
+ selfIndex = 0,
+ lastBlockUtxoRootHash = CAvlTree(
+ AvlTreeData(
+ ErgoAlgos.decodeUnsafe("54d23dd080006bdb56800100356080935a80ffb77e90b800057f00661601807f17").toColl,
+ AvlTreeFlags(true, true, true),
+ 1211925457,
+ None
+ )
+ ),
+ _minerPubKey = Helpers.decodeBytes("0227a58e9b2537103338c237c52c1213bf44bdb344fa07d9df8ab826cca26ca08f"),
+ vars = Colls
+ .replicate[AnyValue](10, null) // reserve 10 vars
+ .append(Coll[AnyValue](
+ CAnyValue(Helpers.decodeBytes("00")),
+ CAnyValue(true))),
+ spendingTransaction = tx,
+ activatedScriptVersion = activatedVersionInTests,
+ currentErgoTreeVersion = ergoTreeVersionInTests
+ )
+ val ctx2 = ctx.copy(spendingTransaction = tx2)
+ val ctx3 = ctx.copy(spendingTransaction = tx3, vars = ctx.vars.patch(11, Coll(CAnyValue(0)), 1))
+ val ctx4 = ctx.copy(spendingTransaction = tx4, vars = ctx.vars.patch(11, Coll(CAnyValue(false)), 1))
+
+ (ctx, ctx2, ctx3, ctx4)
+ }
+
+ property("getVarFromInput") {
+
+ def getVarFromInput = {
+ newFeature(
+ { (x: Context) => x.getVarFromInput[Boolean](0, 11) },
+ "{ (x: Context) => x.getVarFromInput[Boolean](0, 11) }",
+ FuncValue(
+ Array((1, SContext)),
+ MethodCall.typed[Value[SOption[SBoolean.type]]](
+ ValUse(1, SContext),
+ SContextMethods.getVarFromInputMethod.withConcreteTypes(Map(STypeVar("T") -> SBoolean)),
+ Array(ShortConstant(0.toShort), ByteConstant(11.toByte)),
+ Map(STypeVar("T") -> SBoolean)
+ )
+ ),
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+ }
+
+ val (ctx, ctx2, ctx3, ctx4) = contextData()
+
+ verifyCases(
+ Seq(
+ ctx -> new Expected(ExpectedResult(Success(None), None)), // input with # provided does not exist
+ ctx2 -> new Expected(ExpectedResult(Success(Some(true)), None)),
+ ctx3 -> new Expected(ExpectedResult(Success(None), None)), // not expected type in context var
+ ctx4 -> new Expected(ExpectedResult(Success(Some(false)), None))
+ ),
+ getVarFromInput
+ )
+ }
+
+ property("Context.getVar") {
+
+ def getVar = {
+ newFeature(
+ { (x: Context) => x.getVar[Boolean](11)},
+ "{ (x: Context) => CONTEXT.getVar[Boolean](11.toByte) }",
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+ }
+
+ val (_, ctx2, ctx3, ctx4) = contextData()
+
+ verifyCases(
+ Seq(
+ ctx2 -> new Expected(ExpectedResult(Success(Some(true)), None)),
+ ctx3 -> new Expected(ExpectedResult(Failure(new sigma.exceptions.InvalidType("Cannot getVar[Boolean](11): invalid type of value TestValue(0) at id=11")), None)), // not expected type in context var
+ ctx4 -> new Expected(ExpectedResult(Success(Some(false)), None))
+ ),
+ getVar
+ )
+ }
+
+ property("Option.getOrElse with lazy default") {
+
+ val trace = TracedCost(
+ Array(
+ FixedCostItem(Apply),
+ FixedCostItem(FuncValue),
+ FixedCostItem(GetVar),
+ FixedCostItem(OptionGet),
+ FixedCostItem(FuncValue.AddToEnvironmentDesc, FixedCost(JitCost(5))),
+ FixedCostItem(ValUse),
+ FixedCostItem(OptionGetOrElse)
+ )
+ )
+
+ verifyCases(
+ Seq(
+ Some(2L) -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793,
+ newVersionedResults = {
+ expectedSuccessForAllTreeVersions(2L, 2015, trace)
+ } ),
+ None -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793)
+ ),
+ changedFeature(
+ changedInVersion = VersionContext.V6SoftForkVersion,
+ { (x: Option[Long]) => val default = 1 / 0L; x.getOrElse(default) },
+ { (x: Option[Long]) => if (VersionContext.current.isV6SoftForkActivated) {x.getOrElse(1 / 0L)} else {val default = 1 / 0L; x.getOrElse(default)} },
+ "{ (x: Option[Long]) => x.getOrElse(1 / 0L) }",
+ FuncValue(
+ Array((1, SOption(SLong))),
+ OptionGetOrElse(
+ ValUse(1, SOption(SLong)),
+ ArithOp(LongConstant(1L), LongConstant(0L), OpCode @@ (-99.toByte))
+ )
+ ),
+ allowNewToSucceed = true
+ )
+ )
+ }
+
+ property("Coll getOrElse with lazy default") {
+
+ val trace = TracedCost(
+ Array(
+ FixedCostItem(Apply),
+ FixedCostItem(FuncValue),
+ FixedCostItem(GetVar),
+ FixedCostItem(OptionGet),
+ FixedCostItem(FuncValue.AddToEnvironmentDesc, FixedCost(JitCost(5))),
+ FixedCostItem(ValUse),
+ FixedCostItem(Constant),
+ FixedCostItem(ByIndex)
+ )
+ )
+
+ def scalaFuncNew(x: Coll[Int]) = {
+ if (VersionContext.current.isV6SoftForkActivated) {
+ x.toArray.toIndexedSeq.headOption.getOrElse(1 / 0)
+ } else scalaFuncOld(x)
+ }
+
+ def scalaFuncOld(x: Coll[Int]) = {
+ x.getOrElse(0, 1 / 0)
+ }
+
+ verifyCases(
+ Seq(
+ Coll(1) -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793,
+ newVersionedResults = {
+ expectedSuccessForAllTreeVersions(1, 2029, trace)
+ } ),
+ Coll[Int]() -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793)
+ ),
+ changedFeature(
+ changedInVersion = VersionContext.V6SoftForkVersion,
+ scalaFuncOld,
+ scalaFuncNew,
+ "{ (x: Coll[Int]) => x.getOrElse(0, 1 / 0) }",
+ FuncValue(
+ Array((1, SCollectionType(SInt))),
+ ByIndex(
+ ValUse(1, SCollectionType(SInt)),
+ IntConstant(0),
+ Some(ArithOp(IntConstant(1), IntConstant(0), OpCode @@ (-99.toByte)))
+ )
+ ),
+ allowNewToSucceed = true
+ )
+ )
+ }
+
+
+ property("Global - fromBigEndianBytes") {
+ import sigma.data.OrderingOps.BigIntOrdering
+
+ def byteFromBigEndianBytes: Feature[Byte, Boolean] = {
+ newFeature(
+ { (x: Byte) => CSigmaDslBuilder.fromBigEndianBytes[Byte](Colls.fromArray(Array(x))) == x},
+ "{ (x: Byte) => fromBigEndianBytes[Byte](x.toBytes) == x }",
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+ }
+
+ verifyCases(
+ Seq(
+ 5.toByte -> new Expected(ExpectedResult(Success(true), None)),
+ Byte.MaxValue -> new Expected(ExpectedResult(Success(true), None)),
+ Byte.MinValue -> new Expected(ExpectedResult(Success(true), None))
+ ),
+ byteFromBigEndianBytes
+ )
+
+ def shortFromBigEndianBytes: Feature[Short, Boolean] = {
+ newFeature(
+ { (x: Short) => CSigmaDslBuilder.fromBigEndianBytes[Short](Colls.fromArray(Shorts.toByteArray(x))) == x},
+ "{ (x: Short) => fromBigEndianBytes[Short](x.toBytes) == x }",
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+ }
+
+ verifyCases(
+ Seq(
+ 5.toShort -> new Expected(ExpectedResult(Success(true), None)),
+ Short.MaxValue -> new Expected(ExpectedResult(Success(true), None)),
+ Short.MinValue -> new Expected(ExpectedResult(Success(true), None))
+ ),
+ shortFromBigEndianBytes
+ )
+
+ def intFromBigEndianBytes: Feature[Int, Boolean] = {
+ newFeature(
+ { (x: Int) => CSigmaDslBuilder.fromBigEndianBytes[Int](Colls.fromArray(Ints.toByteArray(x))) == x},
+ "{ (x: Int) => fromBigEndianBytes[Int](x.toBytes) == x }",
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+ }
+
+ verifyCases(
+ Seq(
+ 5 -> new Expected(ExpectedResult(Success(true), None)),
+ Int.MaxValue -> new Expected(ExpectedResult(Success(true), None))
+ ),
+ intFromBigEndianBytes
+ )
+
+ def longFromBigEndianBytes: Feature[Long, Boolean] = {
+ newFeature(
+ { (x: Long) => CSigmaDslBuilder.fromBigEndianBytes[Long](Colls.fromArray(Longs.toByteArray(x))) == x},
+ "{ (x: Long) => fromBigEndianBytes[Long](x.toBytes) == x }",
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+ }
+
+ verifyCases(
+ Seq(
+ 5L -> new Expected(ExpectedResult(Success(true), None)),
+ Long.MinValue -> new Expected(ExpectedResult(Success(true), None))
+ ),
+ longFromBigEndianBytes
+ )
+
+ def bigIntFromBigEndianBytes: Feature[BigInt, Boolean] = {
+ newFeature(
+ { (x: BigInt) => CSigmaDslBuilder.fromBigEndianBytes[BigInt](x.toBytes) == x},
+ "{ (x: BigInt) => Global.fromBigEndianBytes[BigInt](x.toBytes) == x }",
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+ }
+
+ verifyCases(
+ Seq(
+ CBigInt(BigInteger.valueOf(50)) -> new Expected(ExpectedResult(Success(true), None)),
+ CBigInt(BigInteger.valueOf(-500000000000L)) -> new Expected(ExpectedResult(Success(true), None)),
+ CBigInt(sigma.crypto.CryptoConstants.groupOrder.divide(BigInteger.valueOf(2))) -> new Expected(ExpectedResult(Success(true), None))
+ ),
+ bigIntFromBigEndianBytes
+ )
+
+ }
+
+ property("Coll.reverse") {
+ val f = newFeature[Coll[Int], Coll[Int]](
+ { (xs: Coll[Int]) => xs.reverse },
+ """{(xs: Coll[Int]) => xs.reverse }""".stripMargin,
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+
+ verifyCases(
+ Seq(
+ Coll(1, 2) -> Expected(ExpectedResult(Success(Coll(2, 1)), None)),
+ Coll[Int]() -> Expected(ExpectedResult(Success(Coll[Int]()), None))
+ ),
+ f
+ )
+ }
+
+ property("Coll.distinct") {
+ val f = newFeature[Coll[Int], Coll[Int]](
+ { (xs: Coll[Int]) => xs.distinct },
+ """{(xs: Coll[Int]) => xs.distinct }""".stripMargin,
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+
+ verifyCases(
+ Seq(
+ Coll(1, 2) -> Expected(ExpectedResult(Success(Coll(1, 2)), None)),
+ Coll(1, 1, 2) -> Expected(ExpectedResult(Success(Coll(1, 2)), None)),
+ Coll(1, 2, 2) -> Expected(ExpectedResult(Success(Coll(1, 2)), None)),
+ Coll(2, 2, 2) -> Expected(ExpectedResult(Success(Coll(2)), None)),
+ Coll(3, 1, 2, 2, 2, 4, 4, 1) -> Expected(ExpectedResult(Success(Coll(3, 1, 2, 4)), None)),
+ Coll[Int]() -> Expected(ExpectedResult(Success(Coll[Int]()), None))
+ ),
+ f
+ )
+ }
+
+ property("Coll.startsWith") {
+ val f = newFeature[(Coll[Int], Coll[Int]), Boolean](
+ { (xs: (Coll[Int], Coll[Int])) => xs._1.startsWith(xs._2) },
+ """{(xs: (Coll[Int], Coll[Int])) => xs._1.startsWith(xs._2) }""".stripMargin,
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+
+ verifyCases(
+ Seq(
+ (Coll(1, 2, 3), Coll(1, 2)) -> Expected(ExpectedResult(Success(true), None)),
+ (Coll(1, 2, 3), Coll(1, 2, 3)) -> Expected(ExpectedResult(Success(true), None)),
+ (Coll(1, 2, 3), Coll(1, 2, 4)) -> Expected(ExpectedResult(Success(false), None)),
+ (Coll(1, 2, 3), Coll(1, 2, 3, 4)) -> Expected(ExpectedResult(Success(false), None)),
+ (Coll[Int](), Coll[Int]()) -> Expected(ExpectedResult(Success(true), None)),
+ (Coll[Int](1, 2), Coll[Int]()) -> Expected(ExpectedResult(Success(true), None))
+ ),
+ f
+ )
+ }
+
+ property("Coll.endsWith") {
+ val f = newFeature[(Coll[Int], Coll[Int]), Boolean](
+ { (xs: (Coll[Int], Coll[Int])) => xs._1.endsWith(xs._2) },
+ """{(xs: (Coll[Int], Coll[Int])) => xs._1.endsWith(xs._2) }""".stripMargin,
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+
+ verifyCases(
+ Seq(
+ (Coll(1, 2, 3), Coll(1, 2)) -> Expected(ExpectedResult(Success(false), None)),
+ (Coll(1, 2, 3), Coll(2, 3)) -> Expected(ExpectedResult(Success(true), None)),
+ (Coll(1, 2, 3), Coll(2, 3, 4)) -> Expected(ExpectedResult(Success(false), None)),
+ (Coll(1, 2, 3), Coll(1, 2, 3)) -> Expected(ExpectedResult(Success(true), None)),
+ (Coll[Int](), Coll[Int]()) -> Expected(ExpectedResult(Success(true), None))
+ ),
+ f
+ )
+ }
+
+ property("Coll.get") {
+ val f = newFeature[(Coll[Int], Int), Option[Int]](
+ { (xs: (Coll[Int], Int)) => xs._1.get(xs._2) },
+ """{(xs: (Coll[Int], Int)) => xs._1.get(xs._2) }""".stripMargin,
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+
+ verifyCases(
+ Seq(
+ (Coll(1, 2), 0) -> Expected(ExpectedResult(Success(Some(1)), None)),
+ (Coll(1, 2), 1) -> Expected(ExpectedResult(Success(Some(2)), None)),
+ (Coll(1, 2), -1) -> Expected(ExpectedResult(Success(None), None)),
+ (Coll(1, 2), 2) -> Expected(ExpectedResult(Success(None), None)),
+ (Coll[Int](), 0) -> Expected(ExpectedResult(Success(None), None))
+ ),
+ f
+ )
+ }
+
+}
diff --git a/sc/shared/src/test/scala/sigma/SigmaDslStaginTests.scala b/sc/shared/src/test/scala/sigma/SigmaDslStaginTests.scala
index 5ac9b80889..266c5e66e5 100644
--- a/sc/shared/src/test/scala/sigma/SigmaDslStaginTests.scala
+++ b/sc/shared/src/test/scala/sigma/SigmaDslStaginTests.scala
@@ -2,6 +2,7 @@ package sigma
import org.scalatest.BeforeAndAfterAll
import scalan.{BaseCtxTests, BaseLiftableTests}
+import sigma.compiler.ir.IRContext
import sigma.data.TrivialProp
import sigma.eval.Extensions.toAnyValue
import sigmastate.eval._
@@ -28,13 +29,11 @@ class SigmaDslStaginTests extends BaseCtxTests with ErgoScriptTestkit with BaseL
type RContext = cake.Context
type RBox = cake.Box
type RSigmaProp = cake.SigmaProp
- val boxA1 = newAliceBox(1, 100)
- val boxA2 = newAliceBox(2, 200)
+ val boxA1 = newAliceBox(100)
+ val boxA2 = newAliceBox(200)
val ctx: SContext = newContext(10, boxA1, VersionContext.MaxSupportedScriptVersion, VersionContext.MaxSupportedScriptVersion)
.withInputs(boxA2)
.withVariables(Map(1 -> toAnyValue(30), 2 -> toAnyValue(40)))
- val p1: SSigmaProp = sigma.eval.SigmaDsl.SigmaProp(TrivialProp(true))
- val p2: SSigmaProp = sigma.eval.SigmaDsl.SigmaProp(TrivialProp(false))
cake.check(dsl, { env: EnvRep[RSigmaDslBuilder] =>
for { dsl <- env; arg <- lifted(true) } yield dsl.sigmaProp(arg) }, dsl.sigmaProp(true))
diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala
index 46222d9fb1..de9e080862 100644
--- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala
+++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala
@@ -14,6 +14,7 @@ import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
import scalan.Platform.threadSleepOrNoOp
import sigma.Extensions.ArrayOps
import sigma.data.{CBox, CollType, OptionType, PairType, ProveDlog, RType, SigmaLeaf}
+import sigma.VersionContext.V6SoftForkVersion
import sigma.util.BenchmarkUtil
import sigma.util.CollectionUtil._
import sigma.util.Extensions._
@@ -25,12 +26,13 @@ import sigma.ast._
import sigma.eval.{CostDetails, EvalSettings, SigmaDsl}
import sigmastate.crypto.DLogProtocol.DLogProverInput
import sigmastate.crypto.SigmaProtocolPrivateInput
-import sigmastate.eval.{CContext, CompiletimeIRContext, IRContext}
+import sigmastate.eval.CContext
import sigmastate.helpers.TestingHelpers._
import sigmastate.helpers.{CompilerTestingCommons, ErgoLikeContextTesting, ErgoLikeTestInterpreter, SigmaPPrint}
import sigmastate.interpreter.Interpreter.{ScriptEnv, VerificationResult}
import sigmastate.interpreter._
import sigma.ast.Apply
+import sigma.compiler.ir.{CompiletimeIRContext, IRContext}
import sigma.eval.Extensions.SigmaBooleanOps
import sigma.interpreter.{ContextExtension, ProverResult}
import sigma.serialization.ValueSerializer
@@ -122,6 +124,12 @@ 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
+
+ /** Version in which the feature is first implemented of changed. */
+ def sinceVersion: Byte
+
/** Script containing this feature. */
def script: String
@@ -176,13 +184,13 @@ class SigmaDslTesting extends AnyPropSpec
}
/** v3 and v4 implementation*/
- private var _oldF: CompiledFunc[A, B] = _
+ private var _oldF: Try[CompiledFunc[A, B]] = _
def oldF: CompiledFunc[A, B] = {
if (_oldF == null) {
- _oldF = oldImpl()
- checkExpectedExprIn(_oldF)
+ _oldF = Try(oldImpl())
+ _oldF.foreach(cf => checkExpectedExprIn(cf))
}
- _oldF
+ _oldF.getOrThrow
}
/** v5 implementation*/
@@ -253,6 +261,7 @@ class SigmaDslTesting extends AnyPropSpec
s"""Should succeed with the same value or fail with the same exception, but was:
|First result: $b1
|Second result: $b2
+ |Input: $x
|Root cause: $cause
|""".stripMargin)
}
@@ -322,14 +331,16 @@ class SigmaDslTesting extends AnyPropSpec
// Compile script the same way it is performed by applications (i.e. via Ergo Appkit)
val prop = compile(env, code)(IR).asSigmaProp
- // Add additional oparations which are not yet implemented in ErgoScript compiler
+ // Add additional operations which are not yet implemented in ErgoScript compiler
val multisig = AtLeast(
IntConstant(2),
Array(
pkAlice,
DeserializeRegister(ErgoBox.R5, SSigmaProp), // deserialize pkBob
DeserializeContext(2, SSigmaProp))) // deserialize pkCarol
- val header = ErgoTree.headerWithVersion(ZeroHeader, ergoTreeVersionInTests)
+ // We set size for trees v0 as well, to have the same size and so the same cost in V6 interpreter
+ // (where tree size is accounted in cost)
+ val header = ErgoTree.setSizeBit(ErgoTree.headerWithVersion(ZeroHeader, ergoTreeVersionInTests))
ErgoTree.withSegregation(header, SigmaOr(prop, multisig))
}
@@ -393,7 +404,7 @@ class SigmaDslTesting extends AnyPropSpec
ctx
}
- val (expectedResult, expectedCost) = if (activatedVersionInTests < VersionContext.JitActivationVersion)
+ val (expectedResult, expectedCost) = if (activatedVersionInTests < sinceVersion)
(expected.oldResult, expected.verificationCostOpt)
else {
val res = expected.newResults(ergoTreeVersionInTests)
@@ -452,7 +463,7 @@ class SigmaDslTesting extends AnyPropSpec
val verificationCost = cost.toIntExact
if (expectedCost.isDefined) {
assertResult(expectedCost.get,
- s"Actual verify() cost $cost != expected ${expectedCost.get}")(verificationCost)
+ s"Actual verify() cost $cost != expected ${expectedCost.get} (version: ${VersionContext.current.activatedVersion})")(verificationCost)
}
case Failure(t) => throw t
@@ -500,6 +511,10 @@ class SigmaDslTesting extends AnyPropSpec
implicit val cs = compilerSettingsInTests
+ override def sinceVersion: Byte = 0
+
+ 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)
@@ -634,10 +649,11 @@ class SigmaDslTesting extends AnyPropSpec
}
}
- /** Descriptor of a language feature which is changed in v5.0.
+ /** Descriptor of a language feature which is changed in the specified version.
*
* @tparam A type of an input test data
* @tparam B type of an output of the feature function
+ * @param changedInVersion version in which the feature behaviour is changed
* @param script script of the feature function (see Feature trait)
* @param scalaFunc feature function written in Scala and used to simulate the behavior
* of the script
@@ -657,6 +673,7 @@ class SigmaDslTesting extends AnyPropSpec
* @param allowDifferentErrors if true, allow v4.x and v5.0 to fail with different error
*/
case class ChangedFeature[A, B](
+ changedInVersion: Byte,
script: String,
scalaFunc: A => B,
override val scalaFuncNew: A => B,
@@ -670,6 +687,10 @@ class SigmaDslTesting extends AnyPropSpec
implicit val cs = compilerSettingsInTests
+ override def sinceVersion: Byte = changedInVersion
+
+ 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])
@@ -695,11 +716,17 @@ class SigmaDslTesting extends AnyPropSpec
override def checkEquality(input: A, logInputOutput: Boolean = false): Try[(B, CostDetails)] = {
// check the old implementation against Scala semantic function
var oldRes: Try[(B, CostDetails)] = null
- if (ergoTreeVersionInTests < VersionContext.JitActivationVersion)
oldRes = VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) {
try checkEq(scalaFunc)(oldF)(input)
catch {
- case e: TestFailedException => throw e
+ case e: TestFailedException =>
+ if(activatedVersionInTests < changedInVersion) {
+ throw e
+ } else {
+ // old ergoscript may succeed in new version while old scalafunc may fail,
+ // see e.g. "Option.getOrElse with lazy default" test
+ Failure(e)
+ }
case t: Throwable =>
Failure(t)
}
@@ -744,10 +771,10 @@ class SigmaDslTesting extends AnyPropSpec
override def checkExpected(input: A, expected: Expected[B]): Unit = {
// check the new implementation with Scala semantic function
val newRes = VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) {
- checkEq(scalaFuncNew)(newF)(input)
+ checkEq(scalaFuncNew)(newF)(input)
}
- if (!VersionContext.current.isJitActivated) {
+ if (VersionContext.current.activatedVersion < changedInVersion) {
// check the old implementation with Scala semantic
val expectedOldRes = expected.value
@@ -832,8 +859,17 @@ class SigmaDslTesting extends AnyPropSpec
* This in not yet implemented and will be finished in v6.0.
* In v5.0 is only checks that some features are NOT implemented, i.e. work for
* negative tests.
+ *
+ * @param sinceVersion language version (protocol) when the feature is introduced, see
+ * [[VersionContext]]
+ * @param script the script to be tested against semantic function
+ * @param scalaFuncNew semantic function which defines expected behavior of the given script
+ * @param expectedExpr expected ErgoTree expression which corresponds to the given script
+ * @param printExpectedExpr if true, print the test vector for expectedExpr when it is None
+ * @param logScript if true, log scripts to console
*/
case class NewFeature[A, B](
+ sinceVersion: Byte,
script: String,
override val scalaFuncNew: A => B,
expectedExpr: Option[SValue],
@@ -841,25 +877,34 @@ class SigmaDslTesting extends AnyPropSpec
logScript: Boolean = LogScriptDefault
)(implicit IR: IRContext, override val evalSettings: EvalSettings, val tA: RType[A], val tB: RType[B])
extends Feature[A, B] {
+
+ override def isSupportedIn(vc: VersionContext): Boolean =
+ vc.activatedVersion >= 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
- /** in v5.x the old and the new interpreters are the same */
+ /** Starting from v5.x the old and the new interpreters are the same */
val oldImpl = () => funcJit[A, B](script)
- val newImpl = oldImpl // funcJit[A, B](script) // TODO v6.0: use actual new implementation here (https://github.com/ScorexFoundation/sigmastate-interpreter/issues/910)
+ val newImpl = oldImpl
- /** In v5.x this method just checks the old implementations fails on the new feature. */
+ /** Check the new implementation works equal to the semantic function.
+ * This method also checks the old implementations fails on the new feature.
+ */
override def checkEquality(input: A, logInputOutput: Boolean = false): Try[(B, CostDetails)] = {
- val oldRes = Try(oldF(input))
- oldRes.isFailure shouldBe true
- if (!(newImpl eq oldImpl)) {
- val newRes = VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) {
- checkEq(scalaFuncNew)(newF)(input)
- }
+ if (this.isSupportedIn(VersionContext.current)) {
+ checkEq(scalaFuncNew)(newF)(input)
+ } else {
+ val oldRes = Try(oldF(input))
+ oldRes.isFailure shouldBe true
+ oldRes
}
- oldRes
}
override def checkExpected(input: A, expected: Expected[B]): Unit = {
@@ -879,7 +924,10 @@ class SigmaDslTesting extends AnyPropSpec
printTestCases: Boolean,
failOnTestVectors: Boolean): Unit = {
val res = checkEquality(input, printTestCases).map(_._1)
- res.isFailure shouldBe true
+ if (this.isSupportedIn(VersionContext.current)) {
+ res shouldBe expectedResult
+ } else
+ res.isFailure shouldBe true
Try(scalaFuncNew(input)) shouldBe expectedResult
}
@@ -888,8 +936,19 @@ 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)) {
+ val res = Try(scalaFunc(input))
+ if(expected.value.isSuccess) {
+ res shouldBe expected.value
+ } else {
+ res.isFailure shouldBe true
+ }
+ } else {
+ Try(scalaFunc(input)).isFailure shouldBe true
+ }
}
}
@@ -957,6 +1016,20 @@ class SigmaDslTesting extends AnyPropSpec
}
}
+ /** Used when the old and new value are the same for all versions
+ * and the expected costs are not specified.
+ *
+ * @param value expected result of tested function
+ * @param expectedDetails expected cost details for all versions
+ */
+ def apply[A](value: Try[A], expectedDetails: CostDetails): Expected[A] =
+ new Expected(ExpectedResult(value, None)) {
+ override val newResults = defaultNewResults.map {
+ case (ExpectedResult(v, _), _) =>
+ (ExpectedResult(v, None), Some(expectedDetails))
+ }
+ }
+
/** Used when the old and new value and costs are the same for all versions.
*
* @param value expected result of tested function
@@ -975,6 +1048,30 @@ class SigmaDslTesting extends AnyPropSpec
}
}
+ /** Used when the old and new value and costs are the same for all versions, but Version 3 (Ergo 6.0) will have a different cost due to deserialization cost being added.
+ * Different versions of ErgoTree can have different deserialization costs as well
+ *
+ * @param value expected result of tested function
+ * @param cost expected verification cost
+ * @param expectedDetails expected cost details for all versions <= V3
+ * @param expectedNewCost expected new verification cost for all versions <= V3
+ * @param expectedV3Cost expected cost for >=V3
+ */
+ def apply[A](value: Try[A],
+ cost: Int,
+ expectedDetails: CostDetails,
+ expectedNewCost: Int,
+ expectedV3Costs: Seq[Int]
+ )(implicit dummy: DummyImplicit): Expected[A] =
+ new Expected(ExpectedResult(value, Some(cost))) {
+ override val newResults = defaultNewResults.zipWithIndex.map {
+ case ((ExpectedResult(v, _), _), version) => {
+ var cost = if (activatedVersionInTests >= V6SoftForkVersion) expectedV3Costs(version) else expectedNewCost
+ (ExpectedResult(v, Some(cost)), Some(expectedDetails))
+ }
+ }
+ }
+
/** Used when operation semantics changes in new versions. For those versions expected
* test vectors can be specified.
*
@@ -985,8 +1082,10 @@ class SigmaDslTesting extends AnyPropSpec
* @param newVersionedResults new results returned by each changed feature function in
* v5.+ for each ErgoTree version.
*/
- def apply[A](value: Try[A], cost: Int,
- expectedDetails: CostDetails, newCost: Int,
+ def apply[A](value: Try[A],
+ cost: Int,
+ expectedDetails: CostDetails,
+ newCost: Int,
newVersionedResults: Seq[(Int, (ExpectedResult[A], Option[CostDetails]))]): Expected[A] =
new Expected[A](ExpectedResult(value, Some(cost))) {
override val newResults = {
@@ -1029,14 +1128,16 @@ class SigmaDslTesting extends AnyPropSpec
* various ways
*/
def changedFeature[A: RType, B: RType]
- (scalaFunc: A => B,
+ (changedInVersion: Byte,
+ scalaFunc: A => B,
scalaFuncNew: A => B,
script: String,
expectedExpr: SValue = null,
allowNewToSucceed: Boolean = false,
- allowDifferentErrors: Boolean = false)
+ allowDifferentErrors: Boolean = false
+ )
(implicit IR: IRContext, evalSettings: EvalSettings): Feature[A, B] = {
- ChangedFeature(script, scalaFunc, scalaFuncNew, Option(expectedExpr),
+ ChangedFeature(changedInVersion, script, scalaFunc, scalaFuncNew, Option(expectedExpr),
allowNewToSucceed = allowNewToSucceed,
allowDifferentErrors = allowDifferentErrors)
}
@@ -1044,6 +1145,7 @@ class SigmaDslTesting extends AnyPropSpec
/** Describes a NEW language feature which must NOT be supported in v4 and
* must BE supported in v5 of the language.
*
+ * @param sinceVersion language version (protocol) when the feature is introduced, see [[VersionContext]]
* @param scalaFunc semantic function which defines expected behavior of the given script
* @param script the script to be tested against semantic function
* @param expectedExpr expected ErgoTree expression which corresponds to the given script
@@ -1051,9 +1153,9 @@ class SigmaDslTesting extends AnyPropSpec
* various ways
*/
def newFeature[A: RType, B: RType]
- (scalaFunc: A => B, script: String, expectedExpr: SValue = null)
+ (scalaFunc: A => B, script: String, expectedExpr: SValue = null, sinceVersion: Byte = VersionContext.JitActivationVersion)
(implicit IR: IRContext, es: EvalSettings): Feature[A, B] = {
- NewFeature(script, scalaFunc, Option(expectedExpr))
+ NewFeature(sinceVersion, script, scalaFunc, Option(expectedExpr))
}
val contextGen: Gen[Context] = ergoLikeContextGen.map(c => c.toSigmaContext())
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)
}
}
}
diff --git a/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala b/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala
index 28f907c199..f1d5c6aa89 100644
--- a/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala
+++ b/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala
@@ -1,16 +1,17 @@
package sigmastate
import scala.util.DynamicVariable
-import sigmastate.lang.{CompilerResult, CompilerSettings, SigmaCompiler}
import sigmastate.interpreter.Interpreter.ScriptEnv
import sigma.ast.{ErgoTree, SType, TransformingSigmaBuilder, Value}
import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix
import sigma.ast.syntax.{SValue, SigmaPropValue}
import sigma.serialization.ValueSerializer
-import sigmastate.eval.IRContext
+import sigma.compiler.ir.IRContext
import sigma.ast.syntax.ValueOps
+import sigma.compiler.{CompilerResult, CompilerSettings, SigmaCompiler}
+import sigmastate.helpers.{NegativeTesting, SigmaPPrint}
-trait CompilerTestsBase extends TestsBase {
+trait CompilerTestsBase extends TestsBase with NegativeTesting {
protected val _lowerMethodCalls = new DynamicVariable[Boolean](true)
/** Returns true if MethodCall nodes should be lowered by TypeChecker to the
@@ -63,4 +64,12 @@ trait CompilerTestsBase extends TestsBase {
val tree = mkTestErgoTree(prop)
(tree, prop)
}
+
+ /** Checks expectation pretty printing the actual value if there is a difference. */
+ def checkEquals[T](actual: T, expected: T): Unit = {
+ if (expected != actual) {
+ SigmaPPrint.pprintln(actual, width = 100)
+ }
+ actual shouldBe expected
+ }
}
diff --git a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala
index b0b6273fad..1c38ca45a0 100644
--- a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala
@@ -17,18 +17,18 @@ import sigmastate.helpers.{ErgoLikeContextTesting, SigmaPPrint}
import sigmastate.interpreter.Interpreter.ReductionResult
import sigmastate.interpreter.CErgoTreeEvaluator
import sigma.ast.syntax._
+import sigma.compiler.CompilerSettings
import sigma.eval.EvalSettings
import sigma.exceptions.{CostLimitException, InterpreterException}
-import sigmastate.lang.CompilerSettings
import sigma.serialization.ErgoTreeSerializer.DefaultSerializer
-import sigmastate.Plus
+import sigmastate.{CrossVersionProps, Plus}
import sigmastate.utils.Helpers.TryOps
/** 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 with ContractsTestkit {
+class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with CrossVersionProps {
property("Value.sourceContext") {
val srcCtx = SourceContext.fromParserIndex(0, "")
@@ -313,37 +313,126 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit {
*/
case class MInfo(methodId: Byte, method: SMethod, isResolvableFromIds: Boolean = true)
+ def isV6Activated = VersionContext.current.isV6SoftForkActivated
+
// NOTE, the type code constants are checked above
// The methodId codes as checked here, they MUST be PRESERVED.
- // The following table should be made dependent on HF activation
- val methods = Table(
+ // Note, the following table is dependent on SF activation.
+ def methods = {
+ import SNumericTypeMethods._
+ Table(
("typeId", "methods", "CanHaveMethods"),
(SBoolean.typeId, Seq.empty[MInfo], true),
- (SByte.typeId, Seq.empty[MInfo], false),
- (SShort.typeId, Seq.empty[MInfo], false),
- (SInt.typeId, Seq.empty[MInfo], false),
- (SLong.typeId, Seq.empty[MInfo], false),
-
- { // SNumericType.typeId is erroneously shadowed by SGlobal.typeId
- // this should be preserved in v3.x and fixed in v4.0
- (SNumericType.typeId, Seq(
- MInfo(methodId = 1, SGlobalMethods.groupGeneratorMethod),
- MInfo(2, SGlobalMethods.xorMethod)
- ), true)
+ {
+ if (isV6Activated)
+ (SByte.typeId, Seq(
+ MInfo(methodId = 1, ToByteMethod),
+ MInfo(2, ToShortMethod),
+ MInfo(3, ToIntMethod),
+ MInfo(4, ToLongMethod),
+ MInfo(5, ToBigIntMethod),
+ MInfo(6, ToBytesMethod),
+ MInfo(7, ToBitsMethod),
+ MInfo(8, BitwiseInverseMethod, isResolvableFromIds = true),
+ MInfo(9, BitwiseOrMethod, isResolvableFromIds = true),
+ MInfo(10, BitwiseAndMethod, isResolvableFromIds = true),
+ MInfo(11, BitwiseXorMethod, isResolvableFromIds = true),
+ MInfo(12, ShiftLeftMethod, isResolvableFromIds = true),
+ MInfo(13, ShiftRightMethod, isResolvableFromIds = true)
+ ), true)
+ else
+ (SByte.typeId, Seq.empty[MInfo], false)
+ },
+ {
+ if (isV6Activated)
+ (SShort.typeId, Seq(
+ MInfo(methodId = 1, ToByteMethod),
+ MInfo(2, ToShortMethod),
+ MInfo(3, ToIntMethod),
+ MInfo(4, ToLongMethod),
+ MInfo(5, ToBigIntMethod),
+ MInfo(6, ToBytesMethod),
+ MInfo(7, ToBitsMethod),
+ MInfo(8, BitwiseInverseMethod, isResolvableFromIds = true),
+ MInfo(9, BitwiseOrMethod, isResolvableFromIds = true),
+ MInfo(10, BitwiseAndMethod, isResolvableFromIds = true),
+ MInfo(11, BitwiseXorMethod, isResolvableFromIds = true),
+ MInfo(12, ShiftLeftMethod, isResolvableFromIds = true),
+ MInfo(13, ShiftRightMethod, isResolvableFromIds = true)
+ ), true)
+ else
+ (SShort.typeId, Seq.empty[MInfo], false)
+ },
+ {
+ if (isV6Activated)
+ (SInt.typeId, Seq(
+ MInfo(methodId = 1, ToByteMethod),
+ MInfo(2, ToShortMethod),
+ MInfo(3, ToIntMethod),
+ MInfo(4, ToLongMethod),
+ MInfo(5, ToBigIntMethod),
+ MInfo(6, ToBytesMethod),
+ MInfo(7, ToBitsMethod),
+ MInfo(8, BitwiseInverseMethod, isResolvableFromIds = true),
+ MInfo(9, BitwiseOrMethod, isResolvableFromIds = true),
+ MInfo(10, BitwiseAndMethod, isResolvableFromIds = true),
+ MInfo(11, BitwiseXorMethod, isResolvableFromIds = true),
+ MInfo(12, ShiftLeftMethod, isResolvableFromIds = true),
+ MInfo(13, ShiftRightMethod, isResolvableFromIds = true)
+ ), true)
+ else
+ (SInt.typeId, Seq.empty[MInfo], false)
+ },
+ {
+ if (isV6Activated)
+ (SLong.typeId, Seq(
+ MInfo(methodId = 1, ToByteMethod),
+ MInfo(2, ToShortMethod),
+ MInfo(3, ToIntMethod),
+ MInfo(4, ToLongMethod),
+ MInfo(5, ToBigIntMethod),
+ MInfo(6, ToBytesMethod),
+ MInfo(7, ToBitsMethod),
+ MInfo(8, BitwiseInverseMethod, isResolvableFromIds = true),
+ MInfo(9, BitwiseOrMethod, isResolvableFromIds = true),
+ MInfo(10, BitwiseAndMethod, isResolvableFromIds = true),
+ MInfo(11, BitwiseXorMethod, isResolvableFromIds = true),
+ MInfo(12, ShiftLeftMethod, isResolvableFromIds = true),
+ MInfo(13, ShiftRightMethod, isResolvableFromIds = true)
+ ), true)
+ else
+ (SLong.typeId, Seq.empty[MInfo], false)
},
+// { // SNumericType.typeId is erroneously shadowed by SGlobal.typeId
+// // this should be preserved in v3.x and fixed in v4.0
+// (SNumericType.typeId, Seq(
+// MInfo(methodId = 1, SGlobalMethods.groupGeneratorMethod),
+// MInfo(2, SGlobalMethods.xorMethod)
+// ), true)
+// },
+
{ // SBigInt inherit methods from SNumericType.methods
- // however they are not resolvable via SBigInt.typeId
+ // however they are not resolvable via SBigInt.typeId before v6.0
import SNumericTypeMethods._
(SBigInt.typeId, Seq(
- MInfo(methodId = 1, ToByteMethod, isResolvableFromIds = false),
- MInfo(2, ToShortMethod, isResolvableFromIds = false),
- MInfo(3, ToIntMethod, isResolvableFromIds = false),
- MInfo(4, ToLongMethod, isResolvableFromIds = false),
- MInfo(5, ToBigIntMethod, isResolvableFromIds = false),
- MInfo(6, ToBytesMethod, isResolvableFromIds = false),
- MInfo(7, ToBitsMethod, isResolvableFromIds = false)
- ), true)
+ MInfo(methodId = 1, ToByteMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(2, ToShortMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(3, ToIntMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(4, ToLongMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(5, ToBigIntMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(6, ToBytesMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(7, ToBitsMethod, isResolvableFromIds = if (isV6Activated) true else false)) ++
+ (if (isV6Activated) Seq(
+ // methods added in v6.0
+ MInfo(8, BitwiseInverseMethod, isResolvableFromIds = true),
+ MInfo(9, BitwiseOrMethod, isResolvableFromIds = true),
+ MInfo(10, BitwiseAndMethod, isResolvableFromIds = true),
+ MInfo(11, BitwiseXorMethod, isResolvableFromIds = true),
+ MInfo(12, ShiftLeftMethod, isResolvableFromIds = true),
+ MInfo(13, ShiftRightMethod, isResolvableFromIds = true)
+ ) else Seq.empty)
+ , true)
},
{ import SGroupElementMethods._
(SGroupElement.typeId, Seq(
@@ -367,9 +456,12 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit {
MInfo(4, BytesWithoutRefMethod),
MInfo(5, IdMethod),
MInfo(6, creationInfoMethod),
- MInfo(7, getRegMethod),
MInfo(8, tokensMethod)
- ) ++ registers(idOfs = 8)
+ ) ++ (if (isV6Activated) {
+ Seq(MInfo(7, getRegMethodV6))
+ } else {
+ Seq(MInfo(7, getRegMethodV5))
+ }) ++ registers(idOfs = 8)
.zipWithIndex
.map { case (m,i) => MInfo((8 + i + 1).toByte, m) }, true)
},
@@ -399,7 +491,11 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit {
MInfo(7, timestampMethod), MInfo(8, nBitsMethod), MInfo(9, heightMethod),
MInfo(10, extensionRootMethod), MInfo(11, minerPkMethod), MInfo(12, powOnetimePkMethod),
MInfo(13, powNonceMethod), MInfo(14, powDistanceMethod), MInfo(15, votesMethod)
- ), true)
+ ) ++ (if (isV6Activated) {
+ Seq(MInfo(16, checkPowMethod)) // methods added in v6.0
+ } else {
+ Seq.empty[MInfo]
+ }), true)
},
{ import SPreHeaderMethods._
(SPreHeader.typeId, Seq(
@@ -413,13 +509,21 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit {
MInfo(1, dataInputsMethod), MInfo(2, headersMethod), MInfo(3, preHeaderMethod),
MInfo(4, inputsMethod), MInfo(5, outputsMethod), MInfo(6, heightMethod),
MInfo(7, selfMethod), MInfo(8, selfBoxIndexMethod), MInfo(9, lastBlockUtxoRootHashMethod),
- MInfo(10, minerPubKeyMethod), MInfo(11, getVarMethod)
- ), true)
+ MInfo(10, minerPubKeyMethod)) ++ (if(VersionContext.current.isV6SoftForkActivated){
+ Seq(MInfo(11, getVarV6Method), MInfo(12, getVarFromInputMethod))
+ } else {
+ Seq(MInfo(11, getVarV5Method))
+ }), true)
},
{ import SGlobalMethods._
(SGlobal.typeId, Seq(
MInfo(1, groupGeneratorMethod), MInfo(2, xorMethod)
- ), true)
+ ) ++ (if (isV6Activated) {
+ // id = 4 reserved for deserializeTo method
+ Seq(MInfo(3, serializeMethod), MInfo(5, fromBigEndianBytesMethod)) // methods added in v6.0
+ } else {
+ Seq.empty[MInfo]
+ }), true)
},
{ import SCollectionMethods._
(SCollection.typeId, Seq(
@@ -461,7 +565,9 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit {
EndsWithMethod,
MapReduceMethod,
*/
- ), true)
+ ) ++ (if (isV6Activated) {
+ Seq(MInfo(30, ReverseMethod), MInfo(31, DistinctMethod), MInfo(32, StartsWithMethod), MInfo(33, EndsWithMethod), MInfo(34, GetMethod))
+ } else Seq.empty), true)
},
{ import SOptionMethods._
(SOption.typeId, Seq(
@@ -475,7 +581,13 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit {
MInfo(8, FilterMethod)
), true)
}
- )
+ )
+ }
+
+ property("SNumericType.typeId resolves to SGlobal") {
+ SNumericType.typeId shouldBe SGlobal.typeId
+ SMethod.fromIds(SNumericType.typeId, 1) shouldBe SGlobalMethods.groupGeneratorMethod
+ }
property("MethodCall Codes") {
forAll(methods) { (typeId, methods, canHaveMethods) =>
@@ -484,7 +596,9 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit {
assert(canHaveMethods, s"Type $tyDesc should NOT have methods")
val mc = MethodsContainer(tyDesc.typeId)
+
mc.methods.length shouldBe methods.length
+
for (expectedMethod <- methods) {
if (expectedMethod.isResolvableFromIds) {
@@ -508,21 +622,28 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit {
assert(!canHaveMethods, s"Type with code $typeId can have methods")
}
}
-
}
property("MethodCall on numerics") {
forAll(Table[STypeCompanion]("type", SByte, SShort, SInt, SLong, SBigInt)) { t =>
- // this methods are expected to fail resolution in v3.x (but may change in future)
- (1 to 7).foreach { methodId =>
- assertExceptionThrown(
- SMethod.fromIds(t.typeId, methodId.toByte),
- {
- case _: ValidationException => true
- case _ => false
- },
- s"SMethod mustn't resolve for typeId = ${t.typeId} and methodId = $methodId"
- )
+ // this methods are expected to fail resolution in before v6.0
+ if (!isV6Activated) {
+ (1 to 7).foreach { methodId =>
+ assertExceptionThrown(
+ SMethod.fromIds(t.typeId, methodId.toByte),
+ {
+ case _: ValidationException => true
+ case _ => false
+ },
+ s"SMethod mustn't resolve for typeId = ${t.typeId} and methodId = $methodId"
+ )
+ }
+ } else {
+ // in v6.0 these codes should resolve to the methods of the concrete numeric type
+ (1 to 7).foreach { methodId =>
+ val m = SMethod.fromIds(t.typeId, methodId.toByte)
+ m.objType.ownerType shouldBe t
+ }
}
}
}
diff --git a/sc/shared/src/test/scala/sigmastate/ScriptVersionSwitchSpecification.scala b/sc/shared/src/test/scala/sigmastate/ScriptVersionSwitchSpecification.scala
index b0206fa464..153aae28d5 100644
--- a/sc/shared/src/test/scala/sigmastate/ScriptVersionSwitchSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/ScriptVersionSwitchSpecification.scala
@@ -14,6 +14,7 @@ import sigmastate.interpreter.CErgoTreeEvaluator.DefaultEvalSettings
import sigma.eval.EvalSettings.EvaluationMode
import sigmastate.interpreter._
import sigma.ast.syntax.ValueOps
+import sigma.compiler.ir.IRContext
import sigma.data.CBox
import sigma.eval.EvalSettings
import sigma.exceptions.InterpreterException
@@ -272,17 +273,18 @@ class ScriptVersionSwitchSpecification extends SigmaDslTesting {
/** Rule#| BlockVer | Block Type| Script Version | Release | Validation Action
* -----|----------|-----------|----------------|---------|--------
- * 19 | 4 | candidate | Script v3 | v5.0 | skip-accept (rely on majority)
- * 20 | 4 | mined | Script v3 | v5.0 | skip-accept (rely on majority)
+ * 19 | 5 | candidate | Script v4 | v6.0 | skip-accept (rely on majority)
+ * 20 | 5 | mined | Script v4 | v6.0 | skip-accept (rely on majority)
*/
- property("Rules 19,20 | Block v4 | candidate or mined block | Script v3") {
- forEachActivatedScriptVersion(activatedVers = Array[Byte](3)) // version for Block v4
+ property("Rules 19,20 | Block v5 | candidate or mined block | Script v4") {
+ forEachActivatedScriptVersion(activatedVers = Array[Byte](4)) // activated version is greater than MaxSupported
{
- forEachErgoTreeVersion(ergoTreeVers = Array[Byte](3, 4)) { // scripts >= v3
+ forEachErgoTreeVersion(ergoTreeVers = Array[Byte](4, 5)) { // tree version >= activated
val headerFlags = ErgoTree.defaultHeaderWithVersion(ergoTreeVersionInTests)
val ergoTree = createErgoTree(headerFlags)
- // prover is rejecting, because such context parameters doesn't make sense
+ // prover is rejecting, because it cannot generate proofs for ErgoTrees with version
+ // higher than max supported by the interpreter
assertExceptionThrown(
testProve(ergoTree, activatedScriptVersion = activatedVersionInTests),
exceptionLike[InterpreterException](s"Both ErgoTree version ${ergoTree.version} and activated version $activatedVersionInTests is greater than MaxSupportedScriptVersion $MaxSupportedScriptVersion")
@@ -296,20 +298,20 @@ class ScriptVersionSwitchSpecification extends SigmaDslTesting {
}
}
- /** Rule#| BlockVer | Block Type| Script Version | Release | Validation Action
- * -----|----------|-----------|----------------|---------|--------
- * 21 | 4 | candidate | Script v0/v1 | v5.0 | R5.0-JIT-verify
- * 22 | 4 | candidate | Script v2 | v5.0 | R5.0-JIT-verify
- * 23 | 4 | mined | Script v0/v1 | v5.0 | R5.0-JIT-verify
- * 24 | 4 | mined | Script v2 | v5.0 | R5.0-JIT-verify
+ /** Rule#| BlockVer | Block Type| Script Version | Release | Validation Action
+ * -----|----------|-----------|-----------------|---------|--------
+ * 21 | 5 | candidate | Script v0/v1/v2 | v6.0 | R6.0-JIT-verify
+ * 22 | 5 | candidate | Script v3 | v6.0 | R6.0-JIT-verify
+ * 23 | 5 | mined | Script v0/v1/v2 | v6.0 | R6.0-JIT-verify
+ * 24 | 5 | mined | Script v3 | v6.0 | R6.0-JIT-verify
*/
- property("Rules 21,22,23,24 | Block v4 | candidate or mined block | Script v0/v1/v2") {
- // this test verifies the normal validation action R5.0-JIT-verify of v5.x releases
- // when Block v4 already activated, but the script is v0, v1 or v2.
+ property("Rules 21,22,23,24 | Block v5 | candidate or mined block | Script v0/v1/v2/v3") {
+ // this test verifies the normal validation action R6.0-JIT-verify of v6.x releases
+ // when Block v5 already activated, but the script is v0, v1, v2, or v3.
- forEachActivatedScriptVersion(Array[Byte](3)) // version for Block v4
+ forEachActivatedScriptVersion(Array[Byte](4)) // version for Block v5
{
- forEachErgoTreeVersion(Array[Byte](0, 1, 2)) { // tree versions supported by v5.x
+ forEachErgoTreeVersion(Array[Byte](0, 1, 2, 3)) { // tree versions supported by v6.x
// SF inactive: check cost vectors of v4.x interpreter
val headerFlags = ErgoTree.defaultHeaderWithVersion(ergoTreeVersionInTests)
val ergoTree = createErgoTree(headerFlags)
diff --git a/sc/shared/src/test/scala/sigmastate/SoftForkabilitySpecification.scala b/sc/shared/src/test/scala/sigmastate/SoftForkabilitySpecification.scala
index bca2d0e638..c8b9f06399 100644
--- a/sc/shared/src/test/scala/sigmastate/SoftForkabilitySpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/SoftForkabilitySpecification.scala
@@ -29,7 +29,7 @@ class SoftForkabilitySpecification extends SigmaTestingData
with CompilerTestingCommons
with BeforeAndAfterAll {
- implicit lazy val IR: TestingIRContext = new TestingIRContext
+ val IR: TestingIRContext = new TestingIRContext
lazy val prover = new ErgoLikeTestProvingInterpreter()
lazy val verifier = new ErgoLikeTestInterpreter
val deadline = 100
@@ -38,7 +38,7 @@ class SoftForkabilitySpecification extends SigmaTestingData
lazy val booleanPropV1 = compile(emptyEnv + ("deadline" -> deadline),
"""{
| HEIGHT > deadline && OUTPUTS.size == 1
- |}""".stripMargin).asBoolValue
+ |}""".stripMargin)(IR).asBoolValue
// cast Boolean typed prop to SigmaProp (which is invalid) // ErgoTree v0
lazy val invalidPropV1: ErgoTree =
diff --git a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala
index fe5a678679..4ba6b1a9f7 100644
--- a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala
@@ -6,38 +6,58 @@ import sigma.ast._
import sigma.ast.syntax._
import sigmastate.interpreter._
import Interpreter._
-import sigma.ast.syntax._
import org.ergoplatform._
import org.scalatest.BeforeAndAfterAll
-import scorex.util.encode.Base58
-import sigma.crypto.CryptoConstants
-import sigma.data.{AvlTreeData, CAND, ProveDlog, SigmaBoolean, TrivialProp}
+import scorex.util.encode.{Base16, Base58}
+import sigma.Colls
+import sigma.VersionContext.V6SoftForkVersion
+import sigma.VersionContext
+import sigma.data.{CAND, CAvlTree, CHeader, ProveDlog, SigmaBoolean, TrivialProp}
+import sigma.interpreter.ContextExtension
import sigma.util.Extensions.IntOps
import sigmastate.helpers.{CompilerTestingCommons, ErgoLikeContextTesting, ErgoLikeTestInterpreter, ErgoLikeTestProvingInterpreter}
import sigmastate.helpers.TestingHelpers._
-import sigma.serialization.ValueSerializer
+import sigma.serialization.{GroupElementSerializer, SigmaSerializer, ValueSerializer}
+import sigmastate.eval.CPreHeader
+import sigmastate.helpers.ErgoLikeContextTesting.noBoxes
+import sigmastate.interpreter.CErgoTreeEvaluator.DefaultEvalSettings
import sigmastate.utils.Helpers._
+import sigma.util.Extensions._
import scala.util.Random
class TestingInterpreterSpecification extends CompilerTestingCommons
with CompilerCrossVersionProps with BeforeAndAfterAll {
- implicit lazy val IR: TestingIRContext = new TestingIRContext
- lazy val prover = new ErgoLikeTestProvingInterpreter() {
- }
+ val IR: TestingIRContext = new TestingIRContext
- lazy val verifier = new ErgoLikeTestInterpreter {
- }
+ lazy val prover = new ErgoLikeTestProvingInterpreter()
- implicit val soundness: Int = CryptoConstants.soundnessBits
+ lazy val verifier = new ErgoLikeTestInterpreter
- def testingContext(h: Int) =
- ErgoLikeContextTesting(h,
- AvlTreeData.dummy, ErgoLikeContextTesting.dummyPubkey, IndexedSeq(fakeSelf),
- ErgoLikeTransaction(IndexedSeq.empty, IndexedSeq.empty),
- fakeSelf, activatedVersionInTests)
- .withErgoTreeVersion(ergoTreeVersionInTests)
+ def testingContext(h: Int = 614401) = {
+ // bytes of real mainnet block header at height 614,440
+ val headerBytes = "02ac2101807f0000ca01ff0119db227f202201007f62000177a080005d440896d05d3f80dcff7f5e7f59007294c180808d0158d1ff6ba10000f901c7f0ef87dcfff17fffacb6ff7f7f1180d2ff7f1e24ffffe1ff937f807f0797b9ff6ebdae007e5c8c00b8403d3701557181c8df800001b6d5009e2201c6ff807d71808c00019780f087adb3fcdbc0b3441480887f80007f4b01cf7f013ff1ffff564a0000b9a54f00770e807f41ff88c00240000080c0250000000003bedaee069ff4829500b3c07c4d5fe6b3ea3d3bf76c5c28c1d4dcdb1bed0ade0c0000000000003105"
+ val header1 = new CHeader(ErgoHeader.sigmaSerializer.fromBytes(Base16.decode(headerBytes).get))
+
+ val boxesToSpend = IndexedSeq(fakeSelf)
+
+ val preHeader = CPreHeader(activatedVersionInTests,
+ parentId = header1.id,
+ timestamp = 3,
+ nBits = 0,
+ height = h,
+ minerPk = GroupElementSerializer.parse(SigmaSerializer.startReader(ErgoLikeContextTesting.dummyPubkey)).toGroupElement,
+ votes = Colls.emptyColl[Byte]
+ )
+
+ new ErgoLikeContext(
+ header1.stateRoot.asInstanceOf[CAvlTree].treeData, Colls.fromArray(Array(header1)),
+ preHeader, noBoxes,
+ boxesToSpend, ErgoLikeTransaction(IndexedSeq.empty, IndexedSeq.empty),
+ boxesToSpend.indexOf(fakeSelf), ContextExtension.empty, vs, DefaultEvalSettings.scriptCostLimitInEvaluator,
+ initCost = 0L, activatedVersionInTests).withErgoTreeVersion(ergoTreeVersionInTests)
+ }
property("Reduction to crypto #1") {
forAll() { i: Int =>
@@ -119,7 +139,7 @@ class TestingInterpreterSpecification extends CompilerTestingCommons
val dk1 = prover.dlogSecrets(0).publicImage
val dk2 = prover.dlogSecrets(1).publicImage
- val ctx = testingContext(99)
+ val ctx = testingContext()
val env = Map(
"dk1" -> dk1,
"dk2" -> dk2,
@@ -127,8 +147,10 @@ class TestingInterpreterSpecification extends CompilerTestingCommons
"bytes2" -> Array[Byte](4, 5, 6),
"box1" -> testBox(10, TrueTree, 0, Seq(), Map(
reg1 -> IntArrayConstant(Array[Int](1, 2, 3)),
- reg2 -> BoolArrayConstant(Array[Boolean](true, false, true)))))
- val prop = mkTestErgoTree(compile(env, code).asBoolValue.toSigmaProp)
+ reg2 -> BoolArrayConstant(Array[Boolean](true, false, true))
+ ))
+ )
+ val prop = mkTestErgoTree(compile(env, code)(IR).asBoolValue.toSigmaProp)
val challenge = Array.fill(32)(Random.nextInt(100).toByte)
val proof1 = prover.prove(prop, ctx, challenge).get.proof
verifier.verify(Interpreter.emptyEnv, prop, ctx, proof1, challenge)
@@ -218,6 +240,46 @@ class TestingInterpreterSpecification extends CompilerTestingCommons
testWithCasting("toBigInt")
}
+ property("BigInt downcasting to byte") {
+ def test() = testEval("{ sigmaProp(0L.toBigInt.toByte <= CONTEXT.preHeader.version) }")
+ if(VersionContext.current.isV6SoftForkActivated) {
+ test()
+ } else {
+ an[Exception] shouldBe thrownBy(test())
+ }
+ }
+
+ property("BigInt downcasting to short") {
+ def test() = testEval("{ sigmaProp(0L.toBigInt.toShort <= CONTEXT.preHeader.version.toShort) }")
+ if(VersionContext.current.isV6SoftForkActivated) {
+ test()
+ } else {
+ an[Exception] shouldBe thrownBy(test())
+ }
+ }
+
+ property("BigInt downcasting to int") {
+ def test() = testEval("{ sigmaProp(1L.toBigInt.toInt < CONTEXT.preHeader.timestamp.toInt) }")
+ if(VersionContext.current.isV6SoftForkActivated) {
+ test()
+ } else {
+ an[Exception] shouldBe thrownBy(test())
+ }
+ }
+
+ property("BigInt downcasting to long") {
+ def test() = testEval("{ sigmaProp(1L.toBigInt.toLong < CONTEXT.preHeader.timestamp) }")
+ if(VersionContext.current.isV6SoftForkActivated) {
+ test()
+ } else {
+ an[Exception] shouldBe thrownBy(test())
+ }
+ }
+
+ property("upcasting to bigint") {
+ testEval("{ sigmaProp(1L.toBigInt < bigInt(\"2\")) }")
+ }
+
property("Evaluate arithmetic ops") {
def testWithCasting(castSuffix: String): Unit = {
testEval(s"1.$castSuffix + 2.$castSuffix == 3.$castSuffix")
@@ -340,6 +402,24 @@ class TestingInterpreterSpecification extends CompilerTestingCommons
verifier.verify(prop3, env, proof, challenge).map(_._1).getOrElse(false) shouldBe false
}
+ property("blake2b - test vector") {
+ testEval(
+ """ {
+ | val input = fromBase16("68656c6c6f20776f726c64")
+ | val output = fromBase16("256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610")
+ | blake2b256(input) == output
+ | }""".stripMargin)
+ }
+
+ property("blake2b - test vector #2") {
+ testEval(
+ """ {
+ | val input = fromBase16("02ac2101807f0000ca01ff0119db227f202201007f62000177a080005d440896d05d3f80dcff7f5e7f59007294c180808d0158d1ff6ba10000f901c7f0ef87dcfff17fffacb6ff7f7f1180d2ff7f1e24ffffe1ff937f807f0797b9ff6ebdae007e5c8c00b8403d3701557181c8df800001b6d5009e2201c6ff807d71808c00019780d085adb3fcdbc0b3441480887f80007f4b01cf7f013ff1ffff564a0000b9a54f00770e807f41ff88c00240000080c02500000000")
+ | val output = fromBase16("bdb84cda5b105c3eb522857b50a0882f88ed5bb3cc8cf3325a1edf7eeb6a0954")
+ | blake2b256(input) == output
+ | }""".stripMargin)
+ }
+
property("passing a lambda argument") {
// single expression
testEval(
@@ -374,6 +454,29 @@ class TestingInterpreterSpecification extends CompilerTestingCommons
testEval(s"""deserialize[Coll[Byte]]("$str")(0) == 2""")
}
+ property("header.id") {
+ testEval(
+ """ {
+ | val h = CONTEXT.headers(0)
+ | val id = h.id
+ | id.size == 32
+ | }""".stripMargin)
+ }
+
+ property("checkPow") {
+ val source = """ {
+ | val h = CONTEXT.headers(0)
+ | h.checkPow
+ | }
+ | """.stripMargin
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an [Exception] should be thrownBy testEval(source)
+ } else {
+ testEval(source)
+ }
+ }
+
override protected def afterAll(): Unit = {
}
diff --git a/sc/shared/src/test/scala/sigmastate/TypesSpecification.scala b/sc/shared/src/test/scala/sigmastate/TypesSpecification.scala
index 9a4c5ce1b8..6d13863f26 100644
--- a/sc/shared/src/test/scala/sigmastate/TypesSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/TypesSpecification.scala
@@ -13,8 +13,6 @@ class TypesSpecification extends SigmaTestingData {
implicit val tWrapped = wrappedTypeGen(t)
forAll { x: SPredefType#WrappedType =>
isValueOfType(x, t) shouldBe true
- // since forall t. SHeader != t
- isValueOfType(x, SHeader) shouldBe false
}
}
}
diff --git a/sc/shared/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala b/sc/shared/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala
index abbed09992..da9ed70efd 100644
--- a/sc/shared/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala
+++ b/sc/shared/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala
@@ -14,14 +14,16 @@ import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeConte
import sigmastate.interpreter.Interpreter.ScriptEnv
import sigmastate.interpreter.CErgoTreeEvaluator
import sigma.ast.syntax.ValueOps
+import sigma.compiler.{CompilerResult, CompilerSettings, SigmaCompiler}
+import sigma.compiler.ir.IRContext
import sigma.interpreter.ContextExtension
-import sigmastate.lang.{CompilerResult, CompilerSettings, LangTests, SigmaCompiler}
+import sigmastate.lang.LangTests
import sigma.serialization.ErgoTreeSerializer.DefaultSerializer
import sigmastate.CompilerTestsBase
import sigma.{ContractsTestkit, Context => DContext}
import scala.annotation.unused
-import scala.util.Success
+import scala.util.{Success, Try}
trait ErgoScriptTestkit extends ContractsTestkit with LangTests
with ValidationSpecification with CompilerTestsBase { self: BaseCtxTests =>
@@ -54,9 +56,8 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests
ergoCtx
}
-
- lazy val boxA1 = newAliceBox(1, 100)
- lazy val boxA2 = newAliceBox(2, 200)
+ lazy val boxA1 = newAliceBox(100)
+ lazy val boxA2 = newAliceBox(200)
lazy val n1Sym = liftConst(n1)
@@ -147,6 +148,31 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests
res
}
+ private val SigmaM = SigmaProp.SigmaPropMethods
+
+ /** Finds SigmaProp.isProven method calls in the given Lambda `f` */
+ private def findIsProven[T](f: Ref[Context => T]): Option[Sym] = {
+ val Def(Lambda(lam,_,_,_)) = f
+ val s = lam.flatSchedule.find(sym => sym.node match {
+ case SigmaM.isValid(_) => true
+ case _ => false
+ })
+ s
+ }
+
+ /** Checks that if SigmaProp.isProven method calls exists in the given Lambda's schedule,
+ * then it is the last operation. */
+ private def verifyIsProven[T](f: Ref[Context => T]): Try[Unit] = {
+ val isProvenOpt = findIsProven(f)
+ Try {
+ isProvenOpt match {
+ case Some(s) =>
+ if (f.getLambda.y != s) !!!(s"Sigma.isProven found in none-root position", s)
+ case None =>
+ }
+ }
+ }
+
def doReduce(): Unit = {
val res = doCosting
verifyIsProven(res.compiledGraph) shouldBe Success(())
@@ -183,13 +209,6 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests
}
}
- def Case(env: ScriptEnv, name: String, script: String, ctx: ErgoLikeContext,
- calc: Ref[Context] => Ref[Any],
- tree: SValue,
- result: Result) =
- EsTestCase(name, env, Code(script), Option(ctx), None,
- Option(calc), Option(tree), result)
-
def reduce(env: ScriptEnv, name: String, script: String, ergoCtx: ErgoLikeContext, expectedResult: Any): Unit = {
val tcase = EsTestCase(name, env, Code(script), Some(ergoCtx), expectedResult = Result(expectedResult))
tcase.doReduce()
diff --git a/sc/shared/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala b/sc/shared/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala
index 526012f212..11ef6f4fac 100644
--- a/sc/shared/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala
+++ b/sc/shared/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala
@@ -8,6 +8,7 @@ import scalan.BaseCtxTests
import sigma.ast.syntax.ValueOps
import sigmastate.lang.LangTests
import sigma.ast.Apply
+import sigma.compiler.ir.IRContext
class ErgoTreeBuildingTest extends BaseCtxTests
with LangTests with ExampleContracts with ErgoScriptTestkit {
diff --git a/sc/shared/src/test/scala/sigmastate/eval/EvaluationTest.scala b/sc/shared/src/test/scala/sigmastate/eval/EvaluationTest.scala
index 5fcbd0f220..f9a7edf0cb 100644
--- a/sc/shared/src/test/scala/sigmastate/eval/EvaluationTest.scala
+++ b/sc/shared/src/test/scala/sigmastate/eval/EvaluationTest.scala
@@ -81,24 +81,6 @@ class EvaluationTest extends BaseCtxTests
| f(SELF) || g(SELF.R5[Coll[Int]].get)
| }""".stripMargin, ctx, true)
}
-
- test("Measure IRContext creation speed") {
- var ctx: RuntimeIRContext = new RuntimeIRContext
- measure(100, okShowIterTime = printDebugInfo, okShowTotalTime = printDebugInfo) { i =>
- ctx = new RuntimeIRContext
- }
- printDebug(s"Def count: ${ctx.defCount}")
- /*
- Iter 0: 4 ms
- ...
- Iter 96: 2 ms
- Iter 97: 1 ms
- Iter 98: 2 ms
- Iter 99: 2 ms
- Total time: 244 ms
- Def count: 20
- */
- }
test("SubstConst") {
def script(pk: ProveDlog): SigmaPropValue =
diff --git a/sc/shared/src/test/scala/sigmastate/eval/MeasureIRContext.scala b/sc/shared/src/test/scala/sigmastate/eval/MeasureIRContext.scala
deleted file mode 100644
index 9f88588cc9..0000000000
--- a/sc/shared/src/test/scala/sigmastate/eval/MeasureIRContext.scala
+++ /dev/null
@@ -1,36 +0,0 @@
-package sigmastate.eval
-
-import scalan.{BaseCtxTests, Benchmark}
-import sigma.util.BenchmarkUtil.measure
-
-object MeasureIRContext extends App {
- var ctx: RuntimeIRContext = null
- measure(1, false) { i =>
- ctx = new RuntimeIRContext
- }
- measure(10000, false) { i =>
- ctx = new RuntimeIRContext
- }
- print(s"Def count: ${ctx.defCount}")
- /*
- Total time: 2485 ms
- Total time: 2714 ms
- Def count: 20
- */
-}
-
-class SigmaLibraryTests extends BaseCtxTests {
-
- test("Benchmark SigmaLibrary creation time") {
- new Benchmark(new RuntimeIRContext).run()
- }
-}
-
-object MeasureSigmaLibraryCreate extends App {
- new Benchmark(new RuntimeIRContext).run()
- /*
- Total time: 12932 ms
- Def count: 20, total: 15774 msec
- */
-}
-
diff --git a/sc/shared/src/test/scala/sigmastate/helpers/CompilerTestingCommons.scala b/sc/shared/src/test/scala/sigmastate/helpers/CompilerTestingCommons.scala
index 332ee902a2..3b1d6ba3dc 100644
--- a/sc/shared/src/test/scala/sigmastate/helpers/CompilerTestingCommons.scala
+++ b/sc/shared/src/test/scala/sigmastate/helpers/CompilerTestingCommons.scala
@@ -12,16 +12,17 @@ import sigma.data.{RType, SigmaBoolean}
import sigma.validation.ValidationException
import sigma.validation.ValidationRules.CheckSerializableTypeCode
import sigma.ast.syntax.{SValue, SigmaPropValue}
+import sigma.compiler.{CompilerSettings, SigmaCompiler}
+import sigma.compiler.ir.IRContext
import sigma.eval.{CostDetails, EvalSettings, Extensions, GivenCost, TracedCost}
import sigmastate.helpers.TestingHelpers._
import sigma.interpreter.ContextExtension.VarBinding
import sigmastate.interpreter.CErgoTreeEvaluator.DefaultProfiler
import sigmastate.interpreter.Interpreter.ScriptEnv
import sigmastate.interpreter._
-import sigmastate.lang.{CompilerSettings, SigmaCompiler}
import sigma.serialization.SigmaSerializer
import sigmastate.CompilerTestsBase
-import sigmastate.eval.{CContext, IRContext}
+import sigmastate.eval.CContext
import scala.util.DynamicVariable
@@ -29,8 +30,7 @@ trait CompilerTestingCommons extends TestingCommons
with TestUtils with TestContexts with ValidationSpecification
with CompilerTestsBase {
- class TestingIRContext extends TestContext with IRContext {
- }
+ class TestingIRContext extends TestContext with IRContext
case class CompiledFunc[A,B]
(script: String, bindings: Seq[VarBinding], expr: SValue, compiledTree: SValue, func: A => (B, CostDetails))
diff --git a/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala b/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala
index 1f758370a0..3c3687cb37 100644
--- a/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala
+++ b/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala
@@ -10,9 +10,12 @@ import sigma.ast.syntax.SValue
import sigmastate._
import sigmastate.interpreter.Interpreter.ScriptEnv
import SigmaPredef.PredefinedFuncRegistry
+import sigma.VersionContext
import sigma.ast.syntax._
+import sigma.compiler.phases.SigmaBinder
import sigma.eval.SigmaDsl
import sigma.exceptions.BinderException
+import sigmastate.helpers.SigmaPPrint
class SigmaBinderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers with LangTests {
import StdSigmaBuilder._
@@ -28,6 +31,17 @@ class SigmaBinderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Mat
res
}
+ /** Checks that parsing and binding results in the expected value.
+ * @return the inferred type of the expression
+ */
+ def checkBound(env: ScriptEnv, x: String, expected: SValue) = {
+ val bound = bind(env, x)
+ if (expected != bound) {
+ SigmaPPrint.pprintln(bound, width = 100)
+ }
+ bound shouldBe expected
+ }
+
private def fail(env: ScriptEnv, x: String, expectedLine: Int, expectedCol: Int): Unit = {
val builder = TransformingSigmaBuilder
val ast = SigmaParser(x).get.value
@@ -202,4 +216,15 @@ class SigmaBinderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Mat
e.source shouldBe Some(SourceContext(2, 5, "val x = 10"))
}
+ property("predefined `serialize` should be transformed to MethodCall") {
+ runWithVersion(VersionContext.V6SoftForkVersion) {
+ checkBound(env, "serialize(1)",
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ Global,
+ SGlobalMethods.getMethodByName("serialize").withConcreteTypes(Map(STypeVar("T") -> SInt)),
+ Array(IntConstant(1)),
+ Map()
+ ))
+ }
+ }
}
diff --git a/sc/shared/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala b/sc/shared/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala
index 88c75a90b6..90e5d21b1e 100644
--- a/sc/shared/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala
+++ b/sc/shared/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala
@@ -12,6 +12,8 @@ import sigma.ast.{Apply, MethodCall, ZKProofBlock}
import sigma.exceptions.{GraphBuildingException, InvalidArguments, TyperException}
import sigma.serialization.ValueSerializer
import sigma.serialization.generators.ObjectGenerators
+
+import java.math.BigInteger
import scala.annotation.unused
class SigmaCompilerTest extends CompilerTestingCommons with LangTests with ObjectGenerators {
@@ -127,6 +129,13 @@ class SigmaCompilerTest extends CompilerTestingCommons with LangTests with Objec
res shouldEqual SigmaPropConstant(dk1)
}
+ property("bigInt") {
+ comp(""" bigInt("326674862673836209462483453386286740270338859283019276168539876024851191344") """) shouldBe
+ BigIntConstant(new BigInteger("326674862673836209462483453386286740270338859283019276168539876024851191344"))
+ comp(""" bigInt("-10") """) shouldBe
+ BigIntConstant(-10L)
+ }
+
property("fromBaseX") {
comp(""" fromBase16("31") """) shouldBe ByteArrayConstant(Array[Byte](49))
comp(""" fromBase58("r") """) shouldBe ByteArrayConstant(Array[Byte](49))
diff --git a/sc/shared/src/test/scala/sigmastate/lang/SigmaTemplateCompilerTest.scala b/sc/shared/src/test/scala/sigmastate/lang/SigmaTemplateCompilerTest.scala
index df8f644172..a03d160654 100644
--- a/sc/shared/src/test/scala/sigmastate/lang/SigmaTemplateCompilerTest.scala
+++ b/sc/shared/src/test/scala/sigmastate/lang/SigmaTemplateCompilerTest.scala
@@ -2,13 +2,19 @@ package sigmastate.lang
import org.ergoplatform.ErgoAddressEncoder
import org.ergoplatform.sdk.Parameter
-import org.scalatest.matchers.should.Matchers
import org.scalatest.propspec.AnyPropSpec
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-import sigma.ast.{IntConstant, SInt, SLong, SString, StringConstant}
-import sigmastate.eval.CompiletimeIRContext
+import sigma.VersionContext
+import sigma.ast.ErgoTree.HeaderType
+import sigma.ast.{BinAnd, BoolToSigmaProp, ConstantPlaceholder, ErgoTree, FalseLeaf, GT, Height, IntConstant, LT, SBoolean, SInt, SLong, SString, TrueLeaf}
+import sigma.compiler.SigmaTemplateCompiler
+import sigma.exceptions.TyperException
+import sigmastate.CompilerTestsBase
+import sigmastate.interpreter.Interpreter.ScriptEnv
+
+class SigmaTemplateCompilerTest extends AnyPropSpec with ScalaCheckPropertyChecks with CompilerTestsBase {
+ val templateCompiler = SigmaTemplateCompiler(ErgoAddressEncoder.MainnetNetworkPrefix)
-class SigmaTemplateCompilerTest extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers {
property("compiles full contract template") {
val source =
"""/** This is my contracts description.
@@ -24,8 +30,7 @@ class SigmaTemplateCompilerTest extends AnyPropSpec with ScalaCheckPropertyCheck
|@contract def contractName(p1: Int = 5, p2: String = "default string", param3: Long) = {
| sigmaProp(true)
|}""".stripMargin
- val compiler = SigmaTemplateCompiler(ErgoAddressEncoder.MainnetNetworkPrefix)
- val template = compiler.compile(Map.empty, source)
+ val template = templateCompiler.compile(source)
template.name shouldBe "contractName"
template.description shouldBe "This is my contracts description. Here is another line describing what it does in more detail."
@@ -36,16 +41,12 @@ class SigmaTemplateCompilerTest extends AnyPropSpec with ScalaCheckPropertyCheck
)
template.constTypes should contain theSameElementsInOrderAs Seq(SInt, SString, SLong)
template.constValues.get should contain theSameElementsInOrderAs IndexedSeq(
- Some(IntConstant(5).asWrappedType),
- Some(StringConstant("default string").asWrappedType),
+ Some(5),
+ Some("default string"),
None
)
- val sigmaCompiler = new SigmaCompiler(ErgoAddressEncoder.MainnetNetworkPrefix)
- implicit val ir = new CompiletimeIRContext
- val result = sigmaCompiler.compile(Map.empty, "{ sigmaProp(true) }")
-
- template.expressionTree shouldBe result.buildTree
+ checkEquals(template.expressionTree, BoolToSigmaProp(TrueLeaf))
}
property("compiles contract template without braces") {
@@ -62,8 +63,7 @@ class SigmaTemplateCompilerTest extends AnyPropSpec with ScalaCheckPropertyCheck
|*/
|@contract def contractName(p1: Int = 5, p2: String = "default string") = sigmaProp(true)
|""".stripMargin
- val compiler = SigmaTemplateCompiler(ErgoAddressEncoder.MainnetNetworkPrefix)
- val template = compiler.compile(Map.empty, source)
+ val template = templateCompiler.compile(source)
template.name shouldBe "contractName"
template.description shouldBe "This is my contracts description. Here is another line describing what it does in more detail."
@@ -73,16 +73,137 @@ class SigmaTemplateCompilerTest extends AnyPropSpec with ScalaCheckPropertyCheck
)
template.constTypes should contain theSameElementsInOrderAs Seq(SInt, SString)
template.constValues.get should contain theSameElementsInOrderAs IndexedSeq(
- Some(IntConstant(5).asWrappedType),
- Some(StringConstant("default string").asWrappedType)
+ Some(5),
+ Some("default string")
+ )
+
+ checkEquals(template.expressionTree, BoolToSigmaProp(TrueLeaf))
+ }
+
+ property("uses default value from parameter definition") {
+ val source =
+ """/**/
+ |@contract def contractName(p: Boolean = true) = sigmaProp(p && HEIGHT > 1000)
+ |""".stripMargin
+ val template = templateCompiler.compile(source)
+
+ template.parameters should contain theSameElementsInOrderAs IndexedSeq(
+ Parameter("p", "", 0)
+ )
+ template.constTypes should contain theSameElementsInOrderAs Seq(SBoolean)
+ template.constValues.get should contain theSameElementsInOrderAs IndexedSeq(
+ Some(true)
+ )
+
+ val expectedExpr = BoolToSigmaProp(BinAnd(ConstantPlaceholder(0, SBoolean), GT(Height, IntConstant(1000))))
+ checkEquals(template.expressionTree, expectedExpr)
+
+ val expectedTree = new ErgoTree(
+ HeaderType @@ 26.toByte, // use ErgoTreeUtils to get explanation
+ Vector(TrueLeaf),
+ Right(BoolToSigmaProp(BinAnd(ConstantPlaceholder(0, SBoolean), GT(Height, IntConstant(1000))))))
+
+ expectedTree.version shouldBe VersionContext.JitActivationVersion
+ expectedTree.hasSize shouldBe true
+ expectedTree.isConstantSegregation shouldBe true
+
+ // apply using default values declared in the parameters
+ checkEquals(
+ template.applyTemplate(
+ version = Some(VersionContext.JitActivationVersion),
+ paramValues = Map.empty
+ ),
+ expectedTree
+ )
+
+ // apply overriding the default values
+ checkEquals(
+ template.applyTemplate(
+ version = Some(VersionContext.JitActivationVersion),
+ paramValues = Map("p" -> FalseLeaf)
+ ),
+ expectedTree.copy(constants = Vector(FalseLeaf))
+ )
+ }
+
+ property("uses given environment when provided (overriding default value)") {
+ val source =
+ """/**/
+ |@contract def contractName(low: Int = 0, high: Int) = sigmaProp(low < HEIGHT && HEIGHT < high)
+ |""".stripMargin
+ val template = templateCompiler.compile(source)
+
+ template.parameters should contain theSameElementsInOrderAs IndexedSeq(
+ Parameter("low", "", 0),
+ Parameter("high", "", 1)
+ )
+ template.constTypes should contain theSameElementsInOrderAs Seq(SInt, SInt)
+ // check parsed default values
+ template.constValues.get should contain theSameElementsInOrderAs IndexedSeq(
+ Some(0),
+ None
+ )
+ checkEquals(
+ template.expressionTree,
+ BoolToSigmaProp(
+ BinAnd(
+ LT(ConstantPlaceholder(0, SInt), Height),
+ LT(Height, ConstantPlaceholder(1, SInt))
+ )
+ )
)
- val sigmaCompiler = new SigmaCompiler(ErgoAddressEncoder.MainnetNetworkPrefix)
- implicit val ir = new CompiletimeIRContext
- val result = sigmaCompiler.compile(Map.empty, "sigmaProp(true)")
+ // incomplete application (missing `high` parameter)
+ assertExceptionThrown(
+ template.applyTemplate(
+ version = Some(VersionContext.JitActivationVersion),
+ paramValues = Map.empty
+ ),
+ exceptionLike[IllegalArgumentException](
+ "requirement failed: value for parameter `high` was not provided while it does not have a default value.")
+ )
+
+ val expectedTree = new ErgoTree(
+ HeaderType @@ 26.toByte,
+ Vector(IntConstant(0), IntConstant(100)),
+ Right(
+ BoolToSigmaProp(
+ BinAnd(LT(ConstantPlaceholder(0, SInt), Height), LT(Height, ConstantPlaceholder(1, SInt)))
+ )
+ )
+ )
+
+ // apply providing the parameter without default value
+ checkEquals(
+ template.applyTemplate(
+ version = Some(VersionContext.JitActivationVersion),
+ paramValues = Map("high" -> IntConstant(100))
+ ),
+ expectedTree
+ )
- template.expressionTree shouldBe result.buildTree
+ // apply providing all parameters overriding the default values
+ checkEquals(
+ template.applyTemplate(
+ version = Some(VersionContext.JitActivationVersion),
+ paramValues = Map("low" -> IntConstant(10), "high" -> IntConstant(100))
+ ),
+ expectedTree.copy(constants = Vector(IntConstant(10), IntConstant(100)))
+ )
}
+
+ property("fails when the parameter is not provided") {
+ // NOTE: parameter `condition` is not provided */
+ val source =
+ """/**/
+ |@contract def contractName(low: Int = 0, high: Int) = sigmaProp(low < HEIGHT && HEIGHT < high) && condition
+ |""".stripMargin
+ assertExceptionThrown(
+ templateCompiler.compile(source),
+ exceptionLike[TyperException]("Cannot assign type for variable 'condition' because it is not found in env")
+ )
+ }
+
}
diff --git a/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala b/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala
index 99ad2ae908..c86cb11afc 100644
--- a/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala
+++ b/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala
@@ -5,7 +5,7 @@ import org.ergoplatform._
import org.scalatest.matchers.should.Matchers
import org.scalatest.propspec.AnyPropSpec
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-import sigma.Colls
+import sigma.{Colls, VersionContext}
import sigma.ast.SCollection._
import sigma.ast._
import sigma.ast.syntax.{SValue, SigmaPropValue, SigmaPropValueOps}
@@ -19,7 +19,10 @@ import sigmastate.lang.parsers.ParserException
import sigma.serialization.ErgoTreeSerializer
import sigma.serialization.generators.ObjectGenerators
import sigma.ast.Select
+import sigma.compiler.phases.{SigmaBinder, SigmaTyper}
import sigma.exceptions.TyperException
+import sigmastate.exceptions.MethodNotFound
+import sigmastate.helpers.SigmaPPrint
class SigmaTyperTest extends AnyPropSpec
with ScalaCheckPropertyChecks with Matchers with LangTests with ObjectGenerators {
@@ -27,6 +30,7 @@ class SigmaTyperTest extends AnyPropSpec
private val predefFuncRegistry = new PredefinedFuncRegistry(StdSigmaBuilder)
import predefFuncRegistry._
+ /** Checks that parsing, binding and typing of `x` results in the given expected value. */
def typecheck(env: ScriptEnv, x: String, expected: SValue = null): SType = {
try {
val builder = TransformingSigmaBuilder
@@ -34,10 +38,16 @@ class SigmaTyperTest extends AnyPropSpec
val predefinedFuncRegistry = new PredefinedFuncRegistry(builder)
val binder = new SigmaBinder(env, builder, TestnetNetworkPrefix, predefinedFuncRegistry)
val bound = binder.bind(parsed)
- val typer = new SigmaTyper(builder, predefinedFuncRegistry, lowerMethodCalls = true)
+ val typeEnv = env.collect { case (k, v: SType) => k -> v }
+ val typer = new SigmaTyper(builder, predefinedFuncRegistry, typeEnv, lowerMethodCalls = true)
val typed = typer.typecheck(bound)
assertSrcCtxForAllNodes(typed)
- if (expected != null) typed shouldBe expected
+ if (expected != null) {
+ if (expected != typed) {
+ SigmaPPrint.pprintln(typed, width = 100)
+ }
+ typed shouldBe expected
+ }
typed.tpe
} catch {
case e: Exception => throw e
@@ -51,7 +61,8 @@ class SigmaTyperTest extends AnyPropSpec
val predefinedFuncRegistry = new PredefinedFuncRegistry(builder)
val binder = new SigmaBinder(env, builder, TestnetNetworkPrefix, predefinedFuncRegistry)
val bound = binder.bind(parsed)
- val typer = new SigmaTyper(builder, predefinedFuncRegistry, lowerMethodCalls = true)
+ val typeEnv = env.collect { case (k, v: SType) => k -> v }
+ val typer = new SigmaTyper(builder, predefinedFuncRegistry, typeEnv, lowerMethodCalls = true)
typer.typecheck(bound)
}, {
case te: TyperException =>
@@ -113,6 +124,7 @@ class SigmaTyperTest extends AnyPropSpec
typecheck(env, "min(HEIGHT, INPUTS.size)") shouldBe SInt
typecheck(env, "max(1, 2)") shouldBe SInt
typecheck(env, "max(1L, 2)") shouldBe SLong
+ typecheck(env, """bigInt("1111")""") shouldBe SBigInt
typecheck(env, """fromBase16("1111")""") shouldBe SByteArray
typecheck(env, """fromBase58("111")""") shouldBe SByteArray
typecheck(env, """fromBase64("111")""") shouldBe SByteArray
@@ -507,6 +519,48 @@ class SigmaTyperTest extends AnyPropSpec
typefail(env, "1.toSuperBigInteger", 1, 1)
}
+ property("toBytes method for numeric types") {
+ typecheck(env, "1.toByte.toBytes",
+ expected = MethodCall.typed[Value[SCollection[SByte.type]]](
+ Select(IntConstant(1), "toByte", Some(SByte)),
+ SNumericTypeMethods.ToBytesMethod.withConcreteTypes(Map(STypeVar("TNum") -> SByte)),
+ Vector(),
+ Map()
+ )) shouldBe SByteArray
+
+ typecheck(env, "1.toShort.toBytes",
+ expected = MethodCall.typed[Value[SCollection[SByte.type]]](
+ Select(IntConstant(1), "toShort", Some(SShort)),
+ SNumericTypeMethods.ToBytesMethod.withConcreteTypes(Map(STypeVar("TNum") -> SShort)),
+ Vector(),
+ Map()
+ )) shouldBe SByteArray
+
+ typecheck(env, "1.toBytes",
+ expected = MethodCall.typed[Value[SCollection[SByte.type]]](
+ IntConstant(1),
+ SNumericTypeMethods.ToBytesMethod.withConcreteTypes(Map(STypeVar("TNum") -> SInt)),
+ Vector(),
+ Map()
+ )) shouldBe SByteArray
+
+ typecheck(env, "1.toLong.toBytes",
+ expected = MethodCall.typed[Value[SCollection[SByte.type]]](
+ Select(IntConstant(1), "toLong", Some(SLong)),
+ SNumericTypeMethods.ToBytesMethod.withConcreteTypes(Map(STypeVar("TNum") -> SLong)),
+ Vector(),
+ Map()
+ )) shouldBe SByteArray
+
+ typecheck(env, "1.toBigInt.toBytes",
+ expected = MethodCall.typed[Value[SCollection[SByte.type]]](
+ Select(IntConstant(1), "toBigInt", Some(SBigInt)),
+ SNumericTypeMethods.ToBytesMethod.withConcreteTypes(Map(STypeVar("TNum") -> SBigInt)),
+ Vector(),
+ Map()
+ )) shouldBe SByteArray
+ }
+
property("string concat") {
typecheck(env, """ "a" + "b" """) shouldBe SString
}
@@ -629,6 +683,16 @@ class SigmaTyperTest extends AnyPropSpec
typecheck(env, "CONTEXT.dataInputs") shouldBe SCollection(SBox)
}
+ property("SContext.getVar") {
+ typecheck(env, "CONTEXT.getVar[Int](1.toByte).get") shouldBe SInt
+ }
+
+ property("SContext.getVarFromInput") {
+ runWithVersion(VersionContext.V6SoftForkVersion) {
+ typecheck(env, "CONTEXT.getVarFromInput[Int](1.toShort, 1.toByte).get") shouldBe SInt
+ }
+ }
+
property("SAvlTree.digest") {
typecheck(env, "getVar[AvlTree](1).get.digest") shouldBe SByteArray
}
@@ -659,4 +723,36 @@ class SigmaTyperTest extends AnyPropSpec
)
typecheck(customEnv, "substConstants(scriptBytes, positions, newVals)") shouldBe SByteArray
}
+
+ property("Global.serialize") {
+ runWithVersion(VersionContext.V6SoftForkVersion) {
+ typecheck(env, "Global.serialize(1)",
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ Global,
+ SGlobalMethods.getMethodByName("serialize").withConcreteTypes(Map(STypeVar("T") -> SInt)),
+ Array(IntConstant(1)),
+ Map()
+ )) shouldBe SByteArray
+ }
+
+ runWithVersion((VersionContext.V6SoftForkVersion - 1).toByte) {
+ assertExceptionThrown(
+ typecheck(env, "Global.serialize(1)"),
+ exceptionLike[MethodNotFound]("Cannot find method 'serialize' in in the object Global")
+ )
+ }
+ }
+
+ property("predefined serialize") {
+ runWithVersion(VersionContext.V6SoftForkVersion) {
+ typecheck(env, "serialize((1, 2L))",
+ expected = MethodCall.typed[Value[SCollection[SByte.type]]](
+ Global,
+ SGlobalMethods.getMethodByName("serialize").withConcreteTypes(Map(STypeVar("T") -> SPair(SInt, SLong))),
+ Array(Tuple(Vector(IntConstant(1), LongConstant(2L)))),
+ Map()
+ )) shouldBe SByteArray
+ }
+ }
+
}
diff --git a/sc/shared/src/test/scala/sigmastate/serialization/ErgoTreeSerializerSpecification.scala b/sc/shared/src/test/scala/sigmastate/serialization/ErgoTreeSerializerSpecification.scala
index e20d8a6d1e..f7129a7723 100644
--- a/sc/shared/src/test/scala/sigmastate/serialization/ErgoTreeSerializerSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/serialization/ErgoTreeSerializerSpecification.scala
@@ -10,9 +10,9 @@ import sigma.util.Extensions.SigmaPropOps
import sigma.validation.ValidationException
import ErgoTree.EmptyConstants
import ErgoTree.HeaderType
+import sigma.compiler.ir.IRContext
import sigma.eval.Extensions.SigmaBooleanOps
import sigmastate._
-import sigmastate.eval.IRContext
import sigmastate.helpers.CompilerTestingCommons
import sigma.serialization.ErgoTreeSerializer.DefaultSerializer
diff --git a/sc/shared/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala
index 566bf5bd58..6b0c0080c9 100644
--- a/sc/shared/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala
@@ -9,7 +9,6 @@ import scorex.crypto.hash.{Blake2b256, Digest32}
import sigma.ast.SCollection.SByteArray
import sigma.ast._
import sigmastate._
-import sigmastate.eval.IRContext
import sigmastate.eval._
import sigma.Extensions.ArrayOps
import sigmastate.helpers.{CompilerTestingCommons, ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestInterpreter}
@@ -19,6 +18,7 @@ import sigma.ast.syntax._
import sigma.Coll
import sigma.ast.SAvlTree
import sigma.ast.syntax.{GetVarByteArray, OptionValueOps}
+import sigma.compiler.ir.IRContext
import sigma.data.{AvlTreeData, AvlTreeFlags, CSigmaProp, TrivialProp}
import sigma.eval.SigmaDsl
import sigma.interpreter.ProverResult
@@ -30,7 +30,7 @@ class AVLTreeScriptsSpecification extends CompilerTestingCommons
with CompilerCrossVersionProps { suite =>
import org.ergoplatform.dsl.AvlTreeHelpers._
lazy val spec = TestContractSpec(suite)(new TestingIRContext)
- lazy val prover = spec.ProvingParty("Alice")
+ lazy val prover = spec.ProvingParty("Alice")
private implicit lazy val IR: IRContext = spec.IR
private val reg1 = ErgoBox.nonMandatoryRegisters(0)
diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala
index 346ad69e1a..0eba3c9878 100644
--- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala
@@ -2,10 +2,15 @@ package sigmastate.utxo
import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8}
import org.ergoplatform._
+import org.scalatest.Assertion
+import scorex.util.encode.Base16
+import scorex.utils.Ints
import sigma.Extensions.ArrayOps
+import sigma.{SigmaTestingData, VersionContext}
+import sigma.VersionContext.{V6SoftForkVersion, withVersions}
import sigma.ast.SCollection.SByteArray
import sigma.ast.SType.AnyOps
-import sigma.data.{AvlTreeData, CAnyValue}
+import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder}
import sigma.util.StringUtil._
import sigma.ast._
import sigma.ast.syntax._
@@ -14,14 +19,18 @@ import sigmastate._
import sigmastate.helpers.TestingHelpers._
import sigmastate.helpers.{CompilerTestingCommons, ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestInterpreter}
import sigma.interpreter.ContextExtension.VarBinding
-import sigmastate.interpreter.CErgoTreeEvaluator.DefaultEvalSettings
+import sigmastate.interpreter.CErgoTreeEvaluator.{DefaultEvalSettings, currentEvaluator}
import sigmastate.interpreter.Interpreter._
import sigma.ast.Apply
import sigma.eval.EvalSettings
import sigma.exceptions.InvalidType
+import sigma.serialization.ErgoTreeSerializer
+import sigma.interpreter.{ContextExtension, ProverResult}
+import sigmastate.utils.Helpers
import sigmastate.utils.Helpers._
import java.math.BigInteger
+import scala.collection.compat.immutable.ArraySeq
class BasicOpsSpecification extends CompilerTestingCommons
with CompilerCrossVersionProps {
@@ -83,8 +92,11 @@ class BasicOpsSpecification extends CompilerTestingCommons
// is not supported by ErgoScript Compiler)
// In such cases we use expected property as the property to test
propExp.asSigmaProp
- } else
- compile(env, script).asBoolValue.toSigmaProp
+ } else {
+ withVersions(VersionContext.MaxSupportedScriptVersion, ergoTreeVersionInTests) {
+ compile(env, script).asBoolValue.toSigmaProp
+ }
+ }
if (propExp != null)
prop shouldBe propExp
@@ -101,7 +113,8 @@ class BasicOpsSpecification extends CompilerTestingCommons
val newBox1 = testBox(10, tree, creationHeight = 0, boxIndex = 0, additionalRegisters = Map(
reg1 -> IntConstant(1),
reg2 -> IntConstant(10)))
- val tx = createTransaction(newBox1)
+ val ce = ContextExtension(prover.contextExtenders)
+ val tx = new ErgoLikeTransaction(IndexedSeq(Input(boxToSpend.id, ProverResult(Array.empty, ce))), ArraySeq.empty, IndexedSeq(newBox1))
val ctx = ErgoLikeContextTesting(currentHeight = 0,
lastBlockUtxoRoot = AvlTreeData.dummy, ErgoLikeContextTesting.dummyPubkey, boxesToSpend = IndexedSeq(boxToSpend),
@@ -135,26 +148,1045 @@ class BasicOpsSpecification extends CompilerTestingCommons
flexVerifier.verify(verifyEnv, tree, ctxExt, pr.proof, fakeMessage).get._1 shouldBe true
}
- property("Unit register") {
- // TODO frontend: implement missing Unit support in compiler
- // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820
- test("R1", env, ext,
- script = "", /* means cannot be compiled
- the corresponding script is { SELF.R4[Unit].isDefined } */
- ExtractRegisterAs[SUnit.type](Self, reg1)(SUnit).isDefined.toSigmaProp,
- additionalRegistersOpt = Some(Map(
- reg1 -> UnitConstant.instance
- ))
+
+ property("getVarFromInput") {
+ def getVarTest(): Assertion = {
+ val customExt = Map(
+ 1.toByte -> IntConstant(5)
+ ).toSeq
+ test("R1", env, customExt,
+ "{ sigmaProp(getVarFromInput[Int](0, 1).get == 5) }",
+ null
+ )
+ }
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ getVarTest()
+ } else {
+ an[sigma.validation.ValidationException] should be thrownBy getVarTest()
+ }
+ }
+
+ property("getVarFromInput - self index") {
+ def getVarTest(): Assertion = {
+ val customExt = Map(
+ 1.toByte -> IntConstant(5)
+ ).toSeq
+ test("R1", env, customExt,
+ """{
+ | val idx = CONTEXT.selfBoxIndex
+ | sigmaProp(CONTEXT.getVarFromInput[Int](idx.toShort, 1.toByte).get == 5)
+ | }""".stripMargin,
+ null
+ )
+ }
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ getVarTest()
+ } else {
+ an[sigma.validation.ValidationException] should be thrownBy getVarTest()
+ }
+ }
+
+ property("getVarFromInput - invalid input") {
+ def getVarTest(): Assertion = {
+ val customExt = Map(
+ 1.toByte -> IntConstant(5)
+ ).toSeq
+ test("R1", env, customExt,
+ "{ sigmaProp(CONTEXT.getVarFromInput[Int](1, 1).isDefined == false) }",
+ null
+ )
+ }
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ getVarTest()
+ } else {
+ an[sigma.validation.ValidationException] should be thrownBy getVarTest()
+ }
+ }
+
+ property("Byte.toBits") {
+ val customExt = Map(
+ 1.toByte -> ByteConstant(1)
+ ).toSeq
+ def toBitsTest() = test("Byte.toBits", env, customExt,
+ """{
+ | val b = getVar[Byte](1).get
+ | b.toBits == Coll(false, false, false, false, false, false, false, true)
+ |}""".stripMargin,
+ null
)
- test("R2", env, ext,
- script = "", /* means cannot be compiled
- the corresponding script is "{ SELF.R4[Unit].get == () }" */
- EQ(ExtractRegisterAs[SUnit.type](Self, reg1)(SUnit).get, UnitConstant.instance).toSigmaProp,
- additionalRegistersOpt = Some(Map(
- reg1 -> UnitConstant.instance
- ))
+ if (VersionContext.current.isV6SoftForkActivated) {
+ toBitsTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(toBitsTest())
+ }
+ }
+
+ property("Long.toBits") {
+ val customExt = Map(
+ 1.toByte -> LongConstant(1)
+ ).toSeq
+ def toBitsTest() = test("Long.toBits", env, customExt,
+ """{
+ | val b = getVar[Long](1).get
+ | val ba = b.toBits
+ |
+ | // only rightmost bit is set
+ | ba.size == 64 && ba(63) == true && ba.slice(0, 63).forall({ (b: Boolean ) => b == false })
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ toBitsTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(toBitsTest())
+ }
+ }
+
+ property("BigInt.toBits") {
+ def toBitsTest() = test("BigInt.toBits", env, ext,
+ s"""{
+ | val b = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}")
+ | val ba = b.toBits
+ | ba.size == 256
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ toBitsTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(toBitsTest())
+ }
+ }
+
+ property("BigInt.bitwiseInverse") {
+ def bitwiseInverseTest(): Assertion = test("BigInt.bitwiseInverse", env, ext,
+ s"""{
+ | val b = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}")
+ | val bi = b.bitwiseInverse
+ | bi.bitwiseInverse == b
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseInverseTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseInverseTest())
+ }
+ }
+
+
+ property("Byte.bitwiseInverse") {
+ def bitwiseInverseTest(): Assertion = test("Byte.bitwiseInverse", env, ext,
+ s"""{
+ | val b = (126 + 1).toByte // max byte value
+ | b.bitwiseInverse == (-128).toByte
+ |}""".stripMargin,
+ null
)
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseInverseTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseInverseTest())
+ }
+ }
+
+ property("Long.bitwiseInverse") {
+ val customExt = Map(
+ 1.toByte -> LongConstant(9223372036854775807L)
+ ).toSeq
+ def bitwiseInverseTest(): Assertion = test("Long.bitwiseInverse", env, customExt,
+ s"""{
+ | val l = getVar[Long](1).get
+ | val lb = l.bitwiseInverse
+ | lb.bitwiseInverse == l
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseInverseTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseInverseTest())
+ }
+ }
+
+
+ property("Byte.bitwiseOr") {
+ val customExt = Map(
+ 1.toByte -> ByteConstant(127)
+ ).toSeq
+ def bitwiseOrTest(): Assertion = test("Byte.bitwiseOrTest", env, customExt,
+ s"""{
+ | val x = getVar[Byte](1).get
+ | val y = (-128).toByte
+ | x.bitwiseOr(y) == -1
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseOrTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseOrTest())
+ }
+ }
+
+ property("BigInt.bitwiseOr") {
+ def bitwiseOrTest(): Assertion = test("BigInt.bitwiseOr", env, ext,
+ s"""{
+ | val x = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}")
+ | x.bitwiseOr(x) == x
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseOrTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseOrTest())
+ }
+ }
+
+ property("BigInt.bitwiseAnd") {
+ def bitwiseAndTest(): Assertion = test("BigInt.bitwiseAnd", env, ext,
+ s"""{
+ | val x = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}")
+ | val y = 0.toBigInt
+ | x.bitwiseAnd(y) == y
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseAndTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseAndTest())
+ }
+ }
+
+ property("Short.bitwiseAnd") {
+ val customExt = Map(
+ 1.toByte -> ShortConstant(32767)
+ ).toSeq
+ def bitwiseAndTest(): Assertion = test("Short.bitwiseAnd", env, customExt,
+ s"""{
+ | val x = getVar[Short](1).get
+ | val y = (-32768).toShort
+ | x.bitwiseAnd(y) == 0
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseAndTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseAndTest())
+ }
+ }
+
+ property("Short.bitwiseXor") {
+ val customExt = Map(
+ 1.toByte -> ShortConstant(32767)
+ ).toSeq
+ def bitwiseXorTest(): Assertion = test("Short.bitwiseXor", env, customExt,
+ s"""{
+ | val x = getVar[Short](1).get
+ | val y = (-32768).toShort
+ | x.bitwiseXor(y) == -1
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseXorTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseXorTest())
+ }
+ }
+
+ property("Byte.shiftLeft") {
+ def shiftLeftTest(): Assertion = test("Byte.shiftLeft", env, ext,
+ s"""{
+ | val x = 4.toByte
+ | val y = 2
+ | x.shiftLeft(y) == 16.toByte
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ shiftLeftTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest())
+ }
+ }
+
+ property("Byte.shiftLeft - over limit") {
+ def shiftLeftTest(): Assertion = test("Byte.shiftLeft2", env, ext,
+ s"""{
+ | val x = 4.toByte
+ | val y = 2222
+ | x.shiftLeft(y) == 0
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ an[IllegalArgumentException] shouldBe thrownBy(shiftLeftTest())
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest())
+ }
+ }
+
+ property("Byte.shiftLeft - over limit 2") {
+ def shiftLeftTest(): Assertion = test("Byte.shiftLeft2", env, ext,
+ s"""{
+ | val x = (-128).toByte
+ | val y = 1
+ | x.shiftLeft(y) == 0
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ shiftLeftTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest())
+ }
+ }
+
+ property("BigInt.shiftLeft") {
+ def shiftLeftTest(): Assertion = test("BigInt.shiftLeft", env, ext,
+ s"""{
+ | val x = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("8"))}")
+ | val y = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}")
+ | x.shiftLeft(2) == y
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ shiftLeftTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest())
+ }
+ }
+
+ property("BigInt.shiftLeft over limits") {
+ def shiftLeftTest(): Assertion = test("BigInt.shiftLeft", env, ext,
+ s"""{
+ | val x = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}")
+ | x.shiftLeft(1) > x
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ an[ArithmeticException] shouldBe thrownBy(shiftLeftTest())
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest())
+ }
+ }
+
+ property("Byte.shiftRight") {
+ def shiftRightTest(): Assertion = test("Byte.shiftRight", env, ext,
+ s"""{
+ | val x = 8.toByte
+ | val y = 2
+ | x.shiftRight(y) == 2.toByte
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ shiftRightTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest())
+ }
+ }
+
+ property("Byte.shiftRight - neg") {
+ def shiftRightTest(): Assertion = test("Byte.shiftRight", env, ext,
+ s"""{
+ | val x = (-8).toByte
+ | val y = 2
+ | x.shiftRight(y) == (-2).toByte
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ shiftRightTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest())
+ }
+ }
+
+ property("Byte.shiftRight - neg - neg shift") {
+ def shiftRightTest(): Assertion = test("Byte.shiftRight", env, ext,
+ s"""{
+ | val x = (-8).toByte
+ | val y = -2
+ | x.shiftRight(y) == (-1).toByte
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ an[IllegalArgumentException] shouldBe thrownBy(shiftRightTest())
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest())
+ }
+ }
+
+
+ property("Long.shiftRight - neg") {
+ def shiftRightTest(): Assertion = test("Long.shiftRight", env, ext,
+ s"""{
+ | val x = -32L
+ | val y = 2
+ | x.shiftRight(y) == -8L
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ shiftRightTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest())
+ }
+ }
+
+ property("Long.shiftRight - neg - neg shift") {
+ def shiftRightTest(): Assertion = test("Long.shiftRight", env, ext,
+ s"""{
+ | val x = -32L
+ | val y = -2
+ | x.shiftRight(y) == -1L
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ an[IllegalArgumentException] shouldBe thrownBy(shiftRightTest())
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest())
+ }
+ }
+
+ property("BigInt.shiftRight") {
+ def shiftRightTest(): Assertion = test("BigInt.shiftRight", env, ext,
+ s"""{
+ | val x = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}")
+ | val y = 2
+ | val z = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("8"))}")
+ | x.shiftRight(y) == z
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ shiftRightTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest())
+ }
+ }
+
+ property("BigInt.shiftRight - neg shift") {
+ def shiftRightTest(): Assertion = test("BigInt.shiftRight", env, ext,
+ s"""{
+ | val x = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}")
+ | val y = -2
+ | val z = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("8"))}")
+ | z.shiftRight(y) == x
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ an[IllegalArgumentException] shouldBe thrownBy(shiftRightTest())
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest())
+ }
+ }
+
+ property("getVarFromInput - invalid var") {
+ def getVarTest(): Assertion = {
+ val customExt = Map(
+ 1.toByte -> IntConstant(5)
+ ).toSeq
+ test("R1", env, customExt,
+ "{ sigmaProp(CONTEXT.getVarFromInput[Int](0, 2).isDefined == false) }",
+ null
+ )
+ }
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ getVarTest()
+ } else {
+ an[sigma.validation.ValidationException] should be thrownBy getVarTest()
+ }
+ }
+
+ property("Coll.reverse"){
+ def reverseTest() = test("reverse", env, ext,
+ """{
+ | val c1 = Coll(1, 2, 3)
+ | val c2 = Coll(3, 2, 1)
+ |
+ | val b1 = Coll(INPUTS(0), OUTPUTS(0))
+ | val b2 = Coll(OUTPUTS(0), INPUTS(0))
+ |
+ | c1.reverse == c2 && b1.reverse == b2
+ | }""".stripMargin,
+ null
+ )
+
+ if(VersionContext.current.isV6SoftForkActivated) {
+ reverseTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest())
+ }
+ }
+
+ property("Coll.distinct"){
+ def reverseTest() = test("distinct", env, ext,
+ """{
+ | val c1 = Coll(1, 2, 3, 3, 2)
+ | val c2 = Coll(3, 2, 1)
+ |
+ | val h1 = Coll(INPUTS(0), INPUTS(0))
+ | val h2 = Coll(INPUTS(0))
+ |
+ | c1.distinct.reverse == c2 && h1.distinct == h2
+ | }""".stripMargin,
+ null
+ )
+
+ if(VersionContext.current.isV6SoftForkActivated) {
+ reverseTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest())
+ }
+ }
+
+ property("Coll.startsWith"){
+ def reverseTest() = test("distinct", env, ext,
+ """{
+ | val c1 = Coll(1, 2, 3)
+ | val c2 = Coll(1, 2)
+ | val c3 = Coll(1, 3)
+ | val c4 = Coll[Int]()
+ | val c5 = Coll(1, 2, 3, 4)
+ |
+ | val b1 = c1.startsWith(c3)
+ | val b2 = c1.startsWith(c5)
+ |
+ | c1.startsWith(c2) && c1.startsWith(c4) && c1.startsWith(c1) && !b1 && !b2
+ | }""".stripMargin,
+ null
+ )
+
+ if(VersionContext.current.isV6SoftForkActivated) {
+ reverseTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest())
+ }
+ }
+
+ property("Coll.startsWith - tuples"){
+ def reverseTest() = test("distinct", env, ext,
+ """{
+ | val c1 = Coll((1, 2), (3, 4), (5, 6))
+ | val c2 = Coll((1, 2), (3, 4))
+ | val c3 = Coll((1, 3))
+ | val c4 = Coll[(Int, Int)]()
+ | val c5 = Coll((1, 2), (3, 4), (5, 6), (7, 8))
+ |
+ | val b1 = c1.startsWith(c3)
+ | val b2 = c1.startsWith(c5)
+ |
+ | c1.startsWith(c2) && c1.startsWith(c4) && c1.startsWith(c1) && !b1 && !b2
+ | }""".stripMargin,
+ null
+ )
+
+ if(VersionContext.current.isV6SoftForkActivated) {
+ reverseTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest())
+ }
+ }
+
+ property("Coll.endsWith"){
+ def reverseTest() = test("distinct", env, ext,
+ """{
+ | val c1 = Coll(1, 2, 3)
+ | val c2 = Coll(2, 3)
+ | val c3 = Coll(2, 2)
+ | val c4 = Coll[Int]()
+ | val c5 = Coll(1, 2, 3, 4)
+ |
+ | val b1 = c1.endsWith(c3)
+ | val b2 = c1.endsWith(c5)
+ |
+ | c1.endsWith(c2) && c1.endsWith(c4) && c1.endsWith(c1) && !b1 && !b2
+ | }""".stripMargin,
+ null
+ )
+
+ if(VersionContext.current.isV6SoftForkActivated) {
+ reverseTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest())
+ }
+ }
+
+ property("Coll.endsWith - tuples"){
+ def reverseTest() = test("endsWith tuples", env, ext,
+ """{
+ | val c1 = Coll((1, 2), (2, 3))
+ | val c2 = Coll((2, 3))
+ | val c3 = Coll((2, 2))
+ | val c4 = Coll[(Int, Int)]()
+ | val c5 = Coll((0, 2), (2, 3))
+ |
+ | val b1 = c1.endsWith(c3)
+ | val b2 = c1.endsWith(c5)
+ |
+ | c1.endsWith(c2) && c1.endsWith(c4) && c1.endsWith(c1) && !b1 && !b2
+ | }""".stripMargin,
+ null
+ )
+
+ if(VersionContext.current.isV6SoftForkActivated) {
+ reverseTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(reverseTest())
+ }
+ }
+
+ property("Coll.get"){
+ def getTest() = test("get", env, ext,
+ """{
+ | val c1 = Coll(1)
+ | val c2 = Coll[Int]()
+ |
+ | c2.get(0).getOrElse(c1.get(0).get) == c1.get(0).get
+ | }""".stripMargin,
+ null
+ )
+
+ if(VersionContext.current.isV6SoftForkActivated) {
+ getTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(getTest())
+ }
+ }
+
+ property("Global.fromBigEndianBytes - byte") {
+ def fromTest() = test("fromBigEndianBytes - byte", env, ext,
+ s"""{
+ | val ba = Coll(5.toByte)
+ | Global.fromBigEndianBytes[Byte](ba) == 5
+ |}
+ |""".stripMargin,
+ null
+ )
+ if(VersionContext.current.isV6SoftForkActivated) {
+ fromTest()
+ } else {
+ an[sigma.validation.ValidationException] should be thrownBy(fromTest())
+ }
+ }
+
+ property("Global.fromBigEndianBytes - short") {
+ def fromTest() = test("fromBigEndianBytes - short", env, ext,
+ s"""{
+ | val ba = Coll(5.toByte, 5.toByte)
+ | Global.fromBigEndianBytes[Short](ba) != 0
+ |}
+ |""".stripMargin,
+ null
+ )
+ if(VersionContext.current.isV6SoftForkActivated) {
+ fromTest()
+ } else {
+ an[sigma.validation.ValidationException] should be thrownBy(fromTest())
+ }
+ }
+
+ property("Global.fromBigEndianBytes - int") {
+ def fromTest() = test("fromBigEndianBytes - int", env, ext,
+ s"""{
+ | val ba = fromBase16("${Base16.encode(Ints.toByteArray(Int.MaxValue))}")
+ | Global.fromBigEndianBytes[Int](ba) == ${Int.MaxValue}
+ |}
+ |""".stripMargin,
+ null
+ )
+ if(VersionContext.current.isV6SoftForkActivated) {
+ fromTest()
+ } else {
+ an[sigma.validation.ValidationException] should be thrownBy(fromTest())
+ }
+ }
+
+ property("Global.fromBigEndianBytes - long") {
+ def fromTest() = test("fromBigEndianBytes - long", env, ext,
+ s"""{
+ | val l = 1088800L
+ | val ba = longToByteArray(l)
+ | Global.fromBigEndianBytes[Long](ba) == l
+ |}
+ |""".stripMargin,
+ null
+ )
+ if(VersionContext.current.isV6SoftForkActivated) {
+ fromTest()
+ } else {
+ an[sigma.validation.ValidationException] should be thrownBy(fromTest())
+ }
+ }
+
+ property("Global.fromBigEndianBytes - Long.toBytes") {
+ val customExt = Map(
+ 1.toByte -> LongConstant(1088800L)
+ ).toSeq
+ def fromTest() = test("fromBigEndianBytes - long", env, customExt,
+ s"""{
+ | val l = getVar[Long](1).get
+ | val ba = l.toBytes
+ | Global.fromBigEndianBytes[Long](ba) == l
+ |}
+ |""".stripMargin,
+ null
+ )
+ if(VersionContext.current.isV6SoftForkActivated) {
+ fromTest()
+ } else {
+ an[sigma.validation.ValidationException] should be thrownBy(fromTest())
+ }
+ }
+
+ property("Global.fromBigEndianBytes - bigInt") {
+ val bi = new BigInteger("9785856985394593489356430476450674590674598659865986594859056865984690568904")
+ def fromTest() = test("fromBigEndianBytes - bigInt", env, ext,
+ s"""{
+ | val ba = fromBase16("${Base16.encode(bi.toByteArray)}")
+ | Global.fromBigEndianBytes[BigInt](ba) == bigInt("$bi")
+ |}
+ |""".stripMargin,
+ null
+ )
+ if(VersionContext.current.isV6SoftForkActivated) {
+ fromTest()
+ } else {
+ an[sigma.validation.ValidationException] should be thrownBy(fromTest())
+ }
+ }
+
+ property("Int.toBytes") {
+ val customExt = Map(
+ 1.toByte -> IntConstant(1)
+ ).toSeq
+ def toBytesTest() = test("Int.toBytes", env, customExt,
+ """{
+ | val l = getVar[Int](1).get
+ | l.toBytes == Coll(0.toByte, 0.toByte, 0.toByte, 1.toByte)
+ | }""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ toBytesTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(toBytesTest())
+ }
+ }
+
+ property("Int.toBits") {
+ val customExt = Map(
+ 1.toByte -> IntConstant(1477959696)
+ ).toSeq
+ def toBytesTest() = test("Int.toBytes", env, customExt,
+ """{
+ | val l = getVar[Int](1).get
+ | l.toBits == Coll(false, true, false, true, true, false, false, false, false, false, false, true, false, true, true ,true, true, true, true, false, false, false, false, false, false, false, false, true, false, false, false, false)
+ | }""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ toBytesTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(toBytesTest())
+ }
+ }
+
+ property("Byte.toBytes") {
+ val customExt = Map(
+ 1.toByte -> ByteConstant(10)
+ ).toSeq
+ def toBytesTest() = test("Byte.toBytes", env, customExt,
+ """{
+ | val l = getVar[Byte](1).get
+ | l.toBytes == Coll(10.toByte)
+ | }""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ toBytesTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(toBytesTest())
+ }
+ }
+
+
+ property("BigInt.toBytes") {
+ def toBytesTest() = test("BigInt.toBytes", env, ext,
+ s"""{
+ | val l = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}")
+ | l.toBytes.size == 32
+ | }""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ toBytesTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(toBytesTest())
+ }
+ }
+
+ property("serialize - byte array") {
+ def deserTest() = test("serialize", env, ext,
+ s"""{
+ val ba = fromBase16("c0ffee");
+ Global.serialize(ba).size > ba.size
+ }""",
+ null,
+ true
+ )
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an [sigma.validation.ValidationException] should be thrownBy deserTest()
+ } else {
+ deserTest()
+ }
+ }
+
+ property("serialize - collection of boxes") {
+ def deserTest() = test("serialize", env, ext,
+ s"""{
+ val boxes = INPUTS;
+ Global.serialize(boxes).size > 0
+ }""",
+ null,
+ true
+ )
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an [sigma.validation.ValidationException] should be thrownBy deserTest()
+ } else {
+ deserTest()
+ }
+ }
+
+ property("serialize - optional collection") {
+ def deserTest() = test("serialize", env, ext,
+ s"""{
+ val opt = SELF.R1[Coll[Byte]];
+ Global.serialize(opt).size > SELF.R1[Coll[Byte]].get.size
+ }""",
+ null,
+ true
+ )
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an [sigma.validation.ValidationException] should be thrownBy deserTest()
+ } else {
+ deserTest()
+ }
+ }
+
+ property("serialize(long) is producing different result from longToByteArray()") {
+ def deserTest() = test("serialize", env, ext,
+ s"""{
+ val l = -1000L
+ val ba1 = Global.serialize(l);
+ val ba2 = longToByteArray(l)
+ ba1 != ba2
+ }""",
+ null,
+ true
+ )
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an [sigma.validation.ValidationException] should be thrownBy deserTest()
+ } else {
+ deserTest()
+ }
+ }
+
+ // the test shows that serialize(groupElement) is the same as groupElement.getEncoded
+ property("serialize - group element - equivalence with .getEncoded") {
+ val ge = Helpers.decodeGroupElement("026930cb9972e01534918a6f6d6b8e35bc398f57140d13eb3623ea31fbd069939b")
+ // val ba = Base16.encode(ge.getEncoded.toArray)
+ def deserTest() = test("serialize", env, Seq(21.toByte -> GroupElementConstant(ge)),
+ s"""{
+ val ge = getVar[GroupElement](21).get
+ val ba = serialize(ge);
+ ba == ge.getEncoded
+ }""",
+ null,
+ true
+ )
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an [sigma.validation.ValidationException] should be thrownBy deserTest()
+ } else {
+ deserTest()
+ }
+ }
+
+ // the test shows that serialize(sigmaProp) is the same as sigmaProp.propBytes without first 2 bytes
+ property("serialize and .propBytes correspondence") {
+ def deserTest() = test("deserializeTo", env, ext,
+ s"""{
+ val p1 = getVar[SigmaProp]($propVar1).get
+ val bytes = p1.propBytes
+ val ba = bytes.slice(2, bytes.size)
+ val ba2 = serialize(p1)
+ ba == ba2
+ }""",
+ null,
+ true
+ )
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an [sigma.validation.ValidationException] should be thrownBy deserTest()
+ } else {
+ deserTest()
+ }
+ }
+
+ // todo: failing, needs for Header (de)serialization support from https://github.com/ScorexFoundation/sigmastate-interpreter/pull/972
+ property("serialize - collection of collection of headers") {
+ val td = new SigmaTestingData {}
+ val h1 = td.TestData.h1
+
+ val customExt = Seq(21.toByte -> HeaderConstant(h1))
+
+ def deserTest() = test("serialize", env, customExt,
+ s"""{
+ val h1 = getVar[Header](21).get;
+ val c = Coll(Coll(h1))
+ Global.serialize(c).size > 0
+ }""",
+ null,
+ true
+ )
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an [sigma.validation.ValidationException] should be thrownBy deserTest()
+ } else {
+ deserTest()
+ }
+ }
+
+ // todo: roundtrip tests with deserializeTo from https://github.com/ScorexFoundation/sigmastate-interpreter/pull/979
+
+ // todo: move spam tests to dedicated test suite?
+ property("serialize - not spam") {
+ val customExt = Seq(21.toByte -> ShortArrayConstant((1 to Short.MaxValue).map(_.toShort).toArray),
+ 22.toByte -> ByteArrayConstant(Array.fill(1)(1.toByte)))
+ def deserTest() = test("serialize", env, customExt,
+ s"""{
+ val indices = getVar[Coll[Short]](21).get
+ val base = getVar[Coll[Byte]](22).get
+
+ def check(index:Short): Boolean = { serialize(base) != base }
+ indices.forall(check)
+ }""",
+ null,
+ true
+ )
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[sigma.validation.ValidationException] should be thrownBy deserTest()
+ } else {
+ deserTest()
+ }
+ }
+
+ property("serialize - spam attempt") {
+ val customExt = Seq(21.toByte -> ShortArrayConstant((1 to Short.MaxValue).map(_.toShort).toArray),
+ 22.toByte -> ByteArrayConstant(Array.fill(16000)(1.toByte)))
+ def deserTest() = test("serialize", env, customExt,
+ s"""{
+ val indices = getVar[Coll[Short]](21).get
+ val base = getVar[Coll[Byte]](22).get
+
+ def check(index:Short): Boolean = { serialize(base) != base }
+ indices.forall(check)
+ }""",
+ null,
+ true
+ )
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[sigma.validation.ValidationException] should be thrownBy deserTest()
+ } else {
+ // we have wrapped CostLimitException here
+ an[Exception] should be thrownBy deserTest()
+ }
+ }
+
+ property("Lazy evaluation of default in Option.getOrElse") {
+ val customExt = Map (
+ 1.toByte -> IntConstant(5)
+ ).toSeq
+ def optTest() = test("getOrElse", env, customExt,
+ """{
+ | getVar[Int](1).getOrElse(getVar[Int](44).get) > 0
+ |}
+ |""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ optTest()
+ } else {
+ assertExceptionThrown(optTest(), _.isInstanceOf[NoSuchElementException])
+ }
+ }
+
+ property("Lazy evaluation of default in Coll.getOrElse") {
+ def optTest() = test("getOrElse", env, ext,
+ """{
+ | val c = Coll[Int](1)
+ | c.getOrElse(0, getVar[Int](44).get) > 0 &&
+ | c.getOrElse(1, c.getOrElse(0, getVar[Int](44).get)) > 0
+ |}
+ |""".stripMargin,
+ null
+ )
+
+ if(VersionContext.current.isV6SoftForkActivated) {
+ optTest()
+ } else {
+ assertExceptionThrown(optTest(), _.isInstanceOf[NoSuchElementException])
+ }
}
property("Relation operations") {
@@ -339,7 +1371,7 @@ class BasicOpsSpecification extends CompilerTestingCommons
})
val dataVar = (lastExtVar + 1).toByte
- val Colls = IR.sigmaDslBuilderValue.Colls
+ val Colls = CSigmaDslBuilder.Colls
implicit val eAny = sigma.AnyType
val data = Colls.fromItems((Array[Byte](1,2,3).toColl, 10L))
val env1 = env + ("dataVar" -> CAnyValue(dataVar))
@@ -454,6 +1486,32 @@ class BasicOpsSpecification extends CompilerTestingCommons
rootCause(_).isInstanceOf[NoSuchElementException])
}
+ property("higher order lambdas") {
+ def holTest() = test("HOL", env, ext,
+ """
+ | {
+ | val c = Coll(Coll(1))
+ | def fn(xs: Coll[Int]) = {
+ | val inc = { (x: Int) => x + 1 }
+ | def apply(in: (Int => Int, Int)) = in._1(in._2)
+ | val ys = xs.map { (x: Int) => apply((inc, x)) }
+ | ys.size == xs.size && ys != xs
+ | }
+ |
+ | c.exists(fn)
+ | }
+ |""".stripMargin,
+ null,
+ true
+ )
+
+ if(VersionContext.current.isV6SoftForkActivated) {
+ holTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(holTest())
+ }
+ }
+
property("OptionGetOrElse") {
test("OptGet1", env, ext,
"{ SELF.R5[Int].getOrElse(3) == 1 }",
@@ -721,4 +1779,113 @@ class BasicOpsSpecification extends CompilerTestingCommons
true
)
}
+
+ property("substConstants") {
+ val initTreeScript =
+ """
+ | {
+ | val v1 = 1 // 0
+ | val v2 = 2 // 2
+ | val v3 = 3 // 4
+ | val v4 = 4 // 3
+ | val v5 = 5 // 1
+ | sigmaProp(v1 == -v5 && v2 == -v4 && v3 == v2 + v4)
+ | }
+ |""".stripMargin
+
+ val iet = ErgoTree.fromProposition(compile(Map.empty, initTreeScript).asInstanceOf[SigmaPropValue])
+
+ iet.constants.toArray shouldBe Array(IntConstant(1), IntConstant(5), IntConstant(2), IntConstant(4), IntConstant(3), IntConstant(6))
+
+ val originalBytes = Base16.encode(ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(iet))
+
+ val set = ErgoTree(
+ iet.header,
+ IndexedSeq(IntConstant(-2), IntConstant(2), IntConstant(-1), IntConstant(1), IntConstant(0), IntConstant(0)),
+ iet.toProposition(false)
+ )
+
+ val hostScript =
+ s"""
+ |{
+ | val bytes = fromBase16("${originalBytes}")
+ |
+ | val substBytes = substConstants[Int](bytes, Coll[Int](0, 2, 4, 3, 1, 5), Coll[Int](-2, -1, 0, 1, 2, 0))
+ |
+ | val checkSubst = substBytes == fromBase16("${Base16.encode(ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(set))}")
+ |
+ | sigmaProp(checkSubst)
+ |}
+ |""".stripMargin
+
+ test("subst", env, ext, hostScript, null)
+ }
+
+ property("Box.getReg") {
+ val customExt = Map(
+ 1.toByte -> IntConstant(0)
+ ).toSeq
+ def getRegTest(): Assertion = {
+ test("Box.getReg", env, customExt,
+ """{
+ | val idx = getVar[Int](1).get
+ | val x = SELF
+ | x.getReg[Long](idx).get == SELF.value &&
+ | x.getReg[Coll[(Coll[Byte], Long)]](2).get == SELF.tokens &&
+ | x.getReg[Int](9).isEmpty
+ |}""".stripMargin,
+ null
+ )
+ }
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ getRegTest()
+ } else {
+ an[sigma.exceptions.ConstraintFailed] should be thrownBy getRegTest()
+ }
+ }
+
+ property("Box.getReg - computable index") {
+ val ext: Seq[VarBinding] = Seq(
+ (intVar1, IntConstant(0))
+ )
+ def getRegTest(): Assertion = {
+ test("Box.getReg", env, ext,
+ """{
+ | val x = SELF.getReg[Long](getVar[Int](1).get).get
+ | x == SELF.value
+ |}""".stripMargin,
+ null
+ )
+ }
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ getRegTest()
+ } else {
+ an[java.nio.BufferUnderflowException] should be thrownBy getRegTest()
+ }
+ }
+
+ property("Unit register") {
+ // TODO frontend: implement missing Unit support in compiler
+ // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820
+ test("R1", env, ext,
+ script = "", /* means cannot be compiled
+ the corresponding script is { SELF.R4[Unit].isDefined } */
+ ExtractRegisterAs[SUnit.type](Self, reg1)(SUnit).isDefined.toSigmaProp,
+ additionalRegistersOpt = Some(Map(
+ reg1 -> UnitConstant.instance
+ ))
+ )
+
+ test("R2", env, ext,
+ script = "", /* means cannot be compiled
+ the corresponding script is "{ SELF.R4[Unit].get == () }" */
+ EQ(ExtractRegisterAs[SUnit.type](Self, reg1)(SUnit).get, UnitConstant.instance).toSigmaProp,
+ additionalRegistersOpt = Some(Map(
+ reg1 -> UnitConstant.instance
+ ))
+ )
+ }
+
}
diff --git a/sc/shared/src/test/scala/sigmastate/utxo/UsingContextPropertiesSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/UsingContextPropertiesSpecification.scala
index e3d43ab868..77e78aa6bf 100644
--- a/sc/shared/src/test/scala/sigmastate/utxo/UsingContextPropertiesSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/utxo/UsingContextPropertiesSpecification.scala
@@ -1,19 +1,19 @@
package sigmastate.utxo
import sigmastate.CompilerCrossVersionProps
-import sigmastate.eval.IRContext
import sigma.Extensions.ArrayOps
import sigma.Context
import sigmastate.helpers.CompilerTestingCommons
import org.ergoplatform.dsl.{ContractSpec, SigmaContractSyntax, TestContractSpec}
import org.ergoplatform.ErgoBox
import scorex.crypto.hash.Blake2b256
+import sigma.compiler.ir.IRContext
import sigma.data.{CSigmaProp, TrivialProp}
class UsingContextPropertiesSpecification extends CompilerTestingCommons
with CompilerCrossVersionProps { suite =>
lazy val spec = TestContractSpec(suite)(new TestingIRContext)
- lazy val prover = spec.ProvingParty("Alice")
+ lazy val prover = spec.ProvingParty("Alice")
private implicit lazy val IR: IRContext = spec.IR
private val reg1 = ErgoBox.nonMandatoryRegisters(0)
diff --git a/sc/shared/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationTestingCommons.scala b/sc/shared/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationTestingCommons.scala
index 0dca8a4471..16b4e3e232 100644
--- a/sc/shared/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationTestingCommons.scala
+++ b/sc/shared/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationTestingCommons.scala
@@ -17,6 +17,7 @@ import scorex.util._
import sigma.Colls
import sigma.data.{AvlTreeData, AvlTreeFlags}
import ErgoTree.ZeroHeader
+import sigma.compiler.ir.IRContext
import sigma.eval.Extensions.SigmaBooleanOps
import sigma.interpreter.ContextExtension
import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
diff --git a/sc/shared/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala b/sc/shared/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala
index 969439fe59..5e89915384 100644
--- a/sc/shared/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala
+++ b/sc/shared/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala
@@ -68,11 +68,9 @@ case class AssetsPartialFilling[Spec <: ContractSpec]
val out = OUTPUTS(outIdx)
val tokenData = out.R2[Coll[(Coll[Byte], Long)]].get(0)
- val tokenId = tokenData._1
val tokenValue = tokenData._2
val selfTokenData = SELF.R2[Coll[(Coll[Byte], Long)]].get(0)
- val selfTokenId = selfTokenData._1
val selfTokenValue = selfTokenData._2
val selfValue = SELF.value
diff --git a/sc/shared/src/test/scala/sigmastate/utxo/examples/IcoExample.scala b/sc/shared/src/test/scala/sigmastate/utxo/examples/IcoExample.scala
index c930135bc2..556c56bc03 100644
--- a/sc/shared/src/test/scala/sigmastate/utxo/examples/IcoExample.scala
+++ b/sc/shared/src/test/scala/sigmastate/utxo/examples/IcoExample.scala
@@ -22,6 +22,7 @@ import sigmastate.helpers.{CompilerTestingCommons, ContextEnrichingTestProvingIn
import sigmastate.interpreter.Interpreter.ScriptNameProp
import sigmastate.interpreter.Interpreter
import sigma.ast.syntax._
+import sigma.compiler.ir.IRContext
import sigma.eval.SigmaDsl
import sigma.serialization.ErgoTreeSerializer
import sigma.serialization.ErgoTreeSerializer.DefaultSerializer
diff --git a/sc/shared/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala
index ce4ed2114e..556fbf9c06 100644
--- a/sc/shared/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala
@@ -10,12 +10,12 @@ import sigma.data.{AvlTreeData, AvlTreeFlags, Digest32Coll, TrivialProp}
import sigmastate.CompilerCrossVersionProps
import sigma.ast.{AvlTreeConstant, ByteArrayConstant, LongConstant, SigmaPropConstant}
import sigma.Extensions.ArrayOps
-import sigmastate.eval.IRContext
import sigmastate.helpers.{CompilerTestingCommons, ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestProvingInterpreter}
import sigmastate.helpers.TestingHelpers._
import sigmastate.interpreter.Interpreter.ScriptNameProp
import sigma.serialization.ErgoTreeSerializer
import sigma.ast.syntax._
+import sigma.compiler.ir.IRContext
import sigma.eval.SigmaDsl
import scala.util.Random
diff --git a/sc/shared/src/test/scala/special/wrappers/WOptionTests.scala b/sc/shared/src/test/scala/special/wrappers/WOptionTests.scala
index 7e046739f0..e952ba7c00 100644
--- a/sc/shared/src/test/scala/special/wrappers/WOptionTests.scala
+++ b/sc/shared/src/test/scala/special/wrappers/WOptionTests.scala
@@ -1,7 +1,6 @@
package special.wrappers
import scala.language.reflectiveCalls
-import scalan.Library
class WOptionTests extends WrappersTests {
diff --git a/sc/shared/src/test/scala/special/wrappers/WSpecialPredefTests.scala b/sc/shared/src/test/scala/special/wrappers/WSpecialPredefTests.scala
deleted file mode 100644
index e1097ebf6c..0000000000
--- a/sc/shared/src/test/scala/special/wrappers/WSpecialPredefTests.scala
+++ /dev/null
@@ -1,24 +0,0 @@
-package special.wrappers
-
-
-import scala.language.reflectiveCalls
-import sigma.data.RType
-
-class WSpecialPredefTests extends WrappersTests {
-
- lazy val ctx = new WrappersCtx
- import ctx._
- import WSpecialPredef._
-
- lazy val SPCM = WSpecialPredefCompanionMethods
-
- test("some") {
- val x: Ref[Int] = 10
- val opt = RWSpecialPredef.some(x)
- opt match {
- case SPCM.some(_x) => _x shouldBe x
- case _ => assert(false)
- }
- }
-
-}
diff --git a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Header.scala b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Header.scala
index ef53e13dbd..2220c9827a 100644
--- a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Header.scala
+++ b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Header.scala
@@ -12,7 +12,7 @@ import scala.scalajs.js.annotation.JSExportTopLevel
class Header(
/** Hex representation of ModifierId of this Header */
val id: String,
- /** Block version, to be increased on every soft and hardfork. */
+ /** Block version, to be increased on every soft- or hard-fork. */
val version: Byte,
/** Hex representation of ModifierId of the parent block */
val parentId: String,
@@ -48,5 +48,7 @@ class Header(
val powDistance: js.BigInt,
/** Miner votes for changing system parameters. */
- val votes: String
+ val votes: String,
+
+ val unparsedBytes: String
) extends js.Object
diff --git a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Isos.scala b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Isos.scala
index f6393f62bb..84f2b21da8 100644
--- a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Isos.scala
+++ b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Isos.scala
@@ -1,93 +1,48 @@
package org.ergoplatform.sdk.js
-import org.ergoplatform.ErgoBox._
import org.ergoplatform._
import org.ergoplatform.sdk.ExtendedInputBox
-import org.ergoplatform.sdk.JavaHelpers.UniversalConverter
import org.ergoplatform.sdk.wallet.protocol.context
-import scorex.crypto.authds.ADKey
-import scorex.util.ModifierId
-import scorex.util.encode.Base16
-import sigma.Extensions.CollBytesOps
-import sigma.ast.syntax.GroupElementConstant
-import sigma.ast.{Constant, GroupElementConstant, SType}
+import sigma.ast.{Constant, SType}
+import sigma.data.Iso
import sigma.data.Iso.{isoStringToArray, isoStringToColl}
-import sigma.data.{CBigInt, CGroupElement, Digest32Coll, Digest32CollRType, Iso}
+import sigma.data.js.{Isos => DataIsos}
+import sigma.data.CHeader
import sigma.interpreter.{ContextExtension, ProverResult}
-import sigma.js.{AvlTree, GroupElement}
-import sigma.serialization.{ErgoTreeSerializer, ValueSerializer}
-import sigma.{Coll, Colls}
-import sigmastate.eval.{CHeader, CPreHeader}
+import sigma.js.AvlTree
+import sigmastate.eval.CPreHeader
import sigmastate.fleetSdkCommon.distEsmTypesBoxesMod.Box
-import sigmastate.fleetSdkCommon.distEsmTypesCommonMod.HexString
import sigmastate.fleetSdkCommon.distEsmTypesRegistersMod.NonMandatoryRegisters
import sigmastate.fleetSdkCommon.distEsmTypesTokenMod.TokenAmount
import sigmastate.fleetSdkCommon.distEsmTypesTransactionsMod.{SignedTransaction, UnsignedTransaction}
-import sigmastate.fleetSdkCommon.{distEsmTypesBoxesMod => boxesMod, distEsmTypesCommonMod => commonMod, distEsmTypesContextExtensionMod => contextExtensionMod, distEsmTypesInputsMod => inputsMod, distEsmTypesProverResultMod => proverResultMod, distEsmTypesRegistersMod => registersMod, distEsmTypesTokenMod => tokenMod}
+import sigmastate.fleetSdkCommon.{distEsmTypesCommonMod => commonMod, distEsmTypesContextExtensionMod => contextExtensionMod, distEsmTypesInputsMod => inputsMod, distEsmTypesProverResultMod => proverResultMod}
-import java.math.BigInteger
import scala.collection.immutable.ListMap
import scala.scalajs.js
import scala.scalajs.js.Object
-/** Definitions of isomorphisms. */
+/** Definitions of isomorphisms for sigma-sdk module.
+ * @see sigma.data.Iso
+ */
object Isos {
- val isoStringToGroupElement: Iso[String, sigma.GroupElement] = new Iso[String, sigma.GroupElement] {
- override def to(x: String): sigma.GroupElement = {
- val bytes = Base16.decode(x).get
- ValueSerializer.deserialize(bytes).asInstanceOf[GroupElementConstant].value
- }
- override def from(x: sigma.GroupElement): String = {
- val bytes = ValueSerializer.serialize(GroupElementConstant(x))
- Base16.encode(bytes)
- }
- }
-
- val isoGroupElement: Iso[GroupElement, sigma.GroupElement] = new Iso[GroupElement, sigma.GroupElement] {
- override def to(x: GroupElement): sigma.GroupElement = {
- CGroupElement(x.point)
- }
- override def from(x: sigma.GroupElement): GroupElement = {
- new GroupElement(x.asInstanceOf[CGroupElement].wrappedValue)
- }
- }
-
- implicit val isoBoxId: Iso[boxesMod.BoxId, ErgoBox.BoxId] = new Iso[boxesMod.BoxId, ErgoBox.BoxId] {
- override def to(x: boxesMod.BoxId): ErgoBox.BoxId = ADKey @@@ isoStringToArray.to(x)
-
- override def from(x: ErgoBox.BoxId): boxesMod.BoxId = isoStringToArray.from(x)
- }
-
- implicit val isoHexStringToConstant: Iso[HexString, Constant[SType]] = new Iso[HexString, Constant[SType]] {
- override def to(x: HexString): Constant[SType] = {
- val bytes = isoStringToArray.to(x)
- val value = ValueSerializer.deserialize(bytes)
- value.asInstanceOf[Constant[SType]]
- }
- override def from(x: Constant[SType]): HexString = {
- val bytes = ValueSerializer.serialize(x)
- isoStringToArray.from(bytes)
- }
- }
-
implicit val isoHeader: Iso[Header, sigma.Header] = new Iso[Header, sigma.Header] {
override def to(a: Header): sigma.Header = {
CHeader(
- id = isoStringToColl.to(a.id),
version = a.version,
parentId = isoStringToColl.to(a.parentId),
ADProofsRoot = isoStringToColl.to(a.ADProofsRoot),
- stateRoot = AvlTree.isoAvlTree.to(a.stateRoot),
+ stateRootDigest = AvlTree.isoAvlTree.to(a.stateRoot).digest,
transactionsRoot = isoStringToColl.to(a.transactionsRoot),
timestamp = sigma.js.Isos.isoBigIntToLong.to(a.timestamp),
nBits = sigma.js.Isos.isoBigIntToLong.to(a.nBits),
height = a.height,
extensionRoot = isoStringToColl.to(a.extensionRoot),
- minerPk = isoGroupElement.to(a.minerPk),
- powOnetimePk = isoGroupElement.to(a.powOnetimePk),
+ minerPk = DataIsos.isoGroupElement.to(a.minerPk),
+ powOnetimePk = DataIsos.isoGroupElement.to(a.powOnetimePk),
powNonce = isoStringToColl.to(a.powNonce),
powDistance = sigma.js.Isos.isoBigInt.to(a.powDistance),
- votes = isoStringToColl.to(a.votes)
+ votes = isoStringToColl.to(a.votes),
+ unparsedBytes = isoStringToColl.to(a.unparsedBytes)
)
}
override def from(b: sigma.Header): Header = {
@@ -103,11 +58,12 @@ object Isos {
nBits = sigma.js.Isos.isoBigIntToLong.from(header.nBits),
height = header.height,
extensionRoot = isoStringToColl.from(header.extensionRoot),
- minerPk = isoGroupElement.from(header.minerPk),
- powOnetimePk = isoGroupElement.from(header.powOnetimePk),
+ minerPk = DataIsos.isoGroupElement.from(header.minerPk),
+ powOnetimePk = DataIsos.isoGroupElement.from(header.powOnetimePk),
powNonce = isoStringToColl.from(header.powNonce),
powDistance = sigma.js.Isos.isoBigInt.from(header.powDistance),
- votes = isoStringToColl.from(header.votes)
+ votes = isoStringToColl.from(header.votes),
+ unparsedBytes = isoStringToColl.from(header.unparsedBytes)
)
}
}
@@ -120,7 +76,7 @@ object Isos {
timestamp = sigma.js.Isos.isoBigIntToLong.to(a.timestamp),
nBits = sigma.js.Isos.isoBigIntToLong.to(a.nBits),
height = a.height,
- minerPk = isoGroupElement.to(a.minerPk),
+ minerPk = DataIsos.isoGroupElement.to(a.minerPk),
votes = isoStringToColl.to(a.votes)
)
}
@@ -132,7 +88,7 @@ object Isos {
timestamp = sigma.js.Isos.isoBigIntToLong.from(header.timestamp),
nBits = sigma.js.Isos.isoBigIntToLong.from(header.nBits),
height = header.height,
- minerPk = isoGroupElement.from(header.minerPk),
+ minerPk = DataIsos.isoGroupElement.from(header.minerPk),
votes = isoStringToColl.from(header.votes)
)
}
@@ -195,7 +151,7 @@ object Isos {
val keys = js.Object.keys(x).sorted
for ( k <- keys ) {
val id = k.toInt.toByte
- val c = isoHexStringToConstant.to(x.apply(id).get.get)
+ val c = DataIsos.isoHexStringToConstant.to(x.apply(id).get.get)
map = map + (id -> c)
}
ContextExtension(map)
@@ -204,7 +160,7 @@ object Isos {
override def from(x: ContextExtension): contextExtensionMod.ContextExtension = {
val res = new Object().asInstanceOf[contextExtensionMod.ContextExtension]
x.values.foreach { case (k, v: Constant[_]) =>
- val hex = isoHexStringToConstant.from(v)
+ val hex = DataIsos.isoHexStringToConstant.from(v)
res.update(k, hex)
}
res
@@ -213,10 +169,10 @@ object Isos {
implicit val isoUnsignedInput: Iso[inputsMod.UnsignedInput, UnsignedInput] = new Iso[inputsMod.UnsignedInput, UnsignedInput] {
override def to(x: inputsMod.UnsignedInput): UnsignedInput =
- new UnsignedInput(x.boxId.convertTo[ErgoBox.BoxId], isoContextExtension.to(x.extension))
+ new UnsignedInput(DataIsos.isoBoxId.to(x.boxId), isoContextExtension.to(x.extension))
override def from(x: UnsignedInput): inputsMod.UnsignedInput =
- inputsMod.UnsignedInput(x.boxId.convertTo[boxesMod.BoxId], isoContextExtension.from(x.extension))
+ inputsMod.UnsignedInput(DataIsos.isoBoxId.from(x.boxId), isoContextExtension.from(x.extension))
}
implicit val isoProverResult: Iso[proverResultMod.ProverResult, ProverResult] = new Iso[proverResultMod.ProverResult, ProverResult] {
@@ -236,135 +192,17 @@ object Isos {
implicit val isoSignedInput: Iso[inputsMod.SignedInput, Input] = new Iso[inputsMod.SignedInput, Input] {
override def to(x: inputsMod.SignedInput): Input =
- Input(x.boxId.convertTo[ErgoBox.BoxId], isoProverResult.to(x.spendingProof))
+ Input(DataIsos.isoBoxId.to(x.boxId), isoProverResult.to(x.spendingProof))
override def from(x: Input): inputsMod.SignedInput =
- inputsMod.SignedInput(x.boxId.convertTo[boxesMod.BoxId], isoProverResult.from(x.spendingProof))
+ inputsMod.SignedInput(DataIsos.isoBoxId.from(x.boxId), isoProverResult.from(x.spendingProof))
}
implicit val isoDataInput: Iso[inputsMod.DataInput, DataInput] = new Iso[inputsMod.DataInput, DataInput] {
- override def to(x: inputsMod.DataInput): DataInput = DataInput(x.boxId.convertTo[ErgoBox.BoxId])
-
- override def from(x: DataInput): inputsMod.DataInput = inputsMod.DataInput(x.boxId.convertTo[boxesMod.BoxId])
- }
-
- implicit val isoAmount: Iso[commonMod.Amount, Long] = new Iso[commonMod.Amount, Long] {
- override def to(x: commonMod.Amount): Long = x.asInstanceOf[Any] match {
- case s: String => BigInt(s).toLong
- case _ => java.lang.Long.parseLong(x.asInstanceOf[js.BigInt].toString(10))
- }
- override def from(x: Long): commonMod.Amount = x.toString
- }
-
- implicit val isoToken: Iso[tokenMod.TokenAmount[commonMod.Amount], Token] =
- new Iso[tokenMod.TokenAmount[commonMod.Amount], Token] {
- override def to(x: tokenMod.TokenAmount[commonMod.Amount]): Token =
- (Digest32Coll @@@ Colls.fromArray(Base16.decode(x.tokenId).get), isoAmount.to(x.amount))
+ override def to(x: inputsMod.DataInput): DataInput =
+ DataInput(DataIsos.isoBoxId.to(x.boxId))
- override def from(x: Token): tokenMod.TokenAmount[commonMod.Amount] =
- tokenMod.TokenAmount[commonMod.Amount](isoAmount.from(x._2), x._1.toHex)
- }
-
- val isoTokenArray: Iso[js.Array[tokenMod.TokenAmount[commonMod.Amount]], Coll[Token]] =
- new Iso[js.Array[tokenMod.TokenAmount[commonMod.Amount]], Coll[Token]] {
- override def to(x: js.Array[tokenMod.TokenAmount[commonMod.Amount]]): Coll[Token] = {
- sigma.js.Isos.isoArrayToColl(isoToken).to(x)
- }
- override def from(x: Coll[Token]): js.Array[tokenMod.TokenAmount[commonMod.Amount]] = {
- sigma.js.Isos.isoArrayToColl(isoToken).from(x)
- }
- }
-
- val isoNonMandatoryRegisters: Iso[registersMod.NonMandatoryRegisters, AdditionalRegisters] =
- new Iso[registersMod.NonMandatoryRegisters, AdditionalRegisters] {
- override def to(x: registersMod.NonMandatoryRegisters): AdditionalRegisters = {
- val regs = Seq(
- x.R4 -> R4,
- x.R5 -> R5,
- x.R6 -> R6,
- x.R7 -> R7,
- x.R8 -> R8,
- x.R9 -> R9
- ).collect {
- case (regOpt, id) if regOpt.isDefined => id -> isoHexStringToConstant.to(regOpt.get)
- }
- Map(regs:_*)
- }
- override def from(regs: AdditionalRegisters): registersMod.NonMandatoryRegisters = {
- def regHexOpt(t: NonMandatoryRegisterId): Option[HexString] =
- regs.get(t).map(v => isoHexStringToConstant.from(v.asInstanceOf[Constant[SType]]))
-
- val resRegs = NonMandatoryRegisters()
- regHexOpt(R4).foreach(resRegs.setR4(_))
- regHexOpt(R5).foreach(resRegs.setR5(_))
- regHexOpt(R6).foreach(resRegs.setR6(_))
- regHexOpt(R7).foreach(resRegs.setR7(_))
- regHexOpt(R8).foreach(resRegs.setR8(_))
- regHexOpt(R9).foreach(resRegs.setR9(_))
- resRegs
- }
- }
-
- implicit val isoBoxCandidate: Iso[boxesMod.BoxCandidate[commonMod.Amount, NonMandatoryRegisters], ErgoBoxCandidate] = new Iso[boxesMod.BoxCandidate[commonMod.Amount, NonMandatoryRegisters], ErgoBoxCandidate] {
- override def to(x: boxesMod.BoxCandidate[commonMod.Amount, NonMandatoryRegisters]): ErgoBoxCandidate = {
- val ergoBoxCandidate = new ErgoBoxCandidate(
- value = isoAmount.to(x.value),
- ergoTree = {
- val bytes = Base16.decode(x.ergoTree).get
- ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes)
- },
- x.creationHeight.toInt,
- additionalTokens = isoTokenArray.to(x.assets),
- additionalRegisters = isoNonMandatoryRegisters.to(x.additionalRegisters)
- )
- ergoBoxCandidate
- }
-
- override def from(x: ErgoBoxCandidate): boxesMod.BoxCandidate[commonMod.Amount, NonMandatoryRegisters] = {
- val ergoTree = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(x.ergoTree)
- val ergoTreeStr = Base16.encode(ergoTree)
- val assets = isoTokenArray.from(x.additionalTokens)
- boxesMod.BoxCandidate[commonMod.Amount, NonMandatoryRegisters](
- ergoTree = ergoTreeStr,
- value = isoAmount.from(x.value),
- assets = assets,
- creationHeight = x.creationHeight,
- additionalRegisters = isoNonMandatoryRegisters.from(x.additionalRegisters)
- )
- }
- }
-
- val isoBox: Iso[Box[commonMod.Amount, NonMandatoryRegisters], ErgoBox] = new Iso[Box[commonMod.Amount, NonMandatoryRegisters], ErgoBox] {
- override def to(x: Box[commonMod.Amount, NonMandatoryRegisters]): ErgoBox = {
- val ergoBox = new ErgoBox(
- value = isoAmount.to(x.value),
- ergoTree = {
- val bytes = Base16.decode(x.ergoTree).get
- ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes)
- },
- creationHeight = x.creationHeight.toInt,
- additionalTokens = isoTokenArray.to(x.assets),
- additionalRegisters = isoNonMandatoryRegisters.to(x.additionalRegisters),
- transactionId = ModifierId @@ x.transactionId,
- index = x.index.toShort
- )
- ergoBox
- }
-
- override def from(x: ErgoBox): Box[commonMod.Amount, NonMandatoryRegisters] = {
- val ergoTree = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(x.ergoTree)
- val ergoTreeStr = Base16.encode(ergoTree)
- val assets = isoTokenArray.from(x.additionalTokens)
- Box[commonMod.Amount, NonMandatoryRegisters](
- boxId = Base16.encode(x.id),
- ergoTree = ergoTreeStr,
- value = isoAmount.from(x.value),
- assets = assets,
- creationHeight = x.creationHeight,
- additionalRegisters = isoNonMandatoryRegisters.from(x.additionalRegisters),
- transactionId = x.transactionId,
- index = x.index
- )
- }
+ override def from(x: DataInput): inputsMod.DataInput =
+ inputsMod.DataInput(DataIsos.isoBoxId.from(x.boxId))
}
val isoEIP12UnsignedInput: Iso[inputsMod.EIP12UnsignedInput, ExtendedInputBox] =
@@ -380,12 +218,12 @@ object Isos {
transactionId = x.transactionId,
index = x.index
)
- val ergoBox = isoBox.to(box)
+ val ergoBox = sigma.js.Box.isoBox.to(box)
val extendedInputBox = ExtendedInputBox(ergoBox, isoContextExtension.to(x.extension))
extendedInputBox
}
override def from(x: ExtendedInputBox): inputsMod.EIP12UnsignedInput = {
- val box = isoBox.from(x.box)
+ val box = sigma.js.Box.isoBox.from(x.box)
val ext = isoContextExtension.from(x.extension)
inputsMod.EIP12UnsignedInput(
boxId = box.boxId,
@@ -407,7 +245,7 @@ object Isos {
new UnsignedErgoLikeTransaction(
inputs = sigma.js.Isos.isoArrayToIndexed(isoUnsignedInput).to(a.inputs),
dataInputs = sigma.js.Isos.isoArrayToIndexed(isoDataInput).to(a.dataInputs),
- outputCandidates = sigma.js.Isos.isoArrayToIndexed(isoBoxCandidate).to(a.outputs),
+ outputCandidates = sigma.js.Isos.isoArrayToIndexed(DataIsos.isoBoxCandidate).to(a.outputs),
)
}
@@ -415,7 +253,7 @@ object Isos {
UnsignedTransaction(
inputs = sigma.js.Isos.isoArrayToIndexed(isoUnsignedInput).from(b.inputs),
dataInputs = sigma.js.Isos.isoArrayToIndexed(isoDataInput).from(b.dataInputs),
- outputs = sigma.js.Isos.isoArrayToIndexed(isoBoxCandidate).from(b.outputCandidates)
+ outputs = sigma.js.Isos.isoArrayToIndexed(DataIsos.isoBoxCandidate).from(b.outputCandidates)
)
}
}
@@ -426,14 +264,14 @@ object Isos {
new ErgoLikeTransaction(
inputs = sigma.js.Isos.isoArrayToIndexed(isoSignedInput).to(a.inputs),
dataInputs = sigma.js.Isos.isoArrayToIndexed(isoDataInput).to(a.dataInputs),
- outputCandidates = sigma.js.Isos.isoArrayToIndexed(isoBox).to(a.outputs),
+ outputCandidates = sigma.js.Isos.isoArrayToIndexed(sigma.js.Box.isoBox).to(a.outputs),
)
}
override def from(tx: ErgoLikeTransaction): SignedTransaction = {
val inputs = sigma.js.Isos.isoArrayToIndexed(isoSignedInput).from(tx.inputs)
val dataInputs = sigma.js.Isos.isoArrayToIndexed(isoDataInput).from(tx.dataInputs)
- val outputs = sigma.js.Isos.isoArrayToIndexed(isoBox).from(tx.outputs)
+ val outputs = sigma.js.Isos.isoArrayToIndexed(sigma.js.Box.isoBox).from(tx.outputs)
SignedTransaction(dataInputs, tx.id, inputs, outputs)
}
}
diff --git a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/ProverBuilder.scala b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/ProverBuilder.scala
index 12ecf1d03f..7ab95c187e 100644
--- a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/ProverBuilder.scala
+++ b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/ProverBuilder.scala
@@ -6,6 +6,7 @@ import org.ergoplatform.sdk.SecretString
import scala.scalajs.js
import scala.scalajs.js.annotation.JSExportTopLevel
import Isos._
+import sigma.data.js.{Isos => DataIsos}
import sigma.eval.SigmaDsl
/** Equivalent of [[sdk.ProverBuilder]] available from JS.
@@ -66,10 +67,10 @@ class ProverBuilder(parameters: BlockchainParameters, network: Byte) extends js.
*/
def withDHTSecret(g: String, h: String, u: String, v: String, x: js.BigInt): ProverBuilder = {
_builder.withDHTData(
- isoStringToGroupElement.to(g),
- isoStringToGroupElement.to(h),
- isoStringToGroupElement.to(u),
- isoStringToGroupElement.to(v),
+ DataIsos.isoStringToGroupElement.to(g),
+ DataIsos.isoStringToGroupElement.to(h),
+ DataIsos.isoStringToGroupElement.to(u),
+ DataIsos.isoStringToGroupElement.to(v),
SigmaDsl.toBigInteger(sigma.js.Isos.isoBigInt.to(x))
)
this
diff --git a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/SigmaProver.scala b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/SigmaProver.scala
index 0a6aca4830..693c0717bb 100644
--- a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/SigmaProver.scala
+++ b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/SigmaProver.scala
@@ -51,8 +51,8 @@ class SigmaProver(_prover: sdk.SigmaProver) extends js.Object {
val unreducedTx = sdk.UnreducedTransaction(
unsignedTx = isoUnsignedTransaction.to(unsignedTx),
boxesToSpend = sigma.js.Isos.isoArrayToIndexed(isoEIP12UnsignedInput).to(boxesToSpend),
- dataInputs = sigma.js.Isos.isoArrayToIndexed(isoBox).to(dataInputs),
- tokensToBurn = sigma.js.Isos.isoArrayToIndexed(isoToken.andThen(sdk.SdkIsos.isoErgoTokenToPair.inverse)).to(tokensToBurn)
+ dataInputs = sigma.js.Isos.isoArrayToIndexed(sigma.js.Box.isoBox).to(dataInputs),
+ tokensToBurn = sigma.js.Isos.isoArrayToIndexed(sigma.data.js.Isos.isoToken.andThen(sdk.SdkIsos.isoErgoTokenToPair.inverse)).to(tokensToBurn)
)
val ctx = isoBlockchainStateContext.to(stateCtx)
val reducedTx = _prover.reduce(ctx, unreducedTx, baseCost)
diff --git a/sdk/js/src/test/scala/org/ergoplatform/sdk/js/IsosSpec.scala b/sdk/js/src/test/scala/org/ergoplatform/sdk/js/IsosSpec.scala
index a366e33d3c..31b8a84c2b 100644
--- a/sdk/js/src/test/scala/org/ergoplatform/sdk/js/IsosSpec.scala
+++ b/sdk/js/src/test/scala/org/ergoplatform/sdk/js/IsosSpec.scala
@@ -1,8 +1,9 @@
package org.ergoplatform.sdk.js
+import io.circe.parser.parse
import org.ergoplatform.ErgoBox.{AdditionalRegisters, BoxId, TokenId}
import org.ergoplatform._
-import org.ergoplatform.sdk.ExtendedInputBox
+import org.ergoplatform.sdk.{ExtendedInputBox, JsonCodecs}
import org.ergoplatform.sdk.wallet.protocol.context.BlockchainStateContext
import org.scalacheck.Arbitrary
import sigma.ast.{Constant, SType}
@@ -10,6 +11,7 @@ import sigma.data.Iso
import sigma.interpreter.{ContextExtension, ProverResult}
import sigma.js.AvlTree
import sigma.{Coll, GroupElement}
+import sigma.data.js.{Isos => DataIsos}
import scala.scalajs.js
@@ -31,19 +33,19 @@ class IsosSpec extends IsosSpecBase with sdk.generators.ObjectGenerators {
property("Iso.isoStringToGroupElement") {
forAll() { (bytes: GroupElement) =>
- roundtrip(Isos.isoStringToGroupElement)(bytes)
+ roundtrip(DataIsos.isoStringToGroupElement)(bytes)
}
}
property("Iso.isoBoxId") {
forAll(boxIdGen) { (id: BoxId) =>
- roundtrip(Isos.isoBoxId)(id)
+ roundtrip(DataIsos.isoBoxId)(id)
}
}
property("Iso.isoHexStringToConstant") {
forAll(constantGen, MinSuccessful(100)) { (c: Constant[SType]) =>
- roundtrip(Isos.isoHexStringToConstant)(c)
+ roundtrip(DataIsos.isoHexStringToConstant)(c)
}
}
@@ -115,20 +117,20 @@ class IsosSpec extends IsosSpecBase with sdk.generators.ObjectGenerators {
property("Iso.isoAmount") {
forAll { (c: Long) =>
- roundtrip(Isos.isoAmount)(c)
- Isos.isoAmount.to(js.BigInt(c.toString)) shouldBe c
+ roundtrip(DataIsos.isoAmount)(c)
+ DataIsos.isoAmount.to(js.BigInt(c.toString)) shouldBe c
}
}
property("Iso.isoToken") {
forAll(tokenIdGen, Arbitrary.arbLong.arbitrary) { (id: TokenId, amount: Long) =>
- roundtrip(Isos.isoToken)((id, amount))
+ roundtrip(DataIsos.isoToken)((id, amount))
}
}
property("Iso.isoTokenArray") {
forAll(ergoBoxTokens(tokensGen.sample.get)) { tokens =>
- roundtrip(Isos.isoTokenArray)(tokens)
+ roundtrip(DataIsos.isoTokenArray)(tokens)
}
}
@@ -140,19 +142,19 @@ class IsosSpec extends IsosSpecBase with sdk.generators.ObjectGenerators {
property("Iso.isoNonMandatoryRegisters") {
forAll(additionalRegistersGen) { (x: AdditionalRegisters) =>
- roundtrip(Isos.isoNonMandatoryRegisters)(x)
+ roundtrip(DataIsos.isoNonMandatoryRegisters)(x)
}
}
property("Iso.isoBoxCandidate") {
forAll { (box: ErgoBoxCandidate) =>
- roundtrip(Isos.isoBoxCandidate)(box)
+ roundtrip(DataIsos.isoBoxCandidate)(box)
}
}
property("Iso.isoBox") {
forAll { (b: ErgoBox) =>
- roundtrip(Isos.isoBox)(b)
+ roundtrip(sigma.js.Box.isoBox)(b)
}
}
diff --git a/sdk/shared/src/main/scala/org/ergoplatform/sdk/ContractTemplate.scala b/sdk/shared/src/main/scala/org/ergoplatform/sdk/ContractTemplate.scala
index 5e491630bd..8da420bee6 100644
--- a/sdk/shared/src/main/scala/org/ergoplatform/sdk/ContractTemplate.scala
+++ b/sdk/shared/src/main/scala/org/ergoplatform/sdk/ContractTemplate.scala
@@ -153,7 +153,7 @@ case class ContractTemplate(
.map(p => p.name)
requiredParameterNames.foreach(name => require(
paramValues.contains(name),
- s"value for parameter $name was not provided while it does not have a default value."))
+ s"value for parameter `$name` was not provided while it does not have a default value."))
val parameterizedConstantIndices = this.parameters.map(p => p.constantIndex).toSet
val constIndexToParamIndex = this.parameters.zipWithIndex.map(pi => pi._1.constantIndex -> pi._2).toMap
diff --git a/sdk/shared/src/main/scala/org/ergoplatform/sdk/DataJsonEncoder.scala b/sdk/shared/src/main/scala/org/ergoplatform/sdk/DataJsonEncoder.scala
index fc95b77e61..6c0c866baf 100644
--- a/sdk/shared/src/main/scala/org/ergoplatform/sdk/DataJsonEncoder.scala
+++ b/sdk/shared/src/main/scala/org/ergoplatform/sdk/DataJsonEncoder.scala
@@ -122,6 +122,10 @@ object DataJsonEncoder {
val w = SigmaSerializer.startWriter()
DataSerializer.serialize(v, tpe, w)
encodeBytes(w.toBytes)
+ case SHeader =>
+ val w = SigmaSerializer.startWriter()
+ DataSerializer.serialize(v, tpe, w)
+ encodeBytes(w.toBytes)
case SAvlTree =>
val w = SigmaSerializer.startWriter()
DataSerializer.serialize(v, tpe, w)
@@ -203,6 +207,10 @@ object DataJsonEncoder {
val str = decodeBytes(json)
val r = SigmaSerializer.startReader(str)
DataSerializer.deserialize(SSigmaProp, r)
+ case SHeader => // for Sigma < 6.0 , exception will be thrown by DataSerializer
+ val str = decodeBytes(json)
+ val r = SigmaSerializer.startReader(str)
+ DataSerializer.deserialize(SHeader, r)
case SBox =>
val value = decodeData(json.hcursor.downField(s"value").focus.get, SLong)
val tree = ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(decodeBytes(json.hcursor.downField(s"ergoTree").focus.get))
diff --git a/sdk/shared/src/main/scala/org/ergoplatform/sdk/JsonCodecs.scala b/sdk/shared/src/main/scala/org/ergoplatform/sdk/JsonCodecs.scala
index ae14fd831a..98e8011bcc 100644
--- a/sdk/shared/src/main/scala/org/ergoplatform/sdk/JsonCodecs.scala
+++ b/sdk/shared/src/main/scala/org/ergoplatform/sdk/JsonCodecs.scala
@@ -12,7 +12,7 @@ import scorex.crypto.hash.Digest32
import scorex.util.ModifierId
import sigma.Extensions.ArrayOps
import sigma.ast.{ErgoTree, EvaluatedValue, SType}
-import sigma.data.{AvlTreeData, AvlTreeFlags, CBigInt, Digest32Coll, WrapperOf}
+import sigma.data.{AvlTreeData, AvlTreeFlags, CBigInt, CHeader, Digest32Coll, WrapperOf}
import sigma.eval.Extensions.EvalIterableOps
import sigma.eval.SigmaDsl
import sigma.interpreter.{ContextExtension, ProverResult}
@@ -125,13 +125,18 @@ trait JsonCodecs {
"powOnetimePk" -> h.powOnetimePk.getEncoded.asJson,
"powNonce" -> h.powNonce.asJson,
"powDistance" -> h.powDistance.asJson,
- "votes" -> h.votes.asJson
+ "votes" -> h.votes.asJson,
+ "unparsedBytes" -> h.unparsedBytes.asJson
).asJson
})
+ /**
+ * JSON decoder for Header instance. Field "unparsedBytes" is optional for now, to preserve compatibility
+ * with clients using older JSON decoders (before node 5.0.23). Better to add an (empty) field anyway if possible.
+ * This field could become mandatory in future.
+ */
implicit val headerDecoder: Decoder[Header] = Decoder.instance({ cursor =>
for {
- id <- cursor.downField("id").as[Coll[Byte]]
version <- cursor.downField("version").as[Byte]
parentId <- cursor.downField("parentId").as[Coll[Byte]]
adProofsRoot <- cursor.downField("adProofsRoot").as[Coll[Byte]]
@@ -146,8 +151,10 @@ trait JsonCodecs {
powNonce <- cursor.downField("powNonce").as[Coll[Byte]]
powDistance <- cursor.downField("powDistance").as[sigma.BigInt]
votes <- cursor.downField("votes").as[Coll[Byte]]
- } yield new CHeader(id, version, parentId, adProofsRoot, stateRoot, transactionsRoot, timestamp, nBits,
- height, extensionRoot, SigmaDsl.decodePoint(minerPk), SigmaDsl.decodePoint(powOnetimePk), powNonce, powDistance, votes)
+ unparsedBytes <- cursor.downField("unparsedBytes").as[Option[Coll[Byte]]]
+ } yield CHeader(version, parentId, adProofsRoot, stateRoot.digest, transactionsRoot, timestamp, nBits,
+ height, extensionRoot, SigmaDsl.decodePoint(minerPk), SigmaDsl.decodePoint(powOnetimePk), powNonce, powDistance,
+ votes, unparsedBytes.getOrElse(Colls.emptyColl))
})
implicit val preHeaderEncoder: Encoder[PreHeader] = Encoder.instance({ v: PreHeader =>
diff --git a/sdk/shared/src/main/scala/org/ergoplatform/sdk/utils/ErgoTreeUtils.scala b/sdk/shared/src/main/scala/org/ergoplatform/sdk/utils/ErgoTreeUtils.scala
new file mode 100644
index 0000000000..ffa6505377
--- /dev/null
+++ b/sdk/shared/src/main/scala/org/ergoplatform/sdk/utils/ErgoTreeUtils.scala
@@ -0,0 +1,26 @@
+package org.ergoplatform.sdk.utils
+
+import sigma.ast.ErgoTree
+import sigma.ast.ErgoTree.HeaderType
+import sigma.util.Extensions.BooleanOps
+
+/** SDK level utilities and helper methods to work with ErgoTrees. */
+object ErgoTreeUtils {
+ /** Prints description of the bits in the given ErgoTree header. */
+ def explainTreeHeader(header: HeaderType): String = {
+ // convert byte to hex
+ val byteToHex = (b: Byte) => f"Ox${b & 0xff}%02x"
+ val hasSize = ErgoTree.hasSize(header)
+ s"""
+ |Header: ${byteToHex(header)} (${header.toString})
+ |Bit 0: ${header.toByte & 0x01} \\
+ |Bit 1: ${(header.toByte & 0x02) >> 1}\t-- ErgoTree version ${ErgoTree.getVersion(header)}
+ |Bit 2: ${(header.toByte & 0x04) >> 2} /
+ |Bit 3: ${hasSize.toByte} \t-- size of the whole tree is serialized after the header byte
+ |Bit 4: ${ErgoTree.isConstantSegregation(header).toByte} \t-- constant segregation is used for this ErgoTree
+ |Bit 5: ${header.toByte & 0x20} \t-- reserved (should be 0)
+ |Bit 6: ${header.toByte & 0x40} \t-- reserved (should be 0)
+ |Bit 7: ${header.toByte & 0x80} \t-- header contains more than 1 byte (default == 0)
+ |""".stripMargin
+ }
+}
diff --git a/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala b/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala
index c3f7b43af4..5835f399cb 100644
--- a/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala
+++ b/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala
@@ -13,7 +13,7 @@ import sigma.serialization.SerializerException
import sigma.util.Extensions.{BigIntegerOps, EcpOps, SigmaBooleanOps}
import sigma.Extensions.ArrayOps
import sigma.eval.SigmaDsl
-import sigma.{AvlTree, Box, Colls, Evaluation}
+import sigma.{AvlTree, Box, Colls, Evaluation, Header, VersionContext}
import sigma.serialization.SerializationSpecification
import scala.annotation.nowarn
@@ -22,29 +22,48 @@ import scala.reflect.ClassTag
class DataJsonEncoderSpecification extends SerializationSpecification {
object JsonCodecs extends JsonCodecs
- def roundtrip[T <: SType](obj: T#WrappedType, tpe: T) = {
- val json = DataJsonEncoder.encode(obj, tpe)
- val res = DataJsonEncoder.decode(json)
- res shouldBe obj
+ def roundtrip[T <: SType](obj: T#WrappedType, tpe: T, withVersion: Option[Byte] = None) = {
+ def test() = {
+ val json = DataJsonEncoder.encode(obj, tpe)
+ val res = DataJsonEncoder.decode(json)
+ res shouldBe obj
+ }
+
+ withVersion match {
+ case Some(ver) =>
+ VersionContext.withVersions(ver, 0) {
+ test()
+ }
+ case None =>
+ test()
+ }
}
def testCollection[T <: SType](tpe: T) = {
implicit val wWrapped = wrappedTypeGen(tpe)
implicit val tT = Evaluation.stypeToRType(tpe)
implicit val tagT = tT.classTag
+
+ val withVersion = if (tpe == SHeader) {
+ Some(VersionContext.V6SoftForkVersion)
+ } else {
+ None
+ }
+
forAll { xs: Array[T#WrappedType] =>
- roundtrip[SCollection[T]](xs.toColl, SCollection(tpe))
- roundtrip[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe)))
+ roundtrip[SCollection[T]](xs.toColl, SCollection(tpe), withVersion)
+ roundtrip[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe)), withVersion)
val nested = xs.toColl.map(x => Colls.fromItems[T#WrappedType](x, x))
- roundtrip[SCollection[SCollection[T]]](nested, SCollection(SCollection(tpe)))
+ roundtrip[SCollection[SCollection[T]]](nested, SCollection(SCollection(tpe)), withVersion)
roundtrip[SType](
xs.toColl.map { x =>
val arr = Colls.fromItems[T#WrappedType](x, x)
(arr, arr)
}.asWrappedType,
- SCollection(STuple(SCollection(tpe), SCollection(tpe)))
+ SCollection(STuple(SCollection(tpe), SCollection(tpe))),
+ withVersion
)
}
}
@@ -54,11 +73,18 @@ class DataJsonEncoderSpecification extends SerializationSpecification {
val tT = Evaluation.stypeToRType(tpe)
@nowarn implicit val tag : ClassTag[T#WrappedType] = tT.classTag
@nowarn implicit val tAny : RType[Any] = sigma.AnyType
+
+ val withVersion = if (tpe == SHeader) {
+ Some(VersionContext.V6SoftForkVersion)
+ } else {
+ None
+ }
+
forAll { in: (T#WrappedType, T#WrappedType) =>
val (x,y) = (in._1, in._2)
- roundtrip[SType]((x, y).asWrappedType, STuple(tpe, tpe))
- roundtrip[SType](((x, y), (x, y)).asWrappedType, STuple(STuple(tpe, tpe), STuple(tpe, tpe)))
- roundtrip[SType](((x, y), ((x, y), (x, y))).asWrappedType, STuple(STuple(tpe, tpe), STuple(STuple(tpe, tpe), STuple(tpe, tpe))))
+ roundtrip[SType]((x, y).asWrappedType, STuple(tpe, tpe), withVersion)
+ roundtrip[SType](((x, y), (x, y)).asWrappedType, STuple(STuple(tpe, tpe), STuple(tpe, tpe)), withVersion)
+ roundtrip[SType](((x, y), ((x, y), (x, y))).asWrappedType, STuple(STuple(tpe, tpe), STuple(STuple(tpe, tpe), STuple(tpe, tpe))), withVersion)
}
}
@@ -98,6 +124,7 @@ class DataJsonEncoderSpecification extends SerializationSpecification {
forAll { x: AvlTree => roundtrip[SAvlTree.type](x, SAvlTree) }
forAll { x: Array[Byte] => roundtrip[SByteArray](x.toColl, SByteArray) }
forAll { x: Box => roundtrip[SBox.type](x, SBox) }
+ forAll { x: Header => roundtrip[SHeader.type](x, SHeader, Some(VersionContext.V6SoftForkVersion)) }
forAll { x: Option[Byte] => roundtrip[SOption[SByte.type]](x, SOption[SByte.type]) }
testCollection(SOption[SLong.type])
testTuples(SOption[SLong.type])
@@ -187,25 +214,44 @@ class DataJsonEncoderSpecification extends SerializationSpecification {
val tT = Evaluation.stypeToRType(tpe)
@nowarn implicit val tag = tT.classTag
@nowarn implicit val tAny = sigma.AnyType
- forAll { x: T#WrappedType =>
- an[SerializerException] should be thrownBy {
- DataJsonEncoder.encode(TupleColl(x, x, x).asWrappedType, STuple(tpe, tpe, tpe))
- }
- // supported case
- DataJsonEncoder.encode(SigmaDsl.Colls.fromItems(TupleColl(x, x)).asWrappedType, SCollection(STuple(tpe, tpe)))
- // not supported case
- an[SerializerException] should be thrownBy {
- DataJsonEncoder.encode(SigmaDsl.Colls.fromItems(TupleColl(x, x, x)).asWrappedType, SCollection(STuple(tpe, tpe, tpe)))
+ def test() = {
+ forAll { x: T#WrappedType =>
+ an[SerializerException] should be thrownBy {
+ DataJsonEncoder.encode(TupleColl(x, x, x).asWrappedType, STuple(tpe, tpe, tpe))
+ }
+
+ // supported case
+ DataJsonEncoder.encode(SigmaDsl.Colls.fromItems(TupleColl(x, x)).asWrappedType, SCollection(STuple(tpe, tpe)))
+
+ // not supported case
+ an[SerializerException] should be thrownBy {
+ DataJsonEncoder.encode(SigmaDsl.Colls.fromItems(TupleColl(x, x, x)).asWrappedType, SCollection(STuple(tpe, tpe, tpe)))
+ }
}
}
+
+ if (tpe == SHeader) {
+ VersionContext.withVersions(VersionContext.V6SoftForkVersion, 0) {
+ test()
+ }
+ } else {
+ test()
+ }
}
property("AnyValue") {
forAll { t: SPredefType =>
- testAnyValue(t)
- testAnyValue(SOption(t))
+ if (t == SHeader) {
+ VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
+ testAnyValue(t)
+ testAnyValue(SOption(t))
+ }
+ } else {
+ testAnyValue(t)
+ testAnyValue(SOption(t))
+ }
}
}
diff --git a/sdk/shared/src/test/scala/org/ergoplatform/sdk/utils/ErgoTreeUtilsSpec.scala b/sdk/shared/src/test/scala/org/ergoplatform/sdk/utils/ErgoTreeUtilsSpec.scala
new file mode 100644
index 0000000000..8dd20ecf81
--- /dev/null
+++ b/sdk/shared/src/test/scala/org/ergoplatform/sdk/utils/ErgoTreeUtilsSpec.scala
@@ -0,0 +1,23 @@
+package org.ergoplatform.sdk.utils
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.propspec.AnyPropSpec
+import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
+import sigma.ast.ErgoTree.HeaderType
+
+class ErgoTreeUtilsSpec extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers {
+ property("explainTreeHeader") {
+ ErgoTreeUtils.explainTreeHeader(HeaderType @@ 26.toByte) shouldBe
+ """|
+ |Header: Ox1a (26)
+ |Bit 0: 0 \
+ |Bit 1: 1 -- ErgoTree version 2
+ |Bit 2: 0 /
+ |Bit 3: 1 -- size of the whole tree is serialized after the header byte
+ |Bit 4: 1 -- constant segregation is used for this ErgoTree
+ |Bit 5: 0 -- reserved (should be 0)
+ |Bit 6: 0 -- reserved (should be 0)
+ |Bit 7: 0 -- header contains more than 1 byte (default == 0)
+ |""".stripMargin
+ }
+}
diff --git a/sigma-js/README.md b/sigma-js/README.md
index ff867e1cb6..c1f30f3497 100644
--- a/sigma-js/README.md
+++ b/sigma-js/README.md
@@ -46,14 +46,15 @@ with `$` suffix, thus if X is the JS class, then X$ is the JS object, which corr
## The list of modules and their exported classes
- [sigma-core module](../core/js) - contains core classes of Sigma.js library
- [Type](../core/js/src/main/scala/sigma/js/Type.scala)
- - [Value](../core/js/src/main/scala/sigma/js/Value.scala)
- [GroupElement](../core/js/src/main/scala/sigma/js/GroupElement.scala)
- [SigmaProp](../core/js/src/main/scala/sigma/js/SigmaProp.scala)
- [AvlTree](../core/js/src/main/scala/sigma/js/AvlTree.scala)
- [sigma-data module](../data/js) - contains classes for working with ErgoTree, addresses and all related serializers
- all classes from sigma-core module
+ - [Value](../data/js/src/main/scala/sigma/js/Value.scala)
- [ErgoTree](../data/js/src/main/scala/sigma/ast/js/ErgoTree.scala)
+ - [Box](../data/js/src/main/scala/sigma/js/Box.scala)
- [Address](../data/js/src/main/scala/org/ergoplatform/js/Address.scala)
- [Expr](../data/js/src/main/scala/sigma/ast/js/Expr.scala)
diff --git a/sigma-js/package-lock.json b/sigma-js/package-lock.json
index 893a0ee141..c34f802f6e 100644
--- a/sigma-js/package-lock.json
+++ b/sigma-js/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "sigmastate-js",
- "version": "0.3.0",
+ "version": "0.4.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "sigmastate-js",
- "version": "0.3.0",
+ "version": "0.4.0",
"license": "MIT",
"dependencies": {
"@fleet-sdk/common": "0.1.3",
diff --git a/sigma-js/package.json b/sigma-js/package.json
index 77ff920585..f6900571bd 100644
--- a/sigma-js/package.json
+++ b/sigma-js/package.json
@@ -1,6 +1,6 @@
{
"name": "sigmastate-js",
- "version": "0.4.0",
+ "version": "0.4.2",
"description": "Sigma.js library",
"files": [
"dist/",
diff --git a/sigma-js/sigmastate-js.d.ts b/sigma-js/sigmastate-js.d.ts
index b70ca39258..53baa3b026 100644
--- a/sigma-js/sigmastate-js.d.ts
+++ b/sigma-js/sigmastate-js.d.ts
@@ -1,7 +1,7 @@
declare module "sigmastate-js/main" {
import {
Amount,
- Box,
+ Box as FBox,
EIP12UnsignedInput,
NonMandatoryRegisters, SignedTransaction, TokenAmount,
UnsignedTransaction
@@ -173,6 +173,10 @@ declare module "sigmastate-js/main" {
valueLengthOpt: number | undefined;
}
+ export declare class Box {
+ box: FBox;
+ }
+
export declare class PreHeader {
/** Block version, to be increased on every soft and hardfork. */
version: number;
@@ -301,6 +305,8 @@ declare module "sigmastate-js/main" {
static ofSigmaProp(pointHex: string): Value;
+ static ofBox(box: FBox): Value;
+
static pairOf(left: Value, right: Value): Value<[R, L]>;
static collOf(items: T[], elemType: Type): Value;
@@ -498,7 +504,7 @@ declare module "sigmastate-js/main" {
stateCtx: BlockchainStateContext,
unsignedTx: UnsignedTransaction,
boxesToSpend: EIP12UnsignedInput[],
- dataInputs: Box[],
+ dataInputs: FBox[],
tokensToBurn: TokenAmount[],
baseCost: number): ReducedTransaction;
diff --git a/sigma-js/tests/js/Box.spec.js b/sigma-js/tests/js/Box.spec.js
new file mode 100644
index 0000000000..24238013ba
--- /dev/null
+++ b/sigma-js/tests/js/Box.spec.js
@@ -0,0 +1,28 @@
+const {Box$, Value$} = require("sigmastate-js/main");
+
+describe("Box", () => {
+ it("should serialize from/to hex", () => {
+ let boxHex = "63b96000d1968302010100ff83020193040204020100c0843d000401010e32297000800b80f1d56c809a8c6affbed864b87f007f6f007f00ac00018c01c4fdff011088807f0100657f00f9ab0101ff6d6505a4a7b5a2e7a4a4dd3a05feffffffffffffffff01003bd5c630803cfff6c1ff7f7fb980ff136afc011f8080b8b04ad4dbda2d7f4e01"
+ let deserialized = Value$.fromHex(boxHex);
+ let expected = {
+ additionalRegisters: {
+ R4: '0101',
+ R5: '0e32297000800b80f1d56c809a8c6affbed864b87f007f6f007f00ac00018c01c4fdff011088807f0100657f00f9ab0101ff6d65',
+ R6: '05a4a7b5a2e7a4a4dd3a',
+ R7: '05feffffffffffffffff01'
+ },
+ assets: [],
+ boxId: '3a0089be265460e29ca47d26e5b55a6f3e3ffaf5b4aed941410a2437913848ad',
+ creationHeight: 1000000,
+ ergoTree: '00d1968302010100ff83020193040204020100',
+ index: 1,
+ transactionId: '003bd5c630803cfff6c1ff7f7fb980ff136afc011f8080b8b04ad4dbda2d7f4e',
+ value: '12345'
+ }
+ let fleetBox = deserialized.data.box
+ expect(fleetBox).toEqual(expected)
+
+ let newBoxValue = Value$.ofBox(fleetBox)
+ expect(newBoxValue.toHex()).toEqual(boxHex)
+ });
+});
\ No newline at end of file