From 08439025534cfcdb35e5b10792bf615bf14f6ed9 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 2 Apr 2024 22:23:12 +0300 Subject: [PATCH 001/123] DecodeNBitsMethod definition --- .../src/main/scala/sigmastate/types.scala | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/interpreter/shared/src/main/scala/sigmastate/types.scala b/interpreter/shared/src/main/scala/sigmastate/types.scala index 586a06432e..7ba062046a 100644 --- a/interpreter/shared/src/main/scala/sigmastate/types.scala +++ b/interpreter/shared/src/main/scala/sigmastate/types.scala @@ -739,6 +739,7 @@ object SPrimType { /** Marker trait for all numeric types. */ trait SNumericType extends SProduct { import SNumericType._ + protected override def getMethods(): Seq[SMethod] = { super.getMethods() ++ SNumericType.methods.map { m => m.copy(stype = Terms.applySubst(m.stype, Map(tNum -> this)).asFunc) @@ -778,6 +779,7 @@ trait SNumericType extends SProduct { override def toString: String = this.getClass.getSimpleName } + object SNumericType extends STypeCompanion { /** Array of all numeric types ordered by number of bytes in the representation. */ final val allNumericTypes = Array(SByte, SShort, SInt, SLong, SBigInt) @@ -983,7 +985,7 @@ case object SLong extends SPrimType with SEmbeddable with SNumericType with SMon override type WrappedType = Long override val typeCode: TypeCode = 5: Byte override val reprClass: RClass[_] = RClass(classOf[Long]) - override def typeId = typeCode + override def typeId: TypeCode = typeCode override def numericTypeIndex: Int = 3 override def upcast(v: AnyVal): Long = v match { case x: Byte => x.toLong @@ -999,15 +1001,27 @@ case object SLong extends SPrimType with SEmbeddable with SNumericType with SMon case l: Long => l case _ => sys.error(s"Cannot downcast value $v to the type $this") } + + lazy val DecodeNBitsMethod: SMethod = SMethod( + this, "DecodeNBits", SFunc(this, SBigInt), 8, FixedCost(JitCost(5))) + .withInfo(PropertyCall, "Consider this Long value as nbits-encoded BigInt value and decode it to BigInt") + + protected override def getMethods(): Seq[SMethod] = { + if (VersionContext.current.isEvolutionActivated) { + super.getMethods() ++ Seq(DecodeNBitsMethod) + } else { + super.getMethods() + } + } } -/** Type of 256 bit integet values. Implemented using [[java.math.BigInteger]]. */ +/** Type of 256 bit signed 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 override val reprClass: RClass[_] = RClass(classOf[BigInt]) - override def typeId = typeCode + override def typeId: TypeCode = typeCode /** Type of Relation binary op like GE, LE, etc. */ val RelationOpType = SFunc(Array(SBigInt, SBigInt), SBoolean) @@ -1038,8 +1052,8 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM SigmaDsl.BigInt(bi) } - /** 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 + /** The following `modQ` methods are not fully implemented in v4.x. + * The following descriptors 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. */ @@ -1053,7 +1067,7 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM .withIRInfo(MethodCallIrBuilder) .withInfo(MethodCall, "Multiply this number with \\lst{other} by module Q.", ArgInfo("other", "Number to multiply with this.")) - protected override def getMethods() = super.getMethods() ++ Seq( + protected override def getMethods(): Seq[SMethod] = super.getMethods() ++ Seq( // ModQMethod, // PlusModQMethod, // MinusModQMethod, @@ -1067,7 +1081,7 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM case object SString extends SProduct with SMonoType { override type WrappedType = String override val typeCode: TypeCode = 102: Byte - override def typeId = typeCode + override def typeId: TypeCode = typeCode override def reprClass: RClass[_] = RClass(classOf[String]) } From 49dce782be238e5bce6704d200b2790a1375f5c5 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 3 Apr 2024 00:24:01 +0300 Subject: [PATCH 002/123] ToNBits def --- interpreter/shared/src/main/scala/sigmastate/types.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interpreter/shared/src/main/scala/sigmastate/types.scala b/interpreter/shared/src/main/scala/sigmastate/types.scala index 7ba062046a..095dfccd0b 100644 --- a/interpreter/shared/src/main/scala/sigmastate/types.scala +++ b/interpreter/shared/src/main/scala/sigmastate/types.scala @@ -1052,6 +1052,9 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM SigmaDsl.BigInt(bi) } + val ToNBits = SMethod(this, "toNbits", SFunc(this, SLong), 1, FixedCost(JitCost(5))) + .withInfo(ModQ, "Encode this big integer value as NBits") + /** The following `modQ` methods are not fully implemented in v4.x. * The following descriptors 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 @@ -1068,6 +1071,7 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM .withInfo(MethodCall, "Multiply this number with \\lst{other} by module Q.", ArgInfo("other", "Number to multiply with this.")) protected override def getMethods(): Seq[SMethod] = super.getMethods() ++ Seq( + ToNBits // ModQMethod, // PlusModQMethod, // MinusModQMethod, From 37bb86c3cf7c07648e36d6114ef857ec3ddf6d65 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 4 Apr 2024 10:12:11 +0300 Subject: [PATCH 003/123] toNBits added to SigmaDsl --- core/shared/src/main/scala/sigma/SigmaDsl.scala | 2 ++ core/shared/src/main/scala/sigma/data/CBigInt.scala | 2 ++ 2 files changed, 4 insertions(+) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index df2b419273..19bca4ab1a 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -154,6 +154,8 @@ trait BigInt { */ def or(that: BigInt): BigInt def |(that: BigInt): BigInt = or(that) + + def toNbits(): Long } /** Base class for points on elliptic curves. */ diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index bbf1a85e46..b41d7d2347 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -49,4 +49,6 @@ 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 toNbits(): Long = ??? // todo: implement } From 6f8981f84f6c6d3e94732c63fe1c83a8e634a952 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 4 Apr 2024 13:57:48 +0300 Subject: [PATCH 004/123] NBitsUtils --- .../src/main/scala/sigma/ast/SType.scala | 2 +- .../src/main/scala/sigma/data/CBigInt.scala | 3 +- .../main/scala/sigma/util/NBitsUtils.scala | 84 +++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 core/shared/src/main/scala/sigma/util/NBitsUtils.scala diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index 0a0b12c59b..f1bf9d1508 100644 --- a/core/shared/src/main/scala/sigma/ast/SType.scala +++ b/core/shared/src/main/scala/sigma/ast/SType.scala @@ -449,7 +449,7 @@ case object SLong extends SPrimType with SEmbeddable with SNumericType with SMon } } -/** 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 diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index b41d7d2347..8b9deaf9bd 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -1,6 +1,7 @@ package sigma.data import sigma.util.Extensions.BigIntegerOps +import sigma.util.NBitsUtils import sigma.{BigInt, Coll, Colls} import java.math.BigInteger @@ -50,5 +51,5 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr override def or(that: BigInt): BigInt = CBigInt(wrappedValue.or(that.asInstanceOf[CBigInt].wrappedValue)) - override def toNbits(): Long = ??? // todo: implement + override def toNbits(): Long = NBitsUtils.encodeCompactBits(wrappedValue) } 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 + } + } + } + +} From d0f1b7d6c3fd05d7e5477ec670d7d2a0974a4e6c Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 5 Apr 2024 17:19:20 +0300 Subject: [PATCH 005/123] unused import removed --- core/shared/src/main/scala/sigma/ast/SType.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index f1bf9d1508..e01edf938f 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, VersionContext} +import sigma.{AvlTree, BigInt, Box, Coll, Context, Evaluation, GroupElement, Header, PreHeader, SigmaDslBuilder, SigmaProp} import java.math.BigInteger From fcc7f0f69f5ed34c8c6fdfa44c4116e43e4d9d3d Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sat, 6 Apr 2024 21:57:01 +0300 Subject: [PATCH 006/123] merging latest 5.0.14 commits --- core/shared/src/main/scala/sigma/VersionContext.scala | 4 ++-- .../src/main/scala/org/ergoplatform/ErgoAddress.scala | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/core/shared/src/main/scala/sigma/VersionContext.scala b/core/shared/src/main/scala/sigma/VersionContext.scala index ea564f335b..5663bfed60 100644 --- a/core/shared/src/main/scala/sigma/VersionContext.scala +++ b/core/shared/src/main/scala/sigma/VersionContext.scala @@ -51,8 +51,8 @@ object VersionContext { val EvolutionVersion: Byte = 3 private val _defaultContext = VersionContext( - activatedVersion = 2/* v5.x */, - ergoTreeVersion = 2 + activatedVersion = 1 /* v4.x */, + ergoTreeVersion = 1 ) /** Universally accessible version context which is used to version the code diff --git a/data/shared/src/main/scala/org/ergoplatform/ErgoAddress.scala b/data/shared/src/main/scala/org/ergoplatform/ErgoAddress.scala index 270f32d35d..59eb8df5c5 100644 --- a/data/shared/src/main/scala/org/ergoplatform/ErgoAddress.scala +++ b/data/shared/src/main/scala/org/ergoplatform/ErgoAddress.scala @@ -165,11 +165,7 @@ class Pay2SHAddress(val scriptHash: Array[Byte])(implicit val encoder: ErgoAddre ByteArrayConstant(scriptHash) ) val scriptIsCorrect = DeserializeContext(scriptId, SSigmaProp) - // Get script version either from the default context or from a context provided by an application - // This is never part of the consensus and can be controlled by applications - val treeVersion = VersionContext.current.ergoTreeVersion - val header = setVersionBits(ZeroHeader, treeVersion) - ErgoTree.withoutSegregation(header, SigmaAnd(hashEquals.toSigmaProp, scriptIsCorrect)) + ErgoTree.withoutSegregation(ZeroHeader, SigmaAnd(hashEquals.toSigmaProp, scriptIsCorrect)) } override def equals(obj: Any): Boolean = obj match { From 6e47167f76c99b5defa41f79edd3038df8e28e8d Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 9 Apr 2024 13:58:23 +0300 Subject: [PATCH 007/123] nbits impl --- .../src/main/scala/sigma/SigmaDsl.scala | 2 +- .../src/main/scala/sigma/VersionContext.scala | 6 +-- .../src/main/scala/sigma/data/CBigInt.scala | 2 +- .../sigma/reflection/ReflectionData.scala | 3 ++ .../src/main/scala/sigma/ast/methods.scala | 22 ++++++++--- .../scala/sigma/eval/ErgoTreeEvaluator.scala | 7 +++- .../interpreter/CErgoTreeEvaluator.scala | 13 +++++-- .../scala/sigmastate/eval/GraphBuilding.scala | 10 ++++- .../scala/special/sigma/SigmaDslUnit.scala | 1 + .../special/sigma/impl/SigmaDslImpl.scala | 14 +++++++ .../ErgoAddressSpecification.scala | 37 ++++++++++++++----- .../TestingInterpreterSpecification.scala | 19 +++++++++- 12 files changed, 109 insertions(+), 27 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 19bca4ab1a..56e4a1da37 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -155,7 +155,7 @@ trait BigInt { def or(that: BigInt): BigInt def |(that: BigInt): BigInt = or(that) - def toNbits(): Long + def nbits: Long } /** Base class for points on elliptic curves. */ diff --git a/core/shared/src/main/scala/sigma/VersionContext.scala b/core/shared/src/main/scala/sigma/VersionContext.scala index 5663bfed60..19a4857086 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.{EvolutionVersion, JitActivationVersion} +import VersionContext.{JitActivationVersion, V6SoftForkVersion} import scala.util.DynamicVariable @@ -24,7 +24,7 @@ case class VersionContext(activatedVersion: Byte, ergoTreeVersion: Byte) { /** @return true, if the activated script version of Ergo protocol on the network is * including Evolution update. */ - def isEvolutionActivated: Boolean = activatedVersion >= EvolutionVersion + def isV6SoftForkActivated: Boolean = activatedVersion >= V6SoftForkVersion } object VersionContext { @@ -48,7 +48,7 @@ object VersionContext { /** * The version of ErgoTree corresponding to "evolution" (6.0) soft-fork */ - val EvolutionVersion: Byte = 3 + val V6SoftForkVersion: Byte = 3 private val _defaultContext = VersionContext( activatedVersion = 1 /* v4.x */, diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index 8b9deaf9bd..43198fbf8a 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -51,5 +51,5 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr override def or(that: BigInt): BigInt = CBigInt(wrappedValue.or(that.asInstanceOf[CBigInt].wrappedValue)) - override def toNbits(): Long = NBitsUtils.encodeCompactBits(wrappedValue) + override def nbits: Long = NBitsUtils.encodeCompactBits(wrappedValue) } diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index 2aac1a5670..e25462651f 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -118,6 +118,9 @@ object ReflectionData { }, mkMethod(clazz, "divide", paramTypes) { (obj, args) => obj.asInstanceOf[BigInt].divide(args(0).asInstanceOf[BigInt]) + }, + mkMethod(clazz, "nbits", paramTypes) { (obj, _) => + obj.asInstanceOf[BigInt].nbits } ) ) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 275ad9e4b5..a21459fcb9 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -53,7 +53,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) => @@ -309,7 +309,7 @@ case object SLongMethods extends SNumericTypeMethods { .withInfo(PropertyCall, "Consider this Long value as nbits-encoded BigInt value and decode it to BigInt") protected override def getMethods(): Seq[SMethod] = { - if (VersionContext.current.isEvolutionActivated) { + if (VersionContext.current.isV6SoftForkActivated) { super.getMethods() ++ Seq(DecodeNBitsMethod) } else { super.getMethods() @@ -322,8 +322,12 @@ case object SBigIntMethods extends SNumericTypeMethods { /** Type for which this container defines methods. */ override def ownerType: SMonoType = SBigInt - val ToNBits = SMethod(this, "toNbits", SFunc(this.ownerType, SLong), 1, FixedCost(JitCost(5))) - .withInfo(ModQ, "Encode this big integer value as NBits") + final val ToNBitsCostInfo = OperationCostInfo( + FixedCost(JitCost(5)), NamedDesc("NBitsMethodCall")) + + //id = 8 to make it after toBits + val ToNBits = SMethod(this, "nbits", SFunc(this.ownerType, SLong), 8, ToNBitsCostInfo.costKind) + .withInfo(ModQ, "Encode this big integer value as NBits") /** 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 @@ -341,7 +345,7 @@ case object SBigIntMethods extends SNumericTypeMethods { .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.isEvolutionActivated) { + if (VersionContext.current.isV6SoftForkActivated) { super.getMethods() ++ Seq(ToNBits) // ModQMethod, // PlusModQMethod, @@ -352,6 +356,14 @@ case object SBigIntMethods extends SNumericTypeMethods { super.getMethods() } } + + /** + * + */ + def nbits_eval(mc: MethodCall, bi: sigma.BigInt)(implicit E: ErgoTreeEvaluator): Long = { + E.nbits(mc, bi) + } + } /** Methods of type `String`. */ diff --git a/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala b/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala index 52f839354c..ec12a52849 100644 --- a/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala +++ b/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala @@ -59,9 +59,9 @@ abstract class ErgoTreeEvaluator { * @param opDesc the operation descriptor to associate the cost with (when costTracingEnabled) * @param block operation executed under the given cost */ - def addFixedCost(costKind: FixedCost, opDesc: OperationDesc)(block: => Unit): Unit + def addFixedCost[R](costKind: FixedCost, opDesc: OperationDesc)(block: => R): R - def addFixedCost(costInfo: OperationCostInfo[FixedCost])(block: => Unit): Unit + def addFixedCost[R](costInfo: OperationCostInfo[FixedCost])(block: => R): R /** Adds the given cost to the `coster`. If tracing is enabled, creates a new cost item * with the given operation. @@ -98,6 +98,9 @@ abstract class ErgoTreeEvaluator { /** Represents blockchain data context for ErgoTree evaluation. */ def context: Context + /** Implements evaluation of BigInt.nbits method call ErgoTree node. */ + def nbits(mc: MethodCall, bi: sigma.BigInt): Long + /** Create an instance of [[AvlTreeVerifier]] for the given tree and proof. */ def createTreeVerifier(tree: AvlTree, proof: Coll[Byte]): AvlTreeVerifier diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala index de8aa6b620..53aa3dc08b 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala @@ -67,6 +67,12 @@ class CErgoTreeEvaluator( override def createTreeVerifier(tree: AvlTree, proof: Coll[Byte]): AvlTreeVerifier = CAvlTreeVerifier(tree, proof) + def nbits(mc: MethodCall, bi: sigma.BigInt): Long = { + addFixedCost(SBigIntMethods.ToNBitsCostInfo) { + bi.nbits + } + } + /** Creates [[sigma.eval.AvlTreeVerifier]] for the given tree and proof. */ def createVerifier(tree: AvlTree, proof: Coll[Byte]) = { // the cost of tree reconstruction from proof is O(proof.length) @@ -293,7 +299,7 @@ class CErgoTreeEvaluator( } /** @hotspot don't beautify the code */ - override def addFixedCost(costKind: FixedCost, opDesc: OperationDesc)(block: => Unit): Unit = { + override def addFixedCost[R](costKind: FixedCost, opDesc: OperationDesc)(block: => R): R = { var costItem: FixedCostItem = null if (settings.costTracingEnabled) { costItem = FixedCostItem(opDesc, costKind) @@ -305,16 +311,17 @@ class CErgoTreeEvaluator( } val start = System.nanoTime() coster.add(costKind.cost) - val _ = block + val res = block val end = System.nanoTime() profiler.addCostItem(costItem, end - start) + res } else { coster.add(costKind.cost) block } } - override def addFixedCost(costInfo: OperationCostInfo[FixedCost])(block: => Unit): Unit = { + override def addFixedCost[R](costInfo: OperationCostInfo[FixedCost])(block: => R): R = { addFixedCost(costInfo.costKind, costInfo.opDesc)(block) } diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index 9c9fa5ffe1..0ea648691e 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -8,6 +8,7 @@ import sigma.ast.Value.Typed import sigma.ast._ import sigma.ast.syntax.{SValue, ValueOps} import sigma.crypto.EcPointType +import sigma.VersionContext 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} @@ -52,7 +53,7 @@ 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. + /** Whether to create CostOf nodes or substitute costs from CostTable as constants in the graph. * true - substitute; false - create CostOf nodes */ var substFromCostTable: Boolean = true @@ -496,6 +497,9 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => else error(s"The type of $obj is expected to be Collection to select 'size' property", obj.sourceContext.toOption) + case Select(obj, SBigIntMethods.ToNBits.name, _) if obj.tpe == SBigInt && VersionContext.current.isV6SoftForkActivated => + eval(sigma.ast.MethodCall(obj, SBigIntMethods.ToNBits, IndexedSeq.empty, Map.empty)) + // Rule: proof.isProven --> IsValid(proof) case Select(p, SSigmaPropMethods.IsProven, _) if p.tpe == SSigmaProp => eval(SigmaPropIsProven(p.asSigmaProp)) @@ -925,6 +929,10 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => val objV = eval(obj) val argsV = args.map(eval) (objV, method.objType) match { + case (bi: Ref[BigInt]@unchecked, SBigIntMethods) => method.name match { + case SBigIntMethods.ToNBits.name => + bi.nbits + } case (xs: RColl[t]@unchecked, SCollectionMethods) => method.name match { case SCollectionMethods.IndicesMethod.name => xs.indices diff --git a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala index 48548226a5..9e3a06a62f 100644 --- a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala @@ -11,6 +11,7 @@ package sigma { def mod(m: Ref[BigInt]): Ref[BigInt]; def min(that: Ref[BigInt]): Ref[BigInt]; def max(that: Ref[BigInt]): Ref[BigInt]; + def nbits: Ref[Long] }; trait GroupElement extends Def[GroupElement] { def exp(k: Ref[BigInt]): Ref[GroupElement]; diff --git a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala index 8da36ce6cf..c9f7ec9656 100644 --- a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala @@ -96,6 +96,13 @@ object BigInt extends EntityObject("BigInt") { Array[AnyRef](that), true, false, element[BigInt])) } + + override def nbits: Ref[Long] = { + asRep[Long](mkMethodCall(self, + BigIntClass.getMethod("nbits"), + Array[AnyRef](), + neverInvoke = true, isAdapterCall = false, element[Long])) + } } implicit object LiftableBigInt @@ -164,6 +171,13 @@ object BigInt extends EntityObject("BigInt") { Array[AnyRef](that), true, true, element[BigInt])) } + + def nbits: Ref[Long] = { + asRep[Long](mkMethodCall(source, + BigIntClass.getMethod("nbits", classOf[Sym]), + Array[AnyRef](), + neverInvoke = true, isAdapterCall = true, element[Long])) + } } // entityUnref: single unref method for each type family diff --git a/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala b/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala index ad0d316519..83d2892a0c 100644 --- a/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala +++ b/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala @@ -16,9 +16,8 @@ import sigma.serialization.ErgoTreeSerializer.DefaultSerializer import sigma.serialization.ValueSerializer import sigmastate.utils.Helpers._ import sigmastate.CompilerCrossVersionProps -import sigma.SigmaDslTesting +import sigma.{SigmaDslTesting, VersionContext} import sigma.ast.ErgoTree.{ZeroHeader, setConstantSegregation} - import sigma.ast.SType import sigma.data.ProveDlog import sigma.exceptions.{CostLimitException, InvalidType} @@ -30,7 +29,7 @@ import sigma.validation.ValidationRules.CheckTypeCode import java.math.BigInteger class ErgoAddressSpecification extends SigmaDslTesting - with TryValues with CompilerCrossVersionProps { + with TryValues with CompilerCrossVersionProps with AnyPropSpecLike { private implicit val ergoAddressEncoder: ErgoAddressEncoder = new ErgoAddressEncoder(TestnetNetworkPrefix) @@ -252,12 +251,16 @@ class ErgoAddressSpecification extends SigmaDslTesting verifier.verify(env + (ScriptNameProp -> s"verify_ext"), address.script, ctx, pr.proof, fakeMessage).getOrThrow._1 shouldBe true } - property("spending a box protected by P2SH contract") { + def createPropAndScriptBytes() = { implicit lazy val IR = new TestingIRContext - val script = "{ 1 < 2 }" val prop = compile(Map.empty, script).asBoolValue.toSigmaProp val scriptBytes = ValueSerializer.serialize(prop) + (prop, scriptBytes) + } + + property("spending a box protected by P2SH contract") { + val (prop, scriptBytes) = createPropAndScriptBytes() testPay2SHAddress(Pay2SHAddress(prop), scriptBytes) @@ -265,8 +268,24 @@ class ErgoAddressSpecification extends SigmaDslTesting testPay2SHAddress(Pay2SHAddress(tree), scriptBytes) // NOTE: same scriptBytes regardless of ErgoTree version } + property("Pay2SHAddress.script should create ErgoTree v0") { + val (prop, _) = createPropAndScriptBytes() + + val address = VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) { + Pay2SHAddress(prop) + } + address.script.version shouldBe 0 + } + + // create non-versioned property which is executed under default version context + // see VersionContext._defaultContext + super[AnyPropSpecLike].property("using default VersionContext still creates ErgoTree v0") { + val (prop, _) = createPropAndScriptBytes() + val address = Pay2SHAddress(prop) + address.script.version shouldBe 0 + } + property("negative cases: deserialized script + costing exceptions") { - implicit lazy val IR = new TestingIRContext def testPay2SHAddress(address: Pay2SHAddress, script: VarBinding, costLimit: Int = scriptCostLimitInTests): CostedProverResult = { val boxToSpend = testBox(10, address.script, creationHeight = 5) @@ -281,15 +300,13 @@ class ErgoAddressSpecification extends SigmaDslTesting } val scriptVarId = Pay2SHAddress.scriptId - val script = "{ 1 < 2 }" - val prop = compile(Map.empty, script).asBoolValue.toSigmaProp - val scriptBytes = ValueSerializer.serialize(prop) + val (prop, scriptBytes) = createPropAndScriptBytes() val addr = Pay2SHAddress(prop) // when everything is ok testPay2SHAddress(addr, script = scriptVarId -> ByteArrayConstant(scriptBytes)) - val expectedCost = if (ergoTreeVersionInTests == 0) 88 else 90 // account for size serialized for version > 0 + val expectedCost = 88 // when limit is low { diff --git a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala index fe5a678679..736ea15abb 100644 --- a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala @@ -6,12 +6,12 @@ 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 sigma.VersionContext.V6SoftForkVersion import sigma.util.Extensions.IntOps import sigmastate.helpers.{CompilerTestingCommons, ErgoLikeContextTesting, ErgoLikeTestInterpreter, ErgoLikeTestProvingInterpreter} import sigmastate.helpers.TestingHelpers._ @@ -204,6 +204,23 @@ class TestingInterpreterSpecification extends CompilerTestingCommons |}""".stripMargin) } + property("Evaluate BigInt to nbits conversion") { + val source = + """ + |{ + | val b: BigInt = 11999.toBigInt + | b.nbits == 36626176 + |} + |""".stripMargin + if (activatedVersionInTests < V6SoftForkVersion) { + println("h") + an [sigmastate.exceptions.MethodNotFound] should be thrownBy testEval(source, true) + } else { + println("here!") + testEval(source, true) + } + } + property("Evaluate numeric casting ops") { def testWithCasting(castSuffix: String): Unit = { testEval(s"OUTPUTS.size.toByte.$castSuffix == 0.$castSuffix") From 9e4e098873227744bb809ef6ea5c3b567e5995bb Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 10 Apr 2024 13:34:41 +0300 Subject: [PATCH 008/123] failing roundtrip test for deserialization roundtrip --- .../MethodCallSerializerSpecification.scala | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala index ac9c997d98..e04f5e3746 100644 --- a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala @@ -21,4 +21,14 @@ class MethodCallSerializerSpecification extends SerializationSpecification { ) roundTripTest(expr) } + + property("MethodCall deserialization round trip for BigInt.nbits") { + val bi = BigIntConstant(5) + val expr = MethodCall(bi, + SBigIntMethods.ToNBits, + Vector(), + Map() + ) + roundTripTest(expr) + } } From 1016323a7acec0489c3bf54afa5fca6860e16d46 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 10 Apr 2024 14:15:50 +0300 Subject: [PATCH 009/123] importing method def from i675 --- .../src/main/scala/sigma/ast/methods.scala | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index b637acf792..5371be233c 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -2,7 +2,7 @@ package sigma.ast import org.ergoplatform._ import org.ergoplatform.validation._ -import sigma._ +import sigma.{VersionContext, _} import sigma.ast.SCollection.{SBooleanArray, SBoxArray, SByteArray, SByteArray2, SHeaderArray} import sigma.ast.SMethod.{MethodCallIrBuilder, MethodCostFunc, javaMethodOf} import sigma.ast.SType.TypeCode @@ -53,7 +53,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) => @@ -303,6 +303,18 @@ case object SIntMethods extends SNumericTypeMethods { case object SLongMethods extends SNumericTypeMethods { /** Type for which this container defines methods. */ override def ownerType: SMonoType = SLong + + lazy val DecodeNBitsMethod: SMethod = SMethod( + this, "DecodeNBits", SFunc(this.ownerType, SBigInt), 8, FixedCost(JitCost(5))) + .withInfo(PropertyCall, "Consider this Long value as nbits-encoded BigInt value and decode it to BigInt") + + protected override def getMethods(): Seq[SMethod] = { + if (VersionContext.current.isV6SoftForkActivated) { + super.getMethods() ++ Seq(DecodeNBitsMethod) + } else { + super.getMethods() + } + } } /** Methods of BigInt type. Implemented using [[java.math.BigInteger]]. */ From 93748f1ee7c8027ce98c80186e5ebcfed8a199ed Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 10 Apr 2024 14:32:45 +0300 Subject: [PATCH 010/123] removing decode nbits --- data/shared/src/main/scala/sigma/ast/methods.scala | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index a21459fcb9..adc2a119bf 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -303,18 +303,6 @@ case object SIntMethods extends SNumericTypeMethods { case object SLongMethods extends SNumericTypeMethods { /** Type for which this container defines methods. */ override def ownerType: SMonoType = SLong - - lazy val DecodeNBitsMethod: SMethod = SMethod( - this, "DecodeNBits", SFunc(this.ownerType, SBigInt), 8, FixedCost(JitCost(5))) - .withInfo(PropertyCall, "Consider this Long value as nbits-encoded BigInt value and decode it to BigInt") - - protected override def getMethods(): Seq[SMethod] = { - if (VersionContext.current.isV6SoftForkActivated) { - super.getMethods() ++ Seq(DecodeNBitsMethod) - } else { - super.getMethods() - } - } } /** Methods of BigInt type. Implemented using [[java.math.BigInteger]]. */ From a3cb64d3ba78d31121a2b681d08d67ee886355cd Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 12 Apr 2024 12:09:31 +0300 Subject: [PATCH 011/123] versioned nbits serialization roundtrip test --- .../MethodCallSerializerSpecification.scala | 28 ++++++++++++++----- .../ErgoAddressSpecification.scala | 1 + .../TestingInterpreterSpecification.scala | 6 ++-- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala index e04f5e3746..769874d148 100644 --- a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala @@ -1,6 +1,8 @@ package sigma.serialization +import sigma.VersionContext import sigma.ast._ +import sigma.validation.ValidationException class MethodCallSerializerSpecification extends SerializationSpecification { @@ -23,12 +25,24 @@ class MethodCallSerializerSpecification extends SerializationSpecification { } property("MethodCall deserialization round trip for BigInt.nbits") { - val bi = BigIntConstant(5) - val expr = MethodCall(bi, - SBigIntMethods.ToNBits, - Vector(), - Map() - ) - roundTripTest(expr) + def code = { + val bi = BigIntConstant(5) + val expr = MethodCall(bi, + SBigIntMethods.ToNBits, + Vector(), + Map() + ) + roundTripTest(expr) + } + + // should be ok + VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) { + code + } + + an[ValidationException] should be thrownBy ( + VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) { + code + }) } } diff --git a/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala b/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala index 83d2892a0c..d8ee6e3707 100644 --- a/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala +++ b/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala @@ -1,6 +1,7 @@ package org.ergoplatform import org.ergoplatform.ErgoAddressEncoder.{MainnetNetworkPrefix, TestnetNetworkPrefix, hash256} +import org.scalatest.propspec.AnyPropSpecLike import org.scalatest.{Assertion, TryValues} import scorex.crypto.hash.Blake2b256 import scorex.util.encode.Base58 diff --git a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala index 736ea15abb..15b94b3ab3 100644 --- a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala @@ -213,11 +213,9 @@ class TestingInterpreterSpecification extends CompilerTestingCommons |} |""".stripMargin if (activatedVersionInTests < V6SoftForkVersion) { - println("h") - an [sigmastate.exceptions.MethodNotFound] should be thrownBy testEval(source, true) + an [sigmastate.exceptions.MethodNotFound] should be thrownBy testEval(source) } else { - println("here!") - testEval(source, true) + testEval(source) } } From 8941a8ed7cf06c08879c533f071a604ba3ebe3c9 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 15 Apr 2024 20:52:59 +0300 Subject: [PATCH 012/123] nbits evaluation test --- .../scala/sigmastate/eval/BasicOpsTests.scala | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala b/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala index ba996b0246..d3474d9355 100644 --- a/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala +++ b/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala @@ -2,12 +2,16 @@ package sigmastate.eval import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import sigma.ast.{BigIntConstant, ErgoTree, JitCost, MethodCall, SBigIntMethods} import sigma.crypto.SecP256K1Group -import sigma.data.{CSigmaDslBuilder, TrivialProp} +import sigma.data.{CBigInt, CSigmaDslBuilder, TrivialProp} import sigma.util.Extensions.SigmaBooleanOps +import sigma.util.NBitsUtils import java.math.BigInteger import sigma.{ContractsTestkit, SigmaDslBuilder, SigmaProp} +import sigmastate.interpreter.{CErgoTreeEvaluator, CostAccumulator} +import sigmastate.interpreter.CErgoTreeEvaluator.DefaultProfiler import scala.language.implicitConversions @@ -64,4 +68,27 @@ class BasicOpsTests extends AnyFunSuite with ContractsTestkit with Matchers { box.creationInfo._1 shouldBe a [Integer] } + /** + * Checks BigInt.nbits evaluation for SigmaDSL as well as AST interpreter (MethodCall) layers + */ + test("nbits evaluation") { + SigmaDsl.BigInt(BigInteger.valueOf(0)).nbits should be + (NBitsUtils.encodeCompactBits(0)) + + 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 res = MethodCall(BigIntConstant(BigInteger.valueOf(0)), SBigIntMethods.ToNBits, IndexedSeq.empty, Map.empty) + .evalTo[Long](Map.empty)(evaluator) + + res should be (NBitsUtils.encodeCompactBits(0)) + + } + } From 92e2d77aa824e6a5b44d8b52913b6561deab8945 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 6 May 2024 13:39:05 +0300 Subject: [PATCH 013/123] close #974 : Header.bytes method implementation --- .../src/main/scala/sigma/SigmaDsl.scala | 1 + .../sigma/reflection/ReflectionData.scala | 3 + .../serialization/CoreDataSerializer.scala | 1 - .../scala/org/ergoplatform/ErgoHeader.scala | 12 ++- .../org/ergoplatform/HeaderWithoutPow.scala | 2 +- .../src/main/scala/sigma/ast/methods.scala | 7 +- .../src/main/scala/sigma/data/CHeader.scala | 10 +- .../MethodCallSerializerSpecification.scala | 26 ++++- .../special/sigma/SigmaTestingData.scala | 7 +- .../scala/sigmastate/eval/GraphBuilding.scala | 2 + .../scala/special/sigma/SigmaDslUnit.scala | 1 + .../special/sigma/impl/SigmaDslImpl.scala | 14 +++ .../TestingInterpreterSpecification.scala | 97 +++++++++++-------- .../org/ergoplatform/sdk/JsonCodecs.scala | 4 +- 14 files changed, 127 insertions(+), 60 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index a2894515a2..0ac4f266df 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -466,6 +466,7 @@ trait Header { def checkPow: Boolean + def bytes: Coll[Byte] } /** Runtime representation of Context ErgoTree type. diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index 2a5e74e659..381bd4faf8 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -349,6 +349,9 @@ object ReflectionData { }, mkMethod(clazz, "checkPow", Array[Class[_]]()) { (obj, _) => obj.asInstanceOf[Header].checkPow + }, + mkMethod(clazz, "bytes", Array[Class[_]]()) { (obj, _) => + obj.asInstanceOf[Header].bytes } ) ) diff --git a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala index 56872cd68e..0c7a991662 100644 --- a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala +++ b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala @@ -69,7 +69,6 @@ class CoreDataSerializer { } // TODO v6.0 : support Option[T] (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/659) - // TODO v6.0 : support Header case _ => CheckSerializableTypeCode(tpe.typeCode) throw new SerializerException(s"Don't know how to serialize ($v, $tpe)") diff --git a/data/shared/src/main/scala/org/ergoplatform/ErgoHeader.scala b/data/shared/src/main/scala/org/ergoplatform/ErgoHeader.scala index cc678003d6..7d70d67d25 100644 --- a/data/shared/src/main/scala/org/ergoplatform/ErgoHeader.scala +++ b/data/shared/src/main/scala/org/ergoplatform/ErgoHeader.scala @@ -5,7 +5,7 @@ import scorex.crypto.authds.ADDigest import scorex.crypto.hash.{Blake2b256, Digest32} import scorex.util.ModifierId import sigma.Colls -import sigma.crypto.{CryptoConstants, CryptoFacade, EcPointType} +import sigma.crypto.{CryptoConstants, EcPointType} import sigma.serialization.{GroupElementSerializer, SigmaByteReader, SigmaByteWriter, SigmaSerializer} @@ -90,7 +90,7 @@ object AutolykosSolution { * @param votes - votes for changing system parameters * @param _bytes - serialized bytes of the header when not `null` */ -case class ErgoHeader(override val version: ErgoHeader.Version, +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! @@ -99,7 +99,7 @@ case class ErgoHeader(override val version: ErgoHeader.Version, override val nBits: Long, //actually it is unsigned int override val height: Int, override val extensionRoot: Digest32, - powSolution: AutolykosSolution, + val powSolution: AutolykosSolution, override val votes: Array[Byte], //3 bytes override val unparsedBytes: Array[Byte], _bytes: Array[Byte]) extends @@ -116,6 +116,12 @@ case class ErgoHeader(override val version: ErgoHeader.Version, 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 + } } diff --git a/data/shared/src/main/scala/org/ergoplatform/HeaderWithoutPow.scala b/data/shared/src/main/scala/org/ergoplatform/HeaderWithoutPow.scala index 56e2eafb1b..0ea6617b2a 100644 --- a/data/shared/src/main/scala/org/ergoplatform/HeaderWithoutPow.scala +++ b/data/shared/src/main/scala/org/ergoplatform/HeaderWithoutPow.scala @@ -23,7 +23,7 @@ class HeaderWithoutPow(val version: Byte, // 1 byte 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, + new ErgoHeader(version, parentId, ADProofsRoot, stateRoot, transactionsRoot, timestamp, nBits, height, extensionRoot, powSolution, votes, unparsedBytes, bytes) } diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 97c2302b2d..07b3bc3b7c 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -1457,11 +1457,14 @@ 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))) + // methods added in 6.0 below lazy val checkPowMethod = SMethod( this, "checkPow", SFunc(Array(SHeader), SBoolean), 16, GroupGenerator.costKind) // todo: cost .withIRInfo(MethodCallIrBuilder) .withInfo(Xor, "Check PoW of this header") // todo: desc + lazy val bytesMethod = propertyCall("bytes", SByteArray, 17, FixedCost(JitCost(10))) + def checkPow_eval(mc: MethodCall, G: SigmaDslBuilder, header: Header) (implicit E: ErgoTreeEvaluator): Boolean = { E.checkPow_eval(mc, header) @@ -1469,11 +1472,11 @@ case object SHeaderMethods extends MonoTypeMethods { protected override def getMethods() = { if (VersionContext.current.isV6SoftForkActivated) { - // 6.0 : checkPow method added + // 6.0 : checkPow & bytes methods added super.getMethods() ++ Seq( idMethod, versionMethod, parentIdMethod, ADProofsRootMethod, stateRootMethod, transactionsRootMethod, timestampMethod, nBitsMethod, heightMethod, extensionRootMethod, minerPkMethod, powOnetimePkMethod, - powNonceMethod, powDistanceMethod, votesMethod, checkPowMethod) + powNonceMethod, powDistanceMethod, votesMethod, checkPowMethod, bytesMethod) } else { super.getMethods() ++ Seq( idMethod, versionMethod, parentIdMethod, ADProofsRootMethod, stateRootMethod, transactionsRootMethod, diff --git a/data/shared/src/main/scala/sigma/data/CHeader.scala b/data/shared/src/main/scala/sigma/data/CHeader.scala index ed75fee4be..1a0d5b37ed 100644 --- a/data/shared/src/main/scala/sigma/data/CHeader.scala +++ b/data/shared/src/main/scala/sigma/data/CHeader.scala @@ -11,7 +11,7 @@ import sigma.{AvlTree, BigInt, Coll, Colls, GroupElement, Header} * * @see [[Header]] for detailed descriptions */ -class CHeader(val ergoHeader: ErgoHeader) extends Header with WrapperOf[ErgoHeader] { +case class CHeader(ergoHeader: ErgoHeader) extends Header with WrapperOf[ErgoHeader] { /** Bytes representation of ModifierId of this Header */ override lazy val id: Coll[Byte] = ergoHeader.id @@ -81,12 +81,8 @@ class CHeader(val ergoHeader: ErgoHeader) extends Header with WrapperOf[ErgoHead } } - override def hashCode(): Int = id.hashCode() + override def bytes: Coll[Byte] = Colls.fromArray(ergoHeader.bytes) - override def equals(other: Any): Boolean = other match { - case ch: CHeader => ch.id == this.id - case _ => false - } } object CHeader { @@ -115,7 +111,7 @@ object CHeader { powNonce.toArray, powDistance.asInstanceOf[CBigInt].wrappedValue) - val h = ErgoHeader(version, bytesToId(parentId.toArray), Digest32 @@ ADProofsRoot.toArray, + val h = new ErgoHeader(version, bytesToId(parentId.toArray), Digest32 @@ ADProofsRoot.toArray, ADDigest @@ stateRoot.digest.toArray, Digest32 @@ transactionsRoot.toArray, timestamp, nBits, height, Digest32 @@ extensionRoot.toArray, solution, votes.toArray, unparsedBytes.toArray, null) diff --git a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala index 2332aaccaa..e8a7ba7a2f 100644 --- a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala @@ -4,9 +4,6 @@ import sigma.VersionContext import sigma.ast._ import sigma.validation.ValidationException -import scala.util.Try - - class MethodCallSerializerSpecification extends SerializationSpecification { property("MethodCall deserialization round trip") { @@ -72,4 +69,27 @@ class MethodCallSerializerSpecification extends SerializationSpecification { ) } + + property("MethodCall deserialization round trip for Header.bytes") { + def code = { + val h = HeaderConstant(headerGen.sample.get) + val expr = MethodCall(h, + SHeaderMethods.bytesMethod, + Vector(), + Map() + ) + roundTripTest(expr) + } + + VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) { + code + } + + // sigma.serialization.SerializerException: Don't know how to serialize (sigma.data.CHeader@51dbec76, SHeader) + an[SerializerException] should be thrownBy ( + VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) { + code + } + ) + } } diff --git a/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala b/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala index d1253d4686..97aa432c51 100644 --- a/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala +++ b/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala @@ -1,6 +1,6 @@ package sigma -import org.ergoplatform.ErgoBox +import org.ergoplatform.{ErgoBox, ErgoHeader} import org.ergoplatform.settings.ErgoAlgos import org.scalacheck.Arbitrary.arbitrary import org.scalacheck.Gen.containerOfN @@ -268,7 +268,10 @@ trait SigmaTestingData extends TestingCommons with ObjectGenerators { val h1: Header = create_h1() - val h2: Header = new CHeader(h1.asInstanceOf[CHeader].wrappedValue.copy(height = 2)) + val eh1 = h1.asInstanceOf[CHeader].ergoHeader + val h2: Header = new CHeader(new ErgoHeader(eh1.version, eh1.parentId, eh1.ADProofsRoot, eh1.stateRoot, + eh1.transactionsRoot, eh1.timestamp, eh1.nBits, 2, eh1.extensionRoot, + eh1.powSolution, eh1.votes, eh1.unparsedBytes, null)) val dlog_instances = new CloneSet(1000, ProveDlog( SigmaDsl.toECPoint(create_ge1()).asInstanceOf[EcPointType] diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index a35a44ee23..3657a13a5c 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -1126,6 +1126,8 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => h.votes case SHeaderMethods.checkPowMethod.name if VersionContext.current.isV6SoftForkActivated => h.checkPow + case SHeaderMethods.bytesMethod.name if VersionContext.current.isV6SoftForkActivated => + h.bytes case _ => throwError } case (g: Ref[SigmaDslBuilder]@unchecked, SGlobalMethods) => method.name match { diff --git a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala index d84bf40c4f..3ab2c86efc 100644 --- a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala @@ -77,6 +77,7 @@ package sigma { def powDistance: Ref[BigInt]; def votes: Ref[Coll[Byte]] def checkPow: Ref[Boolean] + def bytes: Ref[Coll[Byte]] }; trait Context extends Def[Context] { def OUTPUTS: Ref[Coll[Box]]; diff --git a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala index 100e0777ce..407394001d 100644 --- a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala @@ -1371,6 +1371,13 @@ object Header extends EntityObject("Header") { ArraySeq.empty, true, false, element[Boolean])) } + + override def bytes: Ref[Coll[Byte]] = { + asRep[Coll[Byte]](mkMethodCall(self, + HeaderClass.getMethod("bytes"), + ArraySeq.empty, + true, false, element[Coll[Byte]])) + } } implicit object LiftableHeader @@ -1502,6 +1509,13 @@ object Header extends EntityObject("Header") { ArraySeq.empty, true, true, element[Boolean])) } + + def bytes: Ref[Coll[Byte]] = { + asRep[Coll[Byte]](mkMethodCall(source, + HeaderClass.getMethod("bytes"), + ArraySeq.empty, + true, true, element[Coll[Byte]])) + } } // entityUnref: single unref method for each type family diff --git a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala index 4948f70c23..a9c8fff5f8 100644 --- a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala @@ -10,10 +10,9 @@ import io.circe.parser.parse import org.ergoplatform._ import org.ergoplatform.sdk.JsonCodecs import org.scalatest.BeforeAndAfterAll -import scorex.util.encode.Base58 +import scorex.util.encode.{Base16, Base58} import sigma.Colls import sigma.VersionContext.V6SoftForkVersion -import sigma.crypto.CryptoConstants import sigma.data.{CAND, CAvlTree, ProveDlog, SigmaBoolean, TrivialProp} import sigma.interpreter.ContextExtension import sigma.util.Extensions.IntOps @@ -36,47 +35,47 @@ class TestingInterpreterSpecification extends CompilerTestingCommons lazy val prover = new ErgoLikeTestProvingInterpreter() lazy val verifier = new ErgoLikeTestInterpreter - - def testingContext(h: Int = 614401) = { - // valid header from Ergo blockchain - val headerJson = - """ - |{ - | "extensionId" : "00cce45975d87414e8bdd8146bc88815be59cd9fe37a125b5021101e05675a18", - | "votes" : "000000", - | "timestamp" : 4928911477310178288, - | "size" : 223, - | "unparsedBytes" : "", - | "stateRoot" : { - | "digest" : "5c8c00b8403d3701557181c8df800001b6d5009e2201c6ff807d71808c00019780", - | "treeFlags" : "0", - | "keyLength" : "32" - | }, - | "height" : 614400, - | "nBits" : 37748736, - | "version" : 2, - | "id" : "5603a937ec1988220fc44fb5022fb82d5565b961f005ebb55d85bd5a9e6f801f", - | "adProofsRoot" : "5d3f80dcff7f5e7f59007294c180808d0158d1ff6ba10000f901c7f0ef87dcff", - | "transactionsRoot" : "f17fffacb6ff7f7f1180d2ff7f1e24ffffe1ff937f807f0797b9ff6ebdae007e", - | "extensionRoot" : "1480887f80007f4b01cf7f013ff1ffff564a0000b9a54f00770e807f41ff88c0", - | "minerPk" : "03bedaee069ff4829500b3c07c4d5fe6b3ea3d3bf76c5c28c1d4dcdb1bed0ade0c", - | "powOnetimePk" : "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", - | "powNonce" : "0000000000003105", - | "powDistance" : 0, - | "adProofsId" : "dec129290a763f4de41f04e87e2b661dd59758af6bdd00dd51f5d97c3a8cb9b5", - | "transactionsId" : "eba1dd82cf51147232e09c1f72b37c554c30f63274d5093bff36849a83472a42", - | "parentId" : "ac2101807f0000ca01ff0119db227f202201007f62000177a080005d440896d0" - |} - |""".stripMargin - - object JsonCodecs extends JsonCodecs - val header1 = JsonCodecs.headerDecoder.decodeJson(parse(headerJson).toOption.get).toOption.get + // valid header from Ergo blockchain + val headerJson = + """ + |{ + | "extensionId" : "00cce45975d87414e8bdd8146bc88815be59cd9fe37a125b5021101e05675a18", + | "votes" : "000000", + | "timestamp" : 4928911477310178288, + | "size" : 223, + | "unparsedBytes" : "", + | "stateRoot" : { + | "digest" : "5c8c00b8403d3701557181c8df800001b6d5009e2201c6ff807d71808c00019780", + | "treeFlags" : "0", + | "keyLength" : "32" + | }, + | "height" : 614400, + | "nBits" : 37748736, + | "version" : 2, + | "id" : "5603a937ec1988220fc44fb5022fb82d5565b961f005ebb55d85bd5a9e6f801f", + | "adProofsRoot" : "5d3f80dcff7f5e7f59007294c180808d0158d1ff6ba10000f901c7f0ef87dcff", + | "transactionsRoot" : "f17fffacb6ff7f7f1180d2ff7f1e24ffffe1ff937f807f0797b9ff6ebdae007e", + | "extensionRoot" : "1480887f80007f4b01cf7f013ff1ffff564a0000b9a54f00770e807f41ff88c0", + | "minerPk" : "03bedaee069ff4829500b3c07c4d5fe6b3ea3d3bf76c5c28c1d4dcdb1bed0ade0c", + | "powOnetimePk" : "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + | "powNonce" : "0000000000003105", + | "powDistance" : 0, + | "adProofsId" : "dec129290a763f4de41f04e87e2b661dd59758af6bdd00dd51f5d97c3a8cb9b5", + | "transactionsId" : "eba1dd82cf51147232e09c1f72b37c554c30f63274d5093bff36849a83472a42", + | "parentId" : "ac2101807f0000ca01ff0119db227f202201007f62000177a080005d440896d0" + |} + |""".stripMargin + + object JsonCodecs extends JsonCodecs + val contextHeader = JsonCodecs.headerDecoder.decodeJson(parse(headerJson).toOption.get).toOption.get + + def testingContext(h: Int = 614401) = { val boxesToSpend = IndexedSeq(fakeSelf) val preHeader = CPreHeader(activatedVersionInTests, - parentId = header1.id, + parentId = contextHeader.id, timestamp = 3, nBits = 0, height = h, @@ -85,7 +84,7 @@ class TestingInterpreterSpecification extends CompilerTestingCommons ) new ErgoLikeContext( - header1.stateRoot.asInstanceOf[CAvlTree].treeData, Colls.fromArray(Array(header1)), + contextHeader.stateRoot.asInstanceOf[CAvlTree].treeData, Colls.fromArray(Array(contextHeader)), preHeader, noBoxes, boxesToSpend, ErgoLikeTransaction(IndexedSeq.empty, IndexedSeq.empty), boxesToSpend.indexOf(fakeSelf), ContextExtension.empty, vs, DefaultEvalSettings.scriptCostLimitInEvaluator, @@ -455,6 +454,26 @@ class TestingInterpreterSpecification extends CompilerTestingCommons } } + property("bytes") { + + val headerBytes = Base16.encode(contextHeader.bytes.toArray) + + // checking hash of bytes(id) against known value + val source = s""" { + | val h = CONTEXT.headers(0) + | h.bytes == fromBase16("$headerBytes") && + | blake2b256(h.bytes) == h.id && + | h.id == fromBase16("5603a937ec1988220fc44fb5022fb82d5565b961f005ebb55d85bd5a9e6f801f") + | } + | """.stripMargin + + if (activatedVersionInTests < V6SoftForkVersion) { + an [sigmastate.exceptions.MethodNotFound] should be thrownBy testEval(source) + } else { + testEval(source) + } + } + override protected def afterAll(): Unit = { } 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 f3ece3a894..e10c2a0f9b 100644 --- a/sdk/shared/src/main/scala/org/ergoplatform/sdk/JsonCodecs.scala +++ b/sdk/shared/src/main/scala/org/ergoplatform/sdk/JsonCodecs.scala @@ -20,7 +20,7 @@ import sigma.serialization.{ErgoTreeSerializer, ValueSerializer} import sigma.validation.SigmaValidationSettings import sigma.{AnyValue, Coll, Colls, Header, PreHeader, SigmaException} import sigmastate.eval.{CPreHeader, _} -import sigmastate.utils.Helpers._ +import sigmastate.utils.Helpers._ // required for Scala 2.11 import java.math.BigInteger import scala.collection.mutable @@ -148,7 +148,7 @@ trait JsonCodecs { powDistance <- cursor.downField("powDistance").as[sigma.BigInt] votes <- cursor.downField("votes").as[Coll[Byte]] unparsedBytes <- cursor.downField("unparsedBytes").as[Option[Coll[Byte]]] - } yield new CHeader(id, version, parentId, adProofsRoot, stateRoot, transactionsRoot, timestamp, nBits, + } yield CHeader(id, version, parentId, adProofsRoot, stateRoot, transactionsRoot, timestamp, nBits, height, extensionRoot, SigmaDsl.decodePoint(minerPk), SigmaDsl.decodePoint(powOnetimePk), powNonce, powDistance, votes, unparsedBytes.getOrElse(Colls.emptyColl)) }) From 98e2756cb363462b6fd459a6789a9a274e120898 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 6 May 2024 14:07:44 +0300 Subject: [PATCH 014/123] moving failing test from #612 to here --- .../sigmastate/utxo/BasicOpsSpecification.scala | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 79701d6e07..9f8d3c2f79 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -19,6 +19,7 @@ import sigmastate.interpreter.Interpreter._ import sigma.ast.Apply import sigma.eval.EvalSettings import sigma.exceptions.InvalidType +import sigma.serialization.ValueSerializer import sigmastate.utils.Helpers._ import java.math.BigInteger @@ -157,6 +158,17 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } + property("executeFromVar") { + val script = GT(Height, IntConstant(1)).toSigmaProp + val scriptBytes = ValueSerializer.serialize(script) + val customExt = Seq(21.toByte -> ByteArrayConstant(scriptBytes)) + test("executeFromVar", env, customExt, + "executeFromVar[SigmaProp](21)", + null, + true + ) + } + property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", From 624558fdec9a82240e208a7ce2f55c28c4d51d58 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 7 May 2024 17:16:25 +0300 Subject: [PATCH 015/123] executeFromVar tests are passing --- .../src/main/scala/sigma/SigmaDsl.scala | 2 ++ .../main/scala/sigma/ast/SigmaPredef.scala | 33 +++++++++---------- .../scala/sigma/data/CSigmaDslBuilder.scala | 17 ++++++++-- .../sigmastate/interpreter/Interpreter.scala | 2 +- sc/shared/src/main/scala/scalan/Base.scala | 2 +- .../scala/sigmastate/eval/GraphBuilding.scala | 6 ++++ .../scala/special/sigma/SigmaDslUnit.scala | 1 + .../special/sigma/impl/SigmaDslImpl.scala | 14 ++++++++ .../test/scala/sigma/SigmaDslTesting.scala | 2 +- .../utxo/BasicOpsSpecification.scala | 3 +- .../ExecuteFromExamplesSpecification.scala | 5 +-- 11 files changed, 59 insertions(+), 28 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index df2b419273..29142a624c 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -729,5 +729,7 @@ trait SigmaDslBuilder { /** Returns a byte-wise XOR of the two collections of bytes. */ def xor(l: Coll[Byte], r: Coll[Byte]): Coll[Byte] + + def deserialize[T](bytes: Coll[Byte])(implicit cT: RType[T]): T } diff --git a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala index 631f7f2d75..716b167e2b 100644 --- a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala +++ b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala @@ -136,17 +136,6 @@ object SigmaPredef { Seq(ArgInfo("condition", "boolean value to embed in SigmaProp value"))) ) - val GetVarFunc = PredefinedFunc("getVar", - Lambda(Array(paramT), Array("varId" -> SByte), SOption(tT), None), - PredefFuncInfo( - { case (Ident(_, SFunc(_, SOption(rtpe), _)), Seq(id: Constant[SNumericType]@unchecked)) => - mkGetVar(SByte.downcast(id.value.asInstanceOf[AnyVal]), rtpe) - }), - OperationInfo(GetVar, - "Get context variable with given \\lst{varId} and type.", - Seq(ArgInfo("varId", "\\lst{Byte} identifier of context variable"))) - ) - def PKFunc(networkPrefix: NetworkPrefix) = PredefinedFunc("PK", Lambda(Array("input" -> SString), SSigmaProp, None), PredefFuncInfo( @@ -366,13 +355,23 @@ object SigmaPredef { ArgInfo("newValues", "new values to be injected into the corresponding positions in ErgoTree.constants array"))) ) + val GetVarFunc = PredefinedFunc("getVar", + Lambda(Array(paramT), Array("varId" -> SByte), SOption(tT), None), + PredefFuncInfo( + { case (Ident(_, SFunc(_, SOption(rtpe), _)), Seq(id: Constant[SNumericType]@unchecked)) => + mkGetVar(SByte.downcast(id.value.asInstanceOf[AnyVal]), rtpe) + }), + OperationInfo(GetVar, + "Get context variable with given \\lst{varId} and type.", + Seq(ArgInfo("varId", "\\lst{Byte} identifier of context variable"))) + ) + val ExecuteFromVarFunc = PredefinedFunc("executeFromVar", - Lambda( - Seq(paramT), - Array("id" -> SByte), - tT, None - ), - PredefFuncInfo(undefined), + Lambda(Array(paramT), Array("id" -> SByte), tT, None), + PredefFuncInfo( + { case (Ident(_, SFunc(_, rtpe, _)), Seq(id: Constant[SNumericType]@unchecked)) => + mkDeserializeContext(SByte.downcast(id.value.asInstanceOf[AnyVal]), rtpe) + }), OperationInfo(DeserializeContext, """Extracts context variable as \lst{Coll[Byte]}, deserializes it to script | and then executes this script in the current context. diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 3938feacd3..cc5eb3e7d6 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -5,10 +5,12 @@ import org.ergoplatform.ErgoBox import org.ergoplatform.validation.ValidationRules import scorex.crypto.hash.{Blake2b256, Sha256} import scorex.utils.Longs -import sigma.ast.{AtLeast, SubstConstants} +import sigma.Evaluation.stypeToRType +import sigma.ast.{AtLeast, EvaluatedValue, SType, SubstConstants, Value} import sigma.crypto.{CryptoConstants, EcPointType, Ecp} -import sigma.eval.Extensions.EvalCollOps -import sigma.serialization.{GroupElementSerializer, SigmaSerializer} +import sigma.eval.Extensions.{EvalCollOps, toAnyValue} +import sigma.exceptions.InvalidType +import sigma.serialization.{GroupElementSerializer, SigmaSerializer, ValueSerializer} import sigma.util.Extensions.BigIntegerOps import sigma.validation.SigmaValidationSettings import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext} @@ -200,6 +202,15 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => val p = GroupElementSerializer.parse(r) this.GroupElement(p) } + + def deserialize[T](bytes: Coll[Byte])(implicit cT: RType[T]): T = { + val v = ValueSerializer.deserialize(bytes.toArray) + if(stypeToRType(v.tpe) == cT) { + v.asInstanceOf[EvaluatedValue[_]].value.asInstanceOf[T] + } else { + throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: $cT") + } + } } /** Default singleton instance of Global object, which implements global ErgoTree functions. */ diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala index 9a1ab11f0e..8e8da22462 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala @@ -126,7 +126,7 @@ trait Interpreter { case _ => None } - /** Extracts proposition for ErgoTree handing soft-fork condition. + /** Extracts proposition for ErgoTree handling soft-fork condition. * @note soft-fork handler */ protected def propositionFromErgoTree(ergoTree: ErgoTree, context: CTX): SigmaPropValue = { val validationSettings = context.validationSettings diff --git a/sc/shared/src/main/scala/scalan/Base.scala b/sc/shared/src/main/scala/scalan/Base.scala index cc29af45b9..dd4079054f 100644 --- a/sc/shared/src/main/scala/scalan/Base.scala +++ b/sc/shared/src/main/scala/scalan/Base.scala @@ -168,7 +168,7 @@ abstract class Base { scalan: Scalan => /** Create a copy of this definition applying the given transformer to all `syms`. */ def transform(t: Transformer): Def[T] = - !!!(s"Cannot transfrom definition using transform($this)", self) + !!!(s"Cannot transform definition using transform($this)", self) /** Clone this definition transforming all symbols using `t`. * If new Def[A] is created, it is added to the graph with collapsing and rewriting. diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index 5ddcdfa946..c8238f43e2 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -2,6 +2,7 @@ package sigmastate.eval import org.ergoplatform._ import scalan.MutableLazy +import sigma.ast.SCollection.SByteArray import sigma.{SigmaException, ast} import sigma.ast.TypeCodes.LastConstantCode import sigma.ast.Value.Typed @@ -536,6 +537,11 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => val e = stypeToElem(optTpe.elemType) ctx.getVar(id)(e) + case DeserializeContext(id, tpe) => + val e = stypeToElem(tpe) + val og = OptionGet(mkGetVar(id, SByteArray)) + sigmaDslBuilder.deserialize(asRep[Coll[Byte]](eval(og)))(e) + case ValUse(valId, _) => env.getOrElse(valId, !!!(s"ValUse $valId not found in environment $env")) diff --git a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala index 48548226a5..26addccf8d 100644 --- a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala @@ -112,6 +112,7 @@ 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 deserialize[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] }; trait CostModelCompanion; trait BigIntCompanion; diff --git a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala index 70fb35c329..1231f47693 100644 --- a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala @@ -1941,6 +1941,13 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { Array[AnyRef](l, r), true, false, element[Coll[Byte]])) } + + override def deserialize[T](l: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { + asRep[T](mkMethodCall(self, + SigmaDslBuilderClass.getMethod("deserialize", classOf[Sym], classOf[Elem[_]]), + Array[AnyRef](l, cT), + true, false, element[T])) + } } implicit object LiftableSigmaDslBuilder @@ -2100,6 +2107,13 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { Array[AnyRef](l, r), true, true, element[Coll[Byte]])) } + + def deserialize[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { + asRep[T](mkMethodCall(source, + SigmaDslBuilderClass.getMethod("deserialize", classOf[Sym], classOf[Elem[_]]), + Array[AnyRef](bytes, cT), + true, true, element[T])) + } } // entityUnref: single unref method for each type family diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index 46222d9fb1..b398b6808c 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -322,7 +322,7 @@ 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( diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 9f8d3c2f79..e8d355ac24 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -60,7 +60,8 @@ class BasicOpsSpecification extends CompilerTestingCommons "proofVar2" -> CAnyValue(propVar2) ) - def test(name: String, env: ScriptEnv, + def test(name: String, + env: ScriptEnv, ext: Seq[VarBinding], script: String, propExp: SValue, diff --git a/sc/shared/src/test/scala/sigmastate/utxo/examples/ExecuteFromExamplesSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/examples/ExecuteFromExamplesSpecification.scala index b75b404aed..741b4829cf 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/examples/ExecuteFromExamplesSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/examples/ExecuteFromExamplesSpecification.scala @@ -9,8 +9,6 @@ import sigma.ast.ByteArrayConstant class ExecuteFromExamplesSpecification extends CompilerTestingCommons { suite => implicit lazy val IR = new TestingIRContext - private val reg1 = ErgoBox.nonMandatoryRegisters(0) - case class OracleContract[Spec <: ContractSpec] (alice: Spec#ProvingParty) (implicit val spec: Spec) extends SigmaContractSyntax with StdContracts @@ -40,8 +38,7 @@ class ExecuteFromExamplesSpecification extends CompilerTestingCommons { suite => lazy val alice = spec.ProvingParty("Alice") - // TODO soft-fork: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/443 - ignore("Execute from var example (ErgoDsl)") { + property("Execute from var example (ErgoDsl)") { val contract = OracleContract[spec.type](alice)(spec) import contract.spec._ From 690a3e2ec756564f78e0b120d943a5b58fd78df7 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 7 May 2024 19:10:08 +0300 Subject: [PATCH 016/123] Global.deserialize method --- .../sigma/reflection/ReflectionData.scala | 3 ++ .../src/main/scala/sigma/ast/methods.scala | 34 ++++++++++++++++--- .../scala/sigmastate/eval/GraphBuilding.scala | 6 +++- .../special/sigma/impl/SigmaDslImpl.scala | 4 ++- .../utxo/BasicOpsSpecification.scala | 23 +++++++++++++ 5 files changed, 63 insertions(+), 7 deletions(-) diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index 028e68bf72..cecc0f91bd 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -443,6 +443,9 @@ object ReflectionData { }, mkMethod(clazz, "decodePoint", Array[Class[_]](cColl)) { (obj, args) => obj.asInstanceOf[SigmaDslBuilder].decodePoint(args(0).asInstanceOf[Coll[Byte]]) + }, + mkMethod(clazz, "deserialize", Array[Class[_]](cColl, classOf[RType[_]])) { (obj, args) => + obj.asInstanceOf[SigmaDslBuilder].deserialize(args(0).asInstanceOf[Coll[Byte]])(args(1).asInstanceOf[RType[_]]) } ) ) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index e4cf0007e0..9df1d4b456 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -4,8 +4,9 @@ import org.ergoplatform._ import org.ergoplatform.validation._ import sigma._ import sigma.ast.SCollection.{SBooleanArray, SBoxArray, SByteArray, SByteArray2, SHeaderArray} +import sigma.ast.SContextMethods.ContextFuncDom 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.OverloadHack.Overloaded1 import sigma.data.{DataValueComparer, KeyValueColl, Nullable, RType, SigmaConstants} @@ -1510,6 +1511,11 @@ case object SGlobalMethods extends MonoTypeMethods { .withInfo(Xor, "Byte-wise XOR of two collections of bytes", ArgInfo("left", "left operand"), ArgInfo("right", "right operand")) + lazy val deserializeMethod = SMethod( + this, "deserialize", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 3, Xor.costKind) // todo: cost + .withInfo(Xor, "Byte-wise XOR of two collections of bytes", + ArgInfo("left", "left operand"), ArgInfo("right", "right operand")) + /** Implements evaluation of Global.xor method call ErgoTree node. * Called via reflection based on naming convention. * @see SMethod.evalMethod, Xor.eval, Xor.xorWithCosting @@ -1519,9 +1525,27 @@ case object SGlobalMethods extends MonoTypeMethods { Xor.xorWithCosting(ls, rs) } - protected override def getMethods() = super.getMethods() ++ Seq( - groupGeneratorMethod, - xorMethod - ) + + def deserialize_eval[T](mc: MethodCall, G: SigmaDslBuilder, bytes: Coll[Byte], cT: RType[T]) + (implicit E: ErgoTreeEvaluator): T = { + E.addSeqCost(Xor.costKind, bytes.length, Xor.opDesc) { () => // todo: cost + G.deserialize(bytes)(cT) + } + } + + protected override def getMethods() = super.getMethods() ++ { + if (VersionContext.current.isV6SoftForkActivated) { + Seq( + groupGeneratorMethod, + xorMethod, + deserializeMethod + ) + } else { + Seq( + groupGeneratorMethod, + xorMethod + ) + } + } } diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index c8238f43e2..9369eac09e 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -3,7 +3,7 @@ package sigmastate.eval import org.ergoplatform._ import scalan.MutableLazy import sigma.ast.SCollection.SByteArray -import sigma.{SigmaException, ast} +import sigma.{SigmaException, VersionContext, ast} import sigma.ast.TypeCodes.LastConstantCode import sigma.ast.Value.Typed import sigma.ast._ @@ -1139,6 +1139,10 @@ 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 SGlobalMethods.deserializeMethod.name if VersionContext.current.isV6SoftForkActivated => + val c1 = asRep[Coll[Byte]](argsV(0)) + val c2 = argsV(1).asInstanceOf[Elem[_]] + g.deserialize(c1)(c2) case _ => throwError } case _ => throwError diff --git a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala index 1231f47693..df1270315c 100644 --- a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala @@ -2131,7 +2131,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", "deserialize" )) } } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index e8d355ac24..eec55ae4cc 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -2,7 +2,9 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ +import scorex.util.encode.Base16 import sigma.Extensions.ArrayOps +import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder} @@ -159,6 +161,27 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } + property("deserialize - int") { + + val bytes = Base16.encode(ValueSerializer.serialize(IntConstant(5.toShort))) + + if (activatedVersionInTests < V6SoftForkVersion) { + /* an [sigmastate.exceptions.MethodNotFound] should be thrownBy { + test("executeFromVar", env, ext, + s"Global.deserialize[Int](fromBase16(\"$bytes\")) == 5", + null, + true + ) + } */ + } else { + test("executeFromVar", env, ext, + s"Global.deserialize[Int](fromBase16(\"$bytes\")) == 5", + null, + true + ) + } + } + property("executeFromVar") { val script = GT(Height, IntConstant(1)).toSigmaProp val scriptBytes = ValueSerializer.serialize(script) From 023ad097483a619df4da836d4a4f52bbad29e933 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 8 May 2024 23:15:22 +0300 Subject: [PATCH 017/123] deserialize int - test passing --- .../src/main/scala/sigma/ast/methods.scala | 10 ++- .../serialization/MethodCallSerializer.scala | 16 ++++- .../scala/sigmastate/eval/GraphBuilding.scala | 30 +++++++-- .../scala/sigmastate/eval/TreeBuilding.scala | 14 +++- .../scala/sigmastate/lang/SigmaTyper.scala | 17 ++++- .../special/sigma/impl/SigmaDslImpl.scala | 14 +++- .../scala/sigmastate/CompilerTestsBase.scala | 2 +- .../utxo/BasicOpsSpecification.scala | 65 ++++++++++++++----- 8 files changed, 136 insertions(+), 32 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 9df1d4b456..e948346868 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -2,9 +2,9 @@ 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.SContextMethods.ContextFuncDom import sigma.ast.SMethod.{MethodCallIrBuilder, MethodCostFunc, javaMethodOf} import sigma.ast.SType.{TypeCode, paramT, tT} import sigma.ast.syntax.{SValue, ValueOps} @@ -1511,8 +1511,11 @@ case object SGlobalMethods extends MonoTypeMethods { .withInfo(Xor, "Byte-wise XOR of two collections of bytes", ArgInfo("left", "left operand"), ArgInfo("right", "right operand")) + lazy val desJava = ownerType.reprClass.getMethod("deserialize", classOf[Coll[Byte]], classOf[RType[_]]) + lazy val deserializeMethod = SMethod( this, "deserialize", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 3, Xor.costKind) // todo: cost + .copy(irInfo = MethodIRInfo(None, Some(desJava), None)) .withInfo(Xor, "Byte-wise XOR of two collections of bytes", ArgInfo("left", "left operand"), ArgInfo("right", "right operand")) @@ -1526,8 +1529,9 @@ case object SGlobalMethods extends MonoTypeMethods { } - def deserialize_eval[T](mc: MethodCall, G: SigmaDslBuilder, bytes: Coll[Byte], cT: RType[T]) - (implicit E: ErgoTreeEvaluator): T = { + def deserialize_eval(mc: MethodCall, G: SigmaDslBuilder, bytes: Coll[Byte]) + (implicit E: ErgoTreeEvaluator): Any = { + val cT = stypeToRType(mc.tpe) E.addSeqCost(Xor.costKind, bytes.length, Xor.opDesc) { () => // todo: cost G.deserialize(bytes)(cT) } diff --git a/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala b/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala index 319a4284e2..693e66d57e 100644 --- a/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala +++ b/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala @@ -1,11 +1,12 @@ package sigma.serialization import sigma.ast.syntax._ -import sigma.ast.{MethodCall, SContextMethods, SMethod, SType, STypeSubst, Value, ValueCompanion} +import sigma.ast.{MethodCall, SContextMethods, SGlobalMethods, SMethod, SType, STypeSubst, Value, ValueCompanion} import sigma.util.safeNewArray import SigmaByteWriter._ import debox.cfor import sigma.ast.SContextMethods.BlockchainContextMethodNames +import sigma.ast.SType.tT import sigma.serialization.CoreByteWriter.{ArgInfo, DataInfo} case class MethodCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value[SType]], STypeSubst) => Value[SType]) @@ -15,6 +16,7 @@ case class MethodCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value[S val methodCodeInfo: DataInfo[Byte] = ArgInfo("methodCode", "a code of the method") val objInfo: DataInfo[SValue] = ArgInfo("obj", "receiver object of this method call") val argsInfo: DataInfo[Seq[SValue]] = ArgInfo("args", "arguments of the method call") + val typeInfo: DataInfo[SType] = ArgInfo("type", "expected type of method result") val argsItemInfo = valuesItemInfo(argsInfo) override def serialize(mc: MethodCall, w: SigmaByteWriter): Unit = { @@ -23,6 +25,9 @@ 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) + if(mc.method.name == SGlobalMethods.deserializeMethod.name){ + w.putType(mc.tpe, typeInfo) + } } /** The SMethod instances in STypeCompanions may have type STypeIdent in methods types, @@ -57,10 +62,17 @@ case class MethodCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value[S val specMethod = method.specializeFor(obj.tpe, types) + val subst: STypeSubst = if(method.name == SGlobalMethods.deserializeMethod.name) { + val tpe = r.getType() + Map(tT -> tpe) + } else { + Map.empty + } + var isUsingBlockchainContext = specMethod.objType == SContextMethods && BlockchainContextMethodNames.contains(method.name) r.wasUsingBlockchainContext ||= isUsingBlockchainContext - cons(obj, specMethod, args, Map.empty) + cons(obj, specMethod, args, subst) } } diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index 9369eac09e..31cb06e698 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -20,6 +20,25 @@ import sigma.serialization.OpCodes import scala.collection.mutable.ArrayBuffer + +case class DeserializeBytes[V <: SType](bytes: Value[SByteArray], tpe: V) extends NotReadyValue[V] { + /** The companion node descriptor with opCode, cost and other metadata. */ + override def companion: ValueCompanion = ??? + + /** Every value represents an operation and that operation can be associated with a function type, + * describing functional meaning of the operation, kind of operation signature. + * Thus, we can obtain global operation identifiers by combining Value.opName with Value.opType, + * so that if (v1.opName == v2.opName) && (v1.opType == v2.opType) then v1 and v2 are functionally + * point-wise equivalent. + * This in particular means that if two _different_ ops have the same opType they _should_ have + * different opNames. + * Thus defined op ids are used in a v4.x Cost Model - a table of all existing primitives coupled with + * performance parameters. + * */ + override def opType: SFunc = Value.notSupportedError(this, "opType") +} + + /** Perform translation of typed expression given by [[Value]] to a graph in IRContext. * Which be than be translated to [[ErgoTree]] by using [[TreeBuilding]]. * @@ -537,10 +556,11 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => val e = stypeToElem(optTpe.elemType) ctx.getVar(id)(e) + case DeserializeBytes(bytes, tpe) => + sigmaDslBuilder.deserialize(asRep[Coll[Byte]](eval(bytes)))(stypeToElem(tpe)) + case DeserializeContext(id, tpe) => - val e = stypeToElem(tpe) - val og = OptionGet(mkGetVar(id, SByteArray)) - sigmaDslBuilder.deserialize(asRep[Coll[Byte]](eval(og)))(e) + eval(DeserializeBytes(OptionGet(mkGetVar(id, SByteArray)), tpe)) case ValUse(valId, _) => env.getOrElse(valId, !!!(s"ValUse $valId not found in environment $env")) @@ -921,7 +941,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 { @@ -1141,7 +1161,7 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => g.xor(c1, c2) case SGlobalMethods.deserializeMethod.name if VersionContext.current.isV6SoftForkActivated => val c1 = asRep[Coll[Byte]](argsV(0)) - val c2 = argsV(1).asInstanceOf[Elem[_]] + val c2 = stypeToElem(method.stype.tRange.withSubstTypes(typeSubst)) g.deserialize(c1)(c2) case _ => throwError } diff --git a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala index 27f659c1ed..09dc06535f 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala @@ -3,6 +3,7 @@ package sigmastate.eval import sigma.ast._ import org.ergoplatform._ +import sigma.ast.SType.tT import sigma.ast.syntax.ValueOps import sigma.serialization.OpCodes._ import sigma.serialization.ConstantStore @@ -218,6 +219,10 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext => val tpe = elemToSType(eVar) mkGetVar(id, tpe) + case SDBM.deserialize(g, bytes, eVar) => + val tpe = elemToSType(eVar) + builder.mkMethodCall(recurse(g), SGlobalMethods.deserializeMethod, IndexedSeq(recurse(bytes)), Map(tT -> tpe): STypeSubst) + case BIM.subtract(In(x), In(y)) => mkArith(x.asNumValue, y.asNumValue, MinusCode) case BIM.add(In(x), In(y)) => @@ -397,13 +402,18 @@ 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 d@Def(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: STypeSubst = if(m.getName == SGlobalMethods.deserializeMethod.name) { + Map.empty + } else { + Map.empty + } + builder.mkMethodCall(obj, specMethod, args.toIndexedSeq, typeSubst) case None => error(s"Cannot find method ${m.getName} in object $obj") } diff --git a/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala b/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala index 7fd6dadd45..991b3ce064 100644 --- a/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala +++ b/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala @@ -1,6 +1,5 @@ package sigmastate.lang -import org.ergoplatform._ import sigma.ast.SCollection.{SBooleanArray, SByteArray} import sigma.ast._ import sigma.ast.syntax.SValue @@ -11,6 +10,7 @@ import SigmaPredef._ import sigma.ast.syntax._ import sigma.exceptions.TyperException import sigma.serialization.OpCodes +import sigmastate.eval.DeserializeBytes import scala.collection.mutable.ArrayBuffer @@ -33,7 +33,7 @@ class SigmaTyper(val builder: SigmaBuilder, private def processGlobalMethod(srcCtx: Nullable[SourceContext], method: SMethod, - args: IndexedSeq[SValue]) = { + args: IndexedSeq[SValue]): SValue = { val global = Global.withPropagatedSrcCtx(srcCtx) val node = for { pf <- method.irInfo.irBuilder if lowerMethodCalls @@ -133,6 +133,19 @@ class SigmaTyper(val builder: SigmaBuilder, val newObj = assignType(env, obj) val newArgs = args.map(assignType(env, _)) obj.tpe match { + case SGlobal => + SGlobalMethods.method(n) match { + case Some(method) => + val srcCtx = sel.sourceContext + if(method.name == SGlobalMethods.deserializeMethod.name) { + val global = Global.withPropagatedSrcCtx(srcCtx) + DeserializeBytes(args(0).asInstanceOf[Value[SByteArray]], rangeTpe) + } else { + processGlobalMethod(srcCtx, method, newArgs) + } + case _ => + error(s"Cannot find Global method: $n", bound.sourceContext) + } case p: SProduct => MethodsContainer.getMethod(p, n) match { case Some(method @ SMethod(_, _, genFunTpe @ SFunc(_, _, _), _, _, _, _, _)) => diff --git a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala index df1270315c..efdb3dbda0 100644 --- a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala @@ -1944,7 +1944,7 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { override def deserialize[T](l: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { asRep[T](mkMethodCall(self, - SigmaDslBuilderClass.getMethod("deserialize", classOf[Sym], classOf[Elem[_]]), + SigmaDslBuilderClass.getMethod("deserialize", classOf[Sym], classOf[Elem[T]]), Array[AnyRef](l, cT), true, false, element[T])) } @@ -2110,7 +2110,7 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { def deserialize[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { asRep[T](mkMethodCall(source, - SigmaDslBuilderClass.getMethod("deserialize", classOf[Sym], classOf[Elem[_]]), + SigmaDslBuilderClass.getMethod("deserialize", classOf[Sym], classOf[Elem[T]]), Array[AnyRef](bytes, cT), true, true, element[T])) } @@ -2312,6 +2312,16 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { def unapply(exp: Sym): Nullable[(Ref[SigmaDslBuilder], Ref[Coll[Byte]])] = unapply(exp.node) } + object deserialize { + def unapply(d: Def[_]): Nullable[(Ref[SigmaDslBuilder], Ref[Coll[Byte]], Elem[T]) forSome {type T}] = d match { + case MethodCall(receiver, method, args, _) if method.getName == "deserialize" && receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] => + val res = (receiver, args(0), args(1)) + Nullable(res).asInstanceOf[Nullable[(Ref[SigmaDslBuilder], Ref[Coll[Byte]], Elem[T]) forSome {type T}]] + case _ => Nullable.None + } + def unapply(exp: Sym): Nullable[(Ref[SigmaDslBuilder], Ref[Coll[Byte]], Elem[T]) forSome {type T}] = unapply(exp.node) + } + /** This is necessary to handle CreateAvlTree in GraphBuilding (v6.0) */ object avlTree { def unapply(d: Def[_]): Nullable[(Ref[SigmaDslBuilder], Ref[Byte], Ref[Coll[Byte]], Ref[Int], Ref[WOption[Int]])] = d match { diff --git a/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala b/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala index 28f907c199..a5ae8f1bce 100644 --- a/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala +++ b/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala @@ -38,7 +38,7 @@ trait CompilerTestsBase extends TestsBase { def checkSerializationRoundTrip(v: SValue): Unit = { val compiledTreeBytes = ValueSerializer.serialize(v) withClue(s"(De)Serialization roundtrip failed for the tree:") { - ValueSerializer.deserialize(compiledTreeBytes) shouldEqual v + ValueSerializer.deserialize(compiledTreeBytes) shouldEqual v } } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index eec55ae4cc..ed84c02c33 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -3,6 +3,7 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ import scorex.util.encode.Base16 +import sigma.Colls import sigma.Extensions.ArrayOps import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray @@ -87,8 +88,9 @@ 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 + } else { compile(env, script).asBoolValue.toSigmaProp + } if (propExp != null) prop shouldBe propExp @@ -163,34 +165,67 @@ class BasicOpsSpecification extends CompilerTestingCommons property("deserialize - int") { - val bytes = Base16.encode(ValueSerializer.serialize(IntConstant(5.toShort))) + val bytes = Base16.encode(ValueSerializer.serialize(IntConstant(5))) if (activatedVersionInTests < V6SoftForkVersion) { - /* an [sigmastate.exceptions.MethodNotFound] should be thrownBy { - test("executeFromVar", env, ext, + an [sigma.exceptions.TyperException] should be thrownBy { + test("deserialize", env, ext, s"Global.deserialize[Int](fromBase16(\"$bytes\")) == 5", null, true ) - } */ + } } else { - test("executeFromVar", env, ext, - s"Global.deserialize[Int](fromBase16(\"$bytes\")) == 5", + test("deserialize", env, ext, + s"{ val ba = fromBase16(\"$bytes\"); Global.deserialize[Int](ba) == 5 }", null, true ) } } +/* + todo: fix + property("deserialize - coll") { - property("executeFromVar") { - val script = GT(Height, IntConstant(1)).toSigmaProp - val scriptBytes = ValueSerializer.serialize(script) - val customExt = Seq(21.toByte -> ByteArrayConstant(scriptBytes)) - test("executeFromVar", env, customExt, - "executeFromVar[SigmaProp](21)", - null, - true + val bytes = Base16.encode(ValueSerializer.serialize(CollectionConstant[SInt.type](Colls.fromArray(Array(IntConstant(5).value)), SInt))) + + if (activatedVersionInTests < V6SoftForkVersion) { + an [sigma.exceptions.TyperException] should be thrownBy { + test("deserialize", env, ext, + s"Global.deserialize[Coll[Int]](fromBase16(\"$bytes\")).apply(0) == 5", + null, + true + ) + } + } else { + test("deserialize", env, ext, + s"Global.deserialize[Coll[Int]](fromBase16(\"$bytes\")).apply(0) == 5", + null, + true + ) + } + } + + property("getVar") { + test("getVar", env, ext, + "{ allOf(Coll(CONTEXT.getVar[Boolean](trueVar).get, true, true)) }", + AND(GetVarBoolean(booleanVar).get, TrueLeaf, TrueLeaf).toSigmaProp ) + } */ + + property("executeFromVar") { + if (activatedVersionInTests < V6SoftForkVersion) { + + } else { + val script = GT(Height, IntConstant(1)).toSigmaProp + val scriptBytes = ValueSerializer.serialize(script) + val customExt = Seq(21.toByte -> ByteArrayConstant(scriptBytes)) + test("executeFromVar", env, customExt, + "executeFromVar[SigmaProp](21)", + null, + true + ) + } } property("Relation operations") { From 76481823fa7f16a7e81b89f95629e264d9b05a2a Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 9 May 2024 11:21:15 +0300 Subject: [PATCH 018/123] unused code removal --- sc/shared/src/main/scala/scalan/Base.scala | 6 ------ .../src/main/scala/sigmastate/eval/GraphBuilding.scala | 5 +++-- .../src/main/scala/sigmastate/eval/TreeBuilding.scala | 9 ++------- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/sc/shared/src/main/scala/scalan/Base.scala b/sc/shared/src/main/scala/scalan/Base.scala index dd4079054f..aecb9cb2ec 100644 --- a/sc/shared/src/main/scala/scalan/Base.scala +++ b/sc/shared/src/main/scala/scalan/Base.scala @@ -202,12 +202,6 @@ abstract class Base { scalan: Scalan => } } - /** Logical AND between two pattern matches of the save value `x`. - * Can be used to construct patterns like `case P1 && P2 => ...` */ - object && { - def unapply[T](x: T): Option[(T,T)] = Some((x, x)) - } - /** Base class for virtualized instances of type companions. * Each virtualized entity type (trait or class) may have virtualized companion class. */ abstract class CompanionDef[T] extends Def[T] { diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index 31cb06e698..d20b10f7d4 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -559,8 +559,9 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => case DeserializeBytes(bytes, tpe) => sigmaDslBuilder.deserialize(asRep[Coll[Byte]](eval(bytes)))(stypeToElem(tpe)) - case DeserializeContext(id, tpe) => - eval(DeserializeBytes(OptionGet(mkGetVar(id, SByteArray)), tpe)) + case d@DeserializeContext(_, _) => + ??? + // eval(DeserializeBytes(OptionGet(mkGetVar(id, SByteArray)), tpe)) case ValUse(valId, _) => env.getOrElse(valId, !!!(s"ValUse $valId not found in environment $env")) diff --git a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala index 09dc06535f..52d35736dc 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala @@ -402,18 +402,13 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext => mkMultiplyGroup(obj.asGroupElement, arg.asGroupElement) // Fallback MethodCall rule: should be the last in this list of cases - case d@Def(MethodCall(objSym, m, argSyms, _)) => + case Def(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)) - val typeSubst: STypeSubst = if(m.getName == SGlobalMethods.deserializeMethod.name) { - Map.empty - } else { - Map.empty - } - builder.mkMethodCall(obj, specMethod, args.toIndexedSeq, typeSubst) + builder.mkMethodCall(obj, specMethod, args.toIndexedSeq, Map.empty) case None => error(s"Cannot find method ${m.getName} in object $obj") } From 79b4d11a370788bbb9acb869c45b8169f01947ff Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 9 May 2024 13:32:04 +0300 Subject: [PATCH 019/123] executeFromVar is passing for SigmaProp --- sc/shared/src/main/scala/scalan/Base.scala | 9 +++- .../scala/sigmastate/eval/GraphBuilding.scala | 3 +- .../scala/sigmastate/eval/TreeBuilding.scala | 3 ++ .../utxo/BasicOpsSpecification.scala | 53 ++++++++++--------- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/sc/shared/src/main/scala/scalan/Base.scala b/sc/shared/src/main/scala/scalan/Base.scala index aecb9cb2ec..c18eddfc14 100644 --- a/sc/shared/src/main/scala/scalan/Base.scala +++ b/sc/shared/src/main/scala/scalan/Base.scala @@ -1,6 +1,7 @@ package scalan import debox.{cfor, Buffer => DBuffer} +import sigma.ast.{DeserializeContext, SType} import sigma.data.{AVHashMap, Nullable, RType} import sigma.data.OverloadHack.Overloaded1 import sigma.util.StringUtil @@ -202,6 +203,13 @@ abstract class Base { scalan: Scalan => } } + case class DeserializeContextDef[V <: SType](d: DeserializeContext[V]) extends Def[V] { + /** Type of a resulting value produced by the operation represented by this definition. + * For example, if this definition represents application of `+: (Int, Int) => Int` operation + * then the result type is Int and `resultType` should return IntElement. */ + override def resultType: Elem[V] = ??? + } + /** Base class for virtualized instances of type companions. * Each virtualized entity type (trait or class) may have virtualized companion class. */ abstract class CompanionDef[T] extends Def[T] { @@ -376,7 +384,6 @@ abstract class Base { scalan: Scalan => /** Returns the string like `x45: Int = Const(10)` */ def toStringWithDefinition: String def varNameWithType = varName + ":" + elem.name - } /** Untyped shortcut sinonim of Ref, which is used as untyped reference to graph nodes (definitions). diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index d20b10f7d4..3be5ef6db1 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -560,8 +560,7 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => sigmaDslBuilder.deserialize(asRep[Coll[Byte]](eval(bytes)))(stypeToElem(tpe)) case d@DeserializeContext(_, _) => - ??? - // eval(DeserializeBytes(OptionGet(mkGetVar(id, SByteArray)), tpe)) + DeserializeContextDef(d) case ValUse(valId, _) => env.getOrElse(valId, !!!(s"ValUse $valId not found in environment $env")) diff --git a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala index 52d35736dc..3fe2f2f4ce 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala @@ -188,6 +188,9 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext => val tpe = elemToSType(s.elem) mkConstant[tpe.type](wc.constValue.asInstanceOf[tpe.WrappedType], tpe) + case Def(DeserializeContextDef(d)) => + d + case Def(IsContextProperty(v)) => v case s if s == sigmaDslBuilder => Global diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index ed84c02c33..5172109674 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -166,21 +166,16 @@ class BasicOpsSpecification extends CompilerTestingCommons property("deserialize - int") { val bytes = Base16.encode(ValueSerializer.serialize(IntConstant(5))) + def deserTest() = {test("deserialize", env, ext, + s"{ val ba = fromBase16(\"$bytes\"); Global.deserialize[Int](ba) == 5 }", + null, + true + )} if (activatedVersionInTests < V6SoftForkVersion) { - an [sigma.exceptions.TyperException] should be thrownBy { - test("deserialize", env, ext, - s"Global.deserialize[Int](fromBase16(\"$bytes\")) == 5", - null, - true - ) - } + an [sigma.exceptions.TyperException] should be thrownBy deserTest() } else { - test("deserialize", env, ext, - s"{ val ba = fromBase16(\"$bytes\"); Global.deserialize[Int](ba) == 5 }", - null, - true - ) + deserTest() } } /* @@ -213,21 +208,29 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } */ - property("executeFromVar") { - if (activatedVersionInTests < V6SoftForkVersion) { - - } else { - val script = GT(Height, IntConstant(1)).toSigmaProp - val scriptBytes = ValueSerializer.serialize(script) - val customExt = Seq(21.toByte -> ByteArrayConstant(scriptBytes)) - test("executeFromVar", env, customExt, - "executeFromVar[SigmaProp](21)", - null, - true - ) - } + property("executeFromVar - SigmaProp") { + val script = GT(Height, IntConstant(-1)).toSigmaProp + val scriptBytes = ValueSerializer.serialize(script) + val customExt = Seq(21.toByte -> ByteArrayConstant(scriptBytes)) + test("executeFromVar", env, customExt, + "executeFromVar[SigmaProp](21)", + null, + true + ) } + /* todo: fix + property("executeFromVar - Coll[Byte]") { + val bytes = ByteArrayConstant(Colls.fromArray(Array.fill(5)(1.toByte))) + val valueBytes = ValueSerializer.serialize(bytes) + val customExt = Seq(21.toByte -> ByteArrayConstant(valueBytes)) + test("executeFromVar", env, customExt, + "{val ba = executeFromVar[Coll[Byte]](21); ba.size == 5 }", + null, + true + ) + } */ + property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", From a470406738644485606ee2898d1afb7a8d36d341 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 9 May 2024 14:28:39 +0300 Subject: [PATCH 020/123] more executeFromVar and deserialize tests, all passing --- sc/shared/src/main/scala/scalan/Base.scala | 4 +-- .../scala/sigmastate/eval/GraphBuilding.scala | 5 ++-- .../scala/sigmastate/eval/TreeBuilding.scala | 2 +- .../utxo/BasicOpsSpecification.scala | 27 ++++++++++++------- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/sc/shared/src/main/scala/scalan/Base.scala b/sc/shared/src/main/scala/scalan/Base.scala index c18eddfc14..d40a0dabe9 100644 --- a/sc/shared/src/main/scala/scalan/Base.scala +++ b/sc/shared/src/main/scala/scalan/Base.scala @@ -203,11 +203,11 @@ abstract class Base { scalan: Scalan => } } - case class DeserializeContextDef[V <: SType](d: DeserializeContext[V]) extends Def[V] { + case class DeserializeContextDef[V <: SType](d: DeserializeContext[V], e: Elem[V]) extends Def[V] { /** Type of a resulting value produced by the operation represented by this definition. * For example, if this definition represents application of `+: (Int, Int) => Int` operation * then the result type is Int and `resultType` should return IntElement. */ - override def resultType: Elem[V] = ??? + override def resultType: Elem[V] = e } /** Base class for virtualized instances of type companions. diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index 3be5ef6db1..ef78790db7 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -559,8 +559,9 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => case DeserializeBytes(bytes, tpe) => sigmaDslBuilder.deserialize(asRep[Coll[Byte]](eval(bytes)))(stypeToElem(tpe)) - case d@DeserializeContext(_, _) => - DeserializeContextDef(d) + case d: DeserializeContext[T] => + val e = stypeToElem(d.tpe).asInstanceOf[Elem[T]] + DeserializeContextDef(d, e) case ValUse(valId, _) => env.getOrElse(valId, !!!(s"ValUse $valId not found in environment $env")) diff --git a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala index 3fe2f2f4ce..2071e7b0d1 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala @@ -188,7 +188,7 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext => val tpe = elemToSType(s.elem) mkConstant[tpe.type](wc.constValue.asInstanceOf[tpe.WrappedType], tpe) - case Def(DeserializeContextDef(d)) => + case Def(DeserializeContextDef(d, _)) => d case Def(IsContextProperty(v)) => v diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 5172109674..5b63afaa44 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -8,7 +8,7 @@ import sigma.Extensions.ArrayOps import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps -import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder} +import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder, ProveDlog} import sigma.util.StringUtil._ import sigma.ast._ import sigma.ast.syntax._ @@ -178,8 +178,7 @@ class BasicOpsSpecification extends CompilerTestingCommons deserTest() } } -/* - todo: fix + property("deserialize - coll") { val bytes = Base16.encode(ValueSerializer.serialize(CollectionConstant[SInt.type](Colls.fromArray(Array(IntConstant(5).value)), SInt))) @@ -187,20 +186,21 @@ class BasicOpsSpecification extends CompilerTestingCommons if (activatedVersionInTests < V6SoftForkVersion) { an [sigma.exceptions.TyperException] should be thrownBy { test("deserialize", env, ext, - s"Global.deserialize[Coll[Int]](fromBase16(\"$bytes\")).apply(0) == 5", + s"{val ba = fromBase16(\"$bytes\"); val coll = Global.deserialize[Coll[Int]](ba); coll(0) == 5 }", null, true ) } } else { test("deserialize", env, ext, - s"Global.deserialize[Coll[Int]](fromBase16(\"$bytes\")).apply(0) == 5", + s"{val ba = fromBase16(\"$bytes\"); val coll = Global.deserialize[Coll[Int]](ba); coll(0) == 5 }", null, true ) } } + /* property("getVar") { test("getVar", env, ext, "{ allOf(Coll(CONTEXT.getVar[Boolean](trueVar).get, true, true)) }", @@ -219,17 +219,26 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - /* todo: fix + property("executeFromVar - Int") { + val valueBytes = ValueSerializer.serialize(Plus(IntConstant(2), IntConstant(3))) + val customExt = Seq(21.toByte -> ByteArrayConstant(valueBytes)) + test("executeFromVar", env, customExt, + "{ executeFromVar[Int](21) == 5 }", + null, + true + ) + } + property("executeFromVar - Coll[Byte]") { - val bytes = ByteArrayConstant(Colls.fromArray(Array.fill(5)(1.toByte))) + val bytes = Slice(ByteArrayConstant(Colls.fromArray(Array.fill(5)(1.toByte))), IntConstant(1), IntConstant(3)) val valueBytes = ValueSerializer.serialize(bytes) val customExt = Seq(21.toByte -> ByteArrayConstant(valueBytes)) test("executeFromVar", env, customExt, - "{val ba = executeFromVar[Coll[Byte]](21); ba.size == 5 }", + "{val ba = executeFromVar[Coll[Byte]](21); ba.size == 2 }", null, true ) - } */ + } property("Relation operations") { test("R1", env, ext, From c1947d46f95e4a8057edb556b1142163caab2ec2 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 9 May 2024 15:05:24 +0300 Subject: [PATCH 021/123] negative test for DeserializeContext in executeFromVar, new stubs for deserialize test --- .../scala/sigma/data/CSigmaDslBuilder.scala | 13 +++-- .../utxo/BasicOpsSpecification.scala | 54 ++++++++++++++----- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index cc5eb3e7d6..7ec227a06c 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -16,6 +16,7 @@ import sigma.validation.SigmaValidationSettings import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext} import java.math.BigInteger +import scala.reflect.ClassTag /** A default implementation of [[SigmaDslBuilder]] interface. * @@ -204,12 +205,16 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => } def deserialize[T](bytes: Coll[Byte])(implicit cT: RType[T]): T = { - val v = ValueSerializer.deserialize(bytes.toArray) - if(stypeToRType(v.tpe) == cT) { - v.asInstanceOf[EvaluatedValue[_]].value.asInstanceOf[T] - } else { + if(!cT.isInstanceOf[PrimitiveType[_]]) { throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: $cT") } + + cT.classTag match { + case ClassTag.Int => scorex.utils.Ints.fromByteArray(bytes.toArray).asInstanceOf[T] + case BoxClassTag => scorex.utils.Ints.fromByteArray(bytes.toArray).asInstanceOf[T] + case _ => + throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: $cT") + } } } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 5b63afaa44..275c32171c 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -3,7 +3,8 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ import scorex.util.encode.Base16 -import sigma.Colls +import scorex.utils.Ints +import sigma.{Colls, SigmaProp} import sigma.Extensions.ArrayOps import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray @@ -164,8 +165,7 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("deserialize - int") { - - val bytes = Base16.encode(ValueSerializer.serialize(IntConstant(5))) + val bytes = Base16.encode(Ints.toByteArray(5)) def deserTest() = {test("deserialize", env, ext, s"{ val ba = fromBase16(\"$bytes\"); Global.deserialize[Int](ba) == 5 }", null, @@ -183,23 +183,42 @@ class BasicOpsSpecification extends CompilerTestingCommons val bytes = Base16.encode(ValueSerializer.serialize(CollectionConstant[SInt.type](Colls.fromArray(Array(IntConstant(5).value)), SInt))) - if (activatedVersionInTests < V6SoftForkVersion) { - an [sigma.exceptions.TyperException] should be thrownBy { - test("deserialize", env, ext, - s"{val ba = fromBase16(\"$bytes\"); val coll = Global.deserialize[Coll[Int]](ba); coll(0) == 5 }", - null, - true - ) - } - } else { + def deserTest() = { test("deserialize", env, ext, s"{val ba = fromBase16(\"$bytes\"); val coll = Global.deserialize[Coll[Int]](ba); coll(0) == 5 }", null, true ) } + + if (activatedVersionInTests < V6SoftForkVersion) { + an [sigma.exceptions.TyperException] should be thrownBy deserTest() + } else { + an [java.lang.reflect.InvocationTargetException] should be thrownBy deserTest() + } + } + + property("deserialize - long roundtrip") { + + } + + property("deserialize - box") { + + } + + property("deserialize - bigint") { + + } + + property("deserialize - header") { + } + property("deserialize - short") { + + } + + /* property("getVar") { test("getVar", env, ext, @@ -240,6 +259,17 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } + property("executeFromVar - deserialize") { + val script = DeserializeContext(21.toByte, SSigmaProp) + val scriptBytes = ValueSerializer.serialize(script) + val customExt = Seq(21.toByte -> ByteArrayConstant(scriptBytes)) + an [Exception] should be thrownBy test("executeFromVar", env, customExt, + "executeFromVar[SigmaProp](21)", + null, + true + ) + } + property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", From cec0adda39dfc9909d795b643c82de35644a07c2 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 9 May 2024 15:35:50 +0300 Subject: [PATCH 022/123] long roundtrip --- .../scala/sigma/data/CSigmaDslBuilder.scala | 7 ++++--- .../sigmastate/utxo/BasicOpsSpecification.scala | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 7ec227a06c..99f247bc21 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -209,12 +209,13 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: $cT") } - cT.classTag match { - case ClassTag.Int => scorex.utils.Ints.fromByteArray(bytes.toArray).asInstanceOf[T] - case BoxClassTag => scorex.utils.Ints.fromByteArray(bytes.toArray).asInstanceOf[T] + val res = cT.classTag match { + case ClassTag.Int => scorex.utils.Ints.fromByteArray(bytes.toArray) + case ClassTag.Long => scorex.utils.Longs.fromByteArray(bytes.toArray) case _ => throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: $cT") } + res.asInstanceOf[T] } } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 275c32171c..a6630ee48c 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -194,12 +194,27 @@ class BasicOpsSpecification extends CompilerTestingCommons if (activatedVersionInTests < V6SoftForkVersion) { an [sigma.exceptions.TyperException] should be thrownBy deserTest() } else { + // only primitive types are supported, so the test fails an [java.lang.reflect.InvocationTargetException] should be thrownBy deserTest() } } property("deserialize - long roundtrip") { - + def deserTest() = test("deserialize", env, ext, + s"""{ + val l = 5L; + val ba = longToByteArray(l); + Global.deserialize[Long](ba) == l + }""", + null, + true + ) + + if (activatedVersionInTests < V6SoftForkVersion) { + an [sigma.exceptions.TyperException] should be thrownBy deserTest() + } else { + deserTest() + } } property("deserialize - box") { From 838a6172ecd279bb7dad64807ed4a1d470ee416a Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 10 May 2024 18:14:00 +0300 Subject: [PATCH 023/123] box rouundtrip test --- .../main/scala/sigma/data/CSigmaDslBuilder.scala | 15 +++++++-------- .../sigmastate/utxo/BasicOpsSpecification.scala | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 99f247bc21..035fde1949 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -6,7 +6,7 @@ import org.ergoplatform.validation.ValidationRules import scorex.crypto.hash.{Blake2b256, Sha256} import scorex.utils.Longs import sigma.Evaluation.stypeToRType -import sigma.ast.{AtLeast, EvaluatedValue, SType, SubstConstants, Value} +import sigma.ast.{AtLeast, BoxConstant, EvaluatedValue, SType, SubstConstants, Value} import sigma.crypto.{CryptoConstants, EcPointType, Ecp} import sigma.eval.Extensions.{EvalCollOps, toAnyValue} import sigma.exceptions.InvalidType @@ -16,7 +16,7 @@ import sigma.validation.SigmaValidationSettings import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext} import java.math.BigInteger -import scala.reflect.ClassTag +import scala.reflect.{ClassTag, classTag} /** A default implementation of [[SigmaDslBuilder]] interface. * @@ -205,15 +205,14 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => } def deserialize[T](bytes: Coll[Byte])(implicit cT: RType[T]): T = { - if(!cT.isInstanceOf[PrimitiveType[_]]) { - throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: $cT") - } + val ba = bytes.toArray val res = cT.classTag match { - case ClassTag.Int => scorex.utils.Ints.fromByteArray(bytes.toArray) - case ClassTag.Long => scorex.utils.Longs.fromByteArray(bytes.toArray) + case ClassTag.Int => scorex.utils.Ints.fromByteArray(ba) + case ClassTag.Long => scorex.utils.Longs.fromByteArray(ba) + case sigma.data.BoxClassTag => CBox(ErgoBox.sigmaSerializer.fromBytes(ba)) case _ => - throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: $cT") + throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: ${cT.classTag}") } res.asInstanceOf[T] } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index a6630ee48c..235b422966 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -217,8 +217,22 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - box") { + property("deserialize - box rountrip") { + def deserTest() = test("deserialize", env, ext, + s"""{ + val b = INPUTS(0); + val ba = b.bytes; + Global.deserialize[Box](ba) == b + }""", + null, + true + ) + if (activatedVersionInTests < V6SoftForkVersion) { + an [sigma.exceptions.TyperException] should be thrownBy deserTest() + } else { + deserTest() + } } property("deserialize - bigint") { From fd589a8cf2447375b2e8028dc73cf7b49ceceac8 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 10 May 2024 18:26:45 +0300 Subject: [PATCH 024/123] bigInt test --- .../main/scala/sigma/data/CSigmaDslBuilder.scala | 9 ++++----- .../sigmastate/utxo/BasicOpsSpecification.scala | 13 +++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 035fde1949..b89ac66c57 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -205,12 +205,11 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => } def deserialize[T](bytes: Coll[Byte])(implicit cT: RType[T]): T = { - val ba = bytes.toArray - val res = cT.classTag match { - case ClassTag.Int => scorex.utils.Ints.fromByteArray(ba) - case ClassTag.Long => scorex.utils.Longs.fromByteArray(ba) - case sigma.data.BoxClassTag => CBox(ErgoBox.sigmaSerializer.fromBytes(ba)) + case ClassTag.Int => scorex.utils.Ints.fromByteArray(bytes.toArray) + case ClassTag.Long => byteArrayToLong(bytes) + case sigma.data.BigIntClassTag => byteArrayToBigInt(bytes) + case sigma.data.BoxClassTag => CBox(ErgoBox.sigmaSerializer.fromBytes(bytes.toArray)) case _ => throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: ${cT.classTag}") } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 235b422966..9010855106 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -236,7 +236,20 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("deserialize - bigint") { + def deserTest() = test("deserialize", env, ext, + s"""{ + val ba = fromBase16("028a5b7f7f7f7f7f7f6c"); + Global.deserialize[BigInt](ba) == byteArrayToBigInt(ba) + }""", + null, + true + ) + if (activatedVersionInTests < V6SoftForkVersion) { + an [sigma.exceptions.TyperException] should be thrownBy deserTest() + } else { + deserTest() + } } property("deserialize - header") { From 4404741275e9b2460c2962dc488a265df94d014c Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 10 May 2024 21:05:40 +0300 Subject: [PATCH 025/123] Short test --- .../scala/sigma/data/CSigmaDslBuilder.scala | 12 ++--- .../utxo/BasicOpsSpecification.scala | 44 +++++++++++++++++-- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index b89ac66c57..98de7ac69b 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -5,18 +5,18 @@ import org.ergoplatform.ErgoBox import org.ergoplatform.validation.ValidationRules import scorex.crypto.hash.{Blake2b256, Sha256} import scorex.utils.Longs -import sigma.Evaluation.stypeToRType -import sigma.ast.{AtLeast, BoxConstant, EvaluatedValue, SType, SubstConstants, Value} +import sigma.ast.{AtLeast, SubstConstants} import sigma.crypto.{CryptoConstants, EcPointType, Ecp} -import sigma.eval.Extensions.{EvalCollOps, toAnyValue} +import sigma.eval.Extensions.EvalCollOps import sigma.exceptions.InvalidType -import sigma.serialization.{GroupElementSerializer, SigmaSerializer, ValueSerializer} +import sigma.serialization.{GroupElementSerializer, SigmaSerializer} import sigma.util.Extensions.BigIntegerOps import sigma.validation.SigmaValidationSettings import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext} import java.math.BigInteger -import scala.reflect.{ClassTag, classTag} +import java.nio.ByteBuffer +import scala.reflect.ClassTag /** A default implementation of [[SigmaDslBuilder]] interface. * @@ -205,7 +205,9 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => } def deserialize[T](bytes: Coll[Byte])(implicit cT: RType[T]): T = { + val res = cT.classTag match { + case ClassTag.Short => ByteBuffer.wrap(bytes.toArray).getShort case ClassTag.Int => scorex.utils.Ints.fromByteArray(bytes.toArray) case ClassTag.Long => byteArrayToLong(bytes) case sigma.data.BigIntClassTag => byteArrayToBigInt(bytes) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 9010855106..8f20bb0d69 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -3,7 +3,7 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ import scorex.util.encode.Base16 -import scorex.utils.Ints +import scorex.utils.{Ints, Shorts} import sigma.{Colls, SigmaProp} import sigma.Extensions.ArrayOps import sigma.VersionContext.V6SoftForkVersion @@ -252,14 +252,52 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - header") { + property("deserialize - short") { + val s = (-1925).toShort + def deserTest() = test("deserialize", env, ext, + s"""{ + val ba = fromBase16("${Base16.encode(Shorts.toByteArray(s))}"); + Global.deserialize[Short](ba) == -1925 + }""", + null, + true + ) + if (activatedVersionInTests < V6SoftForkVersion) { + an [sigma.exceptions.TyperException] should be thrownBy deserTest() + } else { + deserTest() + } } - property("deserialize - short") { + property("deserialize - group element") { + val s = (-1925).toShort + def deserTest() = test("deserialize", env, ext, + s"""{ + val ba = fromBase16("${Base16.encode(Shorts.toByteArray(s))}"); + Global.deserialize[Short](ba) == -1925 + }""", + null, + true + ) + if (activatedVersionInTests < V6SoftForkVersion) { + an [sigma.exceptions.TyperException] should be thrownBy deserTest() + } else { + deserTest() + } } + property("deserialize - avltree") { + + } + + property("deserialize - header") { + + } + + + /* property("getVar") { From 7d69ebc55651d19cea2232763bb92660f219c287 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 10 May 2024 21:18:33 +0300 Subject: [PATCH 026/123] group elem impl & test --- .../main/scala/sigma/data/CSigmaDslBuilder.scala | 1 + .../sigmastate/utxo/BasicOpsSpecification.scala | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 98de7ac69b..d57533d492 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -212,6 +212,7 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => case ClassTag.Long => byteArrayToLong(bytes) case sigma.data.BigIntClassTag => byteArrayToBigInt(bytes) case sigma.data.BoxClassTag => CBox(ErgoBox.sigmaSerializer.fromBytes(bytes.toArray)) + case sigma.data.GroupElementClassTag => CGroupElement(GroupElementSerializer.fromBytes(bytes.toArray)) case _ => throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: ${cT.classTag}") } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 8f20bb0d69..dd226bfb4a 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -24,6 +24,7 @@ import sigma.ast.Apply import sigma.eval.EvalSettings import sigma.exceptions.InvalidType import sigma.serialization.ValueSerializer +import sigmastate.utils.Helpers import sigmastate.utils.Helpers._ import java.math.BigInteger @@ -271,18 +272,21 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("deserialize - group element") { - val s = (-1925).toShort - def deserTest() = test("deserialize", env, ext, + val ge = Helpers.decodeGroupElement("026930cb9972e01534918a6f6d6b8e35bc398f57140d13eb3623ea31fbd069939b") + val ba = Base16.encode(ge.getEncoded.toArray) + def deserTest() = test("deserialize", env, Seq(21.toByte -> GroupElementConstant(ge)), s"""{ - val ba = fromBase16("${Base16.encode(Shorts.toByteArray(s))}"); - Global.deserialize[Short](ba) == -1925 + val ge = getVar[GroupElement](21).get + val ba = fromBase16("$ba"); + val ge2 = Global.deserialize[GroupElement](ba) + ba == ge2.getEncoded && ge == ge2 }""", null, true ) if (activatedVersionInTests < V6SoftForkVersion) { - an [sigma.exceptions.TyperException] should be thrownBy deserTest() + an [sigma.exceptions.TyperException] should be thrownBy deserTest() } else { deserTest() } From 48f112a3abbfb124b591483cdd242d3a8badc536 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sun, 12 May 2024 20:03:30 +0300 Subject: [PATCH 027/123] sigmaprop test & impl --- .../scala/sigma/data/CSigmaDslBuilder.scala | 10 +++- .../utxo/BasicOpsSpecification.scala | 47 +++++++++++++------ 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index d57533d492..db2c0c8869 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -5,11 +5,11 @@ import org.ergoplatform.ErgoBox import org.ergoplatform.validation.ValidationRules import scorex.crypto.hash.{Blake2b256, Sha256} import scorex.utils.Longs -import sigma.ast.{AtLeast, SubstConstants} +import sigma.ast.{AtLeast, EvaluatedValue, SigmaPropConstant, SubstConstants} import sigma.crypto.{CryptoConstants, EcPointType, Ecp} import sigma.eval.Extensions.EvalCollOps import sigma.exceptions.InvalidType -import sigma.serialization.{GroupElementSerializer, SigmaSerializer} +import sigma.serialization.{ErgoTreeSerializer, GroupElementSerializer, SigmaSerializer} import sigma.util.Extensions.BigIntegerOps import sigma.validation.SigmaValidationSettings import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext} @@ -213,6 +213,12 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => case sigma.data.BigIntClassTag => byteArrayToBigInt(bytes) case sigma.data.BoxClassTag => CBox(ErgoBox.sigmaSerializer.fromBytes(bytes.toArray)) case sigma.data.GroupElementClassTag => CGroupElement(GroupElementSerializer.fromBytes(bytes.toArray)) + case sigma.data.SigmaPropClassTag => + //todo : better exception, check for isInstance [EvaluatedValue[_]] + ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes.toArray).root match { + case Left(_) => throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: ${cT.classTag}") + case Right(prop) => prop.asInstanceOf[EvaluatedValue[_]].value + } case _ => throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: ${cT.classTag}") } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index dd226bfb4a..4303ccb655 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -9,7 +9,7 @@ import sigma.Extensions.ArrayOps import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps -import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder, ProveDlog} +import sigma.data.{AvlTreeData, CAND, CAnyValue, CSigmaDslBuilder, CSigmaProp, ProveDlog} import sigma.util.StringUtil._ import sigma.ast._ import sigma.ast.syntax._ @@ -48,7 +48,9 @@ class BasicOpsSpecification extends CompilerTestingCommons val booleanVar = 9.toByte val propVar1 = 10.toByte val propVar2 = 11.toByte - val lastExtVar = propVar2 + val propVar3 = 12.toByte + val propBytesVar1 = 13.toByte + val lastExtVar = propBytesVar1 val ext: Seq[VarBinding] = Seq( (intVar1, IntConstant(1)), (intVar2, IntConstant(2)), @@ -77,7 +79,14 @@ class BasicOpsSpecification extends CompilerTestingCommons override lazy val contextExtenders: Map[Byte, EvaluatedValue[_ <: SType]] = { val p1 = dlogSecrets(0).publicImage val p2 = dlogSecrets(1).publicImage - (ext ++ Seq(propVar1 -> SigmaPropConstant(p1), propVar2 -> SigmaPropConstant(p2))).toMap + val d1 = dhSecrets(0).publicImage + + (ext ++ Seq( + propVar1 -> SigmaPropConstant(p1), + propVar2 -> SigmaPropConstant(p2), + propVar3 -> SigmaPropConstant(CSigmaProp(CAND(Seq(p1, d1)))), + propBytesVar1 -> ByteArrayConstant(CSigmaProp(CAND(Seq(p1, d1))).propBytes) + )).toMap } override val evalSettings: EvalSettings = DefaultEvalSettings.copy( isMeasureOperationTime = true, @@ -240,7 +249,8 @@ class BasicOpsSpecification extends CompilerTestingCommons def deserTest() = test("deserialize", env, ext, s"""{ val ba = fromBase16("028a5b7f7f7f7f7f7f6c"); - Global.deserialize[BigInt](ba) == byteArrayToBigInt(ba) + val b = Global.deserialize[BigInt](ba) + b == byteArrayToBigInt(ba) }""", null, true @@ -292,25 +302,34 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - avltree") { + property("deserialize - sigmaprop roundtrip") { + + def deserTest() = test("deserialize", env, ext, + s"""{ + val ba = getVar[Coll[Byte]]($propBytesVar1).get + val prop = Global.deserialize[SigmaProp](ba) + prop == getVar[SigmaProp]($propVar3).get && prop + }""", + null, + true + ) + if (activatedVersionInTests < V6SoftForkVersion) { + an [sigma.exceptions.TyperException] should be thrownBy deserTest() + } else { + deserTest() + } } - property("deserialize - header") { + property("deserialize - avltree") { } + property("deserialize - header") { + } - /* - property("getVar") { - test("getVar", env, ext, - "{ allOf(Coll(CONTEXT.getVar[Boolean](trueVar).get, true, true)) }", - AND(GetVarBoolean(booleanVar).get, TrueLeaf, TrueLeaf).toSigmaProp - ) - } */ - property("executeFromVar - SigmaProp") { val script = GT(Height, IntConstant(-1)).toSigmaProp val scriptBytes = ValueSerializer.serialize(script) From 63f8cccedddcb71c4251655919ce7530312fb8e6 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sun, 12 May 2024 20:24:12 +0300 Subject: [PATCH 028/123] non evaluated sigmaprop test --- .../scala/sigma/data/CSigmaDslBuilder.scala | 9 +++++-- .../utxo/BasicOpsSpecification.scala | 25 ++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index db2c0c8869..faf995c810 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -216,8 +216,13 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => case sigma.data.SigmaPropClassTag => //todo : better exception, check for isInstance [EvaluatedValue[_]] ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes.toArray).root match { - case Left(_) => throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: ${cT.classTag}") - case Right(prop) => prop.asInstanceOf[EvaluatedValue[_]].value + case Left(_) => throw new InvalidType(s"Cannot deserialize($bytes): unparsed tree provided") + case Right(prop) => + if(prop.isInstanceOf[EvaluatedValue[_]]) { + prop.asInstanceOf[EvaluatedValue[_]].value + } else { + throw new InvalidType(s"Cannot deserialize($bytes): prop is not evaluated: $prop}") + } } case _ => throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: ${cT.classTag}") diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 4303ccb655..c470f946e6 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -23,7 +23,7 @@ import sigmastate.interpreter.Interpreter._ import sigma.ast.Apply import sigma.eval.EvalSettings import sigma.exceptions.InvalidType -import sigma.serialization.ValueSerializer +import sigma.serialization.{ErgoTreeSerializer, ValueSerializer} import sigmastate.utils.Helpers import sigmastate.utils.Helpers._ @@ -321,6 +321,29 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("deserialize - sigmaprop roundtrip - non evaluated") { + + val script = GT(Height, IntConstant(-1)).toSigmaProp + val scriptBytes = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(ErgoTree.fromProposition(script)) + val customExt = Seq(21.toByte -> ByteArrayConstant(scriptBytes)) + + def deserTest() = test("deserialize", env, customExt, + s"""{ + val ba = getVar[Coll[Byte]](21).get + val prop = Global.deserialize[SigmaProp](ba) + prop + }""", + null, + true + ) + + if (activatedVersionInTests < V6SoftForkVersion) { + an [sigma.exceptions.TyperException] should be thrownBy deserTest() + } else { + an [Exception] should be thrownBy deserTest() + } + } + property("deserialize - avltree") { } From 516f05d3e09248a4ff5549203538096971790909 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sun, 12 May 2024 20:40:11 +0300 Subject: [PATCH 029/123] avltree test & impl --- .../scala/sigma/data/CSigmaDslBuilder.scala | 5 +++- .../utxo/BasicOpsSpecification.scala | 27 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index faf995c810..0f63b98b33 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -214,7 +214,6 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => case sigma.data.BoxClassTag => CBox(ErgoBox.sigmaSerializer.fromBytes(bytes.toArray)) case sigma.data.GroupElementClassTag => CGroupElement(GroupElementSerializer.fromBytes(bytes.toArray)) case sigma.data.SigmaPropClassTag => - //todo : better exception, check for isInstance [EvaluatedValue[_]] ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes.toArray).root match { case Left(_) => throw new InvalidType(s"Cannot deserialize($bytes): unparsed tree provided") case Right(prop) => @@ -224,6 +223,10 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => throw new InvalidType(s"Cannot deserialize($bytes): prop is not evaluated: $prop}") } } + case sigma.data.AvlTreeClassTag => + CAvlTree(AvlTreeData.serializer.fromBytes(bytes.toArray)) + case sigma.data.HeaderClassTag => + // todo: add header case _ => throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: ${cT.classTag}") } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index c470f946e6..7ef5c080dc 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -2,14 +2,17 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ +import scorex.crypto.authds.{ADKey, ADValue} +import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert} +import scorex.crypto.hash.{Blake2b256, Digest32} import scorex.util.encode.Base16 -import scorex.utils.{Ints, Shorts} +import scorex.utils.{Ints, Longs, Shorts} import sigma.{Colls, SigmaProp} import sigma.Extensions.ArrayOps import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps -import sigma.data.{AvlTreeData, CAND, CAnyValue, CSigmaDslBuilder, CSigmaProp, ProveDlog} +import sigma.data.{AvlTreeClassTag, AvlTreeData, AvlTreeFlags, CAND, CAnyValue, CSigmaDslBuilder, CSigmaProp, ProveDlog} import sigma.util.StringUtil._ import sigma.ast._ import sigma.ast.syntax._ @@ -345,7 +348,27 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("deserialize - avltree") { + val elements = Seq(123, 22) + val treeElements = elements.map(i => Longs.toByteArray(i)).map(s => (ADKey @@@ Blake2b256(s), ADValue @@ s)) + val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None) + treeElements.foreach(s => avlProver.performOneOperation(Insert(s._1, s._2))) + avlProver.generateProof() + val treeData = new AvlTreeData(avlProver.digest.toColl, AvlTreeFlags.ReadOnly, 32, None) + val treeBytes = AvlTreeData.serializer.toBytes(treeData) + val customExt = Seq(21.toByte -> ByteArrayConstant(treeBytes)) + + def deserTest() = test("deserialize", env, customExt, + s"""{ + val ba = getVar[Coll[Byte]](21).get + val tree = Global.deserialize[AvlTree](ba) + tree.digest == fromBase16(${Base16.encode(treeData.digest.toArray)}) && tree.enabledOperations == 0 + }""", + null, + true + ) + + an [Exception] should be thrownBy deserTest() } property("deserialize - header") { From 5f3a1ad23248d2be0cff59591ae5cccf5960217b Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 13 May 2024 12:23:26 +0300 Subject: [PATCH 030/123] removing executeFromVar from i443 and some code cleaning --- .../main/scala/sigma/ast/SigmaPredef.scala | 33 ++++++------- sc/shared/src/main/scala/scalan/Base.scala | 11 ++--- .../scala/sigmastate/eval/GraphBuilding.scala | 4 -- .../scala/sigmastate/eval/TreeBuilding.scala | 5 +- .../scala/sigmastate/lang/SigmaTyper.scala | 1 - .../scala/sigmastate/CompilerTestsBase.scala | 2 +- .../utxo/BasicOpsSpecification.scala | 48 +------------------ .../ExecuteFromExamplesSpecification.scala | 3 +- 8 files changed, 28 insertions(+), 79 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala index 716b167e2b..631f7f2d75 100644 --- a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala +++ b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala @@ -136,6 +136,17 @@ object SigmaPredef { Seq(ArgInfo("condition", "boolean value to embed in SigmaProp value"))) ) + val GetVarFunc = PredefinedFunc("getVar", + Lambda(Array(paramT), Array("varId" -> SByte), SOption(tT), None), + PredefFuncInfo( + { case (Ident(_, SFunc(_, SOption(rtpe), _)), Seq(id: Constant[SNumericType]@unchecked)) => + mkGetVar(SByte.downcast(id.value.asInstanceOf[AnyVal]), rtpe) + }), + OperationInfo(GetVar, + "Get context variable with given \\lst{varId} and type.", + Seq(ArgInfo("varId", "\\lst{Byte} identifier of context variable"))) + ) + def PKFunc(networkPrefix: NetworkPrefix) = PredefinedFunc("PK", Lambda(Array("input" -> SString), SSigmaProp, None), PredefFuncInfo( @@ -355,23 +366,13 @@ object SigmaPredef { ArgInfo("newValues", "new values to be injected into the corresponding positions in ErgoTree.constants array"))) ) - val GetVarFunc = PredefinedFunc("getVar", - Lambda(Array(paramT), Array("varId" -> SByte), SOption(tT), None), - PredefFuncInfo( - { case (Ident(_, SFunc(_, SOption(rtpe), _)), Seq(id: Constant[SNumericType]@unchecked)) => - mkGetVar(SByte.downcast(id.value.asInstanceOf[AnyVal]), rtpe) - }), - OperationInfo(GetVar, - "Get context variable with given \\lst{varId} and type.", - Seq(ArgInfo("varId", "\\lst{Byte} identifier of context variable"))) - ) - val ExecuteFromVarFunc = PredefinedFunc("executeFromVar", - Lambda(Array(paramT), Array("id" -> SByte), tT, None), - PredefFuncInfo( - { case (Ident(_, SFunc(_, rtpe, _)), Seq(id: Constant[SNumericType]@unchecked)) => - mkDeserializeContext(SByte.downcast(id.value.asInstanceOf[AnyVal]), rtpe) - }), + Lambda( + Seq(paramT), + Array("id" -> SByte), + tT, None + ), + PredefFuncInfo(undefined), OperationInfo(DeserializeContext, """Extracts context variable as \lst{Coll[Byte]}, deserializes it to script | and then executes this script in the current context. diff --git a/sc/shared/src/main/scala/scalan/Base.scala b/sc/shared/src/main/scala/scalan/Base.scala index d40a0dabe9..dd4079054f 100644 --- a/sc/shared/src/main/scala/scalan/Base.scala +++ b/sc/shared/src/main/scala/scalan/Base.scala @@ -1,7 +1,6 @@ package scalan import debox.{cfor, Buffer => DBuffer} -import sigma.ast.{DeserializeContext, SType} import sigma.data.{AVHashMap, Nullable, RType} import sigma.data.OverloadHack.Overloaded1 import sigma.util.StringUtil @@ -203,11 +202,10 @@ abstract class Base { scalan: Scalan => } } - case class DeserializeContextDef[V <: SType](d: DeserializeContext[V], e: Elem[V]) extends Def[V] { - /** Type of a resulting value produced by the operation represented by this definition. - * For example, if this definition represents application of `+: (Int, Int) => Int` operation - * then the result type is Int and `resultType` should return IntElement. */ - override def resultType: Elem[V] = e + /** Logical AND between two pattern matches of the save value `x`. + * Can be used to construct patterns like `case P1 && P2 => ...` */ + object && { + def unapply[T](x: T): Option[(T,T)] = Some((x, x)) } /** Base class for virtualized instances of type companions. @@ -384,6 +382,7 @@ abstract class Base { scalan: Scalan => /** Returns the string like `x45: Int = Const(10)` */ def toStringWithDefinition: String def varNameWithType = varName + ":" + elem.name + } /** Untyped shortcut sinonim of Ref, which is used as untyped reference to graph nodes (definitions). diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index ef78790db7..e42bc744b2 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -559,10 +559,6 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => case DeserializeBytes(bytes, tpe) => sigmaDslBuilder.deserialize(asRep[Coll[Byte]](eval(bytes)))(stypeToElem(tpe)) - case d: DeserializeContext[T] => - val e = stypeToElem(d.tpe).asInstanceOf[Elem[T]] - DeserializeContextDef(d, e) - case ValUse(valId, _) => env.getOrElse(valId, !!!(s"ValUse $valId not found in environment $env")) diff --git a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala index 2071e7b0d1..a7cb6abab6 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala @@ -188,9 +188,6 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext => val tpe = elemToSType(s.elem) mkConstant[tpe.type](wc.constValue.asInstanceOf[tpe.WrappedType], tpe) - case Def(DeserializeContextDef(d, _)) => - d - case Def(IsContextProperty(v)) => v case s if s == sigmaDslBuilder => Global @@ -411,7 +408,7 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext => 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.empty) + builder.mkMethodCall(obj, specMethod, args.toIndexedSeq, Map()) case None => error(s"Cannot find method ${m.getName} in object $obj") } diff --git a/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala b/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala index 991b3ce064..38ceca1c60 100644 --- a/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala +++ b/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala @@ -138,7 +138,6 @@ class SigmaTyper(val builder: SigmaBuilder, case Some(method) => val srcCtx = sel.sourceContext if(method.name == SGlobalMethods.deserializeMethod.name) { - val global = Global.withPropagatedSrcCtx(srcCtx) DeserializeBytes(args(0).asInstanceOf[Value[SByteArray]], rangeTpe) } else { processGlobalMethod(srcCtx, method, newArgs) diff --git a/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala b/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala index a5ae8f1bce..28f907c199 100644 --- a/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala +++ b/sc/shared/src/test/scala/sigmastate/CompilerTestsBase.scala @@ -38,7 +38,7 @@ trait CompilerTestsBase extends TestsBase { def checkSerializationRoundTrip(v: SValue): Unit = { val compiledTreeBytes = ValueSerializer.serialize(v) withClue(s"(De)Serialization roundtrip failed for the tree:") { - ValueSerializer.deserialize(compiledTreeBytes) shouldEqual v + ValueSerializer.deserialize(compiledTreeBytes) shouldEqual v } } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 7ef5c080dc..09e4ea14ef 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -7,12 +7,12 @@ import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert} import scorex.crypto.hash.{Blake2b256, Digest32} import scorex.util.encode.Base16 import scorex.utils.{Ints, Longs, Shorts} -import sigma.{Colls, SigmaProp} +import sigma.Colls import sigma.Extensions.ArrayOps import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps -import sigma.data.{AvlTreeClassTag, AvlTreeData, AvlTreeFlags, CAND, CAnyValue, CSigmaDslBuilder, CSigmaProp, ProveDlog} +import sigma.data.{AvlTreeData, AvlTreeFlags, CAND, CAnyValue, CSigmaDslBuilder, CSigmaProp} import sigma.util.StringUtil._ import sigma.ast._ import sigma.ast.syntax._ @@ -375,50 +375,6 @@ class BasicOpsSpecification extends CompilerTestingCommons } - - property("executeFromVar - SigmaProp") { - val script = GT(Height, IntConstant(-1)).toSigmaProp - val scriptBytes = ValueSerializer.serialize(script) - val customExt = Seq(21.toByte -> ByteArrayConstant(scriptBytes)) - test("executeFromVar", env, customExt, - "executeFromVar[SigmaProp](21)", - null, - true - ) - } - - property("executeFromVar - Int") { - val valueBytes = ValueSerializer.serialize(Plus(IntConstant(2), IntConstant(3))) - val customExt = Seq(21.toByte -> ByteArrayConstant(valueBytes)) - test("executeFromVar", env, customExt, - "{ executeFromVar[Int](21) == 5 }", - null, - true - ) - } - - property("executeFromVar - Coll[Byte]") { - val bytes = Slice(ByteArrayConstant(Colls.fromArray(Array.fill(5)(1.toByte))), IntConstant(1), IntConstant(3)) - val valueBytes = ValueSerializer.serialize(bytes) - val customExt = Seq(21.toByte -> ByteArrayConstant(valueBytes)) - test("executeFromVar", env, customExt, - "{val ba = executeFromVar[Coll[Byte]](21); ba.size == 2 }", - null, - true - ) - } - - property("executeFromVar - deserialize") { - val script = DeserializeContext(21.toByte, SSigmaProp) - val scriptBytes = ValueSerializer.serialize(script) - val customExt = Seq(21.toByte -> ByteArrayConstant(scriptBytes)) - an [Exception] should be thrownBy test("executeFromVar", env, customExt, - "executeFromVar[SigmaProp](21)", - null, - true - ) - } - property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", diff --git a/sc/shared/src/test/scala/sigmastate/utxo/examples/ExecuteFromExamplesSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/examples/ExecuteFromExamplesSpecification.scala index 741b4829cf..8090d87803 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/examples/ExecuteFromExamplesSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/examples/ExecuteFromExamplesSpecification.scala @@ -38,7 +38,8 @@ class ExecuteFromExamplesSpecification extends CompilerTestingCommons { suite => lazy val alice = spec.ProvingParty("Alice") - property("Execute from var example (ErgoDsl)") { + // TODO soft-fork: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/443 + ignore("Execute from var example (ErgoDsl)") { val contract = OracleContract[spec.type](alice)(spec) import contract.spec._ From 126bc053a32c28c35fcbe9a8ce7bf81b160b0506 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 13 May 2024 13:54:09 +0300 Subject: [PATCH 031/123] header impl & test --- .../scala/sigma/data/CSigmaDslBuilder.scala | 4 ++-- .../utxo/BasicOpsSpecification.scala | 24 ++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 0f63b98b33..4fb7aa55d8 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -1,7 +1,7 @@ package sigma.data import debox.cfor -import org.ergoplatform.ErgoBox +import org.ergoplatform.{ErgoBox, ErgoHeader} import org.ergoplatform.validation.ValidationRules import scorex.crypto.hash.{Blake2b256, Sha256} import scorex.utils.Longs @@ -226,7 +226,7 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => case sigma.data.AvlTreeClassTag => CAvlTree(AvlTreeData.serializer.fromBytes(bytes.toArray)) case sigma.data.HeaderClassTag => - // todo: add header + CHeader(ErgoHeader.sigmaSerializer.fromBytes(bytes.toArray)) case _ => throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: ${cT.classTag}") } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 7dd5f4c3f2..ddcb875d3b 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -27,6 +27,7 @@ import sigma.ast.Apply import sigma.eval.EvalSettings import sigma.exceptions.InvalidType import sigma.serialization.{ErgoTreeSerializer, ValueSerializer} +import sigma.util.Extensions import sigmastate.utils.Helpers import sigmastate.utils.Helpers._ @@ -378,7 +379,28 @@ class BasicOpsSpecification extends CompilerTestingCommons val td = new SigmaTestingData {} val h1 = td.TestData.h1 val headerBytes = h1.bytes - ??? + + val headerStateBytes = AvlTreeData.serializer.toBytes(Extensions.CoreAvlTreeOps(h1.stateRoot).toAvlTreeData) + val customExt = Seq(21.toByte -> ByteArrayConstant(headerBytes), 22.toByte -> ByteArrayConstant(headerStateBytes)) + + def deserTest() = test("deserialize", env, customExt, + s"""{ + val ba = getVar[Coll[Byte]](21).get + val header = Global.deserialize[Header](ba) + val ba2 = getVar[Coll[Byte]](22).get + val tree = Global.deserialize[AvlTree](ba2) + val id = fromBase16("${Base16.encode(h1.id.toArray)}") + header.height == ${h1.height} && header.stateRoot == tree && header.id == id + }""", + null, + true + ) + + if (activatedVersionInTests < V6SoftForkVersion) { + an[sigma.exceptions.TyperException] should be thrownBy deserTest() + } else { + deserTest() + } } property("Relation operations") { From 5bf47046400bd47b67fbd818eb551238656d93f0 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 13 May 2024 14:49:01 +0300 Subject: [PATCH 032/123] renaming to deserializeRaw, LangSpec.md update --- .../src/main/scala/sigma/SigmaDsl.scala | 2 +- .../sigma/reflection/ReflectionData.scala | 4 +- .../src/main/scala/sigma/ast/methods.scala | 15 ++-- .../scala/sigma/data/CSigmaDslBuilder.scala | 2 +- .../serialization/MethodCallSerializer.scala | 4 +- docs/LangSpec.md | 6 +- .../scala/sigmastate/eval/GraphBuilding.scala | 10 +-- .../scala/sigmastate/eval/TreeBuilding.scala | 4 +- .../scala/sigmastate/lang/SigmaTyper.scala | 6 +- .../scala/special/sigma/SigmaDslUnit.scala | 2 +- .../special/sigma/impl/SigmaDslImpl.scala | 14 ++-- .../utxo/BasicOpsSpecification.scala | 68 +++++++++---------- 12 files changed, 70 insertions(+), 67 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index e318572b46..32d6edd9ca 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -738,6 +738,6 @@ trait SigmaDslBuilder { /** Returns a byte-wise XOR of the two collections of bytes. */ def xor(l: Coll[Byte], r: Coll[Byte]): Coll[Byte] - def deserialize[T](bytes: Coll[Byte])(implicit cT: RType[T]): T + def deserializeRaw[T](bytes: Coll[Byte])(implicit cT: RType[T]): T } diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index d95c39f93c..810eb7ac67 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -450,8 +450,8 @@ object ReflectionData { mkMethod(clazz, "decodePoint", Array[Class[_]](cColl)) { (obj, args) => obj.asInstanceOf[SigmaDslBuilder].decodePoint(args(0).asInstanceOf[Coll[Byte]]) }, - mkMethod(clazz, "deserialize", Array[Class[_]](cColl, classOf[RType[_]])) { (obj, args) => - obj.asInstanceOf[SigmaDslBuilder].deserialize(args(0).asInstanceOf[Coll[Byte]])(args(1).asInstanceOf[RType[_]]) + mkMethod(clazz, "deserializeRaw", Array[Class[_]](cColl, classOf[RType[_]])) { (obj, args) => + obj.asInstanceOf[SigmaDslBuilder].deserializeRaw(args(0).asInstanceOf[Coll[Byte]])(args(1).asInstanceOf[RType[_]]) } ) ) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index d0abca2bfd..9c9be355c5 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -11,7 +11,6 @@ import sigma.ast.syntax.{SValue, ValueOps} import sigma.data.OverloadHack.Overloaded1 import sigma.data.{DataValueComparer, KeyValueColl, Nullable, RType, SigmaConstants} import sigma.eval.{CostDetails, ErgoTreeEvaluator, TracedCost} -import sigma.pow.Autolykos2PowValidation import sigma.reflection.RClass import sigma.serialization.CoreByteWriter.ArgInfo import sigma.utils.SparseArrayContainer @@ -1534,12 +1533,12 @@ case object SGlobalMethods extends MonoTypeMethods { .withInfo(Xor, "Byte-wise XOR of two collections of bytes", ArgInfo("left", "left operand"), ArgInfo("right", "right operand")) - lazy val desJava = ownerType.reprClass.getMethod("deserialize", classOf[Coll[Byte]], classOf[RType[_]]) + lazy val desJava = ownerType.reprClass.getMethod("deserializeRaw", classOf[Coll[Byte]], classOf[RType[_]]) - lazy val deserializeMethod = SMethod( - this, "deserialize", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 3, Xor.costKind) // todo: cost + lazy val deserializeRawMethod = SMethod( + this, "deserializeRaw", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 3, Xor.costKind) // todo: cost .copy(irInfo = MethodIRInfo(None, Some(desJava), None)) - .withInfo(Xor, "Byte-wise XOR of two collections of bytes", + .withInfo(Xor, "Byte-wise XOR of two collections of bytes", // todo: desc ArgInfo("left", "left operand"), ArgInfo("right", "right operand")) /** Implements evaluation of Global.xor method call ErgoTree node. @@ -1552,11 +1551,11 @@ case object SGlobalMethods extends MonoTypeMethods { } - def deserialize_eval(mc: MethodCall, G: SigmaDslBuilder, bytes: Coll[Byte]) + def deserializeRaw_eval(mc: MethodCall, G: SigmaDslBuilder, bytes: Coll[Byte]) (implicit E: ErgoTreeEvaluator): Any = { val cT = stypeToRType(mc.tpe) E.addSeqCost(Xor.costKind, bytes.length, Xor.opDesc) { () => // todo: cost - G.deserialize(bytes)(cT) + G.deserializeRaw(bytes)(cT) } } @@ -1565,7 +1564,7 @@ case object SGlobalMethods extends MonoTypeMethods { Seq( groupGeneratorMethod, xorMethod, - deserializeMethod + deserializeRawMethod ) } else { Seq( diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 4fb7aa55d8..71579e711b 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -204,7 +204,7 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => this.GroupElement(p) } - def deserialize[T](bytes: Coll[Byte])(implicit cT: RType[T]): T = { + def deserializeRaw[T](bytes: Coll[Byte])(implicit cT: RType[T]): T = { val res = cT.classTag match { case ClassTag.Short => ByteBuffer.wrap(bytes.toArray).getShort diff --git a/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala b/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala index 693e66d57e..1ba0637d07 100644 --- a/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala +++ b/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala @@ -25,7 +25,7 @@ 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) - if(mc.method.name == SGlobalMethods.deserializeMethod.name){ + if(mc.method.name == SGlobalMethods.deserializeRawMethod.name){ w.putType(mc.tpe, typeInfo) } } @@ -62,7 +62,7 @@ case class MethodCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value[S val specMethod = method.specializeFor(obj.tpe, types) - val subst: STypeSubst = if(method.name == SGlobalMethods.deserializeMethod.name) { + val subst: STypeSubst = if(method.name == SGlobalMethods.deserializeRawMethod.name) { val tpe = r.getType() Map(tT -> tpe) } else { diff --git a/docs/LangSpec.md b/docs/LangSpec.md index ba66748f08..ef49b4b846 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: `deserializeRaw`, `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)` @@ -899,6 +899,10 @@ def blake2b256(input: Coll[Byte]): Coll[Byte] /** Cryptographic hash function Sha256 (See scorex.crypto.hash.Sha256) */ def sha256(input: Coll[Byte]): Coll[Byte] +/** Create an instance of type T from bytes of its wrapped type. +See https://github.com/ScorexFoundation/sigmastate-interpreter/pull/979 for more details */ +def deserializeRaw[T](input: Coll[Byte]): T + /** Create BigInt from a collection of bytes. */ def byteArrayToBigInt(input: Coll[Byte]): BigInt diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index 12b15b0e00..8a18ea1c48 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -21,7 +21,7 @@ import sigma.serialization.OpCodes import scala.collection.mutable.ArrayBuffer -case class DeserializeBytes[V <: SType](bytes: Value[SByteArray], tpe: V) extends NotReadyValue[V] { +case class DeserializeRawBytes[V <: SType](bytes: Value[SByteArray], tpe: V) extends NotReadyValue[V] { /** The companion node descriptor with opCode, cost and other metadata. */ override def companion: ValueCompanion = ??? @@ -556,8 +556,8 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => val e = stypeToElem(optTpe.elemType) ctx.getVar(id)(e) - case DeserializeBytes(bytes, tpe) => - sigmaDslBuilder.deserialize(asRep[Coll[Byte]](eval(bytes)))(stypeToElem(tpe)) + case DeserializeRawBytes(bytes, tpe) => + sigmaDslBuilder.deserializeRaw(asRep[Coll[Byte]](eval(bytes)))(stypeToElem(tpe)) case ValUse(valId, _) => env.getOrElse(valId, !!!(s"ValUse $valId not found in environment $env")) @@ -1160,10 +1160,10 @@ 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 SGlobalMethods.deserializeMethod.name if VersionContext.current.isV6SoftForkActivated => + case SGlobalMethods.deserializeRawMethod.name if VersionContext.current.isV6SoftForkActivated => val c1 = asRep[Coll[Byte]](argsV(0)) val c2 = stypeToElem(method.stype.tRange.withSubstTypes(typeSubst)) - g.deserialize(c1)(c2) + g.deserializeRaw(c1)(c2) case _ => throwError } case _ => throwError diff --git a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala index a7cb6abab6..a1f99979be 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala @@ -219,9 +219,9 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext => val tpe = elemToSType(eVar) mkGetVar(id, tpe) - case SDBM.deserialize(g, bytes, eVar) => + case SDBM.deserializeRaw(g, bytes, eVar) => val tpe = elemToSType(eVar) - builder.mkMethodCall(recurse(g), SGlobalMethods.deserializeMethod, IndexedSeq(recurse(bytes)), Map(tT -> tpe): STypeSubst) + builder.mkMethodCall(recurse(g), SGlobalMethods.deserializeRawMethod, IndexedSeq(recurse(bytes)), Map(tT -> tpe): STypeSubst) case BIM.subtract(In(x), In(y)) => mkArith(x.asNumValue, y.asNumValue, MinusCode) diff --git a/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala b/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala index 38ceca1c60..2337fcadbf 100644 --- a/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala +++ b/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala @@ -10,7 +10,7 @@ import SigmaPredef._ import sigma.ast.syntax._ import sigma.exceptions.TyperException import sigma.serialization.OpCodes -import sigmastate.eval.DeserializeBytes +import sigmastate.eval.DeserializeRawBytes import scala.collection.mutable.ArrayBuffer @@ -137,8 +137,8 @@ class SigmaTyper(val builder: SigmaBuilder, SGlobalMethods.method(n) match { case Some(method) => val srcCtx = sel.sourceContext - if(method.name == SGlobalMethods.deserializeMethod.name) { - DeserializeBytes(args(0).asInstanceOf[Value[SByteArray]], rangeTpe) + if(method.name == SGlobalMethods.deserializeRawMethod.name) { + DeserializeRawBytes(args(0).asInstanceOf[Value[SByteArray]], rangeTpe) } else { processGlobalMethod(srcCtx, method, newArgs) } diff --git a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala index 37ba2a06a2..d7962c0ae6 100644 --- a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala @@ -114,7 +114,7 @@ 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 deserialize[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] + def deserializeRaw[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] }; trait CostModelCompanion; trait BigIntCompanion; diff --git a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala index c21506ea77..0385916a67 100644 --- a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala @@ -1970,9 +1970,9 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { true, false, element[Coll[Byte]])) } - override def deserialize[T](l: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { + override def deserializeRaw[T](l: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { asRep[T](mkMethodCall(self, - SigmaDslBuilderClass.getMethod("deserialize", classOf[Sym], classOf[Elem[T]]), + SigmaDslBuilderClass.getMethod("deserializeRaw", classOf[Sym], classOf[Elem[T]]), Array[AnyRef](l, cT), true, false, element[T])) } @@ -2136,9 +2136,9 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { true, true, element[Coll[Byte]])) } - def deserialize[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { + def deserializeRaw[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { asRep[T](mkMethodCall(source, - SigmaDslBuilderClass.getMethod("deserialize", classOf[Sym], classOf[Elem[T]]), + SigmaDslBuilderClass.getMethod("deserializeRaw", classOf[Sym], classOf[Elem[T]]), Array[AnyRef](bytes, cT), true, true, element[T])) } @@ -2161,7 +2161,7 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { 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", "deserialize" + "decodePoint", "avlTree", "xor", "deserializeRaw" )) } } @@ -2340,9 +2340,9 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { def unapply(exp: Sym): Nullable[(Ref[SigmaDslBuilder], Ref[Coll[Byte]])] = unapply(exp.node) } - object deserialize { + object deserializeRaw { def unapply(d: Def[_]): Nullable[(Ref[SigmaDslBuilder], Ref[Coll[Byte]], Elem[T]) forSome {type T}] = d match { - case MethodCall(receiver, method, args, _) if method.getName == "deserialize" && receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] => + case MethodCall(receiver, method, args, _) if method.getName == "deserializeRaw" && receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] => val res = (receiver, args(0), args(1)) Nullable(res).asInstanceOf[Nullable[(Ref[SigmaDslBuilder], Ref[Coll[Byte]], Elem[T]) forSome {type T}]] case _ => Nullable.None diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index ddcb875d3b..af86296992 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -178,10 +178,10 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - property("deserialize - int") { + property("deserializeRaw - int") { val bytes = Base16.encode(Ints.toByteArray(5)) - def deserTest() = {test("deserialize", env, ext, - s"{ val ba = fromBase16(\"$bytes\"); Global.deserialize[Int](ba) == 5 }", + def deserTest() = {test("deserializeRaw", env, ext, + s"{ val ba = fromBase16(\"$bytes\"); Global.deserializeRaw[Int](ba) == 5 }", null, true )} @@ -193,13 +193,13 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - coll") { + property("deserializeRaw - coll") { val bytes = Base16.encode(ValueSerializer.serialize(CollectionConstant[SInt.type](Colls.fromArray(Array(IntConstant(5).value)), SInt))) def deserTest() = { - test("deserialize", env, ext, - s"{val ba = fromBase16(\"$bytes\"); val coll = Global.deserialize[Coll[Int]](ba); coll(0) == 5 }", + test("deserializeRaw", env, ext, + s"{val ba = fromBase16(\"$bytes\"); val coll = Global.deserializeRaw[Coll[Int]](ba); coll(0) == 5 }", null, true ) @@ -213,12 +213,12 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - long roundtrip") { - def deserTest() = test("deserialize", env, ext, + property("deserializeRaw - long roundtrip") { + def deserTest() = test("deserializeRaw", env, ext, s"""{ val l = 5L; val ba = longToByteArray(l); - Global.deserialize[Long](ba) == l + Global.deserializeRaw[Long](ba) == l }""", null, true @@ -231,12 +231,12 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - box rountrip") { - def deserTest() = test("deserialize", env, ext, + property("deserializeRaw - box rountrip") { + def deserTest() = test("deserializeRaw", env, ext, s"""{ val b = INPUTS(0); val ba = b.bytes; - Global.deserialize[Box](ba) == b + Global.deserializeRaw[Box](ba) == b }""", null, true @@ -249,11 +249,11 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - bigint") { - def deserTest() = test("deserialize", env, ext, + property("deserializeRaw - bigint") { + def deserTest() = test("deserializeRaw", env, ext, s"""{ val ba = fromBase16("028a5b7f7f7f7f7f7f6c"); - val b = Global.deserialize[BigInt](ba) + val b = Global.deserializeRaw[BigInt](ba) b == byteArrayToBigInt(ba) }""", null, @@ -267,12 +267,12 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - short") { + property("deserializeRaw - short") { val s = (-1925).toShort - def deserTest() = test("deserialize", env, ext, + def deserTest() = test("deserializeRaw", env, ext, s"""{ val ba = fromBase16("${Base16.encode(Shorts.toByteArray(s))}"); - Global.deserialize[Short](ba) == -1925 + Global.deserializeRaw[Short](ba) == -1925 }""", null, true @@ -285,14 +285,14 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - group element") { + property("deserializeRaw - group element") { val ge = Helpers.decodeGroupElement("026930cb9972e01534918a6f6d6b8e35bc398f57140d13eb3623ea31fbd069939b") val ba = Base16.encode(ge.getEncoded.toArray) - def deserTest() = test("deserialize", env, Seq(21.toByte -> GroupElementConstant(ge)), + def deserTest() = test("deserializeRaw", env, Seq(21.toByte -> GroupElementConstant(ge)), s"""{ val ge = getVar[GroupElement](21).get val ba = fromBase16("$ba"); - val ge2 = Global.deserialize[GroupElement](ba) + val ge2 = Global.deserializeRaw[GroupElement](ba) ba == ge2.getEncoded && ge == ge2 }""", null, @@ -306,12 +306,12 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - sigmaprop roundtrip") { + property("deserializeRaw - sigmaprop roundtrip") { - def deserTest() = test("deserialize", env, ext, + def deserTest() = test("deserializeRaw", env, ext, s"""{ val ba = getVar[Coll[Byte]]($propBytesVar1).get - val prop = Global.deserialize[SigmaProp](ba) + val prop = Global.deserializeRaw[SigmaProp](ba) prop == getVar[SigmaProp]($propVar3).get && prop }""", null, @@ -325,16 +325,16 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - sigmaprop roundtrip - non evaluated") { + property("deserializeRaw - sigmaprop roundtrip - non evaluated") { val script = GT(Height, IntConstant(-1)).toSigmaProp val scriptBytes = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(ErgoTree.fromProposition(script)) val customExt = Seq(21.toByte -> ByteArrayConstant(scriptBytes)) - def deserTest() = test("deserialize", env, customExt, + def deserTest() = test("deserializeRaw", env, customExt, s"""{ val ba = getVar[Coll[Byte]](21).get - val prop = Global.deserialize[SigmaProp](ba) + val prop = Global.deserializeRaw[SigmaProp](ba) prop }""", null, @@ -348,7 +348,7 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserialize - avltree") { + property("deserializeRaw - avltree") { val elements = Seq(123, 22) val treeElements = elements.map(i => Longs.toByteArray(i)).map(s => (ADKey @@@ Blake2b256(s), ADValue @@ s)) val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None) @@ -359,10 +359,10 @@ class BasicOpsSpecification extends CompilerTestingCommons val customExt = Seq(21.toByte -> ByteArrayConstant(treeBytes)) - def deserTest() = test("deserialize", env, customExt, + def deserTest() = test("deserializeRaw", env, customExt, s"""{ val ba = getVar[Coll[Byte]](21).get - val tree = Global.deserialize[AvlTree](ba) + val tree = Global.deserializeRaw[AvlTree](ba) tree.digest == fromBase16(${Base16.encode(treeData.digest.toArray)}) && tree.enabledOperations == 0 && tree.keyLength == 32 @@ -375,7 +375,7 @@ class BasicOpsSpecification extends CompilerTestingCommons an [Exception] should be thrownBy deserTest() } - property("deserialize - header") { + property("deserializeRaw - header") { val td = new SigmaTestingData {} val h1 = td.TestData.h1 val headerBytes = h1.bytes @@ -383,12 +383,12 @@ class BasicOpsSpecification extends CompilerTestingCommons val headerStateBytes = AvlTreeData.serializer.toBytes(Extensions.CoreAvlTreeOps(h1.stateRoot).toAvlTreeData) val customExt = Seq(21.toByte -> ByteArrayConstant(headerBytes), 22.toByte -> ByteArrayConstant(headerStateBytes)) - def deserTest() = test("deserialize", env, customExt, + def deserTest() = test("deserializeRaw", env, customExt, s"""{ val ba = getVar[Coll[Byte]](21).get - val header = Global.deserialize[Header](ba) + val header = Global.deserializeRaw[Header](ba) val ba2 = getVar[Coll[Byte]](22).get - val tree = Global.deserialize[AvlTree](ba2) + val tree = Global.deserializeRaw[AvlTree](ba2) val id = fromBase16("${Base16.encode(h1.id.toArray)}") header.height == ${h1.height} && header.stateRoot == tree && header.id == id }""", From 4004cc9efcd724b115f2b43f280c1f3d9dc5c8fe Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Tue, 14 May 2024 10:10:51 +0100 Subject: [PATCH 033/123] i486-toBytes: tests added to SigmaTyperTest --- .../sigmastate/lang/SigmaTyperTest.scala | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala b/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala index a474727943..f2ac5e8cf2 100644 --- a/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala +++ b/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala @@ -20,6 +20,7 @@ import sigma.serialization.ErgoTreeSerializer import sigma.serialization.generators.ObjectGenerators import sigma.ast.Select import sigma.exceptions.TyperException +import sigmastate.helpers.SigmaPPrint class SigmaTyperTest extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers with LangTests with ObjectGenerators { @@ -37,7 +38,12 @@ class SigmaTyperTest extends AnyPropSpec val typer = new SigmaTyper(builder, predefinedFuncRegistry, 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 @@ -508,6 +514,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.getMethodByName("toBytes").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.getMethodByName("toBytes").withConcreteTypes(Map(STypeVar("TNum") -> SShort)), + Vector(), + Map() + )) shouldBe SByteArray + + typecheck(env, "1.toBytes", + expected = MethodCall.typed[Value[SCollection[SByte.type]]]( + IntConstant(1), + SNumericTypeMethods.getMethodByName("toBytes").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.getMethodByName("toBytes").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.getMethodByName("toBytes").withConcreteTypes(Map(STypeVar("TNum") -> SBigInt)), + Vector(), + Map() + )) shouldBe SByteArray + } + property("string concat") { typecheck(env, """ "a" + "b" """) shouldBe SString } From b55d3362de79afad58f9755e89dc75984bf78c3c Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Tue, 14 May 2024 12:34:02 +0100 Subject: [PATCH 034/123] i486-toBytes: ExactNumeric.toBytes implemented --- .../main/scala/sigma/data/BigIntegerOps.scala | 3 +++ .../main/scala/sigma/data/ExactIntegral.scala | 7 +++++++ .../src/main/scala/sigma/data/ExactNumeric.scala | 7 +++++++ .../test/scala/sigma/SigmaDslSpecification.scala | 16 ++++++++++++++-- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala index 168b2f8266..b93334daf6 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,8 @@ 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 toBytes(x: BigInt): Coll[Byte] = Colls.fromArray(x.toBigInteger.toByteArray) } /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */ diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index 34e2f47f63..b207a1794d 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,7 @@ 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 toBytes(x: Byte): Coll[Byte] = Colls.fromItems(x) } implicit object ShortIsExactIntegral extends ExactIntegral[Short] { @@ -44,6 +46,7 @@ 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 toBytes(x: Short): Coll[Byte] = Colls.fromItems((x >> 8).toByte, x.toByte) } implicit object IntIsExactIntegral extends ExactIntegral[Int] { @@ -51,6 +54,8 @@ 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 toBytes(x: Int): Coll[Byte] = + Colls.fromItems((x >> 24).toByte, (x >> 16).toByte, (x >> 8).toByte, x.toByte) } implicit object LongIsExactIntegral extends ExactIntegral[Long] { @@ -58,5 +63,7 @@ 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 toBytes(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) } } diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index 2e9b799a61..fef951b4d7 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -1,5 +1,6 @@ package sigma.data +import sigma.Coll import sigma.data.ExactIntegral._ /** Numeric operations with overflow checks. @@ -30,6 +31,12 @@ 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 toBytes(x: T): Coll[Byte] + /** A value of type T which corresponds to integer 0. */ lazy val zero: T = fromInt(0) diff --git a/sc/shared/src/test/scala/sigma/SigmaDslSpecification.scala b/sc/shared/src/test/scala/sigma/SigmaDslSpecification.scala index 4dd576f03a..e9ea2b8776 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslSpecification.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslSpecification.scala @@ -1058,8 +1058,20 @@ class SigmaDslSpecification extends SigmaDslTesting ">=", GE.apply)(_ >= _) } +// property("Numeric.toBytes methods equivalence") { +// lazy val toBytes = changedFeature( +// (x: Byte) => x.toBytes, +// (x: Byte) => x.toBytes, +// "{ (x: Byte) => x.toBytes }") +// val cases = Seq( +// (0.toByte, Success(Coll(0.toByte))), +// (1.toByte, Success(Coll(1.toByte))) +// ) +// +// testCases(cases, toBytes) +// } + 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), @@ -1074,7 +1086,7 @@ class SigmaDslSpecification extends SigmaDslTesting "{ (x: (Byte, Byte)) => (x._1 & x._2).toByteExact }") forAll { x: Byte => - Seq(toBytes, toAbs).foreach(f => f.checkEquality(x)) + Seq(toAbs).foreach(f => f.checkEquality(x)) } forAll { x: (Byte, Byte) => From 35c9375b390f02b11c51de6c815aeecaa4557786 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 16 May 2024 13:37:57 +0300 Subject: [PATCH 035/123] DataSerializer WIP #1 --- core/shared/src/main/scala/sigma/SigmaDsl.scala | 5 +++-- .../scala/sigma/reflection/ReflectionData.scala | 4 ++-- .../serialization/CoreDataSerializer.scala | 2 +- .../src/main/scala/sigma/ast/methods.scala | 7 ++++--- .../scala/sigma/data/CSigmaDslBuilder.scala | 17 ++++++----------- .../sigmastate/utxo/BasicOpsSpecification.scala | 17 +++++++++++------ 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 32d6edd9ca..8a95b5225b 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -1,7 +1,8 @@ package sigma -import java.math.BigInteger +import sigma.ast.SType +import java.math.BigInteger import sigma.data._ /** @@ -738,6 +739,6 @@ trait SigmaDslBuilder { /** Returns a byte-wise XOR of the two collections of bytes. */ def xor(l: Coll[Byte], r: Coll[Byte]): Coll[Byte] - def deserializeRaw[T](bytes: Coll[Byte])(implicit cT: RType[T]): T + def deserializeRaw[T](tpe: SType, bytes: Coll[Byte])(implicit cT: RType[T]): T } diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index 810eb7ac67..22bc791287 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -450,8 +450,8 @@ object ReflectionData { mkMethod(clazz, "decodePoint", Array[Class[_]](cColl)) { (obj, args) => obj.asInstanceOf[SigmaDslBuilder].decodePoint(args(0).asInstanceOf[Coll[Byte]]) }, - mkMethod(clazz, "deserializeRaw", Array[Class[_]](cColl, classOf[RType[_]])) { (obj, args) => - obj.asInstanceOf[SigmaDslBuilder].deserializeRaw(args(0).asInstanceOf[Coll[Byte]])(args(1).asInstanceOf[RType[_]]) + mkMethod(clazz, "deserializeRaw", Array[Class[_]](classOf[SType], cColl, classOf[RType[_]])) { (obj, args) => + obj.asInstanceOf[SigmaDslBuilder].deserializeRaw(args(0).asInstanceOf[SType], args(1).asInstanceOf[Coll[Byte]])(args(2).asInstanceOf[RType[_]]) } ) ) diff --git a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala index 0c7a991662..64e8f274d8 100644 --- a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala +++ b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala @@ -126,7 +126,7 @@ class CoreDataSerializer { res } - def deserializeColl[T <: SType](len: Int, tpeElem: T, r: CoreByteReader): Coll[T#WrappedType] = + private def deserializeColl[T <: SType](len: Int, tpeElem: T, r: CoreByteReader): Coll[T#WrappedType] = tpeElem match { case SBoolean => Colls.fromArray(r.getBits(len)).asInstanceOf[Coll[T#WrappedType]] diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 9c9be355c5..e61d3781fd 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -1533,7 +1533,7 @@ case object SGlobalMethods extends MonoTypeMethods { .withInfo(Xor, "Byte-wise XOR of two collections of bytes", ArgInfo("left", "left operand"), ArgInfo("right", "right operand")) - lazy val desJava = ownerType.reprClass.getMethod("deserializeRaw", classOf[Coll[Byte]], classOf[RType[_]]) + lazy val desJava = ownerType.reprClass.getMethod("deserializeRaw", classOf[SType], classOf[Coll[Byte]], classOf[RType[_]]) lazy val deserializeRawMethod = SMethod( this, "deserializeRaw", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 3, Xor.costKind) // todo: cost @@ -1553,9 +1553,10 @@ case object SGlobalMethods extends MonoTypeMethods { def deserializeRaw_eval(mc: MethodCall, G: SigmaDslBuilder, bytes: Coll[Byte]) (implicit E: ErgoTreeEvaluator): Any = { - val cT = stypeToRType(mc.tpe) + val tpe = mc.tpe + val cT = stypeToRType(tpe) E.addSeqCost(Xor.costKind, bytes.length, Xor.opDesc) { () => // todo: cost - G.deserializeRaw(bytes)(cT) + G.deserializeRaw(tpe, bytes)(cT) } } diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 71579e711b..292c3255bd 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -4,12 +4,13 @@ import debox.cfor import org.ergoplatform.{ErgoBox, ErgoHeader} import org.ergoplatform.validation.ValidationRules import scorex.crypto.hash.{Blake2b256, Sha256} +import scorex.util.serialization.VLQByteBufferReader import scorex.utils.Longs -import sigma.ast.{AtLeast, EvaluatedValue, SigmaPropConstant, SubstConstants} +import sigma.ast.{AtLeast, EvaluatedValue, SType, SigmaPropConstant, SubstConstants} import sigma.crypto.{CryptoConstants, EcPointType, Ecp} import sigma.eval.Extensions.EvalCollOps import sigma.exceptions.InvalidType -import sigma.serialization.{ErgoTreeSerializer, GroupElementSerializer, SigmaSerializer} +import sigma.serialization.{ConstantStore, CoreByteReader, CoreByteWriter, DataSerializer, ErgoTreeSerializer, GroupElementSerializer, SigmaByteReader, SigmaSerializer} import sigma.util.Extensions.BigIntegerOps import sigma.validation.SigmaValidationSettings import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext} @@ -204,15 +205,12 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => this.GroupElement(p) } - def deserializeRaw[T](bytes: Coll[Byte])(implicit cT: RType[T]): T = { - + def deserializeRaw[T](tpe: SType, bytes: Coll[Byte])(implicit cT: RType[T]): T = { val res = cT.classTag match { case ClassTag.Short => ByteBuffer.wrap(bytes.toArray).getShort case ClassTag.Int => scorex.utils.Ints.fromByteArray(bytes.toArray) case ClassTag.Long => byteArrayToLong(bytes) case sigma.data.BigIntClassTag => byteArrayToBigInt(bytes) - case sigma.data.BoxClassTag => CBox(ErgoBox.sigmaSerializer.fromBytes(bytes.toArray)) - case sigma.data.GroupElementClassTag => CGroupElement(GroupElementSerializer.fromBytes(bytes.toArray)) case sigma.data.SigmaPropClassTag => ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes.toArray).root match { case Left(_) => throw new InvalidType(s"Cannot deserialize($bytes): unparsed tree provided") @@ -223,12 +221,9 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => throw new InvalidType(s"Cannot deserialize($bytes): prop is not evaluated: $prop}") } } - case sigma.data.AvlTreeClassTag => - CAvlTree(AvlTreeData.serializer.fromBytes(bytes.toArray)) - case sigma.data.HeaderClassTag => - CHeader(ErgoHeader.sigmaSerializer.fromBytes(bytes.toArray)) case _ => - throw new InvalidType(s"Cannot deserialize($bytes): invalid type of value: ${cT.classTag}") + val reader = new SigmaByteReader(new VLQByteBufferReader(ByteBuffer.wrap(bytes.toArray)), new ConstantStore(), false) + DataSerializer.deserialize(tpe, reader) } res.asInstanceOf[T] } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index af86296992..bb7f16d66f 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -5,9 +5,11 @@ import org.ergoplatform._ import scorex.crypto.authds.{ADKey, ADValue} import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert} import scorex.crypto.hash.{Blake2b256, Digest32} +import scorex.util.ByteArrayBuilder import scorex.util.encode.Base16 +import scorex.util.serialization.VLQByteBufferWriter import scorex.utils.{Ints, Longs, Shorts} -import sigma.{Colls, SigmaTestingData} +import sigma.{BigInt, Colls, SigmaTestingData} import sigma.Extensions.ArrayOps import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray @@ -26,7 +28,7 @@ import sigmastate.interpreter.Interpreter._ import sigma.ast.Apply import sigma.eval.EvalSettings import sigma.exceptions.InvalidType -import sigma.serialization.{ErgoTreeSerializer, ValueSerializer} +import sigma.serialization.{DataSerializer, ErgoTreeSerializer, ValueSerializer} import sigma.util.Extensions import sigmastate.utils.Helpers import sigmastate.utils.Helpers._ @@ -179,15 +181,16 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("deserializeRaw - int") { - val bytes = Base16.encode(Ints.toByteArray(5)) + val value = -109253 + val bytes = Base16.encode(Ints.toByteArray(value)) def deserTest() = {test("deserializeRaw", env, ext, - s"{ val ba = fromBase16(\"$bytes\"); Global.deserializeRaw[Int](ba) == 5 }", + s"{ val ba = fromBase16(\"$bytes\"); Global.deserializeRaw[Int](ba) == $value }", null, true )} if (activatedVersionInTests < V6SoftForkVersion) { - an [sigma.exceptions.TyperException] should be thrownBy deserTest() + an [sigma.exceptions.TyperException] should be thrownBy deserTest() } else { deserTest() } @@ -214,9 +217,11 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("deserializeRaw - long roundtrip") { + val value = -1009253 + def deserTest() = test("deserializeRaw", env, ext, s"""{ - val l = 5L; + val l = ${value}L; val ba = longToByteArray(l); Global.deserializeRaw[Long](ba) == l }""", From 48f11e761016fd1d71cee232a76f4cd58aa887eb Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 16 May 2024 17:45:23 +0300 Subject: [PATCH 036/123] coll allowed --- .../sigmastate/utxo/BasicOpsSpecification.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index bb7f16d66f..918557455e 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -7,7 +7,7 @@ import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert} import scorex.crypto.hash.{Blake2b256, Digest32} import scorex.util.ByteArrayBuilder import scorex.util.encode.Base16 -import scorex.util.serialization.VLQByteBufferWriter +import scorex.util.serialization.{VLQByteBufferReader, VLQByteBufferWriter} import scorex.utils.{Ints, Longs, Shorts} import sigma.{BigInt, Colls, SigmaTestingData} import sigma.Extensions.ArrayOps @@ -28,7 +28,7 @@ import sigmastate.interpreter.Interpreter._ import sigma.ast.Apply import sigma.eval.EvalSettings import sigma.exceptions.InvalidType -import sigma.serialization.{DataSerializer, ErgoTreeSerializer, ValueSerializer} +import sigma.serialization.{ConstantStore, DataSerializer, ErgoTreeSerializer, SigmaByteReader, SigmaByteWriter, ValueSerializer} import sigma.util.Extensions import sigmastate.utils.Helpers import sigmastate.utils.Helpers._ @@ -197,8 +197,9 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("deserializeRaw - coll") { - - val bytes = Base16.encode(ValueSerializer.serialize(CollectionConstant[SInt.type](Colls.fromArray(Array(IntConstant(5).value)), SInt))) + val writer = new SigmaByteWriter(new VLQByteBufferWriter(new ByteArrayBuilder()), None) + DataSerializer.serialize[SCollection[SInt.type]](Colls.fromArray(Array(IntConstant(5).value)), SCollection(SInt), writer) + val bytes = Base16.encode(writer.toBytes) def deserTest() = { test("deserializeRaw", env, ext, @@ -211,8 +212,7 @@ class BasicOpsSpecification extends CompilerTestingCommons if (activatedVersionInTests < V6SoftForkVersion) { an [sigma.exceptions.TyperException] should be thrownBy deserTest() } else { - // only singular types are supported, so the test fails - an [java.lang.reflect.InvocationTargetException] should be thrownBy deserTest() + deserTest() } } From 7fd601b88f6bb73ec0ff2f7dc63c67247d2414cc Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 16 May 2024 20:02:31 +0300 Subject: [PATCH 037/123] .propBytes test --- .../scala/sigma/data/CSigmaDslBuilder.scala | 4 +-- .../utxo/BasicOpsSpecification.scala | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 292c3255bd..2b71a94621 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -211,7 +211,7 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => case ClassTag.Int => scorex.utils.Ints.fromByteArray(bytes.toArray) case ClassTag.Long => byteArrayToLong(bytes) case sigma.data.BigIntClassTag => byteArrayToBigInt(bytes) - case sigma.data.SigmaPropClassTag => + /* case sigma.data.SigmaPropClassTag => ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes.toArray).root match { case Left(_) => throw new InvalidType(s"Cannot deserialize($bytes): unparsed tree provided") case Right(prop) => @@ -220,7 +220,7 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => } else { throw new InvalidType(s"Cannot deserialize($bytes): prop is not evaluated: $prop}") } - } + } */ case _ => val reader = new SigmaByteReader(new VLQByteBufferReader(ByteBuffer.wrap(bytes.toArray)), new ConstantStore(), false) DataSerializer.deserialize(tpe, reader) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 918557455e..c0dca73b61 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -311,6 +311,20 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + /** + * + * todo: decide how to deserialize + * + * DataSerializer, with it round-trip property with existing serializers (longtoByteArray, .propBytes etc) would be broken. Which would lead to following possible consequences: + + deserialization of those those types (Long, BigInt, SigmaProp) and similar (Short, Int) is corresponding to existing serializers, for other options DataSerializer is used + + + new "serialize: SAny -> SByteArray" option is introduced , with DataSerializer under the hood, but then there are two coexisting options, old one (longToByteArray/byteArrayToLong), and new one serialize/deserialize, for round-tripping, with the exception for .propBytes which can be deserialized via skipping first two bytes though, like " { val bytes = p1.propBytes; val ba = bytes.slice(2, bytes.size); val prop = Global.deserialize[SigmaProp](ba)} + + +in case of serialize() (which is the better option I support), there is no need for header.bytes. avlTree.bytes, numeric.bytes (and the latter option would be confusing, as producing different bytes from *ToByteArray). + */ property("deserializeRaw - sigmaprop roundtrip") { def deserTest() = test("deserializeRaw", env, ext, @@ -330,6 +344,26 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("deserializeRaw - .propBytes") { + def deserTest() = test("deserializeRaw", env, ext, + s"""{ + val p1 = getVar[SigmaProp]($propVar1).get + val bytes = p1.propBytes + val ba = bytes.slice(2, bytes.size) + val prop = Global.deserializeRaw[SigmaProp](ba) + prop == p1 && prop + }""", + null, + true + ) + + if (activatedVersionInTests < V6SoftForkVersion) { + an [sigma.exceptions.TyperException] should be thrownBy deserTest() + } else { + deserTest() + } + } + property("deserializeRaw - sigmaprop roundtrip - non evaluated") { val script = GT(Height, IntConstant(-1)).toSigmaProp From a2ffc2db518326ed616441f2813c0bc65c939038 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 17 May 2024 19:58:03 +0300 Subject: [PATCH 038/123] all types rely on DataSerializer --- .../scala/sigma/data/CSigmaDslBuilder.scala | 21 +------ .../utxo/BasicOpsSpecification.scala | 55 ++++++++++--------- 2 files changed, 30 insertions(+), 46 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 2b71a94621..9468d3e537 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -206,25 +206,8 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => } def deserializeRaw[T](tpe: SType, bytes: Coll[Byte])(implicit cT: RType[T]): T = { - val res = cT.classTag match { - case ClassTag.Short => ByteBuffer.wrap(bytes.toArray).getShort - case ClassTag.Int => scorex.utils.Ints.fromByteArray(bytes.toArray) - case ClassTag.Long => byteArrayToLong(bytes) - case sigma.data.BigIntClassTag => byteArrayToBigInt(bytes) - /* case sigma.data.SigmaPropClassTag => - ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes.toArray).root match { - case Left(_) => throw new InvalidType(s"Cannot deserialize($bytes): unparsed tree provided") - case Right(prop) => - if(prop.isInstanceOf[EvaluatedValue[_]]) { - prop.asInstanceOf[EvaluatedValue[_]].value - } else { - throw new InvalidType(s"Cannot deserialize($bytes): prop is not evaluated: $prop}") - } - } */ - case _ => - val reader = new SigmaByteReader(new VLQByteBufferReader(ByteBuffer.wrap(bytes.toArray)), new ConstantStore(), false) - DataSerializer.deserialize(tpe, reader) - } + val reader = new SigmaByteReader(new VLQByteBufferReader(ByteBuffer.wrap(bytes.toArray)), new ConstantStore(), false) + val res = DataSerializer.deserialize(tpe, reader) res.asInstanceOf[T] } } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 965e5b0661..35d6b022d2 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -18,7 +18,7 @@ import sigma.data.{AvlTreeData, AvlTreeFlags, CAND, CAnyValue, CSigmaDslBuilder, import sigma.util.StringUtil._ import sigma.ast._ import sigma.ast.syntax._ -import sigma.crypto.CryptoConstants +import sigma.crypto.{CryptoConstants, SecP256K1Group} import sigmastate._ import sigmastate.helpers.TestingHelpers._ import sigmastate.helpers.{CompilerTestingCommons, ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestInterpreter} @@ -182,7 +182,8 @@ class BasicOpsSpecification extends CompilerTestingCommons property("deserializeRaw - int") { val value = -109253 - val bytes = Base16.encode(Ints.toByteArray(value)) + val w = new VLQByteBufferWriter(new ByteArrayBuilder()).putInt(value) + val bytes = Base16.encode(w.toBytes) def deserTest() = {test("deserializeRaw", env, ext, s"{ val ba = fromBase16(\"$bytes\"); Global.deserializeRaw[Int](ba) == $value }", null, @@ -196,7 +197,7 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - coll") { + property("deserializeRaw - coll[int]") { val writer = new SigmaByteWriter(new VLQByteBufferWriter(new ByteArrayBuilder()), None) DataSerializer.serialize[SCollection[SInt.type]](Colls.fromArray(Array(IntConstant(5).value)), SCollection(SInt), writer) val bytes = Base16.encode(writer.toBytes) @@ -216,14 +217,16 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - long roundtrip") { - val value = -1009253 + property("deserializeRaw - long") { + val value = -10009253L + + val w = new VLQByteBufferWriter(new ByteArrayBuilder()).putLong(value) + val bytes = Base16.encode(w.toBytes) def deserTest() = test("deserializeRaw", env, ext, s"""{ - val l = ${value}L; - val ba = longToByteArray(l); - Global.deserializeRaw[Long](ba) == l + val ba = fromBase16("$bytes"); + Global.deserializeRaw[Long](ba) == ${value}L }""", null, true @@ -255,11 +258,20 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("deserializeRaw - bigint") { + + val bigInt = SecP256K1Group.q.divide(new BigInteger("512")) + val biBytes = bigInt.toByteArray + + val w = new VLQByteBufferWriter(new ByteArrayBuilder()).putUShort(biBytes.length) + val lengthBytes = w.toBytes + + val bytes = Base16.encode(lengthBytes ++ biBytes) + def deserTest() = test("deserializeRaw", env, ext, s"""{ - val ba = fromBase16("028a5b7f7f7f7f7f7f6c"); + val ba = fromBase16("$bytes"); val b = Global.deserializeRaw[BigInt](ba) - b == byteArrayToBigInt(ba) + b == bigInt("${bigInt.toString}") }""", null, true @@ -274,9 +286,11 @@ class BasicOpsSpecification extends CompilerTestingCommons property("deserializeRaw - short") { val s = (-1925).toShort + val w = new VLQByteBufferWriter(new ByteArrayBuilder()).putShort(s) + val bytes = Base16.encode(w.toBytes) def deserTest() = test("deserializeRaw", env, ext, s"""{ - val ba = fromBase16("${Base16.encode(Shorts.toByteArray(s))}"); + val ba = fromBase16("$bytes"); Global.deserializeRaw[Short](ba) == -1925 }""", null, @@ -310,26 +324,13 @@ class BasicOpsSpecification extends CompilerTestingCommons deserTest() } } - - /** - * - * todo: decide how to deserialize - * - * DataSerializer, with it round-trip property with existing serializers (longtoByteArray, .propBytes etc) would be broken. Which would lead to following possible consequences: - - deserialization of those those types (Long, BigInt, SigmaProp) and similar (Short, Int) is corresponding to existing serializers, for other options DataSerializer is used - - - new "serialize: SAny -> SByteArray" option is introduced , with DataSerializer under the hood, but then there are two coexisting options, old one (longToByteArray/byteArrayToLong), and new one serialize/deserialize, for round-tripping, with the exception for .propBytes which can be deserialized via skipping first two bytes though, like " { val bytes = p1.propBytes; val ba = bytes.slice(2, bytes.size); val prop = Global.deserialize[SigmaProp](ba)} - - -in case of serialize() (which is the better option I support), there is no need for header.bytes. avlTree.bytes, numeric.bytes (and the latter option would be confusing, as producing different bytes from *ToByteArray). - */ + property("deserializeRaw - sigmaprop roundtrip") { def deserTest() = test("deserializeRaw", env, ext, s"""{ - val ba = getVar[Coll[Byte]]($propBytesVar1).get + val bytes = getVar[Coll[Byte]]($propBytesVar1).get + val ba = bytes.slice(2, bytes.size) val prop = Global.deserializeRaw[SigmaProp](ba) prop == getVar[SigmaProp]($propVar3).get && prop }""", From ae271cd6ffa68f7903d20ef7e05c0aefcf20e9ac Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 17 May 2024 20:02:22 +0300 Subject: [PATCH 039/123] deserializeRaw -> deserializeTo --- .../src/main/scala/sigma/SigmaDsl.scala | 2 +- .../sigma/reflection/ReflectionData.scala | 4 +- .../src/main/scala/sigma/ast/methods.scala | 12 +-- .../scala/sigma/data/CSigmaDslBuilder.scala | 2 +- .../serialization/MethodCallSerializer.scala | 4 +- docs/LangSpec.md | 4 +- .../scala/sigmastate/eval/GraphBuilding.scala | 10 +-- .../scala/sigmastate/eval/TreeBuilding.scala | 4 +- .../scala/sigmastate/lang/SigmaTyper.scala | 6 +- .../scala/special/sigma/SigmaDslUnit.scala | 2 +- .../special/sigma/impl/SigmaDslImpl.scala | 14 ++-- .../utxo/BasicOpsSpecification.scala | 82 +++++++++---------- 12 files changed, 73 insertions(+), 73 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 8a95b5225b..42d8df1587 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -739,6 +739,6 @@ trait SigmaDslBuilder { /** Returns a byte-wise XOR of the two collections of bytes. */ def xor(l: Coll[Byte], r: Coll[Byte]): Coll[Byte] - def deserializeRaw[T](tpe: SType, bytes: Coll[Byte])(implicit cT: RType[T]): T + def deserializeTo[T](tpe: SType, bytes: Coll[Byte])(implicit cT: RType[T]): T } diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index 22bc791287..174a631210 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -450,8 +450,8 @@ object ReflectionData { mkMethod(clazz, "decodePoint", Array[Class[_]](cColl)) { (obj, args) => obj.asInstanceOf[SigmaDslBuilder].decodePoint(args(0).asInstanceOf[Coll[Byte]]) }, - mkMethod(clazz, "deserializeRaw", Array[Class[_]](classOf[SType], cColl, classOf[RType[_]])) { (obj, args) => - obj.asInstanceOf[SigmaDslBuilder].deserializeRaw(args(0).asInstanceOf[SType], args(1).asInstanceOf[Coll[Byte]])(args(2).asInstanceOf[RType[_]]) + mkMethod(clazz, "deserializeTo", Array[Class[_]](classOf[SType], cColl, classOf[RType[_]])) { (obj, args) => + obj.asInstanceOf[SigmaDslBuilder].deserializeTo(args(0).asInstanceOf[SType], args(1).asInstanceOf[Coll[Byte]])(args(2).asInstanceOf[RType[_]]) } ) ) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index e61d3781fd..bec11a2231 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -1533,10 +1533,10 @@ case object SGlobalMethods extends MonoTypeMethods { .withInfo(Xor, "Byte-wise XOR of two collections of bytes", ArgInfo("left", "left operand"), ArgInfo("right", "right operand")) - lazy val desJava = ownerType.reprClass.getMethod("deserializeRaw", classOf[SType], classOf[Coll[Byte]], classOf[RType[_]]) + lazy val desJava = ownerType.reprClass.getMethod("deserializeTo", classOf[SType], classOf[Coll[Byte]], classOf[RType[_]]) - lazy val deserializeRawMethod = SMethod( - this, "deserializeRaw", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 3, Xor.costKind) // todo: cost + lazy val deserializeToMethod = SMethod( + this, "deserializeTo", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 3, Xor.costKind) // todo: cost .copy(irInfo = MethodIRInfo(None, Some(desJava), None)) .withInfo(Xor, "Byte-wise XOR of two collections of bytes", // todo: desc ArgInfo("left", "left operand"), ArgInfo("right", "right operand")) @@ -1551,12 +1551,12 @@ case object SGlobalMethods extends MonoTypeMethods { } - def deserializeRaw_eval(mc: MethodCall, G: SigmaDslBuilder, bytes: Coll[Byte]) + def deserializeTo_eval(mc: MethodCall, G: SigmaDslBuilder, bytes: Coll[Byte]) (implicit E: ErgoTreeEvaluator): Any = { val tpe = mc.tpe val cT = stypeToRType(tpe) E.addSeqCost(Xor.costKind, bytes.length, Xor.opDesc) { () => // todo: cost - G.deserializeRaw(tpe, bytes)(cT) + G.deserializeTo(tpe, bytes)(cT) } } @@ -1565,7 +1565,7 @@ case object SGlobalMethods extends MonoTypeMethods { Seq( groupGeneratorMethod, xorMethod, - deserializeRawMethod + deserializeToMethod ) } else { Seq( diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 9468d3e537..cbe94a9bfa 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -205,7 +205,7 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => this.GroupElement(p) } - def deserializeRaw[T](tpe: SType, bytes: Coll[Byte])(implicit cT: RType[T]): T = { + def deserializeTo[T](tpe: SType, bytes: Coll[Byte])(implicit cT: RType[T]): T = { val reader = new SigmaByteReader(new VLQByteBufferReader(ByteBuffer.wrap(bytes.toArray)), new ConstantStore(), false) val res = DataSerializer.deserialize(tpe, reader) res.asInstanceOf[T] diff --git a/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala b/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala index 1ba0637d07..cd97edbfb3 100644 --- a/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala +++ b/data/shared/src/main/scala/sigma/serialization/MethodCallSerializer.scala @@ -25,7 +25,7 @@ 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) - if(mc.method.name == SGlobalMethods.deserializeRawMethod.name){ + if(mc.method.name == SGlobalMethods.deserializeToMethod.name){ w.putType(mc.tpe, typeInfo) } } @@ -62,7 +62,7 @@ case class MethodCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value[S val specMethod = method.specializeFor(obj.tpe, types) - val subst: STypeSubst = if(method.name == SGlobalMethods.deserializeRawMethod.name) { + val subst: STypeSubst = if(method.name == SGlobalMethods.deserializeToMethod.name) { val tpe = r.getType() Map(tT -> tpe) } else { diff --git a/docs/LangSpec.md b/docs/LangSpec.md index ef49b4b846..2beb7b8487 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: `deserializeRaw`, `blake2b256`, `byteArrayToBigInt`, `proveDlog` etc. +- predefined primitives: `deserializeTo`, `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)` @@ -901,7 +901,7 @@ def sha256(input: Coll[Byte]): Coll[Byte] /** Create an instance of type T from bytes of its wrapped type. See https://github.com/ScorexFoundation/sigmastate-interpreter/pull/979 for more details */ -def deserializeRaw[T](input: Coll[Byte]): T +def deserializeTo[T](input: Coll[Byte]): T /** Create BigInt from a collection of bytes. */ def byteArrayToBigInt(input: Coll[Byte]): BigInt diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index 8a18ea1c48..1c33055aa6 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -21,7 +21,7 @@ import sigma.serialization.OpCodes import scala.collection.mutable.ArrayBuffer -case class DeserializeRawBytes[V <: SType](bytes: Value[SByteArray], tpe: V) extends NotReadyValue[V] { +case class deserializeToBytes[V <: SType](bytes: Value[SByteArray], tpe: V) extends NotReadyValue[V] { /** The companion node descriptor with opCode, cost and other metadata. */ override def companion: ValueCompanion = ??? @@ -556,8 +556,8 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => val e = stypeToElem(optTpe.elemType) ctx.getVar(id)(e) - case DeserializeRawBytes(bytes, tpe) => - sigmaDslBuilder.deserializeRaw(asRep[Coll[Byte]](eval(bytes)))(stypeToElem(tpe)) + case deserializeToBytes(bytes, tpe) => + sigmaDslBuilder.deserializeTo(asRep[Coll[Byte]](eval(bytes)))(stypeToElem(tpe)) case ValUse(valId, _) => env.getOrElse(valId, !!!(s"ValUse $valId not found in environment $env")) @@ -1160,10 +1160,10 @@ 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 SGlobalMethods.deserializeRawMethod.name if VersionContext.current.isV6SoftForkActivated => + case SGlobalMethods.deserializeToMethod.name if VersionContext.current.isV6SoftForkActivated => val c1 = asRep[Coll[Byte]](argsV(0)) val c2 = stypeToElem(method.stype.tRange.withSubstTypes(typeSubst)) - g.deserializeRaw(c1)(c2) + g.deserializeTo(c1)(c2) case _ => throwError } case _ => throwError diff --git a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala index a1f99979be..0b60304b38 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/TreeBuilding.scala @@ -219,9 +219,9 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext => val tpe = elemToSType(eVar) mkGetVar(id, tpe) - case SDBM.deserializeRaw(g, bytes, eVar) => + case SDBM.deserializeTo(g, bytes, eVar) => val tpe = elemToSType(eVar) - builder.mkMethodCall(recurse(g), SGlobalMethods.deserializeRawMethod, IndexedSeq(recurse(bytes)), Map(tT -> tpe): STypeSubst) + builder.mkMethodCall(recurse(g), SGlobalMethods.deserializeToMethod, IndexedSeq(recurse(bytes)), Map(tT -> tpe): STypeSubst) case BIM.subtract(In(x), In(y)) => mkArith(x.asNumValue, y.asNumValue, MinusCode) diff --git a/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala b/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala index 2337fcadbf..be5fa9a304 100644 --- a/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala +++ b/sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala @@ -10,7 +10,7 @@ import SigmaPredef._ import sigma.ast.syntax._ import sigma.exceptions.TyperException import sigma.serialization.OpCodes -import sigmastate.eval.DeserializeRawBytes +import sigmastate.eval.deserializeToBytes import scala.collection.mutable.ArrayBuffer @@ -137,8 +137,8 @@ class SigmaTyper(val builder: SigmaBuilder, SGlobalMethods.method(n) match { case Some(method) => val srcCtx = sel.sourceContext - if(method.name == SGlobalMethods.deserializeRawMethod.name) { - DeserializeRawBytes(args(0).asInstanceOf[Value[SByteArray]], rangeTpe) + if(method.name == SGlobalMethods.deserializeToMethod.name) { + deserializeToBytes(args(0).asInstanceOf[Value[SByteArray]], rangeTpe) } else { processGlobalMethod(srcCtx, method, newArgs) } diff --git a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala index d7962c0ae6..54ad906e39 100644 --- a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala @@ -114,7 +114,7 @@ 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 deserializeRaw[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] + def deserializeTo[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] }; trait CostModelCompanion; trait BigIntCompanion; diff --git a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala index 0385916a67..287786fccc 100644 --- a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala @@ -1970,9 +1970,9 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { true, false, element[Coll[Byte]])) } - override def deserializeRaw[T](l: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { + override def deserializeTo[T](l: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { asRep[T](mkMethodCall(self, - SigmaDslBuilderClass.getMethod("deserializeRaw", classOf[Sym], classOf[Elem[T]]), + SigmaDslBuilderClass.getMethod("deserializeTo", classOf[Sym], classOf[Elem[T]]), Array[AnyRef](l, cT), true, false, element[T])) } @@ -2136,9 +2136,9 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { true, true, element[Coll[Byte]])) } - def deserializeRaw[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { + def deserializeTo[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { asRep[T](mkMethodCall(source, - SigmaDslBuilderClass.getMethod("deserializeRaw", classOf[Sym], classOf[Elem[T]]), + SigmaDslBuilderClass.getMethod("deserializeTo", classOf[Sym], classOf[Elem[T]]), Array[AnyRef](bytes, cT), true, true, element[T])) } @@ -2161,7 +2161,7 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { 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", "deserializeRaw" + "decodePoint", "avlTree", "xor", "deserializeTo" )) } } @@ -2340,9 +2340,9 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { def unapply(exp: Sym): Nullable[(Ref[SigmaDslBuilder], Ref[Coll[Byte]])] = unapply(exp.node) } - object deserializeRaw { + object deserializeTo { def unapply(d: Def[_]): Nullable[(Ref[SigmaDslBuilder], Ref[Coll[Byte]], Elem[T]) forSome {type T}] = d match { - case MethodCall(receiver, method, args, _) if method.getName == "deserializeRaw" && receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] => + case MethodCall(receiver, method, args, _) if method.getName == "deserializeTo" && receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] => val res = (receiver, args(0), args(1)) Nullable(res).asInstanceOf[Nullable[(Ref[SigmaDslBuilder], Ref[Coll[Byte]], Elem[T]) forSome {type T}]] case _ => Nullable.None diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 35d6b022d2..8b8a538f71 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -180,12 +180,12 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - property("deserializeRaw - int") { + property("deserializeTo - int") { val value = -109253 val w = new VLQByteBufferWriter(new ByteArrayBuilder()).putInt(value) val bytes = Base16.encode(w.toBytes) - def deserTest() = {test("deserializeRaw", env, ext, - s"{ val ba = fromBase16(\"$bytes\"); Global.deserializeRaw[Int](ba) == $value }", + def deserTest() = {test("deserializeTo", env, ext, + s"{ val ba = fromBase16(\"$bytes\"); Global.deserializeTo[Int](ba) == $value }", null, true )} @@ -197,14 +197,14 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - coll[int]") { + property("deserializeTo - coll[int]") { val writer = new SigmaByteWriter(new VLQByteBufferWriter(new ByteArrayBuilder()), None) DataSerializer.serialize[SCollection[SInt.type]](Colls.fromArray(Array(IntConstant(5).value)), SCollection(SInt), writer) val bytes = Base16.encode(writer.toBytes) def deserTest() = { - test("deserializeRaw", env, ext, - s"{val ba = fromBase16(\"$bytes\"); val coll = Global.deserializeRaw[Coll[Int]](ba); coll(0) == 5 }", + test("deserializeTo", env, ext, + s"{val ba = fromBase16(\"$bytes\"); val coll = Global.deserializeTo[Coll[Int]](ba); coll(0) == 5 }", null, true ) @@ -217,16 +217,16 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - long") { + property("deserializeTo - long") { val value = -10009253L val w = new VLQByteBufferWriter(new ByteArrayBuilder()).putLong(value) val bytes = Base16.encode(w.toBytes) - def deserTest() = test("deserializeRaw", env, ext, + def deserTest() = test("deserializeTo", env, ext, s"""{ val ba = fromBase16("$bytes"); - Global.deserializeRaw[Long](ba) == ${value}L + Global.deserializeTo[Long](ba) == ${value}L }""", null, true @@ -239,12 +239,12 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - box rountrip") { - def deserTest() = test("deserializeRaw", env, ext, + property("deserializeTo - box rountrip") { + def deserTest() = test("deserializeTo", env, ext, s"""{ val b = INPUTS(0); val ba = b.bytes; - Global.deserializeRaw[Box](ba) == b + Global.deserializeTo[Box](ba) == b }""", null, true @@ -257,7 +257,7 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - bigint") { + property("deserializeTo - bigint") { val bigInt = SecP256K1Group.q.divide(new BigInteger("512")) val biBytes = bigInt.toByteArray @@ -267,10 +267,10 @@ class BasicOpsSpecification extends CompilerTestingCommons val bytes = Base16.encode(lengthBytes ++ biBytes) - def deserTest() = test("deserializeRaw", env, ext, + def deserTest() = test("deserializeTo", env, ext, s"""{ val ba = fromBase16("$bytes"); - val b = Global.deserializeRaw[BigInt](ba) + val b = Global.deserializeTo[BigInt](ba) b == bigInt("${bigInt.toString}") }""", null, @@ -284,14 +284,14 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - short") { + property("deserializeTo - short") { val s = (-1925).toShort val w = new VLQByteBufferWriter(new ByteArrayBuilder()).putShort(s) val bytes = Base16.encode(w.toBytes) - def deserTest() = test("deserializeRaw", env, ext, + def deserTest() = test("deserializeTo", env, ext, s"""{ val ba = fromBase16("$bytes"); - Global.deserializeRaw[Short](ba) == -1925 + Global.deserializeTo[Short](ba) == -1925 }""", null, true @@ -304,14 +304,14 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - group element") { + property("deserializeTo - group element") { val ge = Helpers.decodeGroupElement("026930cb9972e01534918a6f6d6b8e35bc398f57140d13eb3623ea31fbd069939b") val ba = Base16.encode(ge.getEncoded.toArray) - def deserTest() = test("deserializeRaw", env, Seq(21.toByte -> GroupElementConstant(ge)), + def deserTest() = test("deserializeTo", env, Seq(21.toByte -> GroupElementConstant(ge)), s"""{ val ge = getVar[GroupElement](21).get val ba = fromBase16("$ba"); - val ge2 = Global.deserializeRaw[GroupElement](ba) + val ge2 = Global.deserializeTo[GroupElement](ba) ba == ge2.getEncoded && ge == ge2 }""", null, @@ -324,14 +324,14 @@ class BasicOpsSpecification extends CompilerTestingCommons deserTest() } } - - property("deserializeRaw - sigmaprop roundtrip") { - def deserTest() = test("deserializeRaw", env, ext, + property("deserializeTo - sigmaprop roundtrip") { + + def deserTest() = test("deserializeTo", env, ext, s"""{ val bytes = getVar[Coll[Byte]]($propBytesVar1).get val ba = bytes.slice(2, bytes.size) - val prop = Global.deserializeRaw[SigmaProp](ba) + val prop = Global.deserializeTo[SigmaProp](ba) prop == getVar[SigmaProp]($propVar3).get && prop }""", null, @@ -345,13 +345,13 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - .propBytes") { - def deserTest() = test("deserializeRaw", env, ext, + property("deserializeTo - .propBytes") { + 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 prop = Global.deserializeRaw[SigmaProp](ba) + val prop = Global.deserializeTo[SigmaProp](ba) prop == p1 && prop }""", null, @@ -365,16 +365,16 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - sigmaprop roundtrip - non evaluated") { + property("deserializeTo - sigmaprop roundtrip - non evaluated") { val script = GT(Height, IntConstant(-1)).toSigmaProp val scriptBytes = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(ErgoTree.fromProposition(script)) val customExt = Seq(21.toByte -> ByteArrayConstant(scriptBytes)) - def deserTest() = test("deserializeRaw", env, customExt, + def deserTest() = test("deserializeTo", env, customExt, s"""{ val ba = getVar[Coll[Byte]](21).get - val prop = Global.deserializeRaw[SigmaProp](ba) + val prop = Global.deserializeTo[SigmaProp](ba) prop }""", null, @@ -388,7 +388,7 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - avltree") { + property("deserializeTo - avltree") { val elements = Seq(123, 22) val treeElements = elements.map(i => Longs.toByteArray(i)).map(s => (ADKey @@@ Blake2b256(s), ADValue @@ s)) val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None) @@ -399,10 +399,10 @@ class BasicOpsSpecification extends CompilerTestingCommons val customExt = Seq(21.toByte -> ByteArrayConstant(treeBytes)) - def deserTest() = test("deserializeRaw", env, customExt, + def deserTest() = test("deserializeTo", env, customExt, s"""{ val ba = getVar[Coll[Byte]](21).get - val tree = Global.deserializeRaw[AvlTree](ba) + val tree = Global.deserializeTo[AvlTree](ba) tree.digest == fromBase16(${Base16.encode(treeData.digest.toArray)}) && tree.enabledOperations == 0 && tree.keyLength == 32 @@ -415,7 +415,7 @@ class BasicOpsSpecification extends CompilerTestingCommons an [Exception] should be thrownBy deserTest() } - property("deserializeRaw - header") { + property("deserializeTo - header") { val td = new SigmaTestingData {} val h1 = td.TestData.h1 val headerBytes = h1.bytes @@ -423,12 +423,12 @@ class BasicOpsSpecification extends CompilerTestingCommons val headerStateBytes = AvlTreeData.serializer.toBytes(Extensions.CoreAvlTreeOps(h1.stateRoot).toAvlTreeData) val customExt = Seq(21.toByte -> ByteArrayConstant(headerBytes), 22.toByte -> ByteArrayConstant(headerStateBytes)) - def deserTest() = test("deserializeRaw", env, customExt, + def deserTest() = test("deserializeTo", env, customExt, s"""{ val ba = getVar[Coll[Byte]](21).get - val header = Global.deserializeRaw[Header](ba) + val header = Global.deserializeTo[Header](ba) val ba2 = getVar[Coll[Byte]](22).get - val tree = Global.deserializeRaw[AvlTree](ba2) + val tree = Global.deserializeTo[AvlTree](ba2) val id = fromBase16("${Base16.encode(h1.id.toArray)}") header.height == ${h1.height} && header.stateRoot == tree && header.id == id }""", @@ -443,17 +443,17 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("deserializeRaw - header option") { + property("deserializeTo - header option") { val td = new SigmaTestingData {} val h1 = td.TestData.h1 val headerBytes = Colls.fromArray(Array(1.toByte) ++ h1.bytes.toArray) val customExt = Seq(21.toByte -> ByteArrayConstant(headerBytes)) - def deserTest() = test("deserializeRaw", env, customExt, + def deserTest() = test("deserializeTo", env, customExt, s"""{ val ba = getVar[Coll[Byte]](21).get - val headerOpt = Global.deserializeRaw[Option[Header]](ba) + val headerOpt = Global.deserializeTo[Option[Header]](ba) val header = headerOpt.get val id = fromBase16("${Base16.encode(h1.id.toArray)}") header.height == ${h1.height} && header.id == id From 60a111b7512cf59763037abc877404c3f418966e Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sat, 18 May 2024 21:55:14 +0300 Subject: [PATCH 040/123] unused import fix --- .../shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index cbe94a9bfa..59f12741a9 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -6,18 +6,16 @@ import org.ergoplatform.validation.ValidationRules import scorex.crypto.hash.{Blake2b256, Sha256} import scorex.util.serialization.VLQByteBufferReader import scorex.utils.Longs -import sigma.ast.{AtLeast, EvaluatedValue, SType, SigmaPropConstant, SubstConstants} +import sigma.ast.{AtLeast, SType, SubstConstants} import sigma.crypto.{CryptoConstants, EcPointType, Ecp} import sigma.eval.Extensions.EvalCollOps -import sigma.exceptions.InvalidType -import sigma.serialization.{ConstantStore, CoreByteReader, CoreByteWriter, DataSerializer, ErgoTreeSerializer, GroupElementSerializer, SigmaByteReader, SigmaSerializer} +import sigma.serialization.{ConstantStore, DataSerializer, GroupElementSerializer, SigmaByteReader, SigmaSerializer} import sigma.util.Extensions.BigIntegerOps import sigma.validation.SigmaValidationSettings import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext} import java.math.BigInteger import java.nio.ByteBuffer -import scala.reflect.ClassTag /** A default implementation of [[SigmaDslBuilder]] interface. * From d3e4040e00c92285c97f6aa950a03773b6d20eff Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 20 May 2024 10:59:26 +0300 Subject: [PATCH 041/123] MethodCall deserialization roundtrip for Global.deserializeTo[] --- .../MethodCallSerializerSpecification.scala | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala index e8a7ba7a2f..de41c58169 100644 --- a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala @@ -1,6 +1,7 @@ package sigma.serialization import sigma.VersionContext +import sigma.ast.SType.tT import sigma.ast._ import sigma.validation.ValidationException @@ -69,7 +70,6 @@ class MethodCallSerializerSpecification extends SerializationSpecification { ) } - property("MethodCall deserialization round trip for Header.bytes") { def code = { val h = HeaderConstant(headerGen.sample.get) @@ -92,4 +92,28 @@ class MethodCallSerializerSpecification extends SerializationSpecification { } ) } + + property("MethodCall deserialization round trip for Global.deserializeTo[]") { + def code = { + val h = HeaderConstant(headerGen.sample.get) + val expr = MethodCall(h, + SGlobalMethods.deserializeToMethod, + Vector(h), + Map(tT -> SHeader) + ) + roundTripTest(expr) + } + + VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) { + code + } + + // sigma.serialization.SerializerException: Don't know how to serialize (sigma.data.CHeader@51dbec76, SHeader) + an[SerializerException] should be thrownBy ( + VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) { + code + } + ) + } + } From 3ccf11ea33c584eae38d3af7baa8e99bd80d829f Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Thu, 23 May 2024 18:11:20 +0200 Subject: [PATCH 042/123] i486-toBytes: fixes after merge --- .../scala/sigmastate/utils/Extensions.scala | 8 ++--- .../scala/sigma/LanguageSpecificationV5.scala | 36 ------------------- .../scala/sigma/LanguageSpecificationV6.scala | 16 +++++++++ 3 files changed, 20 insertions(+), 40 deletions(-) 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/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala index dc6d1f6173..f568515c89 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala @@ -929,42 +929,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ">=", GE.apply)(_ >= _) } -// property("Numeric.toBytes methods equivalence") { -// lazy val toBytes = changedFeature( -// (x: Byte) => x.toBytes, -// (x: Byte) => x.toBytes, -// "{ (x: Byte) => x.toBytes }") -// val cases = Seq( -// (0.toByte, Success(Coll(0.toByte))), -// (1.toByte, Success(Coll(1.toByte))) -// ) -// -// testCases(cases, toBytes) -// } - - property("Byte methods equivalence (new features)") { - 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(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 diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index fd2e18ebfb..e105e4bee9 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -10,6 +10,7 @@ import sigma.eval.{CostDetails, SigmaDsl, TracedCost} import sigma.serialization.ErgoTreeSerializer import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} import sigmastate.exceptions.MethodNotFound +import sigmastate.utils.Extensions.ByteOpsForSigma import sigmastate.utils.Helpers import java.math.BigInteger @@ -473,4 +474,19 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => tree.constants.length shouldBe t2.constants.length tree.root shouldBe t2.root } + + property("Numeric.toBytes methods equivalence") { + lazy val toBytes = newFeature( + { (x: Byte) => x.toBigEndianBytes }, + "{ (x: Byte) => x.toBytes }", + sinceVersion = VersionContext.V6SoftForkVersion) + val cases = Seq( + (0.toByte, Success(Coll(0.toByte))), + (1.toByte, Success(Coll(1.toByte))) + ) + + testCases(cases, toBytes) + } + + } From 3d47f2ac29e975de1754b46ddf210708d8eee088 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 24 May 2024 20:50:25 +0300 Subject: [PATCH 043/123] initial raw, buggy & unversioned unsigned bit int impl --- .../main/scala/sigma/crypto/Platform.scala | 1 + .../src/main/scala/sigma/Evaluation.scala | 2 + .../src/main/scala/sigma/SigmaDsl.scala | 140 +++++++++++++++- .../src/main/scala/sigma/ast/SType.scala | 45 +++++- .../src/main/scala/sigma/data/CBigInt.scala | 43 ++++- .../src/main/scala/sigma/data/package.scala | 1 + .../shared/src/main/scala/sigma/package.scala | 1 + .../serialization/CoreDataSerializer.scala | 11 ++ .../sigma/serialization/TypeSerializer.scala | 3 +- .../main/scala/sigma/ast/SigmaPredef.scala | 12 ++ .../src/main/scala/sigma/ast/trees.scala | 4 +- .../src/main/scala/sigma/ast/values.scala | 16 +- .../scala/sigma/data/CSigmaDslBuilder.scala | 4 +- .../main/scala/sigma/data/ExactIntegral.scala | 2 +- .../sigma/data/UnsignedBigIntegerOps.scala | 98 +++++++++++ .../main/scala/sigma/eval/Extensions.scala | 3 +- .../crypto/BigIntSpecification.scala | 9 ++ .../scala/sigmastate/eval/GraphBuilding.scala | 15 +- .../scala/special/sigma/SigmaDslUnit.scala | 9 ++ .../special/sigma/impl/SigmaDslImpl.scala | 153 ++++++++++++++++++ .../utxo/BasicOpsSpecification.scala | 114 ++++++++++++- .../OracleExamplesSpecification.scala | 2 +- 22 files changed, 668 insertions(+), 20 deletions(-) create mode 100644 data/shared/src/main/scala/sigma/data/UnsignedBigIntegerOps.scala create mode 100644 interpreter/shared/src/test/scala/sigmastate/crypto/BigIntSpecification.scala diff --git a/core/jvm/src/main/scala/sigma/crypto/Platform.scala b/core/jvm/src/main/scala/sigma/crypto/Platform.scala index b71694e81b..13c8d6515e 100644 --- a/core/jvm/src/main/scala/sigma/crypto/Platform.scala +++ b/core/jvm/src/main/scala/sigma/crypto/Platform.scala @@ -185,6 +185,7 @@ object Platform { case _: Int => tpe == SInt case _: Long => tpe == SLong case _: BigInt => tpe == SBigInt + case _: UnsignedBigInt => tpe == SUnsignedBigInt case _: String => tpe == SString // TODO v6.0: remove this case (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905) case _: GroupElement => tpe.isGroupElement case _: SigmaProp => tpe.isSigmaProp diff --git a/core/shared/src/main/scala/sigma/Evaluation.scala b/core/shared/src/main/scala/sigma/Evaluation.scala index d86b7c1650..c3ffcc8896 100644 --- a/core/shared/src/main/scala/sigma/Evaluation.scala +++ b/core/shared/src/main/scala/sigma/Evaluation.scala @@ -25,6 +25,7 @@ object Evaluation { case SAny => AnyType case SUnit => UnitType case SBigInt => BigIntRType + case SUnsignedBigInt => UnsignedBigIntRType case SBox => BoxRType case SContext => ContextRType case SGlobal => SigmaDslBuilderRType @@ -67,6 +68,7 @@ object Evaluation { case AnyType => SAny case UnitType => SUnit case BigIntRType => SBigInt + case UnsignedBigIntRType => SUnsignedBigInt case GroupElementRType => SGroupElement case AvlTreeRType => SAvlTree case ot: OptionType[_] => SOption(rtypeToSType(ot.tA)) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index df2b419273..cc102b6b36 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -5,10 +5,8 @@ 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. - * */ + * Base class for signed 256-bits integers + */ trait BigInt { /** Convert this BigInt value to Byte. * @throws ArithmeticException if overflow happens. @@ -156,6 +154,138 @@ trait BigInt { def |(that: BigInt): BigInt = or(that) } + +trait UnsignedBigInt { + /** Convert this BigInt value to Byte. + * @throws ArithmeticException if overflow happens. + */ + def toByte: Byte + + /** Convert this BigInt value to Short. + * @throws ArithmeticException if overflow happens. + */ + def toShort: Short + + /** Convert this BigInt value to Int. + * @throws ArithmeticException if overflow happens. + */ + def toInt: Int + + /** Convert this BigInt value to Int. + * @throws ArithmeticException if overflow happens. + */ + def toLong: Long + + /** Returns a big-endian representation of this BigInt in a collection of bytes. + * For example, the value {@code 0x1213141516171819} would yield the + * byte array {@code {0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19}}. + * @since 2.0 + */ + def toBytes: Coll[Byte] + + + /** Compares this numeric with that numeric for order. Returns a negative integer, zero, or a positive integer as the + * `this` is less than, equal to, or greater than `that`. + */ + def compareTo(that: UnsignedBigInt): Int + + /** Returns a BigInt whose value is {@code (this + that)}. + * + * @param that value to be added to this BigInt. + * @return { @code this + that} + */ + def add(that: UnsignedBigInt): UnsignedBigInt + def +(that: UnsignedBigInt): UnsignedBigInt = add(that) + + /** Returns a BigInt whose value is {@code (this - that)}. + * + * @param that value to be subtracted from this BigInt. + * @return { @code this - that} + */ + def subtract(that: UnsignedBigInt): UnsignedBigInt + + def -(that: UnsignedBigInt): UnsignedBigInt = subtract(that) + + /** Returns a BigInt whose value is {@code (this * that)}. + * + * @implNote An implementation may offer better algorithmic + * performance when { @code that == this}. + * @param that value to be multiplied by this BigInt. + * @return { @code this * that} + */ + def multiply(that: UnsignedBigInt): UnsignedBigInt + def *(that: UnsignedBigInt): UnsignedBigInt = multiply(that) + + /** Returns a BigInt whose value is {@code (this / that)}. + * + * @param that value by which this BigInt is to be divided. + * @return { @code this / that} + * @throws ArithmeticException if { @code that} is zero. + */ + def divide(that: UnsignedBigInt): UnsignedBigInt + def /(that: UnsignedBigInt): UnsignedBigInt = divide(that) + + /** + * Returns a BigInt whose value is {@code (this mod m}). This method + * differs from {@code remainder} in that it always returns a + * non-negative BigInteger. + * + * @param m the modulus. + * @return { @code this mod m} + * @throws ArithmeticException { @code m} ≤ 0 + * @see #remainder + */ + def mod(m: UnsignedBigInt): UnsignedBigInt + def %(m: UnsignedBigInt): UnsignedBigInt = mod(m) + + /** + * Returns a BigInt whose value is {@code (this % that)}. + * + * @param that value by which this BigInt is to be divided, and the + * remainder computed. + * @return { @code this % that} + * @throws ArithmeticException if { @code that} is zero. + */ + def remainder(that: UnsignedBigInt): UnsignedBigInt + + /** + * Returns the minimum of this BigInteger and {@code val}. + * + * @param that value with which the minimum is to be computed. + * @return the BigInteger whose value is the lesser of this BigInteger and + * { @code val}. If they are equal, either may be returned. + */ + def min(that: UnsignedBigInt): UnsignedBigInt + + /** + * Returns the maximum of this BigInteger and {@code val}. + * + * @param that value with which the maximum is to be computed. + * @return the BigInteger whose value is the greater of this and + * { @code val}. If they are equal, either may be returned. + */ + def max(that: UnsignedBigInt): UnsignedBigInt + + /** Returns a BigInteger whose value is `(this & that)`. + * @param that value to be AND'ed with this BigInteger. + * @return `this & that` + */ + def and(that: UnsignedBigInt): UnsignedBigInt + def &(that: UnsignedBigInt): UnsignedBigInt = and(that) + + /** Returns a BigInteger whose value is `(this | that)`. (This + * method returns a negative BigInteger if and only if either `this` or `that`` is + * negative.) + * + * @param that value to be OR'ed with this BigInteger. + * @return `this | that` + */ + def or(that: UnsignedBigInt): UnsignedBigInt + def |(that: UnsignedBigInt): UnsignedBigInt = or(that) +} + + + /** Base class for points on elliptic curves. */ trait GroupElement { /** Checks if the provided element is an identity element. */ @@ -721,6 +851,8 @@ trait SigmaDslBuilder { /** Create DSL big integer from existing `java.math.BigInteger`*/ def BigInt(n: BigInteger): BigInt + def UnsignedBigInt(n: BigInteger): UnsignedBigInt + /** Extract `java.math.BigInteger` from DSL's `BigInt` type*/ def toBigInteger(n: BigInt): BigInteger diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index f75cbc9e8b..50763ba56e 100644 --- a/core/shared/src/main/scala/sigma/ast/SType.scala +++ b/core/shared/src/main/scala/sigma/ast/SType.scala @@ -4,10 +4,10 @@ import sigma.Evaluation.stypeToRType import sigma.ast.SCollection.SByteArray import sigma.ast.SType.TypeCode import sigma.data.OverloadHack.Overloaded1 -import sigma.data.{CBigInt, Nullable, SigmaConstants} +import sigma.data.{CBigInt, CUnsignedBigInt, 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, UnsignedBigInt} import java.math.BigInteger @@ -156,6 +156,7 @@ object SType { case SInt => x.isInstanceOf[Int] case SLong => x.isInstanceOf[Long] case SBigInt => x.isInstanceOf[BigInt] + case SUnsignedBigInt => x.isInstanceOf[UnsignedBigInt] case SGroupElement => x.isInstanceOf[GroupElement] case SSigmaProp => x.isInstanceOf[SigmaProp] case SBox => x.isInstanceOf[Box] @@ -448,13 +449,12 @@ case object SLong extends SPrimType with SEmbeddable with SNumericType with SMon } } -/** Type of 256 bit integet values. Implemented using [[java.math.BigInteger]]. */ +/** Type of 256-bit signed 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 override val reprClass: RClass[_] = RClass(classOf[BigInt]) override def typeId = typeCode - implicit def typeBigInt: SBigInt.type = this /** Type of Relation binary op like GE, LE, etc. */ val RelationOpType = SFunc(Array(SBigInt, SBigInt), SBoolean) @@ -486,6 +486,43 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM } } +/** Type of 256-bit unsigned integer values. Implemented using [[java.math.BigInteger]]. */ +case object SUnsignedBigInt extends SPrimType with SEmbeddable with SNumericType with SMonoType { + override type WrappedType = UnsignedBigInt + override val typeCode: TypeCode = 9: Byte + override val reprClass: RClass[_] = RClass(classOf[BigInt]) + override def typeId = typeCode + + /** Type of Relation binary op like GE, LE, etc. */ + val RelationOpType = SFunc(Array(SUnsignedBigInt, SUnsignedBigInt), SBoolean) + + /** The maximum size of BigInteger value in byte array representation. */ + val MaxSizeInBytes: Long = SigmaConstants.MaxBigIntSizeInBytes.value // todo: 256 bits or more? + + override def numericTypeIndex: Int = 5 + + override def upcast(v: AnyVal): UnsignedBigInt = { + 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) + case _ => sys.error(s"Cannot upcast value $v to the type $this") + } + CUnsignedBigInt(bi) + } + override def downcast(v: AnyVal): UnsignedBigInt = { + 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) + case _ => sys.error(s"Cannot downcast value $v to the type $this") + } + CUnsignedBigInt(bi) + } +} + /** Descriptor of type `String` which is not used in ErgoTree, but used in ErgoScript. * NOTE: this descriptor both type and type companion */ case object SString extends SProduct with SMonoType { diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index bbf1a85e46..5ae617feba 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -1,7 +1,7 @@ package sigma.data import sigma.util.Extensions.BigIntegerOps -import sigma.{BigInt, Coll, Colls} +import sigma.{BigInt, Coll, Colls, UnsignedBigInt} import java.math.BigInteger @@ -50,3 +50,44 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr override def or(that: BigInt): BigInt = CBigInt(wrappedValue.or(that.asInstanceOf[CBigInt].wrappedValue)) } + +/** A default implementation of [[BigInt]] interface. + * + * @see [[BigInt]] for detailed descriptions + */ +case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends UnsignedBigInt with WrapperOf[BigInteger] { + + override def toByte: Byte = wrappedValue.toByteExact + + override def toShort: Short = wrappedValue.toShortExact + + override def toInt: Int = wrappedValue.toIntExact + + override def toLong: Long = wrappedValue.toLongExact + + override def toBytes: Coll[Byte] = Colls.fromArray(wrappedValue.toByteArray) + + override def compareTo(that: UnsignedBigInt): Int = + wrappedValue.compareTo(that.asInstanceOf[CUnsignedBigInt].wrappedValue) + + //todo: consider result's bits limit + override def add(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.add(that.asInstanceOf[CUnsignedBigInt].wrappedValue).to256BitValueExact) + + override def subtract(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.subtract(that.asInstanceOf[CUnsignedBigInt].wrappedValue).to256BitValueExact) + + override def multiply(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.multiply(that.asInstanceOf[CUnsignedBigInt].wrappedValue).to256BitValueExact) + + override def divide(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.divide(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) + + override def mod(m: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.mod(m.asInstanceOf[CUnsignedBigInt].wrappedValue)) + + override def remainder(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.remainder(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) + + override def min(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.min(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) + + override def max(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.max(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) + + override def and(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.and(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) + + override def or(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.or(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) +} diff --git a/core/shared/src/main/scala/sigma/data/package.scala b/core/shared/src/main/scala/sigma/data/package.scala index c5a35f7b5f..58870c0888 100644 --- a/core/shared/src/main/scala/sigma/data/package.scala +++ b/core/shared/src/main/scala/sigma/data/package.scala @@ -14,6 +14,7 @@ package object data { val StringClassTag = classTag[String] val BigIntClassTag = classTag[BigInt] + val UnsignedBigIntClassTag = classTag[UnsignedBigInt] val GroupElementClassTag = classTag[GroupElement] val SigmaPropClassTag = classTag[SigmaProp] val SigmaBooleanClassTag = classTag[SigmaBoolean] diff --git a/core/shared/src/main/scala/sigma/package.scala b/core/shared/src/main/scala/sigma/package.scala index 89b883f52d..4473bd338f 100644 --- a/core/shared/src/main/scala/sigma/package.scala +++ b/core/shared/src/main/scala/sigma/package.scala @@ -26,6 +26,7 @@ package object sigma { implicit val StringType : RType[String] = GeneralType(StringClassTag) implicit val BigIntRType : RType[BigInt] = GeneralType(BigIntClassTag) + implicit val UnsignedBigIntRType : RType[UnsignedBigInt] = GeneralType(UnsignedBigIntClassTag) implicit val GroupElementRType: RType[GroupElement] = GeneralType(GroupElementClassTag) implicit val SigmaPropRType : RType[SigmaProp] = GeneralType(SigmaPropClassTag) implicit val SigmaBooleanRType: RType[SigmaBoolean] = GeneralType(SigmaBooleanClassTag) diff --git a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala index 479b199da5..834edfb9a4 100644 --- a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala +++ b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala @@ -33,6 +33,10 @@ class CoreDataSerializer { val data = v.asInstanceOf[BigInt].toBigInteger.toByteArray w.putUShort(data.length) w.putBytes(data) + case SUnsignedBigInt => // todo: versioning + val data = v.asInstanceOf[CUnsignedBigInt].wrappedValue.toByteArray + w.putUShort(data.length) + w.putBytes(data) case SGroupElement => GroupElementSerializer.serialize(v.asInstanceOf[GroupElement].toECPoint, w) case SSigmaProp => @@ -103,6 +107,13 @@ class CoreDataSerializer { } val valueBytes = r.getBytes(size) CBigInt(new BigInteger(valueBytes)) + case SUnsignedBigInt => // todo: versioning + val size: Short = r.getUShort().toShort + if (size > SBigInt.MaxSizeInBytes + 1) { //todo: use encoding with no sign bit + throw new SerializerException(s"BigInt value doesn't not fit into ${SBigInt.MaxSizeInBytes} bytes: $size") + } + val valueBytes = r.getBytes(size) + CUnsignedBigInt(new BigInteger(valueBytes)) case SGroupElement => CGroupElement(GroupElementSerializer.parse(r)) case SSigmaProp => diff --git a/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala b/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala index 9c84de0944..f00421a31c 100644 --- a/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala +++ b/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala @@ -215,6 +215,7 @@ class TypeSerializer { object TypeSerializer extends TypeSerializer { /** The list of embeddable types, i.e. types that can be combined with type constructor for optimized encoding. * For each embeddable type `T`, and type constructor `C`, the type `C[T]` can be represented by single byte. */ - val embeddableIdToType = Array[SType](null, SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp) + //todo: versioning + val embeddableIdToType = Array[SType](null, SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnsignedBigInt) } \ No newline at end of file diff --git a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala index 631f7f2d75..d8c65a7afe 100644 --- a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala +++ b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala @@ -192,6 +192,17 @@ object SigmaPredef { Seq(ArgInfo("", ""))) ) + val UBigIntFromStringFunc = PredefinedFunc("unsignedBigInt", + Lambda(Array("input" -> SString), SUnsignedBigInt, None), + PredefFuncInfo( + { case (_, Seq(arg: EvaluatedValue[SString.type]@unchecked)) => + UnsignedBigIntConstant(new BigInteger(arg.value)) + }), + OperationInfo(Constant, + """Parsing string literal argument as a 256-bit unsigned big integer.""".stripMargin, + Seq(ArgInfo("", ""))) + ) + val FromBase16Func = PredefinedFunc("fromBase16", Lambda(Array("input" -> SString), SByteArray, None), PredefFuncInfo( @@ -416,6 +427,7 @@ object SigmaPredef { GetVarFunc, DeserializeFunc, BigIntFromStringFunc, + UBigIntFromStringFunc, FromBase16Func, FromBase64Func, FromBase58Func, diff --git a/data/shared/src/main/scala/sigma/ast/trees.scala b/data/shared/src/main/scala/sigma/ast/trees.scala index 39e666a389..7be73ad55a 100644 --- a/data/shared/src/main/scala/sigma/ast/trees.scala +++ b/data/shared/src/main/scala/sigma/ast/trees.scala @@ -15,6 +15,7 @@ import sigma.serialization.CoreByteWriter.ArgInfo import sigma.validation.SigmaValidationSettings import sigma.{Coll, Colls, GroupElement, SigmaProp, VersionContext} import NumericOps.{BigIntIsExactIntegral, BigIntIsExactOrdering} +import sigma.data.UnsignedBigIntNumericOps.{UnsignedBigIntIsExactIntegral, UnsignedBigIntIsExactOrdering} import sigma.eval.ErgoTreeEvaluator.DataEnv import sigma.eval.Extensions.EvalCollOps import sigma.eval.{ErgoTreeEvaluator, SigmaDsl} @@ -875,7 +876,8 @@ object ArithOp { SShort -> new OperationImpl(ShortIsExactIntegral, ShortIsExactOrdering, SShort), SInt -> new OperationImpl(IntIsExactIntegral, IntIsExactOrdering, SInt), SLong -> new OperationImpl(LongIsExactIntegral, LongIsExactOrdering, SLong), - SBigInt -> new OperationImpl(BigIntIsExactIntegral, BigIntIsExactOrdering, SBigInt) + SBigInt -> new OperationImpl(BigIntIsExactIntegral, BigIntIsExactOrdering, SBigInt), + SUnsignedBigInt -> new OperationImpl(UnsignedBigIntIsExactIntegral, UnsignedBigIntIsExactOrdering, SUnsignedBigInt) ).map { case (t, n) => (t.typeCode, n) }) /** Returns operation name for the given opCode. */ diff --git a/data/shared/src/main/scala/sigma/ast/values.scala b/data/shared/src/main/scala/sigma/ast/values.scala index 87c661a00a..8c55d27a94 100644 --- a/data/shared/src/main/scala/sigma/ast/values.scala +++ b/data/shared/src/main/scala/sigma/ast/values.scala @@ -8,7 +8,7 @@ import sigma.ast.TypeCodes.ConstantCode import sigma.ast.syntax._ import sigma.crypto.{CryptoConstants, EcPointType} import sigma.data.OverloadHack.Overloaded1 -import sigma.data.{CSigmaDslBuilder, CSigmaProp, Nullable, RType, SigmaBoolean} +import sigma.data.{CSigmaDslBuilder, CSigmaProp, CUnsignedBigInt, Nullable, RType, SigmaBoolean} import sigma.eval.ErgoTreeEvaluator.DataEnv import sigma.eval.{ErgoTreeEvaluator, SigmaDsl} import sigma.exceptions.InterpreterException @@ -499,6 +499,20 @@ object BigIntConstant { def apply(value: Long): Constant[SBigInt.type] = Constant[SBigInt.type](SigmaDsl.BigInt(BigInteger.valueOf(value)), SBigInt) } +object UnsignedBigIntConstant { + def apply(value: UnsignedBigInt): Constant[SUnsignedBigInt.type] = { + Constant[SUnsignedBigInt.type](value, SUnsignedBigInt) + } + + def apply(value: BigInteger): Constant[SUnsignedBigInt.type] = { + Constant[SUnsignedBigInt.type](CUnsignedBigInt(value), SUnsignedBigInt) + } + + def apply(value: Long): Constant[SUnsignedBigInt.type] = { + Constant[SUnsignedBigInt.type](CUnsignedBigInt(BigInteger.valueOf(value)), SUnsignedBigInt) + } +} + object StringConstant { def apply(value: String): Constant[SString.type] = Constant[SString.type](value, SString) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 3938feacd3..4a3842e250 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -11,7 +11,7 @@ import sigma.eval.Extensions.EvalCollOps import sigma.serialization.{GroupElementSerializer, 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, GroupElement, SigmaDslBuilder, SigmaProp, UnsignedBigInt, VersionContext} import java.math.BigInteger @@ -26,6 +26,8 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => override def BigInt(n: BigInteger): BigInt = CBigInt(n) + override def UnsignedBigInt(n: BigInteger): UnsignedBigInt = CUnsignedBigInt(n) + override def toBigInteger(n: BigInt): BigInteger = n.asInstanceOf[CBigInt].wrappedValue /** Wraps the given elliptic curve point into GroupElement type. */ diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index 34e2f47f63..70158b828f 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -2,7 +2,7 @@ package sigma.data import sigma.util.Extensions.{ByteOps, ShortOps} -/** Type-class which defines the operations on Integral types (Byte, Short, Int, Long, BigInt) +/** Type-class which defines the operations on Integral types (Byte, Short, Int, Long, BigInt, UnsignedBigInt) * with overflow checks. * * An exception is raised when an overflow is detected. diff --git a/data/shared/src/main/scala/sigma/data/UnsignedBigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/UnsignedBigIntegerOps.scala new file mode 100644 index 0000000000..77b4a339e4 --- /dev/null +++ b/data/shared/src/main/scala/sigma/data/UnsignedBigIntegerOps.scala @@ -0,0 +1,98 @@ +package sigma.data + +import sigma._ +import sigma.data.UnsignedBigIntOrderingOps.UnsignedBigIntOrdering +import sigma.eval.Extensions.IntExt + +import scala.math.{Integral, Ordering} + +object UnsignedBigIntOrderingOps { + def apply[T](implicit ord: Ordering[T]) = ord + + trait UnsignedBigIntOrdering extends Ordering[UnsignedBigInt] { + def compare(x: UnsignedBigInt, y: UnsignedBigInt) = x.compareTo(y) + } + implicit object UnsignedBigIntOrdering extends UnsignedBigIntOrdering +} + +object UnsignedBigIntNumericOps { + + /** Base implementation of Integral methods for UnsignedBigInt. */ + trait UnsignedBigIntIsIntegral extends Integral[UnsignedBigInt] { + /** This method should not be used in v4.x */ + def quot(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.divide(y) + + /** This method is used in ErgoTreeEvaluator based interpreter, to implement + * '%' operation of ErgoTree (i.e. `%: (T, T) => T` operation) for all + * numeric types T including BigInt. + * + * In the v4.x interpreter, however, the `%` operation is implemented using + * [[CBigInt]].mod method , which delegates to [[java.math.BigInteger]].mod method. + * + * Even though this method is called `rem`, the semantics of ErgoTree + * language requires it to correspond to [[java.math.BigInteger]].mod + * method. + * + * For this reason we define implementation of this `rem` method using + * [[BigInt]].mod. + * + * NOTE: This method should not be used in v4.x + */ + def rem(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.mod(y) + + def plus(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.add(y) + def minus(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.subtract(y) + def times(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.multiply(y) + def negate(x: UnsignedBigInt): UnsignedBigInt = ??? + def fromInt(x: Int): UnsignedBigInt = x.toUnsignedBigInt + def toInt(x: UnsignedBigInt): Int = x.toInt + def toLong(x: UnsignedBigInt): Long = x.toLong + def toFloat(x: UnsignedBigInt): Float = ??? + def toDouble(x: UnsignedBigInt): Double = ??? + } + + /** The instance of Integral for BigInt. + * + * Note: ExactIntegral was not defined for [[sigma.BigInt]] in v4.x. + * This is because arithmetic BigInt operations were handled in a special way + * (see `case op: ArithOp[t] if op.tpe == SBigInt =>` in RuntimeCosting.scala). + * As result [[scalan.primitives.UnBinOps.ApplyBinOp]] nodes were not created for + * BigInt operations in v4.x., and hence operation descriptors such as + * [[scalan.primitives.NumericOps.IntegralDivide]] and + * [[scalan.primitives.NumericOps.IntegralMod]] were not used for BigInt. + * NOTE: this instance is used in the new v5.0 interpreter. + */ + object UnsignedBigIntIsIntegral extends UnsignedBigIntIsIntegral with UnsignedBigIntOrdering { + def parseString(str: String): Option[UnsignedBigInt] = ??? + } + + /** The instance of [[ExactIntegral]] typeclass for [[BigInt]]. */ + implicit object UnsignedBigIntIsExactIntegral extends ExactIntegral[UnsignedBigInt] { + val n = UnsignedBigIntIsIntegral + override def plus(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = n.plus(x, y) + override def minus(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = n.minus(x, y) + override def times(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = n.times(x, y) + + override def quot(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.divide(y) + + /** This method is used in ErgoTreeEvaluator based interpreter, to implement + * '%' operation of ErgoTree (i.e. `%: (T, T) => T` operation) for all + * numeric types T including BigInt. + * + * In the v4.x interpreter, however, the `%` operation is implemented using + * [[CBigInt]].mod method, which delegates to [[java.math.BigInteger]].mod method. + * + * Even though this method is called `divisionRemainder`, the semantics of ErgoTree + * language requires it to correspond to [[java.math.BigInteger]].mod method. + * + * For this reason we define implementation of this method using [[BigInt]].mod. + * + * NOTE: This method should not be used in v4.x + */ + override def divisionRemainder(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.mod(y) + } + + /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */ + implicit object UnsignedBigIntIsExactOrdering extends ExactOrderingImpl[UnsignedBigInt](UnsignedBigIntIsIntegral) +} + diff --git a/data/shared/src/main/scala/sigma/eval/Extensions.scala b/data/shared/src/main/scala/sigma/eval/Extensions.scala index def9086e02..520d97377d 100644 --- a/data/shared/src/main/scala/sigma/eval/Extensions.scala +++ b/data/shared/src/main/scala/sigma/eval/Extensions.scala @@ -2,7 +2,7 @@ package sigma.eval import sigma.ast.syntax.SigmaPropValue import sigma.data.{CAnyValue, CSigmaDslBuilder, Nullable, RType, SigmaBoolean} -import sigma.{BigInt, Coll, Colls, Evaluation, Platform} +import sigma.{BigInt, Coll, Colls, Evaluation, Platform, UnsignedBigInt} import sigma.ast.{Constant, ConstantNode, SBoolean, SCollection, SCollectionType, SType, SigmaPropConstant, SigmaPropIsProven, TransformingSigmaBuilder, Value} import java.math.BigInteger @@ -19,6 +19,7 @@ object Extensions { implicit class IntExt(val x: Int) extends AnyVal { /** Convert this value to BigInt. */ @inline def toBigInt: BigInt = CSigmaDslBuilder.BigInt(BigInteger.valueOf(x.toLong)) + @inline def toUnsignedBigInt: UnsignedBigInt = CSigmaDslBuilder.UnsignedBigInt(BigInteger.valueOf(x.toLong)) } implicit class LongExt(val x: Long) extends AnyVal { diff --git a/interpreter/shared/src/test/scala/sigmastate/crypto/BigIntSpecification.scala b/interpreter/shared/src/test/scala/sigmastate/crypto/BigIntSpecification.scala new file mode 100644 index 0000000000..2662ff0a7a --- /dev/null +++ b/interpreter/shared/src/test/scala/sigmastate/crypto/BigIntSpecification.scala @@ -0,0 +1,9 @@ +package sigmastate.crypto + +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import sigmastate.TestsBase + +class BigIntSpecification extends AnyPropSpec with ScalaCheckPropertyChecks with TestsBase { + +} diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index 5ddcdfa946..e06e37272e 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -14,6 +14,7 @@ import sigma.data.{CSigmaDslBuilder, ExactIntegral, ExactNumeric, ExactOrdering, import sigma.util.Extensions.ByteOps import sigmastate.interpreter.Interpreter.ScriptEnv import sigma.ast.{Ident, Select, Val} +import sigma.data.UnsignedBigIntNumericOps.{UnsignedBigIntIsExactIntegral, UnsignedBigIntIsExactOrdering} import sigma.exceptions.GraphBuildingException import sigma.serialization.OpCodes @@ -30,6 +31,7 @@ import scala.collection.mutable.ArrayBuffer trait GraphBuilding extends SigmaLibrary { IR: IRContext => import AvlTree._ import BigInt._ + import UnsignedBigInt._ import Box._ import Coll._ import CollBuilder._ @@ -255,6 +257,7 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => case SString => StringElement case SAny => AnyElement case SBigInt => bigIntElement + case SUnsignedBigInt => unsignedBigIntElement case SBox => boxElement case SContext => contextElement case SGlobal => sigmaDslBuilderElement @@ -281,6 +284,7 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => case StringElement => SString case AnyElement => SAny case _: BigIntElem[_] => SBigInt + case _: UnsignedBigIntElem[_] => SUnsignedBigInt case _: GroupElementElem[_] => SGroupElement case _: AvlTreeElem[_] => SAvlTree case oe: WOptionElem[_, _] => SOption(elemToSType(oe.eItem)) @@ -308,6 +312,7 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => case StringElement => StringIsLiftable case UnitElement => UnitIsLiftable case _: BigIntElem[_] => LiftableBigInt + case _: UnsignedBigIntElem[_] => LiftableUnsignedBigInt case _: GroupElementElem[_] => LiftableGroupElement case ce: CollElem[t,_] => implicit val lt = liftableFromElem[t](ce.eItem) @@ -328,7 +333,8 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => (ShortElement, ShortIsExactIntegral), (IntElement, IntIsExactIntegral), (LongElement, LongIsExactIntegral), - (bigIntElement, BigIntIsExactIntegral) + (bigIntElement, BigIntIsExactIntegral), + (unsignedBigIntElement, UnsignedBigIntIsExactIntegral) ) private lazy val elemToExactIntegralMap = Map[Elem[_], ExactIntegral[_]]( (ByteElement, ByteIsExactIntegral), @@ -341,7 +347,8 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => (ShortElement, ShortIsExactOrdering), (IntElement, IntIsExactOrdering), (LongElement, LongIsExactOrdering), - (bigIntElement, BigIntIsExactOrdering) + (bigIntElement, BigIntIsExactOrdering), + (unsignedBigIntElement, UnsignedBigIntIsExactOrdering) ) /** @return [[ExactNumeric]] instance for the given type */ @@ -439,6 +446,10 @@ trait GraphBuilding extends SigmaLibrary { IR: IRContext => assert(tpe == SBigInt) val resV = liftConst(bi) resV + case ubi: SUnsignedBigInt => + assert(tpe == SUnsignedBigInt) + val resV = liftConst(ubi) + resV case p: SGroupElement => assert(tpe == SGroupElement) val resV = liftConst(p) diff --git a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala index 48548226a5..4984f2f35d 100644 --- a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala @@ -12,6 +12,15 @@ package sigma { def min(that: Ref[BigInt]): Ref[BigInt]; def max(that: Ref[BigInt]): Ref[BigInt]; }; + trait UnsignedBigInt extends Def[UnsignedBigInt] { + def add(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; + def subtract(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; + def multiply(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; + def divide(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; + def mod(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; + def min(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; + def max(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; + }; trait GroupElement extends Def[GroupElement] { def exp(k: Ref[BigInt]): Ref[GroupElement]; def multiply(that: Ref[GroupElement]): Ref[GroupElement]; diff --git a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala index 70fb35c329..fb4360e05c 100644 --- a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala @@ -263,6 +263,159 @@ object BigInt extends EntityObject("BigInt") { } // of object BigInt registerEntityObject("BigInt", BigInt) +object UnsignedBigInt extends EntityObject("UnsignedBigInt") { + import Liftables._ + + type SUnsignedBigInt = sigma.UnsignedBigInt + unsignedBigIntElement + + case class UnsignedBigIntConst(constValue: SUnsignedBigInt) + extends LiftedConst[SUnsignedBigInt, UnsignedBigInt] with UnsignedBigInt + with Def[UnsignedBigInt] with UnsignedBigIntConstMethods { + val liftable: Liftable[SUnsignedBigInt, UnsignedBigInt] = LiftableUnsignedBigInt + val resultType: Elem[UnsignedBigInt] = liftable.eW + } + + trait UnsignedBigIntConstMethods extends UnsignedBigInt { thisConst: Def[_] => + + private val UnsignedBigIntClass = RClass(classOf[UnsignedBigInt]) + + override def add(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("add", classOf[Sym]), + Array[AnyRef](that), + true, false, element[UnsignedBigInt])) + } + + override def subtract(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("subtract", classOf[Sym]), + Array[AnyRef](that), + true, false, element[UnsignedBigInt])) + } + + override def multiply(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("multiply", classOf[Sym]), + Array[AnyRef](that), + true, false, element[UnsignedBigInt])) + } + + override def divide(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("divide", classOf[Sym]), + Array[AnyRef](that), + true, false, element[UnsignedBigInt])) + } + + override def mod(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("mod", classOf[Sym]), + Array[AnyRef](m), + true, false, element[UnsignedBigInt])) + } + + override def min(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("min", classOf[Sym]), + Array[AnyRef](that), + true, false, element[UnsignedBigInt])) + } + + override def max(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("max", classOf[Sym]), + Array[AnyRef](that), + true, false, element[UnsignedBigInt])) + } + } + + + implicit object LiftableUnsignedBigInt extends Liftable[SUnsignedBigInt, UnsignedBigInt] { + lazy val eW: Elem[UnsignedBigInt] = unsignedBigIntElement + lazy val sourceType: RType[SUnsignedBigInt] = { + RType[SUnsignedBigInt] + } + + def lift(x: SUnsignedBigInt): Ref[UnsignedBigInt] = UnsignedBigIntConst(x) + } + + private val UnsignedBigIntClass = RClass(classOf[UnsignedBigInt]) + + // entityAdapter for BigInt trait + case class UnsignedBigIntAdapter(source: Ref[UnsignedBigInt]) + extends Node with UnsignedBigInt + with Def[UnsignedBigInt] { + val resultType: Elem[UnsignedBigInt] = element[UnsignedBigInt] + + override def transform(t: Transformer) = UnsignedBigIntAdapter(t(source)) + + def add(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("add", classOf[Sym]), + Array[AnyRef](that), + true, true, element[UnsignedBigInt])) + } + + def subtract(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("subtract", classOf[Sym]), + Array[AnyRef](that), + true, true, element[UnsignedBigInt])) + } + + def multiply(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("multiply", classOf[Sym]), + Array[AnyRef](that), + true, true, element[UnsignedBigInt])) + } + + def divide(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("divide", classOf[Sym]), + Array[AnyRef](that), + true, true, element[UnsignedBigInt])) + } + + def mod(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("mod", classOf[Sym]), + Array[AnyRef](m), + true, true, element[UnsignedBigInt])) + } + + def min(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("min", classOf[Sym]), + Array[AnyRef](that), + true, true, element[UnsignedBigInt])) + } + + def max(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("max", classOf[Sym]), + Array[AnyRef](that), + true, true, element[UnsignedBigInt])) + } + } + + class UnsignedBigIntElem[To <: UnsignedBigInt] + extends EntityElem[To] { + override val liftable: Liftables.Liftable[_, To] = asLiftable[SUnsignedBigInt, To](LiftableUnsignedBigInt) + + override protected def collectMethods: Map[RMethod, MethodDesc] = { + super.collectMethods ++ + Elem.declaredMethods(RClass(classOf[UnsignedBigInt]), RClass(classOf[UnsignedBigInt]), Set( + "add", "subtract", "multiply", "divide", "mod", "min", "max" + )) + } + } + + implicit lazy val unsignedBigIntElement: Elem[UnsignedBigInt] = new UnsignedBigIntElem[UnsignedBigInt] +} // of object BigInt + registerEntityObject("UnsignedBigInt", UnsignedBigInt) + object GroupElement extends EntityObject("GroupElement") { // entityConst: single const for each entity import Liftables._ diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 79701d6e07..621e32ad3f 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -2,14 +2,17 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ +import scorex.util.encode.Base16 import sigma.Extensions.ArrayOps +import sigma.GroupElement +import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps -import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder} +import sigma.data.{AvlTreeData, CAnyValue, CBigInt, CGroupElement, CSigmaDslBuilder} import sigma.util.StringUtil._ import sigma.ast._ import sigma.ast.syntax._ -import sigma.crypto.CryptoConstants +import sigma.crypto.{CryptoConstants, SecP256K1Group} import sigmastate._ import sigmastate.helpers.TestingHelpers._ import sigmastate.helpers.{CompilerTestingCommons, ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestInterpreter} @@ -22,6 +25,8 @@ import sigma.exceptions.InvalidType import sigmastate.utils.Helpers._ import java.math.BigInteger +import java.security.SecureRandom +import scala.annotation.tailrec class BasicOpsSpecification extends CompilerTestingCommons with CompilerCrossVersionProps { @@ -135,6 +140,111 @@ class BasicOpsSpecification extends CompilerTestingCommons flexVerifier.verify(verifyEnv, tree, ctxExt, pr.proof, fakeMessage).get._1 shouldBe true } + property("group order serialization") { + val value = SecP256K1Group.q.divide(new BigInteger("2")) + + def deserTest() = {test("big int - q", env, ext, + s"{ val b = bigInt(\"${value.toString}\"); b > 1 }", + null, + true + )} + + if (activatedVersionInTests < V6SoftForkVersion) { + deserTest() + } else { + deserTest() + } + } + + property("restoring unsigned 256 bits") { + val b = new BigInteger("92805629300808893548929804498612226467505866636839045998233220279839291898608") + val ub = new BigInteger(1, b.toByteArray) + + def deserTest() = {test("restoring", env, ext, + s"{ val b = unsignedBigInt(\"${ub.toString}\"); b > 1 }", + null, + true + )} + + deserTest() + } + + property("signed <-> unsigned bigint conversion") { + + } + + property("schnorr sig check") { + + val g = CGroupElement(SecP256K1Group.generator) + + def randBigInt: BigInt = { + val random = new SecureRandom() + val values = new Array[Byte](32) + random.nextBytes(values) + BigInt(values).mod(SecP256K1Group.q) + } + + @tailrec + def sign(msg: Array[Byte], secretKey: BigInt): (GroupElement, BigInt) = { + val r = randBigInt + + val a: GroupElement = g.exp(CBigInt(r.bigInteger)) + val z = (r + secretKey * BigInt(scorex.crypto.hash.Blake2b256(msg))) % CryptoConstants.groupOrder + + if(z.bitLength > 255) { + println("z: " + z) + (a, z) + } else { + sign(msg,secretKey) + } + } + + val holderSecret = randBigInt + val holderPk = g.exp(CBigInt(holderSecret.bigInteger)) + + val message = Array.fill(5)(1.toByte) + + val (a,z) = sign(message, holderSecret) + + val customExt: Seq[(Byte, EvaluatedValue[_ <: SType])] = Map( + 0.toByte -> GroupElementConstant(holderPk), + 1.toByte -> GroupElementConstant(a), + 2.toByte -> ByteArrayConstant(z.bigInteger.toByteArray) + ).toSeq + + def deserTest() = {test("schnorr", env, customExt, + s"""{ + | + | val g: GroupElement = groupGenerator + | val holder = getVar[GroupElement](0).get + | + | val message = fromBase16("${Base16.encode(message)}") + | val e: Coll[Byte] = blake2b256(message) // weak Fiat-Shamir + | val eInt = byteArrayToBigInt(e) // challenge as big integer + | + | // a of signature in (a, z) + | val a = getVar[GroupElement](1).get + | val aBytes = a.getEncoded + | + | // z of signature in (a, z) + | val zBytes = getVar[Coll[Byte]](2).get + | val z = byteArrayToBigInt(zBytes) + | + | // Signature is valid if g^z = a * x^e + | val properSignature = g.exp(z) == a.multiply(holder.exp(eInt)) + | sigmaProp(properSignature) + |}""".stripMargin, + null, + true + )} + + if (activatedVersionInTests < V6SoftForkVersion) { + deserTest() + } else { + deserTest() + } + } + property("Unit register") { // TODO frontend: implement missing Unit support in compiler // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820 diff --git a/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala index 9d0ffc880b..8d3d09de74 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala @@ -138,7 +138,7 @@ class OracleExamplesSpecification extends CompilerTestingCommons LastBlockUtxoRootHash, SAvlTreeMethods.getMethod, IndexedSeq(ExtractId(GetVarBox(22: Byte).get), GetVarByteArray(23: Byte).get)).asOption[SByteArray]), EQ(extract[SByteArray](ErgoBox.ScriptRegId), ByteArrayConstant(ErgoTree.fromSigmaBoolean(oraclePubKey).bytes)), - EQ(Exponentiate(GroupGenerator, extract[SBigInt.type](reg3)), + EQ(Exponentiate(GroupGenerator, extract[SBigInt.type](reg3)(SBigInt)), MultiplyGroup(extract[SGroupElement.type](reg2), Exponentiate(GroupElementConstant(oraclePubImage.value), ByteArrayToBigInt( From b13cef6d0713821cb7fb31fa2f2bf82bf689fe13 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sat, 25 May 2024 00:23:28 +0300 Subject: [PATCH 044/123] failing schnorr sig check w. unsigned --- .../test/scala/sigmastate/utxo/BasicOpsSpecification.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 621e32ad3f..28084be987 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -192,7 +192,6 @@ class BasicOpsSpecification extends CompilerTestingCommons val z = (r + secretKey * BigInt(scorex.crypto.hash.Blake2b256(msg))) % CryptoConstants.groupOrder if(z.bitLength > 255) { - println("z: " + z) (a, z) } else { sign(msg,secretKey) @@ -209,7 +208,7 @@ class BasicOpsSpecification extends CompilerTestingCommons val customExt: Seq[(Byte, EvaluatedValue[_ <: SType])] = Map( 0.toByte -> GroupElementConstant(holderPk), 1.toByte -> GroupElementConstant(a), - 2.toByte -> ByteArrayConstant(z.bigInteger.toByteArray) + 2.toByte -> UnsignedBigIntConstant(z.bigInteger) ).toSeq def deserTest() = {test("schnorr", env, customExt, @@ -227,8 +226,7 @@ class BasicOpsSpecification extends CompilerTestingCommons | val aBytes = a.getEncoded | | // z of signature in (a, z) - | val zBytes = getVar[Coll[Byte]](2).get - | val z = byteArrayToBigInt(zBytes) + | val z = getVar[UnsignedBigInt](2).get | | // Signature is valid if g^z = a * x^e | val properSignature = g.exp(z) == a.multiply(holder.exp(eInt)) From e5a32c8fe2efd772ef3d803e06d76f45d37454b9 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Sat, 25 May 2024 10:21:58 +0200 Subject: [PATCH 045/123] i486-toBytes: Versioned.scala added --- .../src/main/scala/sigma/util/Versioned.scala | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 core/shared/src/main/scala/sigma/util/Versioned.scala diff --git a/core/shared/src/main/scala/sigma/util/Versioned.scala b/core/shared/src/main/scala/sigma/util/Versioned.scala new file mode 100644 index 0000000000..a3eae2325a --- /dev/null +++ b/core/shared/src/main/scala/sigma/util/Versioned.scala @@ -0,0 +1,27 @@ +package sigma.util + +import sigma.VersionContext + +import scala.reflect.ClassTag + +/** Represents a versioned object that can be created for each supported version. + * The object is created lazily and cached for each version. + * + * @param builder a total function that creates an object for a given version in [0, + * maxVersion] range. + * @param maxVersion the maximum supported version. + */ +case class Versioned[T <: AnyRef: ClassTag](builder: Byte => T, maxVersion: Byte = VersionContext.MaxSupportedScriptVersion) { + private val cache = new Array[T](maxVersion + 1) + + def get(version: Byte): T = { + require(version <= VersionContext.MaxSupportedScriptVersion, s"Not supported version $version") + if (cache(version) == null) { + val v = builder(version) + cache(version) = v + v + } else { + cache(version) + } + } +} From bba2230da50f1fc4cb1cba8d097138aa9adadf72 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Sat, 25 May 2024 10:24:23 +0200 Subject: [PATCH 046/123] i486-toBytes: ensure VersionContext.current in tests --- .../shared/src/test/scala/sigmastate/CrossVersionProps.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala b/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala index e55b874dc3..87101a1f71 100644 --- a/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala +++ b/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala @@ -31,7 +31,9 @@ trait CrossVersionProps extends AnyPropSpecLike with TestsBase { System.gc() } forEachScriptAndErgoTreeVersion(activatedVersions, ergoTreeVersions) { + VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) { testFun_Run(testName, testFun) + } } } } From dc361a1469b85365e321285308eb010a155f8234 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Sat, 25 May 2024 10:49:51 +0200 Subject: [PATCH 047/123] i486-toBytes: ErgoTreeSpecification versioned and updated --- .../src/main/scala/sigma/ast/SType.scala | 36 +++-- .../src/main/scala/sigma/ast/methods.scala | 27 +++- .../main/scala/sigma/data/BigIntegerOps.scala | 2 +- .../main/scala/sigma/data/ExactIntegral.scala | 8 +- .../main/scala/sigma/data/ExactNumeric.scala | 2 +- .../sigma/compiler/ir/GraphBuilding.scala | 6 + .../sigma/compiler/ir/TreeBuilding.scala | 7 + .../compiler/ir/primitives/NumericOps.scala | 9 ++ .../scala/sigma/LanguageSpecificationV6.scala | 22 +-- .../sigmastate/ErgoTreeSpecification.scala | 145 +++++++++++++----- 10 files changed, 192 insertions(+), 72 deletions(-) diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index f75cbc9e8b..8b386fa729 100644 --- a/core/shared/src/main/scala/sigma/ast/SType.scala +++ b/core/shared/src/main/scala/sigma/ast/SType.scala @@ -7,7 +7,8 @@ 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.util.Versioned +import sigma.{AvlTree, BigInt, Box, Coll, Context, Evaluation, GroupElement, Header, PreHeader, SigmaDslBuilder, SigmaProp, VersionContext} import java.math.BigInteger @@ -113,27 +114,40 @@ 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 + * @note on versioning: + * In v3.x-5.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 * resolved (using SMethod.fromIds()) for all numeric types (SByte, SShort, SInt, * SLong, SBigInt). See the corresponding regression `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. + * + * Starting from v6.0 the SNumericType.typeId is not used as receiver of object of + * method call, instead, 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, - SAvlTree, SBox, SOption, SCollection, SBigInt - ).map { t => (t.typeId, t) }.toMap + private val _types: Versioned[Map[Byte, STypeCompanion]] = Versioned({ version => + val v5x = Seq( + SBoolean, SString, STuple, SGroupElement, SSigmaProp, SContext, SGlobal, SHeader, SPreHeader, + SAvlTree, SBox, SOption, SCollection, SBigInt + ) + val v6 = if (version >= VersionContext.V6SoftForkVersion) + Seq(SByte, SShort, SInt, SLong) + else + Seq.empty + (v5x ++ v6).map { t => (t.typeId, t) }.toMap + }) + def types: Map[Byte, STypeCompanion] = _types.get(VersionContext.current.activatedVersion) /** Checks that the type of the value corresponds to the descriptor `tpe`. * If the value has complex structure only root type constructor is checked. diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 3f27f85e2d..c53a9b84c7 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -13,6 +13,7 @@ import sigma.data.{DataValueComparer, KeyValueColl, Nullable, RType, SigmaConsta import sigma.eval.{CostDetails, ErgoTreeEvaluator, TracedCost} import sigma.reflection.RClass import sigma.serialization.CoreByteWriter.ArgInfo +import sigma.util.Versioned import sigma.utils.SparseArrayContainer import scala.annotation.unused @@ -157,11 +158,23 @@ trait MonoTypeMethods extends MethodsContainer { trait SNumericTypeMethods extends MonoTypeMethods { import SNumericTypeMethods.tNum - protected override def getMethods(): Seq[SMethod] = { - super.getMethods() ++ SNumericTypeMethods.methods.map { - m => m.copy(stype = applySubst(m.stype, Map(tNum -> this.ownerType)).asFunc) - } - } + private val _getMethods = Versioned({ version => + val subst = Map(tNum -> this.ownerType) + val numericMethods = if (version < VersionContext.V6SoftForkVersion) + SNumericTypeMethods.methods.map { m => + m.copy(stype = applySubst(m.stype, subst).asFunc ) + } + else + SNumericTypeMethods.methods.map { m => + m.copy( + objType = this, // associate the method with the concrete numeric type + stype = applySubst(m.stype, subst).asFunc + )} + super.getMethods() ++ numericMethods + }) + + protected override def getMethods(): Seq[SMethod] = + _getMethods.get(VersionContext.current.activatedVersion) } object SNumericTypeMethods extends MethodsContainer { @@ -313,8 +326,8 @@ case object SBigIntMethods extends SNumericTypeMethods { final val ToNBitsCostInfo = OperationCostInfo( FixedCost(JitCost(5)), NamedDesc("NBitsMethodCall")) - //id = 8 to make it after toBits - val ToNBits = SMethod(this, "nbits", SFunc(this.ownerType, SLong), 8, ToNBitsCostInfo.costKind) + //id = 20 to make it after toBits and reserve space for future methods at SNumericTypeMethods + val ToNBits = SMethod(this, "nbits", SFunc(this.ownerType, SLong), 20, ToNBitsCostInfo.costKind) .withInfo(ModQ, "Encode this big integer value as NBits") /** The following `modQ` methods are not fully implemented in v4.x and this descriptors. diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala index b93334daf6..0bb9e9101b 100644 --- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala +++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala @@ -91,7 +91,7 @@ object NumericOps { */ override def divisionRemainder(x: BigInt, y: BigInt): BigInt = x.mod(y) - override def toBytes(x: BigInt): Coll[Byte] = Colls.fromArray(x.toBigInteger.toByteArray) + override def toBigEndianBytes(x: BigInt): Coll[Byte] = Colls.fromArray(x.toBigInteger.toByteArray) } /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */ diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index b207a1794d..eaf89947c1 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -38,7 +38,7 @@ 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 toBytes(x: Byte): Coll[Byte] = Colls.fromItems(x) + override def toBigEndianBytes(x: Byte): Coll[Byte] = Colls.fromItems(x) } implicit object ShortIsExactIntegral extends ExactIntegral[Short] { @@ -46,7 +46,7 @@ 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 toBytes(x: Short): Coll[Byte] = Colls.fromItems((x >> 8).toByte, x.toByte) + override def toBigEndianBytes(x: Short): Coll[Byte] = Colls.fromItems((x >> 8).toByte, x.toByte) } implicit object IntIsExactIntegral extends ExactIntegral[Int] { @@ -54,7 +54,7 @@ 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 toBytes(x: Int): Coll[Byte] = + override def toBigEndianBytes(x: Int): Coll[Byte] = Colls.fromItems((x >> 24).toByte, (x >> 16).toByte, (x >> 8).toByte, x.toByte) } @@ -63,7 +63,7 @@ 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 toBytes(x: Long): Coll[Byte] = + 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) } } diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index fef951b4d7..d8b3b5df0d 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -35,7 +35,7 @@ trait ExactNumeric[T] { * For example, the `Int` value `0x12131415` would yield the * collection of bytes [0x12, 0x13, 0x14, 0x15] */ - def toBytes(x: T): Coll[Byte] + def toBigEndianBytes(x: T): Coll[Byte] /** A value of type T which corresponds to integer 0. */ lazy val zero: T = fromInt(0) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index a6a244778e..c34d91b41a 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1151,6 +1151,12 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => g.serialize(value) case _ => throwError } + case (x: Ref[tNum], SNumericTypeMethods) => method.name match { + case SNumericTypeMethods.ToBytesMethod.name => + val op = NumericToBigEndianBytes(elemToExactNumeric(x.elem)) + ApplyUnOp(op, x) + case _ => throwError + } case _ => throwError } diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala index 725e3b1d19..655010dbc5 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala @@ -106,6 +106,13 @@ trait TreeBuilding extends Base { 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 specMethod = SNumericTypeMethods.ToBytesMethod + .withConcreteTypes(Map(SNumericTypeMethods.tNum -> v.tpe)) + builder.mkMethodCall(v.asNumValue, specMethod, IndexedSeq.empty) + } + Some(mkNode) case _ => None } } diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala index 4e732bbb5f..ef4124d0b5 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala @@ -14,6 +14,7 @@ trait NumericOps extends Base { self: IRContext => 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. */ @@ -66,6 +67,14 @@ trait NumericOps extends Base { self: IRContext => 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] = + n.toBigEndianBytes(x).asInstanceOf[Coll[Byte]] + } + /** 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/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index e105e4bee9..ed6b6d5165 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -475,18 +475,18 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => tree.root shouldBe t2.root } - property("Numeric.toBytes methods equivalence") { - lazy val toBytes = newFeature( - { (x: Byte) => x.toBigEndianBytes }, - "{ (x: Byte) => x.toBytes }", - sinceVersion = VersionContext.V6SoftForkVersion) - val cases = Seq( - (0.toByte, Success(Coll(0.toByte))), - (1.toByte, Success(Coll(1.toByte))) - ) + property("Numeric.toBytes methods equivalence") { + lazy val toBytes = newFeature( + { (x: Byte) => x.toBigEndianBytes }, + "{ (x: Byte) => x.toBytes }", + sinceVersion = VersionContext.V6SoftForkVersion) + val cases = Seq( + (0.toByte, Success(Coll(0.toByte))), + (1.toByte, Success(Coll(1.toByte))) + ) - testCases(cases, toBytes) - } + testCases(cases, toBytes) + } } diff --git a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala index 7539bd5e48..7a48ec8b45 100644 --- a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala @@ -21,14 +21,14 @@ import sigma.compiler.CompilerSettings import sigma.eval.EvalSettings import sigma.exceptions.{CostLimitException, InterpreterException} 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,97 @@ 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) + ), 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) + ), 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) + ), 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) + ), 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(20, SBigIntMethods.ToNBits) + ) else Seq.empty) + , true) }, { import SGroupElementMethods._ (SGroupElement.typeId, Seq( @@ -419,7 +479,10 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit { { import SGlobalMethods._ (SGlobal.typeId, Seq( MInfo(1, groupGeneratorMethod), MInfo(2, xorMethod) - ), true) + ) ++ (if (isV6Activated) Seq( + // methods added in v6.0 + MInfo(3, serializeMethod) + ) else Seq.empty), true) }, { import SCollectionMethods._ (SCollection.typeId, Seq( @@ -475,7 +538,8 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit { MInfo(8, FilterMethod) ), true) } - ) + ) + } property("MethodCall Codes") { forAll(methods) { (typeId, methods, canHaveMethods) => @@ -508,21 +572,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 + } } } } From 70786a0c7dcfabc6cf65a92229d44926698785d8 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Sat, 25 May 2024 11:22:19 +0200 Subject: [PATCH 048/123] i486-toBytes: clarified description of demotion of SNumericType --- .../src/main/scala/sigma/ast/SType.scala | 29 +++++++++++-------- .../sigmastate/ErgoTreeSpecification.scala | 5 ++++ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index 8b386fa729..7143504ca8 100644 --- a/core/shared/src/main/scala/sigma/ast/SType.scala +++ b/core/shared/src/main/scala/sigma/ast/SType.scala @@ -118,24 +118,29 @@ object SType { * * @note on versioning: * In v3.x-5.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 + * `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. + * 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 not used as receiver of object of - * method call, instead, 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")`. + * 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 private val _types: Versioned[Map[Byte, STypeCompanion]] = Versioned({ version => val v5x = Seq( SBoolean, SString, STuple, SGroupElement, SSigmaProp, SContext, SGlobal, SHeader, SPreHeader, diff --git a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala index 7a48ec8b45..6e6fb824de 100644 --- a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala @@ -541,6 +541,11 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with C ) } + 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) => SType.types.get(typeId) match { From c76ac1a484e8d15a1e34469f35f1693e507a0715 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Sat, 25 May 2024 13:09:23 +0200 Subject: [PATCH 049/123] i486-toBytes: GraphBuilding to handle numeric methods --- .../sigma/compiler/ir/GraphBuilding.scala | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index c34d91b41a..ddbec96518 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1,6 +1,7 @@ package sigma.compiler.ir import org.ergoplatform._ +import sigma.Evaluation.stypeToRType import sigma.ast.TypeCodes.LastConstantCode import sigma.ast.Value.Typed import sigma.ast.syntax.{SValue, ValueOps} @@ -437,8 +438,8 @@ trait GraphBuilding extends Base with DefRewriting { 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 Constant(v, tpe) => v match { @@ -985,7 +986,7 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => val i = asRep[Int](argsV(0)) val d = asRep[t](argsV(1)) xs.getOrElse(i, d) - case _ => throwError + case _ => throwError() } case (opt: ROption[t]@unchecked, SOptionMethods) => method.name match { case SOptionMethods.GetMethod.name => @@ -999,7 +1000,7 @@ trait GraphBuilding extends Base with DefRewriting { 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 => @@ -1012,12 +1013,12 @@ trait GraphBuilding extends Base with DefRewriting { 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 _ => throwError() } case (ctx: Ref[Context]@unchecked, SContextMethods) => method.name match { case SContextMethods.dataInputsMethod.name => @@ -1040,7 +1041,7 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => ctx.LastBlockUtxoRootHash case SContextMethods.minerPubKeyMethod.name => ctx.minerPubKey - case _ => throwError + case _ => throwError() } case (tree: Ref[AvlTree]@unchecked, SAvlTreeMethods) => method.name match { case SAvlTreeMethods.digestMethod.name => @@ -1087,7 +1088,7 @@ trait GraphBuilding extends Base with DefRewriting { 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 => @@ -1104,7 +1105,7 @@ trait GraphBuilding extends Base with DefRewriting { 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 => @@ -1137,7 +1138,7 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => h.powDistance case SHeaderMethods.votesMethod.name => h.votes - case _ => throwError + case _ => throwError() } case (g: Ref[SigmaDslBuilder]@unchecked, SGlobalMethods) => method.name match { case SGlobalMethods.groupGeneratorMethod.name => @@ -1149,19 +1150,19 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => case SGlobalMethods.serializeMethod.name => val value = asRep[Any](argsV(0)) g.serialize(value) - case _ => throwError + case _ => throwError() } - case (x: Ref[tNum], SNumericTypeMethods) => method.name match { + case (x: Ref[tNum], _: SNumericTypeMethods) => method.name match { case SNumericTypeMethods.ToBytesMethod.name => val op = NumericToBigEndianBytes(elemToExactNumeric(x.elem)) ApplyUnOp(op, x) - case _ => throwError + 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 From 2427db30fdaedd4f75c85677507d656ce4c86412 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Sat, 25 May 2024 13:10:24 +0200 Subject: [PATCH 050/123] i486-toBytes: added userDefinedInvoke handler to SMethod --- .../src/main/scala/sigma/ast/package.scala | 6 ++++++ .../src/main/scala/sigma/ast/SMethod.scala | 19 ++++++++++++++++--- .../sigma/compiler/ir/TreeBuilding.scala | 8 ++++---- .../sigma/compiler/phases/SigmaTyper.scala | 3 ++- 4 files changed, 28 insertions(+), 8 deletions(-) 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/data/shared/src/main/scala/sigma/ast/SMethod.scala b/data/shared/src/main/scala/sigma/ast/SMethod.scala index 332c74be6b..19fa427b9e 100644 --- a/data/shared/src/main/scala/sigma/ast/SMethod.scala +++ b/data/shared/src/main/scala/sigma/ast/SMethod.scala @@ -73,7 +73,9 @@ case class SMethod( 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) @@ -112,7 +114,12 @@ 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]): Any = { - javaMethod.invoke(obj, args.asInstanceOf[Array[AnyRef]]:_*) + userDefinedInvoke match { + case Some(h) => + h(obj, args) + case None => + javaMethod.invoke(obj, args.asInstanceOf[Array[AnyRef]]:_*) + } } // TODO optimize: avoid lookup when this SMethod is created via `specializeFor` @@ -261,6 +268,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 = (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 @@ -295,7 +308,7 @@ object SMethod { ): SMethod = { SMethod( objType, name, stype, methodId, costKind, explicitTypeArgs, - MethodIRInfo(None, None, None), None, None) + MethodIRInfo(None, None, None), None, None, None) } diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala index 655010dbc5..f7daff90ae 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala @@ -106,11 +106,11 @@ trait TreeBuilding extends Base { IR: IRContext => object IsNumericUnOp { def unapply(op: UnOp[_,_]): Option[SValue => SValue] = op match { case NumericNegate(_) => Some({ v: SValue => builder.mkNegation(v.asNumValue) }) - case NumericToBigEndianBytes(_) => + case _: NumericToBigEndianBytes[_] => val mkNode = { v: SValue => - val specMethod = SNumericTypeMethods.ToBytesMethod - .withConcreteTypes(Map(SNumericTypeMethods.tNum -> v.tpe)) - builder.mkMethodCall(v.asNumValue, specMethod, IndexedSeq.empty) + 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 _ => None diff --git a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala index f9b52fe061..ac30a6cd0a 100644 --- a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala +++ b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala @@ -139,7 +139,8 @@ class SigmaTyper(val builder: SigmaBuilder, obj.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 From 02e2d06d7b66082bed697767d6446cce138d6ef8 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Sat, 25 May 2024 15:15:40 +0200 Subject: [PATCH 051/123] i486-toBytes: toBigEndianBytes implemented --- .../src/main/scala/sigma/VersionContext.scala | 13 ++++ .../src/main/scala/sigma/ast/SMethod.scala | 9 ++- .../src/main/scala/sigma/ast/methods.scala | 11 ++- .../scala/sigma/LanguageSpecificationV5.scala | 14 ++-- .../scala/sigma/LanguageSpecificationV6.scala | 70 +++++++++---------- .../test/scala/sigma/SigmaDslTesting.scala | 23 +++--- 6 files changed, 84 insertions(+), 56 deletions(-) diff --git a/core/shared/src/main/scala/sigma/VersionContext.scala b/core/shared/src/main/scala/sigma/VersionContext.scala index 19a4857086..ecdcfb5f62 100644 --- a/core/shared/src/main/scala/sigma/VersionContext.scala +++ b/core/shared/src/main/scala/sigma/VersionContext.scala @@ -25,6 +25,12 @@ case class VersionContext(activatedVersion: Byte, ergoTreeVersion: Byte) { /** @return true, if the activated script version of Ergo protocol on the network is * including Evolution update. */ def isV6SoftForkActivated: Boolean = activatedVersion >= V6SoftForkVersion + + /** @return true if another [[VersionContext]] is greater than this. */ + def <= (that: VersionContext): Boolean = { + this.activatedVersion < that.activatedVersion || + (this.activatedVersion == that.activatedVersion && this.ergoTreeVersion <= that.ergoTreeVersion) + } } object VersionContext { @@ -104,4 +110,11 @@ object VersionContext { } } + /** Returns the VersionContext with V5 activation and the given ErgoTree version. */ + def sinceV5AndTreeVersion(treeVersion: Byte): VersionContext = + VersionContext(JitActivationVersion, ergoTreeVersion = treeVersion) + + /** Returns the VersionContext with V6 activation and the given ErgoTree version. */ + def sinceV6AndTreeVersion(treeVersion: Byte): VersionContext = + VersionContext(V6SoftForkVersion, ergoTreeVersion = treeVersion) } diff --git a/data/shared/src/main/scala/sigma/ast/SMethod.scala b/data/shared/src/main/scala/sigma/ast/SMethod.scala index 19fa427b9e..6bf8d4f9a0 100644 --- a/data/shared/src/main/scala/sigma/ast/SMethod.scala +++ b/data/shared/src/main/scala/sigma/ast/SMethod.scala @@ -116,7 +116,7 @@ case class SMethod( def invokeFixed(obj: Any, args: Array[Any]): Any = { userDefinedInvoke match { case Some(h) => - h(obj, args) + h(this, obj, args) case None => javaMethod.invoke(obj, args.asInstanceOf[Array[AnyRef]]:_*) } @@ -159,6 +159,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) @@ -272,7 +277,7 @@ object SMethod { * Instances of this type can be attached to [[SMethod]] instances. * @see SNumericTypeMethods.ToBytesMethod */ - type InvokeHandler = (Any, Array[Any]) => Any + 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 diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index c53a9b84c7..1a0841e97c 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -8,6 +8,7 @@ import sigma.ast.SCollection.{SBooleanArray, SBoxArray, SByteArray, SByteArray2, import sigma.ast.SMethod.{MethodCallIrBuilder, MethodCostFunc, javaMethodOf} import sigma.ast.SType.{TypeCode, paramT, tT} import sigma.ast.syntax.{SValue, ValueOps} +import sigma.data.ExactIntegral.{ByteIsExactIntegral, IntIsExactIntegral, LongIsExactIntegral, ShortIsExactIntegral} import sigma.data.OverloadHack.Overloaded1 import sigma.data.{DataValueComparer, KeyValueColl, Nullable, RType, SigmaConstants} import sigma.eval.{CostDetails, ErgoTreeEvaluator, TracedCost} @@ -230,6 +231,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 @@ -1547,7 +1557,6 @@ case object SGlobalMethods extends MonoTypeMethods { def serialize_eval(mc: MethodCall, G: SigmaDslBuilder, value: SType#WrappedType) (implicit E: ErgoTreeEvaluator): Coll[Byte] = { // TODO v6.0: accumulate cost - CheckMinimalErgoTreeVersion(E.context.currentErgoTreeVersion, VersionContext.V6SoftForkVersion) val t = Evaluation.stypeToRType(mc.args(0).tpe) G.serialize(value)(t) } diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala index f568515c89..48f1a3f7ca 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala @@ -4802,7 +4802,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => })) ), changedFeature( - changedInVersion = VersionContext.JitActivationVersion, + changedInVersion = VersionContext.sinceV5AndTreeVersion(0), { (x: Context) => x.selfBoxIndex }, { (x: Context) => x.selfBoxIndex }, // see versioning in selfBoxIndex implementation "{ (x: Context) => x.selfBoxIndex }", @@ -5004,7 +5004,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ), changedFeature( - changedInVersion = VersionContext.JitActivationVersion, + changedInVersion = VersionContext.sinceV5AndTreeVersion(0), scalaFunc = { (x: Context) => // this error is expected in v3.x, v4.x throw expectedError @@ -5978,7 +5978,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) }, changedFeature( - changedInVersion = VersionContext.JitActivationVersion, + changedInVersion = VersionContext.sinceV5AndTreeVersion(0), (x: Coll[Boolean]) => SigmaDsl.xorOf(x), (x: Coll[Boolean]) => SigmaDsl.xorOf(x), "{ (x: Coll[Boolean]) => xorOf(x) }", @@ -6241,7 +6241,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) }, changedFeature( - changedInVersion = VersionContext.JitActivationVersion, + changedInVersion = VersionContext.sinceV5AndTreeVersion(0), (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) }", @@ -8811,7 +8811,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => (Some(Long.MaxValue) -> Expected(new ArithmeticException("long overflow"))) ), changedFeature( - changedInVersion = VersionContext.JitActivationVersion, + changedInVersion = VersionContext.sinceV5AndTreeVersion(0), scalaFunc = { (x: Option[Long]) => def f(opt: Long): Long = n.plus(opt, 1) if (x.isDefined) f(x.get) @@ -9367,7 +9367,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) }, changedFeature( - changedInVersion = VersionContext.JitActivationVersion, + changedInVersion = VersionContext.sinceV5AndTreeVersion(0), { (x: (Coll[Byte], Int)) => SigmaDsl.substConstants(x._1, Coll[Int](x._2), Coll[Any](SigmaDsl.sigmaProp(false))(sigma.AnyType)) }, @@ -9430,7 +9430,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ), changedFeature( - changedInVersion = VersionContext.JitActivationVersion, + changedInVersion = VersionContext.sinceV5AndTreeVersion(0), { (x: Context) => throw error true diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index ed6b6d5165..d89fc1f623 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -44,7 +44,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => Map() ) ), - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) } property("Global.serialize[Byte]") { @@ -76,7 +76,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => property("Boolean.toByte") { val toByte = newFeature((x: Boolean) => x.toByte, "{ (x: Boolean) => x.toByte }", - sinceVersion = VersionContext.V6SoftForkVersion + sinceVersion = VersionContext.sinceV6AndTreeVersion(0) ) val cases = Seq( @@ -102,22 +102,22 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => // which is checked below lazy val toAbs = newFeature((x: Byte) => x.toAbs, "{ (x: Byte) => x.toAbs }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val compareTo = newFeature( (x: (Byte, Byte)) => x._1.compareTo(x._2), "{ (x: (Byte, Byte)) => x._1.compareTo(x._2) }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val bitOr = newFeature( { (x: (Byte, Byte)) => (x._1 | x._2).toByteExact }, "{ (x: (Byte, Byte)) => (x._1 | x._2) }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val bitAnd = newFeature( { (x: (Byte, Byte)) => (x._1 & x._2).toByteExact }, "{ (x: (Byte, Byte)) => (x._1 & x._2) }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) forAll { x: Byte => Seq(toAbs).foreach(f => f.checkEquality(x)) @@ -136,21 +136,21 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => // which is checked below lazy val toAbs = newFeature((x: Short) => x.toAbs, "{ (x: Short) => x.toAbs }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val compareTo = newFeature((x: (Short, Short)) => x._1.compareTo(x._2), "{ (x: (Short, Short)) => x._1.compareTo(x._2) }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val bitOr = newFeature( { (x: (Short, Short)) => (x._1 | x._2).toShortExact }, "{ (x: (Short, Short)) => x._1 | x._2 }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val bitAnd = newFeature( { (x: (Short, Short)) => (x._1 & x._2).toShortExact }, "{ (x: (Short, Short)) => x._1 & x._2 }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) forAll { x: Short => Seq(toAbs).foreach(_.checkEquality(x)) @@ -166,18 +166,18 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => // NOTE, for such versions the new features are not supported // which is checked below lazy val toAbs = newFeature((x: Int) => x.toAbs, "{ (x: Int) => x.toAbs }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val compareTo = newFeature((x: (Int, Int)) => x._1.compareTo(x._2), "{ (x: (Int, Int)) => x._1.compareTo(x._2) }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val bitOr = newFeature( { (x: (Int, Int)) => x._1 | x._2 }, "{ (x: (Int, Int)) => x._1 | x._2 }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val bitAnd = newFeature( { (x: (Int, Int)) => x._1 & x._2 }, "{ (x: (Int, Int)) => x._1 & x._2 }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) forAll { x: Int => Seq(toAbs).foreach(_.checkEquality(x)) } @@ -192,20 +192,20 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => // NOTE, for such versions the new features are not supported // which is checked below lazy val toAbs = newFeature((x: Long) => x.toAbs, "{ (x: Long) => x.toAbs }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val compareTo = newFeature((x: (Long, Long)) => x._1.compareTo(x._2), "{ (x: (Long, Long)) => x._1.compareTo(x._2) }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val bitOr = newFeature( { (x: (Long, Long)) => x._1 | x._2 }, "{ (x: (Long, Long)) => x._1 | x._2 }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val bitAnd = newFeature( { (x: (Long, Long)) => x._1 & x._2 }, "{ (x: (Long, Long)) => x._1 & x._2 }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) forAll { x: Long => Seq(toAbs).foreach(_.checkEquality(x)) @@ -240,30 +240,30 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => val toByte = newFeature((x: BigInt) => x.toByte, "{ (x: BigInt) => x.toByte }", FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SByte)), - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) val toShort = newFeature((x: BigInt) => x.toShort, "{ (x: BigInt) => x.toShort }", FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SShort)), - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) val toInt = newFeature((x: BigInt) => x.toInt, "{ (x: BigInt) => x.toInt }", FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SInt)), - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) val toLong = newFeature((x: BigInt) => x.toLong, "{ (x: BigInt) => x.toLong }", FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SLong)), - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val toAbs = newFeature((x: BigInt) => x.toAbs, "{ (x: BigInt) => x.toAbs }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val compareTo = newFeature((x: (BigInt, BigInt)) => x._1.compareTo(x._2), "{ (x: (BigInt, BigInt)) => x._1.compareTo(x._2) }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val bitOr = newFeature({ (x: (BigInt, BigInt)) => x._1 | x._2 }, "{ (x: (BigInt, BigInt)) => x._1 | x._2 }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) lazy val bitAnd = newFeature({ (x: (BigInt, BigInt)) => x._1 & x._2 }, "{ (x: (BigInt, BigInt)) => x._1 & x._2 }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) forAll { x: BigInt => Seq(toByte, toShort, toInt, toLong, toAbs).foreach(_.checkEquality(x)) @@ -278,7 +278,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => // 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 }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -294,7 +294,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => 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 = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -313,7 +313,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => if (x.size > 2) x.slice(0, x.size - 2) else Colls.emptyColl[Boolean] }, "{ (x: Coll[Boolean]) => x >> 2 }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -329,7 +329,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => 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 = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -346,7 +346,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => 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 = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -362,7 +362,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => property("allZK equivalence") { lazy val allZK = newFeature((x: Coll[SigmaProp]) => SigmaDsl.allZK(x), "{ (x: Coll[SigmaProp]) => allZK(x) }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -378,7 +378,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => property("anyZK equivalence") { lazy val anyZK = newFeature((x: Coll[SigmaProp]) => SigmaDsl.anyZK(x), "{ (x: Coll[SigmaProp]) => anyZK(x) }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -442,7 +442,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => } ), changedFeature( - changedInVersion = VersionContext.V6SoftForkVersion, + changedInVersion = VersionContext.sinceV6AndTreeVersion(0), { (x: (Coll[Byte], Int)) => SigmaDsl.substConstants(x._1, Coll[Int](x._2), Coll[Any](SigmaDsl.sigmaProp(false))(sigma.AnyType)) }, @@ -479,7 +479,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => lazy val toBytes = newFeature( { (x: Byte) => x.toBigEndianBytes }, "{ (x: Byte) => x.toBytes }", - sinceVersion = VersionContext.V6SoftForkVersion) + sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) val cases = Seq( (0.toByte, Success(Coll(0.toByte))), (1.toByte, Success(Coll(1.toByte))) diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index 3246f968a0..0b512d1380 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -126,8 +126,8 @@ class SigmaDslTesting extends AnyPropSpec /** 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 + /** Version in which the feature is first implemented or changed. */ + def sinceVersion: VersionContext /** Script containing this feature. */ def script: String @@ -400,7 +400,7 @@ class SigmaDslTesting extends AnyPropSpec ctx } - val (expectedResult, expectedCost) = if (activatedVersionInTests < sinceVersion) + val (expectedResult, expectedCost) = if (activatedVersionInTests < sinceVersion.activatedVersion) (expected.oldResult, expected.verificationCostOpt) else { val res = expected.newResults(ergoTreeVersionInTests) @@ -507,7 +507,7 @@ class SigmaDslTesting extends AnyPropSpec implicit val cs = compilerSettingsInTests - override def sinceVersion: Byte = 0 + override def sinceVersion: VersionContext = VersionContext(0, 0) // has always been supported override def isSupportedIn(vc: VersionContext): Boolean = true @@ -669,7 +669,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, + changedInVersion: VersionContext, script: String, scalaFunc: A => B, override val scalaFuncNew: A => B, @@ -683,7 +683,7 @@ class SigmaDslTesting extends AnyPropSpec implicit val cs = compilerSettingsInTests - override def sinceVersion: Byte = changedInVersion + override def sinceVersion: VersionContext = changedInVersion override def isSupportedIn(vc: VersionContext): Boolean = true @@ -764,7 +764,7 @@ class SigmaDslTesting extends AnyPropSpec checkEq(scalaFuncNew)(newF)(input) } - if (VersionContext.current.activatedVersion < changedInVersion) { + if (VersionContext.current.activatedVersion < changedInVersion.activatedVersion) { // check the old implementation with Scala semantic val expectedOldRes = expected.value @@ -859,7 +859,7 @@ class SigmaDslTesting extends AnyPropSpec * @param logScript if true, log scripts to console */ case class NewFeature[A, B]( - sinceVersion: Byte, + sinceVersion: VersionContext, script: String, override val scalaFuncNew: A => B, expectedExpr: Option[SValue], @@ -869,7 +869,7 @@ class SigmaDslTesting extends AnyPropSpec extends Feature[A, B] { override def isSupportedIn(vc: VersionContext): Boolean = - vc.activatedVersion >= sinceVersion && vc.ergoTreeVersion >= sinceVersion + sinceVersion <= vc override def scalaFunc: A => B = { x => sys.error(s"Semantic Scala function is not defined for old implementation: $this") @@ -1063,7 +1063,7 @@ class SigmaDslTesting extends AnyPropSpec * various ways */ def changedFeature[A: RType, B: RType] - (changedInVersion: Byte, + (changedInVersion: VersionContext, scalaFunc: A => B, scalaFuncNew: A => B, script: String, @@ -1088,7 +1088,8 @@ class SigmaDslTesting extends AnyPropSpec * various ways */ def newFeature[A: RType, B: RType] - (scalaFunc: A => B, script: String, expectedExpr: SValue = null, sinceVersion: Byte = VersionContext.JitActivationVersion) + (scalaFunc: A => B, script: String, expectedExpr: SValue = null, + sinceVersion: VersionContext = VersionContext(VersionContext.JitActivationVersion, 0)) (implicit IR: IRContext, es: EvalSettings): Feature[A, B] = { NewFeature(sinceVersion, script, scalaFunc, Option(expectedExpr)) } From c9d0889c91b9e98c5d757711ac3984b6434c4a40 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sun, 26 May 2024 23:13:30 +0300 Subject: [PATCH 052/123] first pow check test --- .../src/main/scala/sigma/ast/methods.scala | 2 +- .../utxo/BasicOpsSpecification.scala | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 3642a82ddb..88ee9c72ed 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -304,7 +304,7 @@ case object SLongMethods extends SNumericTypeMethods { override def ownerType: SMonoType = SLong lazy val DecodeNBitsMethod: SMethod = SMethod( - this, "DecodeNBits", SFunc(this.ownerType, SBigInt), 8, FixedCost(JitCost(5))) + this, "decodeNbits", SFunc(this.ownerType, SBigInt), 8, FixedCost(JitCost(5))) .withInfo(PropertyCall, "Consider this Long value as nbits-encoded BigInt value and decode it to BigInt") protected override def getMethods(): Seq[SMethod] = { diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 79701d6e07..e68b262c59 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -2,6 +2,7 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ +import scorex.util.encode.Base16 import sigma.Extensions.ArrayOps import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps @@ -157,6 +158,45 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } + property("checking Bitcoin PoW") { + val h = "00000020a82ff9c62e69a6cbed277b7f2a9ac9da3c7133a59a6305000000000000000000f6cd5708a6ba38d8501502b5b4e5b93627e8dcc9bd13991894c6e04ade262aa99582815c505b2e17479a751b" + val customExt = Map( + 1.toByte -> ByteArrayConstant(Base16.decode(h).get) + ).toSeq + + test("Prop1", env, customExt, + """{ + | def reverse4(bytes: Coll[Byte]): Coll[Byte] = { + | Coll(bytes(3), bytes(2), bytes(1), bytes(0)) + | } + | + | def reverse32(bytes: Coll[Byte]): Coll[Byte] = { + | Coll(bytes(31), bytes(30), bytes(29), bytes(28), bytes(27), bytes(26), bytes(25), bytes(24), + | bytes(23), bytes(22), bytes(21), bytes(20), bytes(19), bytes(18), bytes(17), bytes(16), + | bytes(15), bytes(14), bytes(13), bytes(12), bytes(11), bytes(10), bytes(9), bytes(8), + | bytes(7), bytes(6), bytes(5), bytes(4), bytes(3), bytes(2), bytes(1), bytes(0)) + | } + | + | val bitcoinHeader = getVar[Coll[Byte]](1).get + | val id = reverse32(sha256(sha256(bitcoinHeader))) + | val hit = byteArrayToBigInt(id) + | + | val nBitsBytes = reverse4(bitcoinHeader.slice(72, 76)) + | + | val pad = Coll[Byte](0.toByte, 0.toByte, 0.toByte, 0.toByte) + | + | val nbits = byteArrayToLong(pad ++ nBitsBytes) + | + | val difficulty = nbits.decodeNbits + | + | hit < 500000000000L + |} + |""".stripMargin, + propExp = null, + testExceededCost = false + ) + } + property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", From a90e7bea5902e1914cbe680e83ec47eff9a8341d Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 27 May 2024 00:30:55 +0300 Subject: [PATCH 053/123] pow check test passing --- .../src/main/scala/sigma/SigmaDsl.scala | 2 + .../sigma/reflection/ReflectionData.scala | 3 + .../src/main/scala/sigma/ast/methods.scala | 50 +++++++++---- .../scala/sigma/data/CSigmaDslBuilder.scala | 5 ++ .../scala/sigmastate/eval/BasicOpsTests.scala | 1 + .../scala/sigmastate/eval/GraphBuilding.scala | 3 + .../scala/special/sigma/SigmaDslUnit.scala | 1 + .../special/sigma/impl/SigmaDslImpl.scala | 14 ++++ .../utxo/BasicOpsSpecification.scala | 70 +++++++++++-------- 9 files changed, 103 insertions(+), 46 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 56e4a1da37..7b20ac80b9 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -697,6 +697,8 @@ trait SigmaDslBuilder { */ def groupGenerator: GroupElement + def decodeNbits(l: Long): BigInt + /** * Transforms serialized bytes of ErgoTree with segregated constants by replacing constants * at given positions with new values. This operation allow to use serialized scripts as diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index debb36e3c0..b4b5fd9f23 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -446,6 +446,9 @@ object ReflectionData { }, mkMethod(clazz, "decodePoint", Array[Class[_]](cColl)) { (obj, args) => obj.asInstanceOf[SigmaDslBuilder].decodePoint(args(0).asInstanceOf[Coll[Byte]]) + }, + mkMethod(clazz, "decodeNbits", Array[Class[_]](cColl)) { (obj, args) => + obj.asInstanceOf[SigmaDslBuilder].decodeNbits(args(0).asInstanceOf[Long]) } ) ) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 38919f81c5..171d2b95c7 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -8,10 +8,11 @@ import sigma.ast.SMethod.{MethodCallIrBuilder, MethodCostFunc, javaMethodOf} import sigma.ast.SType.TypeCode import sigma.ast.syntax.{SValue, ValueOps} import sigma.data.OverloadHack.Overloaded1 -import sigma.data.{DataValueComparer, KeyValueColl, Nullable, RType, SigmaConstants} +import sigma.data.{CBigInt, DataValueComparer, KeyValueColl, Nullable, RType, SigmaConstants} import sigma.eval.{CostDetails, ErgoTreeEvaluator, TracedCost} import sigma.reflection.RClass import sigma.serialization.CoreByteWriter.ArgInfo +import sigma.util.NBitsUtils import sigma.utils.SparseArrayContainer import scala.annotation.unused @@ -303,17 +304,8 @@ case object SLongMethods extends SNumericTypeMethods { /** Type for which this container defines methods. */ override def ownerType: SMonoType = SLong - lazy val DecodeNBitsMethod: SMethod = SMethod( - this, "decodeNbits", SFunc(this.ownerType, SBigInt), 8, FixedCost(JitCost(5))) - .withInfo(PropertyCall, "Consider this Long value as nbits-encoded BigInt value and decode it to BigInt") + protected override def getMethods(): Seq[SMethod] = super.getMethods() - protected override def getMethods(): Seq[SMethod] = { - if (VersionContext.current.isV6SoftForkActivated) { - super.getMethods() ++ Seq(DecodeNBitsMethod) - } else { - super.getMethods() - } - } } /** Methods of BigInt type. Implemented using [[java.math.BigInteger]]. */ @@ -1531,9 +1523,37 @@ case object SGlobalMethods extends MonoTypeMethods { Xor.xorWithCosting(ls, rs) } - protected override def getMethods() = super.getMethods() ++ Seq( - groupGeneratorMethod, - xorMethod - ) + lazy val decodeNBitsMethod: SMethod = SMethod( + this, "decodeNbits", SFunc(Array(SGlobal, SLong), SBigInt), 3, FixedCost(JitCost(5))) + .withIRInfo(MethodCallIrBuilder) + .withInfo(Xor, "Byte-wise XOR of two collections of bytes", ArgInfo("left", "left operand")) + + /** + * + */ + def decodeNbits_eval(mc: MethodCall, G: SigmaDslBuilder, l: Long)(implicit E: ErgoTreeEvaluator): BigInt = { + CBigInt(NBitsUtils.decodeCompactBits(l).bigInteger) // todo: costing is ignored here + } + + { + if (VersionContext.current.isV6SoftForkActivated) { + super.getMethods() ++ Seq(decodeNBitsMethod) + } else { + super.getMethods() + } + } + + protected override def getMethods() = if (VersionContext.current.isV6SoftForkActivated) { + super.getMethods() ++ Seq( + groupGeneratorMethod, + xorMethod, + decodeNBitsMethod + ) + } else { + super.getMethods() ++ Seq( + groupGeneratorMethod, + xorMethod + ) + } } diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 3938feacd3..5f401ad9ff 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -10,6 +10,7 @@ import sigma.crypto.{CryptoConstants, EcPointType, Ecp} import sigma.eval.Extensions.EvalCollOps import sigma.serialization.{GroupElementSerializer, SigmaSerializer} import sigma.util.Extensions.BigIntegerOps +import sigma.util.NBitsUtils import sigma.validation.SigmaValidationSettings import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext} @@ -175,6 +176,10 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => override def groupGenerator: GroupElement = _generatorElement + def decodeNbits(l: Long): BigInt = { + CBigInt(NBitsUtils.decodeCompactBits(l).bigInteger) + } + /** * @return the identity of the Dlog group used in ErgoTree */ diff --git a/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala b/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala index 95548c1969..fbd74ed873 100644 --- a/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala +++ b/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala @@ -5,6 +5,7 @@ import org.scalatest.matchers.should.Matchers import sigma.ast.{BigIntConstant, ErgoTree, JitCost, MethodCall, SBigIntMethods} import sigma.crypto.SecP256K1Group import sigma.data.{CBigInt, CSigmaDslBuilder, TrivialProp} +import sigma.eval.SigmaDsl import sigma.util.Extensions.SigmaBooleanOps import sigma.util.NBitsUtils diff --git a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala index 5afdd3a28c..27bdcc0413 100644 --- a/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigmastate/eval/GraphBuilding.scala @@ -1141,6 +1141,9 @@ 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 SGlobalMethods.decodeNBitsMethod.name if VersionContext.current.isV6SoftForkActivated => + val c1 = asRep[Long](argsV(0)) + g.decodeNbits(c1) case _ => throwError } case _ => throwError diff --git a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala index 9e3a06a62f..2ff51993c3 100644 --- a/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/special/sigma/SigmaDslUnit.scala @@ -113,6 +113,7 @@ 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 decodeNbits(l: Ref[Long]): Ref[BigInt] }; trait CostModelCompanion; trait BigIntCompanion; diff --git a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala index 81525fa0b4..94e207ae25 100644 --- a/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/special/sigma/impl/SigmaDslImpl.scala @@ -1955,6 +1955,13 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { Array[AnyRef](l, r), true, false, element[Coll[Byte]])) } + + override def decodeNbits(l: Ref[Long]): Ref[BigInt] = { + asRep[BigInt](mkMethodCall(self, + SigmaDslBuilderClass.getMethod("decodeNbits", classOf[Sym]), + Array[AnyRef](), + true, false, element[BigInt])) + } } implicit object LiftableSigmaDslBuilder @@ -2114,6 +2121,13 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { Array[AnyRef](l, r), true, true, element[Coll[Byte]])) } + + override def decodeNbits(l: Ref[Long]): Ref[BigInt] = { + asRep[BigInt](mkMethodCall(source, + SigmaDslBuilderClass.getMethod("decodeNbits", classOf[Sym]), + Array[AnyRef](l), + true, true, element[BigInt])) + } } // entityUnref: single unref method for each type family diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index e68b262c59..abfe9c0df4 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -4,6 +4,7 @@ import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ import scorex.util.encode.Base16 import sigma.Extensions.ArrayOps +import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder} @@ -164,37 +165,44 @@ class BasicOpsSpecification extends CompilerTestingCommons 1.toByte -> ByteArrayConstant(Base16.decode(h).get) ).toSeq - test("Prop1", env, customExt, - """{ - | def reverse4(bytes: Coll[Byte]): Coll[Byte] = { - | Coll(bytes(3), bytes(2), bytes(1), bytes(0)) - | } - | - | def reverse32(bytes: Coll[Byte]): Coll[Byte] = { - | Coll(bytes(31), bytes(30), bytes(29), bytes(28), bytes(27), bytes(26), bytes(25), bytes(24), - | bytes(23), bytes(22), bytes(21), bytes(20), bytes(19), bytes(18), bytes(17), bytes(16), - | bytes(15), bytes(14), bytes(13), bytes(12), bytes(11), bytes(10), bytes(9), bytes(8), - | bytes(7), bytes(6), bytes(5), bytes(4), bytes(3), bytes(2), bytes(1), bytes(0)) - | } - | - | val bitcoinHeader = getVar[Coll[Byte]](1).get - | val id = reverse32(sha256(sha256(bitcoinHeader))) - | val hit = byteArrayToBigInt(id) - | - | val nBitsBytes = reverse4(bitcoinHeader.slice(72, 76)) - | - | val pad = Coll[Byte](0.toByte, 0.toByte, 0.toByte, 0.toByte) - | - | val nbits = byteArrayToLong(pad ++ nBitsBytes) - | - | val difficulty = nbits.decodeNbits - | - | hit < 500000000000L - |} - |""".stripMargin, - propExp = null, - testExceededCost = false - ) + def powTest() = { + test("Prop1", env, customExt, + """{ + | def reverse4(bytes: Coll[Byte]): Coll[Byte] = { + | Coll(bytes(3), bytes(2), bytes(1), bytes(0)) + | } + | + | def reverse32(bytes: Coll[Byte]): Coll[Byte] = { + | Coll(bytes(31), bytes(30), bytes(29), bytes(28), bytes(27), bytes(26), bytes(25), bytes(24), + | bytes(23), bytes(22), bytes(21), bytes(20), bytes(19), bytes(18), bytes(17), bytes(16), + | bytes(15), bytes(14), bytes(13), bytes(12), bytes(11), bytes(10), bytes(9), bytes(8), + | bytes(7), bytes(6), bytes(5), bytes(4), bytes(3), bytes(2), bytes(1), bytes(0)) + | } + | + | val bitcoinHeader = getVar[Coll[Byte]](1).get + | val id = reverse32(sha256(sha256(bitcoinHeader))) + | val hit = byteArrayToBigInt(id) + | + | val nBitsBytes = reverse4(bitcoinHeader.slice(72, 76)) + | + | val pad = Coll[Byte](0.toByte, 0.toByte, 0.toByte, 0.toByte) + | + | val nbits = byteArrayToLong(pad ++ nBitsBytes) + | + | val difficulty = Global.decodeNbits(nbits) + | + | hit < difficulty + |} + |""".stripMargin, + propExp = null, + testExceededCost = false + ) + } + if (activatedVersionInTests < V6SoftForkVersion) { + an[sigma.exceptions.TyperException] should be thrownBy powTest() + } else { + powTest() + } } property("Relation operations") { From 2e23a2c5e01101c8655ca41160faaf61a5e63427 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Tue, 28 May 2024 15:07:01 +0200 Subject: [PATCH 054/123] v6.0-serialize: CheckMinimalErgoTreeVersion rule removed --- .../validation/ValidationRules.scala | 17 +---------------- .../src/main/scala/sigma/ast/methods.scala | 2 -- .../src/test/scala/sigma/SigmaDslTesting.scala | 2 +- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala b/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala index 07fe8db0ee..9d4de47a99 100644 --- a/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala +++ b/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala @@ -155,20 +155,6 @@ object ValidationRules { override protected lazy val settings: SigmaValidationSettings = currentSettings } - object CheckMinimalErgoTreeVersion extends ValidationRule(1016, - "ErgoTree should have at least required version") with SoftForkWhenReplaced { - override protected lazy val settings: SigmaValidationSettings = currentSettings - - final def apply(currentVersion: Byte, minVersion: Byte): Unit = { - checkRule() - if (currentVersion < minVersion) { - throwValidationException( - new SigmaException(s"ErgoTree should have at least $minVersion version, but was $currentVersion"), - Array(currentVersion, minVersion)) - } - } - } - val ruleSpecs: Seq[ValidationRule] = Seq( CheckDeserializedScriptType, CheckDeserializedScriptIsSigmaProp, @@ -185,8 +171,7 @@ object ValidationRules { CheckHeaderSizeBit, CheckCostFuncOperation, CheckPositionLimit, - CheckLoopLevelInCostFunction, - CheckMinimalErgoTreeVersion + CheckLoopLevelInCostFunction ) /** Validation settings that correspond to the current version of the ErgoScript implementation. diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 3f27f85e2d..706c1a7894 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -1,7 +1,6 @@ package sigma.ast import org.ergoplatform._ -import org.ergoplatform.validation.ValidationRules.CheckMinimalErgoTreeVersion import org.ergoplatform.validation._ import sigma._ import sigma.ast.SCollection.{SBooleanArray, SBoxArray, SByteArray, SByteArray2, SHeaderArray} @@ -1534,7 +1533,6 @@ case object SGlobalMethods extends MonoTypeMethods { def serialize_eval(mc: MethodCall, G: SigmaDslBuilder, value: SType#WrappedType) (implicit E: ErgoTreeEvaluator): Coll[Byte] = { // TODO v6.0: accumulate cost - CheckMinimalErgoTreeVersion(E.context.currentErgoTreeVersion, VersionContext.V6SoftForkVersion) val t = Evaluation.stypeToRType(mc.args(0).tpe) G.serialize(value)(t) } diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index 28c9c05fec..f14ba275ff 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -860,7 +860,7 @@ class SigmaDslTesting extends AnyPropSpec extends Feature[A, B] { override def isSupportedIn(vc: VersionContext): Boolean = - vc.activatedVersion >= sinceVersion && vc.ergoTreeVersion >= sinceVersion + vc.activatedVersion >= sinceVersion override def scalaFunc: A => B = { x => sys.error(s"Semantic Scala function is not defined for old implementation: $this") From fe68c66859104cd1580a5b16c6f324b318d7d4bc Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Tue, 28 May 2024 15:53:43 +0200 Subject: [PATCH 055/123] v6.0-serialize: cleanup + ScalaDocs --- data/shared/src/main/scala/sigma/ast/SMethod.scala | 4 +++- data/shared/src/main/scala/sigma/ast/SigmaPredef.scala | 10 +++++----- data/shared/src/main/scala/sigma/ast/methods.scala | 2 +- data/shared/src/main/scala/sigma/ast/values.scala | 2 +- .../src/test/scala/sigmastate/CrossVersionProps.scala | 2 ++ .../test/scala/sigmastate/lang/SigmaParserTest.scala | 3 +++ .../compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala | 2 +- .../test/scala/sigmastate/lang/SigmaBinderTest.scala | 3 +++ .../test/scala/sigmastate/lang/SigmaTyperTest.scala | 1 + 9 files changed, 20 insertions(+), 9 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/SMethod.scala b/data/shared/src/main/scala/sigma/ast/SMethod.scala index 332c74be6b..47f6e744b0 100644 --- a/data/shared/src/main/scala/sigma/ast/SMethod.scala +++ b/data/shared/src/main/scala/sigma/ast/SMethod.scala @@ -78,7 +78,9 @@ case class SMethod( /** Operation descriptor of this method. */ lazy val opDesc = MethodDesc(this) - /** Return true if this method has runtime type parameters */ + /** 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. diff --git a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala index f2da24d2df..7d6da0a5f9 100644 --- a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala +++ b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala @@ -405,8 +405,8 @@ object SigmaPredef { val SerializeFunc = PredefinedFunc("serialize", Lambda(Seq(paramT), Array("value" -> tT), SByteArray, None), - PredefFuncInfo( - { case (_, args @ Seq(value)) => + irInfo = PredefFuncInfo( + irBuilder = { case (_, args @ Seq(value)) => MethodCall.typed[Value[SCollection[SByte.type]]]( Global, SGlobalMethods.serializeMethod.withConcreteTypes(Map(tT -> value.tpe)), @@ -414,10 +414,10 @@ object SigmaPredef { Map() ) }), - OperationInfo(MethodCall, - """ + docInfo = OperationInfo(MethodCall, + """Serializes the given `value` into bytes using the default serialization format. """.stripMargin, - Seq(ArgInfo("value", "")) + Seq(ArgInfo("value", "value to serialize")) ) ) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 706c1a7894..262a3266dd 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -1522,7 +1522,7 @@ case object SGlobalMethods extends MonoTypeMethods { lazy val serializeMethod = SMethod(this, "serialize", SFunc(Array(SGlobal, tT), SByteArray, Array(paramT)), 3, DynamicCost) .withIRInfo(MethodCallIrBuilder) - .withInfo(MethodCall, "", + .withInfo(MethodCall, "Serializes the given `value` into bytes using the default serialization format.", ArgInfo("value", "value to be serialized")) diff --git a/data/shared/src/main/scala/sigma/ast/values.scala b/data/shared/src/main/scala/sigma/ast/values.scala index 7980fd96ce..dd1f10d9be 100644 --- a/data/shared/src/main/scala/sigma/ast/values.scala +++ b/data/shared/src/main/scala/sigma/ast/values.scala @@ -1299,7 +1299,7 @@ case class MethodCall( args: IndexedSeq[Value[SType]], typeSubst: Map[STypeVar, SType]) extends Value[SType] { require(method.explicitTypeArgs.forall(tyArg => typeSubst.contains(tyArg)), - s"Runtime Generic method call should have concrete type for each runtime type parameter, but was: $this") + 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/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala b/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala index e55b874dc3..87101a1f71 100644 --- a/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala +++ b/interpreter/shared/src/test/scala/sigmastate/CrossVersionProps.scala @@ -31,7 +31,9 @@ trait CrossVersionProps extends AnyPropSpecLike with TestsBase { System.gc() } forEachScriptAndErgoTreeVersion(activatedVersions, ergoTreeVersions) { + VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) { testFun_Run(testName, testFun) + } } } } diff --git a/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala b/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala index 70aa540a4f..5a0f2b3465 100644 --- a/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala +++ b/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala @@ -35,6 +35,9 @@ 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) { diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala index 9cd524149d..c089c0ccb5 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala @@ -1950,7 +1950,7 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { asRep[Coll[Byte]](mkMethodCall(self, SigmaDslBuilderClass.getMethod("serialize", classOf[Sym]), Array[AnyRef](value), - true, true, element[Coll[Byte]])) + true, false, element[Coll[Byte]])) } } diff --git a/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala b/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala index 54bd89c9c2..3c3687cb37 100644 --- a/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala +++ b/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala @@ -31,6 +31,9 @@ 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) { diff --git a/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala b/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala index 2c3bd44d39..8aeefba8a7 100644 --- a/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala +++ b/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala @@ -30,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 From a5321af4e41f6f6d25fceaec079d16a8786caf38 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Tue, 28 May 2024 20:44:27 +0200 Subject: [PATCH 056/123] v6.0-serialize: added CoreByteWriter.checkCostLimit --- .../sigma/serialization/CoreByteWriter.scala | 150 ++++++++++++++---- .../sigma/serialization/CoreSerializer.scala | 2 +- .../sigma/serialization/SigmaByteWriter.scala | 65 ++++++-- .../sigma/serialization/SigmaSerializer.scala | 7 +- 4 files changed, 178 insertions(+), 46 deletions(-) diff --git a/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala b/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala index aa4255449c..302663ba92 100644 --- a/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala +++ b/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala @@ -3,25 +3,47 @@ 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.{Bits, CostLimitChecker, DataInfo, U, Vlq, ZigZag} /** Implementation of [[Writer]] provided by `sigma-core` module. - * @param w destination [[Writer]] to which all the call got delegated. + * + * @param w destination [[Writer]] to which all the call got delegated. + * @param checkCostLimitOpt callback to check if the cost limit at current writing position + * is reached. The callback will throw an exception if the limit is reached. + * Note, the cost of serialization is approximated using formula + * `this.length * CostPerByte + InitialCost` */ -class CoreByteWriter(val w: Writer) extends Writer { +class CoreByteWriter(val w: Writer, val checkCostLimitOpt: Option[CostLimitChecker]) extends Writer { type CH = w.CH + /** Check the current writer length against the cost limit. */ + @inline protected def checkCostLimit(): Unit = { + if (checkCostLimitOpt.isDefined) + checkCostLimitOpt.get(this.length()) + } + @inline override def length(): Int = w.length() @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); + checkCostLimit() + this + } @inline override def result(): CH = w.result() - @inline def put(x: Byte): this.type = { w.put(x); this } + @inline def put(x: Byte): this.type = { + w.put(x); + checkCostLimit() + this + } + @inline def put(x: Byte, info: DataInfo[Byte]): this.type = { - w.put(x); this + w.put(x); + checkCostLimit() + this } override def putUByte(x: Int): this.type = { @@ -31,49 +53,105 @@ class CoreByteWriter(val w: Writer) extends Writer { super.putUByte(x) } - @inline def putBoolean(x: Boolean): this.type = { w.putBoolean(x); this } + @inline def putBoolean(x: Boolean): this.type = { + w.putBoolean(x); + checkCostLimit() + this + } + @inline def putBoolean(x: Boolean, info: DataInfo[Boolean]): this.type = { - w.putBoolean(x); this + w.putBoolean(x); + checkCostLimit() + this + } + + @inline def putShort(x: Short): this.type = { + w.putShort(x); + checkCostLimit() + this } - @inline def putShort(x: Short): this.type = { w.putShort(x); this } @inline def putShort(x: Short, info: DataInfo[Short]): this.type = { - w.putShort(x); this + w.putShort(x); + checkCostLimit() + this + } + + @inline def putUShort(x: Int): this.type = { + w.putUShort(x); + checkCostLimit() + this } - @inline def putUShort(x: Int): this.type = { w.putUShort(x); this } @inline def putUShort(x: Int, info: DataInfo[Vlq[U[Short]]]): this.type = { - w.putUShort(x); this + w.putUShort(x); + checkCostLimit() + this + } + + @inline def putInt(x: Int): this.type = { + w.putInt(x); + checkCostLimit() + this } - @inline def putInt(x: Int): this.type = { w.putInt(x); this } @inline def putInt(x: Int, info: DataInfo[Int]): this.type = { - w.putInt(x); this + w.putInt(x); + checkCostLimit() + this } - @inline def putUInt(x: Long): this.type = { w.putUInt(x); this } + @inline def putUInt(x: Long): this.type = { + w.putUInt(x); + checkCostLimit() + this + } @inline def putUInt(x: Long, info: DataInfo[Vlq[U[Int]]]): this.type = { - w.putUInt(x); this + w.putUInt(x); + checkCostLimit() + this } - @inline def putLong(x: Long): this.type = { w.putLong(x); this } + @inline def putLong(x: Long): this.type = { + w.putLong(x); + checkCostLimit() + this + } @inline def putLong(x: Long, info: DataInfo[Vlq[ZigZag[Long]]]): this.type = { - w.putLong(x); this + w.putLong(x); + checkCostLimit() + this + } + + @inline def putULong(x: Long): this.type = { + w.putULong(x); + checkCostLimit() + this } - @inline def putULong(x: Long): this.type = { w.putULong(x); this } @inline def putULong(x: Long, info: DataInfo[Vlq[U[Long]]]): this.type = { - w.putULong(x); this + w.putULong(x); + checkCostLimit() + this } override def putBytes(xs: Array[Byte], offset: Int, length: Int): this.type = { - w.putBytes(xs, offset, length); this + w.putBytes(xs, offset, length); + checkCostLimit() + this + } + + @inline def putBytes(xs: Array[Byte]): this.type = { + w.putBytes(xs); + checkCostLimit() + this } - @inline def putBytes(xs: Array[Byte]): this.type = { w.putBytes(xs); this } @inline def putBytes(xs: Array[Byte], info: DataInfo[Array[Byte]]): this.type = { - w.putBytes(xs); this + w.putBytes(xs); + checkCostLimit() + this } /** Put the two bytes of the big-endian representation of the Short value into the @@ -81,12 +159,18 @@ class CoreByteWriter(val w: Writer) extends Writer { @inline def putShortBytes(value: Short): this.type = { w.put((value >> 8).toByte) w.put(value.toByte) + checkCostLimit() this } - @inline def putBits(xs: Array[Boolean]): this.type = { w.putBits(xs); this } + @inline def putBits(xs: Array[Boolean]): this.type = { + w.putBits(xs); + checkCostLimit() + this + } @inline def putBits(xs: Array[Boolean], info: DataInfo[Bits]): this.type = { w.putBits(xs); + checkCostLimit() this } @@ -94,19 +178,28 @@ class CoreByteWriter(val w: Writer) extends Writer { w.putOption(x) { (_, v) => putValueC(this, v) } + checkCostLimit() this } - @inline def putShortString(s: String): this.type = { w.putShortString(s); this } + @inline def putShortString(s: String): this.type = { + w.putShortString(s); + checkCostLimit() + 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 } + @inline def putType[T <: SType](x: T): this.type = { + TypeSerializer.serialize(x, this); // the cost is checked in TypeSerializer + this + } @inline def putType[T <: SType](x: T, info: DataInfo[SType]): this.type = { - TypeSerializer.serialize(x, this); this + TypeSerializer.serialize(x, this); // the cost is checked in TypeSerializer + this } } @@ -114,6 +207,9 @@ class CoreByteWriter(val w: Writer) extends Writer { object CoreByteWriter { import scala.language.implicitConversions + /** Callback type of cost limit checker. */ + type CostLimitChecker = Int => Unit + /** Format descriptor type family. */ trait FormatDescriptor[T] { /** Size formula associated with this format */ diff --git a/core/shared/src/main/scala/sigma/serialization/CoreSerializer.scala b/core/shared/src/main/scala/sigma/serialization/CoreSerializer.scala index 938d3f22c1..2ec3ee5c1a 100644 --- a/core/shared/src/main/scala/sigma/serialization/CoreSerializer.scala +++ b/core/shared/src/main/scala/sigma/serialization/CoreSerializer.scala @@ -66,7 +66,7 @@ object CoreSerializer { def startWriter(): CoreByteWriter = { val b = new ByteArrayBuilder() val wi = new VLQByteBufferWriter(b) - val w = new CoreByteWriter(wi) + val w = new CoreByteWriter(wi, None) w } diff --git a/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala b/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala index 35d5e0c9b9..87b115e942 100644 --- a/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala +++ b/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala @@ -4,15 +4,28 @@ import scorex.util.serialization.Writer import sigma.ast.syntax._ import sigma.ast._ import sigma.serialization.CoreByteWriter.{ArgInfo, DataInfo, FormatDescriptor, SeqFmt} - -class SigmaByteWriter(override val w: Writer, - val constantExtractionStore: Option[ConstantStore]) - extends CoreByteWriter(w) { +import CoreByteWriter.CostLimitChecker + +/** 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 checkCostLimitOpt callback to check if the cost limit at current writing position + * is reached. The callback will throw an exception if the limit is reached. + */ +class SigmaByteWriter( + override val w: Writer, + val constantExtractionStore: Option[ConstantStore], + override val checkCostLimitOpt: Option[CostLimitChecker] +) + extends CoreByteWriter(w, checkCostLimitOpt) { import CoreByteWriter._ import ValueSerializer._ override def put(x: Byte, info: DataInfo[Byte]): this.type = { ValueSerializer.addArgInfo(info) + checkCostLimit() w.put(x); this } @@ -23,59 +36,81 @@ class SigmaByteWriter(override val w: Writer, @inline override def putBoolean(x: Boolean, info: DataInfo[Boolean]): this.type = { ValueSerializer.addArgInfo(info) - w.putBoolean(x); this + w.putBoolean(x); + checkCostLimit() + this } @inline override def putShort(x: Short, info: DataInfo[Short]): this.type = { ValueSerializer.addArgInfo(info) - w.putShort(x); this + w.putShort(x); + checkCostLimit() + this } @inline override def putUShort(x: Int, info: DataInfo[Vlq[U[Short]]]): this.type = { ValueSerializer.addArgInfo(info) - w.putUShort(x); this + w.putUShort(x); + checkCostLimit() + this } @inline override def putInt(x: Int, info: DataInfo[Int]): this.type = { ValueSerializer.addArgInfo(info) - w.putInt(x); this + w.putInt(x); + checkCostLimit() + this } @inline override def putUInt(x: Long, info: DataInfo[Vlq[U[Int]]]): this.type = { ValueSerializer.addArgInfo(info) - w.putUInt(x); this + w.putUInt(x); + checkCostLimit() + this } @inline override def putLong(x: Long, info: DataInfo[Vlq[ZigZag[Long]]]): this.type = { ValueSerializer.addArgInfo(info) - w.putLong(x); this + w.putLong(x); + checkCostLimit() + this } @inline override def putULong(x: Long, info: DataInfo[Vlq[U[Long]]]): this.type = { ValueSerializer.addArgInfo(info) - w.putULong(x); this + w.putULong(x); + checkCostLimit() + this } @inline override def putBytes(xs: Array[Byte], info: DataInfo[Array[Byte]]): this.type = { ValueSerializer.addArgInfo(info) - w.putBytes(xs); this + w.putBytes(xs); + checkCostLimit() + this } @inline override def putBits(xs: Array[Boolean], info: DataInfo[Bits]): this.type = { ValueSerializer.addArgInfo(info) w.putBits(xs); + checkCostLimit() this } @inline 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 checked 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]): this.type = { + ValueSerializer.serialize(x, this) // the cost is checked in ValueSerializer + this + } @inline 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 checked in ValueSerializer + this } @inline def putValues[T <: SType](xs: Seq[Value[T]]): this.type = { putUInt(xs.length) diff --git a/data/shared/src/main/scala/sigma/serialization/SigmaSerializer.scala b/data/shared/src/main/scala/sigma/serialization/SigmaSerializer.scala index 3765adb029..e842258f80 100644 --- a/data/shared/src/main/scala/sigma/serialization/SigmaSerializer.scala +++ b/data/shared/src/main/scala/sigma/serialization/SigmaSerializer.scala @@ -4,6 +4,7 @@ import java.nio.ByteBuffer import scorex.util.ByteArrayBuilder import scorex.util.serialization._ import sigma.data.SigmaConstants +import sigma.serialization.CoreByteWriter.CostLimitChecker import sigma.serialization.ValueCodes.OpCode object SigmaSerializer { @@ -51,14 +52,14 @@ 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, checkCostLimitOpt = None) w } - def startWriter(constantExtractionStore: ConstantStore): SigmaByteWriter = { + def startWriter(constantExtractionStore: ConstantStore, checkCostLimit: Option[CostLimitChecker] = 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 = Some(constantExtractionStore), checkCostLimit) w } } From 37b23cd9f981e4d29ed4a89c6e661040679888ee Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 29 May 2024 12:52:49 +0300 Subject: [PATCH 057/123] hit <= diff --- .../src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index abfe9c0df4..8b7cfc07b2 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -191,7 +191,8 @@ class BasicOpsSpecification extends CompilerTestingCommons | | val difficulty = Global.decodeNbits(nbits) | - | hit < difficulty + | // <= according to https://bitcoin.stackexchange.com/a/105224 + | hit <= difficulty |} |""".stripMargin, propExp = null, From 432addca9dbef1dc2d1f44e797bfbe2bab376c7a Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Wed, 29 May 2024 17:59:28 +0200 Subject: [PATCH 058/123] v6.0-serialize: cost accumulation in SigmaByteWriter and serialize_eval method --- .../sigma/serialization/CoreByteWriter.scala | 115 +++------ .../sigma/serialization/CoreSerializer.scala | 2 +- .../src/main/scala/sigma/ast/ErgoTree.scala | 2 +- .../src/main/scala/sigma/ast/methods.scala | 15 +- .../serialization/ErgoTreeSerializer.scala | 2 +- .../sigma/serialization/SigmaByteWriter.scala | 236 ++++++++++++++---- .../sigma/serialization/SigmaSerializer.scala | 12 +- .../test/scala/sigma/SigmaDslTesting.scala | 12 +- 8 files changed, 243 insertions(+), 153 deletions(-) diff --git a/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala b/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala index 302663ba92..37d1455ba3 100644 --- a/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala +++ b/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala @@ -3,155 +3,106 @@ package sigma.serialization import scorex.util.serialization.Writer.Aux import scorex.util.serialization.{VLQByteBufferWriter, Writer} import sigma.ast.SType -import sigma.serialization.CoreByteWriter.{Bits, CostLimitChecker, 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. - * @param checkCostLimitOpt callback to check if the cost limit at current writing position - * is reached. The callback will throw an exception if the limit is reached. - * Note, the cost of serialization is approximated using formula - * `this.length * CostPerByte + InitialCost` */ -class CoreByteWriter(val w: Writer, val checkCostLimitOpt: Option[CostLimitChecker]) extends Writer { +class CoreByteWriter(val w: Writer) extends Writer { type CH = w.CH - /** Check the current writer length against the cost limit. */ - @inline protected def checkCostLimit(): Unit = { - if (checkCostLimitOpt.isDefined) - checkCostLimitOpt.get(this.length()) - } - @inline override def length(): Int = w.length() @inline override def newWriter(): Aux[CH] = w.newWriter() @inline override def putChunk(chunk: CH): this.type = { - w.putChunk(chunk); - checkCostLimit() - this + w.putChunk(chunk); this } @inline override def result(): CH = w.result() - @inline def put(x: Byte): this.type = { - w.put(x); - checkCostLimit() - this + @inline override def put(x: Byte): this.type = { + w.put(x); this } @inline def put(x: Byte, info: DataInfo[Byte]): this.type = { - w.put(x); - checkCostLimit() - this + w.put(x); this } override def putUByte(x: Int): this.type = { super.putUByte(x) } + def putUByte(x: Int, info: DataInfo[U[Byte]]): this.type = { super.putUByte(x) } @inline def putBoolean(x: Boolean): this.type = { - w.putBoolean(x); - checkCostLimit() - this + w.putBoolean(x); this } @inline def putBoolean(x: Boolean, info: DataInfo[Boolean]): this.type = { - w.putBoolean(x); - checkCostLimit() - this + w.putBoolean(x); this } @inline def putShort(x: Short): this.type = { - w.putShort(x); - checkCostLimit() - this + w.putShort(x); this } @inline def putShort(x: Short, info: DataInfo[Short]): this.type = { - w.putShort(x); - checkCostLimit() - this + w.putShort(x); this } @inline def putUShort(x: Int): this.type = { - w.putUShort(x); - checkCostLimit() - this + w.putUShort(x); this } @inline def putUShort(x: Int, info: DataInfo[Vlq[U[Short]]]): this.type = { - w.putUShort(x); - checkCostLimit() - this + w.putUShort(x); this } @inline def putInt(x: Int): this.type = { - w.putInt(x); - checkCostLimit() - this + w.putInt(x); this } @inline def putInt(x: Int, info: DataInfo[Int]): this.type = { - w.putInt(x); - checkCostLimit() - this + w.putInt(x); this } @inline def putUInt(x: Long): this.type = { - w.putUInt(x); - checkCostLimit() - this + w.putUInt(x); this } @inline def putUInt(x: Long, info: DataInfo[Vlq[U[Int]]]): this.type = { - w.putUInt(x); - checkCostLimit() - this + w.putUInt(x); this } @inline def putLong(x: Long): this.type = { - w.putLong(x); - checkCostLimit() - this + w.putLong(x); this } @inline def putLong(x: Long, info: DataInfo[Vlq[ZigZag[Long]]]): this.type = { - w.putLong(x); - checkCostLimit() - this + w.putLong(x); this } @inline def putULong(x: Long): this.type = { - w.putULong(x); - checkCostLimit() - this + w.putULong(x); this } @inline def putULong(x: Long, info: DataInfo[Vlq[U[Long]]]): this.type = { - w.putULong(x); - checkCostLimit() - this + w.putULong(x); this } override def putBytes(xs: Array[Byte], offset: Int, length: Int): this.type = { - w.putBytes(xs, offset, length); - checkCostLimit() - this + w.putBytes(xs, offset, length); this } @inline def putBytes(xs: Array[Byte]): this.type = { - w.putBytes(xs); - checkCostLimit() - this + w.putBytes(xs); this } @inline def putBytes(xs: Array[Byte], info: DataInfo[Array[Byte]]): this.type = { - w.putBytes(xs); - checkCostLimit() - this + w.putBytes(xs); this } /** Put the two bytes of the big-endian representation of the Short value into the @@ -159,32 +110,25 @@ class CoreByteWriter(val w: Writer, val checkCostLimitOpt: Option[CostLimitCheck @inline def putShortBytes(value: Short): this.type = { w.put((value >> 8).toByte) w.put(value.toByte) - checkCostLimit() this } @inline def putBits(xs: Array[Boolean]): this.type = { - w.putBits(xs); - checkCostLimit() - this + w.putBits(xs); this } @inline def putBits(xs: Array[Boolean], info: DataInfo[Bits]): this.type = { - w.putBits(xs); - checkCostLimit() - this + w.putBits(xs); this } @inline def putOption[T](x: Option[T])(putValueC: (this.type, T) => Unit): this.type = { w.putOption(x) { (_, v) => putValueC(this, v) } - checkCostLimit() this } @inline def putShortString(s: String): this.type = { w.putShortString(s); - checkCostLimit() this } @@ -194,11 +138,11 @@ class CoreByteWriter(val w: Writer, val checkCostLimitOpt: Option[CostLimitCheck } @inline def putType[T <: SType](x: T): this.type = { - TypeSerializer.serialize(x, this); // the cost is checked in TypeSerializer + TypeSerializer.serialize(x, this) this } @inline def putType[T <: SType](x: T, info: DataInfo[SType]): this.type = { - TypeSerializer.serialize(x, this); // the cost is checked in TypeSerializer + TypeSerializer.serialize(x, this) this } @@ -207,9 +151,6 @@ class CoreByteWriter(val w: Writer, val checkCostLimitOpt: Option[CostLimitCheck object CoreByteWriter { import scala.language.implicitConversions - /** Callback type of cost limit checker. */ - type CostLimitChecker = Int => Unit - /** Format descriptor type family. */ trait FormatDescriptor[T] { /** Size formula associated with this format */ diff --git a/core/shared/src/main/scala/sigma/serialization/CoreSerializer.scala b/core/shared/src/main/scala/sigma/serialization/CoreSerializer.scala index 2ec3ee5c1a..938d3f22c1 100644 --- a/core/shared/src/main/scala/sigma/serialization/CoreSerializer.scala +++ b/core/shared/src/main/scala/sigma/serialization/CoreSerializer.scala @@ -66,7 +66,7 @@ object CoreSerializer { def startWriter(): CoreByteWriter = { val b = new ByteArrayBuilder() val wi = new VLQByteBufferWriter(b) - val w = new CoreByteWriter(wi, None) + val w = new CoreByteWriter(wi) w } diff --git a/data/shared/src/main/scala/sigma/ast/ErgoTree.scala b/data/shared/src/main/scala/sigma/ast/ErgoTree.scala index 68d69abd91..8d731e1c67 100644 --- a/data/shared/src/main/scala/sigma/ast/ErgoTree.scala +++ b/data/shared/src/main/scala/sigma/ast/ErgoTree.scala @@ -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/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 262a3266dd..fd9024ee62 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -12,6 +12,7 @@ import sigma.data.{DataValueComparer, KeyValueColl, Nullable, RType, SigmaConsta import sigma.eval.{CostDetails, ErgoTreeEvaluator, TracedCost} import sigma.reflection.RClass import sigma.serialization.CoreByteWriter.ArgInfo +import sigma.serialization.{DataSerializer, SigmaSerializer} import sigma.utils.SparseArrayContainer import scala.annotation.unused @@ -1532,9 +1533,17 @@ case object SGlobalMethods extends MonoTypeMethods { */ def serialize_eval(mc: MethodCall, G: SigmaDslBuilder, value: SType#WrappedType) (implicit E: ErgoTreeEvaluator): Coll[Byte] = { - // TODO v6.0: accumulate cost - val t = Evaluation.stypeToRType(mc.args(0).tpe) - G.serialize(value)(t) + + 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() ++ { diff --git a/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala b/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala index 43e41f91ff..ce7d1241c3 100644 --- a/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala +++ b/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala @@ -347,7 +347,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) diff --git a/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala b/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala index 87b115e942..93e078e319 100644 --- a/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala +++ b/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala @@ -4,28 +4,52 @@ import scorex.util.serialization.Writer import sigma.ast.syntax._ import sigma.ast._ import sigma.serialization.CoreByteWriter.{ArgInfo, DataInfo, FormatDescriptor, SeqFmt} -import CoreByteWriter.CostLimitChecker +import SigmaByteWriter._ /** 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 checkCostLimitOpt callback to check if the cost limit at current writing position - * is reached. The callback will throw an exception if the limit is reached. + * @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], - override val checkCostLimitOpt: Option[CostLimitChecker] -) - extends CoreByteWriter(w, checkCostLimitOpt) { + 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) - checkCostLimit() + addFixedCost(PutByteCost) w.put(x); this } @@ -34,90 +58,160 @@ class SigmaByteWriter( 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) - w.putBoolean(x); - checkCostLimit() - this + addFixedCost(PutByteCost) + w.putBoolean(x); this + } + + override def putShort(x: Short): this.type = { + addFixedCost(PutSignedNumericCost) + super.putShort(x) } - @inline override def putShort(x: Short, info: DataInfo[Short]): this.type = { + override def putShort(x: Short, info: DataInfo[Short]): this.type = { ValueSerializer.addArgInfo(info) - w.putShort(x); - checkCostLimit() - this + addFixedCost(PutSignedNumericCost) + w.putShort(x); this + } + + override def putUShort(x: Int): this.type = { + addFixedCost(PutUnsignedNumericCost) + super.putUShort(x) } - @inline override def putUShort(x: Int, info: DataInfo[Vlq[U[Short]]]): this.type = { + override def putUShort(x: Int, info: DataInfo[Vlq[U[Short]]]): this.type = { ValueSerializer.addArgInfo(info) - w.putUShort(x); - checkCostLimit() - this + 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) - w.putInt(x); - checkCostLimit() - this + 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) - w.putUInt(x); - checkCostLimit() - this + 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) - w.putLong(x); - checkCostLimit() - this + 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) - w.putULong(x); - checkCostLimit() - this + addFixedCost(PutUnsignedNumericCost) + w.putULong(x); this + } + + 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) } - @inline override def putBytes(xs: Array[Byte], info: DataInfo[Array[Byte]]): this.type = { + override def putBytes(xs: Array[Byte], info: DataInfo[Array[Byte]]): this.type = { ValueSerializer.addArgInfo(info) - w.putBytes(xs); - checkCostLimit() - this + addPerItemCost(PutChunkCost, xs.length) + w.putBytes(xs); this + } + + /** 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) } - @inline override def putBits(xs: Array[Boolean], info: DataInfo[Bits]): this.type = { + 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); - checkCostLimit() - 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); // the cost is checked in TypeSerializer + 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) // the cost is checked in ValueSerializer + /** 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 } - @inline def putValue[T <: SType](x: Value[T], info: DataInfo[SValue]): this.type = { + + /** Serializes the given expression using [[ValueSerializer]]. + * @param x the ErgoTree expression to serialize + * @param info additional 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); // the cost is checked in ValueSerializer + 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) @@ -127,6 +221,40 @@ class SigmaByteWriter( } 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 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 e842258f80..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.serialization.CoreByteWriter.CostLimitChecker +import sigma.serialization.SigmaByteWriter.{FixedCostCallback, PerItemCostCallback} import sigma.serialization.ValueCodes.OpCode object SigmaSerializer { @@ -52,14 +52,18 @@ object SigmaSerializer { def startWriter(): SigmaByteWriter = { val b = new ByteArrayBuilder() val wi = new VLQByteBufferWriter(b) - val w = new SigmaByteWriter(wi, constantExtractionStore = None, checkCostLimitOpt = None) + val w = new SigmaByteWriter(wi, constantExtractionStore = None, addFixedCostCallbackOpt = None, addPerItemCostCallbackOpt = None) w } - def startWriter(constantExtractionStore: ConstantStore, checkCostLimit: Option[CostLimitChecker] = None): 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), checkCostLimit) + val w = new SigmaByteWriter(wi, constantExtractionStore = constantExtractionStore, addFixedCostCallback, addPerItemCostCallback) w } } diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index f14ba275ff..5e43eb18e1 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -255,13 +255,21 @@ class SigmaDslTesting extends AnyPropSpec fail( s"""Should succeed with the same value or fail with the same exception, but was: - |First result: $b1 - |Second result: $b2 + |First result: ${errorWithStack(b1)} + |Second result: ${errorWithStack(b2)} |Root cause: $cause |""".stripMargin) } } + private def errorWithStack[A](e: Try[A]): String = e match { + case Failure(t) => + val sw = new java.io.StringWriter + t.printStackTrace(new java.io.PrintWriter(sw)) + sw.toString + case _ => e.toString + } + /** Creates a new ErgoLikeContext using given [[CContext]] as template. * Copies most of the data from ctx and the missing data is taken from the args. * This is a helper method to be used in tests only. From 97377c2f93e2eef527af5343a784819091409f39 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Mon, 3 Jun 2024 11:29:37 +0200 Subject: [PATCH 059/123] v6.0-serialize: cleanup + ScalaDocs --- .../sigma/serialization/CoreByteWriter.scala | 101 +++++++++++++++--- .../sigma/serialization/SigmaByteWriter.scala | 2 +- 2 files changed, 90 insertions(+), 13 deletions(-) diff --git a/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala b/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala index 37d1455ba3..92d85ed9d8 100644 --- a/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala +++ b/core/shared/src/main/scala/sigma/serialization/CoreByteWriter.scala @@ -7,7 +7,7 @@ import sigma.serialization.CoreByteWriter._ /** Implementation of [[Writer]] provided by `sigma-core` module. * - * @param w destination [[Writer]] to which all the call got delegated. + * @param w destination [[Writer]] to which all the call got delegated. */ class CoreByteWriter(val w: Writer) extends Writer { type CH = w.CH @@ -26,6 +26,10 @@ class CoreByteWriter(val w: Writer) extends Writer { 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 } @@ -34,60 +38,109 @@ class CoreByteWriter(val w: Writer) extends Writer { 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 = { + @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 = { + @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 = { + @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 = { + @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 = { + @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 = { + @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 = { + @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 } @@ -98,9 +151,14 @@ class CoreByteWriter(val w: Writer) extends Writer { w.putBytes(xs, offset, length); this } - @inline def putBytes(xs: Array[Byte]): this.type = { + @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 } @@ -113,21 +171,27 @@ class CoreByteWriter(val w: Writer) extends Writer { this } - @inline def putBits(xs: Array[Boolean]): this.type = { + @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 } - @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 = { + @inline override def putShortString(s: String): this.type = { w.putShortString(s); this } @@ -137,10 +201,18 @@ class CoreByteWriter(val w: Writer) extends Writer { case wr: VLQByteBufferWriter => wr.toBytes } + /** 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 @@ -263,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/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala b/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala index 93e078e319..7bda855005 100644 --- a/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala +++ b/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala @@ -192,7 +192,7 @@ class SigmaByteWriter( /** Serializes the given expression using [[ValueSerializer]]. * @param x the ErgoTree expression to serialize - * @param info additional information about the data being serialized + * @param info meta information about the data being serialized */ def putValue[T <: SType](x: Value[T], info: DataInfo[SValue]): this.type = { ValueSerializer.addArgInfo(info) From 767fbb4af9e420c42a0d43e8d7c2945a46046749 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Mon, 3 Jun 2024 15:54:54 +0200 Subject: [PATCH 060/123] v6.0-serialize: tests for cost trace --- .../src/main/scala/sigma/ast/methods.scala | 5 +- .../sigma/serialization/SigmaByteWriter.scala | 6 ++ .../scala/sigma/LanguageSpecificationV6.scala | 56 +++++++++++---- .../test/scala/sigma/SigmaDslTesting.scala | 71 +++++++++++++------ 4 files changed, 101 insertions(+), 37 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index fd9024ee62..ef548d6185 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -12,7 +12,7 @@ import sigma.data.{DataValueComparer, KeyValueColl, Nullable, RType, SigmaConsta import sigma.eval.{CostDetails, ErgoTreeEvaluator, TracedCost} import sigma.reflection.RClass import sigma.serialization.CoreByteWriter.ArgInfo -import sigma.serialization.{DataSerializer, SigmaSerializer} +import sigma.serialization.{DataSerializer, SigmaByteWriter, SigmaSerializer} import sigma.utils.SparseArrayContainer import scala.annotation.unused @@ -1534,6 +1534,8 @@ case object SGlobalMethods extends MonoTypeMethods { 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) } @@ -1542,6 +1544,7 @@ case object SGlobalMethods extends MonoTypeMethods { } val w = SigmaSerializer.startWriter(None, Some(addFixedCostCallback), Some(addPerItemCostCallback)) + DataSerializer.serialize(value, mc.args(0).tpe, w) Colls.fromArray(w.toBytes) } diff --git a/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala b/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala index 7bda855005..db9312240f 100644 --- a/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala +++ b/data/shared/src/main/scala/sigma/serialization/SigmaByteWriter.scala @@ -228,6 +228,12 @@ object SigmaByteWriter { /** 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 diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 20faabe128..e4ae10cac6 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -1,8 +1,8 @@ package sigma -import sigma.ast.{Downcast, FuncValue, Global, MethodCall, SBigInt, SByte, SGlobalMethods, SInt, SLong, SShort, STypeVar, ValUse} +import sigma.ast.{Apply, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, Global, JitCost, MethodCall, NamedDesc, OptionGet, SBigInt, SByte, SGlobalMethods, SInt, SLong, SShort, STypeVar, ValUse} import sigma.data.{CBigInt, ExactNumeric, RType} -import sigma.eval.SigmaDsl +import sigma.eval.{SigmaDsl, TracedCost} import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} import sigmastate.exceptions.MethodNotFound @@ -17,6 +17,8 @@ import scala.util.Success 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) @@ -35,28 +37,54 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => 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, Success(Coll(-128.toByte))), - (-1.toByte, Success(Coll(-1.toByte))), - (0.toByte, Success(Coll(0.toByte))), - (1.toByte, Success(Coll(1.toByte))), - (127.toByte, Success(Coll(127.toByte))) + (-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)) ) - testCases(cases, serializeByte) + 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, Success(Coll[Byte](0xFF.toByte, 0xFF.toByte, 0x03.toByte))), - (-1.toShort, Success(Coll(1.toByte))), - (0.toShort, Success(Coll(0.toByte))), - (1.toShort, Success(Coll(2.toByte))), - (Short.MaxValue, Success(Coll(-2.toByte, -1.toByte, 3.toByte))) + (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)) ) - testCases(cases, serializeShort) + verifyCases(cases, serializeShort, preGeneratedSamples = None) } // TODO v6.0: implement serialization roundtrip tests after merge with deserializeTo diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index 5e43eb18e1..37fb0e6503 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -179,6 +179,34 @@ class SigmaDslTesting extends AnyPropSpec true } + /** Checks the result of feature execution against expected result. + * If settings.failOnTestVectors == true, then print out actual cost results + * + * @param res the result of feature execution + * @param expected the expected result + */ + protected def checkResultAgainstExpected(res: Try[(B, CostDetails)], expected: Expected[B]): Unit = { + val newRes = expected.newResults(ergoTreeVersionInTests) + val expectedTrace = newRes._2.fold(Seq.empty[CostItem])(_.trace) + if (expectedTrace.isEmpty) { + // new cost expectation is missing, print out actual cost results + if (evalSettings.printTestVectors) { + res.foreach { case (_, newDetails) => + printCostDetails(script, newDetails) + } + } + } + else { + // new cost expectation is specified, compare it with the actual result + res.foreach { case (_, newDetails) => + if (newDetails.trace != expectedTrace) { + printCostDetails(script, newDetails) + newDetails.trace shouldBe expectedTrace + } + } + } + } + /** v3 and v4 implementation*/ private var _oldF: Try[CompiledFunc[A, B]] = _ def oldF: CompiledFunc[A, B] = { @@ -624,28 +652,10 @@ class SigmaDslTesting extends AnyPropSpec checkResult(funcRes.map(_._1), expected.value, failOnTestVectors, "ExistingFeature#verifyCase: ") - val newRes = expected.newResults(ergoTreeVersionInTests) - val expectedTrace = newRes._2.fold(Seq.empty[CostItem])(_.trace) - if (expectedTrace.isEmpty) { - // new cost expectation is missing, print out actual cost results - if (evalSettings.printTestVectors) { - funcRes.foreach { case (_, newDetails) => - printCostDetails(script, newDetails) - } - } - } - else { - // new cost expectation is specified, compare it with the actual result - funcRes.foreach { case (_, newDetails) => - if (newDetails.trace != expectedTrace) { - printCostDetails(script, newDetails) - newDetails.trace shouldBe expectedTrace - } - } - } - + checkResultAgainstExpected(funcRes, expected) checkVerify(input, expected) } + } /** Descriptor of a language feature which is changed in v5.0. @@ -921,8 +931,11 @@ 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 (this.isSupportedIn(VersionContext.current)) { + checkResultAgainstExpected(funcRes, expected) + } else + funcRes.isFailure shouldBe true + Try(scalaFuncNew(input)) shouldBe expected.value } } @@ -990,6 +1003,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 From 744d8a58bc7c86c84f2aa1c5694db935a3172260 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 3 Jun 2024 22:23:54 +0300 Subject: [PATCH 061/123] conversion test stub --- .../src/main/scala/sigma/ast/SigmaPredef.scala | 7 ++++++- .../sigmastate/utxo/BasicOpsSpecification.scala | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala index d8c65a7afe..752b69f636 100644 --- a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala +++ b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala @@ -196,7 +196,12 @@ object SigmaPredef { Lambda(Array("input" -> SString), SUnsignedBigInt, None), PredefFuncInfo( { case (_, Seq(arg: EvaluatedValue[SString.type]@unchecked)) => - UnsignedBigIntConstant(new BigInteger(arg.value)) + val bi = new BigInteger(arg.value) + if (bi.compareTo(BigInteger.ZERO) >= 0) { + UnsignedBigIntConstant(bi) + } else { + throw new InvalidArguments(s"Negative argument for unsignedBigInt()") + } }), OperationInfo(Constant, """Parsing string literal argument as a 256-bit unsigned big integer.""".stripMargin, diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 28084be987..e6f08f75fc 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -169,7 +169,21 @@ class BasicOpsSpecification extends CompilerTestingCommons deserTest() } - property("signed <-> unsigned bigint conversion") { + property("signed <-> unsigned bigint conversion - positive bigint") { + val b = new BigInteger("9280562930080889354892980449861222646750586663683904599823322027983929189860") + val ub = new BigInteger(1, b.toByteArray) + + // todo: how to upcast? + def deserTest() = {test("restoring", env, ext, + s"{ val b = bigInt(\"${ub.toString}\"); b > 1 }", + null, + true + )} + + deserTest() + } + + property("signed <-> unsigned bigint conversion - negative bigint") { } From 2acc6db89d96659d1efcb6aa3ddae2ec562a132f Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 4 Jun 2024 11:08:17 +0300 Subject: [PATCH 062/123] more todos --- core/shared/src/main/scala/sigma/ast/SType.scala | 2 +- data/shared/src/main/scala/sigma/ast/methods.scala | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index c72ba65e73..4be9087ca7 100644 --- a/core/shared/src/main/scala/sigma/ast/SType.scala +++ b/core/shared/src/main/scala/sigma/ast/SType.scala @@ -340,7 +340,7 @@ trait SNumericType extends SProduct with STypeCompanion { object SNumericType extends STypeCompanion { /** Array of all numeric types ordered by number of bytes in the representation. */ - final val allNumericTypes = Array(SByte, SShort, SInt, SLong, SBigInt) + final val allNumericTypes = Array(SByte, SShort, SInt, SLong, SBigInt, SUnsignedBigInt) // TODO v6.0: this typeId is now shadowed by SGlobal.typeId // see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/667 diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index e4cf0007e0..4656d3361e 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -210,6 +210,8 @@ object SNumericTypeMethods extends MethodsContainer { .withCost(costOfNumericCast) .withInfo(PropertyCall, "Converts this numeric value to \\lst{BigInt}") + // todo: ToUnsignedBigInt + /** Cost of: 1) creating Byte collection from a numeric value */ val ToBytes_CostKind = FixedCost(JitCost(5)) @@ -316,7 +318,10 @@ case object SBigIntMethods extends SNumericTypeMethods { val ToNBits = SMethod(this, "nbits", SFunc(this.ownerType, SLong), 8, ToNBitsCostInfo.costKind) .withInfo(ModQ, "Encode this big integer value as NBits") - /** The following `modQ` methods are not fully implemented in v4.x and this descriptors. + /** + * todo: remove + * + * 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. From 37ac9212daf09fe899dd9b7981668f1c0a69e979 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 6 Jun 2024 16:34:40 +0300 Subject: [PATCH 063/123] BasicOpsSpecification tests for serialize --- .../utxo/BasicOpsSpecification.scala | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 79701d6e07..29443406c5 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -2,7 +2,10 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ +import scorex.util.encode.Base16 import sigma.Extensions.ArrayOps +import sigma.SigmaTestingData +import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder} @@ -19,6 +22,7 @@ import sigmastate.interpreter.Interpreter._ import sigma.ast.Apply import sigma.eval.EvalSettings import sigma.exceptions.InvalidType +import sigmastate.utils.Helpers import sigmastate.utils.Helpers._ import java.math.BigInteger @@ -157,6 +161,108 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } + 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.exceptions.TyperException] 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.exceptions.TyperException] 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 [Exception] 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 [Exception] 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.exceptions.TyperException] should be thrownBy deserTest() + } else { + deserTest() + } + } + + // todo: roundtrip tests with deserializeTo from https://github.com/ScorexFoundation/sigmastate-interpreter/pull/979 + property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", From 074d609ac854b9c42498efba46bcca22d0d5cdbc Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 6 Jun 2024 17:08:23 +0300 Subject: [PATCH 064/123] MethodCall deserialization round trip for Global.serialize --- .../MethodCallSerializerSpecification.scala | 23 +++++++++++++++++++ .../utxo/BasicOpsSpecification.scala | 18 ++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala index 1db166c685..e78518f8b3 100644 --- a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala @@ -1,6 +1,8 @@ package sigma.serialization import sigma.VersionContext +import sigma.ast.SCollection.SByteArray +import sigma.ast.SType.tT import sigma.ast._ import sigma.validation.ValidationException @@ -45,4 +47,25 @@ class MethodCallSerializerSpecification extends SerializationSpecification { } ) } + + 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/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 29443406c5..13bf74b5f6 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -2,7 +2,6 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ -import scorex.util.encode.Base16 import sigma.Extensions.ArrayOps import sigma.SigmaTestingData import sigma.VersionContext.V6SoftForkVersion @@ -161,6 +160,23 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } + 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.exceptions.TyperException] should be thrownBy deserTest() + } else { + deserTest() + } + } + property("serialize - collection of boxes") { def deserTest() = test("serialize", env, ext, s"""{ From bf53a6b67e22101bb13e8867c43ab6a4ad327302 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 6 Jun 2024 18:20:33 +0300 Subject: [PATCH 065/123] spam tests, test for serialize(long) producing different result from longToByteArray() --- .../utxo/BasicOpsSpecification.scala | 67 ++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 13bf74b5f6..52756b640f 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -20,7 +20,7 @@ import sigmastate.interpreter.CErgoTreeEvaluator.DefaultEvalSettings import sigmastate.interpreter.Interpreter._ import sigma.ast.Apply import sigma.eval.EvalSettings -import sigma.exceptions.InvalidType +import sigma.exceptions.{CostLimitException, InvalidType} import sigmastate.utils.Helpers import sigmastate.utils.Helpers._ @@ -211,6 +211,25 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + 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.exceptions.TyperException] 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") @@ -279,6 +298,52 @@ class BasicOpsSpecification extends CompilerTestingCommons // 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[Exception] 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[Exception] should be thrownBy deserTest() + } else { + // we have wrapped CostLimitException here + an[Exception] should be thrownBy deserTest() + } + } + property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", From dd7bdc63024bfa4e16eb4723c7739c9e0187fb2a Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 7 Jun 2024 13:21:45 +0300 Subject: [PATCH 066/123] removing serialize --- .../src/main/scala/sigma/SigmaDsl.scala | 3 - .../sigma/reflection/ReflectionData.scala | 4 - .../validation/ValidationRules.scala | 17 +-- .../scala/sigma/SigmaDataReflection.scala | 5 - .../src/main/scala/sigma/ast/ErgoTree.scala | 5 - .../main/scala/sigma/ast/SigmaPredef.scala | 18 --- .../src/main/scala/sigma/ast/methods.scala | 37 +---- .../scala/sigma/data/CSigmaDslBuilder.scala | 8 -- .../serialization/ErgoTreeSerializer.scala | 48 ++----- docs/LangSpec.md | 7 +- .../sigmastate/lang/SigmaParserTest.scala | 14 +- .../sigmastate/ReflectionGenerator.scala | 11 ++ .../sigma/compiler/ir/GraphIRReflection.scala | 3 - .../ir/wrappers/sigma/SigmaDslUnit.scala | 1 - .../ir/wrappers/sigma/impl/SigmaDslImpl.scala | 15 -- .../sigma/compiler/phases/SigmaBinder.scala | 3 - .../scala/sigma/LanguageSpecificationV6.scala | 130 ------------------ .../sigmastate/lang/SigmaBinderTest.scala | 11 -- .../sigmastate/lang/SigmaTyperTest.scala | 31 ----- 19 files changed, 30 insertions(+), 341 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 6e306f7a0b..df2b419273 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -727,9 +727,6 @@ 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] } diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index 5cd678b712..028e68bf72 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -441,10 +441,6 @@ 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]]) } diff --git a/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala b/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala index 07fe8db0ee..9d4de47a99 100644 --- a/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala +++ b/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala @@ -155,20 +155,6 @@ object ValidationRules { override protected lazy val settings: SigmaValidationSettings = currentSettings } - object CheckMinimalErgoTreeVersion extends ValidationRule(1016, - "ErgoTree should have at least required version") with SoftForkWhenReplaced { - override protected lazy val settings: SigmaValidationSettings = currentSettings - - final def apply(currentVersion: Byte, minVersion: Byte): Unit = { - checkRule() - if (currentVersion < minVersion) { - throwValidationException( - new SigmaException(s"ErgoTree should have at least $minVersion version, but was $currentVersion"), - Array(currentVersion, minVersion)) - } - } - } - val ruleSpecs: Seq[ValidationRule] = Seq( CheckDeserializedScriptType, CheckDeserializedScriptIsSigmaProp, @@ -185,8 +171,7 @@ object ValidationRules { CheckHeaderSizeBit, CheckCostFuncOperation, CheckPositionLimit, - CheckLoopLevelInCostFunction, - CheckMinimalErgoTreeVersion + CheckLoopLevelInCostFunction ) /** Validation settings that correspond to the current version of the ErgoScript implementation. diff --git a/data/shared/src/main/scala/sigma/SigmaDataReflection.scala b/data/shared/src/main/scala/sigma/SigmaDataReflection.scala index a6e5de2a26..48939b1460 100644 --- a/data/shared/src/main/scala/sigma/SigmaDataReflection.scala +++ b/data/shared/src/main/scala/sigma/SigmaDataReflection.scala @@ -322,11 +322,6 @@ 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 eae420612e..68d69abd91 100644 --- a/data/shared/src/main/scala/sigma/ast/ErgoTree.scala +++ b/data/shared/src/main/scala/sigma/ast/ErgoTree.scala @@ -228,11 +228,6 @@ object ErgoTree { type HeaderType = HeaderType.Type - implicit class HeaderTypeOps(val header: HeaderType) extends AnyVal { - def withVersion(version: Byte): HeaderType = ErgoTree.headerWithVersion(header, version) - def withConstantSegregation: HeaderType = ErgoTree.setConstantSegregation(header) - } - /** Current version of ErgoTree serialization format (aka bite-code language version) */ val VersionFlag: Byte = VersionContext.MaxSupportedScriptVersion diff --git a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala index f2da24d2df..897ac6d757 100644 --- a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala +++ b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala @@ -403,24 +403,6 @@ object SigmaPredef { ArgInfo("default", "optional default value, if register is not available"))) ) - val SerializeFunc = PredefinedFunc("serialize", - Lambda(Seq(paramT), Array("value" -> tT), SByteArray, None), - PredefFuncInfo( - { case (_, args @ Seq(value)) => - MethodCall.typed[Value[SCollection[SByte.type]]]( - Global, - SGlobalMethods.serializeMethod.withConcreteTypes(Map(tT -> value.tpe)), - args.toIndexedSeq, - Map() - ) - }), - OperationInfo(MethodCall, - """ - """.stripMargin, - Seq(ArgInfo("value", "")) - ) - ) - val globalFuncs: Map[String, PredefinedFunc] = Seq( AllOfFunc, AnyOfFunc, diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 1a0841e97c..136225f256 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -1,7 +1,6 @@ package sigma.ast import org.ergoplatform._ -import org.ergoplatform.validation.ValidationRules.CheckMinimalErgoTreeVersion import org.ergoplatform.validation._ import sigma._ import sigma.ast.SCollection.{SBooleanArray, SBoxArray, SByteArray, SByteArray2, SHeaderArray} @@ -1543,37 +1542,9 @@ case object SGlobalMethods extends MonoTypeMethods { Xor.xorWithCosting(ls, rs) } - lazy val serializeMethod = SMethod(this, "serialize", - SFunc(Array(SGlobal, tT), SByteArray, Array(paramT)), 3, DynamicCost) - .withIRInfo(MethodCallIrBuilder) - .withInfo(MethodCall, "", - 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] = { - // TODO v6.0: accumulate cost - val t = Evaluation.stypeToRType(mc.args(0).tpe) - G.serialize(value)(t) - } - - protected override def getMethods() = super.getMethods() ++ { - if (VersionContext.current.isV6SoftForkActivated) { - Seq( - groupGeneratorMethod, - xorMethod, - serializeMethod - ) - } else { - Seq( - groupGeneratorMethod, - xorMethod - ) - } - } + protected override def getMethods() = super.getMethods() ++ Seq( + groupGeneratorMethod, + xorMethod + ) } diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 21b9900028..d7b092fc0e 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -200,14 +200,6 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => val p = GroupElementSerializer.parse(r) this.GroupElement(p) } - - /** 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/serialization/ErgoTreeSerializer.scala b/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala index e7bb46429a..43e41f91ff 100644 --- a/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala +++ b/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala @@ -287,9 +287,6 @@ 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 @@ -307,23 +304,21 @@ class ErgoTreeSerializer { 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 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() + val w = SigmaSerializer.startWriter() + w.put(header) + 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)) { - constW.putUInt(constants.length) + w.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 => @@ -331,38 +326,17 @@ class ErgoTreeSerializer { val iPos = backrefs(i) // index to `positions` if (iPos == -1) { // no position => no substitution, serialize original constant - constantSerializer.serialize(c, constW) + constantSerializer.serialize(c, w) } else { - require(positions(iPos) == i) // INV: backrefs and positions are mutually inverse + assert(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, constW) + constantSerializer.serialize(newConst, w) } } } - - 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) @@ -383,12 +357,10 @@ class ErgoTreeSerializer { case (c, _) => constantSerializer.serialize(c, w) } - - w.putBytes(treeBytes) - w.toBytes } - (resBytes, nConstants) + w.putBytes(treeBytes) + (w.toBytes, constants.length) } } diff --git a/docs/LangSpec.md b/docs/LangSpec.md index 04b345d6d9..ba66748f08 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: `serialize`, `blake2b256`, `byteArrayToBigInt`, `proveDlog` etc. +- predefined primitives: `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)` @@ -1041,11 +1041,6 @@ def deserialize[T](string: String): T * replaced and all other bytes remain exactly the same */ def substConstants[T](scriptBytes: Coll[Byte], positions: Coll[Int], newValues: Coll[T]): Coll[Byte] - -/** Serializes an instance of type T using default serialization format. - * See https://github.com/ScorexFoundation/sigmastate-interpreter/issues/988 for more details - */ -def serialize[T](value: T): Coll[Byte] ``` ## Examples diff --git a/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala b/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala index 70aa540a4f..dc63330f95 100644 --- a/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala +++ b/parsers/shared/src/test/scala/sigmastate/lang/SigmaParserTest.scala @@ -35,6 +35,9 @@ 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) { @@ -903,17 +906,6 @@ 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/jvm/src/test/scala/sigmastate/ReflectionGenerator.scala b/sc/jvm/src/test/scala/sigmastate/ReflectionGenerator.scala index 324542505e..dd5262e700 100644 --- a/sc/jvm/src/test/scala/sigmastate/ReflectionGenerator.scala +++ b/sc/jvm/src/test/scala/sigmastate/ReflectionGenerator.scala @@ -5,6 +5,17 @@ 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 = { diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphIRReflection.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphIRReflection.scala index 6c0403f643..69736a0224 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphIRReflection.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphIRReflection.scala @@ -504,9 +504,6 @@ 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]]) } ) ) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala index d7e574c68c..2a6a341686 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala @@ -114,7 +114,6 @@ import scalan._ /** 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]] }; trait CostModelCompanion; trait BigIntCompanion; diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala index 9cd524149d..c113cb7de3 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala @@ -1945,14 +1945,6 @@ 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, true, element[Coll[Byte]])) - } - } implicit object LiftableSigmaDslBuilder @@ -2112,13 +2104,6 @@ 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]])) - } } // entityUnref: single unref method for each type family diff --git a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala index d4943ef892..af5be938be 100644 --- a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala +++ b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala @@ -105,9 +105,6 @@ 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/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index d89fc1f623..6eb3dc4c11 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -29,51 +29,6 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => Seq(0, 1, 2, 3).map(version => version -> res) } - 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.sinceV6AndTreeVersion(0)) - } - - property("Global.serialize[Byte]") { - lazy val serializeByte = mkSerializeFeature[Byte] - val cases = Seq( - (-128.toByte, Success(Coll(-128.toByte))), - (-1.toByte, Success(Coll(-1.toByte))), - (0.toByte, Success(Coll(0.toByte))), - (1.toByte, Success(Coll(1.toByte))), - (127.toByte, Success(Coll(127.toByte))) - ) - testCases(cases, serializeByte) - } - - property("Global.serialize[Short]") { - lazy val serializeShort = mkSerializeFeature[Short] - val cases = Seq( - (Short.MinValue, Success(Coll[Byte](0xFF.toByte, 0xFF.toByte, 0x03.toByte))), - (-1.toShort, Success(Coll(1.toByte))), - (0.toShort, Success(Coll(0.toByte))), - (1.toShort, Success(Coll(2.toByte))), - (Short.MaxValue, Success(Coll(-2.toByte, -1.toByte, 3.toByte))) - ) - testCases(cases, serializeShort) - } - - // 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 = VersionContext.sinceV6AndTreeVersion(0) @@ -390,91 +345,6 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => } } - property("Fix substConstants in v6.0 for ErgoTree version > 0") { - // tree with one segregated constant and v0 - val t1 = ErgoTree( - header = ZeroHeader.withConstantSegregation, - constants = Vector(TrueSigmaProp), - ConstantPlaceholder(0, SSigmaProp)) - - // tree with one segregated constant and max supported version - val t2 = ErgoTree( - header = ZeroHeader - .withVersion(VersionContext.MaxSupportedScriptVersion) - .withConstantSegregation, - 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 = 1793, - newVersionedResults = expectedSuccessForAllTreeVersions(Helpers.decodeBytes("100108d27300"), 1793, 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 = 1793, - newVersionedResults = expectedSuccessForAllTreeVersions(expectedTreeBytes_V6, 1793, costDetails(1))) - } - ), - changedFeature( - changedInVersion = VersionContext.sinceV6AndTreeVersion(0), - { (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("Numeric.toBytes methods equivalence") { lazy val toBytes = newFeature( { (x: Byte) => x.toBigEndianBytes }, diff --git a/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala b/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala index 54bd89c9c2..1f15f5d747 100644 --- a/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala +++ b/sc/shared/src/test/scala/sigmastate/lang/SigmaBinderTest.scala @@ -213,15 +213,4 @@ 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/SigmaTyperTest.scala b/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala index 102033ead9..ba6eb55ee6 100644 --- a/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala +++ b/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala @@ -713,35 +713,4 @@ 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 - } - } - } From e1bfb1c07999f81a9b9308695f0cd24feec43f12 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 7 Jun 2024 15:21:08 +0300 Subject: [PATCH 067/123] remove serialize from GraphBuilding and ErgoTreeSpecification --- data/shared/src/main/scala/sigma/ast/SigmaPredef.scala | 3 +-- .../src/main/scala/sigma/compiler/ir/GraphBuilding.scala | 3 --- .../src/test/scala/sigmastate/ErgoTreeSpecification.scala | 5 +---- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala index 897ac6d757..ebe8aa0213 100644 --- a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala +++ b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala @@ -430,8 +430,7 @@ object SigmaPredef { AvlTreeFunc, SubstConstantsFunc, ExecuteFromVarFunc, - ExecuteFromSelfRegFunc, - SerializeFunc + ExecuteFromSelfRegFunc ).map(f => f.name -> f).toMap def comparisonOp(symbolName: String, opDesc: ValueCompanion, desc: String, args: Seq[ArgInfo]) = { diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index ddbec96518..5595ded3db 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1147,9 +1147,6 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => val c1 = asRep[Coll[Byte]](argsV(0)) val c2 = asRep[Coll[Byte]](argsV(1)) g.xor(c1, c2) - case SGlobalMethods.serializeMethod.name => - val value = asRep[Any](argsV(0)) - g.serialize(value) case _ => throwError() } case (x: Ref[tNum], _: SNumericTypeMethods) => method.name match { diff --git a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala index 6e6fb824de..05a6017e98 100644 --- a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala @@ -479,10 +479,7 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with C { import SGlobalMethods._ (SGlobal.typeId, Seq( MInfo(1, groupGeneratorMethod), MInfo(2, xorMethod) - ) ++ (if (isV6Activated) Seq( - // methods added in v6.0 - MInfo(3, serializeMethod) - ) else Seq.empty), true) + ), true) }, { import SCollectionMethods._ (SCollection.typeId, Seq( From 15e21a4af57a45ae9a9136ad14278ac7951611ab Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 7 Jun 2024 16:00:54 +0300 Subject: [PATCH 068/123] importing new test for ErgoTreeSpecification from i486 --- .../scala/sigmastate/ErgoTreeSpecification.scala | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala index 7539bd5e48..21966aa0a9 100644 --- a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala @@ -21,14 +21,14 @@ import sigma.compiler.CompilerSettings import sigma.eval.EvalSettings import sigma.exceptions.{CostLimitException, InterpreterException} 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,10 +313,12 @@ 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( + def methods = Table( ("typeId", "methods", "CanHaveMethods"), (SBoolean.typeId, Seq.empty[MInfo], true), (SByte.typeId, Seq.empty[MInfo], false), @@ -419,7 +421,10 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit { { import SGlobalMethods._ (SGlobal.typeId, Seq( MInfo(1, groupGeneratorMethod), MInfo(2, xorMethod) - ), true) + ) ++ (if (isV6Activated) Seq( + // methods added in v6.0 + MInfo(3, serializeMethod) + ) else Seq.empty), true) }, { import SCollectionMethods._ (SCollection.typeId, Seq( From 15f4f67ba83489dff1d2ea7df232b5bea15c01a4 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 7 Jun 2024 21:50:00 +0300 Subject: [PATCH 069/123] removing modq methods --- .../src/main/scala/sigma/ast/methods.scala | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 4656d3361e..fc2e5f11d0 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -318,32 +318,9 @@ case object SBigIntMethods extends SNumericTypeMethods { val ToNBits = SMethod(this, "nbits", SFunc(this.ownerType, SLong), 8, ToNBitsCostInfo.costKind) .withInfo(ModQ, "Encode this big integer value as NBits") - /** - * todo: remove - * - * 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() ++ Seq(ToNBits) - // ModQMethod, - // PlusModQMethod, - // MinusModQMethod, - // TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479 - // MultModQMethod, } else { super.getMethods() } From 303f96986e56ac0f0c5863e328eb9d4771fb989f Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sat, 8 Jun 2024 21:31:27 +0300 Subject: [PATCH 070/123] expUnsigned impl (test still failing) --- .../src/main/scala/sigma/SigmaDsl.scala | 2 ++ .../main/scala/sigma/data/CGroupElement.scala | 5 +++- .../sigma/reflection/ReflectionData.scala | 3 ++ .../src/main/scala/sigma/ast/methods.scala | 28 +++++++++++++++---- .../sigma/compiler/ir/GraphBuilding.scala | 3 ++ .../ir/wrappers/sigma/SigmaDslUnit.scala | 1 + .../ir/wrappers/sigma/impl/SigmaDslImpl.scala | 14 ++++++++++ .../sigma/compiler/phases/SigmaBinder.scala | 4 +++ .../sigma/compiler/phases/SigmaTyper.scala | 5 ++++ 9 files changed, 58 insertions(+), 7 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index cc102b6b36..723ce03bc6 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -298,6 +298,8 @@ trait GroupElement { */ def exp(k: BigInt): GroupElement + def expUnsigned(k: UnsignedBigInt): GroupElement + /** Group operation. */ def multiply(that: GroupElement): GroupElement diff --git a/core/shared/src/main/scala/sigma/data/CGroupElement.scala b/core/shared/src/main/scala/sigma/data/CGroupElement.scala index ed4849f0d7..c5483797cf 100644 --- a/core/shared/src/main/scala/sigma/data/CGroupElement.scala +++ b/core/shared/src/main/scala/sigma/data/CGroupElement.scala @@ -3,7 +3,7 @@ package sigma.data import sigma.crypto.{CryptoFacade, Ecp} import sigma.serialization.GroupElementSerializer import sigma.util.Extensions.EcpOps -import sigma.{BigInt, Coll, Colls, GroupElement} +import sigma.{BigInt, Coll, Colls, GroupElement, UnsignedBigInt} /** A default implementation of [[GroupElement]] interface. * @@ -21,6 +21,9 @@ case class CGroupElement(override val wrappedValue: Ecp) extends GroupElement wi override def exp(k: BigInt): GroupElement = CGroupElement(CryptoFacade.exponentiatePoint(wrappedValue, k.asInstanceOf[CBigInt].wrappedValue)) + override def expUnsigned(k: UnsignedBigInt): GroupElement = + CGroupElement(CryptoFacade.exponentiatePoint(wrappedValue, k.asInstanceOf[CUnsignedBigInt].wrappedValue)) + override def multiply(that: GroupElement): GroupElement = CGroupElement(CryptoFacade.multiplyPoints(wrappedValue, that.asInstanceOf[CGroupElement].wrappedValue)) diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index 028e68bf72..e0e890abca 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -286,6 +286,9 @@ object ReflectionData { mkMethod(clazz, "exp", Array[Class[_]](classOf[BigInt])) { (obj, args) => obj.asInstanceOf[GroupElement].exp(args(0).asInstanceOf[BigInt]) }, + mkMethod(clazz, "expUnsigned", Array[Class[_]](classOf[UnsignedBigInt])) { (obj, args) => + obj.asInstanceOf[GroupElement].expUnsigned(args(0).asInstanceOf[UnsignedBigInt]) + }, mkMethod(clazz, "multiply", Array[Class[_]](classOf[GroupElement])) { (obj, args) => obj.asInstanceOf[GroupElement].multiply(args(0).asInstanceOf[GroupElement]) }, diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index fc2e5f11d0..8499ecd46e 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -364,6 +364,11 @@ case object SGroupElementMethods extends MonoTypeMethods { "Exponentiate this \\lst{GroupElement} to the given number. Returns this to the power of k", ArgInfo("k", "The power")) + lazy val ExponentiateUnsignedMethod: SMethod = SMethod( + this, "expUnsigned", SFunc(Array(this.ownerType, SUnsignedBigInt), this.ownerType), 6, Exponentiate.costKind) // todo: recheck costing + .withInfo("Exponentiate this \\lst{GroupElement} to the given number. Returns this to the power of k", + ArgInfo("k", "The power")) + lazy val MultiplyMethod: SMethod = SMethod( this, "multiply", SFunc(Array(this.ownerType, SGroupElement), this.ownerType), 4, MultiplyGroup.costKind) .withIRInfo({ case (builder, obj, _, Seq(arg), _) => @@ -379,16 +384,27 @@ case object SGroupElementMethods extends MonoTypeMethods { .withIRInfo(MethodCallIrBuilder) .withInfo(PropertyCall, "Inverse element of the group.") - protected override def getMethods(): Seq[SMethod] = super.getMethods() ++ Seq( + protected override def getMethods(): Seq[SMethod] = { /* TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479 SMethod(this, "isIdentity", SFunc(this, SBoolean), 1) .withInfo(PropertyCall, "Checks if this value is identity element of the eliptic curve group."), */ - GetEncodedMethod, - ExponentiateMethod, - MultiplyMethod, - NegateMethod - ) + val v5Methods = Seq( + GetEncodedMethod, + ExponentiateMethod, + MultiplyMethod, + NegateMethod) + + super.getMethods() ++ (if (VersionContext.current.isV6SoftForkActivated) { + v5Methods + } else { + v5Methods ++ Seq(ExponentiateUnsignedMethod) + }) + } + + def expUnsigned_eval(mc: MethodCall, power: UnsignedBigInt)(implicit E: ErgoTreeEvaluator): GroupElement = { + ??? + } } /** Methods of type `SigmaProp` which represent sigma-protocol propositions. */ diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index 3e3b576c3e..e2350b8338 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1024,6 +1024,9 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => case SGroupElementMethods.ExponentiateMethod.name => val k = asRep[BigInt](argsV(0)) ge.exp(k) + case SGroupElementMethods.ExponentiateUnsignedMethod.name => + val k = asRep[UnsignedBigInt](argsV(0)) + ge.expUnsigned(k) case _ => throwError } case (box: Ref[Box]@unchecked, SBoxMethods) => method.name match { diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala index 8616822dd1..b3be395a74 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala @@ -25,6 +25,7 @@ import scalan._ }; trait GroupElement extends Def[GroupElement] { def exp(k: Ref[BigInt]): Ref[GroupElement]; + def expUnsigned(k: Ref[UnsignedBigInt]): Ref[GroupElement]; def multiply(that: Ref[GroupElement]): Ref[GroupElement]; def negate: Ref[GroupElement]; def getEncoded: Ref[Coll[Byte]] diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala index 060759099e..27ebaa717c 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala @@ -444,6 +444,13 @@ object GroupElement extends EntityObject("GroupElement") { true, false, element[GroupElement])) } + override def expUnsigned(k: Ref[UnsignedBigInt]): Ref[GroupElement] = { + asRep[GroupElement](mkMethodCall(self, + GroupElementClass.getMethod("expUnsigned", classOf[Sym]), + Array[AnyRef](k), + true, false, element[GroupElement])) + } + override def multiply(that: Ref[GroupElement]): Ref[GroupElement] = { asRep[GroupElement](mkMethodCall(self, GroupElementClass.getMethod("multiply", classOf[Sym]), @@ -491,6 +498,13 @@ object GroupElement extends EntityObject("GroupElement") { true, true, element[GroupElement])) } + def expUnsigned(k: Ref[UnsignedBigInt]): Ref[GroupElement] = { + asRep[GroupElement](mkMethodCall(source, + GroupElementClass.getMethod("expUnsigned", classOf[Sym]), + Array[AnyRef](k), + true, true, element[GroupElement])) + } + def multiply(that: Ref[GroupElement]): Ref[GroupElement] = { asRep[GroupElement](mkMethodCall(source, GroupElementClass.getMethod("multiply", classOf[Sym]), diff --git a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala index af5be938be..1877131718 100644 --- a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala +++ b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala @@ -56,6 +56,10 @@ class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder, case _ @ Apply(ApplyTypes(Ident("Coll", _), Seq(tpe)), args) => Some(mkConcreteCollection(args, tpe)) + // hack to make possible to write g.exp(ubi) for both unsigned and signed big integers + case Apply(Select(obj, n, resType), args) if n == "exp" && args(0).isInstanceOf[Value[SUnsignedBigInt.type]] => + Some(Apply(Select(obj, "expUnsigned", resType), args)) + // Rule: Coll(...) --> case Apply(Ident("Coll", _), args) => val tpe = if (args.isEmpty) NoType else args(0).tpe diff --git a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala index 679d98a18f..3d62ff8dd8 100644 --- a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala +++ b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala @@ -168,6 +168,11 @@ class SigmaTyper(val builder: SigmaBuilder, case app @ Apply(sel @ Select(obj, n, _), args) => val newSel = assignType(env, sel) val newArgs = args.map(assignType(env, _)) + if(n=="expUnsigned") { + println(app) + println("newSel: " + newSel) + println("newArgs: " + newArgs) + } newSel.tpe match { case genFunTpe @ SFunc(argTypes, _, _) => // If it's a function then the application has type of that function's return type. From 982f32f4920f176c6f6d3310e1dfc843791d1503 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sun, 9 Jun 2024 15:48:00 +0300 Subject: [PATCH 071/123] schnorr sig example passed --- .../src/main/scala/sigma/ast/SType.scala | 4 ++-- .../src/main/scala/sigma/ast/methods.scala | 5 +++-- .../src/main/scala/sigmastate/lang/Types.scala | 1 + .../sigma/compiler/phases/SigmaBinder.scala | 4 ---- .../sigma/compiler/phases/SigmaTyper.scala | 18 ++++++++++++------ .../utxo/BasicOpsSpecification.scala | 2 +- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index 4be9087ca7..411ab1e8c7 100644 --- a/core/shared/src/main/scala/sigma/ast/SType.scala +++ b/core/shared/src/main/scala/sigma/ast/SType.scala @@ -105,7 +105,7 @@ object SType { /** All pre-defined types should be listed here. Note, NoType is not listed. * Should be in sync with sigmastate.lang.Types.predefTypes. */ val allPredefTypes: Seq[SType] = Array[SType]( - SBoolean, SByte, SShort, SInt, SLong, SBigInt, SContext, + SBoolean, SByte, SShort, SInt, SLong, SBigInt, SUnsignedBigInt, SContext, SGlobal, SHeader, SPreHeader, SAvlTree, SGroupElement, SSigmaProp, SString, SBox, SUnit, SAny) @@ -220,7 +220,7 @@ trait STypeCompanion { /** Special type to represent untyped values. * Interpreter raises an error when encounter a Value with this type. - * All Value nodes with this type should be elimitanted during typing. + * All Value nodes with this type should be eliminated during typing. * If no specific type can be assigned statically during typing, * then either error should be raised or type SAny should be assigned * which is interpreted as dynamic typing. */ diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 8499ecd46e..179e21485c 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -366,6 +366,7 @@ case object SGroupElementMethods extends MonoTypeMethods { lazy val ExponentiateUnsignedMethod: SMethod = SMethod( this, "expUnsigned", SFunc(Array(this.ownerType, SUnsignedBigInt), this.ownerType), 6, Exponentiate.costKind) // todo: recheck costing + .withIRInfo(MethodCallIrBuilder) .withInfo("Exponentiate this \\lst{GroupElement} to the given number. Returns this to the power of k", ArgInfo("k", "The power")) @@ -396,9 +397,9 @@ case object SGroupElementMethods extends MonoTypeMethods { NegateMethod) super.getMethods() ++ (if (VersionContext.current.isV6SoftForkActivated) { - v5Methods - } else { v5Methods ++ Seq(ExponentiateUnsignedMethod) + } else { + v5Methods }) } diff --git a/parsers/shared/src/main/scala/sigmastate/lang/Types.scala b/parsers/shared/src/main/scala/sigmastate/lang/Types.scala index 06683f6e96..d928e36f61 100644 --- a/parsers/shared/src/main/scala/sigmastate/lang/Types.scala +++ b/parsers/shared/src/main/scala/sigmastate/lang/Types.scala @@ -34,6 +34,7 @@ trait Types extends Core { "Int" -> SInt, "Long" -> SLong, "BigInt" -> SBigInt, + "UnsignedBigInt" -> SUnsignedBigInt, "AvlTree" -> SAvlTree, "Context" -> SContext, "GroupElement" -> SGroupElement, diff --git a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala index 1877131718..af5be938be 100644 --- a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala +++ b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaBinder.scala @@ -56,10 +56,6 @@ class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder, case _ @ Apply(ApplyTypes(Ident("Coll", _), Seq(tpe)), args) => Some(mkConcreteCollection(args, tpe)) - // hack to make possible to write g.exp(ubi) for both unsigned and signed big integers - case Apply(Select(obj, n, resType), args) if n == "exp" && args(0).isInstanceOf[Value[SUnsignedBigInt.type]] => - Some(Apply(Select(obj, "expUnsigned", resType), args)) - // Rule: Coll(...) --> case Apply(Ident("Coll", _), args) => val tpe = if (args.isEmpty) NoType else args(0).tpe diff --git a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala index 3d62ff8dd8..bad5c92d61 100644 --- a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala +++ b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala @@ -165,14 +165,20 @@ class SigmaTyper(val builder: SigmaBuilder, error(s"Cannot get field '$n' in in the object $obj of non-product type ${obj.tpe}", sel.sourceContext) } - case app @ Apply(sel @ Select(obj, n, _), args) => - val newSel = assignType(env, sel) + case app @ Apply(selOriginal @ Select(obj, nOriginal, resType), args) => val newArgs = args.map(assignType(env, _)) - if(n=="expUnsigned") { - println(app) - println("newSel: " + newSel) - println("newArgs: " + newArgs) + + // hack to make possible to write g.exp(ubi) for both unsigned and signed big integers + // could be useful for other use cases where the same front-end code could be + // translated to different methods under the hood, based on argument types + // todo: consider better place for it + val (n, sel) = if (nOriginal == "exp" && newArgs(0).tpe.isInstanceOf[SUnsignedBigInt.type]) { + val newName = "expUnsigned" + (newName, Select(obj, newName, resType)) + } else { + (nOriginal, selOriginal) } + val newSel = assignType(env, sel) newSel.tpe match { case genFunTpe @ SFunc(argTypes, _, _) => // If it's a function then the application has type of that function's return type. diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index e6f08f75fc..9a829f6829 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -251,7 +251,7 @@ class BasicOpsSpecification extends CompilerTestingCommons )} if (activatedVersionInTests < V6SoftForkVersion) { - deserTest() + an[Exception] should be thrownBy deserTest() } else { deserTest() } From eb47d172e83958225b44f8c0cdb4228e55fd0873 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sun, 9 Jun 2024 20:42:32 +0300 Subject: [PATCH 072/123] eq test, DataValueComparer --- .../scala/sigma/data/DataValueComparer.scala | 6 ++++ .../utxo/BasicOpsSpecification.scala | 31 +++++++------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/DataValueComparer.scala b/data/shared/src/main/scala/sigma/data/DataValueComparer.scala index 21ca85012f..39022a2e7e 100644 --- a/data/shared/src/main/scala/sigma/data/DataValueComparer.scala +++ b/data/shared/src/main/scala/sigma/data/DataValueComparer.scala @@ -344,6 +344,12 @@ object DataValueComparer { okEqual = bi == r } + // todo: check costing + case ubi: UnsignedBigInt => /** case 5 (see [[EQ_BigInt]]) */ + E.addFixedCost(EQ_BigInt) { + okEqual = ubi == r + } + case sp1: SigmaProp => E.addCost(MatchType) // for second match below okEqual = r match { diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 9a829f6829..c3e732cd2b 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -140,28 +140,21 @@ class BasicOpsSpecification extends CompilerTestingCommons flexVerifier.verify(verifyEnv, tree, ctxExt, pr.proof, fakeMessage).get._1 shouldBe true } - property("group order serialization") { - val value = SecP256K1Group.q.divide(new BigInteger("2")) - def deserTest() = {test("big int - q", env, ext, - s"{ val b = bigInt(\"${value.toString}\"); b > 1 }", - null, - true - )} + property("group order deserialization") { + val b = SecP256K1Group.q - if (activatedVersionInTests < V6SoftForkVersion) { - deserTest() - } else { - deserTest() - } - } - - property("restoring unsigned 256 bits") { - val b = new BigInteger("92805629300808893548929804498612226467505866636839045998233220279839291898608") - val ub = new BigInteger(1, b.toByteArray) + val customExt: Seq[(Byte, EvaluatedValue[_ <: SType])] = Map( + 0.toByte -> UnsignedBigIntConstant(b) + ).toSeq - def deserTest() = {test("restoring", env, ext, - s"{ val b = unsignedBigInt(\"${ub.toString}\"); b > 1 }", + def deserTest() = {test("restoring", env, customExt, + s"""{ + | val b1 = unsignedBigInt(\"${b.toString}\") + | val b2 = getVar[UnsignedBigInt](0).get + | b1 == b2 + |} + | """.stripMargin, null, true )} From 33033fc3b9d02934dde612a3efd6bfb2fa63bf48 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 10 Jun 2024 13:48:55 +0300 Subject: [PATCH 073/123] importing CheckMinimalErgoTreeVersion from i994 --- .../validation/ValidationRules.scala | 17 ++++++++++++++++- .../src/main/scala/sigma/ast/methods.scala | 2 ++ .../sigmastate/utxo/BasicOpsSpecification.scala | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala b/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala index 9d4de47a99..07fe8db0ee 100644 --- a/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala +++ b/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala @@ -155,6 +155,20 @@ object ValidationRules { override protected lazy val settings: SigmaValidationSettings = currentSettings } + object CheckMinimalErgoTreeVersion extends ValidationRule(1016, + "ErgoTree should have at least required version") with SoftForkWhenReplaced { + override protected lazy val settings: SigmaValidationSettings = currentSettings + + final def apply(currentVersion: Byte, minVersion: Byte): Unit = { + checkRule() + if (currentVersion < minVersion) { + throwValidationException( + new SigmaException(s"ErgoTree should have at least $minVersion version, but was $currentVersion"), + Array(currentVersion, minVersion)) + } + } + } + val ruleSpecs: Seq[ValidationRule] = Seq( CheckDeserializedScriptType, CheckDeserializedScriptIsSigmaProp, @@ -171,7 +185,8 @@ object ValidationRules { CheckHeaderSizeBit, CheckCostFuncOperation, CheckPositionLimit, - CheckLoopLevelInCostFunction + CheckLoopLevelInCostFunction, + CheckMinimalErgoTreeVersion ) /** Validation settings that correspond to the current version of the ErgoScript implementation. diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index ef548d6185..2cfecea15d 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -1,6 +1,7 @@ package sigma.ast import org.ergoplatform._ +import org.ergoplatform.validation.ValidationRules.CheckMinimalErgoTreeVersion import org.ergoplatform.validation._ import sigma._ import sigma.ast.SCollection.{SBooleanArray, SBoxArray, SByteArray, SByteArray2, SHeaderArray} @@ -1533,6 +1534,7 @@ case object SGlobalMethods extends MonoTypeMethods { */ def serialize_eval(mc: MethodCall, G: SigmaDslBuilder, value: SType#WrappedType) (implicit E: ErgoTreeEvaluator): Coll[Byte] = { + CheckMinimalErgoTreeVersion(E.context.currentErgoTreeVersion, VersionContext.V6SoftForkVersion) E.addCost(SigmaByteWriter.StartWriterCost) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 52756b640f..76d3d84ced 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -20,7 +20,7 @@ import sigmastate.interpreter.CErgoTreeEvaluator.DefaultEvalSettings import sigmastate.interpreter.Interpreter._ import sigma.ast.Apply import sigma.eval.EvalSettings -import sigma.exceptions.{CostLimitException, InvalidType} +import sigma.exceptions.InvalidType import sigmastate.utils.Helpers import sigmastate.utils.Helpers._ From dd62bd7475f3a4f4d1399bdca8e9dd2361e36255 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 11 Jun 2024 17:15:07 +0300 Subject: [PATCH 074/123] failing tests --- .../utxo/BasicOpsSpecification.scala | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 79701d6e07..87a3697462 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -3,6 +3,7 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ import sigma.Extensions.ArrayOps +import sigma.VersionContext import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder} @@ -157,6 +158,47 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } + 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 { + an[Exception] shouldBe thrownBy(optTest()) + } + } + + property("Lazy evaluation of default in Coll.getOrElse") { + val customExt = Map ( + 1.toByte -> IntConstant(5) + ).toSeq + def optTest() = test("getOrElse", env, customExt, + """{ + | val c = Coll[Int](1) + | c.getOrElse(0, getVar[Int](44).get) > 0 + |} + | + |""".stripMargin, + null + ) + + if(VersionContext.current.isV6SoftForkActivated) { + optTest() + } else { + an[Exception] shouldBe thrownBy(optTest()) + } + } + property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", From aaef77e76f8b4be4c97520a56cc6b1492bb70791 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 11 Jun 2024 17:46:20 +0300 Subject: [PATCH 075/123] close #906: lazy evaluation of default in Option.getOrElse and Coll.getOrElse --- .../main/scala/sigma/ast/transformers.scala | 43 ++++++++++++++----- .../utxo/BasicOpsSpecification.scala | 10 ++--- 2 files changed, 36 insertions(+), 17 deletions(-) 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/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 87a3697462..c1489355e6 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -166,7 +166,6 @@ class BasicOpsSpecification extends CompilerTestingCommons """{ | getVar[Int](1).getOrElse(getVar[Int](44).get) > 0 |} - | |""".stripMargin, null ) @@ -179,15 +178,12 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("Lazy evaluation of default in Coll.getOrElse") { - val customExt = Map ( - 1.toByte -> IntConstant(5) - ).toSeq - def optTest() = test("getOrElse", env, customExt, + def optTest() = test("getOrElse", env, ext, """{ | val c = Coll[Int](1) - | c.getOrElse(0, getVar[Int](44).get) > 0 + | c.getOrElse(0, getVar[Int](44).get) > 0 && + | c.getOrElse(1, c.getOrElse(0, getVar[Int](44).get)) > 0 |} - | |""".stripMargin, null ) From ea468c9629d84d7260730208018257b76f0ccb35 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 11 Jun 2024 21:03:20 +0300 Subject: [PATCH 076/123] initial stubs along first todos for bulletproofs contracts --- .../utxo/BasicOpsSpecification.scala | 170 +++++++++++++++--- 1 file changed, 143 insertions(+), 27 deletions(-) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index c3e732cd2b..64fa69bf24 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -148,7 +148,7 @@ class BasicOpsSpecification extends CompilerTestingCommons 0.toByte -> UnsignedBigIntConstant(b) ).toSeq - def deserTest() = {test("restoring", env, customExt, + def deserTest() = {test("restoring q", env, customExt, s"""{ | val b1 = unsignedBigInt(\"${b.toString}\") | val b2 = getVar[UnsignedBigInt](0).get @@ -218,35 +218,151 @@ class BasicOpsSpecification extends CompilerTestingCommons 2.toByte -> UnsignedBigIntConstant(z.bigInteger) ).toSeq - def deserTest() = {test("schnorr", env, customExt, - s"""{ - | - | val g: GroupElement = groupGenerator - | val holder = getVar[GroupElement](0).get - | - | val message = fromBase16("${Base16.encode(message)}") - | val e: Coll[Byte] = blake2b256(message) // weak Fiat-Shamir - | val eInt = byteArrayToBigInt(e) // challenge as big integer - | - | // a of signature in (a, z) - | val a = getVar[GroupElement](1).get - | val aBytes = a.getEncoded - | - | // z of signature in (a, z) - | val z = getVar[UnsignedBigInt](2).get - | - | // Signature is valid if g^z = a * x^e - | val properSignature = g.exp(z) == a.multiply(holder.exp(eInt)) - | sigmaProp(properSignature) - |}""".stripMargin, - null, - true - )} + def schnorrTest() = { + test("schnorr", env, customExt, + s"""{ + | + | val g: GroupElement = groupGenerator + | val holder = getVar[GroupElement](0).get + | + | val message = fromBase16("${Base16.encode(message)}") + | val e: Coll[Byte] = blake2b256(message) // weak Fiat-Shamir + | val eInt = byteArrayToBigInt(e) // challenge as big integer + | + | // a of signature in (a, z) + | val a = getVar[GroupElement](1).get + | val aBytes = a.getEncoded + | + | // z of signature in (a, z) + | val z = getVar[UnsignedBigInt](2).get + | + | // Signature is valid if g^z = a * x^e + | val properSignature = g.exp(z) == a.multiply(holder.exp(eInt)) + | sigmaProp(properSignature) + |}""".stripMargin, + null, + true + ) + } + + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy schnorrTest() + } else { + schnorrTest() + } + } + + property("Bulletproof verification for a circuit proof") { + + val g = CGroupElement(SecP256K1Group.generator) + + def circuitTest() = { + test("schnorr", env, ext, + s"""{ + | // circuit data - should be provided via data input likely + | val lWeights: Coll[UnsignedBigInt] + | val rWeights: Coll[UnsignedBigInt] + | val oWeights: Coll[UnsignedBigInt] + | val commitmentWeights: Coll[UnsignedBigInt] + | + | val cs: Coll[UnsignedBigInt] + | val commitments: Coll[GroupElement] + | + | // proof data + | val ai: GroupElement + | val ao: GroupElement + | val s: GroupElement + | val tCommits: Coll[GroupElement] + | val tauX: UnsignedBigInt + | val mu: UnsignedBigInt + | val t: UnsignedBigInt + | + | // inner product proof + | val L: Coll[GroupElement] + | val R: Coll[GroupElement] + | val a: UnsignedBigInt + | val b: UnsignedBigInt + | + | // proof verification: + | val Q = lWeights.size + | + | val q // group order + | + | val yBytes = sha256(q.toBytes ++ aI.getEncoded ++ aO.getEncoded ++ s.getEncoded) + | + | val y = byteArrayToBigInt(yBytes) // should be to unsigned bigint + | + | val z = byteArrayToBigInt(sha256(y ++ q.toBytes)) + | + | + | + | sigmaProp(properSignature) + |}""".stripMargin, + null, + true + ) + } + + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy circuitTest() + } else { + circuitTest() + } + } + + property("Bulletproof verification for a range proof") { + + val g = CGroupElement(SecP256K1Group.generator) + + def circuitTest() = { + test("range proof", env, ext, + s"""{ + | // circuit data - should be provided via data input likely + | val input: GroupElement + | + | // proof data + | val ai: GroupElement + | val s: GroupElement + | val tCommits: Coll[GroupElement] + | val tauX: UnsignedBigInt + | val mu: UnsignedBigInt + | val t: UnsignedBigInt + | + | // inner product proof + | val L: Coll[GroupElement] + | val R: Coll[GroupElement] + | val a: UnsignedBigInt + | val b: UnsignedBigInt + | + | // proof verification: + | val Q = lWeights.size + | + | val q // group order + | + | val yBytes = sha256(q.toBytes ++ input.getEncoded ++ aI.getEncoded ++ s.getEncoded) + | + | val y = byteArrayToBigInt(yBytes) mod q // should be to unsigned bigint + | + | val z = byteArrayToBigInt(sha256(q.toBytes ++ yBytes)) mod q + | + | val zSquared = z * z mod q + | val zCubed = z * z * z mod q // todo: what to do here? + | + | def times() : // todo: implement + | + | // ops needed: modInverse, mod ops + | + | sigmaProp(properSignature) + |}""".stripMargin, + null, + true + ) + } if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy deserTest() + an[Exception] should be thrownBy circuitTest() } else { - deserTest() + circuitTest() } } From e9b3253dd4c4220be2f87a1ee66240ad67fd45fd Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 12 Jun 2024 13:13:18 +0300 Subject: [PATCH 077/123] original code --- .../utxo/BasicOpsSpecification.scala | 62 ++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 64fa69bf24..4d7d3718e9 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -311,6 +311,66 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("Bulletproof verification for a range proof") { + /* + * Original range proof verifier code by Benedikt Bunz: + * + VectorBase vectorBase = params.getVectorBase(); + PeddersenBase base = params.getBase(); + int n = vectorBase.getGs().size(); + T a = proof.getaI(); + T s = proof.getS(); + + BigInteger q = params.getGroup().groupOrder(); + BigInteger y; + + if (salt.isPresent()) { + y = ProofUtils.computeChallenge(q, salt.get(), input, a, s); + } else { + y = ProofUtils.computeChallenge(q, input, a, s); + + } + FieldVector ys = FieldVector.from(VectorX.iterate(n, BigInteger.ONE, y::multiply), q); + + BigInteger z = ProofUtils.challengeFromints(q, y); + + BigInteger zSquared = z.pow(2).mod(q); + BigInteger zCubed = z.pow(3).mod(q); + + FieldVector twos = FieldVector.from(VectorX.iterate(n, BigInteger.ONE, bi -> bi.shiftLeft(1)), q); + FieldVector twoTimesZSquared = twos.times(zSquared); + GeneratorVector tCommits = proof.gettCommits(); + + BigInteger x = ProofUtils.computeChallenge(q,z, tCommits); + + BigInteger tauX = proof.getTauX(); + BigInteger mu = proof.getMu(); + BigInteger t = proof.getT(); + BigInteger k = ys.sum().multiply(z.subtract(zSquared)).subtract(zCubed.shiftLeft(n).subtract(zCubed)); + T lhs = base.commit(t.subtract(k), tauX); + T rhs = tCommits.commit(Arrays.asList(x, x.pow(2))).add(input.multiply(zSquared)); + System.out.println("y " + y); + System.out.println("z " + z); + + System.out.println("x " + x);pow + equal(lhs, rhs, "Polynomial identity check failed, LHS: %s, RHS %s"); + BigInteger uChallenge = ProofUtils.challengeFromints(q, x, tauX, mu, t); + System.out.println("u " + uChallenge); + T u = base.g.multiply(uChallenge); + GeneratorVector hs = vectorBase.getHs(); + GeneratorVector gs = vectorBase.getGs(); + GeneratorVector hPrimes = hs.haddamard(ys.invert()); + FieldVector hExp = ys.times(z).add(twoTimesZSquared); + T P = a.add(s.multiply(x)).add(gs.sum().multiply(z.negate())).add(hPrimes.commit(hExp)).subtract(base.h.multiply(mu)).add(u.multiply(t)); + VectorBase primeBase = new VectorBase<>(gs, hPrimes, u); + // System.out.println("PVerify "+P.normalize()); + // System.out.println("XVerify" +x); + // System.out.println("YVerify" +y); + // System.out.println("ZVerify" +z); + // System.out.println("uVerify" +u); + + EfficientInnerProductVerifier verifier = new EfficientInnerProductVerifier<>(); + verifier.verify(primeBase, P, proof.getProductProof(), uChallenge); + */ val g = CGroupElement(SecP256K1Group.generator) @@ -346,7 +406,7 @@ class BasicOpsSpecification extends CompilerTestingCommons | val z = byteArrayToBigInt(sha256(q.toBytes ++ yBytes)) mod q | | val zSquared = z * z mod q - | val zCubed = z * z * z mod q // todo: what to do here? + | val zCubed = zSquared * z mod q | | def times() : // todo: implement | From e71d7c2a2e06aec1a301c5de87419db63d7f9050 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 13 Jun 2024 21:00:07 +0300 Subject: [PATCH 078/123] modInverse --- .../src/main/scala/sigma/SigmaDsl.scala | 6 +- .../src/main/scala/sigma/ast/SType.scala | 3 +- .../src/main/scala/sigma/data/CBigInt.scala | 4 + .../sigma/reflection/ReflectionData.scala | 1 + .../src/main/scala/sigma/ast/methods.scala | 74 +++++++++++++++++-- .../sigma/compiler/ir/GraphBuilding.scala | 5 ++ .../ir/wrappers/sigma/SigmaDslUnit.scala | 1 + .../ir/wrappers/sigma/impl/SigmaDslImpl.scala | 21 ++++++ .../utxo/BasicOpsSpecification.scala | 20 +++++ 9 files changed, 126 insertions(+), 9 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 723ce03bc6..3366bddfac 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -273,15 +273,15 @@ trait UnsignedBigInt { def and(that: UnsignedBigInt): UnsignedBigInt def &(that: UnsignedBigInt): UnsignedBigInt = and(that) - /** Returns a BigInteger whose value is `(this | that)`. (This - * method returns a negative BigInteger if and only if either `this` or `that`` is - * negative.) + /** Returns a BigInteger whose value is `(this | that)`. * * @param that value to be OR'ed with this BigInteger. * @return `this | that` */ def or(that: UnsignedBigInt): UnsignedBigInt def |(that: UnsignedBigInt): UnsignedBigInt = or(that) + + def modInverse(m: UnsignedBigInt): UnsignedBigInt } diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index 411ab1e8c7..1ce1663859 100644 --- a/core/shared/src/main/scala/sigma/ast/SType.scala +++ b/core/shared/src/main/scala/sigma/ast/SType.scala @@ -490,7 +490,7 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM case object SUnsignedBigInt extends SPrimType with SEmbeddable with SNumericType with SMonoType { override type WrappedType = UnsignedBigInt override val typeCode: TypeCode = 9: Byte - override val reprClass: RClass[_] = RClass(classOf[BigInt]) + override val reprClass: RClass[_] = RClass(classOf[UnsignedBigInt]) override def typeId = typeCode /** Type of Relation binary op like GE, LE, etc. */ @@ -501,6 +501,7 @@ case object SUnsignedBigInt extends SPrimType with SEmbeddable with SNumericType override def numericTypeIndex: Int = 5 + // todo: consider upcast and downcast rules override def upcast(v: AnyVal): UnsignedBigInt = { val bi = v match { case x: Byte => BigInteger.valueOf(x.toLong) diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index 5ae617feba..b9134ef892 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -90,4 +90,8 @@ case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends Unsign override def and(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.and(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) override def or(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.or(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) + + override def modInverse(m: UnsignedBigInt): UnsignedBigInt = { + CUnsignedBigInt(wrappedValue.modInverse(m.asInstanceOf[CUnsignedBigInt].wrappedValue)) + } } diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index e0e890abca..dde155c7f3 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -128,6 +128,7 @@ object ReflectionData { ) ) } + //todo: add UnsignedBigInt { val clazz = classOf[CollBuilder] registerClassEntry(clazz, diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 179e21485c..c8d8cacfbb 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -90,7 +90,7 @@ sealed trait MethodsContainer { } object MethodsContainer { - private val containers = new SparseArrayContainer[MethodsContainer](Array( + private val methodsV5 = Array( SByteMethods, SShortMethods, SIntMethods, @@ -111,11 +111,29 @@ object MethodsContainer { STupleMethods, SUnitMethods, SAnyMethods - ).map(m => (m.typeId, m))) + ) + + private val methodsV6 = methodsV5 ++ Seq(SUnsignedBigIntMethods) + + private val containersV5 = new SparseArrayContainer[MethodsContainer](methodsV5.map(m => (m.typeId, m))) - def contains(typeId: TypeCode): Boolean = containers.contains(typeId) + private val containersV6 = new SparseArrayContainer[MethodsContainer](methodsV6.map(m => (m.typeId, m))) - def apply(typeId: TypeCode): MethodsContainer = containers(typeId) + def contains(typeId: TypeCode): Boolean = { + if (VersionContext.current.isV6SoftForkActivated) { + containersV6.contains(typeId) + } else { + containersV5.contains(typeId) + } + } + + def apply(typeId: TypeCode): MethodsContainer = { + if (VersionContext.current.isV6SoftForkActivated) { + containersV6(typeId) + } else { + containersV5(typeId) + } + } /** Finds the method of the give type. * @@ -127,7 +145,11 @@ object MethodsContainer { case tup: STuple => STupleMethods.getTupleMethod(tup, methodName) case _ => - containers.get(tpe.typeCode).flatMap(_.method(methodName)) + if (VersionContext.current.isV6SoftForkActivated) { + containersV6.get(tpe.typeCode).flatMap(_.method(methodName)) + } else { + containersV5.get(tpe.typeCode).flatMap(_.method(methodName)) + } } } @@ -335,6 +357,48 @@ case object SBigIntMethods extends SNumericTypeMethods { } +/** Methods of UnsignedBigInt type. Implemented using [[java.math.BigInteger]]. */ +case object SUnsignedBigIntMethods extends SNumericTypeMethods { + /** Type for which this container defines methods. */ + override def ownerType: SMonoType = SUnsignedBigInt + + final val ToNBitsCostInfo = OperationCostInfo( + FixedCost(JitCost(5)), NamedDesc("NBitsMethodCall")) + + //id = 8 to make it after toBits + val ToNBits = SMethod(this, "nbits", SFunc(this.ownerType, SLong), 8, ToNBitsCostInfo.costKind) + .withInfo(ModQ, "Encode this big integer value as NBits") + + // todo: costing + final val ModInverseCostInfo = ToNBitsCostInfo + + // todo: check ids before and after merging with other PRs introducing new methods for Numeric + val ModInverseMethod = SMethod(this, "modInverse", SFunc(Array(this.ownerType, this.ownerType), this.ownerType), 9, ModInverseCostInfo.costKind) + .withIRInfo(MethodCallIrBuilder) + .withInfo(MethodCall, "") + + def modInverse_eval(mc: MethodCall, bi: UnsignedBigInt, m: UnsignedBigInt) + (implicit E: ErgoTreeEvaluator): UnsignedBigInt = { + E.addCost(ModInverseCostInfo.costKind, mc.method.opDesc) + bi.modInverse(m) + } + + // no 6.0 versioning here as it is done in method containers + protected override def getMethods(): Seq[SMethod] = { + super.getMethods() ++ Seq( + ModInverseMethod + ) + } + + /** + * + */ + def nbits_eval(mc: MethodCall, bi: sigma.BigInt)(implicit E: ErgoTreeEvaluator): Long = { + ??? + } + +} + /** Methods of type `String`. */ case object SStringMethods extends MonoTypeMethods { /** Type for which this container defines methods. */ diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index e2350b8338..f9fc30625d 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1013,6 +1013,11 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => opt.filter(asRep[t => Boolean](argsV(0))) case _ => throwError } + case (ubi: Ref[UnsignedBigInt]@unchecked, SUnsignedBigIntMethods) => method.name match { + case SUnsignedBigIntMethods.ModInverseMethod.name => + val m = asRep[UnsignedBigInt](argsV(0)) + ubi.modInverse(m) + } case (ge: Ref[GroupElement]@unchecked, SGroupElementMethods) => method.name match { case SGroupElementMethods.GetEncodedMethod.name => ge.getEncoded diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala index b3be395a74..e3afee48be 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala @@ -22,6 +22,7 @@ import scalan._ def mod(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; def min(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; def max(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; + def modInverse(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] }; trait GroupElement extends Def[GroupElement] { def exp(k: Ref[BigInt]): Ref[GroupElement]; diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala index 27ebaa717c..a81962346a 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala @@ -332,6 +332,13 @@ object UnsignedBigInt extends EntityObject("UnsignedBigInt") { Array[AnyRef](that), true, false, element[UnsignedBigInt])) } + + override def modInverse(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("modInverse", classOf[Sym]), + Array[AnyRef](m), + true, false, element[UnsignedBigInt])) + } } @@ -402,6 +409,20 @@ object UnsignedBigInt extends EntityObject("UnsignedBigInt") { Array[AnyRef](that), true, true, element[UnsignedBigInt])) } + + def modInverse(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("modInverse", classOf[Sym]), + Array[AnyRef](m), + true, true, element[UnsignedBigInt])) + } + } + + // entityUnref: single unref method for each type family + implicit final def unrefUnsignedBigInt(p: Ref[UnsignedBigInt]): UnsignedBigInt = { + if (p.node.isInstanceOf[UnsignedBigInt]) p.node.asInstanceOf[UnsignedBigInt] + else + UnsignedBigIntAdapter(p) } class UnsignedBigIntElem[To <: UnsignedBigInt] diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 4d7d3718e9..df339f5661 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -252,6 +252,26 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("modInverse") { + def miTest() = { + test("modInverse", env, ext, + s"""{ + | val bi = unsignedBigInt("248486720836984554860790790898080606") + | val m = unsignedBigInt("575879797") + | bi.modInverse(m) > 0 + |}""".stripMargin, + null, + true + ) + } + + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy miTest() + } else { + miTest() + } + } + property("Bulletproof verification for a circuit proof") { val g = CGroupElement(SecP256K1Group.generator) From e989665dd3422d981e020d9ba37b395ac447bbde Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 13 Jun 2024 22:10:11 +0300 Subject: [PATCH 079/123] plusMod --- .../src/main/scala/sigma/SigmaDsl.scala | 1 + .../src/main/scala/sigma/data/CBigInt.scala | 6 + .../src/main/scala/sigma/ast/methods.scala | 14 ++- .../sigma/compiler/ir/GraphBuilding.scala | 4 + .../ir/wrappers/sigma/SigmaDslUnit.scala | 1 + .../ir/wrappers/sigma/impl/SigmaDslImpl.scala | 14 +++ .../utxo/BasicOpsSpecification.scala | 113 +++++++++++------- 7 files changed, 106 insertions(+), 47 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 3366bddfac..bd4c352b56 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -282,6 +282,7 @@ trait UnsignedBigInt { def |(that: UnsignedBigInt): UnsignedBigInt = or(that) def modInverse(m: UnsignedBigInt): UnsignedBigInt + def plusMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt } diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index b9134ef892..448cb97e54 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -94,4 +94,10 @@ case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends Unsign override def modInverse(m: UnsignedBigInt): UnsignedBigInt = { CUnsignedBigInt(wrappedValue.modInverse(m.asInstanceOf[CUnsignedBigInt].wrappedValue)) } + + override def plusMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt = { + val thatBi = that.asInstanceOf[CUnsignedBigInt].wrappedValue + val mBi = m.asInstanceOf[CUnsignedBigInt].wrappedValue + CUnsignedBigInt(wrappedValue.add(thatBi).mod(mBi)) + } } diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index c8d8cacfbb..5a1deb184b 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -383,10 +383,22 @@ case object SUnsignedBigIntMethods extends SNumericTypeMethods { bi.modInverse(m) } + // todo: costing + val PlusModMethod = SMethod(this, "plusMod", SFunc(Array(this.ownerType, this.ownerType, this.ownerType), this.ownerType), 10, ModInverseCostInfo.costKind) + .withIRInfo(MethodCallIrBuilder) + .withInfo(MethodCall, "") + + def plusMod_eval(mc: MethodCall, bi: UnsignedBigInt, bi2: UnsignedBigInt, m: UnsignedBigInt) + (implicit E: ErgoTreeEvaluator): UnsignedBigInt = { + E.addCost(ModInverseCostInfo.costKind, mc.method.opDesc) // todo: costing + bi.plusMod(bi2, m) + } + // no 6.0 versioning here as it is done in method containers protected override def getMethods(): Seq[SMethod] = { super.getMethods() ++ Seq( - ModInverseMethod + ModInverseMethod, + PlusModMethod ) } diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index f9fc30625d..d24eac2895 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1017,6 +1017,10 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => case SUnsignedBigIntMethods.ModInverseMethod.name => val m = asRep[UnsignedBigInt](argsV(0)) ubi.modInverse(m) + case SUnsignedBigIntMethods.PlusModMethod.name => + val that = asRep[UnsignedBigInt](argsV(0)) + val m = asRep[UnsignedBigInt](argsV(1)) + ubi.plusMod(that, m) } case (ge: Ref[GroupElement]@unchecked, SGroupElementMethods) => method.name match { case SGroupElementMethods.GetEncodedMethod.name => diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala index e3afee48be..c6c24091ee 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala @@ -23,6 +23,7 @@ import scalan._ def min(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; def max(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; def modInverse(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] + def plusMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] }; trait GroupElement extends Def[GroupElement] { def exp(k: Ref[BigInt]): Ref[GroupElement]; diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala index a81962346a..a34e3dbd52 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala @@ -339,6 +339,13 @@ object UnsignedBigInt extends EntityObject("UnsignedBigInt") { Array[AnyRef](m), true, false, element[UnsignedBigInt])) } + + override def plusMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("plusMod", classOf[Sym], classOf[Sym]), + Array[AnyRef](that, m), + true, false, element[UnsignedBigInt])) + } } @@ -416,6 +423,13 @@ object UnsignedBigInt extends EntityObject("UnsignedBigInt") { Array[AnyRef](m), true, true, element[UnsignedBigInt])) } + + def plusMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("plusMod", classOf[Sym], classOf[Sym]), + Array[AnyRef](that, m), + true, true, element[UnsignedBigInt])) + } } // entityUnref: single unref method for each type family diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index df339f5661..8f942d0ea5 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -272,51 +272,14 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("Bulletproof verification for a circuit proof") { - - val g = CGroupElement(SecP256K1Group.generator) - - def circuitTest() = { - test("schnorr", env, ext, + property("mod ops - plus") { + def miTest() = { + test("modInverse", env, ext, s"""{ - | // circuit data - should be provided via data input likely - | val lWeights: Coll[UnsignedBigInt] - | val rWeights: Coll[UnsignedBigInt] - | val oWeights: Coll[UnsignedBigInt] - | val commitmentWeights: Coll[UnsignedBigInt] - | - | val cs: Coll[UnsignedBigInt] - | val commitments: Coll[GroupElement] - | - | // proof data - | val ai: GroupElement - | val ao: GroupElement - | val s: GroupElement - | val tCommits: Coll[GroupElement] - | val tauX: UnsignedBigInt - | val mu: UnsignedBigInt - | val t: UnsignedBigInt - | - | // inner product proof - | val L: Coll[GroupElement] - | val R: Coll[GroupElement] - | val a: UnsignedBigInt - | val b: UnsignedBigInt - | - | // proof verification: - | val Q = lWeights.size - | - | val q // group order - | - | val yBytes = sha256(q.toBytes ++ aI.getEncoded ++ aO.getEncoded ++ s.getEncoded) - | - | val y = byteArrayToBigInt(yBytes) // should be to unsigned bigint - | - | val z = byteArrayToBigInt(sha256(y ++ q.toBytes)) - | - | - | - | sigmaProp(properSignature) + | val bi1 = unsignedBigInt("248486720836984554860790790898080606") + | val bi2 = unsignedBigInt("2484867208369845548607907908980997780606") + | val m = unsignedBigInt("575879797") + | bi1.plusMod(bi2, m) > 0 |}""".stripMargin, null, true @@ -324,9 +287,9 @@ class BasicOpsSpecification extends CompilerTestingCommons } if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy circuitTest() + an[Exception] should be thrownBy miTest() } else { - circuitTest() + miTest() } } @@ -446,6 +409,64 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("Bulletproof verification for a circuit proof") { + + val g = CGroupElement(SecP256K1Group.generator) + + def circuitTest() = { + test("schnorr", env, ext, + s"""{ + | // circuit data - should be provided via data input likely + | val lWeights = Coll[UnsignedBigInt] + | val rWeights: Coll[UnsignedBigInt] + | val oWeights: Coll[UnsignedBigInt] + | val commitmentWeights: Coll[UnsignedBigInt] + | + | val cs: Coll[UnsignedBigInt] + | val commitments: Coll[GroupElement] + | + | // proof data + | val ai: GroupElement + | val ao: GroupElement + | val s: GroupElement + | val tCommits: Coll[GroupElement] + | val tauX: UnsignedBigInt + | val mu: UnsignedBigInt + | val t: UnsignedBigInt + | + | // inner product proof + | val L: Coll[GroupElement] + | val R: Coll[GroupElement] + | val a: UnsignedBigInt + | val b: UnsignedBigInt + | + | // proof verification: + | val Q = lWeights.size + | + | val q // group order + | + | val yBytes = sha256(q.toBytes ++ aI.getEncoded ++ aO.getEncoded ++ s.getEncoded) + | + | val y = byteArrayToBigInt(yBytes) // should be to unsigned bigint + | + | val z = byteArrayToBigInt(sha256(y ++ q.toBytes)) + | + | + | + | sigmaProp(properSignature) + |}""".stripMargin, + null, + true + ) + } + + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy circuitTest() + } else { + circuitTest() + } + } + property("Unit register") { // TODO frontend: implement missing Unit support in compiler // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820 From d776db3256371c16944aa6c5824d89be4bb1cf51 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 13 Jun 2024 22:27:28 +0300 Subject: [PATCH 080/123] multiplyMod --- .../src/main/scala/sigma/SigmaDsl.scala | 1 + .../src/main/scala/sigma/data/CBigInt.scala | 6 ++ .../src/main/scala/sigma/ast/methods.scala | 13 ++++- .../sigma/compiler/ir/GraphBuilding.scala | 4 ++ .../ir/wrappers/sigma/SigmaDslUnit.scala | 1 + .../ir/wrappers/sigma/impl/SigmaDslImpl.scala | 14 +++++ .../utxo/BasicOpsSpecification.scala | 58 +++++++++++++------ 7 files changed, 78 insertions(+), 19 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index bd4c352b56..251b94b288 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -283,6 +283,7 @@ trait UnsignedBigInt { def modInverse(m: UnsignedBigInt): UnsignedBigInt def plusMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt + def multiplyMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt } diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index 448cb97e54..60f87e7cf7 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -100,4 +100,10 @@ case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends Unsign val mBi = m.asInstanceOf[CUnsignedBigInt].wrappedValue CUnsignedBigInt(wrappedValue.add(thatBi).mod(mBi)) } + + override def multiplyMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt = { + val thatBi = that.asInstanceOf[CUnsignedBigInt].wrappedValue + val mBi = m.asInstanceOf[CUnsignedBigInt].wrappedValue + CUnsignedBigInt(wrappedValue.multiply(thatBi).mod(mBi)) + } } diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 5a1deb184b..35700f799d 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -394,11 +394,22 @@ case object SUnsignedBigIntMethods extends SNumericTypeMethods { bi.plusMod(bi2, m) } + val MultiplyModMethod = SMethod(this, "multiplyMod", SFunc(Array(this.ownerType, this.ownerType, this.ownerType), this.ownerType), 11, ModInverseCostInfo.costKind) + .withIRInfo(MethodCallIrBuilder) + .withInfo(MethodCall, "") + + def multiplyMod_eval(mc: MethodCall, bi: UnsignedBigInt, bi2: UnsignedBigInt, m: UnsignedBigInt) + (implicit E: ErgoTreeEvaluator): UnsignedBigInt = { + E.addCost(ModInverseCostInfo.costKind, mc.method.opDesc) // todo: costing + bi.multiplyMod(bi2, m) + } + // no 6.0 versioning here as it is done in method containers protected override def getMethods(): Seq[SMethod] = { super.getMethods() ++ Seq( ModInverseMethod, - PlusModMethod + PlusModMethod, + MultiplyModMethod ) } diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index d24eac2895..a330ae405b 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1021,6 +1021,10 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => val that = asRep[UnsignedBigInt](argsV(0)) val m = asRep[UnsignedBigInt](argsV(1)) ubi.plusMod(that, m) + case SUnsignedBigIntMethods.MultiplyModMethod.name => + val that = asRep[UnsignedBigInt](argsV(0)) + val m = asRep[UnsignedBigInt](argsV(1)) + ubi.multiplyMod(that, m) } case (ge: Ref[GroupElement]@unchecked, SGroupElementMethods) => method.name match { case SGroupElementMethods.GetEncodedMethod.name => diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala index c6c24091ee..5a9b6903c1 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala @@ -24,6 +24,7 @@ import scalan._ def max(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; def modInverse(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] def plusMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] + def multiplyMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] }; trait GroupElement extends Def[GroupElement] { def exp(k: Ref[BigInt]): Ref[GroupElement]; diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala index a34e3dbd52..05f799dbc5 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala @@ -346,6 +346,13 @@ object UnsignedBigInt extends EntityObject("UnsignedBigInt") { Array[AnyRef](that, m), true, false, element[UnsignedBigInt])) } + + override def multiplyMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("multiplyMod", classOf[Sym], classOf[Sym]), + Array[AnyRef](that, m), + true, false, element[UnsignedBigInt])) + } } @@ -430,6 +437,13 @@ object UnsignedBigInt extends EntityObject("UnsignedBigInt") { Array[AnyRef](that, m), true, true, element[UnsignedBigInt])) } + + def multiplyMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("multiplyMod", classOf[Sym], classOf[Sym]), + Array[AnyRef](that, m), + true, true, element[UnsignedBigInt])) + } } // entityUnref: single unref method for each type family diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 8f942d0ea5..8b0b8a1367 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -168,7 +168,7 @@ class BasicOpsSpecification extends CompilerTestingCommons // todo: how to upcast? def deserTest() = {test("restoring", env, ext, - s"{ val b = bigInt(\"${ub.toString}\"); b > 1 }", + s"{ val b = bigInt(\"${ub.toString}\").toUnsigned; b > 1 }", null, true )} @@ -293,6 +293,27 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("mod ops - multiply") { + def miTest() = { + test("modInverse", env, ext, + s"""{ + | val bi1 = unsignedBigInt("248486720836984554860790790898080606") + | val bi2 = unsignedBigInt("2484867208369845548607907908980997780606") + | val m = unsignedBigInt("575879797") + | bi1.multiplyMod(bi2, m) > 0 + |}""".stripMargin, + null, + true + ) + } + + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy miTest() + } else { + miTest() + } + } + property("Bulletproof verification for a range proof") { /* * Original range proof verifier code by Benedikt Bunz: @@ -357,30 +378,30 @@ class BasicOpsSpecification extends CompilerTestingCommons val g = CGroupElement(SecP256K1Group.generator) - def circuitTest() = { + def rangeTest() = { test("range proof", env, ext, s"""{ - | // circuit data - should be provided via data input likely - | val input: GroupElement + | // range proof input data + | val input: GroupElement = getVar[GroupElement](0).get | | // proof data - | val ai: GroupElement - | val s: GroupElement - | val tCommits: Coll[GroupElement] - | val tauX: UnsignedBigInt - | val mu: UnsignedBigInt - | val t: UnsignedBigInt + | val ai: GroupElement = getVar[GroupElement](1).get + | val s: GroupElement = getVar[GroupElement](2).get + | val tCommits: Coll[GroupElement] = getVar[Coll[GroupElement]](3).get + | val tauX: UnsignedBigInt = getVar[UnsignedBigInt](4).get + | val mu: UnsignedBigInt = getVar[UnsignedBigInt](5).get + | val t: UnsignedBigInt = getVar[UnsignedBigInt](6).get | | // inner product proof - | val L: Coll[GroupElement] - | val R: Coll[GroupElement] - | val a: UnsignedBigInt - | val b: UnsignedBigInt + | val L: Coll[GroupElement] = getVar[Coll[GroupElement]](7).get + | val R: Coll[GroupElement] = getVar[Coll[GroupElement]](8)).get + | val a: UnsignedBigInt = getVar[UnsignedBigInt](9).get + | val b: UnsignedBigInt = getVar[UnsignedBigInt](10).get | | // proof verification: | val Q = lWeights.size | - | val q // group order + | val q // group order = getVar[UnsignedBigInt](11).get | | val yBytes = sha256(q.toBytes ++ input.getEncoded ++ aI.getEncoded ++ s.getEncoded) | @@ -403,13 +424,14 @@ class BasicOpsSpecification extends CompilerTestingCommons } if (activatedVersionInTests < V6SoftForkVersion) { - an[Exception] should be thrownBy circuitTest() + an[Exception] should be thrownBy rangeTest() } else { - circuitTest() + rangeTest() } } - property("Bulletproof verification for a circuit proof") { + // todo: complete + ignore("Bulletproof verification for a circuit proof") { val g = CGroupElement(SecP256K1Group.generator) From 72db85b0f0e1e49557368aa028801a4048b4213e Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 14 Jun 2024 23:11:04 +0300 Subject: [PATCH 081/123] toUnsigned & toUnsignedMod --- .../src/main/scala/sigma/SigmaDsl.scala | 4 ++ .../src/main/scala/sigma/data/CBigInt.scala | 12 +++++ .../src/main/scala/sigma/ast/methods.scala | 29 +++++++++- .../sigma/compiler/ir/GraphBuilding.scala | 7 +++ .../ir/wrappers/sigma/SigmaDslUnit.scala | 2 + .../ir/wrappers/sigma/impl/SigmaDslImpl.scala | 34 +++++++++++- .../utxo/BasicOpsSpecification.scala | 54 ++++++++++++++++--- 7 files changed, 133 insertions(+), 9 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 251b94b288..d7749f825b 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -152,6 +152,10 @@ trait BigInt { */ def or(that: BigInt): BigInt def |(that: BigInt): BigInt = or(that) + + def toUnsigned: UnsignedBigInt + + def toUnsignedMod(m: UnsignedBigInt): UnsignedBigInt } diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index 60f87e7cf7..1951f55486 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -49,6 +49,18 @@ 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)) + + def toUnsigned: UnsignedBigInt = { + if(this.wrappedValue.compareTo(BigInteger.ZERO) < 0){ + throw new ArithmeticException("BigInteger argument for .toUnsigned is negative in"); + } else { + CUnsignedBigInt(this.wrappedValue) + } + } + + def toUnsignedMod(m: UnsignedBigInt): UnsignedBigInt = { + CUnsignedBigInt(this.wrappedValue.mod(m.asInstanceOf[CUnsignedBigInt].wrappedValue)) + } } /** A default implementation of [[BigInt]] interface. diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 35700f799d..b34c256449 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -6,6 +6,7 @@ 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.SUnsignedBigIntMethods.ModInverseCostInfo import sigma.ast.syntax.{SValue, ValueOps} import sigma.data.OverloadHack.Overloaded1 import sigma.data.{DataValueComparer, KeyValueColl, Nullable, RType, SigmaConstants} @@ -336,13 +337,39 @@ case object SBigIntMethods extends SNumericTypeMethods { final val ToNBitsCostInfo = OperationCostInfo( FixedCost(JitCost(5)), NamedDesc("NBitsMethodCall")) + // todo: check ids after merging w. other numeric methods + //id = 8 to make it after toBits val ToNBits = SMethod(this, "nbits", SFunc(this.ownerType, SLong), 8, ToNBitsCostInfo.costKind) .withInfo(ModQ, "Encode this big integer value as NBits") + //id = 8 to make it after toBits + val ToUnsigned = SMethod(this, "toUnsigned", SFunc(this.ownerType, SUnsignedBigInt), 9, ToNBitsCostInfo.costKind) + .withIRInfo(MethodCallIrBuilder) + .withInfo(MethodCall, "") + + def toUnsigned_eval(mc: MethodCall, bi: BigInt) + (implicit E: ErgoTreeEvaluator): UnsignedBigInt = { + E.addCost(ModInverseCostInfo.costKind, mc.method.opDesc) + bi.toUnsigned + } + + + val ToUnsignedMod = SMethod(this, "toUnsignedMod", SFunc(Array(this.ownerType, SUnsignedBigInt), SUnsignedBigInt), 10, ToNBitsCostInfo.costKind) + .withIRInfo(MethodCallIrBuilder) + .withInfo(MethodCall, "") + + def toUnsignedMod_eval(mc: MethodCall, bi: BigInt, m: UnsignedBigInt) + (implicit E: ErgoTreeEvaluator): UnsignedBigInt = { + E.addCost(ModInverseCostInfo.costKind, mc.method.opDesc) + bi.toUnsignedMod(m) + } + + + protected override def getMethods(): Seq[SMethod] = { if (VersionContext.current.isV6SoftForkActivated) { - super.getMethods() ++ Seq(ToNBits) + super.getMethods() ++ Seq(ToNBits, ToUnsigned, ToUnsignedMod) } else { super.getMethods() } diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index a330ae405b..b637294d0c 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1013,6 +1013,13 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => opt.filter(asRep[t => Boolean](argsV(0))) case _ => throwError } + case (bi: Ref[BigInt]@unchecked, SBigIntMethods) => method.name match { + case SBigIntMethods.ToUnsigned.name => + bi.toUnsigned() + case SBigIntMethods.ToUnsignedMod.name => + val m = asRep[UnsignedBigInt](argsV(0)) + bi.toUnsignedMod(m) + } case (ubi: Ref[UnsignedBigInt]@unchecked, SUnsignedBigIntMethods) => method.name match { case SUnsignedBigIntMethods.ModInverseMethod.name => val m = asRep[UnsignedBigInt](argsV(0)) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala index 5a9b6903c1..595880694c 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala @@ -13,6 +13,8 @@ import scalan._ def mod(m: Ref[BigInt]): Ref[BigInt]; def min(that: Ref[BigInt]): Ref[BigInt]; def max(that: Ref[BigInt]): Ref[BigInt]; + def toUnsigned(): Ref[UnsignedBigInt]; + def toUnsignedMod(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] }; trait UnsignedBigInt extends Def[UnsignedBigInt] { def add(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala index 05f799dbc5..ef5894fc71 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala @@ -97,6 +97,22 @@ object BigInt extends EntityObject("BigInt") { Array[AnyRef](that), true, false, element[BigInt])) } + + import UnsignedBigInt.unsignedBigIntElement + + override def toUnsigned(): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + BigIntClass.getMethod("toUnsigned"), + Array[AnyRef](), + true, false, element[UnsignedBigInt](unsignedBigIntElement))) + } + + override def toUnsignedMod(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + BigIntClass.getMethod("toUnsignedMod", classOf[Sym]), + Array[AnyRef](m), + true, false, element[UnsignedBigInt](unsignedBigIntElement))) + } } implicit object LiftableBigInt @@ -165,6 +181,22 @@ object BigInt extends EntityObject("BigInt") { Array[AnyRef](that), true, true, element[BigInt])) } + + import UnsignedBigInt.unsignedBigIntElement + + def toUnsigned(): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + BigIntClass.getMethod("toUnsigned"), + Array[AnyRef](), + true, true, element[UnsignedBigInt](unsignedBigIntElement))) + } + + def toUnsignedMod(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + BigIntClass.getMethod("UnsignedBigInt", classOf[Sym]), + Array[AnyRef](that), + true, true, element[UnsignedBigInt](unsignedBigIntElement))) + } } // entityUnref: single unref method for each type family @@ -182,7 +214,7 @@ object BigInt extends EntityObject("BigInt") { override protected def collectMethods: Map[RMethod, MethodDesc] = { super.collectMethods ++ Elem.declaredMethods(RClass(classOf[BigInt]), RClass(classOf[SBigInt]), Set( - "add", "subtract", "multiply", "divide", "mod", "min", "max" + "add", "subtract", "multiply", "divide", "mod", "min", "max", "toUnsigned", "toUnsignedMod" )) } } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 8b0b8a1367..49b565dac1 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -159,25 +159,65 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - deserTest() + deserTest() // todo: should fail < 6.0 } - property("signed <-> unsigned bigint conversion - positive bigint") { + property("signed -> unsigned bigint conversion - positive bigint") { val b = new BigInteger("9280562930080889354892980449861222646750586663683904599823322027983929189860") val ub = new BigInteger(1, b.toByteArray) - // todo: how to upcast? - def deserTest() = {test("restoring", env, ext, - s"{ val b = bigInt(\"${ub.toString}\").toUnsigned; b > 1 }", + def conversionTest() = {test("restoring", env, ext, + s"""{ + | val b = bigInt(\"${ub.toString}\") + | val ub = b.toUnsigned + | ub > 1 + | } """.stripMargin, null, true )} - deserTest() + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy conversionTest() + } else { + conversionTest() + } } - property("signed <-> unsigned bigint conversion - negative bigint") { + property("signed -> unsigned bigint conversion - negative bigint") { + def conversionTest() = {test("restoring", env, ext, + s"""{ + | val b = bigInt("-1") + | val ub = b.toUnsigned + | ub > 0 + | } """.stripMargin, + null, + true + )} + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy conversionTest() + } else { + an[Exception] should be thrownBy conversionTest() + } + } + + property("signed -> unsigned bigint conversion - negative bigint - mod") { + def conversionTest() = {test("restoring", env, ext, + s"""{ + | val b = bigInt("-1") + | val m = unsignedBigInt("5") + | val ub = b.toUnsignedMod(m) + | ub >= 0 + | } """.stripMargin, + null, + true + )} + + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy conversionTest() + } else { + conversionTest() + } } property("schnorr sig check") { From fc6d8562d39a7e6ca9b59a92ae4d132d0e5938d1 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 17 Jun 2024 19:33:39 +0300 Subject: [PATCH 082/123] mod, toSigned, subtractMod --- .../src/main/scala/sigma/SigmaDsl.scala | 13 +-- .../src/main/scala/sigma/data/CBigInt.scala | 12 ++- .../src/main/scala/sigma/ast/methods.scala | 37 +++++++- .../sigma/compiler/ir/GraphBuilding.scala | 9 ++ .../ir/wrappers/sigma/SigmaDslUnit.scala | 2 + .../ir/wrappers/sigma/impl/SigmaDslImpl.scala | 28 ++++++ .../utxo/BasicOpsSpecification.scala | 88 +++++++++++++++---- 7 files changed, 158 insertions(+), 31 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index d7749f825b..86730a705e 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -242,16 +242,6 @@ trait UnsignedBigInt { def mod(m: UnsignedBigInt): UnsignedBigInt def %(m: UnsignedBigInt): UnsignedBigInt = mod(m) - /** - * Returns a BigInt whose value is {@code (this % that)}. - * - * @param that value by which this BigInt is to be divided, and the - * remainder computed. - * @return { @code this % that} - * @throws ArithmeticException if { @code that} is zero. - */ - def remainder(that: UnsignedBigInt): UnsignedBigInt - /** * Returns the minimum of this BigInteger and {@code val}. * @@ -287,7 +277,10 @@ trait UnsignedBigInt { def modInverse(m: UnsignedBigInt): UnsignedBigInt def plusMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt + def subtractMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt def multiplyMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt + + def toSigned(): BigInt } diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index 1951f55486..0ebf57ab6c 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -93,8 +93,6 @@ case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends Unsign override def mod(m: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.mod(m.asInstanceOf[CUnsignedBigInt].wrappedValue)) - override def remainder(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.remainder(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) - override def min(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.min(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) override def max(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.max(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) @@ -113,9 +111,19 @@ case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends Unsign CUnsignedBigInt(wrappedValue.add(thatBi).mod(mBi)) } + override def subtractMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt = { + val thatBi = that.asInstanceOf[CUnsignedBigInt].wrappedValue + val mBi = m.asInstanceOf[CUnsignedBigInt].wrappedValue + CUnsignedBigInt(wrappedValue.subtract(thatBi).mod(mBi)) + } + override def multiplyMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt = { val thatBi = that.asInstanceOf[CUnsignedBigInt].wrappedValue val mBi = m.asInstanceOf[CUnsignedBigInt].wrappedValue CUnsignedBigInt(wrappedValue.multiply(thatBi).mod(mBi)) } + + override def toSigned(): BigInt = { + CBigInt(wrappedValue.to256BitValueExact) + } } diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index b34c256449..bcd959ebc2 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -421,7 +421,17 @@ case object SUnsignedBigIntMethods extends SNumericTypeMethods { bi.plusMod(bi2, m) } - val MultiplyModMethod = SMethod(this, "multiplyMod", SFunc(Array(this.ownerType, this.ownerType, this.ownerType), this.ownerType), 11, ModInverseCostInfo.costKind) + val SubtractModMethod = SMethod(this, "subtractMod", SFunc(Array(this.ownerType, this.ownerType, this.ownerType), this.ownerType), 11, ModInverseCostInfo.costKind) + .withIRInfo(MethodCallIrBuilder) + .withInfo(MethodCall, "") + + def subtractMod_eval(mc: MethodCall, bi: UnsignedBigInt, bi2: UnsignedBigInt, m: UnsignedBigInt) + (implicit E: ErgoTreeEvaluator): UnsignedBigInt = { + E.addCost(ModInverseCostInfo.costKind, mc.method.opDesc) // todo: costing + bi.subtractMod(bi2, m) + } + + val MultiplyModMethod = SMethod(this, "multiplyMod", SFunc(Array(this.ownerType, this.ownerType, this.ownerType), this.ownerType), 12, ModInverseCostInfo.costKind) .withIRInfo(MethodCallIrBuilder) .withInfo(MethodCall, "") @@ -431,12 +441,35 @@ case object SUnsignedBigIntMethods extends SNumericTypeMethods { bi.multiplyMod(bi2, m) } + val ModMethod = SMethod(this, "mod", SFunc(Array(this.ownerType, this.ownerType), this.ownerType), 13, ModInverseCostInfo.costKind) + .withIRInfo(MethodCallIrBuilder) + .withInfo(MethodCall, "") + + def mod_eval(mc: MethodCall, bi: UnsignedBigInt, m: UnsignedBigInt) + (implicit E: ErgoTreeEvaluator): UnsignedBigInt = { + E.addCost(ModInverseCostInfo.costKind, mc.method.opDesc) // todo: costing + bi.mod(m) + } + + val ToSignedMethod = SMethod(this, "toSigned", SFunc(Array(this.ownerType), SBigInt), 14, ModInverseCostInfo.costKind) + .withIRInfo(MethodCallIrBuilder) + .withInfo(MethodCall, "") + + def toSigned_eval(mc: MethodCall, bi: UnsignedBigInt) + (implicit E: ErgoTreeEvaluator): BigInt = { + E.addCost(ModInverseCostInfo.costKind, mc.method.opDesc) // todo: costing + bi.toSigned() + } + // no 6.0 versioning here as it is done in method containers protected override def getMethods(): Seq[SMethod] = { super.getMethods() ++ Seq( ModInverseMethod, PlusModMethod, - MultiplyModMethod + SubtractModMethod, + MultiplyModMethod, + ModMethod, + ToSignedMethod ) } diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index b637294d0c..80433d593d 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1021,6 +1021,9 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => bi.toUnsignedMod(m) } case (ubi: Ref[UnsignedBigInt]@unchecked, SUnsignedBigIntMethods) => method.name match { + case SUnsignedBigIntMethods.ModMethod.name => + val m = asRep[UnsignedBigInt](argsV(0)) + ubi.mod(m) case SUnsignedBigIntMethods.ModInverseMethod.name => val m = asRep[UnsignedBigInt](argsV(0)) ubi.modInverse(m) @@ -1028,10 +1031,16 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => val that = asRep[UnsignedBigInt](argsV(0)) val m = asRep[UnsignedBigInt](argsV(1)) ubi.plusMod(that, m) + case SUnsignedBigIntMethods.SubtractModMethod.name => + val that = asRep[UnsignedBigInt](argsV(0)) + val m = asRep[UnsignedBigInt](argsV(1)) + ubi.subtractMod(that, m) case SUnsignedBigIntMethods.MultiplyModMethod.name => val that = asRep[UnsignedBigInt](argsV(0)) val m = asRep[UnsignedBigInt](argsV(1)) ubi.multiplyMod(that, m) + case SUnsignedBigIntMethods.ToSignedMethod.name => + ubi.toSigned } case (ge: Ref[GroupElement]@unchecked, SGroupElementMethods) => method.name match { case SGroupElementMethods.GetEncodedMethod.name => diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala index 595880694c..a1d7c9c56b 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala @@ -26,7 +26,9 @@ import scalan._ def max(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]; def modInverse(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] def plusMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] + def subtractMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] def multiplyMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] + def toSigned: Ref[BigInt] }; trait GroupElement extends Def[GroupElement] { def exp(k: Ref[BigInt]): Ref[GroupElement]; diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala index ef5894fc71..6a62007523 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala @@ -379,12 +379,26 @@ object UnsignedBigInt extends EntityObject("UnsignedBigInt") { true, false, element[UnsignedBigInt])) } + override def subtractMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("subtractMod", classOf[Sym], classOf[Sym]), + Array[AnyRef](that, m), + true, false, element[UnsignedBigInt])) + } + override def multiplyMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { asRep[UnsignedBigInt](mkMethodCall(self, UnsignedBigIntClass.getMethod("multiplyMod", classOf[Sym], classOf[Sym]), Array[AnyRef](that, m), true, false, element[UnsignedBigInt])) } + + override def toSigned: Ref[BigInt] = { + asRep[BigInt](mkMethodCall(self, + UnsignedBigIntClass.getMethod("toSigned"), + Array[AnyRef](), + true, false, element[BigInt])) + } } @@ -470,12 +484,26 @@ object UnsignedBigInt extends EntityObject("UnsignedBigInt") { true, true, element[UnsignedBigInt])) } + def subtractMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { + asRep[UnsignedBigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("subtractMod", classOf[Sym], classOf[Sym]), + Array[AnyRef](that, m), + true, true, element[UnsignedBigInt])) + } + def multiplyMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = { asRep[UnsignedBigInt](mkMethodCall(source, UnsignedBigIntClass.getMethod("multiplyMod", classOf[Sym], classOf[Sym]), Array[AnyRef](that, m), true, true, element[UnsignedBigInt])) } + + def toSigned: Ref[BigInt] = { + asRep[BigInt](mkMethodCall(source, + UnsignedBigIntClass.getMethod("toSigned"), + Array[AnyRef](), + true, true, element[BigInt])) + } } // entityUnref: single unref method for each type family diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 49b565dac1..920fa8ba2c 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -166,7 +166,7 @@ class BasicOpsSpecification extends CompilerTestingCommons val b = new BigInteger("9280562930080889354892980449861222646750586663683904599823322027983929189860") val ub = new BigInteger(1, b.toByteArray) - def conversionTest() = {test("restoring", env, ext, + def conversionTest() = {test("conversion", env, ext, s"""{ | val b = bigInt(\"${ub.toString}\") | val ub = b.toUnsigned @@ -184,7 +184,7 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("signed -> unsigned bigint conversion - negative bigint") { - def conversionTest() = {test("restoring", env, ext, + def conversionTest() = {test("conversion", env, ext, s"""{ | val b = bigInt("-1") | val ub = b.toUnsigned @@ -202,7 +202,7 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("signed -> unsigned bigint conversion - negative bigint - mod") { - def conversionTest() = {test("restoring", env, ext, + def conversionTest() = {test("conversion", env, ext, s"""{ | val b = bigInt("-1") | val m = unsignedBigInt("5") @@ -220,6 +220,24 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("unsigned -> signed bigint conversion") { + def conversionTest() = {test("conversion", env, ext, + s"""{ + | val ub = unsignedBigInt("10") + | val b = ub.toSigned + | b - 11 == bigInt("-1") + | } """.stripMargin, + null, + true + )} + + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy conversionTest() + } else { + conversionTest() + } + } + property("schnorr sig check") { val g = CGroupElement(SecP256K1Group.generator) @@ -292,6 +310,26 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("mod") { + def miTest() = { + test("mod", env, ext, + s"""{ + | val bi = unsignedBigInt("248486720836984554860790790898080606") + | val m = unsignedBigInt("575879797") + | bi.mod(m) < bi + |}""".stripMargin, + null, + true + ) + } + + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy miTest() + } else { + miTest() + } + } + property("modInverse") { def miTest() = { test("modInverse", env, ext, @@ -333,6 +371,27 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("mod ops - subtract") { + def miTest() = { + test("subtractMod", env, ext, + s"""{ + | val bi1 = unsignedBigInt("2") + | val bi2 = unsignedBigInt("4") + | val m = unsignedBigInt("575879797") + | bi1.subtractMod(bi2, m) > 0 + |}""".stripMargin, + null, + true + ) + } + + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy miTest() + } else { + miTest() + } + } + property("mod ops - multiply") { def miTest() = { test("modInverse", env, ext, @@ -365,17 +424,11 @@ class BasicOpsSpecification extends CompilerTestingCommons T s = proof.getS(); BigInteger q = params.getGroup().groupOrder(); - BigInteger y; - - if (salt.isPresent()) { - y = ProofUtils.computeChallenge(q, salt.get(), input, a, s); - } else { - y = ProofUtils.computeChallenge(q, input, a, s); + BigInteger y = ProofUtils.computeChallenge(q, input, a, s); - } FieldVector ys = FieldVector.from(VectorX.iterate(n, BigInteger.ONE, y::multiply), q); - BigInteger z = ProofUtils.challengeFromints(q, y); + BigInteger z = ProofUtils.challengeFromints(q, y); BigInteger zSquared = z.pow(2).mod(q); BigInteger zCubed = z.pow(3).mod(q); @@ -445,18 +498,19 @@ class BasicOpsSpecification extends CompilerTestingCommons | | val yBytes = sha256(q.toBytes ++ input.getEncoded ++ aI.getEncoded ++ s.getEncoded) | - | val y = byteArrayToBigInt(yBytes) mod q // should be to unsigned bigint + | val y = byteArrayToBigInt(yBytes).toUnsignedMod(q) | - | val z = byteArrayToBigInt(sha256(q.toBytes ++ yBytes)) mod q + | val ys = | - | val zSquared = z * z mod q - | val zCubed = zSquared * z mod q + | val z = byteArrayToBigInt(sha256(q.toBytes ++ yBytes)).toUnsignedMod(q) + | val zSquared = z.multiplyMod(z, q) + | val zCubed = zSquared.multiplyMod(z, q) | - | def times() : // todo: implement + | // def times() : // todo: implement | | // ops needed: modInverse, mod ops | - | sigmaProp(properSignature) + | sigmaProp(zCubed > 0) |}""".stripMargin, null, true From a731962932c40d2e240e4d282ca78c5092e96743 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 5 Jul 2024 22:44:32 +0300 Subject: [PATCH 083/123] simplifying the code --- .../src/main/scala/sigma/VersionContext.scala | 13 ---- .../src/main/scala/sigma/ast/SType.scala | 28 ++++---- .../src/main/scala/sigma/util/Versioned.scala | 27 ------- .../src/main/scala/sigma/ast/methods.scala | 44 +++++++----- .../scala/sigma/data/CSigmaDslBuilder.scala | 6 +- .../scala/sigma/LanguageSpecificationV5.scala | 20 ++++-- .../scala/sigma/LanguageSpecificationV6.scala | 71 ++++++++++--------- .../test/scala/sigma/SigmaDslTesting.scala | 6 +- 8 files changed, 98 insertions(+), 117 deletions(-) delete mode 100644 core/shared/src/main/scala/sigma/util/Versioned.scala diff --git a/core/shared/src/main/scala/sigma/VersionContext.scala b/core/shared/src/main/scala/sigma/VersionContext.scala index ecdcfb5f62..19a4857086 100644 --- a/core/shared/src/main/scala/sigma/VersionContext.scala +++ b/core/shared/src/main/scala/sigma/VersionContext.scala @@ -25,12 +25,6 @@ case class VersionContext(activatedVersion: Byte, ergoTreeVersion: Byte) { /** @return true, if the activated script version of Ergo protocol on the network is * including Evolution update. */ def isV6SoftForkActivated: Boolean = activatedVersion >= V6SoftForkVersion - - /** @return true if another [[VersionContext]] is greater than this. */ - def <= (that: VersionContext): Boolean = { - this.activatedVersion < that.activatedVersion || - (this.activatedVersion == that.activatedVersion && this.ergoTreeVersion <= that.ergoTreeVersion) - } } object VersionContext { @@ -110,11 +104,4 @@ object VersionContext { } } - /** Returns the VersionContext with V5 activation and the given ErgoTree version. */ - def sinceV5AndTreeVersion(treeVersion: Byte): VersionContext = - VersionContext(JitActivationVersion, ergoTreeVersion = treeVersion) - - /** Returns the VersionContext with V6 activation and the given ErgoTree version. */ - def sinceV6AndTreeVersion(treeVersion: Byte): VersionContext = - VersionContext(V6SoftForkVersion, ergoTreeVersion = treeVersion) } diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index 4c0e797066..aa4ad0bccf 100644 --- a/core/shared/src/main/scala/sigma/ast/SType.scala +++ b/core/shared/src/main/scala/sigma/ast/SType.scala @@ -7,7 +7,6 @@ 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.util.Versioned import sigma.{AvlTree, BigInt, Box, Coll, Context, Evaluation, GroupElement, Header, PreHeader, SigmaDslBuilder, SigmaProp, VersionContext} import java.math.BigInteger @@ -141,18 +140,21 @@ object SType { * * The regression tests in `property("MethodCall Codes")` should pass. */ - private val _types: Versioned[Map[Byte, STypeCompanion]] = Versioned({ version => - val v5x = Seq( - SBoolean, SString, STuple, SGroupElement, SSigmaProp, SContext, SGlobal, SHeader, SPreHeader, - SAvlTree, SBox, SOption, SCollection, SBigInt - ) - val v6 = if (version >= VersionContext.V6SoftForkVersion) - Seq(SByte, SShort, SInt, SLong) - else - Seq.empty - (v5x ++ v6).map { t => (t.typeId, t) }.toMap - }) - def types: Map[Byte, STypeCompanion] = _types.get(VersionContext.current.activatedVersion) + private val v5Types = Seq( + SBoolean, SString, STuple, SGroupElement, SSigmaProp, SContext, SGlobal, SHeader, SPreHeader, + SAvlTree, SBox, SOption, SCollection, SBigInt + ) + 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. diff --git a/core/shared/src/main/scala/sigma/util/Versioned.scala b/core/shared/src/main/scala/sigma/util/Versioned.scala deleted file mode 100644 index a3eae2325a..0000000000 --- a/core/shared/src/main/scala/sigma/util/Versioned.scala +++ /dev/null @@ -1,27 +0,0 @@ -package sigma.util - -import sigma.VersionContext - -import scala.reflect.ClassTag - -/** Represents a versioned object that can be created for each supported version. - * The object is created lazily and cached for each version. - * - * @param builder a total function that creates an object for a given version in [0, - * maxVersion] range. - * @param maxVersion the maximum supported version. - */ -case class Versioned[T <: AnyRef: ClassTag](builder: Byte => T, maxVersion: Byte = VersionContext.MaxSupportedScriptVersion) { - private val cache = new Array[T](maxVersion + 1) - - def get(version: Byte): T = { - require(version <= VersionContext.MaxSupportedScriptVersion, s"Not supported version $version") - if (cache(version) == null) { - val v = builder(version) - cache(version) = v - v - } else { - cache(version) - } - } -} diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 136225f256..27112f7ac2 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -5,7 +5,7 @@ import org.ergoplatform.validation._ import sigma._ import sigma.ast.SCollection.{SBooleanArray, SBoxArray, SByteArray, SByteArray2, SHeaderArray} import sigma.ast.SMethod.{MethodCallIrBuilder, MethodCostFunc, javaMethodOf} -import sigma.ast.SType.{TypeCode, paramT, tT} +import sigma.ast.SType.TypeCode import sigma.ast.syntax.{SValue, ValueOps} import sigma.data.ExactIntegral.{ByteIsExactIntegral, IntIsExactIntegral, LongIsExactIntegral, ShortIsExactIntegral} import sigma.data.OverloadHack.Overloaded1 @@ -13,7 +13,6 @@ import sigma.data.{DataValueComparer, KeyValueColl, Nullable, RType, SigmaConsta import sigma.eval.{CostDetails, ErgoTreeEvaluator, TracedCost} import sigma.reflection.RClass import sigma.serialization.CoreByteWriter.ArgInfo -import sigma.util.Versioned import sigma.utils.SparseArrayContainer import scala.annotation.unused @@ -158,23 +157,30 @@ trait MonoTypeMethods extends MethodsContainer { trait SNumericTypeMethods extends MonoTypeMethods { import SNumericTypeMethods.tNum - private val _getMethods = Versioned({ version => - val subst = Map(tNum -> this.ownerType) - val numericMethods = if (version < VersionContext.V6SoftForkVersion) - SNumericTypeMethods.methods.map { m => - m.copy(stype = applySubst(m.stype, subst).asFunc ) - } - else - SNumericTypeMethods.methods.map { m => - m.copy( - objType = this, // associate the method with the concrete numeric type - stype = applySubst(m.stype, subst).asFunc - )} - super.getMethods() ++ numericMethods - }) - - protected override def getMethods(): Seq[SMethod] = - _getMethods.get(VersionContext.current.activatedVersion) + + private val subst = Map(tNum -> this.ownerType) + + private val v5Methods = { + SNumericTypeMethods.methods.map { m => + m.copy(stype = applySubst(m.stype, subst).asFunc) + } + } + + private val v6Methods = { + SNumericTypeMethods.methods.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] = { + if (VersionContext.current.isV6SoftForkActivated) { + super.getMethods() ++ v6Methods + } else { + super.getMethods() ++ v5Methods + } + } } object SNumericTypeMethods extends MethodsContainer { diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index d7b092fc0e..3938feacd3 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -5,13 +5,13 @@ import org.ergoplatform.ErgoBox import org.ergoplatform.validation.ValidationRules import scorex.crypto.hash.{Blake2b256, Sha256} import scorex.utils.Longs -import sigma.ast.{AtLeast, SType, SubstConstants} +import sigma.ast.{AtLeast, SubstConstants} import sigma.crypto.{CryptoConstants, EcPointType, Ecp} import sigma.eval.Extensions.EvalCollOps -import sigma.serialization.{DataSerializer, GroupElementSerializer, SigmaSerializer} +import sigma.serialization.{GroupElementSerializer, SigmaSerializer} import sigma.util.Extensions.BigIntegerOps import sigma.validation.SigmaValidationSettings -import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, Evaluation, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext} +import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext} import java.math.BigInteger diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala index 48f1a3f7ca..592971ac82 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala @@ -10,6 +10,7 @@ import scorex.crypto.authds.{ADKey, ADValue} import scorex.crypto.hash.{Blake2b256, Digest32} import scorex.util.ModifierId import sigma.Extensions.{ArrayOps, CollOps} +import sigma.VersionContext.JitActivationVersion import sigma.ast.ErgoTree.{HeaderType, ZeroHeader} import sigma.ast.SCollection._ import sigma.ast.syntax._ @@ -47,6 +48,11 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => import TestData._ + /** Returns the VersionContext with V5 activation and the given ErgoTree version. */ + def sinceV5AndTreeVersion(treeVersion: Byte): VersionContext = + VersionContext(JitActivationVersion, ergoTreeVersion = treeVersion) + + def upcastCostDetails(tpe: SType) = TracedCost(traceBase :+ TypeBasedCostItem(Upcast, tpe)) def downcastCostDetails(tpe: SType) = TracedCost(traceBase :+ TypeBasedCostItem(Downcast, tpe)) def arithOpsCostDetails(tpe: SType) = CostDetails( @@ -4802,7 +4808,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => })) ), changedFeature( - changedInVersion = VersionContext.sinceV5AndTreeVersion(0), + changedInVersion = sinceV5AndTreeVersion(0), { (x: Context) => x.selfBoxIndex }, { (x: Context) => x.selfBoxIndex }, // see versioning in selfBoxIndex implementation "{ (x: Context) => x.selfBoxIndex }", @@ -5004,7 +5010,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ), changedFeature( - changedInVersion = VersionContext.sinceV5AndTreeVersion(0), + changedInVersion = sinceV5AndTreeVersion(0), scalaFunc = { (x: Context) => // this error is expected in v3.x, v4.x throw expectedError @@ -5978,7 +5984,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) }, changedFeature( - changedInVersion = VersionContext.sinceV5AndTreeVersion(0), + changedInVersion = sinceV5AndTreeVersion(0), (x: Coll[Boolean]) => SigmaDsl.xorOf(x), (x: Coll[Boolean]) => SigmaDsl.xorOf(x), "{ (x: Coll[Boolean]) => xorOf(x) }", @@ -6241,7 +6247,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) }, changedFeature( - changedInVersion = VersionContext.sinceV5AndTreeVersion(0), + changedInVersion = sinceV5AndTreeVersion(0), (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) }", @@ -8811,7 +8817,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => (Some(Long.MaxValue) -> Expected(new ArithmeticException("long overflow"))) ), changedFeature( - changedInVersion = VersionContext.sinceV5AndTreeVersion(0), + changedInVersion = sinceV5AndTreeVersion(0), scalaFunc = { (x: Option[Long]) => def f(opt: Long): Long = n.plus(opt, 1) if (x.isDefined) f(x.get) @@ -9367,7 +9373,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) }, changedFeature( - changedInVersion = VersionContext.sinceV5AndTreeVersion(0), + changedInVersion = sinceV5AndTreeVersion(0), { (x: (Coll[Byte], Int)) => SigmaDsl.substConstants(x._1, Coll[Int](x._2), Coll[Any](SigmaDsl.sigmaProp(false))(sigma.AnyType)) }, @@ -9430,7 +9436,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ), changedFeature( - changedInVersion = VersionContext.sinceV5AndTreeVersion(0), + changedInVersion = sinceV5AndTreeVersion(0), { (x: Context) => throw error true diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 6eb3dc4c11..3848e3268f 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -1,6 +1,7 @@ package sigma import org.ergoplatform.sdk.utils.ErgoTreeUtils +import sigma.VersionContext.V6SoftForkVersion import sigma.ast.ErgoTree.ZeroHeader import sigma.ast.SCollection.SByteArray import sigma.ast.syntax.TrueSigmaProp @@ -24,6 +25,10 @@ import scala.util.Success class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => override def languageVersion: Byte = VersionContext.V6SoftForkVersion + /** Returns the VersionContext with V6 activation and the given ErgoTree version. */ + def sinceV6AndTreeVersion(treeVersion: Byte): VersionContext = + VersionContext(V6SoftForkVersion, ergoTreeVersion = treeVersion) + 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) @@ -31,7 +36,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => property("Boolean.toByte") { val toByte = newFeature((x: Boolean) => x.toByte, "{ (x: Boolean) => x.toByte }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0) + sinceVersion = sinceV6AndTreeVersion(0) ) val cases = Seq( @@ -57,22 +62,22 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => // which is checked below lazy val toAbs = newFeature((x: Byte) => x.toAbs, "{ (x: Byte) => x.toAbs }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val compareTo = newFeature( (x: (Byte, Byte)) => x._1.compareTo(x._2), "{ (x: (Byte, Byte)) => x._1.compareTo(x._2) }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val bitOr = newFeature( { (x: (Byte, Byte)) => (x._1 | x._2).toByteExact }, "{ (x: (Byte, Byte)) => (x._1 | x._2) }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val bitAnd = newFeature( { (x: (Byte, Byte)) => (x._1 & x._2).toByteExact }, "{ (x: (Byte, Byte)) => (x._1 & x._2) }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) forAll { x: Byte => Seq(toAbs).foreach(f => f.checkEquality(x)) @@ -91,21 +96,21 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => // which is checked below lazy val toAbs = newFeature((x: Short) => x.toAbs, "{ (x: Short) => x.toAbs }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val compareTo = newFeature((x: (Short, Short)) => x._1.compareTo(x._2), "{ (x: (Short, Short)) => x._1.compareTo(x._2) }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val bitOr = newFeature( { (x: (Short, Short)) => (x._1 | x._2).toShortExact }, "{ (x: (Short, Short)) => x._1 | x._2 }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val bitAnd = newFeature( { (x: (Short, Short)) => (x._1 & x._2).toShortExact }, "{ (x: (Short, Short)) => x._1 & x._2 }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) forAll { x: Short => Seq(toAbs).foreach(_.checkEquality(x)) @@ -121,18 +126,18 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => // NOTE, for such versions the new features are not supported // which is checked below lazy val toAbs = newFeature((x: Int) => x.toAbs, "{ (x: Int) => x.toAbs }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val compareTo = newFeature((x: (Int, Int)) => x._1.compareTo(x._2), "{ (x: (Int, Int)) => x._1.compareTo(x._2) }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val bitOr = newFeature( { (x: (Int, Int)) => x._1 | x._2 }, "{ (x: (Int, Int)) => x._1 | x._2 }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val bitAnd = newFeature( { (x: (Int, Int)) => x._1 & x._2 }, "{ (x: (Int, Int)) => x._1 & x._2 }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) forAll { x: Int => Seq(toAbs).foreach(_.checkEquality(x)) } @@ -147,20 +152,20 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => // NOTE, for such versions the new features are not supported // which is checked below lazy val toAbs = newFeature((x: Long) => x.toAbs, "{ (x: Long) => x.toAbs }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val compareTo = newFeature((x: (Long, Long)) => x._1.compareTo(x._2), "{ (x: (Long, Long)) => x._1.compareTo(x._2) }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val bitOr = newFeature( { (x: (Long, Long)) => x._1 | x._2 }, "{ (x: (Long, Long)) => x._1 | x._2 }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val bitAnd = newFeature( { (x: (Long, Long)) => x._1 & x._2 }, "{ (x: (Long, Long)) => x._1 & x._2 }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) forAll { x: Long => Seq(toAbs).foreach(_.checkEquality(x)) @@ -195,30 +200,30 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => val toByte = newFeature((x: BigInt) => x.toByte, "{ (x: BigInt) => x.toByte }", FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SByte)), - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) val toShort = newFeature((x: BigInt) => x.toShort, "{ (x: BigInt) => x.toShort }", FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SShort)), - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) val toInt = newFeature((x: BigInt) => x.toInt, "{ (x: BigInt) => x.toInt }", FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SInt)), - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) val toLong = newFeature((x: BigInt) => x.toLong, "{ (x: BigInt) => x.toLong }", FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SLong)), - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val toAbs = newFeature((x: BigInt) => x.toAbs, "{ (x: BigInt) => x.toAbs }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val compareTo = newFeature((x: (BigInt, BigInt)) => x._1.compareTo(x._2), "{ (x: (BigInt, BigInt)) => x._1.compareTo(x._2) }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val bitOr = newFeature({ (x: (BigInt, BigInt)) => x._1 | x._2 }, "{ (x: (BigInt, BigInt)) => x._1 | x._2 }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) lazy val bitAnd = newFeature({ (x: (BigInt, BigInt)) => x._1 & x._2 }, "{ (x: (BigInt, BigInt)) => x._1 & x._2 }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) forAll { x: BigInt => Seq(toByte, toShort, toInt, toLong, toAbs).foreach(_.checkEquality(x)) @@ -233,7 +238,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => // 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 }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -249,7 +254,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => 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 = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -268,7 +273,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => if (x.size > 2) x.slice(0, x.size - 2) else Colls.emptyColl[Boolean] }, "{ (x: Coll[Boolean]) => x >> 2 }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -284,7 +289,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => 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 = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -301,7 +306,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => 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 = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -317,7 +322,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => property("allZK equivalence") { lazy val allZK = newFeature((x: Coll[SigmaProp]) => SigmaDsl.allZK(x), "{ (x: Coll[SigmaProp]) => allZK(x) }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -333,7 +338,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => property("anyZK equivalence") { lazy val anyZK = newFeature((x: Coll[SigmaProp]) => SigmaDsl.anyZK(x), "{ (x: Coll[SigmaProp]) => anyZK(x) }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions getReg is not supported @@ -349,7 +354,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => lazy val toBytes = newFeature( { (x: Byte) => x.toBigEndianBytes }, "{ (x: Byte) => x.toBytes }", - sinceVersion = VersionContext.sinceV6AndTreeVersion(0)) + sinceVersion = sinceV6AndTreeVersion(0)) val cases = Seq( (0.toByte, Success(Coll(0.toByte))), (1.toByte, Success(Coll(1.toByte))) diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index 0b512d1380..33c4708942 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -868,8 +868,10 @@ class SigmaDslTesting extends AnyPropSpec )(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 = - sinceVersion <= vc + override def isSupportedIn(vc: VersionContext): Boolean = { + sinceVersion.activatedVersion < vc.activatedVersion || + (sinceVersion.activatedVersion == vc.activatedVersion && sinceVersion.ergoTreeVersion <= vc.ergoTreeVersion) + } override def scalaFunc: A => B = { x => sys.error(s"Semantic Scala function is not defined for old implementation: $this") From cb7e26209ee2608a7c36657e8e37279a8a48a2a6 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sat, 6 Jul 2024 22:15:09 +0300 Subject: [PATCH 084/123] initial toBits failing tests --- .../sigmastate/utxo/BasicOpsSpecification.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 79701d6e07..f6f8399aeb 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -3,6 +3,7 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ import sigma.Extensions.ArrayOps +import sigma.VersionContext import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder} @@ -135,6 +136,20 @@ class BasicOpsSpecification extends CompilerTestingCommons flexVerifier.verify(verifyEnv, tree, ctxExt, pr.proof, fakeMessage).get._1 shouldBe true } + property("BigInt.toBits") { + def toBitsTest() = test("R1", env, ext, + """{ + | val b = 1.toBigInt + | b.toBits == Coll(true) + |}""".stripMargin, + null + ) + + if(VersionContext.current.isV6SoftForkActivated) { + toBitsTest() + } + } + property("Unit register") { // TODO frontend: implement missing Unit support in compiler // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820 From f577fd359fe310d61c9a19b1c5bdbc996e1e96cb Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 8 Jul 2024 10:59:16 +0300 Subject: [PATCH 085/123] passing test (compilation fixed) --- .../scala/sigma/compiler/ir/TreeBuilding.scala | 6 +++++- .../compiler/ir/primitives/NumericOps.scala | 5 +++-- .../sigmastate/utxo/BasicOpsSpecification.scala | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala index f7daff90ae..4894940ef6 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala @@ -186,7 +186,11 @@ trait TreeBuilding extends Base { 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) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala index ef4124d0b5..80a2560d0f 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala @@ -71,8 +71,9 @@ trait NumericOps extends Base { self: IRContext => /** 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] = - n.toBigEndianBytes(x).asInstanceOf[Coll[Byte]] + override def applySeq(x: T): Coll[Byte] = { + liftableColl(Liftables.ByteIsLiftable).lift(n.toBigEndianBytes(x)) + } } /** Descriptor of binary `/` operation (integral division). */ diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 79701d6e07..f88e821e9e 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -3,6 +3,7 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ import sigma.Extensions.ArrayOps +import sigma.VersionContext import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder} @@ -157,6 +158,22 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } + property("Long.toBytes") { + def toBytesTest() = test("Long.toBytes", env, ext, + """{ + | val l = 1L + | l.toBytes.size > 0 + | }""".stripMargin, + null + ) + + if (VersionContext.current.isV6SoftForkActivated) { + toBytesTest() + } else { + an[Exception] shouldBe thrownBy(toBytesTest()) + } + } + property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", From cadf53d8e4439cfc2427183bd56069407304a37c Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 8 Jul 2024 11:10:23 +0300 Subject: [PATCH 086/123] tests for Byte and BigInt --- .../utxo/BasicOpsSpecification.scala | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index f88e821e9e..de30a6f509 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -158,11 +158,44 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } - property("Long.toBytes") { - def toBytesTest() = test("Long.toBytes", env, ext, + property("Int.toBytes") { + def toBytesTest() = test("Int.toBytes", env, ext, """{ - | val l = 1L - | l.toBytes.size > 0 + | val l = 1 + | l.toBytes == Coll(0.toByte, 0.toByte, 0.toByte, 1.toByte) + | }""".stripMargin, + null + ) + + if (VersionContext.current.isV6SoftForkActivated) { + toBytesTest() + } else { + an[Exception] shouldBe thrownBy(toBytesTest()) + } + } + + property("Byte.toBytes") { + def toBytesTest() = test("Byte.toBytes", env, ext, + """{ + | val l = 10.toByte + | l.toBytes == Coll(10.toByte) + | }""".stripMargin, + null + ) + + if (VersionContext.current.isV6SoftForkActivated) { + toBytesTest() + } else { + an[Exception] 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 ) From ee59083d9ada7e8ea51b7ad728cc6ada74089c7c Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 8 Jul 2024 13:35:48 +0300 Subject: [PATCH 087/123] Byte.toBits test passing --- .../src/main/scala/sigma/data/BigIntegerOps.scala | 2 ++ .../src/main/scala/sigma/data/ExactIntegral.scala | 11 +++++++++++ .../src/main/scala/sigma/data/ExactNumeric.scala | 2 ++ .../main/scala/sigma/compiler/ir/GraphBuilding.scala | 3 +++ .../main/scala/sigma/compiler/ir/TreeBuilding.scala | 7 +++++++ .../sigma/compiler/ir/primitives/NumericOps.scala | 8 ++++++++ .../sigmastate/utxo/BasicOpsSpecification.scala | 12 +++++++----- 7 files changed, 40 insertions(+), 5 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala index 0bb9e9101b..788915a1e8 100644 --- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala +++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala @@ -92,6 +92,8 @@ object NumericOps { 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 toBits(x: BigInt): Coll[Boolean] = ??? } /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */ diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index eaf89947c1..ad01e34dc3 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -39,6 +39,13 @@ object ExactIntegral { 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 toBits(x: Byte): Coll[Boolean] = { + def byte2Bools(b: Byte): Array[Boolean] = (0 to 7).toArray.reverse.map(isBitSet(b)) + + def isBitSet(byte: Byte)(bit: Int): Boolean = ((byte >> bit) & 1) == 1 + + Colls.fromArray(byte2Bools(x)) + } } implicit object ShortIsExactIntegral extends ExactIntegral[Short] { @@ -47,6 +54,7 @@ object ExactIntegral { 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 toBits(x: Short): Coll[Boolean] = ??? } implicit object IntIsExactIntegral extends ExactIntegral[Int] { @@ -56,6 +64,7 @@ object ExactIntegral { 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 toBits(x: Int): Coll[Boolean] = ??? } implicit object LongIsExactIntegral extends ExactIntegral[Long] { @@ -65,5 +74,7 @@ object ExactIntegral { 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 toBits(x: Long): Coll[Boolean] = ??? } } diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index d8b3b5df0d..166e8d4fd1 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -37,6 +37,8 @@ trait ExactNumeric[T] { */ def toBigEndianBytes(x: T): Coll[Byte] + def toBits(x: T): Coll[Boolean] + /** A value of type T which corresponds to integer 0. */ lazy val zero: T = fromInt(0) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index 5595ded3db..67bd0e37f3 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1153,6 +1153,9 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => 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 _ => throwError() } case _ => throwError(s"Type ${stypeToRType(obj.tpe).name} doesn't have methods") diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala index 4894940ef6..0da5f332cc 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala @@ -113,6 +113,13 @@ trait TreeBuilding extends Base { IR: IRContext => 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 _ => None } } diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala index 80a2560d0f..543bd708c9 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala @@ -76,6 +76,14 @@ trait NumericOps extends Base { self: IRContext => } } + /** Descriptor of unary `ToBigEndianBytes` 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 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/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 28886ba6c6..1380de5f72 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -136,17 +136,19 @@ class BasicOpsSpecification extends CompilerTestingCommons flexVerifier.verify(verifyEnv, tree, ctxExt, pr.proof, fakeMessage).get._1 shouldBe true } - property("BigInt.toBits") { - def toBitsTest() = test("R1", env, ext, + property("Byte.toBits") { + def toBitsTest() = test("Byte.toBits", env, ext, """{ - | val b = 1.toBigInt - | b.toBits == Coll(true) + | val b = 1.toByte + | b.toBits == Coll(false, false, false, false, false, false, false, true) |}""".stripMargin, null ) - if(VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV6SoftForkActivated) { toBitsTest() + } else { + an[Exception] shouldBe thrownBy(toBitsTest()) } } From 3fde5faf34368843d9bcc1e2199217b378ccb1e3 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 8 Jul 2024 19:43:08 +0300 Subject: [PATCH 088/123] toBits tests for Long and BigInt(failing) --- .../main/scala/sigma/data/BigIntegerOps.scala | 2 -- .../main/scala/sigma/data/ExactIntegral.scala | 11 ------ .../main/scala/sigma/data/ExactNumeric.scala | 19 ++++++++-- .../utxo/BasicOpsSpecification.scala | 36 +++++++++++++++++++ 4 files changed, 53 insertions(+), 15 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala index 788915a1e8..0bb9e9101b 100644 --- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala +++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala @@ -92,8 +92,6 @@ object NumericOps { 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 toBits(x: BigInt): Coll[Boolean] = ??? } /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */ diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index ad01e34dc3..eaf89947c1 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -39,13 +39,6 @@ object ExactIntegral { 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 toBits(x: Byte): Coll[Boolean] = { - def byte2Bools(b: Byte): Array[Boolean] = (0 to 7).toArray.reverse.map(isBitSet(b)) - - def isBitSet(byte: Byte)(bit: Int): Boolean = ((byte >> bit) & 1) == 1 - - Colls.fromArray(byte2Bools(x)) - } } implicit object ShortIsExactIntegral extends ExactIntegral[Short] { @@ -54,7 +47,6 @@ object ExactIntegral { 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 toBits(x: Short): Coll[Boolean] = ??? } implicit object IntIsExactIntegral extends ExactIntegral[Int] { @@ -64,7 +56,6 @@ object ExactIntegral { 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 toBits(x: Int): Coll[Boolean] = ??? } implicit object LongIsExactIntegral extends ExactIntegral[Long] { @@ -74,7 +65,5 @@ object ExactIntegral { 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 toBits(x: Long): Coll[Boolean] = ??? } } diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index 166e8d4fd1..93bc577e14 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -1,8 +1,10 @@ package sigma.data -import sigma.Coll +import sigma.{Coll, Colls} import sigma.data.ExactIntegral._ +import scala.collection.mutable + /** Numeric operations with overflow checks. * Raise exception when overflow is detected. * Each instance of this typeclass overrides three methods `plus`, `minus`, `times`. @@ -37,7 +39,20 @@ trait ExactNumeric[T] { */ def toBigEndianBytes(x: T): Coll[Byte] - def toBits(x: T): Coll[Boolean] + def toBits(x: T): Coll[Boolean] = { + def byte2Bools(b: Byte): Array[Boolean] = (0 to 7).toArray.reverse.map(isBitSet(b)) + + def isBitSet(byte: Byte)(bit: Int): Boolean = ((byte >> bit) & 1) == 1 + + val bytes = toBigEndianBytes(x) + val builder = mutable.ArrayBuilder.make[Boolean] + val l = bytes.length + (0 until l).foreach{i=> + val b = bytes(i) + builder.addAll(byte2Bools(b)) + } + Colls.fromArray(builder.result()) + } /** A value of type T which corresponds to integer 0. */ lazy val zero: T = fromInt(0) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 1380de5f72..85e61b31d1 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -152,6 +152,42 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("Long.toBits") { + def toBitsTest() = test("Long.toBits", env, ext, + """{ + | val b = 1L + | 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[Exception] 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[Exception] shouldBe thrownBy(toBitsTest()) + } + } + property("Unit register") { // TODO frontend: implement missing Unit support in compiler // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820 From 9ea75971dac5118e0cb90ecdddf88f2efd92e562 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 8 Jul 2024 19:50:07 +0300 Subject: [PATCH 089/123] BigInt.toBits test passing --- data/shared/src/main/scala/sigma/ast/methods.scala | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 27112f7ac2..7ac65a4613 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -8,6 +8,7 @@ import sigma.ast.SMethod.{MethodCallIrBuilder, MethodCostFunc, javaMethodOf} import sigma.ast.SType.TypeCode 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} @@ -258,6 +259,15 @@ 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. From be77315def76163c44006430bfba2d6f7e4e933a Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 9 Jul 2024 19:12:59 +0300 Subject: [PATCH 090/123] bitwise inversion --- .../src/main/scala/sigma/ast/methods.scala | 23 ++++++++++++++++++- .../main/scala/sigma/data/BigIntegerOps.scala | 2 ++ .../main/scala/sigma/data/ExactIntegral.scala | 4 ++++ .../main/scala/sigma/data/ExactNumeric.scala | 2 ++ .../sigma/compiler/ir/GraphBuilding.scala | 3 +++ .../sigma/compiler/ir/TreeBuilding.scala | 7 ++++++ .../compiler/ir/primitives/NumericOps.scala | 7 +++++- .../utxo/BasicOpsSpecification.scala | 18 +++++++++++++++ 8 files changed, 64 insertions(+), 2 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 7ac65a4613..22ba217d5f 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -273,6 +273,26 @@ object SNumericTypeMethods extends MethodsContainer { | Each boolean corresponds to one bit. """.stripMargin) + /** Cost of inverting bits of a number. */ + val BitwiseInverse_CostKind = FixedCost(JitCost(5)) + + val BitwiseInverseMethod: SMethod = SMethod( + this, "bitwiseInverse", SFunc(tNum, tNum), 8, BitwiseInverse_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, + """ 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( ToByteMethod, // see Downcast ToShortMethod, // see Downcast @@ -280,7 +300,8 @@ object SNumericTypeMethods extends MethodsContainer { ToLongMethod, // see Downcast ToBigIntMethod, // see Downcast ToBytesMethod, - ToBitsMethod + ToBitsMethod, + BitwiseInverseMethod ) /** Collection of names of numeric casting methods (like `toByte`, `toInt`, etc). */ diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala index 0bb9e9101b..723e6a6691 100644 --- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala +++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala @@ -92,6 +92,8 @@ object NumericOps { 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()) } /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */ diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index eaf89947c1..7242259480 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -39,6 +39,7 @@ object ExactIntegral { 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 } implicit object ShortIsExactIntegral extends ExactIntegral[Short] { @@ -47,6 +48,7 @@ object ExactIntegral { 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 } implicit object IntIsExactIntegral extends ExactIntegral[Int] { @@ -56,6 +58,7 @@ object ExactIntegral { 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 } implicit object LongIsExactIntegral extends ExactIntegral[Long] { @@ -65,5 +68,6 @@ object ExactIntegral { 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 } } diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index 93bc577e14..7809ec4ca6 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -54,6 +54,8 @@ trait ExactNumeric[T] { Colls.fromArray(builder.result()) } + def bitwiseInverse(x: T): T + /** A value of type T which corresponds to integer 0. */ lazy val zero: T = fromInt(0) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index 67bd0e37f3..fcde26e0d5 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1156,6 +1156,9 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => 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 _ => throwError() } case _ => throwError(s"Type ${stypeToRType(obj.tpe).name} doesn't have methods") diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala index 0da5f332cc..c671726507 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala @@ -120,6 +120,13 @@ trait TreeBuilding extends Base { IR: IRContext => 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 } } diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala index 543bd708c9..a9f0c0a3fa 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala @@ -76,7 +76,7 @@ trait NumericOps extends Base { self: IRContext => } } - /** Descriptor of unary `ToBigEndianBytes` conversion operation. */ + /** 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] = { @@ -84,6 +84,11 @@ trait NumericOps extends Base { self: IRContext => } } + /** Descriptor of unary `ToBits` 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/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 85e61b31d1..570a1b76d7 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -2,6 +2,7 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ +import org.scalatest.Assertion import sigma.Extensions.ArrayOps import sigma.VersionContext import sigma.ast.SCollection.SByteArray @@ -188,6 +189,23 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + 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[Exception] shouldBe thrownBy(bitwiseInverseTest()) + } + } + property("Unit register") { // TODO frontend: implement missing Unit support in compiler // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820 From a575d38a1b874cb9b87d3bdfb5610f918ed39868 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 9 Jul 2024 19:41:04 +0300 Subject: [PATCH 091/123] bitwiseInverse tests for Long and Byte --- .../utxo/BasicOpsSpecification.scala | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 570a1b76d7..c9e05f5226 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -206,6 +206,39 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("Byte.bitwiseInverse") { + def bitwiseInverseTest(): Assertion = test("Byte.bitwiseInverse", env, ext, + s"""{ + | val b = 127.toByte + | b.bitwiseInverse == (-128).toByte + |}""".stripMargin, + null + ) + + if (VersionContext.current.isV6SoftForkActivated) { + bitwiseInverseTest() + } else { + an[Exception] shouldBe thrownBy(bitwiseInverseTest()) + } + } + + property("Long.bitwiseInverse") { + def bitwiseInverseTest(): Assertion = test("Long.bitwiseInverse", env, ext, + s"""{ + | val l = 9223372036854775807L + | val lb = l.bitwiseInverse + | lb.bitwiseInverse == l + |}""".stripMargin, + null + ) + + if (VersionContext.current.isV6SoftForkActivated) { + bitwiseInverseTest() + } else { + an[Exception] shouldBe thrownBy(bitwiseInverseTest()) + } + } + property("Unit register") { // TODO frontend: implement missing Unit support in compiler // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820 From 7ff35428b87d6bdee060a390f84a212728738b38 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 10 Jul 2024 12:34:10 +0300 Subject: [PATCH 092/123] bitwise or impl --- .../src/main/scala/sigma/ast/methods.scala | 54 ++++++++++++++++++- .../main/scala/sigma/data/BigIntegerOps.scala | 2 + .../main/scala/sigma/data/ExactIntegral.scala | 4 ++ .../main/scala/sigma/data/ExactNumeric.scala | 2 + .../sigma/compiler/ir/GraphBuilding.scala | 4 ++ .../sigma/compiler/ir/TreeBuilding.scala | 7 +++ .../compiler/ir/primitives/NumericOps.scala | 5 ++ .../utxo/BasicOpsSpecification.scala | 35 +++++++++++- 8 files changed, 111 insertions(+), 2 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 22ba217d5f..ade482c168 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -293,6 +293,57 @@ object SNumericTypeMethods extends MethodsContainer { | Each boolean corresponds to one bit. """.stripMargin) + val BitwiseOrMethod: SMethod = SMethod( + this, "bitwiseOr", SFunc(Array(tNum, tNum), tNum), 9, BitwiseInverse_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(PropertyCall, + """ Returns a big-endian representation of this numeric in a collection of Booleans. + | Each boolean corresponds to one bit. + """.stripMargin) + + val BitwiseAndMethod: SMethod = SMethod( + this, "bitwiseInverse", SFunc(tNum, tNum), 10, BitwiseInverse_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, + """ Returns a big-endian representation of this numeric in a collection of Booleans. + | Each boolean corresponds to one bit. + """.stripMargin) + + val BitwiseXorMethod: SMethod = SMethod( + this, "bitwiseInverse", SFunc(tNum, tNum), 11, BitwiseInverse_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, + """ 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( ToByteMethod, // see Downcast ToShortMethod, // see Downcast @@ -301,7 +352,8 @@ object SNumericTypeMethods extends MethodsContainer { ToBigIntMethod, // see Downcast ToBytesMethod, ToBitsMethod, - BitwiseInverseMethod + BitwiseInverseMethod, + BitwiseOrMethod ) /** Collection of names of numeric casting methods (like `toByte`, `toInt`, etc). */ diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala index 723e6a6691..8a7d597ed0 100644 --- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala +++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala @@ -94,6 +94,8 @@ object NumericOps { override def toBigEndianBytes(x: BigInt): Coll[Byte] = Colls.fromArray(x.toBigInteger.toByteArray) override def bitwiseInverse(x: BigInt): BigInt = CBigInt(x.toBigInteger.not()) + + def bitwiseOr(x: BigInt, y: BigInt): BigInt = CBigInt(x.toBigInteger.or(y.toBigInteger)) } /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */ diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index 7242259480..787800a14a 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -40,6 +40,7 @@ object ExactIntegral { 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 } implicit object ShortIsExactIntegral extends ExactIntegral[Short] { @@ -49,6 +50,7 @@ object ExactIntegral { 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 } implicit object IntIsExactIntegral extends ExactIntegral[Int] { @@ -59,6 +61,7 @@ object ExactIntegral { 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 } implicit object LongIsExactIntegral extends ExactIntegral[Long] { @@ -69,5 +72,6 @@ object ExactIntegral { 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 } } diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index 7809ec4ca6..8328ac4143 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -56,6 +56,8 @@ trait ExactNumeric[T] { def bitwiseInverse(x: T): T + def bitwiseOr(x: T, y: T): T + /** A value of type T which corresponds to integer 0. */ lazy val zero: T = fromInt(0) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index fcde26e0d5..cfa67f40a4 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1159,6 +1159,10 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => 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 _ => throwError() } case _ => throwError(s"Type ${stypeToRType(obj.tpe).name} doesn't have methods") diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala index c671726507..9fa4f80208 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala @@ -217,6 +217,13 @@ trait TreeBuilding extends Base { 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(IsArithOp(opCode), xSym, ySym)) => val Seq(x, y) = Seq(xSym, ySym).map(recurse) mkArith(x.asNumValue, y.asNumValue, opCode) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala index a9f0c0a3fa..6c77b02fdf 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala @@ -47,6 +47,11 @@ trait NumericOps extends Base { self: IRContext => 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) + } + /** 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 diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index c9e05f5226..b87121e4e4 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -209,7 +209,7 @@ class BasicOpsSpecification extends CompilerTestingCommons property("Byte.bitwiseInverse") { def bitwiseInverseTest(): Assertion = test("Byte.bitwiseInverse", env, ext, s"""{ - | val b = 127.toByte + | val b = (126 + 1).toByte // max byte value | b.bitwiseInverse == (-128).toByte |}""".stripMargin, null @@ -239,6 +239,39 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("Byte.bitwiseOr") { + def bitwiseOrTest(): Assertion = test("Byte.bitwiseOrTest", env, ext, + s"""{ + | val x = 127.toByte + | val y = (-128).toByte + | x.bitwiseOr(y) == -1 + |}""".stripMargin, + null + ) + + if (VersionContext.current.isV6SoftForkActivated) { + bitwiseOrTest() + } else { + an[Exception] shouldBe thrownBy(bitwiseOrTest()) + } + } + + property("BigInt.bitwiseOr") { + def bitwiseInverseTest(): Assertion = test("BigInt.bitwiseInverse", env, ext, + s"""{ + | val x = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}") + | x.bitwiseOr(x) == x + |}""".stripMargin, + null + ) + + if (VersionContext.current.isV6SoftForkActivated) { + bitwiseInverseTest() + } else { + an[Exception] shouldBe thrownBy(bitwiseInverseTest()) + } + } + property("Unit register") { // TODO frontend: implement missing Unit support in compiler // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820 From 868fbb10c43626faec175698bf94e8f1b9dc3908 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 10 Jul 2024 15:24:19 +0300 Subject: [PATCH 093/123] bitwiseAnd --- .../src/main/scala/sigma/ast/methods.scala | 17 ++++---- .../main/scala/sigma/data/BigIntegerOps.scala | 2 + .../main/scala/sigma/data/ExactIntegral.scala | 4 ++ .../main/scala/sigma/data/ExactNumeric.scala | 2 + .../sigma/compiler/ir/GraphBuilding.scala | 4 ++ .../sigma/compiler/ir/TreeBuilding.scala | 6 +++ .../compiler/ir/primitives/NumericOps.scala | 4 ++ .../utxo/BasicOpsSpecification.scala | 41 +++++++++++++++++-- 8 files changed, 69 insertions(+), 11 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index ade482c168..003b9923e0 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -311,15 +311,15 @@ object SNumericTypeMethods extends MethodsContainer { """.stripMargin) val BitwiseAndMethod: SMethod = SMethod( - this, "bitwiseInverse", SFunc(tNum, tNum), 10, BitwiseInverse_CostKind) + this, "bitwiseAnd", SFunc(Array(tNum, tNum), tNum), 10, BitwiseInverse_CostKind) .withIRInfo(MethodCallIrBuilder) - .withUserDefinedInvoke({ (m: SMethod, obj: Any, _: Array[Any]) => + .withUserDefinedInvoke({ (m: SMethod, obj: Any, other: 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]) + 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(PropertyCall, @@ -353,7 +353,8 @@ object SNumericTypeMethods extends MethodsContainer { ToBytesMethod, ToBitsMethod, BitwiseInverseMethod, - BitwiseOrMethod + BitwiseOrMethod, + BitwiseAndMethod ) /** Collection of names of numeric casting methods (like `toByte`, `toInt`, etc). */ diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala index 8a7d597ed0..2aefe1cbc8 100644 --- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala +++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala @@ -96,6 +96,8 @@ object NumericOps { override def bitwiseInverse(x: BigInt): BigInt = CBigInt(x.toBigInteger.not()) def bitwiseOr(x: BigInt, y: BigInt): BigInt = CBigInt(x.toBigInteger.or(y.toBigInteger)) + + def bitwiseAnd(x: BigInt, y: BigInt): BigInt = CBigInt(x.toBigInteger.and(y.toBigInteger)) } /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */ diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index 787800a14a..490890e21a 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -41,6 +41,7 @@ object ExactIntegral { 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 } implicit object ShortIsExactIntegral extends ExactIntegral[Short] { @@ -51,6 +52,7 @@ object ExactIntegral { 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 } implicit object IntIsExactIntegral extends ExactIntegral[Int] { @@ -62,6 +64,7 @@ object ExactIntegral { 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 } implicit object LongIsExactIntegral extends ExactIntegral[Long] { @@ -73,5 +76,6 @@ object ExactIntegral { 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 } } diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index 8328ac4143..116599ba9b 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -58,6 +58,8 @@ trait ExactNumeric[T] { def bitwiseOr(x: T, y: T): T + def bitwiseAnd(x: T, y: T): T + /** A value of type T which corresponds to integer 0. */ lazy val zero: T = fromInt(0) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index cfa67f40a4..1c467fada8 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1163,6 +1163,10 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => 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 _ => throwError() } case _ => throwError(s"Type ${stypeToRType(obj.tpe).name} doesn't have methods") diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala index 9fa4f80208..e79fb56a2e 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala @@ -223,6 +223,12 @@ trait TreeBuilding extends Base { IR: IRContext => 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(IsArithOp(opCode), xSym, ySym)) => val Seq(x, y) = Seq(xSym, ySym).map(recurse) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala index 6c77b02fdf..13766b17b7 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala @@ -52,6 +52,10 @@ trait NumericOps extends Base { self: IRContext => 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) + } + /** 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 diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index b87121e4e4..0987b84835 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -257,7 +257,7 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("BigInt.bitwiseOr") { - def bitwiseInverseTest(): Assertion = test("BigInt.bitwiseInverse", env, ext, + def bitwiseOrTest(): Assertion = test("BigInt.bitwiseOr", env, ext, s"""{ | val x = bigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}") | x.bitwiseOr(x) == x @@ -266,9 +266,44 @@ class BasicOpsSpecification extends CompilerTestingCommons ) if (VersionContext.current.isV6SoftForkActivated) { - bitwiseInverseTest() + bitwiseOrTest() } else { - an[Exception] shouldBe thrownBy(bitwiseInverseTest()) + an[Exception] 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[Exception] shouldBe thrownBy(bitwiseAndTest()) + } + } + + + property("Short.bitwiseAnd") { + def bitwiseAndTest(): Assertion = test("BigInt.bitwiseAnd", env, ext, + s"""{ + | val x = (32767).toShort + | val y = (-32768).toShort + | x.bitwiseAnd(y) == 0 + |}""".stripMargin, + null + ) + + if (VersionContext.current.isV6SoftForkActivated) { + bitwiseAndTest() + } else { + an[Exception] shouldBe thrownBy(bitwiseAndTest()) } } From f21436d390d197cd12666cf943c2f8ef7e38a296 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 10 Jul 2024 15:37:29 +0300 Subject: [PATCH 094/123] bitwiseXor --- .../src/main/scala/sigma/ast/methods.scala | 18 +++++++++-------- .../main/scala/sigma/data/BigIntegerOps.scala | 2 ++ .../main/scala/sigma/data/ExactIntegral.scala | 4 ++++ .../main/scala/sigma/data/ExactNumeric.scala | 2 ++ .../sigma/compiler/ir/GraphBuilding.scala | 4 ++++ .../sigma/compiler/ir/TreeBuilding.scala | 6 ++++++ .../compiler/ir/primitives/NumericOps.scala | 6 +++++- .../utxo/BasicOpsSpecification.scala | 20 +++++++++++++++++-- 8 files changed, 51 insertions(+), 11 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 003b9923e0..0992788124 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -5,6 +5,7 @@ import org.ergoplatform.validation._ import sigma._ import sigma.ast.SCollection.{SBooleanArray, SBoxArray, SByteArray, SByteArray2, SHeaderArray} import sigma.ast.SMethod.{MethodCallIrBuilder, MethodCostFunc, javaMethodOf} +import sigma.ast.SNumericTypeMethods.BitwiseAndMethod import sigma.ast.SType.TypeCode import sigma.ast.syntax.{SValue, ValueOps} import sigma.data.ExactIntegral.{ByteIsExactIntegral, IntIsExactIntegral, LongIsExactIntegral, ShortIsExactIntegral} @@ -328,15 +329,15 @@ object SNumericTypeMethods extends MethodsContainer { """.stripMargin) val BitwiseXorMethod: SMethod = SMethod( - this, "bitwiseInverse", SFunc(tNum, tNum), 11, BitwiseInverse_CostKind) + this, "bitwiseXor", SFunc(Array(tNum, tNum), tNum), 11, BitwiseInverse_CostKind) .withIRInfo(MethodCallIrBuilder) - .withUserDefinedInvoke({ (m: SMethod, obj: Any, _: Array[Any]) => + .withUserDefinedInvoke({ (m: SMethod, obj: Any, other: 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]) + 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(PropertyCall, @@ -354,7 +355,8 @@ object SNumericTypeMethods extends MethodsContainer { ToBitsMethod, BitwiseInverseMethod, BitwiseOrMethod, - BitwiseAndMethod + BitwiseAndMethod, + BitwiseXorMethod ) /** Collection of names of numeric casting methods (like `toByte`, `toInt`, etc). */ diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala index 2aefe1cbc8..9b50469883 100644 --- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala +++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala @@ -98,6 +98,8 @@ object NumericOps { def bitwiseOr(x: BigInt, y: BigInt): BigInt = CBigInt(x.toBigInteger.or(y.toBigInteger)) def bitwiseAnd(x: BigInt, y: BigInt): BigInt = CBigInt(x.toBigInteger.and(y.toBigInteger)) + + def bitwiseXor(x: BigInt, y: BigInt): BigInt = CBigInt(x.toBigInteger.xor(y.toBigInteger)) } /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */ diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index 490890e21a..58d600d987 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -42,6 +42,7 @@ object ExactIntegral { 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 } implicit object ShortIsExactIntegral extends ExactIntegral[Short] { @@ -53,6 +54,7 @@ object ExactIntegral { 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 } implicit object IntIsExactIntegral extends ExactIntegral[Int] { @@ -65,6 +67,7 @@ object ExactIntegral { 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 } implicit object LongIsExactIntegral extends ExactIntegral[Long] { @@ -77,5 +80,6 @@ object ExactIntegral { 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 } } diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index 116599ba9b..c9903028db 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -60,6 +60,8 @@ trait ExactNumeric[T] { def bitwiseAnd(x: T, y: T): T + def bitwiseXor(x: T, y: T): T + /** A value of type T which corresponds to integer 0. */ lazy val zero: T = fromInt(0) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index 1c467fada8..fa1e6fb8e4 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1167,6 +1167,10 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => 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 _ => throwError() } case _ => throwError(s"Type ${stypeToRType(obj.tpe).name} doesn't have methods") diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala index e79fb56a2e..c0f38b6801 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala @@ -229,6 +229,12 @@ trait TreeBuilding extends Base { IR: IRContext => 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(ApplyBinOp(IsArithOp(opCode), xSym, ySym)) => val Seq(x, y) = Seq(xSym, ySym).map(recurse) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala index 13766b17b7..11f7c6a195 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala @@ -52,10 +52,14 @@ trait NumericOps extends Base { self: IRContext => override def applySeq(x: T, y: T): T = n.bitwiseOr(x, y) } - case class NumericBitwiseAnd[T: Elem](n: ExactNumeric[T]) extends EndoBinOp[T]("|") { + 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) + } + /** 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 diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 0987b84835..e4279f05bc 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -289,9 +289,8 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("Short.bitwiseAnd") { - def bitwiseAndTest(): Assertion = test("BigInt.bitwiseAnd", env, ext, + def bitwiseAndTest(): Assertion = test("Short.bitwiseAnd", env, ext, s"""{ | val x = (32767).toShort | val y = (-32768).toShort @@ -307,6 +306,23 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("Short.bitwiseXor") { + def bitwiseXorTest(): Assertion = test("Short.bitwiseXor", env, ext, + s"""{ + | val x = (32767).toShort + | val y = (-32768).toShort + | x.bitwiseXor(y) == -1 + |}""".stripMargin, + null + ) + + if (VersionContext.current.isV6SoftForkActivated) { + bitwiseXorTest() + } else { + an[Exception] shouldBe thrownBy(bitwiseXorTest()) + } + } + property("Unit register") { // TODO frontend: implement missing Unit support in compiler // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820 From ced229f60e5d1adf9a731d275fc554efd282951e Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 11 Jul 2024 15:38:49 +0300 Subject: [PATCH 095/123] shiftLeft --- .../src/main/scala/sigma/SigmaDsl.scala | 4 ++ .../src/main/scala/sigma/data/CBigInt.scala | 4 ++ .../src/main/scala/sigma/ast/methods.scala | 37 +++++++++- .../main/scala/sigma/data/BigIntegerOps.scala | 8 ++- .../main/scala/sigma/data/ExactIntegral.scala | 4 ++ .../main/scala/sigma/data/ExactNumeric.scala | 2 + .../sigma/compiler/ir/GraphBuilding.scala | 4 ++ .../sigma/compiler/ir/TreeBuilding.scala | 6 ++ .../compiler/ir/primitives/NumericOps.scala | 4 ++ .../compiler/ir/primitives/UnBinOps.scala | 35 ++++++++++ .../utxo/BasicOpsSpecification.scala | 67 +++++++++++++++++++ 11 files changed, 171 insertions(+), 4 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index df2b419273..806d72c908 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -154,6 +154,10 @@ trait BigInt { */ def or(that: BigInt): BigInt def |(that: BigInt): BigInt = or(that) + + def xor(that: BigInt): BigInt + + def shiftLeft(bits: Int): BigInt } /** Base class for points on elliptic curves. */ diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index bbf1a85e46..a22bebbf5b 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -49,4 +49,8 @@ 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)) + + def shiftLeft(bits: Int): BigInt = CBigInt(wrappedValue.shiftLeft(bits).to256BitValueExact) } diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 0992788124..5d21ff1d23 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -345,6 +345,40 @@ object SNumericTypeMethods extends MethodsContainer { | Each boolean corresponds to one bit. """.stripMargin) + val ShiftLeftMethod: SMethod = SMethod( + this, "shiftLeft", SFunc(Array(tNum, SInt), tNum), 12, BitwiseInverse_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(PropertyCall, + """ Returns a big-endian representation of this numeric in a collection of Booleans. + | Each boolean corresponds to one bit. + """.stripMargin) + + val ShiftRightMethod: SMethod = SMethod( + this, "shiftRight", SFunc(Array(tNum, tNum), tNum), 13, BitwiseInverse_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(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( ToByteMethod, // see Downcast ToShortMethod, // see Downcast @@ -356,7 +390,8 @@ object SNumericTypeMethods extends MethodsContainer { BitwiseInverseMethod, BitwiseOrMethod, BitwiseAndMethod, - BitwiseXorMethod + BitwiseXorMethod, + ShiftLeftMethod ) /** Collection of names of numeric casting methods (like `toByte`, `toInt`, etc). */ diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala index 9b50469883..0db7c8fc0b 100644 --- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala +++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala @@ -95,11 +95,13 @@ object NumericOps { override def bitwiseInverse(x: BigInt): BigInt = CBigInt(x.toBigInteger.not()) - def bitwiseOr(x: BigInt, y: BigInt): BigInt = CBigInt(x.toBigInteger.or(y.toBigInteger)) + override def bitwiseOr(x: BigInt, y: BigInt): BigInt = x.or(y) - def bitwiseAnd(x: BigInt, y: BigInt): BigInt = CBigInt(x.toBigInteger.and(y.toBigInteger)) + override def bitwiseAnd(x: BigInt, y: BigInt): BigInt = x.and(y) - def bitwiseXor(x: BigInt, y: BigInt): BigInt = CBigInt(x.toBigInteger.xor(y.toBigInteger)) + override def bitwiseXor(x: BigInt, y: BigInt): BigInt = x.xor(y) + + override def shiftLeft(x: BigInt, y: Int): BigInt = x.shiftLeft(y) } /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */ diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index 58d600d987..a2aa6575f9 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -43,6 +43,7 @@ object ExactIntegral { 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, y: Int): Byte = (x << y).toByte } implicit object ShortIsExactIntegral extends ExactIntegral[Short] { @@ -55,6 +56,7 @@ object ExactIntegral { 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, y: Int): Short = (x << y).toShort } implicit object IntIsExactIntegral extends ExactIntegral[Int] { @@ -68,6 +70,7 @@ object ExactIntegral { 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, y: Int): Int = x << y } implicit object LongIsExactIntegral extends ExactIntegral[Long] { @@ -81,5 +84,6 @@ object ExactIntegral { 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, y: Int): Long = x << y } } diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index c9903028db..0c105c5825 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -62,6 +62,8 @@ trait ExactNumeric[T] { def bitwiseXor(x: T, y: T): T + def shiftLeft(x: T, y: Int): T + /** A value of type T which corresponds to integer 0. */ lazy val zero: T = fromInt(0) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index fa1e6fb8e4..6496198075 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1171,6 +1171,10 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => 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 _ => throwError() } case _ => throwError(s"Type ${stypeToRType(obj.tpe).name} doesn't have methods") diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala index c0f38b6801..1a7621a739 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala @@ -235,6 +235,12 @@ trait TreeBuilding extends Base { IR: IRContext => 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(ApplyBinOp(IsArithOp(opCode), xSym, ySym)) => val Seq(x, y) = Seq(xSym, ySym).map(recurse) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala index 11f7c6a195..d8c495220a 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala @@ -60,6 +60,10 @@ trait NumericOps extends Base { self: IRContext => 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) + } + /** 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 diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/UnBinOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/UnBinOps.scala index 23f8bc3800..62bfc29f68 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/UnBinOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/UnBinOps.scala @@ -45,6 +45,29 @@ trait UnBinOps extends Base { self: IRContext => def shouldPropagate(lhs: A, rhs: A) = true } + 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] @@ -68,6 +91,18 @@ trait UnBinOps extends Base { self: IRContext => 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. */ + 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. */ + 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/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index e4279f05bc..7bd3812443 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -323,6 +323,73 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + 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[Exception] 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) { + shiftLeftTest() + } else { + an[Exception] 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[Exception] 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[Exception] shouldBe thrownBy(shiftLeftTest()) + } + } + property("Unit register") { // TODO frontend: implement missing Unit support in compiler // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820 From 9519ef62c2d7b41163096374a2057c26602905f7 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 16 Jul 2024 21:17:28 +0300 Subject: [PATCH 096/123] shiftRight --- .../src/main/scala/sigma/SigmaDsl.scala | 2 + .../src/main/scala/sigma/data/CBigInt.scala | 2 + .../src/main/scala/sigma/ast/methods.scala | 15 ++- .../main/scala/sigma/data/BigIntegerOps.scala | 2 + .../main/scala/sigma/data/ExactIntegral.scala | 9 +- .../main/scala/sigma/data/ExactNumeric.scala | 6 +- .../sigma/compiler/ir/GraphBuilding.scala | 4 + .../sigma/compiler/ir/TreeBuilding.scala | 6 + .../compiler/ir/primitives/NumericOps.scala | 4 + .../utxo/BasicOpsSpecification.scala | 121 ++++++++++++++++++ 10 files changed, 160 insertions(+), 11 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 806d72c908..6ba84374df 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -158,6 +158,8 @@ trait BigInt { def xor(that: BigInt): BigInt def shiftLeft(bits: Int): BigInt + + def shiftRight(bits: Int): BigInt } /** Base class for points on elliptic curves. */ diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index a22bebbf5b..dbfec02844 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -53,4 +53,6 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr override def xor(that: BigInt): BigInt = CBigInt(wrappedValue.xor(that.asInstanceOf[CBigInt].wrappedValue)) def shiftLeft(bits: Int): BigInt = CBigInt(wrappedValue.shiftLeft(bits).to256BitValueExact) + + def shiftRight(bits: Int): BigInt = CBigInt(wrappedValue.shiftRight(bits).to256BitValueExact) } diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 5d21ff1d23..e7bf6a9bda 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -363,15 +363,15 @@ object SNumericTypeMethods extends MethodsContainer { """.stripMargin) val ShiftRightMethod: SMethod = SMethod( - this, "shiftRight", SFunc(Array(tNum, tNum), tNum), 13, BitwiseInverse_CostKind) + this, "shiftRight", SFunc(Array(tNum, SInt), tNum), 13, BitwiseInverse_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]) + 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(PropertyCall, @@ -391,7 +391,8 @@ object SNumericTypeMethods extends MethodsContainer { BitwiseOrMethod, BitwiseAndMethod, BitwiseXorMethod, - ShiftLeftMethod + ShiftLeftMethod, + ShiftRightMethod ) /** Collection of names of numeric casting methods (like `toByte`, `toInt`, etc). */ diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala index 0db7c8fc0b..2e1d2f62ce 100644 --- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala +++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala @@ -102,6 +102,8 @@ object NumericOps { override def bitwiseXor(x: BigInt, y: BigInt): BigInt = x.xor(y) override def shiftLeft(x: BigInt, y: Int): BigInt = x.shiftLeft(y) + + override def shiftRight(x: BigInt, y: Int): BigInt = x.shiftRight(y) } /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */ diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index a2aa6575f9..418bc1837b 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -43,12 +43,14 @@ object ExactIntegral { 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, y: Int): Byte = (x << y).toByte + override def shiftLeft(x: Byte, bits: Int): Byte = (x << bits).toByte + override def shiftRight(x: Byte, bits: Int): Byte = (x >> bits).toByte } implicit object ShortIsExactIntegral extends ExactIntegral[Short] { val n = scala.math.Numeric.ShortIsIntegral - override def plus(x: Short, y: Short): Short = x.addExact(y) + 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) @@ -57,6 +59,7 @@ object ExactIntegral { 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, y: Int): Short = (x << y).toShort + override def shiftRight(x: Short, bits: Int): Short = (x >> bits).toShort } implicit object IntIsExactIntegral extends ExactIntegral[Int] { @@ -71,6 +74,7 @@ object ExactIntegral { 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, y: Int): Int = x << y + override def shiftRight(x: Int, bits: Int): Int = x >> bits } implicit object LongIsExactIntegral extends ExactIntegral[Long] { @@ -85,5 +89,6 @@ object ExactIntegral { 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, y: Int): Long = x << y + override def shiftRight(x: Long, bits: Int): Long = 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 0c105c5825..214569e6e5 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -1,6 +1,6 @@ package sigma.data -import sigma.{Coll, Colls} +import sigma.{BigInt, Coll, Colls} import sigma.data.ExactIntegral._ import scala.collection.mutable @@ -62,7 +62,9 @@ trait ExactNumeric[T] { def bitwiseXor(x: T, y: T): T - def shiftLeft(x: T, y: Int): T + def shiftLeft(x: T, bits: Int): T + + 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/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index 6496198075..af681fdd2e 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1175,6 +1175,10 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => 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(s"Type ${stypeToRType(obj.tpe).name} doesn't have methods") diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala index 1a7621a739..c218760e24 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala @@ -241,6 +241,12 @@ trait TreeBuilding extends Base { IR: IRContext => 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) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala index d8c495220a..9a6b372033 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala @@ -64,6 +64,10 @@ trait NumericOps extends Base { self: IRContext => 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 diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 7bd3812443..fcd597f7cb 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -390,6 +390,127 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + 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[Exception] 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[Exception] 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) { + shiftRightTest() + } else { + an[Exception] 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[Exception] 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) { + shiftRightTest() + } else { + an[Exception] 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[Exception] 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) { + shiftRightTest() + } else { + an[Exception] shouldBe thrownBy(shiftRightTest()) + } + } + property("Unit register") { // TODO frontend: implement missing Unit support in compiler // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/820 From 4c63a60e981743fd10c29a4b87b8e996ed5b749d Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 30 Jul 2024 19:30:54 +0300 Subject: [PATCH 097/123] LSV5 & LSV6 tests --- .../scala/sigma/LanguageSpecificationV5.scala | 146 +++++++++--------- .../scala/sigma/LanguageSpecificationV6.scala | 60 ++++++- 2 files changed, 134 insertions(+), 72 deletions(-) diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala index 700b48fd13..347a7b90f4 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala @@ -7957,77 +7957,81 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) ) - verifyCases( - // (coll, (index, default)) - { - def success[T](v: T) = Expected(Success(v), 1773, costDetails, 1773) - Seq( - ((Coll[Int](), (0, default)), success(default)), - ((Coll[Int](), (-1, default)), success(default)), - ((Coll[Int](1), (0, default)), success(1)), - ((Coll[Int](1), (1, default)), success(default)), - ((Coll[Int](1), (-1, default)), success(default)), - ((Coll[Int](1, 2), (0, default)), success(1)), - ((Coll[Int](1, 2), (1, default)), success(2)), - ((Coll[Int](1, 2), (2, default)), success(default)), - ((Coll[Int](1, 2), (-1, default)), success(default)) - ) - }, - existingFeature((x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2), - "{ (x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2) }", - if (lowerMethodCallsInTests) - 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 + + if(!VersionContext.current.isV6SoftForkActivated) { + verifyCases( + // (coll, (index, default)) + { + def success[T](v: T) = Expected(Success(v), 1773, costDetails, 1773) + + Seq( + ((Coll[Int](), (0, default)), success(default)), + ((Coll[Int](), (-1, default)), success(default)), + ((Coll[Int](1), (0, default)), success(1)), + ((Coll[Int](1), (1, default)), success(default)), + ((Coll[Int](1), (-1, default)), success(default)), + ((Coll[Int](1, 2), (0, default)), success(1)), + ((Coll[Int](1, 2), (1, default)), success(2)), + ((Coll[Int](1, 2), (2, default)), success(default)), + ((Coll[Int](1, 2), (-1, default)), success(default)) + ) + }, + existingFeature((x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2), + "{ (x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2) }", + if (lowerMethodCallsInTests) + 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 + ) ) - ) - ), - ByIndex( - 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), - Some(SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte)) + ByIndex( + 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), + Some(SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte)) + ) ) ) - ) - else - FuncValue( - Array((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))), - BlockValue( - Array( - ValDef( - 3, - List(), - SelectField.typed[Value[STuple]]( - ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), - 2.toByte + else + FuncValue( + Array((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))), + BlockValue( + Array( + ValDef( + 3, + List(), + SelectField.typed[Value[STuple]]( + ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), + 2.toByte + ) ) - ) - ), - MethodCall.typed[Value[SInt.type]]( - SelectField.typed[Value[SCollection[SInt.type]]]( - ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), - 1.toByte ), - SCollectionMethods.getMethodByName("getOrElse").withConcreteTypes(Map(STypeVar("IV") -> SInt)), - Vector( - SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte), - SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte) - ), - Map() + MethodCall.typed[Value[SInt.type]]( + SelectField.typed[Value[SCollection[SInt.type]]]( + ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), + 1.toByte + ), + SCollectionMethods.getMethodByName("getOrElse").withConcreteTypes(Map(STypeVar("IV") -> SInt)), + Vector( + SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte), + SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte) + ), + Map() + ) ) ) - ) - )) + )) + } } property("Tuple size method equivalence") { @@ -8591,13 +8595,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => "{ (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)), + (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))))) + } verifyCases( Seq( diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 3b3de407b5..612f0e33c3 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -1,8 +1,9 @@ package sigma -import sigma.ast.{Apply, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, JitCost, OptionGet, SBigInt, SByte, SInt, SLong, SShort, ValUse} +import sigma.ast.{Apply, ArithOp, BlockValue, ByIndex, CompanionDesc, Constant, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, IntConstant, JitCost, LongConstant, MethodCall, OptionGet, OptionGetOrElse, PerItemCost, SBigInt, SByte, SCollection, SCollectionMethods, SCollectionType, SInt, SLong, SOption, SPair, SShort, STuple, STypeVar, SelectField, ValDef, ValUse, Value} import sigma.data.{CBigInt, ExactNumeric} -import sigma.eval.SigmaDsl +import sigma.eval.{SigmaDsl, TracedCost} +import sigma.serialization.ValueCodes.OpCode import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} import sigmastate.exceptions.MethodNotFound @@ -168,7 +169,62 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) } } + } + + property("Option.getOrElse with lazy default") { + def getOrElse = newFeature( + { (x: Option[Long]) => x.getOrElse(1 / 0L) }, + "{ (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)) + ) + ) + ) + if (VersionContext.current.isV6SoftForkActivated) { + forAll { x: Option[Long] => + Seq(getOrElse).map(_.checkEquality(x)) + } + } else { + forAll { x: Option[Long] => + if (x.isEmpty) { + Seq(getOrElse).map(_.checkEquality(x)) + } + } + } + } + + property("Coll getOrElse with lazy default") { + def getOrElse = newFeature( + (x: (Coll[Int], Int)) => x._1.toArray.unapply(x._2).getOrElse(1 / 0), + "{ (x: (Coll[Int], Int)) => x._1.getOrElse(x._2, 1 / 0) }", + FuncValue( + Array((1, SPair(SCollectionType(SInt), SInt))), + ByIndex( + SelectField.typed[Value[SCollection[SInt.type]]]( + ValUse(1, SPair(SCollectionType(SInt), SInt)), + 1.toByte + ), + SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SCollectionType(SInt), SInt)), 2.toByte), + Some(ArithOp(IntConstant(1), IntConstant(0), OpCode @@ (-99.toByte))) + ) + ) + ) + + if (VersionContext.current.isV6SoftForkActivated) { + forAll { x: (Coll[Int], Int) => + Seq(getOrElse).map(_.checkEquality(x)) + } + } else { + forAll { x: (Coll[Int], Int) => + if (x._1.isEmpty) { + Seq(getOrElse).map(_.checkEquality(x)) + } + } + } } property("BigInt methods equivalence (new features)") { From 61f90cd339b9a79ce20154f45f3db2980be9dc4c Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 31 Jul 2024 14:04:30 +0300 Subject: [PATCH 098/123] assertEXceptionThrown --- sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala | 2 +- .../test/scala/sigmastate/utxo/BasicOpsSpecification.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 612f0e33c3..b4fb5b12fb 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -199,7 +199,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => property("Coll getOrElse with lazy default") { def getOrElse = newFeature( - (x: (Coll[Int], Int)) => x._1.toArray.unapply(x._2).getOrElse(1 / 0), + (x: (Coll[Int], Int)) => x._1.toArray.toIndexedSeq.unapply(x._2).getOrElse(1 / 0), "{ (x: (Coll[Int], Int)) => x._1.getOrElse(x._2, 1 / 0) }", FuncValue( Array((1, SPair(SCollectionType(SInt), SInt))), diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index c1489355e6..3d25326660 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -170,10 +170,10 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if(VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV6SoftForkActivated) { optTest() } else { - an[Exception] shouldBe thrownBy(optTest()) + assertExceptionThrown(optTest(), _.isInstanceOf[NoSuchElementException]) } } From a20c04fc38ea4cfb700bbfe97f18fc84e00aa516 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 31 Jul 2024 15:29:08 +0300 Subject: [PATCH 099/123] moving to Global, finalizing costing --- .../src/main/scala/sigma/SigmaDsl.scala | 14 +++- .../src/main/scala/sigma/data/CBigInt.scala | 3 - .../sigma/reflection/ReflectionData.scala | 6 +- .../src/main/scala/sigma/ast/methods.scala | 73 +++++++++---------- .../scala/sigma/data/CSigmaDslBuilder.scala | 4 + .../scala/sigma/eval/ErgoTreeEvaluator.scala | 3 - .../interpreter/CErgoTreeEvaluator.scala | 6 -- .../MethodCallSerializerSpecification.scala | 18 ++--- .../scala/sigmastate/eval/BasicOpsTests.scala | 10 +-- .../sigma/compiler/ir/GraphBuilding.scala | 10 +-- .../ir/wrappers/sigma/SigmaDslUnit.scala | 2 +- .../ir/wrappers/sigma/impl/SigmaDslImpl.scala | 30 ++++---- .../TestingInterpreterSpecification.scala | 3 +- 13 files changed, 87 insertions(+), 95 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 7b20ac80b9..aa13e3f89b 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -154,8 +154,6 @@ trait BigInt { */ def or(that: BigInt): BigInt def |(that: BigInt): BigInt = or(that) - - def nbits: Long } /** Base class for points on elliptic curves. */ @@ -697,6 +695,18 @@ trait SigmaDslBuilder { */ def groupGenerator: GroupElement + /** + * @return big integer provided as input approximately encoded using NBits, + * see (https://bitcoin.stackexchange.com/questions/57184/what-does-the-nbits-value-represent) + * for format details + */ + def encodeNbits(bi: BigInt): Long + + /** + * @return big integer decoded from NBits value provided, + * see (https://bitcoin.stackexchange.com/questions/57184/what-does-the-nbits-value-represent) + * for format details + */ def decodeNbits(l: Long): BigInt /** diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index 43198fbf8a..bbf1a85e46 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -1,7 +1,6 @@ package sigma.data import sigma.util.Extensions.BigIntegerOps -import sigma.util.NBitsUtils import sigma.{BigInt, Coll, Colls} import java.math.BigInteger @@ -50,6 +49,4 @@ 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 nbits: Long = NBitsUtils.encodeCompactBits(wrappedValue) } diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index b4b5fd9f23..c1c7e41ef5 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -124,9 +124,6 @@ object ReflectionData { }, mkMethod(clazz, "divide", paramTypes) { (obj, args) => obj.asInstanceOf[BigInt].divide(args(0).asInstanceOf[BigInt]) - }, - mkMethod(clazz, "nbits", paramTypes) { (obj, _) => - obj.asInstanceOf[BigInt].nbits } ) ) @@ -447,6 +444,9 @@ object ReflectionData { mkMethod(clazz, "decodePoint", Array[Class[_]](cColl)) { (obj, args) => obj.asInstanceOf[SigmaDslBuilder].decodePoint(args(0).asInstanceOf[Coll[Byte]]) }, + mkMethod(clazz, "encodeNbits", Array[Class[_]](cColl)) { (obj, args) => + obj.asInstanceOf[SigmaDslBuilder].encodeNbits(args(0).asInstanceOf[BigInt]) + }, mkMethod(clazz, "decodeNbits", Array[Class[_]](cColl)) { (obj, args) => obj.asInstanceOf[SigmaDslBuilder].decodeNbits(args(0).asInstanceOf[Long]) } diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 171d2b95c7..07a3aea4bf 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -303,9 +303,6 @@ case object SIntMethods extends SNumericTypeMethods { case object SLongMethods extends SNumericTypeMethods { /** Type for which this container defines methods. */ override def ownerType: SMonoType = SLong - - protected override def getMethods(): Seq[SMethod] = super.getMethods() - } /** Methods of BigInt type. Implemented using [[java.math.BigInteger]]. */ @@ -313,13 +310,6 @@ case object SBigIntMethods extends SNumericTypeMethods { /** Type for which this container defines methods. */ override def ownerType: SMonoType = SBigInt - final val ToNBitsCostInfo = OperationCostInfo( - FixedCost(JitCost(5)), NamedDesc("NBitsMethodCall")) - - //id = 8 to make it after toBits - val ToNBits = SMethod(this, "nbits", SFunc(this.ownerType, SLong), 8, ToNBitsCostInfo.costKind) - .withInfo(ModQ, "Encode this big integer value as NBits") - /** 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 @@ -337,7 +327,7 @@ case object SBigIntMethods extends SNumericTypeMethods { protected override def getMethods(): Seq[SMethod] = { if (VersionContext.current.isV6SoftForkActivated) { - super.getMethods() ++ Seq(ToNBits) + super.getMethods() // ModQMethod, // PlusModQMethod, // MinusModQMethod, @@ -347,14 +337,6 @@ case object SBigIntMethods extends SNumericTypeMethods { super.getMethods() } } - - /** - * - */ - def nbits_eval(mc: MethodCall, bi: sigma.BigInt)(implicit E: ErgoTreeEvaluator): Long = { - E.nbits(mc, bi) - } - } /** Methods of type `String`. */ @@ -1523,37 +1505,50 @@ case object SGlobalMethods extends MonoTypeMethods { Xor.xorWithCosting(ls, rs) } + private lazy val EnDecodeNBitsCost = FixedCost(JitCost(5)) // the same cost for nbits encoding and decoding + + lazy val encodeNBitsMethod: SMethod = SMethod( + this, "encodeNbits", SFunc(Array(SGlobal, SBigInt), SLong), 3, EnDecodeNBitsCost) + .withIRInfo(MethodCallIrBuilder) + .withInfo(MethodCall, "Encode big integer number as nbits", ArgInfo("bigInt", "Big integer")) + lazy val decodeNBitsMethod: SMethod = SMethod( - this, "decodeNbits", SFunc(Array(SGlobal, SLong), SBigInt), 3, FixedCost(JitCost(5))) + this, "decodeNbits", SFunc(Array(SGlobal, SLong), SBigInt), 4, EnDecodeNBitsCost) .withIRInfo(MethodCallIrBuilder) - .withInfo(Xor, "Byte-wise XOR of two collections of bytes", ArgInfo("left", "left operand")) + .withInfo(MethodCall, "Decode nbits-encoded big integer number", ArgInfo("nbits", "NBits-encoded argument")) /** - * + * encodeNBits evaluation with costing + */ + def encodeNbits_eval(mc: MethodCall, G: SigmaDslBuilder, bigInt: BigInt)(implicit E: ErgoTreeEvaluator): Long = { + E.addFixedCost(EnDecodeNBitsCost, encodeNBitsMethod.opDesc) { + NBitsUtils.encodeCompactBits(bigInt.asInstanceOf[CBigInt].wrappedValue) + } + } + + /** + * decodeNBits evaluation with costing */ def decodeNbits_eval(mc: MethodCall, G: SigmaDslBuilder, l: Long)(implicit E: ErgoTreeEvaluator): BigInt = { - CBigInt(NBitsUtils.decodeCompactBits(l).bigInteger) // todo: costing is ignored here + E.addFixedCost(EnDecodeNBitsCost, decodeNBitsMethod.opDesc) { + CBigInt(NBitsUtils.decodeCompactBits(l).bigInteger) + } } - { + protected override def getMethods() = { if (VersionContext.current.isV6SoftForkActivated) { - super.getMethods() ++ Seq(decodeNBitsMethod) + super.getMethods() ++ Seq( + groupGeneratorMethod, + xorMethod, + encodeNBitsMethod, + decodeNBitsMethod + ) } else { - super.getMethods() + super.getMethods() ++ Seq( + groupGeneratorMethod, + xorMethod + ) } } - - protected override def getMethods() = if (VersionContext.current.isV6SoftForkActivated) { - super.getMethods() ++ Seq( - groupGeneratorMethod, - xorMethod, - decodeNBitsMethod - ) - } else { - super.getMethods() ++ Seq( - groupGeneratorMethod, - xorMethod - ) - } } diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 5f401ad9ff..d7ebd7651a 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -176,6 +176,10 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => override def groupGenerator: GroupElement = _generatorElement + def encodeNbits(bi: BigInt): Long = { + NBitsUtils.encodeCompactBits(bi.asInstanceOf[CBigInt].wrappedValue) + } + def decodeNbits(l: Long): BigInt = { CBigInt(NBitsUtils.decodeCompactBits(l).bigInteger) } diff --git a/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala b/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala index ec12a52849..8eb6171622 100644 --- a/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala +++ b/data/shared/src/main/scala/sigma/eval/ErgoTreeEvaluator.scala @@ -98,9 +98,6 @@ abstract class ErgoTreeEvaluator { /** Represents blockchain data context for ErgoTree evaluation. */ def context: Context - /** Implements evaluation of BigInt.nbits method call ErgoTree node. */ - def nbits(mc: MethodCall, bi: sigma.BigInt): Long - /** Create an instance of [[AvlTreeVerifier]] for the given tree and proof. */ def createTreeVerifier(tree: AvlTree, proof: Coll[Byte]): AvlTreeVerifier diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala index 53aa3dc08b..963a8fadc3 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/CErgoTreeEvaluator.scala @@ -67,12 +67,6 @@ class CErgoTreeEvaluator( override def createTreeVerifier(tree: AvlTree, proof: Coll[Byte]): AvlTreeVerifier = CAvlTreeVerifier(tree, proof) - def nbits(mc: MethodCall, bi: sigma.BigInt): Long = { - addFixedCost(SBigIntMethods.ToNBitsCostInfo) { - bi.nbits - } - } - /** Creates [[sigma.eval.AvlTreeVerifier]] for the given tree and proof. */ def createVerifier(tree: AvlTree, proof: Coll[Byte]) = { // the cost of tree reconstruction from proof is O(proof.length) diff --git a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala index 133361b7b7..9157c991e5 100644 --- a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala @@ -24,12 +24,12 @@ class MethodCallSerializerSpecification extends SerializationSpecification { roundTripTest(expr) } - property("MethodCall deserialization round trip for BigInt.nbits") { + property("MethodCall deserialization round trip for Global.encodeNBits") { def code = { val bi = BigIntConstant(5) - val expr = MethodCall(bi, - SBigIntMethods.ToNBits, - Vector(), + val expr = MethodCall(Global, + SGlobalMethods.encodeNBitsMethod, + Vector(bi), Map() ) roundTripTest(expr) @@ -46,12 +46,12 @@ class MethodCallSerializerSpecification extends SerializationSpecification { }) } - property("MethodCall deserialization round trip for BigInt.nbits") { + property("MethodCall deserialization round trip for Global.decodeNBits") { def code = { - val bi = BigIntConstant(5) - val expr = MethodCall(bi, - SBigIntMethods.ToNBits, - Vector(), + val l = LongConstant(5) + val expr = MethodCall(Global, + SGlobalMethods.decodeNBitsMethod, + Vector(l), Map() ) roundTripTest(expr) diff --git a/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala b/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala index fbd74ed873..c4cd58a4ef 100644 --- a/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala +++ b/interpreter/shared/src/test/scala/sigmastate/eval/BasicOpsTests.scala @@ -2,15 +2,15 @@ package sigmastate.eval import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import sigma.ast.{BigIntConstant, ErgoTree, JitCost, MethodCall, SBigIntMethods} +import sigma.ast.{BigIntConstant, ErgoTree, Global, JitCost, MethodCall, SBigIntMethods, SGlobalMethods} import sigma.crypto.SecP256K1Group -import sigma.data.{CBigInt, CSigmaDslBuilder, TrivialProp} +import sigma.data.{CBigInt, TrivialProp} import sigma.eval.SigmaDsl import sigma.util.Extensions.SigmaBooleanOps import sigma.util.NBitsUtils import java.math.BigInteger -import sigma.{ContractsTestkit, SigmaDslBuilder, SigmaProp} +import sigma.{ContractsTestkit, SigmaProp} import sigmastate.interpreter.{CErgoTreeEvaluator, CostAccumulator} import sigmastate.interpreter.CErgoTreeEvaluator.DefaultProfiler @@ -72,7 +72,7 @@ class BasicOpsTests extends AnyFunSuite with ContractsTestkit with Matchers { * Checks BigInt.nbits evaluation for SigmaDSL as well as AST interpreter (MethodCall) layers */ test("nbits evaluation") { - SigmaDsl.BigInt(BigInteger.valueOf(0)).nbits should be + SigmaDsl.encodeNbits(CBigInt(BigInteger.valueOf(0))) should be (NBitsUtils.encodeCompactBits(0)) val es = CErgoTreeEvaluator.DefaultEvalSettings @@ -84,7 +84,7 @@ class BasicOpsTests extends AnyFunSuite with ContractsTestkit with Matchers { constants = ErgoTree.EmptyConstants, coster = accumulator, DefaultProfiler, es) - val res = MethodCall(BigIntConstant(BigInteger.valueOf(0)), SBigIntMethods.ToNBits, IndexedSeq.empty, Map.empty) + val res = MethodCall(Global, SGlobalMethods.encodeNBitsMethod, IndexedSeq(BigIntConstant(BigInteger.valueOf(0))), Map.empty) .evalTo[Long](Map.empty)(evaluator) res should be (NBitsUtils.encodeCompactBits(0)) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index cda2b64ab0..be7658fa55 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -504,9 +504,6 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => else error(s"The type of $obj is expected to be Collection to select 'size' property", obj.sourceContext.toOption) - case Select(obj, SBigIntMethods.ToNBits.name, _) if obj.tpe == SBigInt && VersionContext.current.isV6SoftForkActivated => - eval(sigma.ast.MethodCall(obj, SBigIntMethods.ToNBits, IndexedSeq.empty, Map.empty)) - // Rule: proof.isProven --> IsValid(proof) case Select(p, SSigmaPropMethods.IsProven, _) if p.tpe == SSigmaProp => eval(SigmaPropIsProven(p.asSigmaProp)) @@ -936,10 +933,6 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => val objV = eval(obj) val argsV = args.map(eval) (objV, method.objType) match { - case (bi: Ref[BigInt]@unchecked, SBigIntMethods) => method.name match { - case SBigIntMethods.ToNBits.name => - bi.nbits - } case (xs: RColl[t]@unchecked, SCollectionMethods) => method.name match { case SCollectionMethods.IndicesMethod.name => xs.indices @@ -1154,6 +1147,9 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => val c1 = asRep[Coll[Byte]](argsV(0)) val c2 = asRep[Coll[Byte]](argsV(1)) g.xor(c1, c2) + case SGlobalMethods.encodeNBitsMethod.name if VersionContext.current.isV6SoftForkActivated => + val c1 = asRep[BigInt](argsV(0)) + g.encodeNbits(c1) case SGlobalMethods.decodeNBitsMethod.name if VersionContext.current.isV6SoftForkActivated => val c1 = asRep[Long](argsV(0)) g.decodeNbits(c1) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala index 427998588e..df229f8ce3 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala @@ -13,7 +13,6 @@ import scalan._ def mod(m: Ref[BigInt]): Ref[BigInt]; def min(that: Ref[BigInt]): Ref[BigInt]; def max(that: Ref[BigInt]): Ref[BigInt]; - def nbits: Ref[Long] }; trait GroupElement extends Def[GroupElement] { def exp(k: Ref[BigInt]): Ref[GroupElement]; @@ -115,6 +114,7 @@ import scalan._ /** 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 encodeNbits(bi: Ref[BigInt]): Ref[Long] def decodeNbits(l: Ref[Long]): Ref[BigInt] }; trait CostModelCompanion; diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala index d92aa14a2e..c63d47cc86 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala @@ -97,13 +97,6 @@ object BigInt extends EntityObject("BigInt") { Array[AnyRef](that), true, false, element[BigInt])) } - - override def nbits: Ref[Long] = { - asRep[Long](mkMethodCall(self, - BigIntClass.getMethod("nbits"), - Array[AnyRef](), - neverInvoke = true, isAdapterCall = false, element[Long])) - } } implicit object LiftableBigInt @@ -172,13 +165,6 @@ object BigInt extends EntityObject("BigInt") { Array[AnyRef](that), true, true, element[BigInt])) } - - def nbits: Ref[Long] = { - asRep[Long](mkMethodCall(source, - BigIntClass.getMethod("nbits", classOf[Sym]), - Array[AnyRef](), - neverInvoke = true, isAdapterCall = true, element[Long])) - } } // entityUnref: single unref method for each type family @@ -1960,10 +1946,17 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { true, false, element[Coll[Byte]])) } + override def encodeNbits(bi: Ref[BigInt]): Ref[Long] = { + asRep[Long](mkMethodCall(self, + SigmaDslBuilderClass.getMethod("encodeNbits", classOf[Sym]), + Array[AnyRef](bi), + true, false, element[Long])) + } + override def decodeNbits(l: Ref[Long]): Ref[BigInt] = { asRep[BigInt](mkMethodCall(self, SigmaDslBuilderClass.getMethod("decodeNbits", classOf[Sym]), - Array[AnyRef](), + Array[AnyRef](l), true, false, element[BigInt])) } } @@ -2126,6 +2119,13 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { true, true, element[Coll[Byte]])) } + override def encodeNbits(bi: Ref[BigInt]): Ref[Long] = { + asRep[Long](mkMethodCall(source, + SigmaDslBuilderClass.getMethod("encodeNbits", classOf[Sym]), + Array[AnyRef](bi), + true, true, element[Long])) + } + override def decodeNbits(l: Ref[Long]): Ref[BigInt] = { asRep[BigInt](mkMethodCall(source, SigmaDslBuilderClass.getMethod("decodeNbits", classOf[Sym]), diff --git a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala index 429cbd33b7..0a3bf29960 100644 --- a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala @@ -10,7 +10,6 @@ import org.ergoplatform._ import org.scalatest.BeforeAndAfterAll import scorex.util.encode.Base58 import sigma.VersionContext -import sigma.crypto.CryptoConstants import sigma.data.{AvlTreeData, CAND, ProveDlog, SigmaBoolean, TrivialProp} import sigma.VersionContext.V6SoftForkVersion import sigma.util.Extensions.IntOps @@ -207,7 +206,7 @@ class TestingInterpreterSpecification extends CompilerTestingCommons """ |{ | val b: BigInt = 11999.toBigInt - | b.nbits == 36626176 + | Global.encodeNbits(b) == 36626176 |} |""".stripMargin if (activatedVersionInTests < V6SoftForkVersion) { From 2c8df317b7cab41fbee753cb107f99ba823ac8c3 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 31 Jul 2024 15:47:36 +0300 Subject: [PATCH 100/123] updating collectMethods --- .../sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala index c63d47cc86..db3a2e4933 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala @@ -2149,7 +2149,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", "encodeNBits", "decodeNBits" )) } } From 6981c34cc863cf34a19588f89e722742ba243d48 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 31 Jul 2024 16:19:10 +0300 Subject: [PATCH 101/123] fixing JS test --- .../sigma/reflection/ReflectionData.scala | 4 +- yarn.lock | 3322 +++++++++++++++++ 2 files changed, 3324 insertions(+), 2 deletions(-) create mode 100644 yarn.lock diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index c1c7e41ef5..5eff8bd251 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -444,10 +444,10 @@ object ReflectionData { mkMethod(clazz, "decodePoint", Array[Class[_]](cColl)) { (obj, args) => obj.asInstanceOf[SigmaDslBuilder].decodePoint(args(0).asInstanceOf[Coll[Byte]]) }, - mkMethod(clazz, "encodeNbits", Array[Class[_]](cColl)) { (obj, args) => + mkMethod(clazz, "encodeNbits", Array[Class[_]](classOf[BigInt])) { (obj, args) => obj.asInstanceOf[SigmaDslBuilder].encodeNbits(args(0).asInstanceOf[BigInt]) }, - mkMethod(clazz, "decodeNbits", Array[Class[_]](cColl)) { (obj, args) => + mkMethod(clazz, "decodeNbits", Array[Class[_]](classOf[Long])) { (obj, args) => obj.asInstanceOf[SigmaDslBuilder].decodeNbits(args(0).asInstanceOf[Long]) } ) diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000000..161dcfd54a --- /dev/null +++ b/yarn.lock @@ -0,0 +1,3322 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@fleet-sdk/common@0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@fleet-sdk/common/-/common-0.1.3.tgz#f9e478b896e9192f03d2d5b30570af4e8632eb15" + integrity sha512-gYEkHhgGpgIcmCL3nCw8E9zHkT2WLmR+mPdxFlUE6fwcwISURbJrP6W9mF7D5Y0ShAP5Is2w3edh7AyIc7ctIQ== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@noble/hashes@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.4.tgz#2611ebf5764c1bf754da7c7794de4fb30512336d" + integrity sha512-+PYsVPrTSqtVjatKt2A/Proukn2Yrz61OBThOCKErc5w2/r1Fh37vbDv0Eah7pyNltrmacjwTvdw3JoR+WE4TA== + +"@noble/hashes@^1.1.4": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + +"@types/eslint-scope@^3.7.0": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "9.6.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.0.tgz#51d4fe4d0316da9e9f2c80884f2c20ed5fb022ff" + integrity sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +"@types/estree@^0.0.46": + version "0.0.46" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe" + integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg== + +"@types/glob@^7.1.1": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/json-schema@*", "@types/json-schema@^7.0.8": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/minimatch@*": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + +"@types/node@*": + version "22.0.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.0.0.tgz#04862a2a71e62264426083abe1e27e87cac05a30" + integrity sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw== + dependencies: + undici-types "~6.11.1" + +"@webassemblyjs/ast@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.0.tgz#a5aa679efdc9e51707a4207139da57920555961f" + integrity sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.0" + "@webassemblyjs/helper-wasm-bytecode" "1.11.0" + +"@webassemblyjs/floating-point-hex-parser@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz#34d62052f453cd43101d72eab4966a022587947c" + integrity sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA== + +"@webassemblyjs/helper-api-error@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz#aaea8fb3b923f4aaa9b512ff541b013ffb68d2d4" + integrity sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w== + +"@webassemblyjs/helper-buffer@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz#d026c25d175e388a7dbda9694e91e743cbe9b642" + integrity sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA== + +"@webassemblyjs/helper-numbers@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz#7ab04172d54e312cc6ea4286d7d9fa27c88cd4f9" + integrity sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.0" + "@webassemblyjs/helper-api-error" "1.11.0" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz#85fdcda4129902fe86f81abf7e7236953ec5a4e1" + integrity sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA== + +"@webassemblyjs/helper-wasm-section@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz#9ce2cc89300262509c801b4af113d1ca25c1a75b" + integrity sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew== + dependencies: + "@webassemblyjs/ast" "1.11.0" + "@webassemblyjs/helper-buffer" "1.11.0" + "@webassemblyjs/helper-wasm-bytecode" "1.11.0" + "@webassemblyjs/wasm-gen" "1.11.0" + +"@webassemblyjs/ieee754@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz#46975d583f9828f5d094ac210e219441c4e6f5cf" + integrity sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.0.tgz#f7353de1df38aa201cba9fb88b43f41f75ff403b" + integrity sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.0.tgz#86e48f959cf49e0e5091f069a709b862f5a2cadf" + integrity sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw== + +"@webassemblyjs/wasm-edit@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz#ee4a5c9f677046a210542ae63897094c2027cb78" + integrity sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ== + dependencies: + "@webassemblyjs/ast" "1.11.0" + "@webassemblyjs/helper-buffer" "1.11.0" + "@webassemblyjs/helper-wasm-bytecode" "1.11.0" + "@webassemblyjs/helper-wasm-section" "1.11.0" + "@webassemblyjs/wasm-gen" "1.11.0" + "@webassemblyjs/wasm-opt" "1.11.0" + "@webassemblyjs/wasm-parser" "1.11.0" + "@webassemblyjs/wast-printer" "1.11.0" + +"@webassemblyjs/wasm-gen@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz#3cdb35e70082d42a35166988dda64f24ceb97abe" + integrity sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ== + dependencies: + "@webassemblyjs/ast" "1.11.0" + "@webassemblyjs/helper-wasm-bytecode" "1.11.0" + "@webassemblyjs/ieee754" "1.11.0" + "@webassemblyjs/leb128" "1.11.0" + "@webassemblyjs/utf8" "1.11.0" + +"@webassemblyjs/wasm-opt@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz#1638ae188137f4bb031f568a413cd24d32f92978" + integrity sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg== + dependencies: + "@webassemblyjs/ast" "1.11.0" + "@webassemblyjs/helper-buffer" "1.11.0" + "@webassemblyjs/wasm-gen" "1.11.0" + "@webassemblyjs/wasm-parser" "1.11.0" + +"@webassemblyjs/wasm-parser@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz#3e680b8830d5b13d1ec86cc42f38f3d4a7700754" + integrity sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw== + dependencies: + "@webassemblyjs/ast" "1.11.0" + "@webassemblyjs/helper-api-error" "1.11.0" + "@webassemblyjs/helper-wasm-bytecode" "1.11.0" + "@webassemblyjs/ieee754" "1.11.0" + "@webassemblyjs/leb128" "1.11.0" + "@webassemblyjs/utf8" "1.11.0" + +"@webassemblyjs/wast-printer@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz#680d1f6a5365d6d401974a8e949e05474e1fab7e" + integrity sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ== + dependencies: + "@webassemblyjs/ast" "1.11.0" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^1.0.1": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5" + integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg== + +"@webpack-cli/info@^1.2.2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1" + integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ== + dependencies: + envinfo "^7.7.3" + +"@webpack-cli/serve@^1.3.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1" + integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abab@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn@^8.0.4, acorn@^8.8.2: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.1.0, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha512-JoAxEa1DfP9m2xfB/y2r/aKcwXNlltr4+0QSBC4TrLfcxyvepX2Pv0t/xpgGV5bGsDzCYV8SzjWgyCW0T9yYbA== + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== + +ansi-regex@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng== + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== + +async-each@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.6.tgz#52f1d9403818c179b7561e11a5d1b77eb2160e77" + integrity sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@^2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +body-parser@1.20.2: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg== + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +browserslist@^4.14.5: + version "4.23.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.2.tgz#244fe803641f1c19c28c48c4b6ec9736eb3d32ed" + integrity sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA== + dependencies: + caniuse-lite "^1.0.30001640" + electron-to-chromium "^1.4.820" + node-releases "^2.0.14" + update-browserslist-db "^1.1.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +call-bind@^1.0.2, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +caniuse-lite@^1.0.30001640: + version "1.0.30001645" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001645.tgz#4c4b7427683dea1170a152cd1654be8d0da7bd71" + integrity sha512-GFtY2+qt91kzyMk6j48dJcwJVq5uTkk71XxE3RtScx7XWRLsO7bU44LOFkOZYR8w9YMS0UhPSYpN/6rAMImmLw== + +chokidar@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chrome-trace-event@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" + integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +colorette@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +component-emitter@^1.2.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17" + integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +concat-with-sourcemaps@1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.0.7.tgz#9420e100fb984cbde11a78dca2d818306bc8f0d2" + integrity sha512-5i4Spc9NNvVXzkR77x2kjcYCDZMNPLzP7ZBzJMNKZjXzk+E6tRVL/lPlYw60VM3hb7gf+iBQn2x1T8TpMN0SEw== + dependencies: + source-map "^0.6.1" + +connect-history-api-fallback@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.1.1: + version "4.3.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" + integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== + dependencies: + ms "2.1.2" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +decode-uri-component@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== + +deep-equal@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.2.tgz#78a561b7830eef3134c7f6f3a3d6af272a678761" + integrity sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg== + dependencies: + is-arguments "^1.1.1" + is-date-object "^1.0.5" + is-regex "^1.1.4" + object-is "^1.1.5" + object-keys "^1.1.1" + regexp.prototype.flags "^1.5.1" + +default-gateway@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" + integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== + dependencies: + execa "^1.0.0" + ip-regex "^2.1.0" + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" + integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== + dependencies: + "@types/glob" "^7.1.1" + globby "^6.1.0" + is-path-cwd "^2.0.0" + is-path-in-cwd "^2.0.0" + p-map "^2.0.0" + pify "^4.0.1" + rimraf "^2.6.3" + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== + +dns-packet@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f" + integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ== + dependencies: + buffer-indexof "^1.0.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.820: + version "1.5.4" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz#cd477c830dd6fca41fbd5465c1ff6ce08ac22343" + integrity sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA== + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^5.7.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +enquirer@^2.3.6: + version "2.4.1" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + +envinfo@^7.7.3: + version "7.13.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.13.0.tgz#81fbb81e5da35d74e814941aeab7c325a606fb31" + integrity sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q== + +errno@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-module-lexer@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.4.1.tgz#dda8c6a14d8f340a24e34331e0fab0cb50438e0e" + integrity sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA== + +escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +eventsource@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-2.0.2.tgz#76dfcc02930fb2ff339520b6d290da573a9e8508" + integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA== + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +express@^4.17.1: + version "4.19.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.2" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +faye-websocket@^0.11.3, faye-websocket@^0.11.4: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +follow-redirects@^1.0.0: + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^1.2.7: + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA== + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.0.3, glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw== + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +hasown@^2.0.0, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" + integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +http-proxy-middleware@0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" + integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== + dependencies: + http-proxy "^1.17.0" + is-glob "^4.0.0" + lodash "^4.17.11" + micromatch "^3.1.10" + +http-proxy@^1.17.0: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + +internal-ip@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" + integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== + dependencies: + default-gateway "^4.2.0" + ipaddr.js "^1.9.0" + +interpret@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" + integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw== + +ip@^1.1.0, ip@^1.1.5: + version "1.1.9" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396" + integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ== + +ipaddr.js@1.9.1, ipaddr.js@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-absolute-url@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== + +is-accessor-descriptor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz#3223b10628354644b86260db29b3e693f5ceedd4" + integrity sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA== + dependencies: + hasown "^2.0.0" + +is-arguments@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q== + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-core-module@^2.13.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" + integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== + dependencies: + hasown "^2.0.2" + +is-data-descriptor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz#2109164426166d32ea38c405c1e0945d9e6a4eeb" + integrity sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw== + dependencies: + hasown "^2.0.0" + +is-date-object@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-descriptor@^0.1.0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.7.tgz#2727eb61fd789dcd5bdf0ed4569f551d2fe3be33" + integrity sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg== + dependencies: + is-accessor-descriptor "^1.0.1" + is-data-descriptor "^1.0.1" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.3.tgz#92d27cb3cd311c4977a4db47df457234a13cb306" + integrity sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw== + dependencies: + is-accessor-descriptor "^1.0.1" + is-data-descriptor "^1.0.1" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw== + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== + dependencies: + kind-of "^3.0.2" + +is-path-cwd@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-in-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" + integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== + dependencies: + is-path-inside "^2.1.0" + +is-path-inside@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" + integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== + dependencies: + path-is-inside "^1.0.2" + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw== + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +killable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== + dependencies: + is-buffer "^1.1.5" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash@^4.17.11, lodash@^4.17.14: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loglevel@^1.6.8: + version "1.9.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.1.tgz#d63976ac9bcd03c7c873116d41c2a85bafff1be7" + integrity sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg== + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== + dependencies: + object-visit "^1.0.0" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memory-fs@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +"mime-db@>= 1.43.0 < 2": + version "1.53.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" + integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== + +mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.4: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.1, mkdirp@^0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ== + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +nan@^2.12.1: + version "2.20.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" + integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-forge@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" + integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== + +node-releases@^2.0.14: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== + dependencies: + path-key "^2.0.0" + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + +object-is@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" + integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== + dependencies: + isobject "^3.0.0" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== + dependencies: + isobject "^3.0.1" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +opn@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== + dependencies: + is-wsl "^1.1.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-retry@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" + integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== + dependencies: + retry "^0.12.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +portfinder@^1.0.26: + version "1.0.32" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.32.tgz#2fe1b9e58389712429dc2bea5beb2146146c7f81" + integrity sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg== + dependencies: + async "^2.6.4" + debug "^3.2.7" + mkdirp "^0.5.6" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +qs@^6.12.3: + version "6.12.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.3.tgz#e43ce03c8521b9c7fd7f1f13e514e5ca37727754" + integrity sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ== + dependencies: + side-channel "^1.0.6" + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@^2.0.1, readable-stream@^2.0.2: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +rechoir@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" + integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== + dependencies: + resolve "^1.9.0" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexp.prototype.flags@^1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== + dependencies: + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== + +repeat-element@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg== + dependencies: + resolve-from "^3.0.0" + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== + +resolve@^1.9.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +schema-utils@^3.0.0, schema-utils@^3.1.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== + +selfsigned@^1.10.8: + version "1.10.14" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.14.tgz#ee51d84d9dcecc61e07e4aba34f229ab525c1574" + integrity sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA== + dependencies: + node-forge "^0.10.0" + +semver@^5.5.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.3.0: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serialize-javascript@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4, side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +sigmajs-crypto-facade@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/sigmajs-crypto-facade/-/sigmajs-crypto-facade-0.0.7.tgz#b81dd53750c38a6a7856153aad2705269bc5afb6" + integrity sha512-4XK8ZS9NKAbo8aGnU6o5GkBW6Upl8+OK8A1KreVDMAamfvZ0iq4LoVH8rHaeEPf9moVtaC4QZY5RYI+0OwiydA== + dependencies: + "@noble/hashes" "^1.1.4" + +signal-exit@^3.0.0, signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sockjs-client@^1.5.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.6.1.tgz#350b8eda42d6d52ddc030c39943364c11dcad806" + integrity sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw== + dependencies: + debug "^3.2.7" + eventsource "^2.0.2" + faye-websocket "^0.11.4" + inherits "^2.0.4" + url-parse "^1.5.10" + +sockjs@^0.3.21: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + +source-list-map@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-loader@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-2.0.0.tgz#6651dc5a46beb2b914abacd00b8f9dd0e7757820" + integrity sha512-DJLK+gR9hlx+58yGU54EDAQZzR/TksgrtvRtyEBWnd5DR7O4n0RgdyO/KBwJ76zF+wDiFRT/1vdV3SdLUR68Lg== + dependencies: + abab "^2.0.5" + iconv-lite "^0.6.2" + source-map "^0.6.1" + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.1.1: + version "5.3.10" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" + integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.20" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.26.0" + +terser@^5.26.0: + version "5.31.3" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.3.tgz#b24b7beb46062f4653f049eea4f0cd165d0f0c38" + integrity sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +undici-types@~6.11.1: + version "6.11.1" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.11.1.tgz#432ea6e8efd54a48569705a699e62d8f4981b197" + integrity sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== + +url-parse@^1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +url@^0.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.4.tgz#adca77b3562d56b72746e76b330b7f27b6721f3c" + integrity sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg== + dependencies: + punycode "^1.4.1" + qs "^6.12.3" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache@^2.2.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" + integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +watchpack@^2.0.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.1.tgz#29308f2cac150fa8e4c92f90e0ec954a9fed7fff" + integrity sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webpack-cli@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.5.0.tgz#b5213b84adf6e1f5de6391334c9fa53a48850466" + integrity sha512-wXg/ef6Ibstl2f50mnkcHblRPN/P9J4Nlod5Hg9HGFgSeF8rsqDGHJeVe4aR26q9l62TUJi6vmvC2Qz96YJw1Q== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^1.0.1" + "@webpack-cli/info" "^1.2.2" + "@webpack-cli/serve" "^1.3.0" + colorette "^1.2.1" + commander "^7.0.0" + enquirer "^2.3.6" + execa "^5.0.0" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^2.2.0" + rechoir "^0.7.0" + v8-compile-cache "^2.2.0" + webpack-merge "^5.7.3" + +webpack-dev-middleware@^3.7.2: + version "3.7.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" + integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" + webpack-log "^2.0.0" + +webpack-dev-server@3.11.2: + version "3.11.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz#695ebced76a4929f0d5de7fd73fafe185fe33708" + integrity sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ== + dependencies: + ansi-html "0.0.7" + bonjour "^3.5.0" + chokidar "^2.1.8" + compression "^1.7.4" + connect-history-api-fallback "^1.6.0" + debug "^4.1.1" + del "^4.1.1" + express "^4.17.1" + html-entities "^1.3.1" + http-proxy-middleware "0.19.1" + import-local "^2.0.0" + internal-ip "^4.3.0" + ip "^1.1.5" + is-absolute-url "^3.0.3" + killable "^1.0.1" + loglevel "^1.6.8" + opn "^5.5.0" + p-retry "^3.0.1" + portfinder "^1.0.26" + schema-utils "^1.0.0" + selfsigned "^1.10.8" + semver "^6.3.0" + serve-index "^1.9.1" + sockjs "^0.3.21" + sockjs-client "^1.5.0" + spdy "^4.0.2" + strip-ansi "^3.0.1" + supports-color "^6.1.0" + url "^0.11.0" + webpack-dev-middleware "^3.7.2" + webpack-log "^2.0.0" + ws "^6.2.1" + yargs "^13.3.2" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-merge@^5.7.3: + version "5.10.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" + integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== + dependencies: + clone-deep "^4.0.1" + flat "^5.0.2" + wildcard "^2.0.0" + +webpack-sources@^2.1.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.1.tgz#570de0af163949fe272233c2cefe1b56f74511fd" + integrity sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA== + dependencies: + source-list-map "^2.0.1" + source-map "^0.6.1" + +webpack@5.24.3: + version "5.24.3" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.24.3.tgz#6ec0f5059f8d7c7961075fa553cfce7b7928acb3" + integrity sha512-x7lrWZ7wlWAdyKdML6YPvfVZkhD1ICuIZGODE5SzKJjqI9A4SpqGTjGJTc6CwaHqn19gGaoOR3ONJ46nYsn9rw== + dependencies: + "@types/eslint-scope" "^3.7.0" + "@types/estree" "^0.0.46" + "@webassemblyjs/ast" "1.11.0" + "@webassemblyjs/wasm-edit" "1.11.0" + "@webassemblyjs/wasm-parser" "1.11.0" + acorn "^8.0.4" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.7.0" + es-module-lexer "^0.4.0" + eslint-scope "^5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.4" + json-parse-better-errors "^1.0.2" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.0.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.1" + watchpack "^2.0.0" + webpack-sources "^2.1.1" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +which-module@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^6.2.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.3.tgz#ccc96e4add5fd6fedbc491903075c85c5a11d9ee" + integrity sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA== + dependencies: + async-limiter "~1.0.0" + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" From 26809c94f0ed8aca3d56fabb10995fb30e2889e0 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 2 Aug 2024 13:58:07 +0300 Subject: [PATCH 102/123] passing but improper changedFeature test --- .gitignore | 1 + .../scala/sigma/LanguageSpecificationV6.scala | 48 +++++++++---------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index df18ce8ab1..d328645cde 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *.fdb_latexmk *.gz +yarn.lock *.log docs/spec/out/ test-out/ diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index b4fb5b12fb..9e9827df1f 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -1,14 +1,14 @@ package sigma -import sigma.ast.{Apply, ArithOp, BlockValue, ByIndex, CompanionDesc, Constant, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, IntConstant, JitCost, LongConstant, MethodCall, OptionGet, OptionGetOrElse, PerItemCost, SBigInt, SByte, SCollection, SCollectionMethods, SCollectionType, SInt, SLong, SOption, SPair, SShort, STuple, STypeVar, SelectField, ValDef, ValUse, Value} +import sigma.ast.{Apply, ByIndex, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, IntConstant, JitCost, LongConstant, MethodCall, OptionGet, OptionGetOrElse, PerItemCost, SBigInt, SByte, SCollection, SCollectionMethods, SCollectionType, SInt, SLong, SOption, SPair, SShort, STuple, STypeVar, SelectField, ValDef, ValUse, Value} import sigma.data.{CBigInt, ExactNumeric} -import sigma.eval.{SigmaDsl, TracedCost} +import sigma.eval.{CostDetails, SigmaDsl, TracedCost} import sigma.serialization.ValueCodes.OpCode import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} import sigmastate.exceptions.MethodNotFound import java.math.BigInteger -import scala.util.Success +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. @@ -172,29 +172,29 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => } property("Option.getOrElse with lazy default") { - def getOrElse = newFeature( - { (x: Option[Long]) => x.getOrElse(1 / 0L) }, - "{ (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)) - ) + verifyCases( + Seq( + Some(0L) -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, CostDetails.ZeroCost, 1793, + newVersionedResults = { + Seq(0 -> (ExpectedResult(Success(6L), Some(1793)) -> None)) + } ), + None -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6) + ), + changedFeature( + { (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, + changedIn = VersionContext.V6SoftForkVersion ) ) - - if (VersionContext.current.isV6SoftForkActivated) { - forAll { x: Option[Long] => - Seq(getOrElse).map(_.checkEquality(x)) - } - } else { - forAll { x: Option[Long] => - if (x.isEmpty) { - Seq(getOrElse).map(_.checkEquality(x)) - } - } - } } property("Coll getOrElse with lazy default") { From 8da35750e295b0fa95e440c21316d147c45b1f1d Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 9 Aug 2024 17:33:12 +0300 Subject: [PATCH 103/123] fixed tests in LSV6 --- .../scala/sigma/LanguageSpecificationV6.scala | 79 ++++++++++++------- .../test/scala/sigma/SigmaDslTesting.scala | 13 ++- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 4e6641984b..d63d6aae65 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -467,7 +467,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => property("Option.getOrElse with lazy default") { - val someTrace = TracedCost( + val trace = TracedCost( Array( FixedCostItem(Apply), FixedCostItem(FuncValue), @@ -481,11 +481,11 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => verifyCases( Seq( - Some(2L) -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, someTrace, 1793, + Some(2L) -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793, newVersionedResults = { - expectedSuccessForAllTreeVersions(2L, 2015, someTrace) + expectedSuccessForAllTreeVersions(2L, 2015, trace) } ), - // None -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6) + None -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793) ), changedFeature( changedInVersion = VersionContext.V6SoftForkVersion, @@ -503,35 +503,56 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) ) } -/* + property("Coll getOrElse with lazy default") { - def getOrElse = newFeature( - (x: (Coll[Int], Int)) => x._1.toArray.toIndexedSeq.unapply(x._2).getOrElse(1 / 0), - "{ (x: (Coll[Int], Int)) => x._1.getOrElse(x._2, 1 / 0) }", - FuncValue( - Array((1, SPair(SCollectionType(SInt), SInt))), - ByIndex( - SelectField.typed[Value[SCollection[SInt.type]]]( - ValUse(1, SPair(SCollectionType(SInt), SInt)), - 1.toByte - ), - SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SCollectionType(SInt), SInt)), 2.toByte), - Some(ArithOp(IntConstant(1), IntConstant(0), OpCode @@ (-99.toByte))) - ) + + val trace = TracedCost( + Array( + FixedCostItem(Apply), + FixedCostItem(FuncValue), + FixedCostItem(GetVar), + FixedCostItem(OptionGet), + FixedCostItem(FuncValue.AddToEnvironmentDesc, FixedCost(JitCost(5))), + FixedCostItem(ValUse), + FixedCostItem(Constant), + FixedCostItem(ByIndex) ) ) - if (VersionContext.current.isV6SoftForkActivated) { - forAll { x: (Coll[Int], Int) => - Seq(getOrElse).map(_.checkEquality(x)) - } - } else { - forAll { x: (Coll[Int], Int) => - if (x._1.isEmpty) { - Seq(getOrElse).map(_.checkEquality(x)) - } - } + 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 + ) + ) } - */ + } diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index 58873449b4..cf2fd98ebf 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -261,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) } @@ -715,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) } @@ -764,7 +771,7 @@ 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.activatedVersion < changedInVersion) { From 65144a9b9e3745d68effbc494171b47c4b472e04 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 13 Aug 2024 18:56:34 +0300 Subject: [PATCH 104/123] merging w. 6.0.0 --- .../src/main/scala/sigma/VersionContext.scala | 2 +- .../src/main/scala/sigma/ast/SType.scala | 30 +- .../validation/ValidationRules.scala | 17 +- .../src/main/scala/sigma/ast/SMethod.scala | 25 +- .../main/scala/sigma/ast/SigmaPredef.scala | 1 - .../src/main/scala/sigma/ast/methods.scala | 2 - .../src/main/scala/sigma/ast/values.scala | 2 + .../serialization/ErgoTreeSerializer.scala | 48 +- .../sigmastate/interpreter/Interpreter.scala | 7 +- .../MethodCallSerializerSpecification.scala | 1 - .../sigma/compiler/phases/SigmaTyper.scala | 3 +- .../sigma/LanguageSpecificationBase.scala | 24 +- .../scala/sigma/LanguageSpecificationV5.scala | 1890 +++++++++-------- .../scala/sigma/LanguageSpecificationV6.scala | 161 +- .../test/scala/sigma/SigmaDslTesting.scala | 84 +- 15 files changed, 1352 insertions(+), 945 deletions(-) diff --git a/core/shared/src/main/scala/sigma/VersionContext.scala b/core/shared/src/main/scala/sigma/VersionContext.scala index 19a4857086..6ede0a1556 100644 --- a/core/shared/src/main/scala/sigma/VersionContext.scala +++ b/core/shared/src/main/scala/sigma/VersionContext.scala @@ -23,7 +23,7 @@ case class VersionContext(activatedVersion: Byte, ergoTreeVersion: Byte) { def isJitActivated: Boolean = activatedVersion >= JitActivationVersion /** @return true, if the activated script version of Ergo protocol on the network is - * including Evolution update. */ + * including v6.0 update. */ def isV6SoftForkActivated: Boolean = activatedVersion >= V6SoftForkVersion } diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index 6656ede3c9..717439bcbb 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 @@ -375,6 +375,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") } } @@ -396,6 +397,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") } } @@ -419,6 +421,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") } } @@ -444,6 +447,7 @@ 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") } } @@ -465,24 +469,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) } } diff --git a/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala b/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala index 07fe8db0ee..9d4de47a99 100644 --- a/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala +++ b/data/shared/src/main/scala/org/ergoplatform/validation/ValidationRules.scala @@ -155,20 +155,6 @@ object ValidationRules { override protected lazy val settings: SigmaValidationSettings = currentSettings } - object CheckMinimalErgoTreeVersion extends ValidationRule(1016, - "ErgoTree should have at least required version") with SoftForkWhenReplaced { - override protected lazy val settings: SigmaValidationSettings = currentSettings - - final def apply(currentVersion: Byte, minVersion: Byte): Unit = { - checkRule() - if (currentVersion < minVersion) { - throwValidationException( - new SigmaException(s"ErgoTree should have at least $minVersion version, but was $currentVersion"), - Array(currentVersion, minVersion)) - } - } - } - val ruleSpecs: Seq[ValidationRule] = Seq( CheckDeserializedScriptType, CheckDeserializedScriptIsSigmaProp, @@ -185,8 +171,7 @@ object ValidationRules { CheckHeaderSizeBit, CheckCostFuncOperation, CheckPositionLimit, - CheckLoopLevelInCostFunction, - CheckMinimalErgoTreeVersion + CheckLoopLevelInCostFunction ) /** Validation settings that correspond to the current version of the ErgoScript implementation. diff --git a/data/shared/src/main/scala/sigma/ast/SMethod.scala b/data/shared/src/main/scala/sigma/ast/SMethod.scala index 47f6e744b0..11e656b1be 100644 --- a/data/shared/src/main/scala/sigma/ast/SMethod.scala +++ b/data/shared/src/main/scala/sigma/ast/SMethod.scala @@ -63,6 +63,7 @@ case class 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, @@ -73,7 +74,9 @@ case class SMethod( 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) @@ -114,7 +117,12 @@ 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]): Any = { - javaMethod.invoke(obj, args.asInstanceOf[Array[AnyRef]]:_*) + 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` @@ -154,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) @@ -263,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 @@ -297,7 +316,7 @@ object SMethod { ): SMethod = { SMethod( objType, name, stype, methodId, costKind, explicitTypeArgs, - MethodIRInfo(None, None, None), None, None) + 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 7d6da0a5f9..8b89851938 100644 --- a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala +++ b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala @@ -5,7 +5,6 @@ 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 diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 2cfecea15d..ef548d6185 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -1,7 +1,6 @@ package sigma.ast import org.ergoplatform._ -import org.ergoplatform.validation.ValidationRules.CheckMinimalErgoTreeVersion import org.ergoplatform.validation._ import sigma._ import sigma.ast.SCollection.{SBooleanArray, SBoxArray, SByteArray, SByteArray2, SHeaderArray} @@ -1534,7 +1533,6 @@ case object SGlobalMethods extends MonoTypeMethods { */ def serialize_eval(mc: MethodCall, G: SigmaDslBuilder, value: SType#WrappedType) (implicit E: ErgoTreeEvaluator): Coll[Byte] = { - CheckMinimalErgoTreeVersion(E.context.currentErgoTreeVersion, VersionContext.V6SoftForkVersion) E.addCost(SigmaByteWriter.StartWriterCost) diff --git a/data/shared/src/main/scala/sigma/ast/values.scala b/data/shared/src/main/scala/sigma/ast/values.scala index dd1f10d9be..ff5da32ec7 100644 --- a/data/shared/src/main/scala/sigma/ast/values.scala +++ b/data/shared/src/main/scala/sigma/ast/values.scala @@ -1298,8 +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/serialization/ErgoTreeSerializer.scala b/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala index ce7d1241c3..5122ee940c 100644 --- a/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala +++ b/data/shared/src/main/scala/sigma/serialization/ErgoTreeSerializer.scala @@ -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 @@ -304,21 +307,23 @@ class ErgoTreeSerializer { 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) @@ -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/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala index 9a1ab11f0e..c54e8bfc46 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala @@ -247,7 +247,12 @@ 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 diff --git a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala index e78518f8b3..603b75511d 100644 --- a/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigma/serialization/MethodCallSerializerSpecification.scala @@ -2,7 +2,6 @@ package sigma.serialization import sigma.VersionContext import sigma.ast.SCollection.SByteArray -import sigma.ast.SType.tT import sigma.ast._ import sigma.validation.ValidationException diff --git a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala index f9b52fe061..ac30a6cd0a 100644 --- a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala +++ b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala @@ -139,7 +139,8 @@ class SigmaTyper(val builder: SigmaBuilder, obj.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 diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationBase.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationBase.scala index 2bb44fc910..7be79546e7 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationBase.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationBase.scala @@ -1,10 +1,11 @@ package sigma import org.scalatest.BeforeAndAfterAll -import sigma.ast.JitCost -import sigma.eval.{EvalSettings, Profiler} +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.) @@ -123,4 +124,23 @@ abstract class LanguageSpecificationBase extends SigmaDslTesting 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/LanguageSpecificationV5.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala index 700b48fd13..af4f93d861 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala @@ -10,6 +10,7 @@ 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.ast.ErgoTree.{HeaderType, ZeroHeader} import sigma.ast.SCollection._ import sigma.ast.syntax._ @@ -47,17 +48,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => import TestData._ - ///===================================================== - /// 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( @@ -144,7 +134,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) 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), @@ -173,14 +165,14 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) } @@ -209,7 +201,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -246,10 +240,10 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) 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) } @@ -279,10 +273,10 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) 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) } @@ -327,7 +321,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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), @@ -343,7 +337,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) }", @@ -357,8 +351,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)) }", @@ -375,8 +369,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))) }", @@ -396,8 +390,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)))) }", @@ -431,7 +425,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)) }", @@ -460,7 +454,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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, @@ -486,7 +480,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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)), @@ -518,7 +512,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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( @@ -568,7 +562,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -611,7 +605,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -628,7 +623,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -645,7 +641,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -662,7 +659,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -679,7 +677,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)))), @@ -697,7 +696,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -796,6 +796,12 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ((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)] )( @@ -814,12 +820,19 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ((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, @@ -844,7 +857,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -885,16 +900,18 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -936,7 +953,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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("Short methods equivalence") { @@ -945,7 +962,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -964,7 +982,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -981,7 +1000,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -998,7 +1018,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -1015,7 +1036,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)))), @@ -1033,7 +1055,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -1125,7 +1148,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -1165,15 +1190,17 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -1215,7 +1242,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)(_ >= _) } @@ -1225,7 +1252,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -1244,7 +1272,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -1263,7 +1292,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -1278,7 +1308,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -1293,7 +1324,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)))), @@ -1310,57 +1342,59 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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( @@ -1403,7 +1437,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -1444,16 +1480,16 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -1495,7 +1531,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)(_ >= _) } @@ -1509,7 +1545,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -1530,7 +1566,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -1551,7 +1587,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -1572,7 +1609,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -1589,7 +1626,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)))), @@ -1609,83 +1646,85 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)) + ) ) ) ) @@ -1694,13 +1733,12 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) ) - ) - ))) + ))) } 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), @@ -1741,16 +1779,16 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -1792,14 +1830,14 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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("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)) @@ -1820,11 +1858,11 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -1946,8 +1984,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -1990,11 +2027,11 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)(_ != _) } @@ -2005,8 +2042,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -2050,7 +2086,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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(_, _)) } @@ -2059,12 +2095,12 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => * @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 @@ -2077,11 +2113,11 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => } 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") { @@ -2089,14 +2125,14 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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") { @@ -2105,30 +2141,29 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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") { @@ -2212,15 +2247,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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") { @@ -2232,63 +2267,71 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 @@ -2297,38 +2340,40 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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(_)) } @@ -2352,10 +2397,10 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)]]] @@ -2398,8 +2443,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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( @@ -2413,14 +2458,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ), 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))), @@ -2451,7 +2497,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -2481,7 +2527,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -2499,8 +2545,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => } 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"))), @@ -2523,7 +2570,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => FixedCostItem(Exponentiate) ) ) - verifyCases(cases(1873, costDetails), + verifyCases(cases(1873, costDetails, Seq.fill(4)(2121)), existingFeature( scalaFunc, script, @@ -2550,7 +2597,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => FixedCostItem(SGroupElementMethods.ExponentiateMethod, FixedCost(JitCost(900))) ) ) - verifyCases(cases(1873, costDetails), + verifyCases(cases(1873, costDetails, Seq.fill(4)(2121)), existingFeature( scalaFunc, script, @@ -2597,7 +2644,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) ) - 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"))), @@ -2660,7 +2707,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => } 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"))), @@ -2673,7 +2720,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -2686,7 +2733,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -2699,11 +2746,11 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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, @@ -2712,7 +2759,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -2725,7 +2772,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -2738,7 +2785,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -2993,7 +3040,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) - 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)) @@ -3071,8 +3118,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => // 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) @@ -3080,14 +3128,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => { 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 @@ -3096,7 +3145,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 @@ -3106,7 +3155,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))) } { @@ -3259,7 +3308,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 @@ -3267,7 +3316,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 @@ -3277,7 +3326,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 @@ -3407,7 +3456,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) @@ -3415,13 +3464,13 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 @@ -3429,7 +3478,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) @@ -3438,15 +3487,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))) } } @@ -3557,7 +3606,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))) } { @@ -3574,13 +3623,13 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 @@ -3588,14 +3637,14 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))) } } } @@ -3604,7 +3653,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -3624,20 +3673,20 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))) @@ -3652,7 +3701,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -3674,7 +3723,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))) @@ -3687,7 +3736,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)) @@ -3700,7 +3749,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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" @@ -3715,7 +3764,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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" @@ -3732,7 +3781,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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" @@ -3749,7 +3798,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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, @@ -3772,8 +3821,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 }", @@ -3842,11 +3891,11 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) => @@ -3971,10 +4020,10 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) => @@ -4068,7 +4117,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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, @@ -4080,7 +4129,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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, @@ -4092,7 +4141,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 }", @@ -4103,7 +4152,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 }", @@ -4114,7 +4163,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 }", @@ -4133,10 +4182,10 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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( @@ -4208,35 +4257,35 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 })) } @@ -4244,81 +4293,81 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => verifyCases( Seq((h1, Expected(Success( Helpers.decodeBytes("957f008001808080ffe4ffffc8f3802401df40006aa05e017fa8d3f6004c804a")), - cost = 1766, methodCostDetails(SHeaderMethods.idMethod, 10), 1766))), + 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 })) } @@ -4532,7 +4581,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) }, @@ -4557,7 +4606,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 }", @@ -4618,7 +4667,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) 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 }", @@ -4655,7 +4704,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => )) 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 } }", @@ -4715,7 +4764,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) 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) => @@ -4807,11 +4856,20 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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, 3).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( @@ -4837,7 +4895,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => } 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)) @@ -4850,7 +4908,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) 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 }", @@ -4871,7 +4929,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)) @@ -4911,7 +4969,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))))), @@ -4945,7 +5003,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) verifyCases( Seq( - ctx -> Expected(Success(-135729055492651903L), 1779, registerIsDefinedCostDetails, 1779) + ctx -> Expected(Success(-135729055492651903L), 1779, registerIsDefinedCostDetails, 1779, Seq.fill(4)(2065)) ), existingFeature( { (x: Context) => @@ -5007,11 +5065,19 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => Seq( ctx -> Expected(Failure(expectedError), 0, CostDetails.ZeroCost, 1793, newVersionedResults = { - Seq.tabulate(4)(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 @@ -5173,12 +5239,12 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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) => @@ -5381,22 +5447,22 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) => @@ -5614,15 +5680,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) => @@ -5847,15 +5913,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) => @@ -5960,7 +6026,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => cost = c, expectedDetails = CostDetails.ZeroCost, newCost = 1766, - newVersionedResults = Seq(0, 1, 2, 3).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))), @@ -5985,6 +6059,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) }, changedFeature( + changedInVersion = VersionContext.JitActivationVersion, (x: Coll[Boolean]) => SigmaDsl.xorOf(x), (x: Coll[Boolean]) => SigmaDsl.xorOf(x), "{ (x: Coll[Boolean]) => xorOf(x) }", @@ -5995,8 +6070,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))))) @@ -6006,7 +6081,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -6025,7 +6101,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -6043,7 +6119,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -6060,7 +6137,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -6077,7 +6155,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)))), @@ -6115,7 +6194,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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")))) @@ -6134,7 +6213,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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")))) @@ -6159,37 +6238,38 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) 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) + ) + ))) } } @@ -6225,7 +6305,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))), @@ -6236,9 +6316,16 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => cost = 0, expectedDetails = CostDetails.ZeroCost, newCost = 1769, - newVersionedResults = { - val res = (ExpectedResult(Success(Helpers.decodeBytes("00")), Some(1769)), Some(costDetails(1))) - Seq(0, 1, 2, 3).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"), @@ -6247,6 +6334,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) }, 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) }", @@ -6380,11 +6468,11 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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 }) }, @@ -6437,13 +6525,13 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 }) }, @@ -6476,11 +6564,12 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) }, @@ -6506,7 +6595,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -6531,7 +6620,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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)), @@ -6587,9 +6676,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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) { @@ -6666,9 +6755,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 }) }, @@ -6759,11 +6848,11 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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( @@ -6874,11 +6963,11 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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( @@ -7008,28 +7097,34 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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( @@ -7067,11 +7162,17 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) -> 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( @@ -7137,7 +7238,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))), @@ -7226,7 +7327,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))), @@ -7303,7 +7404,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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"))), @@ -7450,15 +7551,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => // (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( @@ -7711,15 +7812,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => // (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( @@ -7830,11 +7931,16 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -7896,7 +8002,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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"))), @@ -7960,7 +8067,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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)), @@ -8043,7 +8150,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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)) @@ -8058,7 +8165,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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( @@ -8067,7 +8174,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => )), 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( @@ -8109,9 +8216,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => { 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"))) ) }, @@ -8205,10 +8312,10 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => { 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"))) ) @@ -8256,24 +8363,24 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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") { @@ -8331,29 +8438,30 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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") { @@ -8380,48 +8488,49 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))") @@ -8471,37 +8580,38 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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( @@ -8578,33 +8688,33 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))), + (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))), @@ -8619,8 +8729,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 }) }", @@ -8682,10 +8792,10 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 }) }", @@ -8746,10 +8856,10 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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 ) }, @@ -8802,20 +8912,30 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => verifyCases( Seq( (None -> Expected( - value = Failure(new NoSuchElementException("None.get")), - cost = 0, - expectedDetails = CostDetails.ZeroCost, - newCost = 1766, - newVersionedResults = Seq.tabulate(4)(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) @@ -8880,19 +9000,22 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -8905,19 +9028,22 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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), @@ -8927,10 +9053,11 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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))))) @@ -8957,7 +9084,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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( @@ -8985,7 +9112,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) ) - ), 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")) ), @@ -9017,31 +9144,32 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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( @@ -9061,9 +9189,9 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => { 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( @@ -9092,32 +9220,33 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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( @@ -9141,12 +9270,13 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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( @@ -9184,25 +9314,25 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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, @@ -9213,19 +9343,20 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) }", @@ -9234,19 +9365,20 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) }", @@ -9259,10 +9391,11 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) }", @@ -9282,18 +9415,19 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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) }", @@ -9334,7 +9468,7 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) 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()), @@ -9346,8 +9480,16 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => expectedDetails = CostDetails.ZeroCost, newCost = 1783, newVersionedResults = { - val res = (ExpectedResult(Success(Helpers.decodeBytes("0008d3")), Some(1783)) -> Some(costDetails(0))) - Seq(0, 1, 2, 3).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( @@ -9356,21 +9498,30 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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, 3).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)) }, @@ -9422,6 +9573,12 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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( @@ -9429,107 +9586,110 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => cost = 1776, expectedDetails = CostDetails.ZeroCost, newCost = 1776, - newVersionedResults = Seq(0, 1, 2, 3).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) ) @@ -9540,8 +9700,8 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => 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])) => diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index e4ae10cac6..0b9e1eb4de 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -1,10 +1,14 @@ package sigma -import sigma.ast.{Apply, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, Global, JitCost, MethodCall, NamedDesc, OptionGet, SBigInt, SByte, SGlobalMethods, SInt, SLong, SShort, STypeVar, ValUse} +import sigma.ast.ErgoTree.ZeroHeader +import sigma.ast.SCollection.SByteArray +import sigma.ast.syntax.TrueSigmaProp +import sigma.ast._ import sigma.data.{CBigInt, ExactNumeric, RType} -import sigma.eval.{SigmaDsl, TracedCost} +import sigma.eval.{CostDetails, SigmaDsl, TracedCost} import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} import sigmastate.exceptions.MethodNotFound +import sigmastate.utils.Helpers import java.math.BigInteger import scala.util.Success @@ -234,21 +238,26 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => } 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") - ) + 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") + ) - // 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") - ) + // 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") + ) + } else { + forAll { x: BigInteger => + SBigInt.upcast(CBigInt(x).asInstanceOf[AnyVal]) shouldBe CBigInt(x) + SBigInt.downcast(CBigInt(x).asInstanceOf[AnyVal]) shouldBe CBigInt(x) + } + } if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { // NOTE, for such versions the new features are not supported @@ -287,6 +296,44 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => forAll { x: (BigInt, BigInt) => Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) } + + 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: 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 + } } } @@ -406,5 +453,87 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => } } + 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 + } } diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index 37fb0e6503..b2446b6795 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._ @@ -126,6 +127,9 @@ class SigmaDslTesting extends AnyPropSpec /** 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 @@ -362,14 +366,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)) } @@ -433,7 +439,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) @@ -492,7 +498,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 @@ -540,6 +546,8 @@ 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 */ @@ -652,16 +660,35 @@ class SigmaDslTesting extends AnyPropSpec checkResult(funcRes.map(_._1), expected.value, failOnTestVectors, "ExistingFeature#verifyCase: ") - checkResultAgainstExpected(funcRes, expected) + val newRes = expected.newResults(ergoTreeVersionInTests) + val expectedTrace = newRes._2.fold(Seq.empty[CostItem])(_.trace) + if (expectedTrace.isEmpty) { + // new cost expectation is missing, print out actual cost results + if (evalSettings.printTestVectors) { + funcRes.foreach { case (_, newDetails) => + printCostDetails(script, newDetails) + } + } + } + else { + // new cost expectation is specified, compare it with the actual result + funcRes.foreach { case (_, newDetails) => + if (newDetails.trace != expectedTrace) { + printCostDetails(script, newDetails) + newDetails.trace shouldBe expectedTrace + } + } + } + checkVerify(input, expected) } - } - /** 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 @@ -681,6 +708,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, @@ -694,6 +722,8 @@ 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 */ @@ -773,7 +803,7 @@ class SigmaDslTesting extends AnyPropSpec checkEq(scalaFuncNew)(newF)(input) } - if (!VersionContext.current.isJitActivated) { + if (VersionContext.current.activatedVersion < changedInVersion) { // check the old implementation with Scala semantic val expectedOldRes = expected.value @@ -1035,6 +1065,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. * @@ -1045,8 +1099,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 = { @@ -1089,14 +1145,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) } From d8cc09d386e12049ae77b618a35912b1edc2e4a3 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 14 Aug 2024 14:35:51 +0300 Subject: [PATCH 105/123] deserializeCostKind --- data/shared/src/main/scala/sigma/ast/methods.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index caa2bc44b2..0f5c648e68 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -1533,10 +1533,13 @@ case object SGlobalMethods extends MonoTypeMethods { .withInfo(Xor, "Byte-wise XOR of two collections of bytes", ArgInfo("left", "left operand"), ArgInfo("right", "right operand")) + private val deserializeCostKind = PerItemCost( + baseCost = JitCost(20), perChunkCost = JitCost(7), chunkSize = 128) + lazy val desJava = ownerType.reprClass.getMethod("deserializeTo", classOf[SType], classOf[Coll[Byte]], classOf[RType[_]]) lazy val deserializeToMethod = SMethod( - this, "deserializeTo", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 3, Xor.costKind, Seq(tT)) // todo: cost + this, "deserializeTo", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 3, deserializeCostKind, Seq(tT)) .withIRInfo(MethodCallIrBuilder, desJava) // .copy(irInfo = MethodIRInfo(None, Some(desJava), None)) .withInfo(MethodCall, "Byte-wise XOR of two collections of bytes", // todo: desc @@ -1556,7 +1559,7 @@ case object SGlobalMethods extends MonoTypeMethods { (implicit E: ErgoTreeEvaluator): Any = { val tpe = mc.tpe val cT = stypeToRType(tpe) - E.addSeqCost(Xor.costKind, bytes.length, Xor.opDesc) { () => // todo: cost + E.addSeqCost(deserializeCostKind, bytes.length, deserializeToMethod.opDesc) { () => G.deserializeTo(tpe, bytes)(cT) } } From 57e39bea23992229637fddf2a32d1f74abda479a Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sun, 18 Aug 2024 23:05:40 +0300 Subject: [PATCH 106/123] Header.bytes removed --- core/shared/src/main/scala/sigma/SigmaDsl.scala | 2 -- .../scala/sigma/reflection/ReflectionData.scala | 3 --- .../src/main/scala/sigma/data/CHeader.scala | 2 -- .../TestingInterpreterSpecification.scala | 7 ++----- .../sigmastate/utxo/BasicOpsSpecification.scala | 16 +++++++--------- 5 files changed, 9 insertions(+), 21 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 42d8df1587..c8bf9aabaf 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -466,8 +466,6 @@ trait Header { def serializeWithoutPoW: Coll[Byte] def checkPow: Boolean - - def bytes: Coll[Byte] } /** Runtime representation of Context ErgoTree type. diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index 174a631210..795d0bb8de 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -349,9 +349,6 @@ object ReflectionData { }, mkMethod(clazz, "checkPow", Array[Class[_]]()) { (obj, _) => obj.asInstanceOf[Header].checkPow - }, - mkMethod(clazz, "bytes", Array[Class[_]]()) { (obj, _) => - obj.asInstanceOf[Header].bytes } ) ) diff --git a/data/shared/src/main/scala/sigma/data/CHeader.scala b/data/shared/src/main/scala/sigma/data/CHeader.scala index 1a0d5b37ed..e579f05844 100644 --- a/data/shared/src/main/scala/sigma/data/CHeader.scala +++ b/data/shared/src/main/scala/sigma/data/CHeader.scala @@ -81,8 +81,6 @@ case class CHeader(ergoHeader: ErgoHeader) extends Header with WrapperOf[ErgoHea } } - override def bytes: Coll[Byte] = Colls.fromArray(ergoHeader.bytes) - } object CHeader { diff --git a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala index 28a4d792aa..a783eab745 100644 --- a/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/TestingInterpreterSpecification.scala @@ -13,12 +13,9 @@ import org.scalatest.BeforeAndAfterAll import scorex.util.encode.{Base16, Base58} import sigma.Colls import sigma.VersionContext.V6SoftForkVersion -import sigma.data.{CAND, CAvlTree, ProveDlog, SigmaBoolean, TrivialProp} +import sigma.data.{CAND, CAvlTree, CHeader, ProveDlog, SigmaBoolean, TrivialProp} import sigma.interpreter.ContextExtension -import scorex.util.encode.Base58 import sigma.VersionContext -import sigma.crypto.CryptoConstants -import sigma.data.{AvlTreeData, CAND, ProveDlog, SigmaBoolean, TrivialProp} import sigma.util.Extensions.IntOps import sigmastate.helpers.{CompilerTestingCommons, ErgoLikeContextTesting, ErgoLikeTestInterpreter, ErgoLikeTestProvingInterpreter} import sigmastate.helpers.TestingHelpers._ @@ -497,7 +494,7 @@ class TestingInterpreterSpecification extends CompilerTestingCommons property("bytes") { - val headerBytes = Base16.encode(contextHeader.bytes.toArray) + val headerBytes = Base16.encode(contextHeader.asInstanceOf[CHeader].ergoHeader.bytes) // checking hash of bytes(id) against known value val source = s""" { diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index f8c0bdbadb..ba5ff42f7d 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -7,15 +7,14 @@ import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert} import scorex.crypto.hash.{Blake2b256, Digest32} import scorex.util.ByteArrayBuilder import scorex.util.encode.Base16 -import scorex.util.serialization.{VLQByteBufferReader, VLQByteBufferWriter} -import scorex.utils.{Ints, Longs, Shorts} -import sigma.{BigInt, Colls, SigmaTestingData} -import scorex.util.encode.Base16 +import scorex.util.serialization.VLQByteBufferWriter +import scorex.utils.Longs +import sigma.{Colls, SigmaTestingData} import sigma.Extensions.ArrayOps import sigma.VersionContext.V6SoftForkVersion import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps -import sigma.data.{AvlTreeData, AvlTreeFlags, CAND, CAnyValue, CSigmaDslBuilder, CSigmaProp} +import sigma.data.{AvlTreeData, AvlTreeFlags, CAND, CAnyValue, CHeader, CSigmaDslBuilder, CSigmaProp} import sigma.util.StringUtil._ import sigma.ast._ import sigma.ast.syntax._ @@ -29,10 +28,9 @@ import sigmastate.interpreter.Interpreter._ import sigma.ast.Apply import sigma.eval.EvalSettings import sigma.exceptions.InvalidType -import sigma.serialization.{ConstantStore, DataSerializer, ErgoTreeSerializer, SigmaByteReader, SigmaByteWriter, ValueSerializer} +import sigma.serialization.{DataSerializer, ErgoTreeSerializer, SigmaByteWriter} import sigma.util.Extensions import sigmastate.utils.Helpers -import sigma.serialization.ErgoTreeSerializer import sigmastate.utils.Helpers._ import java.math.BigInteger @@ -420,7 +418,7 @@ class BasicOpsSpecification extends CompilerTestingCommons property("deserializeTo - header") { val td = new SigmaTestingData {} val h1 = td.TestData.h1 - val headerBytes = h1.bytes + val headerBytes = h1.asInstanceOf[CHeader].ergoHeader.bytes val headerStateBytes = AvlTreeData.serializer.toBytes(Extensions.CoreAvlTreeOps(h1.stateRoot).toAvlTreeData) val customExt = Seq(21.toByte -> ByteArrayConstant(headerBytes), 22.toByte -> ByteArrayConstant(headerStateBytes)) @@ -447,7 +445,7 @@ class BasicOpsSpecification extends CompilerTestingCommons property("deserializeTo - header option") { val td = new SigmaTestingData {} - val h1 = td.TestData.h1 + val h1 = td.TestData.h1.asInstanceOf[CHeader].ergoHeader val headerBytes = Colls.fromArray(Array(1.toByte) ++ h1.bytes.toArray) val customExt = Seq(21.toByte -> ByteArrayConstant(headerBytes)) From bcfb24df6ed5bd95753e9164faa7e17efbddf0e8 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 26 Aug 2024 00:36:20 +0300 Subject: [PATCH 107/123] removing unused CSigmaDslBuilder.validationSettings --- data/shared/src/main/scala/sigma/ast/trees.scala | 4 ++-- data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/trees.scala b/data/shared/src/main/scala/sigma/ast/trees.scala index 7be73ad55a..33567868fd 100644 --- a/data/shared/src/main/scala/sigma/ast/trees.scala +++ b/data/shared/src/main/scala/sigma/ast/trees.scala @@ -653,7 +653,7 @@ case class SubstConstants[T <: SType](scriptBytes: Value[SByteArray], positions: val (newBytes, nConstants) = SubstConstants.eval( scriptBytes = scriptBytesV.toArray, positions = positionsV.toArray, - newVals = typedNewVals)(SigmaDsl.validationSettings) + newVals = typedNewVals) res = Colls.fromArray(newBytes) nConstants @@ -684,7 +684,7 @@ object SubstConstants extends ValueCompanion { */ def eval(scriptBytes: Array[Byte], positions: Array[Int], - newVals: Array[Constant[SType]])(implicit vs: SigmaValidationSettings): (Array[Byte], Int) = + newVals: Array[Constant[SType]]): (Array[Byte], Int) = ErgoTreeSerializer.DefaultSerializer.substituteConstants(scriptBytes, positions, newVals) } diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 4a3842e250..e5bb8920ae 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -20,7 +20,6 @@ import java.math.BigInteger * @see [[SigmaDslBuilder]] for detailed descriptions */ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => - implicit val validationSettings: SigmaValidationSettings = ValidationRules.currentSettings override val Colls: CollBuilder = sigma.Colls @@ -193,7 +192,7 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => case e: Throwable => throw new RuntimeException(s"Cannot evaluate substConstants($scriptBytes, $positions, $newValues)", e) } - val (res, _) = SubstConstants.eval(scriptBytes.toArray, positions.toArray, constants)(validationSettings) + val (res, _) = SubstConstants.eval(scriptBytes.toArray, positions.toArray, constants) Colls.fromArray(res) } From 016262b6b2759529ae3f5f9567548b1191f49f7c Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 27 Aug 2024 21:26:16 +0300 Subject: [PATCH 108/123] removing unused SNumericTypeMethods.getMethods --- data/shared/src/main/scala/sigma/ast/methods.scala | 8 +++----- .../src/test/scala/sigmastate/ErgoTreeSpecification.scala | 3 --- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 99459840de..f2481fd879 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -186,6 +186,7 @@ trait SNumericTypeMethods extends MonoTypeMethods { } object SNumericTypeMethods extends MethodsContainer { + /** Type for which this container defines methods. */ override def ownerType: STypeCompanion = SNumericType @@ -399,11 +400,8 @@ object SNumericTypeMethods extends MethodsContainer { ) protected override def getMethods(): Seq[SMethod] = { - if (VersionContext.current.isV6SoftForkActivated) { - v6Methods - } else { - v5Methods - } + // this .getMethods shouldn't ever be called + ??? } /** Collection of names of numeric casting methods (like `toByte`, `toInt`, etc). */ diff --git a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala index 7ca46c8d16..406b84e26a 100644 --- a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala @@ -580,9 +580,6 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with C val mc = MethodsContainer(tyDesc.typeId) - println("mc: " + mc.methods.map(_.name)) - println("methods: " + methods.map(_.method.name)) - mc.methods.length shouldBe methods.length for (expectedMethod <- methods) { From baef87f403cf65ffdeaf264420a35c41e626eb48 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 2 Sep 2024 20:20:50 +0300 Subject: [PATCH 109/123] more efficient toBits impl --- .../main/scala/sigma/data/ExactNumeric.scala | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index 214569e6e5..90d28e5370 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -1,7 +1,10 @@ package sigma.data +import debox.cfor +import sigma.Evaluation.stypeToRType import sigma.{BigInt, Coll, Colls} import sigma.data.ExactIntegral._ +import sigma.data.RType.SomeType import scala.collection.mutable @@ -40,18 +43,22 @@ trait ExactNumeric[T] { def toBigEndianBytes(x: T): Coll[Byte] def toBits(x: T): Coll[Boolean] = { - def byte2Bools(b: Byte): Array[Boolean] = (0 to 7).toArray.reverse.map(isBitSet(b)) def isBitSet(byte: Byte)(bit: Int): Boolean = ((byte >> bit) & 1) == 1 + def byte2Bools(b: Byte): Array[Boolean] = (0 to 7).toArray.reverse.map(isBitSet(b)) + val bytes = toBigEndianBytes(x) - val builder = mutable.ArrayBuilder.make[Boolean] val l = bytes.length - (0 until l).foreach{i=> + val res = new Array[Boolean](l * 8) + var offset = 0 + cfor(0)(_ < l, _ + 1) { i => val b = bytes(i) - builder.addAll(byte2Bools(b)) + val bits = byte2Bools(b) + Array.copy(bits, 0, res, offset, 8) + offset += 8 } - Colls.fromArray(builder.result()) + Colls.fromArray(res) } def bitwiseInverse(x: T): T From 2e8d8f41a86acbca8b4e8d25ad2d7c86511cc7c3 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 3 Sep 2024 14:06:50 +0300 Subject: [PATCH 110/123] optimizing imports, polishing --- core/shared/src/main/scala/sigma/SigmaDsl.scala | 3 +++ .../src/main/scala/sigma/serialization/TypeSerializer.scala | 2 -- data/shared/src/main/scala/sigma/ast/methods.scala | 1 - data/shared/src/main/scala/sigma/data/ExactNumeric.scala | 6 +----- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 5e647cad0e..9cf632cc59 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -155,6 +155,9 @@ trait BigInt { def or(that: BigInt): BigInt def |(that: BigInt): BigInt = or(that) + /** + * @return a big integer whose value is `this xor that` + */ def xor(that: BigInt): BigInt def shiftLeft(bits: Int): BigInt diff --git a/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala b/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala index c21a3458c0..1936bbcd9a 100644 --- a/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala +++ b/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala @@ -4,7 +4,6 @@ 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} @@ -215,7 +214,6 @@ class TypeSerializer { STypeParam(ident.asInstanceOf[STypeVar]) } SFunc(tDom, tRange, tpeParams) - // todo: serialize tParams case _ => // todo: 6.0: replace 1008 check with identical behavior but other opcode, to activate // ReplacedRule(1008 -> new opcode) during 6.0 activation diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index b40cdca79c..67bb1c74fb 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -5,7 +5,6 @@ import org.ergoplatform.validation._ import sigma._ import sigma.ast.SCollection.{SBooleanArray, SBoxArray, SByteArray, SByteArray2, SHeaderArray} import sigma.ast.SMethod.{MethodCallIrBuilder, MethodCostFunc, javaMethodOf} -import sigma.ast.SNumericTypeMethods.BitwiseAndMethod import sigma.ast.SType.TypeCode import sigma.ast.syntax.{SValue, ValueOps} import sigma.data.ExactIntegral.{ByteIsExactIntegral, IntIsExactIntegral, LongIsExactIntegral, ShortIsExactIntegral} diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index 90d28e5370..9612cccc34 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -1,12 +1,8 @@ package sigma.data import debox.cfor -import sigma.Evaluation.stypeToRType -import sigma.{BigInt, Coll, Colls} +import sigma.{Coll, Colls} import sigma.data.ExactIntegral._ -import sigma.data.RType.SomeType - -import scala.collection.mutable /** Numeric operations with overflow checks. * Raise exception when overflow is detected. From ed5b8f5383db1fba53a5d90887fb6efa21a13810 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 4 Sep 2024 14:48:39 +0300 Subject: [PATCH 111/123] fixing SigmaTyperTest --- .../test/scala/sigmastate/lang/SigmaTyperTest.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala b/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala index e8bfeb777f..3696a7e14e 100644 --- a/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala +++ b/sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala @@ -523,7 +523,7 @@ class SigmaTyperTest extends AnyPropSpec typecheck(env, "1.toByte.toBytes", expected = MethodCall.typed[Value[SCollection[SByte.type]]]( Select(IntConstant(1), "toByte", Some(SByte)), - SNumericTypeMethods.getMethodByName("toBytes").withConcreteTypes(Map(STypeVar("TNum") -> SByte)), + SNumericTypeMethods.ToBytesMethod.withConcreteTypes(Map(STypeVar("TNum") -> SByte)), Vector(), Map() )) shouldBe SByteArray @@ -531,7 +531,7 @@ class SigmaTyperTest extends AnyPropSpec typecheck(env, "1.toShort.toBytes", expected = MethodCall.typed[Value[SCollection[SByte.type]]]( Select(IntConstant(1), "toShort", Some(SShort)), - SNumericTypeMethods.getMethodByName("toBytes").withConcreteTypes(Map(STypeVar("TNum") -> SShort)), + SNumericTypeMethods.ToBytesMethod.withConcreteTypes(Map(STypeVar("TNum") -> SShort)), Vector(), Map() )) shouldBe SByteArray @@ -539,7 +539,7 @@ class SigmaTyperTest extends AnyPropSpec typecheck(env, "1.toBytes", expected = MethodCall.typed[Value[SCollection[SByte.type]]]( IntConstant(1), - SNumericTypeMethods.getMethodByName("toBytes").withConcreteTypes(Map(STypeVar("TNum") -> SInt)), + SNumericTypeMethods.ToBytesMethod.withConcreteTypes(Map(STypeVar("TNum") -> SInt)), Vector(), Map() )) shouldBe SByteArray @@ -547,7 +547,7 @@ class SigmaTyperTest extends AnyPropSpec typecheck(env, "1.toLong.toBytes", expected = MethodCall.typed[Value[SCollection[SByte.type]]]( Select(IntConstant(1), "toLong", Some(SLong)), - SNumericTypeMethods.getMethodByName("toBytes").withConcreteTypes(Map(STypeVar("TNum") -> SLong)), + SNumericTypeMethods.ToBytesMethod.withConcreteTypes(Map(STypeVar("TNum") -> SLong)), Vector(), Map() )) shouldBe SByteArray @@ -555,7 +555,7 @@ class SigmaTyperTest extends AnyPropSpec typecheck(env, "1.toBigInt.toBytes", expected = MethodCall.typed[Value[SCollection[SByte.type]]]( Select(IntConstant(1), "toBigInt", Some(SBigInt)), - SNumericTypeMethods.getMethodByName("toBytes").withConcreteTypes(Map(STypeVar("TNum") -> SBigInt)), + SNumericTypeMethods.ToBytesMethod.withConcreteTypes(Map(STypeVar("TNum") -> SBigInt)), Vector(), Map() )) shouldBe SByteArray From b2de9cf057648691d395b036e14f2ade1049dff1 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 6 Sep 2024 19:57:59 +0300 Subject: [PATCH 112/123] scaladoc --- .../src/main/scala/sigma/SigmaDsl.scala | 16 +++++++++---- .../src/main/scala/sigma/data/CBigInt.scala | 4 ++-- .../main/scala/sigma/data/ExactNumeric.scala | 23 +++++++++++++++++++ .../compiler/ir/primitives/UnBinOps.scala | 6 +++-- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 9cf632cc59..6f9a3e2ffe 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -5,9 +5,7 @@ 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. @@ -160,9 +158,17 @@ trait BigInt { */ def xor(that: BigInt): BigInt - def shiftLeft(bits: Int): BigInt + /** + * @return a 256-bit signed integer whose value 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(n: Int): BigInt - def shiftRight(bits: Int): BigInt + /** + * @return a 256-bit signed integer whose value 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(n: Int): BigInt } /** Base class for points on elliptic curves. */ diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index dbfec02844..ea69174877 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -52,7 +52,7 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr override def xor(that: BigInt): BigInt = CBigInt(wrappedValue.xor(that.asInstanceOf[CBigInt].wrappedValue)) - def shiftLeft(bits: Int): BigInt = CBigInt(wrappedValue.shiftLeft(bits).to256BitValueExact) + override def shiftLeft(n: Int): BigInt = CBigInt(wrappedValue.shiftLeft(n).to256BitValueExact) - def shiftRight(bits: Int): BigInt = CBigInt(wrappedValue.shiftRight(bits).to256BitValueExact) + override def shiftRight(n: Int): BigInt = CBigInt(wrappedValue.shiftRight(n).to256BitValueExact) } diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index 9612cccc34..56b4a9369e 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -38,6 +38,9 @@ trait ExactNumeric[T] { */ 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 @@ -57,16 +60,36 @@ trait ExactNumeric[T] { 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. */ diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/UnBinOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/UnBinOps.scala index 62bfc29f68..b55596052e 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/UnBinOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/UnBinOps.scala @@ -45,6 +45,7 @@ trait UnBinOps extends Base { self: IRContext => 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 @@ -91,13 +92,14 @@ trait UnBinOps extends Base { self: IRContext => 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. */ + /** 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. */ + /** 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)) From eccc9cae1b13def59988e60c201410a812982bd6 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 10 Sep 2024 12:55:38 +0300 Subject: [PATCH 113/123] 6.0 methods for Byte in LSV6 --- .../src/main/scala/sigma/ast/methods.scala | 14 +- .../compiler/ir/primitives/NumericOps.scala | 2 +- .../scala/sigma/LanguageSpecificationV6.scala | 197 +++++++++++++++--- .../utxo/BasicOpsSpecification.scala | 17 ++ 4 files changed, 196 insertions(+), 34 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 67bb1c74fb..1e8fb911bb 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -161,13 +161,13 @@ trait SNumericTypeMethods extends MonoTypeMethods { private val subst = Map(tNum -> this.ownerType) - private val v5Methods = { + val v5Methods = { SNumericTypeMethods.v5Methods.map { m => m.copy(stype = applySubst(m.stype, subst).asFunc) } } - private val v6Methods = { + val v6Methods = { SNumericTypeMethods.v6Methods.map { m => m.copy( objType = this, // associate the method with the concrete numeric type @@ -306,7 +306,7 @@ object SNumericTypeMethods extends MethodsContainer { case SBigIntMethods => BigIntIsExactIntegral.bitwiseOr(obj.asInstanceOf[BigInt], other.head.asInstanceOf[BigInt]) } }) - .withInfo(PropertyCall, + .withInfo(MethodCall, """ Returns a big-endian representation of this numeric in a collection of Booleans. | Each boolean corresponds to one bit. """.stripMargin) @@ -323,7 +323,7 @@ object SNumericTypeMethods extends MethodsContainer { case SBigIntMethods => BigIntIsExactIntegral.bitwiseAnd(obj.asInstanceOf[BigInt], other.head.asInstanceOf[BigInt]) } }) - .withInfo(PropertyCall, + .withInfo(MethodCall, """ Returns a big-endian representation of this numeric in a collection of Booleans. | Each boolean corresponds to one bit. """.stripMargin) @@ -340,7 +340,7 @@ object SNumericTypeMethods extends MethodsContainer { case SBigIntMethods => BigIntIsExactIntegral.bitwiseXor(obj.asInstanceOf[BigInt], other.head.asInstanceOf[BigInt]) } }) - .withInfo(PropertyCall, + .withInfo(MethodCall, """ Returns a big-endian representation of this numeric in a collection of Booleans. | Each boolean corresponds to one bit. """.stripMargin) @@ -357,7 +357,7 @@ object SNumericTypeMethods extends MethodsContainer { case SBigIntMethods => BigIntIsExactIntegral.shiftLeft(obj.asInstanceOf[BigInt], other.head.asInstanceOf[Int]) } }) - .withInfo(PropertyCall, + .withInfo(MethodCall, """ Returns a big-endian representation of this numeric in a collection of Booleans. | Each boolean corresponds to one bit. """.stripMargin) @@ -374,7 +374,7 @@ object SNumericTypeMethods extends MethodsContainer { case SBigIntMethods => BigIntIsExactIntegral.shiftRight(obj.asInstanceOf[BigInt], other.head.asInstanceOf[Int]) } }) - .withInfo(PropertyCall, + .withInfo(MethodCall, """ Returns a big-endian representation of this numeric in a collection of Booleans. | Each boolean corresponds to one bit. """.stripMargin) diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala index 9a6b372033..5b858d8586 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/primitives/NumericOps.scala @@ -105,7 +105,7 @@ trait NumericOps extends Base { self: IRContext => } } - /** Descriptor of unary `ToBits` conversion operation. */ + /** 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) } diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index dd577b5b38..57951586fb 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -50,38 +50,183 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => testCases(cases, toByte) } - property("Byte methods equivalence (new features)") { - // TODO v6.0: implement as part of https://github.com/ScorexFoundation/sigmastate-interpreter/issues/474 - if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { - // NOTE, for such versions the new features are not supported - // which is checked below + property("Byte methods - 6.0 features") { - lazy val toAbs = newFeature((x: Byte) => x.toAbs, "{ (x: Byte) => x.toAbs }", - sinceVersion = V6SoftForkVersion) + 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) - lazy val compareTo = newFeature( - (x: (Byte, Byte)) => x._1.compareTo(x._2), - "{ (x: (Byte, Byte)) => x._1.compareTo(x._2) }", - sinceVersion = V6SoftForkVersion) + verifyCases( + Seq( + (1.toByte, 2.toByte) -> new Expected(ExpectedResult(Success(3.toByte), None)) + ), + bitOr + ) - lazy val bitOr = newFeature( - { (x: (Byte, Byte)) => (x._1 | x._2).toByteExact }, - "{ (x: (Byte, Byte)) => (x._1 | x._2) }", - sinceVersion = V6SoftForkVersion) + 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) - lazy val bitAnd = newFeature( - { (x: (Byte, Byte)) => (x._1 & x._2).toByteExact }, - "{ (x: (Byte, Byte)) => (x._1 & x._2) }", - sinceVersion = V6SoftForkVersion) + verifyCases( + Seq( + 1.toByte -> new Expected(ExpectedResult(Success((-2).toByte), None)) + ), + bitNot + ) - forAll { x: Byte => - Seq(toAbs).foreach(f => f.checkEquality(x)) - } + 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) - forAll { x: (Byte, Byte) => - Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) - } - } + 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)) => (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)) + ), + shiftLeft + ) + + lazy val shiftRight = newFeature( + { (x: (Byte, Int)) => (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)) + ), + shiftRight + ) } // TODO v6.0: enable as part of https://github.com/ScorexFoundation/sigmastate-interpreter/issues/474 diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index f531c2b07d..a37a3d1079 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -360,6 +360,23 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + 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[Exception] shouldBe thrownBy(shiftLeftTest()) + } + } + property("BigInt.shiftLeft") { def shiftLeftTest(): Assertion = test("BigInt.shiftLeft", env, ext, s"""{ From f566b7bd4bb93e41ad52357db6d1251979b865d2 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 10 Sep 2024 14:09:02 +0300 Subject: [PATCH 114/123] 6.0 methods for Short in LSV6 --- .../scala/sigma/LanguageSpecificationV6.scala | 205 ++++++++++++++++-- 1 file changed, 182 insertions(+), 23 deletions(-) diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 57951586fb..725b999f6e 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -6,11 +6,12 @@ import sigma.VersionContext.V6SoftForkVersion import org.ergoplatform.ErgoBox import org.ergoplatform.ErgoBox.Token import scorex.util.ModifierId +import scorex.utils.Shorts import sigma.ast.ErgoTree.ZeroHeader import sigma.ast.SCollection.SByteArray import sigma.ast.syntax.TrueSigmaProp import sigma.ast._ -import sigma.data.{CBigInt, CHeader, CBox, ExactNumeric} +import sigma.data.{CBigInt, CBox, CHeader, ExactNumeric} import sigma.eval.{CostDetails, SigmaDsl, TracedCost} import sigma.serialization.ValueCodes.OpCode import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} @@ -229,36 +230,194 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) } - // TODO v6.0: enable as part of https://github.com/ScorexFoundation/sigmastate-interpreter/issues/474 - property("Short methods equivalence (new features)") { - if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { - // NOTE, for such versions the new features are not supported - // which is checked below + property("Short - 6.0 methods") { - lazy val toAbs = newFeature((x: Short) => x.toAbs, "{ (x: Short) => x.toAbs }", - sinceVersion = V6SoftForkVersion) + 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) - lazy val compareTo = newFeature((x: (Short, Short)) => x._1.compareTo(x._2), - "{ (x: (Short, Short)) => x._1.compareTo(x._2) }", - 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 bitOr = newFeature( - { (x: (Short, Short)) => (x._1 | x._2).toShortExact }, - "{ (x: (Short, Short)) => x._1 | x._2 }", + 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) - lazy val bitAnd = newFeature( + 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 & x._2 }", + "{ (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) - forAll { x: Short => - Seq(toAbs).foreach(_.checkEquality(x)) - } - forAll { x: (Short, Short) => - Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) - } - } + 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 => 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)) => (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)), + ), + shiftLeft + ) + + lazy val shiftRight = newFeature( + { (x: (Short, Int)) => (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)) + ), + shiftRight + ) } property("Int methods equivalence (new features)") { From 8cf4264e6c080d61193e8564c4f62ee1fec52ca1 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 10 Sep 2024 15:19:07 +0300 Subject: [PATCH 115/123] 6.0 methods for Int in LSV6 --- .../scala/sigma/LanguageSpecificationV6.scala | 217 ++++++++++++++++-- 1 file changed, 194 insertions(+), 23 deletions(-) diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 725b999f6e..fbc117235a 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -6,11 +6,11 @@ import sigma.VersionContext.V6SoftForkVersion import org.ergoplatform.ErgoBox import org.ergoplatform.ErgoBox.Token import scorex.util.ModifierId -import scorex.utils.Shorts +import scorex.utils.{Ints, Shorts} import sigma.ast.ErgoTree.ZeroHeader import sigma.ast.SCollection.SByteArray import sigma.ast.syntax.TrueSigmaProp -import sigma.ast._ +import sigma.ast.{SInt, _} import sigma.data.{CBigInt, CBox, CHeader, ExactNumeric} import sigma.eval.{CostDetails, SigmaDsl, TracedCost} import sigma.serialization.ValueCodes.OpCode @@ -420,30 +420,201 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) } - property("Int methods equivalence (new features)") { - if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { - // NOTE, for such versions the new features are not supported - // which is checked below - lazy val toAbs = newFeature((x: Int) => x.toAbs, "{ (x: Int) => x.toAbs }", - sinceVersion = V6SoftForkVersion) - lazy val compareTo = newFeature((x: (Int, Int)) => x._1.compareTo(x._2), - "{ (x: (Int, Int)) => x._1.compareTo(x._2) }", - sinceVersion = V6SoftForkVersion) - lazy val bitOr = newFeature( - { (x: (Int, Int)) => x._1 | x._2 }, - "{ (x: (Int, Int)) => x._1 | x._2 }", + 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) - lazy val bitAnd = newFeature( + + 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 & 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) - forAll { x: Int => - Seq(toAbs).foreach(_.checkEquality(x)) - } - forAll { x: (Int, Int) => - Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) - } - } + + 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 => 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)) => (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)) + ), + shiftLeft + ) + + lazy val shiftRight = newFeature( + { (x: (Int, Int)) => (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)) + ), + shiftRight + ) } property("Long methods equivalence (new features)") { From fa2c2dfc7fe0f1dc0102901bf7ce75d1005af87c Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 11 Sep 2024 14:11:39 +0300 Subject: [PATCH 116/123] Long tests in LSV6, shift check in shiftRight --- .../main/scala/sigma/data/ExactIntegral.scala | 32 ++- .../scala/sigma/LanguageSpecificationV6.scala | 237 +++++++++++++++--- .../test/scala/sigma/SigmaDslTesting.scala | 7 +- 3 files changed, 242 insertions(+), 34 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index 418bc1837b..4b0d9cb720 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -44,7 +44,13 @@ object ExactIntegral { 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 = (x << bits).toByte - override def shiftRight(x: Byte, bits: Int): Byte = (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] { @@ -59,7 +65,13 @@ object ExactIntegral { 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, y: Int): Short = (x << y).toShort - override def shiftRight(x: Short, bits: Int): Short = (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] { @@ -74,7 +86,13 @@ object ExactIntegral { 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, y: Int): Int = x << y - override def shiftRight(x: Int, bits: Int): Int = 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] { @@ -89,6 +107,12 @@ object ExactIntegral { 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, y: Int): Long = x << y - override def shiftRight(x: Long, bits: Int): Long = 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/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index fbc117235a..b7dd5b028d 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -6,7 +6,7 @@ import sigma.VersionContext.V6SoftForkVersion import org.ergoplatform.ErgoBox import org.ergoplatform.ErgoBox.Token import scorex.util.ModifierId -import scorex.utils.{Ints, Shorts} +import scorex.utils.{Ints, Longs, Shorts} import sigma.ast.ErgoTree.ZeroHeader import sigma.ast.SCollection.SByteArray import sigma.ast.syntax.TrueSigmaProp @@ -20,7 +20,7 @@ import sigmastate.utils.Extensions.ByteOpsForSigma import sigmastate.utils.Helpers import java.math.BigInteger -import scala.util.Success +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. @@ -226,7 +226,8 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => Seq( (24.toByte, 3) -> new Expected(ExpectedResult(Success(3.toByte), None)) ), - shiftRight + shiftRight, + preGeneratedSamples = Some(Seq()) ) } @@ -416,7 +417,8 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => (1600.toShort, 8) -> new Expected(ExpectedResult(Success(6.toShort), None)), ((-3200).toShort, 8) -> new Expected(ExpectedResult(Success((-13).toShort), None)) ), - shiftRight + shiftRight, + preGeneratedSamples = Some(Seq()) ) } @@ -613,38 +615,215 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => (-3200, 8) -> new Expected(ExpectedResult(Success(-13), None)), (-320019, 18) -> new Expected(ExpectedResult(Success(-2), None)) ), - shiftRight + shiftRight, + preGeneratedSamples = Some(Seq()) ) } - property("Long methods equivalence (new features)") { - if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { - // NOTE, for such versions the new features are not supported - // which is checked below - lazy val toAbs = newFeature((x: Long) => x.toAbs, "{ (x: Long) => x.toAbs }", - sinceVersion = V6SoftForkVersion) - lazy val compareTo = newFeature((x: (Long, Long)) => x._1.compareTo(x._2), - "{ (x: (Long, Long)) => x._1.compareTo(x._2) }", - sinceVersion = V6SoftForkVersion) + property("Long - 6.0 methods") { - lazy val bitOr = newFeature( - { (x: (Long, Long)) => x._1 | x._2 }, - "{ (x: (Long, Long)) => x._1 | x._2 }", - sinceVersion = V6SoftForkVersion) + 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) - lazy val bitAnd = newFeature( - { (x: (Long, Long)) => x._1 & x._2 }, - "{ (x: (Long, Long)) => x._1 & x._2 }", - 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, + failOnTestVectors = false + ) - forAll { x: Long => - Seq(toAbs).foreach(_.checkEquality(x)) - } - forAll { x: (Long, Long) => - Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) - } - } + 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 => 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)) => (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)) + ), + shiftLeft + ) + + 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 methods equivalence (new features)") { diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index d334ac4653..6ab62e39a9 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -940,7 +940,12 @@ class SigmaDslTesting extends AnyPropSpec funcRes.isFailure shouldBe true } if(isSupportedIn(VersionContext.current)) { - Try(scalaFunc(input)) shouldBe expected.value + 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 } From 48db43217fb1d3bf8846fb310e6520c4d30a2cb3 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 11 Sep 2024 15:02:27 +0300 Subject: [PATCH 117/123] shiftLeft/shiftRight shift limit --- .../main/scala/sigma/data/BigIntegerOps.scala | 18 ++++++-- .../main/scala/sigma/data/ExactIntegral.scala | 42 +++++++++++++++---- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala index 2e1d2f62ce..8d272439f4 100644 --- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala +++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala @@ -101,9 +101,21 @@ object NumericOps { override def bitwiseXor(x: BigInt, y: BigInt): BigInt = x.xor(y) - override def shiftLeft(x: BigInt, y: Int): BigInt = x.shiftLeft(y) - - override def shiftRight(x: BigInt, y: Int): BigInt = x.shiftRight(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/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala index 4b0d9cb720..2bd7fbe341 100644 --- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala +++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala @@ -43,9 +43,15 @@ object ExactIntegral { 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 = (x << bits).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){ + if (bits < 0 || bits >= 8) { throw new IllegalArgumentException(s"Wrong argument in Byte.shiftRight: bits < 0 || bits >= 8 ($bits)") } else { (x >> bits).toByte @@ -64,7 +70,13 @@ object ExactIntegral { 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, y: Int): 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)") @@ -85,9 +97,17 @@ object ExactIntegral { 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, 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){ + if (bits < 0 || bits >= 32) { throw new IllegalArgumentException(s"Wrong argument in Int.shiftRight: bits < 0 || bits >= 32 ($bits)") } else { x >> bits @@ -106,9 +126,17 @@ object ExactIntegral { 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, y: Int): 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){ + if (bits < 0 || bits >= 64) { throw new IllegalArgumentException(s"Wrong argument in Long.shiftRight: bits < 0 || bits >= 64 ($bits)") } else { x >> bits From a2f3030d877f692c80c24ab74318c08c7df06bbd Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 12 Sep 2024 00:01:40 +0300 Subject: [PATCH 118/123] bigint - LSV6 tests --- .../src/main/scala/sigma/ast/methods.scala | 4 +- .../scala/sigma/LanguageSpecificationV6.scala | 270 ++++++++++++++---- 2 files changed, 221 insertions(+), 53 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 1e8fb911bb..34c87096cd 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -360,7 +360,7 @@ object SNumericTypeMethods extends MethodsContainer { .withInfo(MethodCall, """ Returns a big-endian representation of this numeric in a collection of Booleans. | Each boolean corresponds to one bit. - """.stripMargin) + """.stripMargin) // todo: describe shift arg and its limits val ShiftRightMethod: SMethod = SMethod( this, "shiftRight", SFunc(Array(tNum, SInt), tNum), 13, BitwiseInverse_CostKind) @@ -377,7 +377,7 @@ object SNumericTypeMethods extends MethodsContainer { .withInfo(MethodCall, """ Returns a big-endian representation of this numeric in a collection of Booleans. | Each boolean corresponds to one bit. - """.stripMargin) + """.stripMargin) // todo: describe shift arg and its limits lazy val v5Methods = Array( ToByteMethod, // see Downcast diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index b7dd5b028d..6c1796cef0 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -205,7 +205,8 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => Seq( (3.toByte, 3) -> new Expected(ExpectedResult(Success(24.toByte), None)) ), - shiftLeft + shiftLeft, + preGeneratedSamples = Some(Seq()) ) lazy val shiftRight = newFeature( @@ -394,7 +395,8 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => (3.toShort, 8) -> new Expected(ExpectedResult(Success(768.toShort), None)), ((-2).toShort, 10) -> new Expected(ExpectedResult(Success((-2048).toShort), None)), ), - shiftLeft + shiftLeft, + preGeneratedSamples = Some(Seq()) ) lazy val shiftRight = newFeature( @@ -591,7 +593,8 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => (-2, 10) -> new Expected(ExpectedResult(Success(-2048), None)), (-222, 10) -> new Expected(ExpectedResult(Success(-227328), None)) ), - shiftLeft + shiftLeft, + preGeneratedSamples = Some(Seq()) ) lazy val shiftRight = newFeature( @@ -643,8 +646,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => (100001L, 20002L) -> new Expected(ExpectedResult(Success(118435L), None)), (1000010111L, -22L) -> new Expected(ExpectedResult(Success(-1L), None)) ), - bitOr, - failOnTestVectors = false + bitOr ) lazy val bitNot = newFeature( @@ -795,7 +797,8 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => (-2L, 10) -> new Expected(ExpectedResult(Success(-2048L), None)), (-222L, 10) -> new Expected(ExpectedResult(Success(-227328L), None)) ), - shiftLeft + shiftLeft, + preGeneratedSamples = Some(Seq()) ) lazy val shiftRight = newFeature( @@ -826,7 +829,9 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) } - property("BigInt methods equivalence (new features)") { + 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 @@ -841,50 +846,6 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => SBigInt.downcast(CBigInt(new BigInteger("0", 16)).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) - } - } - - if (activatedVersionInTests < VersionContext.V6SoftForkVersion) { - // NOTE, for such versions the new features are not supported - // which is checked below - val toByte = newFeature((x: BigInt) => x.toByte, - "{ (x: BigInt) => x.toByte }", - FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SByte)), - sinceVersion = V6SoftForkVersion) - val toShort = newFeature((x: BigInt) => x.toShort, - "{ (x: BigInt) => x.toShort }", - FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SShort)), - sinceVersion = V6SoftForkVersion) - val toInt = newFeature((x: BigInt) => x.toInt, - "{ (x: BigInt) => x.toInt }", - FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SInt)), - sinceVersion = V6SoftForkVersion) - val toLong = newFeature((x: BigInt) => x.toLong, - "{ (x: BigInt) => x.toLong }", - FuncValue(Vector((1, SBigInt)), Downcast(ValUse(1, SBigInt), SLong)), - sinceVersion = V6SoftForkVersion) - lazy val toAbs = newFeature((x: BigInt) => x.toAbs, "{ (x: BigInt) => x.toAbs }", - sinceVersion = V6SoftForkVersion) - lazy val compareTo = newFeature((x: (BigInt, BigInt)) => x._1.compareTo(x._2), - "{ (x: (BigInt, BigInt)) => x._1.compareTo(x._2) }", - sinceVersion = V6SoftForkVersion) - lazy val bitOr = newFeature({ (x: (BigInt, BigInt)) => x._1 | x._2 }, - "{ (x: (BigInt, BigInt)) => x._1 | x._2 }", - sinceVersion = V6SoftForkVersion) - lazy val bitAnd = newFeature({ (x: (BigInt, BigInt)) => x._1 & x._2 }, - "{ (x: (BigInt, BigInt)) => x._1 & x._2 }", - sinceVersion = V6SoftForkVersion) - - forAll { x: BigInt => - Seq(toByte, toShort, toInt, toLong, toAbs).foreach(_.checkEquality(x)) - } - forAll { x: (BigInt, BigInt) => - Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) - } forAll { x: Long => assertExceptionThrown( @@ -911,6 +872,10 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) } } 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 } @@ -924,6 +889,209 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => 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 => Colls.fromArray(x.toBytes.toArray.flatMap(b => 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)) => (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)) + ), + 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)) + ), + shiftRight, + preGeneratedSamples = Some(Seq()) + ) } property("Box properties equivalence (new features)") { From 297265f0989d3b5e6f2ab7eaff6518479e29ed94 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 12 Sep 2024 18:26:22 +0300 Subject: [PATCH 119/123] arg descs, 2.11 comp fix, BOS tests fixed --- .../src/main/scala/sigma/ast/methods.scala | 28 +++++++++---------- .../scala/sigma/LanguageSpecificationV6.scala | 10 +++---- .../utxo/BasicOpsSpecification.scala | 8 +++--- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 34c87096cd..634145c6e1 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -289,10 +289,7 @@ object SNumericTypeMethods extends MethodsContainer { case SBigIntMethods => BigIntIsExactIntegral.bitwiseInverse(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) + .withInfo(PropertyCall, desc = "Returns bitwise inverse of this numeric. ") val BitwiseOrMethod: SMethod = SMethod( this, "bitwiseOr", SFunc(Array(tNum, tNum), tNum), 9, BitwiseInverse_CostKind) @@ -307,9 +304,8 @@ object SNumericTypeMethods extends MethodsContainer { } }) .withInfo(MethodCall, - """ Returns a big-endian representation of this numeric in a collection of Booleans. - | Each boolean corresponds to one bit. - """.stripMargin) + """ 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, BitwiseInverse_CostKind) @@ -324,9 +320,8 @@ object SNumericTypeMethods extends MethodsContainer { } }) .withInfo(MethodCall, - """ Returns a big-endian representation of this numeric in a collection of Booleans. - | Each boolean corresponds to one bit. - """.stripMargin) + """ 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, BitwiseInverse_CostKind) @@ -341,9 +336,8 @@ object SNumericTypeMethods extends MethodsContainer { } }) .withInfo(MethodCall, - """ Returns a big-endian representation of this numeric in a collection of Booleans. - | Each boolean corresponds to one bit. - """.stripMargin) + """ 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, BitwiseInverse_CostKind) @@ -360,7 +354,9 @@ object SNumericTypeMethods extends MethodsContainer { .withInfo(MethodCall, """ Returns a big-endian representation of this numeric in a collection of Booleans. | Each boolean corresponds to one bit. - """.stripMargin) // todo: describe shift arg and its limits + """.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, BitwiseInverse_CostKind) @@ -377,7 +373,9 @@ object SNumericTypeMethods extends MethodsContainer { .withInfo(MethodCall, """ Returns a big-endian representation of this numeric in a collection of Booleans. | Each boolean corresponds to one bit. - """.stripMargin) // todo: describe shift arg and its limits + """.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 diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 6c1796cef0..ddbc06b6b3 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -352,7 +352,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ((byte >> bit) & 1) == 1 lazy val toBits = newFeature[Short, Coll[Boolean]]( - { x: Short => Colls.fromArray(Shorts.toByteArray(x).flatMap(b => byte2Bools(b).toArray)) }, + { x: Short => Colls.fromArray(Shorts.toByteArray(x)).flatMap(b => Colls.fromArray(byte2Bools(b).toArray)) }, "{ (x: Short) => x.toBits }", FuncValue( Array((1, SShort)), @@ -393,7 +393,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => 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, 10) -> new Expected(ExpectedResult(Success((-2048).toShort), None)) ), shiftLeft, preGeneratedSamples = Some(Seq()) @@ -549,7 +549,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ((byte >> bit) & 1) == 1 lazy val toBits = newFeature[Int, Coll[Boolean]]( - { x: Int => Colls.fromArray(Ints.toByteArray(x).flatMap(b => byte2Bools(b).toArray)) }, + { x: Int => Colls.fromArray(Ints.toByteArray(x)).flatMap(b => Colls.fromArray(byte2Bools(b).toArray)) }, "{ (x: Int) => x.toBits }", FuncValue( Array((1, SInt)), @@ -753,7 +753,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ((byte >> bit) & 1) == 1 lazy val toBits = newFeature[Long, Coll[Boolean]]( - { x: Long => Colls.fromArray(Longs.toByteArray(x).flatMap(b => byte2Bools(b).toArray)) }, + { x: Long => Colls.fromArray(Longs.toByteArray(x)).flatMap(b => Colls.fromArray(byte2Bools(b).toArray)) }, "{ (x: Long) => x.toBits }", FuncValue( Array((1, SLong)), @@ -1018,7 +1018,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ((byte >> bit) & 1) == 1 lazy val toBits = newFeature[BigInt, Coll[Boolean]]( - { x: BigInt => Colls.fromArray(x.toBytes.toArray.flatMap(b => byte2Bools(b).toArray)) }, + { x: BigInt => x.toBytes.flatMap(b => Colls.fromArray(byte2Bools(b).toArray)) }, "{ (x: BigInt) => x.toBits }", FuncValue( Array((1, SBigInt)), diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index a37a3d1079..a5d73d2442 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -354,7 +354,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) if (VersionContext.current.isV6SoftForkActivated) { - shiftLeftTest() + an[IllegalArgumentException] shouldBe thrownBy(shiftLeftTest()) } else { an[Exception] shouldBe thrownBy(shiftLeftTest()) } @@ -455,7 +455,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) if (VersionContext.current.isV6SoftForkActivated) { - shiftRightTest() + an[IllegalArgumentException] shouldBe thrownBy(shiftRightTest()) } else { an[Exception] shouldBe thrownBy(shiftRightTest()) } @@ -489,7 +489,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) if (VersionContext.current.isV6SoftForkActivated) { - shiftRightTest() + an[IllegalArgumentException] shouldBe thrownBy(shiftRightTest()) } else { an[Exception] shouldBe thrownBy(shiftRightTest()) } @@ -525,7 +525,7 @@ class BasicOpsSpecification extends CompilerTestingCommons ) if (VersionContext.current.isV6SoftForkActivated) { - shiftRightTest() + an[IllegalArgumentException] shouldBe thrownBy(shiftRightTest()) } else { an[Exception] shouldBe thrownBy(shiftRightTest()) } From 55d03cd38c3d4553520be75a837d561d68ca1cb8 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 17 Sep 2024 01:50:22 +0300 Subject: [PATCH 120/123] addressing review comments --- .../src/main/scala/sigma/ast/methods.scala | 3 +- .../main/scala/sigma/data/ExactNumeric.scala | 9 ++-- .../scala/sigma/LanguageSpecificationV6.scala | 53 +++++++++++++------ 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 634145c6e1..6c401f8fc3 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -397,8 +397,7 @@ object SNumericTypeMethods extends MethodsContainer { ) protected override def getMethods(): Seq[SMethod] = { - // this .getMethods shouldn't ever be called - ??? + throw new Exception("SNumericTypeMethods.getMethods shouldn't ever be called") } /** Collection of names of numeric casting methods (like `toByte`, `toInt`, etc). */ diff --git a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala index 56b4a9369e..244cc6b7b7 100644 --- a/data/shared/src/main/scala/sigma/data/ExactNumeric.scala +++ b/data/shared/src/main/scala/sigma/data/ExactNumeric.scala @@ -45,17 +45,14 @@ trait ExactNumeric[T] { def isBitSet(byte: Byte)(bit: Int): Boolean = ((byte >> bit) & 1) == 1 - def byte2Bools(b: Byte): Array[Boolean] = (0 to 7).toArray.reverse.map(isBitSet(b)) - val bytes = toBigEndianBytes(x) val l = bytes.length val res = new Array[Boolean](l * 8) - var offset = 0 cfor(0)(_ < l, _ + 1) { i => val b = bytes(i) - val bits = byte2Bools(b) - Array.copy(bits, 0, res, offset, 8) - offset += 8 + cfor(0)(_ < 8, _ + 1) { bitIdx => + res(i * 8 + (7 - bitIdx)) = isBitSet(b)(bitIdx) + } } Colls.fromArray(res) } diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index ddbc06b6b3..4ca378c35e 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -188,7 +188,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) lazy val shiftLeft = newFeature( - { (x: (Byte, Int)) => (x._1 << x._2).toByte }, + { (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))), @@ -203,14 +203,17 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => verifyCases( Seq( - (3.toByte, 3) -> new Expected(ExpectedResult(Success(24.toByte), None)) + (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)) => (x._1 >> x._2).toByte }, + { (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))), @@ -225,7 +228,10 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => verifyCases( Seq( - (24.toByte, 3) -> new Expected(ExpectedResult(Success(3.toByte), None)) + (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()) @@ -376,7 +382,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) lazy val shiftLeft = newFeature( - { (x: (Short, Int)) => (x._1 << x._2).toShort }, + { (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))), @@ -393,14 +399,16 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => 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, 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)) => (x._1 >> x._2).toShort }, + { (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))), @@ -417,7 +425,9 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => 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)) + ((-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()) @@ -573,7 +583,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) lazy val shiftLeft = newFeature( - { (x: (Int, Int)) => (x._1 << x._2) }, + { (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))), @@ -591,14 +601,16 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => (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, 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)) => (x._1 >> x._2) }, + { (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))), @@ -616,7 +628,9 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => (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, 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()) @@ -777,7 +791,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) lazy val shiftLeft = newFeature( - { (x: (Long, Int)) => (x._1 << x._2) }, + { (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))), @@ -795,7 +809,9 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => (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, 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()) @@ -1042,7 +1058,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) lazy val shiftLeft = newFeature( - { (x: (BigInt, Int)) => (x._1.asInstanceOf[BigInt].shiftLeft(x._2)) }, + { (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))), @@ -1060,7 +1076,9 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => (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)), 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()) @@ -1087,7 +1105,8 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => (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)), -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)), + (CBigInt(BigInteger.valueOf(24)), 256) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)) ), shiftRight, preGeneratedSamples = Some(Seq()) From 1c2b99df06c840955f9dc7b57164ec6ee11979a0 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 17 Sep 2024 17:35:17 +0300 Subject: [PATCH 121/123] more polishing in UnsignedBigInt impl --- .../src/main/scala/sigma/SigmaDsl.scala | 24 +++++++ .../src/main/scala/sigma/ast/SType.scala | 70 +++++++++++-------- .../src/main/scala/sigma/data/CBigInt.scala | 34 ++++++--- .../sigma/reflection/ReflectionData.scala | 30 +++++++- .../main/scala/sigma/util/Extensions.scala | 11 ++- .../scala/sigma/data/CSigmaDslBuilder.scala | 2 +- 6 files changed, 126 insertions(+), 45 deletions(-) diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala index 8c8a3c2be6..3f060c1af2 100644 --- a/core/shared/src/main/scala/sigma/SigmaDsl.scala +++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala @@ -170,8 +170,15 @@ trait BigInt { */ def shiftRight(n: Int): BigInt + /** + * @return unsigned representation of this BigInt, or exception if its value is negative + */ def toUnsigned: UnsignedBigInt + /** + * @return unsigned representation of this BigInt modulo `m`. Cryptographic mod operation is done, ie result is + * non-negative always + */ def toUnsignedMod(m: UnsignedBigInt): UnsignedBigInt } @@ -297,6 +304,23 @@ trait UnsignedBigInt { def subtractMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt def multiplyMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt + /** + * @return a big integer whose value is `this xor that` + */ + def xor(that: UnsignedBigInt): UnsignedBigInt + + /** + * @return a 256-bit signed integer whose value 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(n: Int): UnsignedBigInt + + /** + * @return a 256-bit signed integer whose value 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(n: Int): UnsignedBigInt + def toSigned(): BigInt } diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index 815a70e222..c99b7b8e34 100644 --- a/core/shared/src/main/scala/sigma/ast/SType.scala +++ b/core/shared/src/main/scala/sigma/ast/SType.scala @@ -144,7 +144,7 @@ object SType { SBoolean, SString, STuple, SGroupElement, SSigmaProp, SContext, SGlobal, SHeader, SPreHeader, SAvlTree, SBox, SOption, SCollection, SBigInt ) - private val v6Types = v5Types ++ Seq(SByte, SShort, SInt, SLong) + private val v6Types = v5Types ++ Seq(SByte, SShort, SInt, SLong, SUnsignedBigInt) private val v5TypesMap = v5Types.map { t => (t.typeId, t) }.toMap @@ -398,6 +398,7 @@ case object SByte extends SPrimType with SEmbeddable with SNumericType with SMon 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 ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toByte // toByteExact from int is called under the hood case _ => sys.error(s"Cannot downcast value $v to the type $this") } } @@ -420,6 +421,7 @@ case object SShort extends SPrimType with SEmbeddable with SNumericType with SMo 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 ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toShort // toShortExact from int is called under the hood case _ => sys.error(s"Cannot downcast value $v to the type $this") } } @@ -444,6 +446,7 @@ case object SInt extends SPrimType with SEmbeddable with SNumericType with SMono case i: Int => i case l: Long => l.toIntExact case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toInt + case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toInt case _ => sys.error(s"Cannot downcast value $v to the type $this") } } @@ -470,6 +473,7 @@ case object SLong extends SPrimType with SEmbeddable with SNumericType with SMon case i: Int => i.toLong case l: Long => l case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toLong + case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toLong case _ => sys.error(s"Cannot downcast value $v to the type $this") } } @@ -687,15 +691,16 @@ object SOption extends STypeCompanion { override val reprClass: RClass[_] = RClass(classOf[Option[_]]) - type SBooleanOption = SOption[SBoolean.type] - type SByteOption = SOption[SByte.type] - type SShortOption = SOption[SShort.type] - type SIntOption = SOption[SInt.type] - type SLongOption = SOption[SLong.type] - type SBigIntOption = SOption[SBigInt.type] - type SGroupElementOption = SOption[SGroupElement.type] - type SBoxOption = SOption[SBox.type] - type SAvlTreeOption = SOption[SAvlTree.type] + type SBooleanOption = SOption[SBoolean.type] + type SByteOption = SOption[SByte.type] + type SShortOption = SOption[SShort.type] + type SIntOption = SOption[SInt.type] + type SLongOption = SOption[SLong.type] + type SBigIntOption = SOption[SBigInt.type] + type SUnsignedBigIntOption = SOption[SUnsignedBigInt.type] + type SGroupElementOption = SOption[SGroupElement.type] + type SBoxOption = SOption[SBox.type] + type SAvlTreeOption = SOption[SAvlTree.type] /** This descriptors are instantiated once here and then reused. */ implicit val SByteOption = SOption(SByte) @@ -704,6 +709,7 @@ object SOption extends STypeCompanion { implicit val SIntOption = SOption(SInt) implicit val SLongOption = SOption(SLong) implicit val SBigIntOption = SOption(SBigInt) + implicit val SUnsignedBigIntOption = SOption(SUnsignedBigInt) implicit val SBooleanOption = SOption(SBoolean) implicit val SAvlTreeOption = SOption(SAvlTree) implicit val SGroupElementOption = SOption(SGroupElement) @@ -764,29 +770,31 @@ object SCollection extends STypeCompanion { def apply[T <: SType](elemType: T): SCollection[T] = SCollectionType(elemType) def apply[T <: SType](implicit elemType: T, ov: Overloaded1): SCollection[T] = SCollectionType(elemType) - type SBooleanArray = SCollection[SBoolean.type] - type SByteArray = SCollection[SByte.type] - type SShortArray = SCollection[SShort.type] - type SIntArray = SCollection[SInt.type] - type SLongArray = SCollection[SLong.type] - type SBigIntArray = SCollection[SBigInt.type] - type SGroupElementArray = SCollection[SGroupElement.type] - type SBoxArray = SCollection[SBox.type] - type SAvlTreeArray = SCollection[SAvlTree.type] + type SBooleanArray = SCollection[SBoolean.type] + type SByteArray = SCollection[SByte.type] + type SShortArray = SCollection[SShort.type] + type SIntArray = SCollection[SInt.type] + type SLongArray = SCollection[SLong.type] + type SBigIntArray = SCollection[SBigInt.type] + type SUnsignedBigIntArray = SCollection[SUnsignedBigInt.type] + type SGroupElementArray = SCollection[SGroupElement.type] + type SBoxArray = SCollection[SBox.type] + type SAvlTreeArray = SCollection[SAvlTree.type] /** This descriptors are instantiated once here and then reused. */ - val SBooleanArray = SCollection(SBoolean) - val SByteArray = SCollection(SByte) - val SByteArray2 = SCollection(SCollection(SByte)) - val SShortArray = SCollection(SShort) - val SIntArray = SCollection(SInt) - val SLongArray = SCollection(SLong) - val SBigIntArray = SCollection(SBigInt) - val SGroupElementArray = SCollection(SGroupElement) - val SSigmaPropArray = SCollection(SSigmaProp) - val SBoxArray = SCollection(SBox) - val SAvlTreeArray = SCollection(SAvlTree) - val SHeaderArray = SCollection(SHeader) + val SBooleanArray = SCollection(SBoolean) + val SByteArray = SCollection(SByte) + val SByteArray2 = SCollection(SCollection(SByte)) + val SShortArray = SCollection(SShort) + val SIntArray = SCollection(SInt) + val SLongArray = SCollection(SLong) + val SBigIntArray = SCollection(SBigInt) + val SUnsignedBigIntArray = SCollection(SUnsignedBigInt) + val SGroupElementArray = SCollection(SGroupElement) + val SSigmaPropArray = SCollection(SSigmaProp) + val SBoxArray = SCollection(SBox) + val SAvlTreeArray = SCollection(SAvlTree) + val SHeaderArray = SCollection(SHeader) } /** Type descriptor of tuple type. */ diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala index 1d1478e0c4..8212955103 100644 --- a/core/shared/src/main/scala/sigma/data/CBigInt.scala +++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala @@ -28,11 +28,11 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr override def signum: Int = wrappedValue.signum() - override def add(that: BigInt): BigInt = CBigInt(wrappedValue.add(that.asInstanceOf[CBigInt].wrappedValue).to256BitValueExact) + override def add(that: BigInt): BigInt = CBigInt(wrappedValue.add(that.asInstanceOf[CBigInt].wrappedValue).toSignedBigIntValueExact) - override def subtract(that: BigInt): BigInt = CBigInt(wrappedValue.subtract(that.asInstanceOf[CBigInt].wrappedValue).to256BitValueExact) + override def subtract(that: BigInt): BigInt = CBigInt(wrappedValue.subtract(that.asInstanceOf[CBigInt].wrappedValue).toSignedBigIntValueExact) - override def multiply(that: BigInt): BigInt = CBigInt(wrappedValue.multiply(that.asInstanceOf[CBigInt].wrappedValue).to256BitValueExact) + override def multiply(that: BigInt): BigInt = CBigInt(wrappedValue.multiply(that.asInstanceOf[CBigInt].wrappedValue).toSignedBigIntValueExact) override def divide(that: BigInt): BigInt = CBigInt(wrappedValue.divide(that.asInstanceOf[CBigInt].wrappedValue)) @@ -44,7 +44,7 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr override def max(that: BigInt): BigInt = CBigInt(wrappedValue.max(that.asInstanceOf[CBigInt].wrappedValue)) - override def negate(): BigInt = CBigInt(wrappedValue.negate().to256BitValueExact) + override def negate(): BigInt = CBigInt(wrappedValue.negate().toSignedBigIntValueExact) override def and(that: BigInt): BigInt = CBigInt(wrappedValue.and(that.asInstanceOf[CBigInt].wrappedValue)) @@ -52,9 +52,9 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr 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 shiftLeft(n: Int): BigInt = CBigInt(wrappedValue.shiftLeft(n).toSignedBigIntValueExact) - override def shiftRight(n: Int): BigInt = CBigInt(wrappedValue.shiftRight(n).to256BitValueExact) + override def shiftRight(n: Int): BigInt = CBigInt(wrappedValue.shiftRight(n).toSignedBigIntValueExact) def toUnsigned: UnsignedBigInt = { if(this.wrappedValue.compareTo(BigInteger.ZERO) < 0){ @@ -88,12 +88,13 @@ case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends Unsign override def compareTo(that: UnsignedBigInt): Int = wrappedValue.compareTo(that.asInstanceOf[CUnsignedBigInt].wrappedValue) - //todo: consider result's bits limit - override def add(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.add(that.asInstanceOf[CUnsignedBigInt].wrappedValue).to256BitValueExact) + override def add(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.add(that.asInstanceOf[CUnsignedBigInt].wrappedValue).toUnsignedBigIntValueExact) - override def subtract(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.subtract(that.asInstanceOf[CUnsignedBigInt].wrappedValue).to256BitValueExact) + override def subtract(that: UnsignedBigInt): UnsignedBigInt = { + CUnsignedBigInt(wrappedValue.subtract(that.asInstanceOf[CUnsignedBigInt].wrappedValue).toUnsignedBigIntValueExact) + } - override def multiply(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.multiply(that.asInstanceOf[CUnsignedBigInt].wrappedValue).to256BitValueExact) + override def multiply(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.multiply(that.asInstanceOf[CUnsignedBigInt].wrappedValue).toUnsignedBigIntValueExact) override def divide(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.divide(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) @@ -129,7 +130,18 @@ case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends Unsign CUnsignedBigInt(wrappedValue.multiply(thatBi).mod(mBi)) } + /** + * @return a big integer whose value is `this xor that` + */ + def xor(that: UnsignedBigInt): UnsignedBigInt = { + CUnsignedBigInt(wrappedValue.xor(that.asInstanceOf[CUnsignedBigInt].wrappedValue)) + } + + override def shiftLeft(n: Int): UnsignedBigInt = CUnsignedBigInt(wrappedValue.shiftLeft(n).toUnsignedBigIntValueExact) + + override def shiftRight(n: Int): UnsignedBigInt = CUnsignedBigInt(wrappedValue.shiftRight(n).toUnsignedBigIntValueExact) + override def toSigned(): BigInt = { - CBigInt(wrappedValue.to256BitValueExact) + CBigInt(wrappedValue.toSignedBigIntValueExact) } } diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala index d94e7b7e0d..53d6c256f2 100644 --- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala +++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala @@ -128,7 +128,35 @@ object ReflectionData { ) ) } - //todo: add UnsignedBigInt + { + val clazz = classOf[sigma.UnsignedBigInt] + val paramTypes = Array[Class[_]](clazz) + registerClassEntry(clazz, + methods = Map( + mkMethod(clazz, "add", paramTypes) { (obj, args) => + obj.asInstanceOf[UnsignedBigInt].add(args(0).asInstanceOf[UnsignedBigInt]) + }, + mkMethod(clazz, "max", paramTypes) { (obj, args) => + obj.asInstanceOf[UnsignedBigInt].max(args(0).asInstanceOf[UnsignedBigInt]) + }, + mkMethod(clazz, "min", paramTypes) { (obj, args) => + obj.asInstanceOf[UnsignedBigInt].min(args(0).asInstanceOf[UnsignedBigInt]) + }, + mkMethod(clazz, "subtract", paramTypes) { (obj, args) => + obj.asInstanceOf[UnsignedBigInt].subtract(args(0).asInstanceOf[UnsignedBigInt]) + }, + mkMethod(clazz, "multiply", paramTypes) { (obj, args) => + obj.asInstanceOf[UnsignedBigInt].multiply(args(0).asInstanceOf[UnsignedBigInt]) + }, + mkMethod(clazz, "mod", paramTypes) { (obj, args) => + obj.asInstanceOf[UnsignedBigInt].mod(args(0).asInstanceOf[UnsignedBigInt]) + }, + mkMethod(clazz, "divide", paramTypes) { (obj, args) => + obj.asInstanceOf[UnsignedBigInt].divide(args(0).asInstanceOf[UnsignedBigInt]) + } + ) + ) + } { val clazz = classOf[CollBuilder] registerClassEntry(clazz, diff --git a/core/shared/src/main/scala/sigma/util/Extensions.scala b/core/shared/src/main/scala/sigma/util/Extensions.scala index 624b3f5d6b..149d61f6c2 100644 --- a/core/shared/src/main/scala/sigma/util/Extensions.scala +++ b/core/shared/src/main/scala/sigma/util/Extensions.scala @@ -204,7 +204,7 @@ object Extensions { * not exactly fit in a 256 bit range. * @see BigInteger#longValueExact */ - @inline final def to256BitValueExact: BigInteger = { + @inline final def toSignedBigIntValueExact: BigInteger = { // Comparing with 255 is correct because bitLength() method excludes the sign bit. // For example, these are the boundary values: // (new BigInteger("80" + "00" * 31, 16)).bitLength() = 256 @@ -217,6 +217,15 @@ object Extensions { throw new ArithmeticException("BigInteger out of 256 bit range"); } + @inline final def toUnsignedBigIntValueExact: BigInteger = { + // todo: make the check soft-forkable + if (x.compareTo(BigInteger.ZERO) >= 0 && x.bitLength() <= 256) { + x + } else { + throw new ArithmeticException("Unsigned BigInteger out of 256 bit range or negative") + } + } + /** Converts `x` to [[sigma.BigInt]] */ def toBigInt: sigma.BigInt = CBigInt(x) } diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index e5bb8920ae..b74f91b133 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -150,7 +150,7 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl => } override def byteArrayToBigInt(bytes: Coll[Byte]): BigInt = { - val bi = new BigInteger(bytes.toArray).to256BitValueExact + val bi = new BigInteger(bytes.toArray).toSignedBigIntValueExact this.BigInt(bi) } From cb51ba8bf3a100982a040d276356fd15f615c36a Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 17 Sep 2024 19:07:01 +0300 Subject: [PATCH 122/123] removing access to type before 6.0, more tests --- .../src/main/scala/sigma/ast/SType.scala | 25 ++++++++--- .../utxo/BasicOpsSpecification.scala | 44 ++++++++++++++++++- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala index c99b7b8e34..7673c11dec 100644 --- a/core/shared/src/main/scala/sigma/ast/SType.scala +++ b/core/shared/src/main/scala/sigma/ast/SType.scala @@ -102,12 +102,23 @@ object SType { /** Immutable empty IndexedSeq, can be used to avoid repeated allocations. */ val EmptySeq: IndexedSeq[SType] = EmptyArray + private val v5PredefTypes = Array[SType]( + SBoolean, SByte, SShort, SInt, SLong, SBigInt, SContext, + SGlobal, SHeader, SPreHeader, SAvlTree, SGroupElement, SSigmaProp, SString, SBox, + SUnit, SAny) + + private val v6PredefTypes = v5PredefTypes ++ Array(SUnsignedBigInt) + + /** All pre-defined types should be listed here. Note, NoType is not listed. * Should be in sync with sigmastate.lang.Types.predefTypes. */ - val allPredefTypes: Seq[SType] = Array[SType]( - SBoolean, SByte, SShort, SInt, SLong, SBigInt, SUnsignedBigInt, SContext, - SGlobal, SHeader, SPreHeader, SAvlTree, SGroupElement, SSigmaProp, SString, SBox, - SUnit, SAny) + def allPredefTypes: Seq[SType] = { + if(VersionContext.current.isV6SoftForkActivated) { + v6PredefTypes + } else { + v5PredefTypes + } + } /** A mapping of object types supporting MethodCall operations. For each serialized * typeId this map contains a companion object which can be used to access the list of @@ -177,7 +188,7 @@ object SType { case SInt => x.isInstanceOf[Int] case SLong => x.isInstanceOf[Long] case SBigInt => x.isInstanceOf[BigInt] - case SUnsignedBigInt => x.isInstanceOf[UnsignedBigInt] + case SUnsignedBigInt if VersionContext.current.isV6SoftForkActivated => x.isInstanceOf[UnsignedBigInt] case SGroupElement => x.isInstanceOf[GroupElement] case SSigmaProp => x.isInstanceOf[SigmaProp] case SBox => x.isInstanceOf[Box] @@ -360,8 +371,6 @@ trait SNumericType extends SProduct with STypeCompanion { } object SNumericType extends STypeCompanion { - /** Array of all numeric types ordered by number of bytes in the representation. */ - final val allNumericTypes = Array(SByte, SShort, SInt, SLong, SBigInt, SUnsignedBigInt) // TODO v6.0: this typeId is now shadowed by SGlobal.typeId // see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/667 @@ -537,6 +546,7 @@ case object SUnsignedBigInt extends SPrimType with SEmbeddable with SNumericType case x: Short => BigInteger.valueOf(x.toLong) case x: Int => BigInteger.valueOf(x.toLong) case x: Long => BigInteger.valueOf(x) + case x: UnsignedBigInt => x.asInstanceOf[CUnsignedBigInt].wrappedValue case _ => sys.error(s"Cannot upcast value $v to the type $this") } CUnsignedBigInt(bi) @@ -547,6 +557,7 @@ case object SUnsignedBigInt extends SPrimType with SEmbeddable with SNumericType case x: Short => BigInteger.valueOf(x.toLong) case x: Int => BigInteger.valueOf(x.toLong) case x: Long => BigInteger.valueOf(x) + case x: UnsignedBigInt => x.asInstanceOf[CUnsignedBigInt].wrappedValue case _ => sys.error(s"Cannot downcast value $v to the type $this") } CUnsignedBigInt(bi) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 8c29783db5..2ecace1690 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -163,7 +163,11 @@ class BasicOpsSpecification extends CompilerTestingCommons true )} - deserTest() // todo: should fail < 6.0 + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy deserTest() + } else { + deserTest() + } } property("signed -> unsigned bigint conversion - positive bigint") { @@ -224,6 +228,44 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("unsigned bigint - add") { + def conversionTest() = {test("add", env, ext, + s"""{ + | val a = unsignedBigInt("5") + | val b = unsignedBigInt("10") + | val res = a + b + | res == 15 + | } """.stripMargin, + null, + true + )} + + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy conversionTest() + } else { + conversionTest() + } + } + + property("unsigned bigint - subtract with neg result") { + def conversionTest() = {test("subtract", env, ext, + s"""{ + | val a = unsignedBigInt("5") + | val b = unsignedBigInt("10") + | val res = a - b + | res >= 0 + | } """.stripMargin, + null, + true + )} + + if (activatedVersionInTests < V6SoftForkVersion) { + an[Exception] should be thrownBy conversionTest() + } else { + an[Exception] should be thrownBy conversionTest() + } + } + property("unsigned -> signed bigint conversion") { def conversionTest() = {test("conversion", env, ext, s"""{ From 6c59ce0481a26661036614489ffa42413991e0b7 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 17 Sep 2024 21:57:36 +0300 Subject: [PATCH 123/123] imports fix --- data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala index 672f4f1122..37b1f449d5 100644 --- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala +++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala @@ -14,7 +14,7 @@ import sigma.serialization.{DataSerializer, GroupElementSerializer, SigmaSeriali import sigma.util.Extensions.BigIntegerOps import sigma.util.NBitsUtils import sigma.validation.SigmaValidationSettings -import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, Evaluation, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext} +import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, Evaluation, GroupElement, SigmaDslBuilder, SigmaProp, UnsignedBigInt, VersionContext} import java.math.BigInteger import java.nio.ByteBuffer