diff --git a/common/src/main/scala/scalan/MutableLazy.scala b/common/src/main/scala/scalan/MutableLazy.scala index e7cd3aee78..5b6a579476 100644 --- a/common/src/main/scala/scalan/MutableLazy.scala +++ b/common/src/main/scala/scalan/MutableLazy.scala @@ -1,5 +1,7 @@ package scalan +import scala.language.implicitConversions + /** Non-thread safe (but efficient on single thread) immutable lazy value with reset. * The `block` may execute potentially many times, but only once before each reset. */ final class MutableLazy[A] private (block: => A) { diff --git a/common/src/main/scala/scalan/TypeDesc.scala b/common/src/main/scala/scalan/TypeDesc.scala index 0d15988399..b7a517f8a0 100644 --- a/common/src/main/scala/scalan/TypeDesc.scala +++ b/common/src/main/scala/scalan/TypeDesc.scala @@ -2,6 +2,7 @@ package scalan import scala.reflect.ClassTag import scala.annotation.implicitNotFound +import scala.language.implicitConversions /** Base type for all runtime type descriptors. Sigma uses type descriptors to * represent structure of the data values. Data values of registers and context diff --git a/common/src/main/scala/scalan/util/CollectionUtil.scala b/common/src/main/scala/scalan/util/CollectionUtil.scala index db16c17088..e5aff804c7 100644 --- a/common/src/main/scala/scalan/util/CollectionUtil.scala +++ b/common/src/main/scala/scalan/util/CollectionUtil.scala @@ -1,5 +1,6 @@ package scalan.util +import scala.language.higherKinds import java.util import java.util.Objects import java.util.function.BiConsumer diff --git a/common/src/main/scala/scalan/util/Extensions.scala b/common/src/main/scala/scalan/util/Extensions.scala index 40852127fe..a1bf61f03b 100644 --- a/common/src/main/scala/scalan/util/Extensions.scala +++ b/common/src/main/scala/scalan/util/Extensions.scala @@ -164,7 +164,7 @@ object Extensions { * @see BigInteger#longValueExact */ @inline final def to256BitValueExact: BigInteger = { - if (x.bitLength() <= 255) x + if (x.bitLength() <= 255) x // TODO HF: allow 256 bit values else throw new ArithmeticException("BigInteger out of 256 bit range"); } diff --git a/common/src/main/scala/scalan/util/ReflectionUtil.scala b/common/src/main/scala/scalan/util/ReflectionUtil.scala index e2f57af5ea..c463e8a787 100644 --- a/common/src/main/scala/scalan/util/ReflectionUtil.scala +++ b/common/src/main/scala/scalan/util/ReflectionUtil.scala @@ -1,7 +1,7 @@ package scalan.util import java.lang.reflect.{Method, AnnotatedElement} - +import scala.language.existentials import scala.reflect.{classTag, ClassTag} import scalan.OverloadId diff --git a/common/src/test/scala/scalan/BaseTests.scala b/common/src/test/scala/scalan/BaseTests.scala index 44542aab7e..905adda285 100644 --- a/common/src/test/scala/scalan/BaseTests.scala +++ b/common/src/test/scala/scalan/BaseTests.scala @@ -1,5 +1,6 @@ package scalan +import scala.language.implicitConversions import org.scalatest.words.ResultOfStringPassedToVerb import org.scalatest.{FlatSpec, _} diff --git a/core/src/main/scala/scalan/Base.scala b/core/src/main/scala/scalan/Base.scala index d151bbeb0c..47cae5da08 100644 --- a/core/src/main/scala/scalan/Base.scala +++ b/core/src/main/scala/scalan/Base.scala @@ -3,6 +3,7 @@ package scalan import java.lang.reflect.{Constructor => Constr} import java.util.Arrays import scalan.OverloadHack.Overloaded1 +import scala.language.implicitConversions import scala.annotation.implicitNotFound import scala.annotation.unchecked.uncheckedVariance import scalan.compilation.GraphVizConfig diff --git a/core/src/main/scala/scalan/TypeDescs.scala b/core/src/main/scala/scalan/TypeDescs.scala index b63d49c2bb..5f3a4536bb 100644 --- a/core/src/main/scala/scalan/TypeDescs.scala +++ b/core/src/main/scala/scalan/TypeDescs.scala @@ -1,7 +1,7 @@ package scalan import java.lang.reflect.{InvocationTargetException, Method} - +import scala.language.{implicitConversions, higherKinds} import scala.annotation.implicitNotFound import scala.collection.immutable.ListMap import scala.reflect.runtime.universe._ diff --git a/core/src/main/scala/scalan/primitives/OrderingOps.scala b/core/src/main/scala/scalan/primitives/OrderingOps.scala index 7d997e1487..479c502795 100644 --- a/core/src/main/scala/scalan/primitives/OrderingOps.scala +++ b/core/src/main/scala/scalan/primitives/OrderingOps.scala @@ -1,6 +1,7 @@ package scalan.primitives import scalan.{Base, Scalan, ExactOrdering} +import scala.language.implicitConversions /** Slice in Scala cake with definitions of comparison operations. */ trait OrderingOps extends Base { self: Scalan => diff --git a/core/src/main/scala/scalan/primitives/Thunks.scala b/core/src/main/scala/scalan/primitives/Thunks.scala index 323fd26042..004a92012a 100644 --- a/core/src/main/scala/scalan/primitives/Thunks.scala +++ b/core/src/main/scala/scalan/primitives/Thunks.scala @@ -1,5 +1,6 @@ package scalan.primitives +import scala.language.{existentials, implicitConversions} import scalan.compilation.{GraphVizConfig, GraphVizExport} import scalan.{Liftable => _, _} import debox.{Set => DSet, Buffer => DBuffer} diff --git a/core/src/main/scala/scalan/primitives/Tuples.scala b/core/src/main/scala/scalan/primitives/Tuples.scala index 15cea7c133..1fa5fbe5ad 100644 --- a/core/src/main/scala/scalan/primitives/Tuples.scala +++ b/core/src/main/scala/scalan/primitives/Tuples.scala @@ -4,6 +4,7 @@ */ package scalan.primitives +import scala.language.implicitConversions import scalan.{Base, Scalan, AVHashMap} trait Tuples extends Base { self: Scalan => diff --git a/core/src/main/scala/scalan/staged/Transforming.scala b/core/src/main/scala/scalan/staged/Transforming.scala index 436e5f69fc..22f021b8cb 100644 --- a/core/src/main/scala/scalan/staged/Transforming.scala +++ b/core/src/main/scala/scalan/staged/Transforming.scala @@ -3,6 +3,7 @@ package scalan.staged import java.lang.reflect.Method import java.util +import scala.language.existentials import scalan.{Nullable, DelayInvokeException, Lazy, Scalan, AVHashMap} import debox.{Buffer => DBuffer} import spire.syntax.all.cfor diff --git a/library-api/src/main/scala/special/collection/package.scala b/library-api/src/main/scala/special/collection/package.scala index e0d13337a0..2e5e21e32e 100644 --- a/library-api/src/main/scala/special/collection/package.scala +++ b/library-api/src/main/scala/special/collection/package.scala @@ -1,5 +1,6 @@ package special +import scala.language.implicitConversions import scalan.RType import scala.reflect.{ClassTag, classTag} diff --git a/library/src/main/scala/scalan/Library.scala b/library/src/main/scala/scalan/Library.scala index a47b8ea407..8874c50d93 100644 --- a/library/src/main/scala/scalan/Library.scala +++ b/library/src/main/scala/scalan/Library.scala @@ -1,5 +1,6 @@ package scalan +import scala.language.implicitConversions import special.collection._ import special.wrappers.{WrappersSpecModule, WrappersModule} import scalan.util.{MemoizedFunc} diff --git a/library/src/main/scala/special/collection/impl/CollsImpl.scala b/library/src/main/scala/special/collection/impl/CollsImpl.scala index 73c4e29bd1..885412750f 100644 --- a/library/src/main/scala/special/collection/impl/CollsImpl.scala +++ b/library/src/main/scala/special/collection/impl/CollsImpl.scala @@ -1,5 +1,6 @@ package special.collection +import scala.language.{existentials,implicitConversions} import scalan._ import scala.reflect.runtime.universe._ import scala.reflect._ diff --git a/library/src/main/scala/special/collection/impl/ConcreteCostsImpl.scala b/library/src/main/scala/special/collection/impl/ConcreteCostsImpl.scala index 4bf37c1cd2..7edc14f857 100644 --- a/library/src/main/scala/special/collection/impl/ConcreteCostsImpl.scala +++ b/library/src/main/scala/special/collection/impl/ConcreteCostsImpl.scala @@ -1,5 +1,6 @@ package special.collection +import scala.language.{existentials,implicitConversions} import scalan._ import scala.reflect.runtime.universe._ import scala.reflect._ diff --git a/library/src/main/scala/special/collection/impl/ConcreteSizesImpl.scala b/library/src/main/scala/special/collection/impl/ConcreteSizesImpl.scala index 27994bbd78..2056b28077 100644 --- a/library/src/main/scala/special/collection/impl/ConcreteSizesImpl.scala +++ b/library/src/main/scala/special/collection/impl/ConcreteSizesImpl.scala @@ -1,5 +1,6 @@ package special.collection +import scala.language.{existentials,implicitConversions} import scalan._ import scala.reflect.runtime.universe._ import scala.reflect._ diff --git a/library/src/main/scala/special/collection/impl/CostedOptionsImpl.scala b/library/src/main/scala/special/collection/impl/CostedOptionsImpl.scala index 1002a5cac2..b43d3dcc68 100644 --- a/library/src/main/scala/special/collection/impl/CostedOptionsImpl.scala +++ b/library/src/main/scala/special/collection/impl/CostedOptionsImpl.scala @@ -1,5 +1,6 @@ package special.collection +import scala.language.{existentials,implicitConversions} import scalan._ import scala.collection.mutable.WrappedArray diff --git a/library/src/main/scala/special/collection/impl/CostsImpl.scala b/library/src/main/scala/special/collection/impl/CostsImpl.scala index 33bdb96697..29e35ae03c 100644 --- a/library/src/main/scala/special/collection/impl/CostsImpl.scala +++ b/library/src/main/scala/special/collection/impl/CostsImpl.scala @@ -1,5 +1,6 @@ package special.collection +import scala.language.{existentials,implicitConversions} import scalan._ import scala.reflect.runtime.universe._ import scala.reflect._ diff --git a/library/src/main/scala/special/collection/impl/MonoidInstancesImpl.scala b/library/src/main/scala/special/collection/impl/MonoidInstancesImpl.scala index f739b2a6f5..e9b049c93a 100644 --- a/library/src/main/scala/special/collection/impl/MonoidInstancesImpl.scala +++ b/library/src/main/scala/special/collection/impl/MonoidInstancesImpl.scala @@ -1,5 +1,6 @@ package special.collection +import scala.language.{existentials,implicitConversions} import scalan._ import scala.reflect.runtime.universe._ import scala.reflect._ diff --git a/library/src/main/scala/special/collection/impl/MonoidsImpl.scala b/library/src/main/scala/special/collection/impl/MonoidsImpl.scala index 011647e54a..7635f2a488 100644 --- a/library/src/main/scala/special/collection/impl/MonoidsImpl.scala +++ b/library/src/main/scala/special/collection/impl/MonoidsImpl.scala @@ -1,5 +1,6 @@ package special.collection +import scala.language.{existentials,implicitConversions} import scalan._ import scala.reflect.runtime.universe._ import scala.reflect._ diff --git a/library/src/main/scala/special/collection/impl/SizesImpl.scala b/library/src/main/scala/special/collection/impl/SizesImpl.scala index b43eaa83a4..d542aa16de 100644 --- a/library/src/main/scala/special/collection/impl/SizesImpl.scala +++ b/library/src/main/scala/special/collection/impl/SizesImpl.scala @@ -1,5 +1,6 @@ package special.collection +import scala.language.{existentials,implicitConversions} import scalan._ import scala.reflect.runtime.universe._ import scala.reflect._ diff --git a/library/src/main/scala/special/wrappers/impl/WrappersSpecImpl.scala b/library/src/main/scala/special/wrappers/impl/WrappersSpecImpl.scala index 26f65a25ba..b9631962e4 100644 --- a/library/src/main/scala/special/wrappers/impl/WrappersSpecImpl.scala +++ b/library/src/main/scala/special/wrappers/impl/WrappersSpecImpl.scala @@ -1,5 +1,6 @@ package special.wrappers +import scala.language.{existentials,implicitConversions} import scalan._ import scala.reflect.runtime.universe._ import scala.reflect._ diff --git a/library/src/main/scala/wrappers/scala/impl/WOptionsImpl.scala b/library/src/main/scala/wrappers/scala/impl/WOptionsImpl.scala index 752a939276..2e92cabaf4 100644 --- a/library/src/main/scala/wrappers/scala/impl/WOptionsImpl.scala +++ b/library/src/main/scala/wrappers/scala/impl/WOptionsImpl.scala @@ -1,5 +1,6 @@ package wrappers.scala +import scala.language.{existentials,implicitConversions} import scalan._ import special.wrappers.WrappersModule import special.wrappers.OptionWrapSpec diff --git a/library/src/main/scala/wrappers/scalan/impl/WRTypesImpl.scala b/library/src/main/scala/wrappers/scalan/impl/WRTypesImpl.scala index 362a5cbe2a..abb2ba904f 100644 --- a/library/src/main/scala/wrappers/scalan/impl/WRTypesImpl.scala +++ b/library/src/main/scala/wrappers/scalan/impl/WRTypesImpl.scala @@ -1,5 +1,6 @@ package wrappers.scalan +import scala.language.{existentials,implicitConversions} import scalan._ import scalan.RType import special.wrappers.WrappersModule diff --git a/library/src/main/scala/wrappers/special/impl/WSpecialPredefsImpl.scala b/library/src/main/scala/wrappers/special/impl/WSpecialPredefsImpl.scala index 292353c715..619969292b 100644 --- a/library/src/main/scala/wrappers/special/impl/WSpecialPredefsImpl.scala +++ b/library/src/main/scala/wrappers/special/impl/WSpecialPredefsImpl.scala @@ -1,5 +1,6 @@ package wrappers.special +import scala.language.{existentials,implicitConversions} import scalan._ import impl._ import special.wrappers.WrappersModule diff --git a/library/src/test/scala/special/collections/CollGens.scala b/library/src/test/scala/special/collections/CollGens.scala index 00b1ab68cc..a78e4d3e3c 100644 --- a/library/src/test/scala/special/collections/CollGens.scala +++ b/library/src/test/scala/special/collections/CollGens.scala @@ -1,5 +1,6 @@ package special.collections +import scala.language.{existentials,implicitConversions} import scala.collection.mutable.ArrayBuffer import org.scalacheck.util.Buildable diff --git a/library/src/test/scala/special/collections/CollsTests.scala b/library/src/test/scala/special/collections/CollsTests.scala index 0e93e1a09a..ba3ddd1210 100644 --- a/library/src/test/scala/special/collections/CollsTests.scala +++ b/library/src/test/scala/special/collections/CollsTests.scala @@ -1,5 +1,6 @@ package special.collections +import scala.language.{existentials,implicitConversions} import special.collection.{Coll, PairOfCols, CollOverArray, CReplColl} import org.scalacheck.Gen import org.scalatest.{PropSpec, Matchers} diff --git a/sigma-library/src/main/scala/special/sigma/impl/CostedObjectsImpl.scala b/sigma-library/src/main/scala/special/sigma/impl/CostedObjectsImpl.scala index 2e9632ca66..3972110a41 100644 --- a/sigma-library/src/main/scala/special/sigma/impl/CostedObjectsImpl.scala +++ b/sigma-library/src/main/scala/special/sigma/impl/CostedObjectsImpl.scala @@ -1,5 +1,6 @@ package special.sigma +import scala.language.{existentials,implicitConversions} import scalan._ import scala.collection.mutable.WrappedArray diff --git a/sigma-library/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sigma-library/src/main/scala/special/sigma/impl/SigmaDslImpl.scala index b964d94b0b..47a377b03e 100644 --- a/sigma-library/src/main/scala/special/sigma/impl/SigmaDslImpl.scala +++ b/sigma-library/src/main/scala/special/sigma/impl/SigmaDslImpl.scala @@ -1,5 +1,6 @@ package special.sigma +import scala.language.{existentials,implicitConversions} import scalan._ import scala.reflect.runtime.universe._ import scala.reflect._ diff --git a/sigmastate/src/main/scala/org/ergoplatform/ErgoBoxCandidate.scala b/sigmastate/src/main/scala/org/ergoplatform/ErgoBoxCandidate.scala index d5ada2cce3..0b11792137 100644 --- a/sigmastate/src/main/scala/org/ergoplatform/ErgoBoxCandidate.scala +++ b/sigmastate/src/main/scala/org/ergoplatform/ErgoBoxCandidate.scala @@ -5,11 +5,10 @@ import java.util import org.ergoplatform.ErgoBox._ import org.ergoplatform.settings.ErgoAlgos import scorex.crypto.hash.Digest32 -import scorex.util.{bytesToId, idToBytes, ModifierId} +import scorex.util.{bytesToId, ModifierId} import sigmastate.Values._ import sigmastate._ import sigmastate.SType.AnyOps -import sigmastate.lang.Terms._ import sigmastate.serialization.SigmaSerializer import sigmastate.utils.{SigmaByteReader, SigmaByteWriter} import special.collection.Coll diff --git a/sigmastate/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala b/sigmastate/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala index 4cbcb555f0..6699cb1d91 100644 --- a/sigmastate/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala +++ b/sigmastate/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala @@ -24,8 +24,17 @@ object ErgoScriptPredef { IR.buildTree(calcF) } - val FalseProp = ErgoTree.withoutSegregation(FalseSigmaProp) - val TrueProp = ErgoTree.withoutSegregation(TrueSigmaProp) + /** Create ErgoTree with `false` proposition, which is never true. + * @param headerFlags ErgoTree header flags to be combined with default header + * @see ErgoTree.headerWithVersion() + */ + def FalseProp(headerFlags: Byte): ErgoTree = ErgoTree.withoutSegregation(headerFlags, FalseSigmaProp) + + /** Create ErgoTree with `true` proposition, which is always true. + * @param headerFlags ErgoTree header flags to be combined with default header + * @see ErgoTree.headerWithVersion() + */ + def TrueProp(headerFlags: Byte): ErgoTree = ErgoTree.withoutSegregation(headerFlags, TrueSigmaProp) /** * Byte array value of the serialized reward output script proposition with pk being substituted diff --git a/sigmastate/src/main/scala/org/ergoplatform/JsonCodecs.scala b/sigmastate/src/main/scala/org/ergoplatform/JsonCodecs.scala index 28a905d342..a8684f1568 100644 --- a/sigmastate/src/main/scala/org/ergoplatform/JsonCodecs.scala +++ b/sigmastate/src/main/scala/org/ergoplatform/JsonCodecs.scala @@ -13,7 +13,7 @@ import scorex.crypto.hash.Digest32 import scorex.util.ModifierId import sigmastate.Values.{ErgoTree, EvaluatedValue} import sigmastate.eval.Extensions._ -import sigmastate.eval.{CGroupElement, CPreHeader, WrapperOf, _} +import sigmastate.eval.{CPreHeader, WrapperOf, _} import sigmastate.interpreter.{ContextExtension, ProverResult} import sigmastate.lang.exceptions.SigmaException import sigmastate.serialization.{DataJsonEncoder, ErgoTreeSerializer, ValueSerializer} @@ -21,7 +21,7 @@ import sigmastate.{AvlTreeData, AvlTreeFlags, SType} import special.collection.Coll import special.sigma.{AnyValue, Header, PreHeader} import scala.util.Try -import sigmastate.utils.Helpers._ +import sigmastate.utils.Helpers._ // required for Scala 2.11 trait JsonCodecs { diff --git a/sigmastate/src/main/scala/org/ergoplatform/dsl/ContractSyntax.scala b/sigmastate/src/main/scala/org/ergoplatform/dsl/ContractSyntax.scala index 3c51834b85..d4266bb1c6 100644 --- a/sigmastate/src/main/scala/org/ergoplatform/dsl/ContractSyntax.scala +++ b/sigmastate/src/main/scala/org/ergoplatform/dsl/ContractSyntax.scala @@ -22,13 +22,16 @@ trait ContractSyntax { contract: SigmaContract => def Coll[T](items: T*)(implicit cT: RType[T]) = builder.Colls.fromItems(items:_*) - def proposition(name: String, dslSpec: Proposition, scriptCode: String) = { + def proposition(name: String, + dslSpec: Proposition, + scriptCode: String, + scriptVersion: Option[Byte] = None): spec.PropositionSpec = { val env = contractEnv.mapValues { v => val tV = Evaluation.rtypeOf(v).get val elemTpe = Evaluation.rtypeToSType(tV) spec.IR.builder.mkConstant[SType](v.asWrappedType, elemTpe) } - spec.mkPropositionSpec(name, dslSpec, ErgoScript(env, scriptCode)) + spec.mkPropositionSpec(name, dslSpec, ErgoScript(env, scriptCode, scriptVersion)) } def Env(entries: (String, Any)*): ScriptEnv = Map(entries:_*) @@ -36,7 +39,7 @@ trait ContractSyntax { contract: SigmaContract => object ContractSyntax { type Proposition = Context => SigmaProp type TokenId = Coll[Byte] - case class ErgoScript(env: ScriptEnv, code: String) + case class ErgoScript(env: ScriptEnv, code: String, scriptVersion: Option[Byte]) case class Token(id: TokenId, value: Long) } diff --git a/sigmastate/src/main/scala/sigmastate/SigSerializer.scala b/sigmastate/src/main/scala/sigmastate/SigSerializer.scala index c17178e9c3..40fa3d8ad6 100644 --- a/sigmastate/src/main/scala/sigmastate/SigSerializer.scala +++ b/sigmastate/src/main/scala/sigmastate/SigSerializer.scala @@ -10,7 +10,6 @@ import Helpers.xor import gf2t.GF2_192_Poly import sigmastate.basics.{SecondDiffieHellmanTupleProverMessage, ProveDHTuple} - object SigSerializer { val hashSize = CryptoConstants.soundnessBits / 8 diff --git a/sigmastate/src/main/scala/sigmastate/Values.scala b/sigmastate/src/main/scala/sigmastate/Values.scala index 17d0b860c8..07e8e3f4d0 100644 --- a/sigmastate/src/main/scala/sigmastate/Values.scala +++ b/sigmastate/src/main/scala/sigmastate/Values.scala @@ -744,6 +744,8 @@ object Values { def isProven: Value[SBoolean.type] = SigmaPropIsProven(p) def propBytes: Value[SByteArray] = SigmaPropBytes(p) def treeWithSegregation: ErgoTree = ErgoTree.withSegregation(p) + def treeWithSegregation(headerFlags: Byte): ErgoTree = + ErgoTree.withSegregation(headerFlags, p) } implicit class SigmaBooleanOps(val sb: SigmaBoolean) extends AnyVal { @@ -1069,6 +1071,12 @@ object Values { h } + /** Substitute [[ConstantPlaceholder]] nodes in the given expression with the constants + * taken from the given collection. + * @param root expression to transform + * @param constants collection of constants to replace placeholders + * @return new expression without placeholders + */ def substConstants(root: SValue, constants: IndexedSeq[Constant[SType]]): SValue = { val store = new ConstantStore(constants) val substRule = strategy[Any] { @@ -1079,29 +1087,52 @@ object Values { everywherebu(substRule)(root).fold(root)(_.asInstanceOf[SValue]) } + /** Create an ErgoTree with the given parameters. */ def apply(header: Byte, constants: IndexedSeq[Constant[SType]], root: SigmaPropValue): ErgoTree = { new ErgoTree(header, constants, Right(root)) } val EmptyConstants: IndexedSeq[Constant[SType]] = Array[Constant[SType]]() + /** Create new ErgoTree for the given proposition using the given header flags and + * without performing constant segregation. + */ def withoutSegregation(root: SigmaPropValue): ErgoTree = ErgoTree(ErgoTree.DefaultHeader, EmptyConstants, root) + /** Create new ErgoTree for the given proposition using the given header flags and + * without performing constant segregation. + */ def withoutSegregation(headerFlags: Byte, root: SigmaPropValue): ErgoTree = ErgoTree((ErgoTree.DefaultHeader | headerFlags).toByte, EmptyConstants, root) + /** Create new ErgoTree for the given proposition using default header. + * If the property is not a simple constant, then constant segregation is performed. + */ implicit def fromProposition(prop: SigmaPropValue): ErgoTree = { + fromProposition(ErgoTree.DefaultHeader, prop) + } + + /** Create new ErgoTree for the given proposition using the given header flags. + * If the property is not a simple constant, then constant segregation is performed. + */ + def fromProposition(headerFlags: Byte, prop: SigmaPropValue): ErgoTree = { prop match { - case SigmaPropConstant(_) => withoutSegregation(prop) - case _ => withSegregation(prop) + case SigmaPropConstant(_) => withoutSegregation(headerFlags, prop) + case _ => withSegregation(headerFlags, prop) } } + /** Create new ErgoTree for the given sigma proposition using default header and + * without performing constant segregation. + */ implicit def fromSigmaBoolean(pk: SigmaBoolean): ErgoTree = { withoutSegregation(pk.toSigmaProp) } + /** Create new ErgoTree for the given sigma proposition using the given header flags + * and without performing constant segregation. + */ def fromSigmaBoolean(headerFlags: Byte, pk: SigmaBoolean): ErgoTree = { withoutSegregation(headerFlags, pk.toSigmaProp) } @@ -1114,12 +1145,15 @@ object Values { * 2) replace constants with ConstantPlaceholders in the `tree`; * 3) write the `tree` to the Writer's buffer obtaining `treeBytes`; * 4) deserialize `tree` with ConstantPlaceholders. + * @param headerFlags additional header flags to combine with + * ConstantSegregationHeader flag. + * @param prop expression to be transformed into ErgoTree **/ - def withSegregation(headerFlags: Byte, value: SigmaPropValue): ErgoTree = { + def withSegregation(headerFlags: Byte, prop: SigmaPropValue): ErgoTree = { val constantStore = new ConstantStore() val byteWriter = SigmaSerializer.startWriter(constantStore) // serialize value and segregate constants into constantStore - ValueSerializer.serialize(value, byteWriter) + ValueSerializer.serialize(prop, byteWriter) val extractedConstants = constantStore.getAll val r = SigmaSerializer.startReader(byteWriter.toBytes) r.constantStore = new ConstantStore(extractedConstants) @@ -1129,8 +1163,11 @@ object Values { new ErgoTree(header, extractedConstants, Right(valueWithPlaceholders)) } - def withSegregation(value: SigmaPropValue): ErgoTree = - withSegregation(0, value) + /** Create new ErgoTree for the given sigma proposition using default header and + * also performing constant segregation. + */ + def withSegregation(prop: SigmaPropValue): ErgoTree = + withSegregation(DefaultHeader, prop) } } diff --git a/sigmastate/src/main/scala/sigmastate/eval/BigIntegerOps.scala b/sigmastate/src/main/scala/sigmastate/eval/BigIntegerOps.scala index 799382cf10..a03ba6fca0 100644 --- a/sigmastate/src/main/scala/sigmastate/eval/BigIntegerOps.scala +++ b/sigmastate/src/main/scala/sigmastate/eval/BigIntegerOps.scala @@ -2,12 +2,11 @@ package sigmastate.eval import java.math.BigInteger -import scalan.{ExactNumeric, ExactIntegral, ExactOrderingImpl} +import scalan.{ExactNumeric, ExactOrderingImpl} import scala.math.{Integral, Ordering} import special.sigma._ import sigmastate.eval.Extensions._ -import special.collection.Coll object OrderingOps { def apply[T](implicit ord: Ordering[T]) = ord diff --git a/sigmastate/src/main/scala/sigmastate/eval/CompiletimeCosting.scala b/sigmastate/src/main/scala/sigmastate/eval/CompiletimeCosting.scala index c4ae6e1590..d3cfcb962c 100644 --- a/sigmastate/src/main/scala/sigmastate/eval/CompiletimeCosting.scala +++ b/sigmastate/src/main/scala/sigmastate/eval/CompiletimeCosting.scala @@ -12,7 +12,6 @@ import sigmastate.SCollection._ import sigmastate.SBigInt._ import sigmastate.Values.Value.Typed import sigmastate.lang.Terms -import scalan.util.Extensions._ trait CompiletimeCosting extends RuntimeCosting { IR: IRContext => import builder._ diff --git a/sigmastate/src/main/scala/sigmastate/eval/Evaluation.scala b/sigmastate/src/main/scala/sigmastate/eval/Evaluation.scala index 1241571810..e2e91693c1 100644 --- a/sigmastate/src/main/scala/sigmastate/eval/Evaluation.scala +++ b/sigmastate/src/main/scala/sigmastate/eval/Evaluation.scala @@ -15,7 +15,7 @@ import scalan.{Nullable, RType} import scalan.RType._ import sigma.types.PrimViewType import sigmastate.basics.DLogProtocol.ProveDlog -import sigmastate.basics.{ProveDHTuple} +import sigmastate.basics.ProveDHTuple import special.sigma.Extensions._ import sigmastate.lang.exceptions.CostLimitException import sigmastate.serialization.OpCodes diff --git a/sigmastate/src/main/scala/sigmastate/eval/TreeBuilding.scala b/sigmastate/src/main/scala/sigmastate/eval/TreeBuilding.scala index 0e8253391a..ed34043c1d 100644 --- a/sigmastate/src/main/scala/sigmastate/eval/TreeBuilding.scala +++ b/sigmastate/src/main/scala/sigmastate/eval/TreeBuilding.scala @@ -1,10 +1,8 @@ package sigmastate.eval -import sigmastate.Values.{BlockItem, BlockValue, BoolValue, Constant, ConstantNode, SValue, SigmaPropConstant, ValDef, ValUse, Value} +import sigmastate.Values._ import org.ergoplatform._ - -import org.ergoplatform.{Height, Inputs, Outputs, Self} import sigmastate._ import sigmastate.lang.Terms.ValueOps import sigmastate.serialization.OpCodes._ @@ -422,7 +420,16 @@ trait TreeBuilding extends RuntimeCosting { IR: IRContext => } val Seq(root) = subG.roots val rhs = buildValue(ctx, mainG, curEnv, root, curId, constantsProcessing) - val res = if (valdefs.nonEmpty) BlockValue(valdefs.toArray[BlockItem], rhs) else rhs + val res = if (valdefs.nonEmpty) { + (valdefs.toArray[BlockItem], rhs) match { + // simple optimization to avoid producing block sub-expressions like: + // `{ val idNew = id; idNew }` which this rules rewrites to just `id` + case (Array(ValDef(idNew, _, source @ ValUse(id, tpe))), ValUse(idUse, tpeUse)) + if idUse == idNew && tpeUse == tpe => source + case (items, _) => + BlockValue(items, rhs) + } + } else rhs res } diff --git a/sigmastate/src/main/scala/sigmastate/eval/Zero.scala b/sigmastate/src/main/scala/sigmastate/eval/Zero.scala index 2fade5bd0a..a29ef6f769 100644 --- a/sigmastate/src/main/scala/sigmastate/eval/Zero.scala +++ b/sigmastate/src/main/scala/sigmastate/eval/Zero.scala @@ -2,17 +2,14 @@ package sigmastate.eval import java.math.BigInteger -import scalan.{Nullable, RType} -import special.collection.{CSizePrim, CSizePair, Size, CSizeOption, CollType, Coll, CSizeColl} +import scalan.RType +import special.collection.{Coll, CollType} import scalan.RType._ import sigmastate._ -import sigmastate.SBigInt.MaxSizeInBytes import special.sigma._ -import SType.AnyOps import scorex.crypto.authds.avltree.batch.BatchAVLProver import scorex.crypto.hash.{Digest32, Blake2b256} import sigmastate.interpreter.CryptoConstants -import sigmastate.interpreter.CryptoConstants.EcPointType trait Zero[T] { def zero: T diff --git a/sigmastate/src/main/scala/sigmastate/interpreter/Interpreter.scala b/sigmastate/src/main/scala/sigmastate/interpreter/Interpreter.scala index 5aee794a74..543dd6bbfb 100644 --- a/sigmastate/src/main/scala/sigmastate/interpreter/Interpreter.scala +++ b/sigmastate/src/main/scala/sigmastate/interpreter/Interpreter.scala @@ -265,23 +265,7 @@ trait Interpreter extends ScorexLogging { val checkingResult = cProp match { case TrivialProp.TrueProp => true case TrivialProp.FalseProp => false - case _ => - // Perform Verifier Steps 1-3 - SigSerializer.parseAndComputeChallenges(cProp, proof) match { - case NoProof => false - case sp: UncheckedSigmaTree => - // Perform Verifier Step 4 - val newRoot = computeCommitments(sp).get.asInstanceOf[UncheckedSigmaTree] - - /** - * Verifier Steps 5-6: Convert the tree to a string `s` for input to the Fiat-Shamir hash function, - * using the same conversion as the prover in 7 - * Accept the proof if the challenge at the root of the tree is equal to the Fiat-Shamir hash of `s` - * (and, if applicable, the associated data). Reject otherwise. - */ - val expectedChallenge = CryptoFunctions.hashFn(FiatShamirTree.toBytes(newRoot) ++ message) - util.Arrays.equals(newRoot.challenge, expectedChallenge) - } + case _ => verifySignature(cProp, message, proof) } checkingResult -> cost }) @@ -303,6 +287,21 @@ trait Interpreter extends ScorexLogging { res } + // Perform Verifier Steps 4-6 + private def checkCommitments(sp: UncheckedSigmaTree, message: Array[Byte]): Boolean = { + // Perform Verifier Step 4 + val newRoot = computeCommitments(sp).get.asInstanceOf[UncheckedSigmaTree] + + /** + * Verifier Steps 5-6: Convert the tree to a string `s` for input to the Fiat-Shamir hash function, + * using the same conversion as the prover in 7 + * Accept the proof if the challenge at the root of the tree is equal to the Fiat-Shamir hash of `s` + * (and, if applicable, the associated data). Reject otherwise. + */ + val expectedChallenge = CryptoFunctions.hashFn(FiatShamirTree.toBytes(newRoot) ++ message) + util.Arrays.equals(newRoot.challenge, expectedChallenge) + } + /** * Verifier Step 4: For every leaf node, compute the commitment a from the challenge e and response $z$, * per the verifier algorithm of the leaf's Sigma-protocol. @@ -347,6 +346,30 @@ trait Interpreter extends ScorexLogging { verify(Interpreter.emptyEnv, ergoTree, context, SigSerializer.toBytes(proof), message) } + /** + * Verify a signature on given (arbitrary) message for a given public key. + * + * @param sigmaTree - public key (represented as a tree) + * @param message - message + * @param signature - signature for the message + * @return - whether signature is valid or not + */ + def verifySignature(sigmaTree: SigmaBoolean, + message: Array[Byte], + signature: Array[Byte]): Boolean = { + // Perform Verifier Steps 1-3 + try { + SigSerializer.parseAndComputeChallenges(sigmaTree, signature) match { + case NoProof => false + case sp: UncheckedSigmaTree => + // Perform Verifier Steps 4-6 + checkCommitments(sp, message) + } + } catch { + case e: Exception => log.warn("Improper signature: ", e); false + } + } + } object Interpreter { @@ -379,4 +402,4 @@ object Interpreter { def error(msg: String) = throw new InterpreterException(msg) -} +} \ No newline at end of file diff --git a/sigmastate/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala b/sigmastate/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala index 1c7cc0082c..da0f26dac6 100644 --- a/sigmastate/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala +++ b/sigmastate/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala @@ -111,7 +111,6 @@ trait ProverInterpreter extends Interpreter with ProverUtils with AttributionCor message: Array[Byte]): Try[CostedProverResult] = prove(emptyEnv, ergoTree, context, message, HintsBag.empty) - def prove(env: ScriptEnv, ergoTree: ErgoTree, context: CTX, @@ -580,4 +579,21 @@ trait ProverInterpreter extends Interpreter with ProverUtils with AttributionCor error(s"Cannot convertToUnproven($a)") } + /** + * + * Sign arbitrary message under a key representing a statement provable via a sigma-protocol. + * + * @param sigmaTree - public key + * @param message - message to sign + * @param hintsBag - additional hints for a signer (useful for distributed signing) + * @return - signature or error + */ + def signMessage(sigmaTree: SigmaBoolean, + message: Array[Byte], + hintsBag: HintsBag): Try[Array[Byte]] = Try { + val unprovenTree = convertToUnproven(sigmaTree) + val proofTree = prove(unprovenTree, message, hintsBag) + SigSerializer.toBytes(proofTree) + } + } diff --git a/sigmastate/src/main/scala/sigmastate/interpreter/ProverUtils.scala b/sigmastate/src/main/scala/sigmastate/interpreter/ProverUtils.scala index ff19d2cc0c..25f8be0a65 100644 --- a/sigmastate/src/main/scala/sigmastate/interpreter/ProverUtils.scala +++ b/sigmastate/src/main/scala/sigmastate/interpreter/ProverUtils.scala @@ -68,7 +68,7 @@ trait ProverUtils extends Interpreter { * See DistributedSigSpecification for examples of usage. * * @param context - context used to reduce the proposition - * @param ergoTree - proposition to reduce + * @param ergoTree - proposition to reduce * @param proof - proof for reduced proposition * @param realSecretsToExtract - public keys of secrets with real proofs * @param simulatedSecretsToExtract - public keys of secrets with simulated proofs @@ -79,10 +79,30 @@ trait ProverUtils extends Interpreter { proof: Array[Byte], realSecretsToExtract: Seq[SigmaBoolean], simulatedSecretsToExtract: Seq[SigmaBoolean] = Seq.empty): HintsBag = { - val reducedTree = fullReduction(ergoTree, context, Interpreter.emptyEnv)._1 + bagForMultisig(context, reducedTree, proof, realSecretsToExtract, simulatedSecretsToExtract) + } + + /** + * A method which is extracting partial proofs of secret knowledge for particular secrets with their + * respective public images given. Useful for distributed signature applications. + * + * See DistributedSigSpecification for examples of usage. + * + * @param context - context used to reduce the proposition + * @param sigmaTree - public key (in form of a sigma-tree) + * @param proof - signature for the key + * @param realSecretsToExtract - public keys of secrets with real proofs + * @param simulatedSecretsToExtract - public keys of secrets with simulated proofs + * @return - bag of OtherSecretProven and OtherCommitment hints + */ + def bagForMultisig(context: CTX, + sigmaTree: SigmaBoolean, + proof: Array[Byte], + realSecretsToExtract: Seq[SigmaBoolean], + simulatedSecretsToExtract: Seq[SigmaBoolean]): HintsBag = { - val ut = SigSerializer.parseAndComputeChallenges(reducedTree, proof) + val ut = SigSerializer.parseAndComputeChallenges(sigmaTree, proof) val proofTree = computeCommitments(ut).get.asInstanceOf[UncheckedSigmaTree] def traverseNode(tree: ProofTree, diff --git a/sigmastate/src/main/scala/sigmastate/lang/SigmaBuilder.scala b/sigmastate/src/main/scala/sigmastate/lang/SigmaBuilder.scala index 5849fa1ffc..5ec5145474 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/SigmaBuilder.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/SigmaBuilder.scala @@ -5,7 +5,7 @@ import java.math.BigInteger import org.ergoplatform.ErgoBox import org.ergoplatform.ErgoBox.RegisterId import sigmastate.SCollection.{SByteArray, SIntArray} -import sigmastate.Values.{BlockItem, BlockValue, BoolValue, ConcreteCollection, Constant, ConstantNode, ConstantPlaceholder, FalseLeaf, FuncValue, GroupElementValue, NoneValue, SValue, SigmaBoolean, SigmaPropValue, SomeValue, StringConstant, TaggedVariable, TaggedVariableNode, TrueLeaf, Tuple, ValUse, Value, _} +import sigmastate.Values._ import sigmastate._ import sigmastate.lang.Constraints.{TypeConstraint2, onlyNumeric2, sameType2} import sigmastate.lang.Terms._ diff --git a/sigmastate/src/main/scala/sigmastate/lang/SigmaCompiler.scala b/sigmastate/src/main/scala/sigmastate/lang/SigmaCompiler.scala index 7ce2e4a6e0..d41c2c1220 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/SigmaCompiler.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/SigmaCompiler.scala @@ -3,12 +3,9 @@ package sigmastate.lang import fastparse.core.Parsed import fastparse.core.Parsed.Success import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix -import org.ergoplatform.ErgoLikeContext -import scalan.RType -import sigmastate.{SBoolean, SType} -import sigmastate.Values.{TrueLeaf, Value, Constant, SValue} -import sigmastate.eval.{Evaluation, IRContext} -import sigmastate.interpreter.Interpreter +import sigmastate.SType +import sigmastate.Values.{Value, SValue} +import sigmastate.eval.IRContext import sigmastate.interpreter.Interpreter.ScriptEnv import sigmastate.lang.SigmaPredef.PredefinedFuncRegistry import sigmastate.lang.syntax.ParserException diff --git a/sigmastate/src/main/scala/sigmastate/lang/SigmaSpecializer.scala b/sigmastate/src/main/scala/sigmastate/lang/SigmaSpecializer.scala index e2e6869904..22e6ce5a2b 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/SigmaSpecializer.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/SigmaSpecializer.scala @@ -1,19 +1,15 @@ package sigmastate.lang import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{reduce, rewrite, strategy} -import org.ergoplatform.ErgoAddressEncoder.{NetworkPrefix, TestnetNetworkPrefix} import org.ergoplatform._ -import scalan.Nullable -import scorex.util.encode.{Base58, Base64} import sigmastate.SCollection._ import sigmastate.Values.Value.Typed import sigmastate.Values._ import sigmastate._ import sigmastate.lang.SigmaPredef._ -import sigmastate.lang.Terms.{Apply, ApplyTypes, Block, Ident, Lambda, Select, Val, ValueOps} +import sigmastate.lang.Terms.{Apply, Block, Ident, Lambda, Select, Val, ValueOps} import sigmastate.lang.exceptions.SpecializerException import sigmastate.utxo._ -import scorex.util.Extensions._ class SigmaSpecializer(val builder: SigmaBuilder) { import SigmaSpecializer._ diff --git a/sigmastate/src/main/scala/sigmastate/lang/Terms.scala b/sigmastate/src/main/scala/sigmastate/lang/Terms.scala index 162f92f3f9..333a08dc0c 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/Terms.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/Terms.scala @@ -238,6 +238,8 @@ object Terms { def apply(args: IndexedSeq[(String,SType)], body: Value[SType]): Lambda = Lambda(Nil, args, NoType, Some(body)) } + /** Operation identity descriptor used in AOT costing (see usages in RuntimeCosting and + * CostTable) */ case class OperationId(name: String, opType: SFunc) implicit class ValueOps(val v: Value[SType]) extends AnyVal { diff --git a/sigmastate/src/main/scala/sigmastate/lang/syntax/Basic.scala b/sigmastate/src/main/scala/sigmastate/lang/syntax/Basic.scala index 0de13a3afa..27ecbb3d24 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/syntax/Basic.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/syntax/Basic.scala @@ -5,7 +5,6 @@ import fastparse.CharPredicates._ import scalan.Nullable import sigmastate.lang.SourceContext import sigmastate.lang.exceptions.SigmaException -import scalan.util.Extensions._ object Basic { val digits = "0123456789" diff --git a/sigmastate/src/main/scala/sigmastate/lang/syntax/Core.scala b/sigmastate/src/main/scala/sigmastate/lang/syntax/Core.scala index 935113e680..b2ec56abbe 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/syntax/Core.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/syntax/Core.scala @@ -1,10 +1,9 @@ package sigmastate.lang.syntax import scala.language.implicitConversions -import sigmastate.lang.Terms._ import sigmastate._ import sigmastate.Values._ -import sigmastate.lang.{SigmaBuilder, StdSigmaBuilder, syntax} +import sigmastate.lang.syntax trait Core extends syntax.Literals { import fastparse.noApi._ diff --git a/sigmastate/src/main/scala/sigmastate/lang/syntax/Exprs.scala b/sigmastate/src/main/scala/sigmastate/lang/syntax/Exprs.scala index 56e50b9546..f7da0bd2a5 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/syntax/Exprs.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/syntax/Exprs.scala @@ -1,7 +1,6 @@ package sigmastate.lang.syntax import fastparse.noApi._ -import scalan.Nullable import sigmastate._ import sigmastate.Values._ import sigmastate.lang.Terms.{ValueOps, Ident, Val} diff --git a/sigmastate/src/main/scala/sigmastate/lang/syntax/Literals.scala b/sigmastate/src/main/scala/sigmastate/lang/syntax/Literals.scala index 989e01939f..f35cd0e266 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/syntax/Literals.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/syntax/Literals.scala @@ -4,7 +4,7 @@ import fastparse.all._ import Identifiers._ import sigmastate._ import Values._ -import fastparse.{all, core} +import fastparse.core import java.lang.Long.parseLong import java.lang.Integer.parseInt diff --git a/sigmastate/src/main/scala/sigmastate/serialization/DataJsonEncoder.scala b/sigmastate/src/main/scala/sigmastate/serialization/DataJsonEncoder.scala index 07d05ab174..c9812e9666 100644 --- a/sigmastate/src/main/scala/sigmastate/serialization/DataJsonEncoder.scala +++ b/sigmastate/src/main/scala/sigmastate/serialization/DataJsonEncoder.scala @@ -8,7 +8,6 @@ import org.ergoplatform.ErgoBox import org.ergoplatform.ErgoBox.NonMandatoryRegisterId import org.ergoplatform.settings.ErgoAlgos import scalan.RType -import scalan.RType.PairType import scorex.crypto.hash.Digest32 import scorex.util._ import sigmastate.Values.{Constant, EvaluatedValue} @@ -16,7 +15,7 @@ import sigmastate._ import sigmastate.eval._ import sigmastate.lang.SigmaParser import sigmastate.lang.exceptions.SerializerException -import special.collection.{Coll, PairColl, collRType} +import special.collection.{Coll, collRType} import special.sigma._ import spire.syntax.all.cfor diff --git a/sigmastate/src/main/scala/sigmastate/trees.scala b/sigmastate/src/main/scala/sigmastate/trees.scala index 1ce7966d4d..2600ab89a1 100644 --- a/sigmastate/src/main/scala/sigmastate/trees.scala +++ b/sigmastate/src/main/scala/sigmastate/trees.scala @@ -380,10 +380,13 @@ case class Upcast[T <: SNumericType, R <: SNumericType](input: Value[T], tpe: R) override def companion = Upcast override def opType = Upcast.OpType } + +/** Base class for Upcast and Downcast companion objects. */ trait NumericCastCompanion extends ValueCompanion { def argInfos: Seq[ArgInfo] val OpType = SFunc(Array(SType.tT), SType.tR) } + object Upcast extends NumericCastCompanion { override def opCode: OpCode = OpCodes.UpcastCode override def argInfos: Seq[ArgInfo] = UpcastInfo.argInfos diff --git a/sigmastate/src/main/scala/sigmastate/types.scala b/sigmastate/src/main/scala/sigmastate/types.scala index ac25257a17..0b453d2067 100644 --- a/sigmastate/src/main/scala/sigmastate/types.scala +++ b/sigmastate/src/main/scala/sigmastate/types.scala @@ -161,16 +161,34 @@ 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(SBoolean, SByte, SShort, SInt, SLong, SBigInt, SContext, SGlobal, SHeader, SPreHeader, SAvlTree, SGroupElement, SSigmaProp, SString, SBox, SUnit, SAny) + val allPredefTypes: Seq[SType] = Array(SBoolean, SByte, SShort, SInt, SLong, SBigInt, SContext, + SGlobal, SHeader, SPreHeader, SAvlTree, SGroupElement, SSigmaProp, SString, SBox, + SUnit, SAny) + val typeCodeToType = allPredefTypes.map(t => t.typeCode -> t).toMap - /** 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 corresponding methods. - * NOTE: in the current implementation only monomorphic methods are supported (without type parameters)*/ - // TODO HF (h4): should contain all numeric types (including also SNumericType) + /** 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 + * corresponding methods. + * + * NOTE: in the current implementation only monomorphic methods are supported (without + * type parameters) + * + * NOTE2: in v3.x SNumericType.typeId is silently shadowed by SGlobal.typeId as part of + * `toMap` operation. As a result, the methods collected into SByte.methods cannot be + * 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. + */ + // TODO v5.0 (h4): 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 - val types: Map[Byte, STypeCompanion] = Seq( + 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 @@ -263,7 +281,7 @@ trait STypeCompanion { /** List of methods defined for instances of this type. */ def methods: Seq[SMethod] - lazy val _methodsMap: Map[Byte, Map[Byte, SMethod]] = methods + private lazy val _methodsMap: Map[Byte, Map[Byte, SMethod]] = methods .groupBy(_.objType.typeId) .map { case (typeId, ms) => (typeId -> ms.map(m => m.methodId -> m).toMap) } @@ -282,11 +300,17 @@ trait STypeCompanion { ValidationRules.CheckAndGetMethod(this, methodId) } + /** Looks up the method descriptor by the method name. */ def getMethodByName(name: String): SMethod = methods.find(_.name == name).get + /** CosterFactory associated with this type. */ def coster: Option[CosterFactory] = None } +/** Defines recognizer method which allows the derived object to be used in patterns + * to recognize method descriptors by method name. + * @see SCollecton + */ trait MethodByNameUnapply extends STypeCompanion { def unapply(methodName: String): Option[SMethod] = methods.find(_.name == methodName) } @@ -295,6 +319,8 @@ trait MethodByNameUnapply extends STypeCompanion { trait SProduct extends SType { /** Returns -1 if `method` is not found. */ def methodIndex(name: String): Int = methods.indexWhere(_.name == name) + + /** Returns true if this type has a method with the given name. */ def hasMethod(name: String): Boolean = methodIndex(name) != -1 /** This method should be overriden in derived classes to add new methods in addition to inherited. @@ -311,6 +337,7 @@ trait SProduct extends SType { ms } + /** Finds a method descriptor [[SMethod]] for the given name. */ def method(methodName: String): Option[SMethod] = methods.find(_.name == methodName) } @@ -350,20 +377,37 @@ case class OperationInfo(opDesc: Option[ValueCompanion], description: String, ar } object OperationInfo { + /** Convenience factory method. */ def apply(opDesc: ValueCompanion, description: String, args: Seq[ArgInfo]): OperationInfo = OperationInfo(Some(opDesc), description, args) } /** Meta information connecting SMethod with ErgoTree. - * @param irBuilder optional recognizer and ErgoTree node builder. */ + * The optional builder is used by front-end ErgoScript compiler to replace method calls + * with ErgoTree nodes. In many cases [[SMethod.MethodCallIrBuilder]] builder is used. + * However there are specific cases where more complex builders are used, see for example + * usage of `withIRInfo` in the declaration of [[SCollection.GetOrElseMethod]]. + * @param irBuilder optional method call recognizer and ErgoTree node builder. + * When the partial function is defined on a tuple + * (builder, obj, m, args, subst) it transforms it to a new ErgoTree + * node, which is then used in the resuting ErgoTree coming out of + * the ErgoScript compiler. + */ case class MethodIRInfo( irBuilder: Option[PartialFunction[(SigmaBuilder, SValue, SMethod, Seq[SValue], STypeSubst), SValue]] ) - -/** Method info including name, arg type and result type. - * Here stype.tDom - arg type and stype.tRange - result type. - * `methodId` should be unique among methods of the same objType. */ +/** Represents method descriptor. + * + * @param objType type or type constructor descriptor + * @param name method name + * @param stype method signature type, + * where `stype.tDom`` - argument type and + * `stype.tRange` - method result type. + * @param methodId method code, it should be unique among methods of the same objType. + * @param irInfo meta information connecting SMethod with ErgoTree (see [[MethodIRInfo]]) + * @param docInfo optional human readable method description data + */ case class SMethod( objType: STypeCompanion, name: String, @@ -372,16 +416,30 @@ case class SMethod( irInfo: MethodIRInfo, docInfo: Option[OperationInfo]) { + /** Create a new instance with the given stype. */ def withSType(newSType: SFunc): SMethod = copy(stype = newSType) + /** Create a new instance in which the `stype` field transformed using + * the given substitution. */ def withConcreteTypes(subst: Map[STypeVar, SType]): SMethod = withSType(stype.withSubstTypes(subst).asFunc) + /** Returns [[OperationId]] for AOT costing. */ def opId: OperationId = { val opName = objType.getClass.getSimpleName + "." + name OperationId(opName, stype) } + /** Specializes this instance by creating a new [[SMethod]] instance where signature + * is specialized with respect to the given object and args types. It is used in + * [[sigmastate.serialization.MethodCallSerializer]] `parse` method, so it is part of + * consensus protocol. + * + * @param objTpe specific type of method receiver (aka object) + * @param args specific types of method arguments + * @return new instance of method descriptor with specialized signature + * @consensus + */ def specializeFor(objTpe: SType, args: Seq[SType]): SMethod = { SigmaTyper.unifyTypeLists(stype.tDom, objTpe +: args) match { case Some(subst) if subst.nonEmpty => @@ -389,32 +447,54 @@ case class SMethod( case _ => this } } + + /** Create a new instance with the given [[OperationInfo]] parameters. */ def withInfo(opDesc: ValueCompanion, desc: String, args: ArgInfo*): SMethod = { this.copy(docInfo = Some(OperationInfo(opDesc, desc, ArgInfo("this", "this instance") +: args.toSeq))) } + + /** Create a new instance with the given [[OperationInfo]] parameters. + * NOTE: opDesc parameter is not defined and falls back to None. + */ def withInfo(desc: String, args: ArgInfo*): SMethod = { this.copy(docInfo = Some(OperationInfo(None, desc, ArgInfo("this", "this instance") +: args.toSeq))) } + + /** Create a new instance with the given IR builder (aka MethodCall rewriter) parameter. */ def withIRInfo( irBuilder: PartialFunction[(SigmaBuilder, SValue, SMethod, Seq[SValue], STypeSubst), SValue]): SMethod = { this.copy(irInfo = MethodIRInfo(Some(irBuilder))) } + + /** Lookup [[ArgInfo]] for the given argName or throw an exception. */ def argInfo(argName: String): ArgInfo = docInfo.get.args.find(_.name == argName).get } object SMethod { - type RCosted[A] = RuntimeCosting#RCosted[A] + + /** Default fallback method call recognizer which builds MethodCall ErgoTree nodes. */ val MethodCallIrBuilder: PartialFunction[(SigmaBuilder, SValue, SMethod, Seq[SValue], STypeSubst), SValue] = { case (builder, obj, method, args, tparamSubst) => builder.mkMethodCall(obj, method, args.toIndexedSeq, tparamSubst) } + /** Convenience factory method. */ def apply(objType: STypeCompanion, name: String, stype: SFunc, methodId: Byte): SMethod = { SMethod(objType, name, stype, methodId, MethodIRInfo(None), None) } + /** Looks up [[SMethod]] instance for the given type and method ids. + * + * @param typeId id of a type which can contain methods + * @param methodId id of a method of the type given by `typeId` + * @return an instance of [[SMethod]] which may contain generic type variables in the + * signature (see SMethod.stype). As a result `specializeFor` is called by + * deserializer to obtain monomorphic method descriptor. + * @consensus this is method is used in [[sigmastate.serialization.MethodCallSerializer]] + * `parse` method and hence it is part of consensus protocol + */ def fromIds(typeId: Byte, methodId: Byte): SMethod = { ValidationRules.CheckTypeWithMethods(typeId, SType.types.contains(typeId)) val typeCompanion = SType.types(typeId) @@ -477,10 +557,24 @@ trait SNumericType extends SProduct { m => m.copy(stype = SigmaTyper.applySubst(m.stype, Map(tNum -> this)).asFunc) } } + + /** Checks if the given name is a cast method name. + * @return true if it is. */ def isCastMethod (name: String): Boolean = castMethods.contains(name) - def upcast(i: AnyVal): WrappedType - def downcast(i: AnyVal): WrappedType + /** Upcasts the given value of a smaller type to this larger type. + * @param n numeric value to be converted + * @return a value of WrappedType of this type descriptor's instance. + * @throw exception if `i` has actual type which is larger than this type. + */ + def upcast(n: AnyVal): WrappedType + + /** Downcasts the given value of a larger type to this smaller type. + * @param n numeric value to be converted + * @return a value of WrappedType of this type descriptor's instance. + * @throw exception if the actual value of `i` cannot fit into this type. + */ + def downcast(n: AnyVal): WrappedType /** Returns a type which is larger. */ @inline def max(that: SNumericType): SNumericType = @@ -531,6 +625,8 @@ object SNumericType extends STypeCompanion { ToBytesMethod, ToBitsMethod ) + + /** Collection of names of numeric casting methods (like `toByte`, `toInt`, etc). */ val castMethods: Array[String] = Array(ToByteMethod, ToShortMethod, ToIntMethod, ToLongMethod, ToBigIntMethod) .map(_.name) diff --git a/sigmastate/src/main/scala/sigmastate/utils/ByteReader.scala b/sigmastate/src/main/scala/sigmastate/utils/ByteReader.scala deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sigmastate/src/main/scala/sigmastate/utils/ByteWriter.scala b/sigmastate/src/main/scala/sigmastate/utils/ByteWriter.scala deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sigmastate/src/main/scala/sigmastate/utxo/CostTable.scala b/sigmastate/src/main/scala/sigmastate/utxo/CostTable.scala index 428f202058..5084552d03 100644 --- a/sigmastate/src/main/scala/sigmastate/utxo/CostTable.scala +++ b/sigmastate/src/main/scala/sigmastate/utxo/CostTable.scala @@ -4,12 +4,6 @@ import org.ergoplatform.SigmaConstants import sigmastate.{Downcast, Upcast} import sigmastate.lang.SigmaParser import sigmastate.lang.Terms.OperationId -import sigmastate.serialization.OpCodes -import sigmastate.serialization.OpCodes.{LastConstantCode, OpCode} -import scalan.util.Extensions.ByteOps -import sigmastate.serialization.ValueSerializer.getSerializer - -import scala.collection.mutable case class CostTable(operCosts: Map[OperationId, Int]) extends (OperationId => Int) { @inline private def cleanOperId(operId: OperationId): OperationId = { diff --git a/sigmastate/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala b/sigmastate/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala index 3db081079f..771a8f21cb 100644 --- a/sigmastate/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala +++ b/sigmastate/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala @@ -44,19 +44,19 @@ class ErgoAddressSpecification extends SigmaDslTesting property("SHA roundtrip") { forAll(proveDlogGen) { pk => - addressRoundtrip(Pay2SHAddress(ErgoTree.fromSigmaBoolean(pk))) + addressRoundtrip(Pay2SHAddress(ErgoTree.fromSigmaBoolean(ergoTreeHeaderInTests, pk))) } } property("SA roundtrip") { forAll(proveDlogGen) { pk => - addressRoundtrip(Pay2SAddress(ErgoTree.fromSigmaBoolean(pk))) + addressRoundtrip(Pay2SAddress(ErgoTree.fromSigmaBoolean(ergoTreeHeaderInTests, pk))) } } property("P2SH proper bytes to track") { forAll(proveDlogGen) { pk => - val p2sh = Pay2SHAddress(ErgoTree.fromSigmaBoolean(pk)) + val p2sh = Pay2SHAddress(ErgoTree.fromSigmaBoolean(ergoTreeHeaderInTests, pk)) //search we're doing to find a box potentially corresponding to some address DefaultSerializer.serializeErgoTree(p2sh.script).containsSlice(p2sh.contentBytes) shouldBe true @@ -65,24 +65,28 @@ class ErgoAddressSpecification extends SigmaDslTesting property("P2S proper bytes to track") { forAll(proveDlogGen) { pk => - val p2s = Pay2SAddress(ErgoTree.fromSigmaBoolean(pk)) + val p2s = Pay2SAddress(ErgoTree.fromSigmaBoolean(ergoTreeHeaderInTests, pk)) //search we're doing to find a box potentially corresponding to some address DefaultSerializer.serializeErgoTree(p2s.script).containsSlice(p2s.contentBytes) shouldBe true } } - property("fromProposition() should properly distinct all types of addresses from script AST") { + def testFromProposition(scriptVersion: Byte, + expectedP2S: String, expectedP2SH: String, expectedP2PK: String) = { val pk: DLogProtocol.ProveDlog = DLogProverInput(BigInteger.ONE).publicImage val pk10: DLogProtocol.ProveDlog = DLogProverInput(BigInteger.TEN).publicImage - val p2s: Pay2SAddress = Pay2SAddress(ErgoTree.fromProposition(SigmaAnd(pk, pk10))) + val p2s: Pay2SAddress = Pay2SAddress( + ErgoTree.fromProposition( + ErgoTree.headerWithVersion(scriptVersion), + SigmaAnd(pk, pk10))) val p2sh: Pay2SHAddress = Pay2SHAddress(pk) val p2pk: P2PKAddress = P2PKAddress(pk) - p2s.toString shouldBe "JryiCXrZf5VDetH1PM7rKDX3q4sLF34AdErWJFqG87Hf5ikTDf636b35Nr7goWMdRUKA3ZPxdeqFNbQzBjhnDR9SUMYwDX1tdV8ZuGgXwQPaRVcB9" - p2sh.toString shouldBe "qETVgcEctaXurNbFRgGUcZEGg4EKa8R4a5UNHY7" - p2pk.toString shouldBe "3WwXpssaZwcNzaGMv3AgxBdTPJQBt5gCmqBsg3DykQ39bYdhJBsN" + p2s.toString shouldBe expectedP2S + p2sh.toString shouldBe expectedP2SH + p2pk.toString shouldBe expectedP2PK assertResult(true)(p2s != p2sh && p2sh != p2s) assertResult(true)(p2sh != p2pk && p2pk != p2sh) @@ -103,7 +107,7 @@ class ErgoAddressSpecification extends SigmaDslTesting assertResult(true)(parsed_p2pk == p2pk && p2pk == parsed_p2pk) parsed_p2pk.hashCode() shouldBe p2pk.hashCode() - val tree = ErgoTree.fromProposition(pk) + val tree = mkTestErgoTree(pk) val p2s_2: Pay2SAddress = Pay2SAddress(tree) // address created via P2S constructor method assertResult(true)(p2s_2 != p2pk && p2pk != p2s_2) @@ -113,6 +117,18 @@ class ErgoAddressSpecification extends SigmaDslTesting assertResult(true)(from_tree == p2pk) } + property("fromProposition() should properly distinct all types of addresses from script AST") { + testFromProposition(scriptVersion = 0, + expectedP2S = "JryiCXrZf5VDetH1PM7rKDX3q4sLF34AdErWJFqG87Hf5ikTDf636b35Nr7goWMdRUKA3ZPxdeqFNbQzBjhnDR9SUMYwDX1tdV8ZuGgXwQPaRVcB9", + expectedP2SH = "qETVgcEctaXurNbFRgGUcZEGg4EKa8R4a5UNHY7", + expectedP2PK = "3WwXpssaZwcNzaGMv3AgxBdTPJQBt5gCmqBsg3DykQ39bYdhJBsN") + + testFromProposition(scriptVersion = 1, + expectedP2S = "2MzJLjzX6UNfJHSVvioB6seYZ99FpWHB4Ds1gekHPv5KtNmLJUecgRWwvcGEqbt8ZAokUxGvKMuNgMZFzkPPdTGiYzPQoSR55NT5isCidMywgp52LYV", + expectedP2SH = "qETVgcEctaXurNbFRgGUcZEGg4EKa8R4a5UNHY7", + expectedP2PK = "3WwXpssaZwcNzaGMv3AgxBdTPJQBt5gCmqBsg3DykQ39bYdhJBsN") + } + property("decode with wrong address") { assertExceptionThrown( ergoAddressEncoder.fromString( @@ -120,6 +136,12 @@ class ErgoAddressSpecification extends SigmaDslTesting .getOrThrow, t => t.getMessage.contains("Checksum check fails") ) + assertExceptionThrown( + ergoAddressEncoder.fromString( + "2MzJLjzX6UNfJHSVvioB6seYZ99FpWHB4Ds1gekHPv5KtNmLJUecgRWwvcGEqbt8ZAokUxGvKMuNgMZFzkPPdTGiYzPQoSR55NT5isCidMywgp52LYU") + .getOrThrow, + t => t.getMessage.contains("Checksum check fails") + ) { val invalid_p2sh = new Pay2SHAddress(Array[Byte](1, 2, 3)) @@ -149,7 +171,7 @@ class ErgoAddressSpecification extends SigmaDslTesting { val unparsedTree = new ErgoTree( - ErgoTree.ConstantSegregationHeader, + (ErgoTree.ConstantSegregationHeader | ergoTreeHeaderInTests).toByte, Array[Constant[SType]](), Left(UnparsedErgoTree(Array[Byte](), ValidationException("", ValidationRules.CheckTypeCode, Seq()))) ) @@ -161,7 +183,7 @@ class ErgoAddressSpecification extends SigmaDslTesting { val invalidTree = new ErgoTree( - ErgoTree.ConstantSegregationHeader, + (ErgoTree.ConstantSegregationHeader | ergoTreeHeaderInTests).toByte, Array[Constant[SType]](), Right(IntConstant(10).asSigmaProp) ) @@ -209,8 +231,8 @@ class ErgoAddressSpecification extends SigmaDslTesting testPay2SHAddress(Pay2SHAddress(prop), scriptBytes) - val tree = ErgoTree.fromProposition(prop) - testPay2SHAddress(Pay2SHAddress(tree), scriptBytes) + val tree = mkTestErgoTree(prop) + testPay2SHAddress(Pay2SHAddress(tree), scriptBytes) // NOTE: same scriptBytes regardless of ErgoTree version } property("negative cases: deserialized script + costing exceptions") { diff --git a/sigmastate/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala b/sigmastate/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala index 66b942b531..9c92c7b74f 100644 --- a/sigmastate/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala +++ b/sigmastate/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala @@ -6,7 +6,7 @@ import scorex.crypto.hash.Digest32 import scorex.util.{Random, ModifierId} import sigmastate.SCollection.SByteArray import sigmastate.{SSigmaProp, SPair, SInt, TrivialProp, SType} -import sigmastate.Values.{LongConstant, FalseLeaf, ConstantNode, SigmaPropConstant, ConstantPlaceholder, TrueSigmaProp, ByteArrayConstant, IntConstant, ErgoTree} +import sigmastate.Values._ import sigmastate.interpreter.{ProverResult, ContextExtension} import sigmastate.serialization.SigmaSerializer import sigmastate.eval._ diff --git a/sigmastate/src/test/scala/org/ergoplatform/ErgoScriptPredefSpec.scala b/sigmastate/src/test/scala/org/ergoplatform/ErgoScriptPredefSpec.scala index a3b099b478..1d9991520b 100644 --- a/sigmastate/src/test/scala/org/ergoplatform/ErgoScriptPredefSpec.scala +++ b/sigmastate/src/test/scala/org/ergoplatform/ErgoScriptPredefSpec.scala @@ -18,7 +18,6 @@ import sigmastate.lang.Terms.ValueOps import sigmastate.serialization.ValueSerializer import sigmastate.utxo.{CostTable, ExtractCreationInfo, ByIndex, SelectField} import scalan.util.BenchmarkUtil._ -import ErgoScriptPredef._ import sigmastate.utils.Helpers._ import scala.util.Try @@ -43,10 +42,11 @@ class ErgoScriptPredefSpec extends SigmaTestingCommons with CrossVersionProps { val prop = EQ(Height, ErgoScriptPredef.boxCreationHeight(ByIndex(Outputs, IntConstant(0)))).toSigmaProp val propInlined = EQ(Height, SelectField(ExtractCreationInfo(ByIndex(Outputs, IntConstant(0))), 1).asIntValue).toSigmaProp prop shouldBe propInlined - val inputBox = testBox(1, prop, nextHeight, Seq(), Map()) + val propTree = mkTestErgoTree(prop) + val inputBox = testBox(1, propTree, nextHeight, Seq(), Map()) val inputBoxes = IndexedSeq(inputBox) val inputs = inputBoxes.map(b => Input(b.id, emptyProverResult)) - val minerBox = new ErgoBoxCandidate(1, SigmaPropConstant(minerProp), nextHeight) + val minerBox = new ErgoBoxCandidate(1, mkTestErgoTree(SigmaPropConstant(minerProp)), nextHeight) val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(minerBox)) @@ -57,8 +57,8 @@ class ErgoScriptPredefSpec extends SigmaTestingCommons with CrossVersionProps { boxesToSpend = inputBoxes, spendingTransaction, self = inputBox, activatedVersionInTests) - val pr = prover.prove(emptyEnv + (ScriptNameProp -> "boxCreationHeight_prove"), prop, ctx, fakeMessage).get - verifier.verify(emptyEnv + (ScriptNameProp -> "boxCreationHeight_verify"), prop, ctx, pr, fakeMessage).get._1 shouldBe true + val pr = prover.prove(emptyEnv + (ScriptNameProp -> "boxCreationHeight_prove"), propTree, ctx, fakeMessage).get + verifier.verify(emptyEnv + (ScriptNameProp -> "boxCreationHeight_verify"), propTree, ctx, pr, fakeMessage).get._1 shouldBe true } property("collect coins from the founders' box") { @@ -106,7 +106,7 @@ class ErgoScriptPredefSpec extends SigmaTestingCommons with CrossVersionProps { val inputBoxes = IndexedSeq(testBox(emission.foundersCoinsTotal, prop, 0, Seq(), Map(R4 -> inputR4Val))) val inputs = inputBoxes.map(b => Input(b.id, emptyProverResult)) val newFoundersBox = testBox(remainingAmount, newProp, 0, Seq(), Map(R4 -> outputR4Val)) - val collectedBox = testBox(inputBoxes.head.value - remainingAmount, TrueProp, 0) + val collectedBox = testBox(inputBoxes.head.value - remainingAmount, TrueTree, 0) val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(newFoundersBox, collectedBox)) val ctx = ErgoLikeContextTesting( currentHeight = height, @@ -127,7 +127,7 @@ class ErgoScriptPredefSpec extends SigmaTestingCommons with CrossVersionProps { val verifier = new ErgoLikeTestInterpreter val inputBoxes = IndexedSeq(testBox(20, prop, 0, Seq(), Map())) val inputs = inputBoxes.map(b => Input(b.id, emptyProverResult)) - val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(testBox(inputBoxes.head.value, TrueProp, 0))) + val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(testBox(inputBoxes.head.value, TrueTree, 0))) val ctx = ErgoLikeContextTesting( currentHeight = inputBoxes.head.creationHeight + settings.minerRewardDelay, @@ -205,18 +205,19 @@ class ErgoScriptPredefSpec extends SigmaTestingCommons with CrossVersionProps { val verifier = new ErgoLikeTestInterpreter() val pubkey = prover.dlogSecrets.head.publicImage + val pubkeyTree = mkTestErgoTree(pubkey) val tokenId: Digest32 = Blake2b256("id") val wrongId: Digest32 = Blake2b256(tokenId) val wrongId2: Digest32 = Blake2b256(wrongId) val tokenAmount: Int = 50 - val prop = ErgoScriptPredef.tokenThresholdScript(tokenId, tokenAmount, TestnetNetworkPrefix) + val prop = mkTestErgoTree(ErgoScriptPredef.tokenThresholdScript(tokenId, tokenAmount, TestnetNetworkPrefix)) def check(inputBoxes: IndexedSeq[ErgoBox]): Try[Unit] = Try { val inputs = inputBoxes.map(b => Input(b.id, emptyProverResult)) val amount = inputBoxes.map(_.value).sum - val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(testBox(amount, pubkey.toSigmaProp, 0))) + val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(testBox(amount, pubkeyTree, 0))) val ctx = ErgoLikeContextTesting( currentHeight = 50, diff --git a/sigmastate/src/test/scala/org/ergoplatform/JsonSerializationSpec.scala b/sigmastate/src/test/scala/org/ergoplatform/JsonSerializationSpec.scala index 3648e6aa36..ee33061c68 100644 --- a/sigmastate/src/test/scala/org/ergoplatform/JsonSerializationSpec.scala +++ b/sigmastate/src/test/scala/org/ergoplatform/JsonSerializationSpec.scala @@ -14,7 +14,7 @@ import sigmastate.basics.DLogProtocol.ProveDlog import sigmastate.helpers.SigmaTestingCommons import sigmastate.interpreter.{ProverResult, ContextExtension, CryptoConstants} import sigmastate.serialization.SerializationSpecification -import sigmastate.utils.Helpers._ +import sigmastate.utils.Helpers._ // required for Scala 2.11 import special.collection.Coll import special.sigma.{PreHeader, Header} diff --git a/sigmastate/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala b/sigmastate/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala index cccf35a72a..155ea7b447 100644 --- a/sigmastate/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala +++ b/sigmastate/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala @@ -26,7 +26,11 @@ case class TestContractSpec(testSuite: SigmaTestingCommons)(implicit val IR: IRC case class TestPropositionSpec(name: String, dslSpec: Proposition, scriptSpec: ErgoScript) extends PropositionSpec { lazy val ergoTree: ErgoTree = { val value = testSuite.compile(scriptSpec.env, scriptSpec.code) - val tree: ErgoTree = value.asSigmaProp + val headerFlags = scriptSpec.scriptVersion match { + case Some(version) => ErgoTree.headerWithVersion(version) + case None => testSuite.ergoTreeHeaderInTests + } + val tree: ErgoTree = ErgoTree.fromProposition(headerFlags, value.asSigmaProp) tree } } diff --git a/sigmastate/src/test/scala/sigmastate/CrossVersionProps.scala b/sigmastate/src/test/scala/sigmastate/CrossVersionProps.scala index ac3bd3c101..2dd25fb151 100644 --- a/sigmastate/src/test/scala/sigmastate/CrossVersionProps.scala +++ b/sigmastate/src/test/scala/sigmastate/CrossVersionProps.scala @@ -6,6 +6,8 @@ import spire.syntax.all.cfor trait CrossVersionProps extends PropSpecLike with TestsBase { + val printVersions: Boolean = false + override protected def property(testName: String, testTags: Tag*) (testFun: => Any) (implicit pos: Position): Unit = { @@ -20,10 +22,15 @@ trait CrossVersionProps extends PropSpecLike with TestsBase { _ + 1) { j => val treeVersion = ergoTreeVersions(j) _currErgoTreeVersion.withValue(treeVersion) { + def msg = s"""property("$testName")(ActivatedVersion = $activatedVersionInTests; ErgoTree version = $ergoTreeVersionInTests)""" + if (printVersions) println(msg) try testFun catch { case t: Throwable => - println(s"ActivatedVersion = $activatedVersion; ErgoTree version = $treeVersion") + if (!printVersions) { + // wasn't printed, print it now + println(msg) + } throw t } } diff --git a/sigmastate/src/test/scala/sigmastate/ErgoTreeSpecification.scala b/sigmastate/src/test/scala/sigmastate/ErgoTreeSpecification.scala index 892b88ab79..0d22c7400c 100644 --- a/sigmastate/src/test/scala/sigmastate/ErgoTreeSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/ErgoTreeSpecification.scala @@ -199,7 +199,7 @@ class ErgoTreeSpecification extends SigmaTestingData { (SLong.typeId, Seq.empty[MInfo], false), { // SNumericType.typeId is erroneously shadowed by SGlobal.typeId - // this should be preserved in 3.x and fixed in 4.0 + // this should be preserved in v3.x and fixed in v4.0 (SNumericType.typeId, Seq( MInfo(methodId = 1, SGlobal.groupGeneratorMethod), MInfo(2, SGlobal.xorMethod) @@ -383,4 +383,20 @@ class ErgoTreeSpecification extends SigmaTestingData { } } + + 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" + ) + } + } + } } diff --git a/sigmastate/src/test/scala/sigmastate/FailingToProveSpec.scala b/sigmastate/src/test/scala/sigmastate/FailingToProveSpec.scala index 53a94af830..6153b7f7a7 100644 --- a/sigmastate/src/test/scala/sigmastate/FailingToProveSpec.scala +++ b/sigmastate/src/test/scala/sigmastate/FailingToProveSpec.scala @@ -5,7 +5,6 @@ import sigmastate.helpers.TestingHelpers._ import sigmastate.lang.Terms._ import org.scalatest.TryValues._ import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv} -import org.ergoplatform.ErgoScriptPredef._ class FailingToProveSpec extends SigmaTestingCommons with CrossVersionProps { @@ -21,7 +20,7 @@ class FailingToProveSpec extends SigmaTestingCommons val verifier = new ErgoLikeTestInterpreter() val env = Map.empty[String, Any] - val compiledScript = compile(env, + val tree = mkTestErgoTree(compile(env, s""" | { | val withdrawCondition1 = @@ -31,11 +30,11 @@ class FailingToProveSpec extends SigmaTestingCommons | | withdrawCondition1 || withdrawCondition2 | } - """.stripMargin).asBoolValue.toSigmaProp + """.stripMargin).asBoolValue.toSigmaProp) - val selfBox = testBox(200L, compiledScript, 0) - val o1 = testBox(101L, TrueProp, 5001) - val o2 = testBox(99L, TrueProp, 5001) + val selfBox = testBox(200L, tree, 0) + val o1 = testBox(101L, TrueTree, 5001) + val o2 = testBox(99L, TrueTree, 5001) val tx = createTransaction(IndexedSeq(o1, o2)) val ctx = ErgoLikeContextTesting( currentHeight = 5001, @@ -45,8 +44,8 @@ class FailingToProveSpec extends SigmaTestingCommons self = selfBox, minerPubkey = ErgoLikeContextTesting.dummyPubkey, activatedVersion = activatedVersionInTests) - val proof = interpreter.prove(emptyEnv + (ScriptNameProp -> "prove"), compiledScript, ctx, fakeMessage).success.value.proof - verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), compiledScript, ctx, proof, fakeMessage) should be a 'success + val proof = interpreter.prove(emptyEnv + (ScriptNameProp -> "prove"), tree, ctx, fakeMessage).success.value.proof + verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), tree, ctx, proof, fakeMessage) should be a 'success } property("successfully evaluate proof 2") { @@ -54,7 +53,7 @@ class FailingToProveSpec extends SigmaTestingCommons val verifier = new ErgoLikeTestInterpreter() val env = Map.empty[String, Any] - val compiledScript = compile(env, + val tree = mkTestErgoTree(compile(env, s""" | { | @@ -65,12 +64,12 @@ class FailingToProveSpec extends SigmaTestingCommons | | withdrawCondition1 || withdrawCondition2 | } - """.stripMargin).asBoolValue.toSigmaProp + """.stripMargin).asBoolValue.toSigmaProp) - val selfBox = testBox(200L, compiledScript, 0) - val o1 = testBox(102L, TrueProp, 5001) - val o2 = testBox(98L, TrueProp, 5001) - val o3 = testBox(100L, TrueProp, 5001) + val selfBox = testBox(200L, tree, 0) + val o1 = testBox(102L, TrueTree, 5001) + val o2 = testBox(98L, TrueTree, 5001) + val o3 = testBox(100L, TrueTree, 5001) val tx = createTransaction(IndexedSeq(o1, o2, o3)) val ctx = ErgoLikeContextTesting( currentHeight = 5001, @@ -80,8 +79,8 @@ class FailingToProveSpec extends SigmaTestingCommons self = selfBox, minerPubkey = ErgoLikeContextTesting.dummyPubkey, activatedVersion = activatedVersionInTests) - val proof = interpreter.prove(emptyEnv + (ScriptNameProp -> "prove"), compiledScript, ctx, fakeMessage).success.value.proof - verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), compiledScript, ctx, proof, fakeMessage) should be a 'success + val proof = interpreter.prove(emptyEnv + (ScriptNameProp -> "prove"), tree, ctx, fakeMessage).success.value.proof + verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), tree, ctx, proof, fakeMessage) should be a 'success } } diff --git a/sigmastate/src/test/scala/sigmastate/ScriptVersionSwitchSpecification.scala b/sigmastate/src/test/scala/sigmastate/ScriptVersionSwitchSpecification.scala index f8dd8a3a8e..ebe56e2fb4 100644 --- a/sigmastate/src/test/scala/sigmastate/ScriptVersionSwitchSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/ScriptVersionSwitchSpecification.scala @@ -14,7 +14,6 @@ import sigmastate.utxo._ import sigmastate.utils.Helpers._ import special.collection._ import special.sigma.{SigmaDslTesting, Box} -import sigmastate.helpers.TestingHelpers._ import scala.util.Success diff --git a/sigmastate/src/test/scala/sigmastate/SoftForkabilitySpecification.scala b/sigmastate/src/test/scala/sigmastate/SoftForkabilitySpecification.scala index 9af961b0db..f830fbb2cd 100644 --- a/sigmastate/src/test/scala/sigmastate/SoftForkabilitySpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/SoftForkabilitySpecification.scala @@ -19,8 +19,7 @@ import sigmastate.utxo.{DeserializeContext, SelectField} import special.sigma.SigmaTestingData import sigmastate.utils.Helpers._ -class SoftForkabilitySpecification extends SigmaTestingData - with CrossVersionProps { +class SoftForkabilitySpecification extends SigmaTestingData { implicit lazy val IR = new TestingIRContext lazy val prover = new ErgoLikeTestProvingInterpreter() @@ -33,14 +32,20 @@ class SoftForkabilitySpecification extends SigmaTestingData | HEIGHT > deadline && OUTPUTS.size == 1 |}""".stripMargin).asBoolValue - // cast Boolean typed prop to SigmaProp (which is invalid) - lazy val invalidPropV1 = ErgoTree.fromProposition(booleanPropV1.asSigmaProp) + // cast Boolean typed prop to SigmaProp (which is invalid) // ErgoTree v0 + lazy val invalidPropV1: ErgoTree = + ErgoTree.fromProposition( + ErgoTree.headerWithVersion(0), + booleanPropV1.asSigmaProp) lazy val invalidTxV1 = createTransaction(createBox(boxAmt, invalidPropV1, 1)) lazy val invalidTxV1bytes = invalidTxV1.messageToSign lazy val propV1 = booleanPropV1.toSigmaProp - lazy val txV1 = createTransaction(createBox(boxAmt, propV1, 1)) + lazy val txV1 = createTransaction( + createBox(boxAmt, + ErgoTree.fromProposition(ErgoTree.headerWithVersion(0), propV1), // ErgoTree v0 + 1)) lazy val txV1bytes = txV1.messageToSign val blockHeight = 110 @@ -115,7 +120,11 @@ class SoftForkabilitySpecification extends SigmaTestingData } lazy val booleanPropV2 = GT(Height2, IntConstant(deadline)) - lazy val invalidPropV2 = ErgoTree.fromProposition(booleanPropV2.asSigmaProp) + + lazy val invalidPropV2: ErgoTree = ErgoTree.fromProposition( + headerFlags = ErgoTree.headerWithVersion(0), // ErgoTree v0 + prop = booleanPropV2.asSigmaProp) + lazy val invalidTxV2 = createTransaction(createBox(boxAmt, invalidPropV2, 1)) @@ -144,9 +153,12 @@ class SoftForkabilitySpecification extends SigmaTestingData // prepare bytes using default serialization and then replacing version in the header val v2tree_withoutSize_bytes = runOnV2Node { - val tree = ErgoTree.fromProposition(propV2) + val tree = ErgoTree.fromProposition( + ErgoTree.headerWithVersion(0), propV2) // ErgoTree v0 val bytes = tree.bytes - bytes(0) = 1.toByte // set version to v2, we cannot do this using ErgoTree constructor + // set version to v2 while not setting the size bit, + // we cannot do this using ErgoTree constructor (due to require() check) + bytes(0) = 1.toByte bytes } @@ -246,8 +258,11 @@ class SoftForkabilitySpecification extends SigmaTestingData // v1 main script which deserializes from context v2 script val mainProp = BinAnd(GT(Height, IntConstant(deadline)), DeserializeContext(1, SBoolean)).toSigmaProp + val mainTree = ErgoTree.fromProposition( + headerFlags = ErgoTree.headerWithVersion(0), // ErgoTree v0 + prop = mainProp) - val tx = createTransaction(createBox(boxAmt, ErgoTree.fromProposition(mainProp), 1)) + val tx = createTransaction(createBox(boxAmt, mainTree, 1)) val bindings = Map(1.toByte -> ByteArrayConstant(Colls.fromArray(propBytes))) val proof = new ProverResult(Array.emptyByteArray, ContextExtension(bindings)) diff --git a/sigmastate/src/test/scala/sigmastate/TestingInterpreterSpecification.scala b/sigmastate/src/test/scala/sigmastate/TestingInterpreterSpecification.scala index 0c58b52a5a..e29d97838e 100644 --- a/sigmastate/src/test/scala/sigmastate/TestingInterpreterSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/TestingInterpreterSpecification.scala @@ -12,7 +12,6 @@ import scorex.util.encode.Base58 import sigmastate.helpers.{ErgoLikeContextTesting, ErgoLikeTestInterpreter, ErgoLikeTestProvingInterpreter, SigmaTestingCommons} import sigmastate.helpers.TestingHelpers._ import sigmastate.serialization.ValueSerializer -import TrivialProp._ import sigmastate.utils.Helpers._ import scala.util.Random @@ -45,17 +44,17 @@ class TestingInterpreterSpecification extends SigmaTestingCommons { val res = prover.reduceToCrypto(ctx, AND(GE(Height, IntConstant(h + 1)), dk1)).get._1 - res should matchPattern { case FalseProp => } + res should matchPattern { case TrivialProp.FalseProp => } } { val res = prover.reduceToCrypto(ctx, OR(GE(Height, IntConstant(h - 1)), dk1)).get._1 - res should matchPattern { case TrueProp => } + res should matchPattern { case TrivialProp.TrueProp => } } { val res = prover.reduceToCrypto(ctx, OR(GE(Height, IntConstant(h)), dk1)).get._1 - res should matchPattern { case TrueProp => } + res should matchPattern { case TrivialProp.TrueProp => } } { val res = prover.reduceToCrypto(ctx, OR(GE(Height, IntConstant(h + 1)), dk1)).get._1 @@ -89,7 +88,7 @@ class TestingInterpreterSpecification extends SigmaTestingCommons prover.reduceToCrypto(ctx, OR( AND(LE(Height, IntConstant(h - 1)), AND(dk1, dk2)), AND(GT(Height, IntConstant(h + 1)), dk1) - )).get._1 shouldBe FalseProp + )).get._1 shouldBe TrivialProp.FalseProp prover.reduceToCrypto(ctx, OR( @@ -99,7 +98,7 @@ class TestingInterpreterSpecification extends SigmaTestingCommons ), AND(GT(Height, IntConstant(h - 1)), LE(Height, IntConstant(h + 1))) ) - ).get._1 shouldBe TrueProp + ).get._1 shouldBe TrivialProp.TrueProp } } @@ -117,10 +116,10 @@ class TestingInterpreterSpecification extends SigmaTestingCommons "dk2" -> dk2, "bytes1" -> Array[Byte](1, 2, 3), "bytes2" -> Array[Byte](4, 5, 6), - "box1" -> testBox(10, ErgoScriptPredef.TrueProp, 0, Seq(), Map( + "box1" -> testBox(10, TrueTree, 0, Seq(), Map( reg1 -> IntArrayConstant(Array[Int](1, 2, 3)), reg2 -> BoolArrayConstant(Array[Boolean](true, false, true))))) - val prop = compile(env, code).asBoolValue.toSigmaProp + val prop = mkTestErgoTree(compile(env, code).asBoolValue.toSigmaProp) println(code) println(prop) val challenge = Array.fill(32)(Random.nextInt(100).toByte) @@ -253,10 +252,10 @@ class TestingInterpreterSpecification extends SigmaTestingCommons val env1 = testingContext(99) val env2 = testingContext(101) - val prop = OR( + val prop = mkTestErgoTree(OR( AND(LE(Height, IntConstant(100)), AND(dk1, dk2)), AND(GT(Height, IntConstant(100)), dk1) - ).toSigmaProp + ).toSigmaProp) val challenge = Array.fill(32)(Random.nextInt(100).toByte) @@ -268,7 +267,7 @@ class TestingInterpreterSpecification extends SigmaTestingCommons } property("Evaluation - no real proving - true case") { - val prop1 = ErgoScriptPredef.TrueProp + val prop1 = TrueTree val challenge = Array.fill(32)(Random.nextInt(100).toByte) val proof = NoProof @@ -276,18 +275,18 @@ class TestingInterpreterSpecification extends SigmaTestingCommons verifier.verify(prop1, env, proof, challenge).map(_._1).getOrThrow shouldBe true - val prop2 = OR(TrueLeaf, FalseLeaf).toSigmaProp + val prop2 = mkTestErgoTree(OR(TrueLeaf, FalseLeaf).toSigmaProp) verifier.verify(prop2, env, proof, challenge).map(_._1).getOrThrow shouldBe true - val prop3 = AND(TrueLeaf, TrueLeaf).toSigmaProp + val prop3 = mkTestErgoTree(AND(TrueLeaf, TrueLeaf).toSigmaProp) verifier.verify(prop3, env, proof, challenge).map(_._1).getOrThrow shouldBe true - val prop4 = GT(Height, IntConstant(90)).toSigmaProp + val prop4 = mkTestErgoTree(GT(Height, IntConstant(90)).toSigmaProp) verifier.verify(prop4, env, proof, challenge).map(_._1).getOrThrow shouldBe true } property("Evaluation - no real proving - false case") { - val prop1 = ErgoScriptPredef.FalseProp + val prop1 = FalseTree val challenge = Array.fill(32)(Random.nextInt(100).toByte) val proof = NoProof @@ -295,13 +294,13 @@ class TestingInterpreterSpecification extends SigmaTestingCommons verifier.verify(prop1, env, proof, challenge).map(_._1).getOrThrow shouldBe false - val prop2 = OR(FalseLeaf, FalseLeaf).toSigmaProp + val prop2 = mkTestErgoTree(OR(FalseLeaf, FalseLeaf).toSigmaProp) verifier.verify(prop2, env, proof, challenge).map(_._1).getOrThrow shouldBe false - val prop3 = AND(FalseLeaf, TrueLeaf).toSigmaProp + val prop3 = mkTestErgoTree(AND(FalseLeaf, TrueLeaf).toSigmaProp) verifier.verify(prop3, env, proof, challenge).map(_._1).getOrThrow shouldBe false - val prop4 = GT(Height, IntConstant(100)).toSigmaProp + val prop4 = mkTestErgoTree(GT(Height, IntConstant(100)).toSigmaProp) verifier.verify(prop4, env, proof, challenge).map(_._1).getOrThrow shouldBe false } @@ -309,7 +308,9 @@ class TestingInterpreterSpecification extends SigmaTestingCommons val bytes = "hello world".getBytes val hash = Blake2b256(bytes) - val prop1 = EQ(CalcBlake2b256(ByteArrayConstant(bytes)), ByteArrayConstant(hash)).toSigmaProp + val prop1 = mkTestErgoTree(EQ( + CalcBlake2b256(ByteArrayConstant(bytes)), + ByteArrayConstant(hash)).toSigmaProp) val challenge = Array.fill(32)(Random.nextInt(100).toByte) val proof = NoProof @@ -317,11 +318,15 @@ class TestingInterpreterSpecification extends SigmaTestingCommons verifier.verify(prop1, env, proof, challenge).map(_._1).getOrElse(false) shouldBe true - val prop2 = NEQ(CalcBlake2b256(ByteArrayConstant(bytes)), ByteArrayConstant(hash)).toSigmaProp + val prop2 = mkTestErgoTree(NEQ( + CalcBlake2b256(ByteArrayConstant(bytes)), + ByteArrayConstant(hash)).toSigmaProp) verifier.verify(prop2, env, proof, challenge).map(_._1).getOrElse(false) shouldBe false - val prop3 = EQ(CalcBlake2b256(ByteArrayConstant(bytes)), ByteArrayConstant(bytes)).toSigmaProp + val prop3 = mkTestErgoTree(EQ( + CalcBlake2b256(ByteArrayConstant(bytes)), + ByteArrayConstant(bytes)).toSigmaProp) verifier.verify(prop3, env, proof, challenge).map(_._1).getOrElse(false) shouldBe false } diff --git a/sigmastate/src/test/scala/sigmastate/TestsBase.scala b/sigmastate/src/test/scala/sigmastate/TestsBase.scala index 5450799c02..dfb1619cac 100644 --- a/sigmastate/src/test/scala/sigmastate/TestsBase.scala +++ b/sigmastate/src/test/scala/sigmastate/TestsBase.scala @@ -1,10 +1,19 @@ package sigmastate +import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix +import org.ergoplatform.ErgoScriptPredef +import org.scalatest.Matchers +import sigmastate.Values.{SValue, Value, SigmaPropValue, ErgoTree, SigmaBoolean} +import sigmastate.eval.IRContext import sigmastate.interpreter.Interpreter +import sigmastate.interpreter.Interpreter.ScriptEnv +import sigmastate.lang.{SigmaCompiler, TransformingSigmaBuilder} +import sigmastate.lang.Terms.ValueOps +import sigmastate.serialization.ValueSerializer import scala.util.DynamicVariable -trait TestsBase { +trait TestsBase extends Matchers { val activatedVersions: Seq[Byte] = Array[Byte](0, 1) @@ -15,6 +24,54 @@ trait TestsBase { (0 to Interpreter.MaxSupportedScriptVersion).map(_.toByte).toArray[Byte] private[sigmastate] val _currErgoTreeVersion = new DynamicVariable[Byte](0) + + /** Current ErgoTree version assigned dynamically using [[CrossVersionProps]]. */ def ergoTreeVersionInTests: Byte = _currErgoTreeVersion.value + /** Current ErgoTree header flags assigned dynamically using [[CrossVersionProps]] and + * ergoTreeVersionInTests. + */ + def ergoTreeHeaderInTests: Byte = ErgoTree.headerWithVersion(ergoTreeVersionInTests) + + /** Obtains [[ErgoTree]] which corresponds to True proposition using current + * ergoTreeHeaderInTests. */ + def TrueTree: ErgoTree = ErgoScriptPredef.TrueProp(ergoTreeHeaderInTests) + + /** Obtains [[ErgoTree]] which corresponds to False proposition using current + * ergoTreeHeaderInTests. */ + def FalseTree: ErgoTree = ErgoScriptPredef.FalseProp(ergoTreeHeaderInTests) + + /** Transform proposition into [[ErgoTree]] using current ergoTreeHeaderInTests. */ + def mkTestErgoTree(prop: SigmaPropValue): ErgoTree = + ErgoTree.fromProposition(ergoTreeHeaderInTests, prop) + + /** Transform sigma proposition into [[ErgoTree]] using current ergoTreeHeaderInTests. */ + def mkTestErgoTree(prop: SigmaBoolean): ErgoTree = + ErgoTree.fromSigmaBoolean(ergoTreeHeaderInTests, prop) + + lazy val compiler = SigmaCompiler(TestnetNetworkPrefix, TransformingSigmaBuilder) + + def checkSerializationRoundTrip(v: SValue): Unit = { + val compiledTreeBytes = ValueSerializer.serialize(v) + withClue(s"(De)Serialization roundtrip failed for the tree:") { + ValueSerializer.deserialize(compiledTreeBytes) shouldEqual v + } + } + + def compileWithoutCosting(env: ScriptEnv, code: String): Value[SType] = + compiler.compileWithoutCosting(env, code) + + def compile(env: ScriptEnv, code: String)(implicit IR: IRContext): Value[SType] = { + val tree = compiler.compile(env, code) + checkSerializationRoundTrip(tree) + tree + } + + def compileAndCheck(env: ScriptEnv, code: String, expected: SValue) + (implicit IR: IRContext): (ErgoTree, SigmaPropValue) = { + val prop = compile(env, code).asSigmaProp + prop shouldBe expected + val tree = mkTestErgoTree(prop) + (tree, prop) + } } diff --git a/sigmastate/src/test/scala/sigmastate/TypesSpecification.scala b/sigmastate/src/test/scala/sigmastate/TypesSpecification.scala index af72d49781..afc3a75eb4 100644 --- a/sigmastate/src/test/scala/sigmastate/TypesSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/TypesSpecification.scala @@ -3,7 +3,6 @@ package sigmastate import java.math.BigInteger import org.ergoplatform.ErgoBox -import org.ergoplatform.ErgoScriptPredef.TrueProp import org.ergoplatform.settings.ErgoAlgos import scalan.RType import scorex.crypto.hash.Digest32 @@ -55,7 +54,7 @@ class TypesSpecification extends SigmaTestingData { val (tree, _) = createAvlTreeAndProver() - val box = SigmaDsl.Box(testBox(20, TrueProp, 0, + val box = SigmaDsl.Box(testBox(20, TrueTree, 0, Seq( (Digest32 @@ (ErgoAlgos.decodeUnsafe("6e789ab7b2fffff12280a6cd01557f6fb22b7f80ff7aff8e1f7f15973d7f0001")), 10000000L) diff --git a/sigmastate/src/test/scala/sigmastate/crypto/SigningSpecification.scala b/sigmastate/src/test/scala/sigmastate/crypto/SigningSpecification.scala index f9fa88465d..5a81fcdfa4 100644 --- a/sigmastate/src/test/scala/sigmastate/crypto/SigningSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/crypto/SigningSpecification.scala @@ -1,13 +1,15 @@ package sigmastate.crypto +import org.scalacheck.Gen import scorex.util.encode.Base16 -import sigmastate.AtLeast +import sigmastate.{AtLeast, CAND} +import sigmastate.Values.SigmaBoolean import sigmastate.basics.DLogProtocol.DLogProverInput import sigmastate.helpers.{ErgoLikeTestInterpreter, ErgoLikeTestProvingInterpreter, SigmaTestingCommons} -import sigmastate.interpreter.{ContextExtension, ProverResult} +import sigmastate.interpreter.{ContextExtension, HintsBag, ProverResult} class SigningSpecification extends SigmaTestingCommons { - implicit lazy val IR = new TestingIRContext + implicit lazy val IR: TestingIRContext = new TestingIRContext property("simple signature test vector") { @@ -39,12 +41,54 @@ class SigningSpecification extends SigmaTestingCommons { val prop = AtLeast(2, sk1.publicImage, sk2.publicImage, sk3.publicImage) val verifier = new ErgoLikeTestInterpreter val proverResult = ProverResult(signature, ContextExtension.empty) - verifier.verify(prop, fakeContext, proverResult, msg).get._1 shouldBe true + verifier.verify(mkTestErgoTree(prop), fakeContext, proverResult, msg).get._1 shouldBe true // print one more random vector for debug purposes printThresholdSignature(msg) } + property("signMessage / verifyMessage roundtrip - simple dlog") { + forAll(Gen.alphaNumStr){str => + val msg = str.getBytes("UTF-8") + val pi = new ErgoLikeTestProvingInterpreter() + val sigmaTree: SigmaBoolean = pi.publicKeys.head + val sig = pi.signMessage(sigmaTree, msg, HintsBag.empty).get + pi.verifySignature(sigmaTree, msg, sig) shouldBe true + pi.verifySignature(sigmaTree, (str + "1").getBytes("UTF-8"), sig) shouldBe false + pi.verifySignature(sigmaTree, msg, sig :+ (1: Byte)) shouldBe true //possible to append bytes + val wrongTree = pi.publicKeys(1) + pi.verifySignature(wrongTree, msg, sig) shouldBe false + } + } + + property("signMessage / verifyMessage roundtrip - complex key") { + forAll(Gen.alphaNumStr){str => + val msg = str.getBytes("UTF-8") + val pi = new ErgoLikeTestProvingInterpreter() + val sigmaTree: SigmaBoolean = CAND(Seq(pi.dlogSecrets.head.publicImage, pi.dhSecrets.head.publicImage)) + val sig = pi.signMessage(sigmaTree, msg, HintsBag.empty).get + pi.verifySignature(sigmaTree, msg, sig) shouldBe true + pi.verifySignature(sigmaTree, (str + "1").getBytes("UTF-8"), sig) shouldBe false + pi.verifySignature(sigmaTree, msg, sig :+ (1: Byte)) shouldBe true //possible to append bytes + val wrongTree = CAND(Seq(pi.dlogSecrets.head.publicImage, pi.dhSecrets(1).publicImage)) + pi.verifySignature(wrongTree, msg, sig) shouldBe false + } + } + + property("verifySignature w. simple signature test vector") { + + val msg = Base16.decode("1dc01772ee0171f5f614c673e3c7fa1107a8cf727bdf5a6dadb379e93c0d1d00").get + val sk = DLogProverInput(BigInt("109749205800194830127901595352600384558037183218698112947062497909408298157746").bigInteger) + val signature = Base16.decode("bcb866ba434d5c77869ddcbc3f09ddd62dd2d2539bf99076674d1ae0c32338ea95581fdc18a3b66789904938ac641eba1a66d234070207a2").get + + // check that signature is correct + val verifier = new ErgoLikeTestInterpreter + verifier.verifySignature(sk.publicImage, msg, signature) shouldBe true + + // print one more random vector for debug purposes + printSimpleSignature(msg: Array[Byte]) + } + private def printSimpleSignature(msg: Array[Byte]) { val proverA = new ErgoLikeTestProvingInterpreter @@ -71,7 +115,7 @@ class SigningSpecification extends SigmaTestingCommons { val prop = AtLeast(2, sk1.publicImage, sk2.publicImage, sk3.publicImage) - val prove = proverA.prove(prop, fakeContext, msg).get + val prove = proverA.prove(mkTestErgoTree(prop), fakeContext, msg).get println(s"Message: ${Base16.encode(msg)}") println(s"sk1: ${sk1.w}") diff --git a/sigmastate/src/test/scala/sigmastate/eval/BasicOpsTests.scala b/sigmastate/src/test/scala/sigmastate/eval/BasicOpsTests.scala index 718f611f4f..aa151d5ea9 100644 --- a/sigmastate/src/test/scala/sigmastate/eval/BasicOpsTests.scala +++ b/sigmastate/src/test/scala/sigmastate/eval/BasicOpsTests.scala @@ -3,8 +3,8 @@ package sigmastate.eval import java.math.BigInteger import org.bouncycastle.crypto.ec.CustomNamedCurves -import org.scalatest.{FunSuite, Matchers} -import special.sigma.{Box, Context, ContractsTestkit, MockSigma, SigmaContract, SigmaDslBuilder, SigmaProp, TestSigmaDslBuilder} +import org.scalatest.{Matchers, FunSuite} +import special.sigma.{SigmaDslBuilder, ContractsTestkit, MockSigma, SigmaProp} import scala.language.implicitConversions diff --git a/sigmastate/src/test/scala/sigmastate/eval/CompilerItTest.scala b/sigmastate/src/test/scala/sigmastate/eval/CompilerItTest.scala index ddc7440f59..2acfa19ac4 100644 --- a/sigmastate/src/test/scala/sigmastate/eval/CompilerItTest.scala +++ b/sigmastate/src/test/scala/sigmastate/eval/CompilerItTest.scala @@ -1,41 +1,26 @@ package sigmastate.eval -import java.math.BigInteger - -import org.bouncycastle.math.ec.ECPoint import org.ergoplatform._ -import sigmastate.SCollection.SByteArray import sigmastate._ -import sigmastate.Values.{BigIntArrayConstant, BigIntConstant, ByteArrayConstant, FalseLeaf, GroupElementConstant, IntConstant, LongConstant, SigmaBoolean, SigmaPropConstant, TrueLeaf, ValUse} +import sigmastate.Values._ import sigmastate.helpers.ContextEnrichingTestProvingInterpreter -import sigmastate.interpreter.{ContextExtension, CryptoConstants} -import sigmastate.lang.DefaultSigmaBuilder.mkTaggedVariable import sigmastate.lang.LangTests import sigmastate.utxo._ -import special.collection.{Coll => VColl} -import special.sigma.{TestValue => VTestValue} import scalan.BaseCtxTests import scalan.util.BenchmarkUtil._ -import sigmastate.basics.DLogProtocol import special.sigma._ class CompilerItTest extends BaseCtxTests with LangTests with ExampleContracts with ErgoScriptTestkit { import IR._ import builder._ - import WOption._ import CollBuilder._ - import SigmaDslBuilder._ import Context._ import Coll._ import SigmaProp._ - import CostedColl._ - import CCostedColl._ import BigInt._ - import GroupElement._ import sigmastate.serialization.OpCodes._ import Liftables._ - import SType.AnyOps def intConstCase = { @@ -121,7 +106,6 @@ class CompilerItTest extends BaseCtxTests } def bigIntArray_Map_Case = { - import SCollection._ val res = bigIntegerArr1.map(n => n.add(n1)).toArray Case(env, "bigIntArray_Map", "bigIntArr1.map { (i: BigInt) => i + n1 }", ergoCtx, @@ -152,7 +136,6 @@ class CompilerItTest extends BaseCtxTests } def bigIntArray_Slice_Case = { - import SCollection._ Case(env, "bigIntArray_Slice_Case", "bigIntArr1.slice(0,1)", ergoCtx, calc = null, @@ -180,7 +163,6 @@ class CompilerItTest extends BaseCtxTests // } def register_BigIntArr_Case = { - import SCollection._ Case(env, "register_BigIntArr_Case", "SELF.R4[Coll[BigInt]].get", ergoCtx, calc = null, @@ -204,7 +186,6 @@ class CompilerItTest extends BaseCtxTests } def register_BigIntArr_Map_Case = { - import SCollection._ Case(env, "register_BigIntArr_Map_Case", "SELF.R4[Coll[BigInt]].get.map { (i: BigInt) => i + n1 }", ergoCtx, calc = null, @@ -218,7 +199,6 @@ class CompilerItTest extends BaseCtxTests } def register_BigIntArr_Slice_Case = { - import SCollection._ Case(env, "register_BinIntArr_Slice_Case", "SELF.R4[Coll[BigInt]].get.slice(0,1)", ergoCtx, calc = null, @@ -232,7 +212,6 @@ class CompilerItTest extends BaseCtxTests } def crowdFunding_Case = { - import SCollection._ import SigmaDslBuilder._ import Box._ import Values._ diff --git a/sigmastate/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala b/sigmastate/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala index 279b517c9b..ac35f6844c 100644 --- a/sigmastate/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala +++ b/sigmastate/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala @@ -31,7 +31,7 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests import Size._ import BigInt._ - lazy val compiler = new SigmaCompiler(TestnetNetworkPrefix, IR.builder) + override lazy val compiler = new SigmaCompiler(TestnetNetworkPrefix, IR.builder) def newErgoContext(height: Int, boxToSpend: ErgoBox, extension: Map[Byte, EvaluatedValue[SType]] = Map()): ErgoLikeContext = { val tx1 = new ErgoLikeTransaction(IndexedSeq(), IndexedSeq(), IndexedSeq(boxToSpend)) @@ -64,7 +64,7 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests lazy val backerPubKey = backerProver.dlogSecrets.head.publicImage lazy val projectPubKey = projectProver.dlogSecrets.head.publicImage - val boxToSpend = testBox(10, ErgoScriptPredef.TrueProp, 0, + val boxToSpend = testBox(10, TrueTree, 0, additionalRegisters = Map(ErgoBox.R4 -> BigIntArrayConstant(bigIntegerArr1))) lazy val tx1Output1 = testBox(minToRaise, projectPubKey, 0) lazy val tx1Output2 = testBox(1, projectPubKey, 0) diff --git a/sigmastate/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala b/sigmastate/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala index 1d35ed2336..357c6113e5 100644 --- a/sigmastate/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala +++ b/sigmastate/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala @@ -1,17 +1,13 @@ package sigmastate.eval -import org.bouncycastle.math.ec.ECPoint -import org.ergoplatform.{Height, Inputs, Outputs, Self} +import org.ergoplatform.{Height, Outputs, Self, Inputs} import sigmastate._ -import sigmastate.lang.Terms.ValueOps -import sigmastate.Values.{BlockValue, FalseLeaf, FuncValue, GroupElementConstant, IntConstant, LongConstant, SigmaPropConstant, TaggedVariable, TrueLeaf, ValDef, ValUse} +import sigmastate.Values.{LongConstant, FuncValue, BlockValue, SigmaPropConstant, IntConstant, ValDef, ValUse} import sigmastate.helpers.ContextEnrichingTestProvingInterpreter -import sigmastate.serialization.OpCodes._ import sigmastate.interpreter.Interpreter._ import scalan.BaseCtxTests -import sigmastate.basics.DLogProtocol import sigmastate.lang.LangTests -import sigmastate.lang.Terms.Apply +import sigmastate.lang.Terms.{ValueOps, Apply} import sigmastate.utxo._ class ErgoTreeBuildingTest extends BaseCtxTests diff --git a/sigmastate/src/test/scala/sigmastate/helpers/ContextEnrichingTestProvingInterpreter.scala b/sigmastate/src/test/scala/sigmastate/helpers/ContextEnrichingTestProvingInterpreter.scala index e1c613236d..594e09dd3d 100644 --- a/sigmastate/src/test/scala/sigmastate/helpers/ContextEnrichingTestProvingInterpreter.scala +++ b/sigmastate/src/test/scala/sigmastate/helpers/ContextEnrichingTestProvingInterpreter.scala @@ -6,7 +6,6 @@ import sigmastate.Values._ import sigmastate.basics.DLogProtocol.DLogProverInput import sigmastate.basics.DiffieHellmanTupleProverInput import sigmastate.eval.IRContext -import sigmastate.utxo.CostTable class ContextEnrichingTestProvingInterpreter(implicit override val IR: IRContext) extends ErgoLikeTestProvingInterpreter with ContextEnrichingProverInterpreter { diff --git a/sigmastate/src/test/scala/sigmastate/helpers/ErgoLikeContextTesting.scala b/sigmastate/src/test/scala/sigmastate/helpers/ErgoLikeContextTesting.scala index 2ddd47e30b..2d734663fc 100644 --- a/sigmastate/src/test/scala/sigmastate/helpers/ErgoLikeContextTesting.scala +++ b/sigmastate/src/test/scala/sigmastate/helpers/ErgoLikeContextTesting.scala @@ -6,13 +6,11 @@ import org.ergoplatform._ import org.ergoplatform.validation.{ValidationRules, SigmaValidationSettings} import sigmastate.AvlTreeData import sigmastate.eval._ -import sigmastate.interpreter.{ContextExtension, CryptoConstants, Interpreter} +import sigmastate.interpreter.{ContextExtension, CryptoConstants} import sigmastate.serialization.{SigmaSerializer, GroupElementSerializer} import special.collection.Coll import special.sigma.{Box, PreHeader, Header} -import scala.util.Try - object ErgoLikeContextTesting { /* NO HF PROOF: Changed: val dummyPubkey from `Array[Byte] = Array.fill(32)(0: Byte)` to `GroupElementSerializer.toBytes(CryptoConstants.dlogGroup.generator)` diff --git a/sigmastate/src/test/scala/sigmastate/helpers/ErgoTransactionValidator.scala b/sigmastate/src/test/scala/sigmastate/helpers/ErgoTransactionValidator.scala index dbd54b450e..22f8bae18d 100644 --- a/sigmastate/src/test/scala/sigmastate/helpers/ErgoTransactionValidator.scala +++ b/sigmastate/src/test/scala/sigmastate/helpers/ErgoTransactionValidator.scala @@ -3,7 +3,6 @@ package sigmastate.helpers import org.ergoplatform._ import sigmastate.eval.IRContext import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv} -import sigmastate.utxo.CostTable import scala.util.{Failure, Success} diff --git a/sigmastate/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala b/sigmastate/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala index 0d2cf49649..c30aa86916 100644 --- a/sigmastate/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala +++ b/sigmastate/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala @@ -1,7 +1,5 @@ package sigmastate.helpers -import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix -import org.ergoplatform.ErgoScriptPredef.TrueProp import org.ergoplatform.SigmaConstants.ScriptCostLimit import org.ergoplatform._ import org.ergoplatform.validation.ValidationRules.{CheckCostFunc, CheckCalcFunc} @@ -16,9 +14,9 @@ import sigma.types.IsPrimView import sigmastate.Values.{Constant, EvaluatedValue, SValue, Value, GroupElementConstant} import sigmastate.interpreter.Interpreter.{ScriptNameProp, ScriptEnv} import sigmastate.interpreter.{CryptoConstants, Interpreter} -import sigmastate.lang.{Terms, TransformingSigmaBuilder, SigmaCompiler} -import sigmastate.serialization.{ValueSerializer, SigmaSerializer} -import sigmastate.{SGroupElement, SType, TestsBase} +import sigmastate.lang.Terms +import sigmastate.serialization.SigmaSerializer +import sigmastate.{SGroupElement, TestsBase, SType} import sigmastate.eval.{CompiletimeCosting, IRContext, Evaluation, _} import sigmastate.interpreter.CryptoConstants.EcPointType import sigmastate.utils.Helpers._ @@ -34,7 +32,7 @@ trait SigmaTestingCommons extends PropSpec with NegativeTesting with TestsBase { - val fakeSelf: ErgoBox = createBox(0, TrueProp) + def fakeSelf: ErgoBox = createBox(0, TrueTree) def fakeContext: ErgoLikeContext = ErgoLikeContextTesting.dummy(fakeSelf, activatedVersionInTests) @@ -47,23 +45,6 @@ trait SigmaTestingCommons extends PropSpec implicit def grLeafConvert(elem: CryptoConstants.EcPointType): Value[SGroupElement.type] = GroupElementConstant(elem) - val compiler = SigmaCompiler(TestnetNetworkPrefix, TransformingSigmaBuilder) - - def checkSerializationRoundTrip(v: SValue): Unit = { - val compiledTreeBytes = ValueSerializer.serialize(v) - withClue(s"(De)Serialization roundtrip failed for the tree:") { - ValueSerializer.deserialize(compiledTreeBytes) shouldEqual v - } - } - - def compileWithoutCosting(env: ScriptEnv, code: String): Value[SType] = compiler.compileWithoutCosting(env, code) - - def compile(env: ScriptEnv, code: String)(implicit IR: IRContext): Value[SType] = { - val tree = compiler.compile(env, code) - checkSerializationRoundTrip(tree) - tree - } - class TestingIRContext extends TestContext with IRContext with CompiletimeCosting { override def onCostingResult[T](env: ScriptEnv, tree: SValue, res: RCostingResultEx[T]): Unit = { env.get(ScriptNameProp) match { @@ -169,8 +150,19 @@ trait SigmaTestingCommons extends PropSpec val tree = IR.buildTree(calcF) // sanity check that buildTree is reverse to buildGraph (see doCostingEx) - if (tA != special.sigma.ContextRType) - tree shouldBe compiledTree + if (tA != special.sigma.ContextRType) { + if (tree != compiledTree) { + println(s"Result of buildTree:") + val prettyTree = SigmaPPrint(tree, height = 150) + println(prettyTree) + + println(s"compiledTree:") + val prettyCompiledTree = SigmaPPrint(compiledTree, height = 150) + println(prettyCompiledTree) + + assert(prettyTree.plainText == prettyCompiledTree.plainText, "Failed sanity check that buildTree is reverse to buildGraph") + } + } val lA = Liftables.asLiftable[SContext, IR.Context](calcF.elem.eDom.liftable) val lB = Liftables.asLiftable[Any, Any](calcF.elem.eRange.liftable) @@ -206,7 +198,7 @@ trait SigmaTestingCommons extends PropSpec (costCtx, calcCtx) case _ => val ergoCtx = ErgoLikeContextTesting.dummy( - createBox(0, TrueProp), activatedVersionInTests + createBox(0, TrueTree), activatedVersionInTests ).withBindings(1.toByte -> Constant[SType](x.asInstanceOf[SType#WrappedType], tpeA)) .withBindings(bindings: _*) diff --git a/sigmastate/src/test/scala/sigmastate/helpers/TestingHelpers.scala b/sigmastate/src/test/scala/sigmastate/helpers/TestingHelpers.scala index 119572e737..9430e39a82 100644 --- a/sigmastate/src/test/scala/sigmastate/helpers/TestingHelpers.scala +++ b/sigmastate/src/test/scala/sigmastate/helpers/TestingHelpers.scala @@ -1,7 +1,7 @@ package sigmastate.helpers import scorex.crypto.hash.Digest32 -import special.collection.Coll +import special.collection.{Coll, CollOverArray, PairOfCols} import scorex.util.ModifierId import org.ergoplatform.{ErgoLikeTransactionTemplate, ErgoLikeTransaction, ErgoLikeContext, UnsignedInput, Input, ErgoBox, DataInput, ErgoBoxCandidate} import sigmastate.Values.ErgoTree @@ -11,7 +11,7 @@ import sigmastate.AvlTreeData import sigmastate.eval.CostingSigmaDslBuilder import sigmastate.eval._ import sigmastate.interpreter.ContextExtension -import special.sigma.{Header, PreHeader} +import special.sigma.{PreHeader, Header} import scala.collection.mutable.WrappedArray @@ -39,11 +39,22 @@ object TestingHelpers { additionalRegisters: AdditionalRegisters = Map.empty) = testBox(value, proposition, 0, additionalTokens, additionalRegisters) + /** Creates a new test box with the given parameters. */ def createBox(value: Long, proposition: ErgoTree, creationHeight: Int) = testBox(value, proposition, creationHeight, WrappedArray.empty, Map.empty, ErgoBox.allZerosModifierId) + /** Creates a clone instance of the given collection by recursively cloning all the underlying + * sub-collections. + */ + def cloneColl[A](c: Coll[A]): Coll[A] = (c match { + case c: CollOverArray[_] => + new CollOverArray(c.toArray.clone())(c.tItem) + case ps: PairOfCols[_,_] => + new PairOfCols(cloneColl(ps.ls), cloneColl(ps.rs)) + }).asInstanceOf[Coll[A]] + /** Copies the given box allowing also to update fields. */ def copyBox(box: ErgoBox)( value: Long = box.value, diff --git a/sigmastate/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala b/sigmastate/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala index c4a2511eb9..9f76b96108 100644 --- a/sigmastate/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala +++ b/sigmastate/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala @@ -12,7 +12,6 @@ import sigmastate.lang.exceptions.{CosterException, InvalidArguments, TyperExcep import sigmastate.serialization.ValueSerializer import sigmastate.serialization.generators.ObjectGenerators import sigmastate.utxo.{ByIndex, ExtractAmount, GetVar, SelectField} -import sigmastate.eval._ class SigmaCompilerTest extends SigmaTestingCommons with LangTests with ObjectGenerators { import CheckingSigmaBuilder._ diff --git a/sigmastate/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala b/sigmastate/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala index 648de1bb22..db7a78324b 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala @@ -18,7 +18,6 @@ import SType.AnyOps import scorex.util.encode.Base16 import sigmastate.lang.DeserializationSigmaBuilder import sigmastate.lang.exceptions.SerializerException -import sigmastate.utils.Helpers class ConstantSerializerSpecification extends TableSerializationSpecification { diff --git a/sigmastate/src/test/scala/sigmastate/serialization/ConstantStoreSpecification.scala b/sigmastate/src/test/scala/sigmastate/serialization/ConstantStoreSpecification.scala index 23bb979e01..f2ceec7014 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/ConstantStoreSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/ConstantStoreSpecification.scala @@ -1,11 +1,9 @@ package sigmastate.serialization -import org.ergoplatform.Self -import sigmastate.Values.{BlockValue, Constant, ConstantPlaceholder, IntConstant, LongConstant, ValDef, ValUse, Value} +import sigmastate.Values.{Constant, IntConstant} import sigmastate._ import sigmastate.helpers.SigmaTestingCommons -import sigmastate.lang.{DeserializationSigmaBuilder, SigmaBuilder} -import sigmastate.utxo.ExtractAmount +import sigmastate.lang.{SigmaBuilder, DeserializationSigmaBuilder} class ConstantStoreSpecification extends SerializationSpecification with SigmaTestingCommons { diff --git a/sigmastate/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala b/sigmastate/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala index 03f859320f..4df5ab5b61 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala @@ -1,8 +1,6 @@ package sigmastate.serialization import sigmastate.basics.ProveDHTuple -import sigmastate.utils.GenSerializers -import sigmastate.utxo.{CostTableStat, ComplexityTableStat} class PDHTSerializerSpecification extends SerializationSpecification { diff --git a/sigmastate/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala b/sigmastate/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala index 6adcd7a662..fa9ebab9e2 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala @@ -2,16 +2,14 @@ package sigmastate.serialization import java.util -import org.ergoplatform.{ErgoLikeContext, ErgoLikeTransaction} import org.scalacheck.{Arbitrary, Gen} import org.scalatest.Assertion -import sigmastate.Values.{SigmaBoolean, SigmaPropConstant, SigmaPropValue, Value} +import sigmastate.Values.SigmaBoolean import sigmastate._ import sigmastate.basics.DLogProtocol.ProveDlog import sigmastate.basics.ProveDHTuple -import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTransactionTesting, SigmaTestingCommons} +import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, SigmaTestingCommons, ErgoLikeTransactionTesting} import sigmastate.serialization.generators.ObjectGenerators -import sigmastate.utxo.Transformer import scala.util.Random @@ -86,7 +84,7 @@ class SigSerializerSpecification extends SigmaTestingCommons // get sigma conjectures out of transformers val prop = prover.reduceToCrypto(ctx, expr).get._1 - val proof = prover.prove(expr, ctx, challenge).get.proof + val proof = prover.prove(mkTestErgoTree(expr), ctx, challenge).get.proof val proofTree = SigSerializer.parseAndComputeChallenges(prop, proof) roundTrip(proofTree, prop) } catch { diff --git a/sigmastate/src/test/scala/sigmastate/serialization/TransformersSerializationSpec.scala b/sigmastate/src/test/scala/sigmastate/serialization/TransformersSerializationSpec.scala index f8952055b3..1239495bba 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/TransformersSerializationSpec.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/TransformersSerializationSpec.scala @@ -1,7 +1,5 @@ package sigmastate.serialization -import org.ergoplatform.{ErgoAddressEncoder, ErgoLikeContext} -import sigmastate.Values.StringConstant import sigmastate._ import sigmastate.utxo._ diff --git a/sigmastate/src/test/scala/sigmastate/serialization/generators/ConcreteCollectionGenerators.scala b/sigmastate/src/test/scala/sigmastate/serialization/generators/ConcreteCollectionGenerators.scala index 2322bbcd85..537cbf66b6 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/generators/ConcreteCollectionGenerators.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/generators/ConcreteCollectionGenerators.scala @@ -2,7 +2,7 @@ package sigmastate.serialization.generators import org.scalacheck.{Arbitrary, Gen} import sigmastate._ -import sigmastate.Values.{ConcreteCollection, Value, EvaluatedValue, IntConstant} +import sigmastate.Values.{ConcreteCollection, Value, IntConstant} trait ConcreteCollectionGenerators { self: ObjectGenerators => val minCollLength = 1 diff --git a/sigmastate/src/test/scala/sigmastate/serialization/generators/TransformerGenerators.scala b/sigmastate/src/test/scala/sigmastate/serialization/generators/TransformerGenerators.scala index 766f2c9c1b..87256fea4e 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/generators/TransformerGenerators.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/generators/TransformerGenerators.scala @@ -1,18 +1,8 @@ package sigmastate.serialization.generators -import org.ergoplatform._ import org.ergoplatform.validation.ValidationSpecification -import org.scalacheck.Arbitrary._ -import org.scalacheck.{Arbitrary, Gen} -import scorex.util.encode.{Base64, Base58} -import sigmastate._ -import sigmastate.Values.{TrueLeaf, Value, IntConstant, _} -import sigmastate.lang.TransformingSigmaBuilder -import sigmastate.utxo._ trait TransformerGenerators extends ValidationSpecification { self: ObjectGenerators with ConcreteCollectionGenerators => - import TransformingSigmaBuilder._ - } diff --git a/sigmastate/src/test/scala/sigmastate/serialization/generators/ValueGenerators.scala b/sigmastate/src/test/scala/sigmastate/serialization/generators/ValueGenerators.scala deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sigmastate/src/test/scala/sigmastate/utils/ByteArrayBuilderTests.scala b/sigmastate/src/test/scala/sigmastate/utils/ByteArrayBuilderTests.scala deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sigmastate/src/test/scala/sigmastate/utils/ByteReaderWriterImpSpecification.scala b/sigmastate/src/test/scala/sigmastate/utils/ByteReaderWriterImpSpecification.scala deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sigmastate/src/test/scala/sigmastate/utils/GenInfoObjects.scala b/sigmastate/src/test/scala/sigmastate/utils/GenInfoObjects.scala index c17aa7cb72..41579fae61 100644 --- a/sigmastate/src/test/scala/sigmastate/utils/GenInfoObjects.scala +++ b/sigmastate/src/test/scala/sigmastate/utils/GenInfoObjects.scala @@ -3,7 +3,7 @@ package sigmastate.utils import sigmastate.SMethod import scalan.util.PrintExtensions._ import scala.util.Try -import Helpers._ +import Helpers._ // required for Scala 2.11 /** Generate as a console output all InfoObject objects. * Those provide stable identifiers to access metadata information. diff --git a/sigmastate/src/test/scala/sigmastate/utils/SpecGen.scala b/sigmastate/src/test/scala/sigmastate/utils/SpecGen.scala index 0b5e1b27e4..a4186d86e8 100644 --- a/sigmastate/src/test/scala/sigmastate/utils/SpecGen.scala +++ b/sigmastate/src/test/scala/sigmastate/utils/SpecGen.scala @@ -6,7 +6,7 @@ import sigmastate.eval.{Zero, Sized} import scalan.util.Extensions.ByteOps import scalan.util.CollectionUtil import scalan.util.PrintExtensions._ -import sigmastate.Values.{FalseLeaf, Constant, TrueLeaf, BlockValue, ConstantPlaceholder, Tuple, ValDef, FunDef, ValUse, ValueCompanion, TaggedVariable, ConcreteCollection, ConcreteCollectionBooleanConstant} +import sigmastate.Values._ import sigmastate.lang.SigmaPredef.{PredefinedFuncRegistry, PredefinedFunc} import sigmastate.lang.StdSigmaBuilder import sigmastate.lang.Terms.{MethodCall, PropertyCall} diff --git a/sigmastate/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala index 044c0e5777..2b1a8d1003 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala @@ -1,7 +1,6 @@ package sigmastate.utxo import com.google.common.primitives.Longs -import org.ergoplatform.ErgoScriptPredef.TrueProp import org.ergoplatform._ import org.ergoplatform.dsl.{ContractSpec, SigmaContractSyntax, TestContractSpec} import scorex.crypto.authds.avltree.batch._ @@ -206,19 +205,19 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons val env = Map("key" -> key, "proof" -> proof) val prop = compile(env, """SELF.R4[AvlTree].get.contains(key, proof)""").asBoolValue.toSigmaProp - val propTree = IR.builder.mkMethodCall( + val propExp = IR.builder.mkMethodCall( ExtractRegisterAs[SAvlTree.type](Self, reg1).get, SAvlTree.containsMethod, IndexedSeq(ByteArrayConstant(key), ByteArrayConstant(proof)) ).asBoolValue.toSigmaProp - prop shouldBe propTree + prop shouldBe propExp val newBox1 = testBox(10, pubkey, 0) val newBoxes = IndexedSeq(newBox1) val spendingTransaction = createTransaction(newBoxes) - val s = testBox(20, TrueProp, 0, Seq(), Map(reg1 -> AvlTreeConstant(SigmaDsl.avlTree(treeData)))) + val s = testBox(20, TrueTree, 0, Seq(), Map(reg1 -> AvlTreeConstant(SigmaDsl.avlTree(treeData)))) val ctx = ErgoLikeContextTesting( currentHeight = 50, @@ -228,8 +227,9 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons spendingTransaction, self = s, activatedVersionInTests) - val pr = prover.prove(prop, ctx, fakeMessage).get - verifier.verify(prop, ctx, pr, fakeMessage).get._1 shouldBe true + val propTree = ErgoTree.fromProposition(ergoTreeHeaderInTests, prop) + val pr = prover.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage).get._1 shouldBe true } property("avl tree - contains key satisfying condition") { @@ -243,17 +243,18 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons val elementId = 1: Byte val env = Map("proofId" -> proofId.toLong, "elementId" -> elementId.toLong) - val prop = compile(env, + val prop = ErgoTree.fromProposition(ergoTreeHeaderInTests, + compile(env, """{ | val tree = SELF.R4[AvlTree].get | val proof = getVar[Coll[Byte]](proofId).get | val element = getVar[Long](elementId).get | val elementKey = blake2b256(longToByteArray(element)) | element >= 120L && tree.contains(elementKey, proof) - |}""".stripMargin).asBoolValue.toSigmaProp + |}""".stripMargin).asBoolValue.toSigmaProp) val recipientProposition = new ContextEnrichingTestProvingInterpreter().dlogSecrets.head.publicImage - val selfBox = testBox(20, TrueProp, 0, Seq(), Map(reg1 -> AvlTreeConstant(SigmaDsl.avlTree(treeData)))) + val selfBox = testBox(20, TrueTree, 0, Seq(), Map(reg1 -> AvlTreeConstant(SigmaDsl.avlTree(treeData)))) val ctx = ErgoLikeContextTesting( currentHeight = 50, lastBlockUtxoRoot = AvlTreeData.dummy, @@ -318,19 +319,21 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons | tree.contains(key, proof) |}""".stripMargin).asBoolValue.toSigmaProp - val propTree = IR.builder.mkMethodCall( + val propTree = ErgoTree.fromProposition(ergoTreeHeaderInTests, prop) + + val propExp = IR.builder.mkMethodCall( ExtractRegisterAs[SAvlTree.type](Self, reg1).get, SAvlTree.containsMethod, IndexedSeq(ExtractRegisterAs[SByteArray](Self, reg2).get, GetVarByteArray(proofId).get) ).asBoolValue.toSigmaProp - prop shouldBe propTree + prop shouldBe propExp val newBox1 = testBox(10, pubkey, 0) val newBoxes = IndexedSeq(newBox1) val spendingTransaction = createTransaction(newBoxes) - val s = testBox(20, TrueProp, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData), reg2 -> ByteArrayConstant(key))) + val s = testBox(20, TrueTree, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData), reg2 -> ByteArrayConstant(key))) val ctx = ErgoLikeContextTesting( currentHeight = 50, @@ -338,10 +341,10 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons minerPubkey = ErgoLikeContextTesting.dummyPubkey, boxesToSpend = IndexedSeq(s), spendingTransaction, self = s, activatedVersionInTests) - val pr = prover.prove(prop, ctx, fakeMessage).get + val pr = prover.prove(propTree, ctx, fakeMessage).get val ctxv = ctx.withExtension(pr.extension) - verifier.verify(prop, ctxv, pr, fakeMessage).get._1 shouldBe true + verifier.verify(propTree, ctxv, pr, fakeMessage).get._1 shouldBe true } property("avl tree - getMany") { @@ -377,12 +380,14 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons | sigmaProp(tree.getMany(keys, proof).forall( { (o: Option[Coll[Byte]]) => o.isDefined })) |}""".stripMargin).asBoolValue.toSigmaProp + val propTree = ErgoTree.fromProposition(ergoTreeHeaderInTests, prop) + val newBox1 = testBox(10, pubkey, 0) val newBoxes = IndexedSeq(newBox1) val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes) - val s = testBox(20, TrueProp, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData))) + val s = testBox(20, TrueTree, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData))) val ctx = ErgoLikeContextTesting( currentHeight = 50, @@ -390,10 +395,10 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons minerPubkey = ErgoLikeContextTesting.dummyPubkey, boxesToSpend = IndexedSeq(s), spendingTransaction, self = s, activatedVersionInTests) - val pr = prover.prove(env + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get + val pr = prover.prove(env + (ScriptNameProp -> "prove"), propTree, ctx, fakeMessage).get val ctxv = ctx.withExtension(pr.extension) - verifier.verify(env + (ScriptNameProp -> "verify"), prop, ctxv, pr, fakeMessage).get._1 shouldBe true + verifier.verify(env + (ScriptNameProp -> "verify"), propTree, ctxv, pr, fakeMessage).get._1 shouldBe true } } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 34c948cd49..a08959d40b 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -20,6 +20,7 @@ import sigmastate.utils.Helpers._ class BasicOpsSpecification extends SigmaTestingCommons with CrossVersionProps { + override val printVersions: Boolean = false implicit lazy val IR = new TestingIRContext { override val okPrintEvaluatedEntries: Boolean = false } @@ -69,13 +70,14 @@ class BasicOpsSpecification extends SigmaTestingCommons if (propExp != null) prop shouldBe propExp + val tree = ErgoTree.fromProposition(ergoTreeHeaderInTests, prop) val p3 = prover.dlogSecrets(2).publicImage - val boxToSpend = testBox(10, prop, additionalRegisters = Map( + val boxToSpend = testBox(10, tree, additionalRegisters = Map( reg1 -> SigmaPropConstant(p3), reg2 -> IntConstant(1)), creationHeight = 5) - val newBox1 = testBox(10, prop, creationHeight = 0, boxIndex = 0, additionalRegisters = Map( + val newBox1 = testBox(10, tree, creationHeight = 0, boxIndex = 0, additionalRegisters = Map( reg1 -> IntConstant(1), reg2 -> IntConstant(10))) val tx = createTransaction(newBox1) @@ -84,14 +86,14 @@ class BasicOpsSpecification extends SigmaTestingCommons lastBlockUtxoRoot = AvlTreeData.dummy, ErgoLikeContextTesting.dummyPubkey, boxesToSpend = IndexedSeq(boxToSpend), spendingTransaction = tx, self = boxToSpend, activatedVersionInTests) - val pr = prover.prove(env + (ScriptNameProp -> s"${name}_prove"), prop, ctx, fakeMessage).getOrThrow + val pr = prover.prove(env + (ScriptNameProp -> s"${name}_prove"), tree, ctx, fakeMessage).getOrThrow val ctxExt = ctx.withExtension(pr.extension) val verifier = new ErgoLikeTestInterpreter if (!onlyPositive) - verifier.verify(env + (ScriptNameProp -> s"${name}_verify"), prop, ctx, pr.proof, fakeMessage).map(_._1).getOrElse(false) shouldBe false //context w/out extensions - verifier.verify(env + (ScriptNameProp -> s"${name}_verify_ext"), prop, ctxExt, pr.proof, fakeMessage).get._1 shouldBe true + verifier.verify(env + (ScriptNameProp -> s"${name}_verify"), tree, ctx, pr.proof, fakeMessage).map(_._1).getOrElse(false) shouldBe false //context w/out extensions + verifier.verify(env + (ScriptNameProp -> s"${name}_verify_ext"), tree, ctxExt, pr.proof, fakeMessage).get._1 shouldBe true } property("Relation operations") { diff --git a/sigmastate/src/test/scala/sigmastate/utxo/BlockchainSimulationSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/BlockchainSimulationSpecification.scala index a3a071a341..8807986713 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/BlockchainSimulationSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/BlockchainSimulationSpecification.scala @@ -10,13 +10,13 @@ import scorex.crypto.authds.avltree.batch.{Remove, BatchAVLProver, Insert} import scorex.crypto.authds.{ADDigest, ADKey, ADValue} import scorex.crypto.hash.{Digest32, Blake2b256} import scorex.util._ -import sigmastate.Values.{LongConstant, IntConstant} +import sigmastate.Values.{LongConstant, IntConstant, ErgoTree} import sigmastate.helpers.{ErgoTransactionValidator, ErgoLikeContextTesting, ErgoLikeTestProvingInterpreter, SigmaTestingCommons, BlockchainState} import sigmastate.helpers.TestingHelpers._ import sigmastate.interpreter.ContextExtension import sigmastate.eval._ import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv} -import sigmastate.{GE, AvlTreeData, AvlTreeFlags, CrossVersionProps} +import sigmastate.{GE, AvlTreeData, CrossVersionProps, AvlTreeFlags} import scala.annotation.tailrec import scala.collection.concurrent.TrieMap @@ -55,8 +55,10 @@ class BlockchainSimulationSpecification extends SigmaTestingCommons Block(txs, minerPubKey.pkBytes) } + import ValidationState._ + property("apply one valid block") { - val state = ValidationState.initialState(activatedVersionInTests) + val state = initialState(activatedVersionInTests, initBlock(ergoTreeVersionInTests)) val miner = new ErgoLikeTestProvingInterpreter() val block = generateBlock(state, miner, 0) val updStateTry = state.applyBlock(block) @@ -64,7 +66,7 @@ class BlockchainSimulationSpecification extends SigmaTestingCommons } property("too costly block") { - val state = ValidationState.initialState(activatedVersionInTests) + val state = initialState(activatedVersionInTests, initBlock(ergoTreeVersionInTests)) val miner = new ErgoLikeTestProvingInterpreter() val block = generateBlock(state, miner, 0) val updStateTry = state.applyBlock(block, maxCost = 1) @@ -72,7 +74,7 @@ class BlockchainSimulationSpecification extends SigmaTestingCommons } property("apply many blocks") { - val state = ValidationState.initialState(activatedVersionInTests) + val state = initialState(activatedVersionInTests, initBlock(ergoTreeVersionInTests)) val miner = new ErgoLikeTestProvingInterpreter() @tailrec @@ -97,7 +99,7 @@ class BlockchainSimulationSpecification extends SigmaTestingCommons def bench(numberOfBlocks: Int): Unit = { - val state = ValidationState.initialState(activatedVersionInTests) + val state = initialState(activatedVersionInTests, initBlock(ergoTreeVersionInTests)) val miner = new ErgoLikeTestProvingInterpreter() val (_, time) = (0 until numberOfBlocks).foldLeft(state -> 0L) { case ((s, timeAcc), h) => @@ -212,16 +214,21 @@ object BlockchainSimulationSpecification { object ValidationState { type BatchProver = BatchAVLProver[Digest32, Blake2b256.type] - val initBlock = Block( + def initBlock(scriptVersion: Byte) = Block( (0 until windowSize).map { i => val txId = hash.hash(i.toString.getBytes ++ scala.util.Random.nextString(12).getBytes).toModifierId - val boxes = (1 to 30).map(_ => testBox(10, GE(Height, IntConstant(i)).toSigmaProp, 0, Seq(), Map(heightReg -> IntConstant(i)), txId)) + val boxes = (1 to 30).map(_ => + testBox(10, + ErgoTree.fromProposition( + ErgoTree.headerWithVersion(scriptVersion), + GE(Height, IntConstant(i)).toSigmaProp), + 0, Seq(), Map(heightReg -> IntConstant(i)), txId)) ergoplatform.ErgoLikeTransaction(IndexedSeq(), boxes) }, ErgoLikeContextTesting.dummyPubkey ) - def initialState(activatedVersion: Byte, block: Block = initBlock)(implicit IR: IRContext): ValidationState = { + def initialState(activatedVersion: Byte, block: Block)(implicit IR: IRContext): ValidationState = { val keySize = 32 val prover = new BatchProver(keySize, None) diff --git a/sigmastate/src/test/scala/sigmastate/utxo/CollectionOperationsSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/CollectionOperationsSpecification.scala index 5293ef0b59..b36c2b707a 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/CollectionOperationsSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/CollectionOperationsSpecification.scala @@ -1,6 +1,5 @@ package sigmastate.utxo -import org.ergoplatform.ErgoScriptPredef.TrueProp import sigmastate.Values._ import sigmastate._ import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestInterpreter, SigmaTestingCommons} @@ -35,16 +34,18 @@ class CollectionOperationsSpecification extends SigmaTestingCommons outputBoxValues: IndexedSeq[Long], boxesToSpendValues: IndexedSeq[Long] = IndexedSeq()) = { val (prover, verifier, prop, ctx) = buildEnv(code, expectedComp, outputBoxValues, boxesToSpendValues) - val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).getOrThrow - verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true + val propTree = mkTestErgoTree(prop) + val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), propTree, ctx, fakeMessage).getOrThrow + verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), propTree, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true } private def assertProof(code: String, outputBoxValues: IndexedSeq[Long], boxesToSpendValues: IndexedSeq[Long]) = { val (prover, verifier, prop, ctx) = buildEnv(code, None, outputBoxValues, boxesToSpendValues) - val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).getOrThrow - verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true + val propTree = mkTestErgoTree(prop) + val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), propTree, ctx, fakeMessage).getOrThrow + verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), propTree, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true } private def assertProverFail(code: String, @@ -52,7 +53,8 @@ class CollectionOperationsSpecification extends SigmaTestingCommons outputBoxValues: IndexedSeq[Long], boxesToSpendValues: IndexedSeq[Long] = IndexedSeq()) = { val (prover, _, prop, ctx) = buildEnv(code, expectedComp, outputBoxValues, boxesToSpendValues) - prover.prove(prop, ctx, fakeMessage).isSuccess shouldBe false + val propTree = mkTestErgoTree(prop) + prover.prove(propTree, ctx, fakeMessage).isSuccess shouldBe false } private def buildEnv(code: String, @@ -69,13 +71,15 @@ class CollectionOperationsSpecification extends SigmaTestingCommons (ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaPropValue, ErgoLikeContext) = { val prover = new ContextEnrichingTestProvingInterpreter val verifier = new ErgoLikeTestInterpreter + val pubkey = prover.dlogSecrets.head.publicImage + val pubkeyTree = mkTestErgoTree(pubkey) val prop = compile(Map(), code).asBoolValue.toSigmaProp expectedComp.foreach(prop shouldBe _) - val ctx = context(boxesToSpendValues.map(testBox(_, pubkey, 0)), - outputBoxValues.map(testBox(_, pubkey, 0))) + val ctx = context(boxesToSpendValues.map(testBox(_, pubkeyTree, 0)), + outputBoxValues.map(testBox(_, pubkeyTree, 0))) (prover, verifier, prop, ctx) } @@ -84,8 +88,10 @@ class CollectionOperationsSpecification extends SigmaTestingCommons val verifier = new ErgoLikeTestInterpreter val pubkey = prover.dlogSecrets.head.publicImage.toSigmaProp + val pubkeyTree = mkTestErgoTree(pubkey) val prop = compile(Map(), "OUTPUTS.exists({ (box: Box) => box.value + 5 > 10 })").asBoolValue.toSigmaProp + val propTree = mkTestErgoTree(prop) val expProp = Exists(Outputs, FuncValue(Vector((1, SBox)), @@ -93,8 +99,8 @@ class CollectionOperationsSpecification extends SigmaTestingCommons ).toSigmaProp prop shouldBe expProp - val newBox1 = testBox(16, pubkey, 0) - val newBox2 = testBox(15, pubkey, 0) + val newBox1 = testBox(16, pubkeyTree, 0) + val newBox2 = testBox(15, pubkeyTree, 0) val spendingTransaction = createTransaction(Array(newBox1, newBox2)) @@ -107,14 +113,14 @@ class CollectionOperationsSpecification extends SigmaTestingCommons self = fakeSelf, activatedVersionInTests) { - val pr = prover.prove(prop, ctx, fakeMessage).get - verifier.verify(prop, ctx, pr, fakeMessage).get._1 shouldBe true + val pr = prover.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage).get._1 shouldBe true } // negative case for `exists` { - val newBox1 = testBox(1, pubkey, 0) - val newBox2 = testBox(5, pubkey, 0) + val newBox1 = testBox(1, pubkeyTree, 0) + val newBox2 = testBox(5, pubkeyTree, 0) val tx2 = createTransaction(Array(newBox1, newBox2)) val ctx2 = ErgoLikeContextTesting( currentHeight = ctx.preHeader.height, @@ -124,24 +130,27 @@ class CollectionOperationsSpecification extends SigmaTestingCommons spendingTransaction = tx2, self = fakeSelf, activatedVersionInTests) - prover.prove(prop, ctx2, fakeMessage).isFailure shouldBe true + prover.prove(propTree, ctx2, fakeMessage).isFailure shouldBe true } } property("forall") { val prover = new ContextEnrichingTestProvingInterpreter val verifier = new ErgoLikeTestInterpreter + val pubkey = prover.dlogSecrets.head.publicImage + val pubkeyTree = mkTestErgoTree(pubkey) val prop = compile(Map(), "OUTPUTS.forall({ (box: Box) => box.value == 10 })").asBoolValue.toSigmaProp + val propTree = mkTestErgoTree(prop) - val propTree = ForAll(Outputs, + val propExpected = ForAll(Outputs, FuncValue(Vector((1, SBox)), EQ(ExtractAmount(ValUse(1, SBox)), LongConstant(10))) ).toSigmaProp - prop shouldBe propTree + prop shouldBe propExpected - val newBox1 = testBox(10, pubkey, 0) - val newBox2 = testBox(10, pubkey, 0) + val newBox1 = testBox(10, pubkeyTree, 0) + val newBox2 = testBox(10, pubkeyTree, 0) val newBoxes = IndexedSeq(newBox1, newBox2) val spendingTransaction = createTransaction(newBoxes) @@ -154,24 +163,26 @@ class CollectionOperationsSpecification extends SigmaTestingCommons spendingTransaction, self = fakeSelf, activatedVersionInTests) - val pr = prover.prove(prop, ctx, fakeMessage).get - verifier.verify(prop, ctx, pr, fakeMessage).get._1 shouldBe true + val pr = prover.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage).get._1 shouldBe true } - property("forall - fail") { val prover = new ContextEnrichingTestProvingInterpreter val pubkey = prover.dlogSecrets.head.publicImage + val pubkeyTree = mkTestErgoTree(pubkey) val prop = compile(Map(), "OUTPUTS.forall({ (box: Box) => box.value == 10 })").asBoolValue.toSigmaProp - val propTree = ForAll(Outputs, + val propTree = mkTestErgoTree(prop) + + val propExpected = ForAll(Outputs, FuncValue(Vector((1, SBox)), EQ(ExtractAmount(ValUse(1, SBox)), LongConstant(10))) ).toSigmaProp - prop shouldBe propTree + prop shouldBe propExpected - val newBox1 = testBox(10, pubkey, 0) - val newBox2 = testBox(11, pubkey, 0) + val newBox1 = testBox(10, pubkeyTree, 0) + val newBox2 = testBox(11, pubkeyTree, 0) val newBoxes = IndexedSeq(newBox1, newBox2) val spendingTransaction = createTransaction(newBoxes) @@ -184,7 +195,7 @@ class CollectionOperationsSpecification extends SigmaTestingCommons spendingTransaction, self = fakeSelf, activatedVersionInTests) - prover.prove(prop, ctx, fakeMessage).isSuccess shouldBe false + prover.prove(propTree, ctx, fakeMessage).isSuccess shouldBe false } property("counter") { @@ -192,13 +203,15 @@ class CollectionOperationsSpecification extends SigmaTestingCommons val verifier = new ErgoLikeTestInterpreter val pubkey = prover.dlogSecrets.head.publicImage.toSigmaProp + val pubkeyTree = mkTestErgoTree(pubkey) val prop = compile(Map(), """OUTPUTS.exists { (box: Box) => | box.R4[Long].get == SELF.R4[Long].get + 1 }""".stripMargin).asBoolValue.toSigmaProp + val propTree = mkTestErgoTree(prop) - val propTree = Exists(Outputs, + val propExpected = Exists(Outputs, FuncValue( Vector((1, SBox)), EQ( @@ -206,15 +219,15 @@ class CollectionOperationsSpecification extends SigmaTestingCommons Plus(ExtractRegisterAs[SLong.type](Self, reg1).get, LongConstant(1))) ) ).toSigmaProp - prop shouldBe propTree + prop shouldBe propExpected - val newBox1 = testBox(10, pubkey, 0, Seq(), Map(reg1 -> LongConstant(3))) - val newBox2 = testBox(10, pubkey, 0, Seq(), Map(reg1 -> LongConstant(6))) + val newBox1 = testBox(10, pubkeyTree, 0, Seq(), Map(reg1 -> LongConstant(3))) + val newBox2 = testBox(10, pubkeyTree, 0, Seq(), Map(reg1 -> LongConstant(6))) val newBoxes = IndexedSeq(newBox1, newBox2) val spendingTransaction = createTransaction(newBoxes) - val s = testBox(20, TrueProp, 0, Seq(), Map(reg1 -> LongConstant(5))) + val s = testBox(20, TrueTree, 0, Seq(), Map(reg1 -> LongConstant(5))) val ctx = ErgoLikeContextTesting( currentHeight = 50, @@ -224,8 +237,8 @@ class CollectionOperationsSpecification extends SigmaTestingCommons spendingTransaction, self = s, activatedVersionInTests) - val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get - verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).get._1 shouldBe true + val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), propTree, ctx, fakeMessage).get + verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), propTree, ctx, pr, fakeMessage).get._1 shouldBe true } property("counter - no register in outputs") { @@ -233,13 +246,15 @@ class CollectionOperationsSpecification extends SigmaTestingCommons val verifier = new ErgoLikeTestInterpreter val pubkey = prover.dlogSecrets.head.publicImage + val pubkeyTree = mkTestErgoTree(pubkey) val prop = compile(Map(), """OUTPUTS.exists { (box: Box) => | box.R4[Long].getOrElse(0L) == SELF.R4[Long].get + 1 }""".stripMargin).asBoolValue.toSigmaProp + val propTree = mkTestErgoTree(prop) - val propTree = Exists(Outputs, + val propExpected = Exists(Outputs, FuncValue( Vector((1, SBox)), EQ( @@ -249,15 +264,15 @@ class CollectionOperationsSpecification extends SigmaTestingCommons ) ).toSigmaProp - prop shouldBe propTree + prop shouldBe propExpected - val newBox1 = testBox(10, pubkey, 0) - val newBox2 = testBox(10, pubkey, 0, Seq(), Map(reg1 -> LongConstant(6))) + val newBox1 = testBox(10, pubkeyTree, 0) + val newBox2 = testBox(10, pubkeyTree, 0, Seq(), Map(reg1 -> LongConstant(6))) val newBoxes = IndexedSeq(newBox1, newBox2) val spendingTransaction = createTransaction(newBoxes) - val s = testBox(20, TrueProp, 0, Seq(), Map(reg1 -> LongConstant(5))) + val s = testBox(20, TrueTree, 0, Seq(), Map(reg1 -> LongConstant(5))) val ctx = ErgoLikeContextTesting( currentHeight = 50, @@ -267,8 +282,8 @@ class CollectionOperationsSpecification extends SigmaTestingCommons spendingTransaction, self = s, activatedVersionInTests) - val pr = prover.prove(prop, ctx, fakeMessage).get - verifier.verify(prop, ctx, pr, fakeMessage).get._1 shouldBe true + val pr = prover.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage).get._1 shouldBe true } property("sizeof - num of outputs = num of inputs + 1") { @@ -276,19 +291,22 @@ class CollectionOperationsSpecification extends SigmaTestingCommons val verifier = new ErgoLikeTestInterpreter val pubkey = prover.dlogSecrets.head.publicImage + val pubkeyTree = mkTestErgoTree(pubkey) val env = Map("pubkey" -> pubkey) val prop = compile(env, """pubkey && OUTPUTS.size == INPUTS.size + 1""").asSigmaProp - val propTree = SigmaAnd(pubkey, BoolToSigmaProp(EQ(SizeOf(Outputs), Plus(SizeOf(Inputs), IntConstant(1))))) - prop shouldBe propTree + val propTree = mkTestErgoTree(prop) + + val propExpected = SigmaAnd(pubkey, BoolToSigmaProp(EQ(SizeOf(Outputs), Plus(SizeOf(Inputs), IntConstant(1))))) + prop shouldBe propExpected - val newBox1 = testBox(11, pubkey, 0) - val newBox2 = testBox(10, pubkey, 0) + val newBox1 = testBox(11, pubkeyTree, 0) + val newBox2 = testBox(10, pubkeyTree, 0) val newBoxes = IndexedSeq(newBox1, newBox2) val spendingTransaction = createTransaction(newBoxes) - val s = testBox(21, pubkey, 0) + val s = testBox(21, pubkeyTree, 0) val ctx = ErgoLikeContextTesting( currentHeight = 50, @@ -298,12 +316,12 @@ class CollectionOperationsSpecification extends SigmaTestingCommons spendingTransaction, self = s, activatedVersionInTests) - val pr = prover.prove(prop, ctx, fakeMessage).get - verifier.verify(prop, ctx, pr, fakeMessage) + val pr = prover.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage) val fProp = SigmaAnd(pubkey, EQ(SizeOf(Outputs), SizeOf(Inputs))) - prover.prove(fProp, ctx, fakeMessage).isSuccess shouldBe false + prover.prove(mkTestErgoTree(fProp), ctx, fakeMessage).isSuccess shouldBe false } property("slice") { @@ -473,7 +491,8 @@ class CollectionOperationsSpecification extends SigmaTestingCommons } property("flatMap") { - assertProof("OUTPUTS.flatMap({ (out: Box) => out.propositionBytes })(0) == 0.toByte", + assertProof( + s"OUTPUTS.flatMap({ (out: Box) => out.propositionBytes })(0) == $ergoTreeHeaderInTests.toByte", EQ( ByIndex( MethodCall(Outputs, @@ -485,7 +504,7 @@ class CollectionOperationsSpecification extends SigmaTestingCommons ).asCollection[SByte.type], IntConstant(0) ), - ByteConstant(0) + ByteConstant(ergoTreeHeaderInTests) ), IndexedSeq(1L, 1L)) } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/ComplexSigSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/ComplexSigSpecification.scala index a12b41e10e..41f9a28535 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/ComplexSigSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/ComplexSigSpecification.scala @@ -33,10 +33,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyB = proverB.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB) - val compiledProp = compile(env, """pubkeyA || pubkeyB""").asSigmaProp + val prop = compile(env, """pubkeyA || pubkeyB""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaOr(pubkeyA, pubkeyB) - compiledProp shouldBe prop + val propExpected = SigmaOr(pubkeyA, pubkeyB) + prop shouldBe propExpected val ctx = ErgoLikeContextTesting( currentHeight = 1, @@ -46,13 +47,13 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA = proverA.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prA, fakeMessage).get._1 shouldBe true + val prA = proverA.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prA, fakeMessage).get._1 shouldBe true - val prB = proverB.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prB, fakeMessage).get._1 shouldBe true + val prB = proverB.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prB, fakeMessage).get._1 shouldBe true - proverC.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true + proverC.prove(propTree, ctx, fakeMessage).isFailure shouldBe true } property("simplest linear-sized ring signature (1-out-of-3 OR), with anyOf syntax") { @@ -66,10 +67,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyC = proverC.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC) - val compiledProp = compile(env, """anyOf(Coll(pubkeyA, pubkeyB, pubkeyC))""").asSigmaProp + val prop = compile(env, """anyOf(Coll(pubkeyA, pubkeyB, pubkeyC))""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaOr(pubkeyA, pubkeyB, pubkeyC) - compiledProp shouldBe prop + val propExpected = SigmaOr(pubkeyA, pubkeyB, pubkeyC) + prop shouldBe propExpected val ctx = ErgoLikeContextTesting( currentHeight = 1, @@ -79,14 +81,14 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA = proverA.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prA, fakeMessage).get._1 shouldBe true + val prA = proverA.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prA, fakeMessage).get._1 shouldBe true - val prB = proverB.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prB, fakeMessage).get._1 shouldBe true + val prB = proverB.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prB, fakeMessage).get._1 shouldBe true - val prC = proverC.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prC, fakeMessage).get._1 shouldBe true + val prC = proverC.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prC, fakeMessage).get._1 shouldBe true } property("simplest linear-sized ring signature (1-out-of-3 OR), with || syntax") { @@ -100,10 +102,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyC = proverC.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC) - val compiledProp = compile(env, """pubkeyA || pubkeyB || pubkeyC""").asSigmaProp + val prop = compile(env, """pubkeyA || pubkeyB || pubkeyC""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaOr(SigmaOr(pubkeyA, pubkeyB), pubkeyC) - compiledProp shouldBe prop + val propExpected = SigmaOr(SigmaOr(pubkeyA, pubkeyB), pubkeyC) + prop shouldBe propExpected val ctx = ErgoLikeContextTesting( currentHeight = 1, @@ -113,14 +116,14 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA = proverA.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prA, fakeMessage).get._1 shouldBe true + val prA = proverA.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prA, fakeMessage).get._1 shouldBe true - val prB = proverB.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prB, fakeMessage).get._1 shouldBe true + val prB = proverB.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prB, fakeMessage).get._1 shouldBe true - val prC = proverC.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prC, fakeMessage).get._1 shouldBe true + val prC = proverC.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prC, fakeMessage).get._1 shouldBe true } //two secrets are known, nevertheless, one will be simulated @@ -135,10 +138,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyA4 = proverA.dlogSecrets(3).publicImage val env = Map("pubkeyA1" -> pubkeyA1, "pubkeyA2" -> pubkeyA2, "pubkeyA3" -> pubkeyA3, "pubkeyA4" -> pubkeyA4) - val compiledProp = compile(env, """anyOf(Coll(pubkeyA1, pubkeyA2, pubkeyA3, pubkeyA4))""").asSigmaProp + val prop = compile(env, """anyOf(Coll(pubkeyA1, pubkeyA2, pubkeyA3, pubkeyA4))""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaOr(pubkeyA1, pubkeyA2, pubkeyA3, pubkeyA4) - compiledProp shouldBe prop + val propExpected = SigmaOr(pubkeyA1, pubkeyA2, pubkeyA3, pubkeyA4) + prop shouldBe propExpected val ctx = ErgoLikeContextTesting( currentHeight = 1, @@ -148,8 +152,8 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA = proverA.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prA, fakeMessage).get._1 shouldBe true + val prA = proverA.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prA, fakeMessage).get._1 shouldBe true } property("complex sig scheme - OR of two ANDs") { @@ -166,10 +170,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyD = proverD.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC, "pubkeyD" -> pubkeyD) - val compiledProp = compile(env, """pubkeyA && pubkeyB || pubkeyC && pubkeyD""").asSigmaProp + val prop = compile(env, """pubkeyA && pubkeyB || pubkeyC && pubkeyD""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaOr(SigmaAnd(pubkeyA, pubkeyB), SigmaAnd(pubkeyC, pubkeyD)) - compiledProp shouldBe prop + val propExpected = SigmaOr(SigmaAnd(pubkeyA, pubkeyB), SigmaAnd(pubkeyC, pubkeyD)) + prop shouldBe propExpected val ctx = ErgoLikeContextTesting( currentHeight = 1, @@ -179,18 +184,18 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - proverA.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverB.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverC.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverD.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true + proverA.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverB.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverC.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverD.prove(propTree, ctx, fakeMessage).isFailure shouldBe true val proverAB = proverA.withSecrets(Seq(proverB.dlogSecrets.head)) - val pr = proverAB.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, pr, fakeMessage).get._1 shouldBe true + val pr = proverAB.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage).get._1 shouldBe true val proverCD = proverC.withSecrets(Seq(proverD.dlogSecrets.head)) - val pr2 = proverCD.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, pr2, fakeMessage).get._1 shouldBe true + val pr2 = proverCD.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr2, fakeMessage).get._1 shouldBe true } property("complex sig scheme - OR of AND and OR") { @@ -207,10 +212,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyD = proverD.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC, "pubkeyD" -> pubkeyD) - val compiledProp = compile(env, """pubkeyA && pubkeyB || (pubkeyC || pubkeyD)""").asSigmaProp + val prop = compile(env, """pubkeyA && pubkeyB || (pubkeyC || pubkeyD)""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaOr(SigmaAnd(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD)) - compiledProp shouldBe prop + val propExpected = SigmaOr(SigmaAnd(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD)) + prop shouldBe propExpected val ctx = ErgoLikeContextTesting( currentHeight = 1, @@ -220,18 +226,18 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - proverA.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverB.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true + proverA.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverB.prove(propTree, ctx, fakeMessage).isFailure shouldBe true - val prC = proverC.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prC, fakeMessage).get._1 shouldBe true + val prC = proverC.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prC, fakeMessage).get._1 shouldBe true - val prD = proverD.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prD, fakeMessage).get._1 shouldBe true + val prD = proverD.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prD, fakeMessage).get._1 shouldBe true val proverAB = proverA.withSecrets(Seq(proverB.dlogSecrets.head)) - val pr = proverAB.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, pr, fakeMessage).get._1 shouldBe true + val pr = proverAB.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage).get._1 shouldBe true } property("simple sig scheme - AND of two") { @@ -244,10 +250,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyB = proverB.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB) - val compiledProp = compile(env, """pubkeyA && pubkeyB""").asSigmaProp + val prop = compile(env, """pubkeyA && pubkeyB""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaAnd(pubkeyA, pubkeyB) - compiledProp shouldBe prop + val propExpected = SigmaAnd(pubkeyA, pubkeyB) + prop shouldBe propExpected val ctx = ErgoLikeContextTesting( currentHeight = 1, @@ -257,12 +264,12 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - proverA.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverB.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true + proverA.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverB.prove(propTree, ctx, fakeMessage).isFailure shouldBe true val proverAB = proverA.withSecrets(Seq(proverB.dlogSecrets.head)) - val pr = proverAB.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, pr, fakeMessage).get._1 shouldBe true + val pr = proverAB.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage).get._1 shouldBe true } property("complex sig scheme - OR of AND and DLOG") { @@ -277,10 +284,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyC = proverC.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC) - val compiledProp = compile(env, """(pubkeyA && pubkeyB) || pubkeyC""").asSigmaProp + val prop = compile(env, """(pubkeyA && pubkeyB) || pubkeyC""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaOr(SigmaAnd(pubkeyA, pubkeyB), pubkeyC) - compiledProp shouldBe prop + val propExpected = SigmaOr(SigmaAnd(pubkeyA, pubkeyB), pubkeyC) + prop shouldBe propExpected val ctx = ErgoLikeContextTesting( currentHeight = 1, @@ -290,17 +298,17 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - proverA.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverB.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverC.prove(compiledProp, ctx, fakeMessage).isSuccess shouldBe true + proverA.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverB.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverC.prove(propTree, ctx, fakeMessage).isSuccess shouldBe true val proverAB = proverA.withSecrets(Seq(proverB.dlogSecrets.head)) - val pr = proverAB.prove(compiledProp, ctx, fakeMessage).get + val pr = proverAB.prove(propTree, ctx, fakeMessage).get println("proof size: " + pr.proof.length) - verifier.verify(compiledProp, ctx, pr, fakeMessage).get._1 shouldBe true + verifier.verify(propTree, ctx, pr, fakeMessage).get._1 shouldBe true - val pr2 = proverC.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, pr2, fakeMessage).get._1 shouldBe true + val pr2 = proverC.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr2, fakeMessage).get._1 shouldBe true } property("complex sig scheme - AND of two ORs") { @@ -317,10 +325,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyD = proverD.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC, "pubkeyD" -> pubkeyD) - val compiledProp = compile(env, """(pubkeyA || pubkeyB) && (pubkeyC || pubkeyD)""").asSigmaProp + val prop = compile(env, """(pubkeyA || pubkeyB) && (pubkeyC || pubkeyD)""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaAnd(SigmaOr(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD)) - compiledProp shouldBe prop + val propExpected = SigmaAnd(SigmaOr(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD)) + prop shouldBe propExpected val ctx = ErgoLikeContextTesting( currentHeight = 1, @@ -330,18 +339,18 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - proverA.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverB.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverC.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverD.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true + proverA.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverB.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverC.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverD.prove(propTree, ctx, fakeMessage).isFailure shouldBe true val proverAC = proverA.withSecrets(Seq(proverC.dlogSecrets.head)) - val pr = proverAC.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, pr, fakeMessage).get._1 shouldBe true + val pr = proverAC.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage).get._1 shouldBe true val proverBD = proverB.withSecrets(Seq(proverD.dlogSecrets.head)) - val pr2 = proverBD.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, pr2, fakeMessage).get._1 shouldBe true + val pr2 = proverBD.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr2, fakeMessage).get._1 shouldBe true } property("complex sig scheme - AND of AND and OR") { @@ -358,10 +367,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyD = proverD.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC, "pubkeyD" -> pubkeyD) - val compiledProp = compile(env, """(pubkeyA && pubkeyB) && (pubkeyC || pubkeyD)""").asSigmaProp + val prop = compile(env, """(pubkeyA && pubkeyB) && (pubkeyC || pubkeyD)""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaAnd(SigmaAnd(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD)) - compiledProp shouldBe prop + val propExpected = SigmaAnd(SigmaAnd(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD)) + prop shouldBe propExpected val ctx = ErgoLikeContextTesting( currentHeight = 1, @@ -371,21 +381,21 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - proverA.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverB.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverC.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - proverD.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true + proverA.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverB.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverC.prove(propTree, ctx, fakeMessage).isFailure shouldBe true + proverD.prove(propTree, ctx, fakeMessage).isFailure shouldBe true val proverAB = proverA.withSecrets(Seq(proverB.dlogSecrets.head)) - proverAB.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true + proverAB.prove(propTree, ctx, fakeMessage).isFailure shouldBe true val proverABC = proverAB.withSecrets(Seq(proverC.dlogSecrets.head)) - val prABC = proverABC.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prABC, fakeMessage).get._1 shouldBe true + val prABC = proverABC.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prABC, fakeMessage).get._1 shouldBe true val proverABD = proverAB.withSecrets(Seq(proverC.dlogSecrets.head)) - val prABD = proverABD.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prABD, fakeMessage).get._1 shouldBe true + val prABD = proverABD.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prABD, fakeMessage).get._1 shouldBe true } property("complex sig scheme - OR of two ORs") { @@ -402,10 +412,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyD = proverD.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC, "pubkeyD" -> pubkeyD) - val compiledProp = compile(env, """(pubkeyA || pubkeyB) || (pubkeyC || pubkeyD)""").asSigmaProp + val prop = compile(env, """(pubkeyA || pubkeyB) || (pubkeyC || pubkeyD)""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaOr(SigmaOr(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD)) - compiledProp shouldBe prop + val propExpected = SigmaOr(SigmaOr(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD)) + prop shouldBe propExpected val ctx = ErgoLikeContextTesting( currentHeight = 1, @@ -415,17 +426,17 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA = proverA.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prA, fakeMessage).get._1 shouldBe true + val prA = proverA.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prA, fakeMessage).get._1 shouldBe true - val prB = proverB.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prB, fakeMessage).get._1 shouldBe true + val prB = proverB.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prB, fakeMessage).get._1 shouldBe true - val prC = proverC.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prC, fakeMessage).get._1 shouldBe true + val prC = proverC.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prC, fakeMessage).get._1 shouldBe true - val prD = proverD.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prD, fakeMessage).get._1 shouldBe true + val prD = proverD.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, prD, fakeMessage).get._1 shouldBe true } property("complex sig scheme - OR w. predicate") { @@ -439,11 +450,12 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyB = proverB.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB) - val compiledProp = compile(env, """anyOf(Coll(pubkeyA, pubkeyB, HEIGHT > 500))""").asSigmaProp + val prop = compile(env, """anyOf(Coll(pubkeyA, pubkeyB, HEIGHT > 500))""").asSigmaProp + val propTree = mkTestErgoTree(prop) // rewritten by http://github.com/aslesarenko/sigma/blob/2740b51c86bdf1917f688d4ccdb1a0eae9755e0c/sigma-library/src/main/scala/scalan/SigmaLibrary.scala#L91 - val prop = SigmaOr(GT(Height, IntConstant(500)).toSigmaProp, SigmaOr(pubkeyA, pubkeyB)) - compiledProp shouldBe prop + val propExpected = SigmaOr(GT(Height, IntConstant(500)).toSigmaProp, SigmaOr(pubkeyA, pubkeyB)) + prop shouldBe propExpected val ctx1 = ErgoLikeContextTesting( currentHeight = 1, @@ -452,11 +464,12 @@ class ComplexSigSpecification extends SigmaTestingCommons boxesToSpend = IndexedSeq(fakeSelf), spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA = proverA.prove(compiledProp, ctx1, fakeMessage).get - verifier.verify(compiledProp, ctx1, prA, fakeMessage).get._1 shouldBe true - val prB = proverB.prove(compiledProp, ctx1, fakeMessage).get - verifier.verify(compiledProp, ctx1, prB, fakeMessage).get._1 shouldBe true - proverC.prove(compiledProp, ctx1, fakeMessage).isFailure shouldBe true + + val prA = proverA.prove(propTree, ctx1, fakeMessage).get + verifier.verify(propTree, ctx1, prA, fakeMessage).get._1 shouldBe true + val prB = proverB.prove(propTree, ctx1, fakeMessage).get + verifier.verify(propTree, ctx1, prB, fakeMessage).get._1 shouldBe true + proverC.prove(propTree, ctx1, fakeMessage).isFailure shouldBe true val ctx2 = ErgoLikeContextTesting( currentHeight = 501, @@ -465,8 +478,9 @@ class ComplexSigSpecification extends SigmaTestingCommons boxesToSpend = IndexedSeq(fakeSelf), spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prC = proverC.prove(compiledProp, ctx2, fakeMessage).get - verifier.verify(compiledProp, ctx2, prC, fakeMessage).get._1 shouldBe true + + val prC = proverC.prove(propTree, ctx2, fakeMessage).get + verifier.verify(propTree, ctx2, prC, fakeMessage).get._1 shouldBe true } property("complex sig scheme - OR of OR and AND w. predicate, parentheses") { @@ -481,11 +495,12 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyC = proverC.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC) - val compiledProp = compile(env, + val prop = compile(env, """anyOf(Coll(pubkeyA || pubkeyB, pubkeyC && HEIGHT > 500))""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaOr(SigmaOr(pubkeyA, pubkeyB), SigmaAnd(pubkeyC, GT(Height, IntConstant(500)).toSigmaProp)) - compiledProp shouldBe prop + val propExpected = SigmaOr(SigmaOr(pubkeyA, pubkeyB), SigmaAnd(pubkeyC, GT(Height, IntConstant(500)).toSigmaProp)) + prop shouldBe propExpected val ctx1 = ErgoLikeContextTesting( currentHeight = 1, @@ -495,11 +510,11 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA = proverA.prove(compiledProp, ctx1, fakeMessage).get - verifier.verify(compiledProp, ctx1, prA, fakeMessage).get._1 shouldBe true - val prB = proverB.prove(compiledProp, ctx1, fakeMessage).get - verifier.verify(compiledProp, ctx1, prB, fakeMessage).get._1 shouldBe true - proverC.prove(compiledProp, ctx1, fakeMessage).isFailure shouldBe true + val prA = proverA.prove(propTree, ctx1, fakeMessage).get + verifier.verify(propTree, ctx1, prA, fakeMessage).get._1 shouldBe true + val prB = proverB.prove(propTree, ctx1, fakeMessage).get + verifier.verify(propTree, ctx1, prB, fakeMessage).get._1 shouldBe true + proverC.prove(propTree, ctx1, fakeMessage).isFailure shouldBe true val ctx2 = ErgoLikeContextTesting( @@ -510,12 +525,12 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA2 = proverA.prove(compiledProp, ctx2, fakeMessage).get - verifier.verify(compiledProp, ctx2, prA2, fakeMessage).get._1 shouldBe true - val prB2 = proverB.prove(compiledProp, ctx2, fakeMessage).get - verifier.verify(compiledProp, ctx2, prB2, fakeMessage).get._1 shouldBe true - val prC2 = proverC.prove(compiledProp, ctx2, fakeMessage).get - verifier.verify(compiledProp, ctx2, prC2, fakeMessage).get._1 shouldBe true + val prA2 = proverA.prove(propTree, ctx2, fakeMessage).get + verifier.verify(propTree, ctx2, prA2, fakeMessage).get._1 shouldBe true + val prB2 = proverB.prove(propTree, ctx2, fakeMessage).get + verifier.verify(propTree, ctx2, prB2, fakeMessage).get._1 shouldBe true + val prC2 = proverC.prove(propTree, ctx2, fakeMessage).get + verifier.verify(propTree, ctx2, prC2, fakeMessage).get._1 shouldBe true } property("complex sig scheme - OR of OR and AND w. predicate, no parentheses") { @@ -530,10 +545,11 @@ class ComplexSigSpecification extends SigmaTestingCommons val pubkeyC = proverC.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC) - val compiledProp = compile(env, """pubkeyA || pubkeyB || (pubkeyC && HEIGHT > 500)""").asSigmaProp + val prop = compile(env, """pubkeyA || pubkeyB || (pubkeyC && HEIGHT > 500)""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaOr(SigmaOr(pubkeyA, pubkeyB), SigmaAnd(pubkeyC, GT(Height, IntConstant(500)).toSigmaProp)) - compiledProp shouldBe prop + val propExpected = SigmaOr(SigmaOr(pubkeyA, pubkeyB), SigmaAnd(pubkeyC, GT(Height, IntConstant(500)).toSigmaProp)) + prop shouldBe propExpected val ctx1 = ErgoLikeContextTesting( currentHeight = 1, @@ -543,11 +559,11 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA = proverA.prove(compiledProp, ctx1, fakeMessage).get - verifier.verify(compiledProp, ctx1, prA, fakeMessage).get._1 shouldBe true - val prB = proverB.prove(compiledProp, ctx1, fakeMessage).get - verifier.verify(compiledProp, ctx1, prB, fakeMessage).get._1 shouldBe true - proverC.prove(compiledProp, ctx1, fakeMessage).isFailure shouldBe true + val prA = proverA.prove(propTree, ctx1, fakeMessage).get + verifier.verify(propTree, ctx1, prA, fakeMessage).get._1 shouldBe true + val prB = proverB.prove(propTree, ctx1, fakeMessage).get + verifier.verify(propTree, ctx1, prB, fakeMessage).get._1 shouldBe true + proverC.prove(propTree, ctx1, fakeMessage).isFailure shouldBe true val ctx2 = ErgoLikeContextTesting( @@ -558,12 +574,12 @@ class ComplexSigSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA2 = proverA.prove(compiledProp, ctx2, fakeMessage).get - verifier.verify(compiledProp, ctx2, prA2, fakeMessage).get._1 shouldBe true - val prB2 = proverB.prove(compiledProp, ctx2, fakeMessage).get - verifier.verify(compiledProp, ctx2, prB2, fakeMessage).get._1 shouldBe true - val prC2 = proverC.prove(compiledProp, ctx2, fakeMessage).get - verifier.verify(compiledProp, ctx2, prC2, fakeMessage).get._1 shouldBe true + val prA2 = proverA.prove(propTree, ctx2, fakeMessage).get + verifier.verify(propTree, ctx2, prA2, fakeMessage).get._1 shouldBe true + val prB2 = proverB.prove(propTree, ctx2, fakeMessage).get + verifier.verify(propTree, ctx2, prB2, fakeMessage).get._1 shouldBe true + val prC2 = proverC.prove(propTree, ctx2, fakeMessage).get + verifier.verify(propTree, ctx2, prC2, fakeMessage).get._1 shouldBe true } property("complex sig scheme - k-out-of-n threshold") { @@ -584,7 +600,7 @@ class ComplexSigSpecification extends SigmaTestingCommons val prop = COR( kNumKeysCombinations.map(combs => CAND(combs.map(_.publicImage))) ) - + val propTree = mkTestErgoTree(prop) val ctx = ErgoLikeContextTesting( currentHeight = 1, lastBlockUtxoRoot = AvlTreeData.dummy, @@ -594,7 +610,7 @@ class ComplexSigSpecification extends SigmaTestingCommons self = fakeSelf, activatedVersionInTests) // any prover alone (no added secrets) should fail - allProvers.foreach(_.prove(prop, ctx, fakeMessage).isFailure shouldBe true) + allProvers.foreach(_.prove(propTree, ctx, fakeMessage).isFailure shouldBe true) for (_ <- 1 to 3) { val shuffledProvers = Random.shuffle(allProvers) @@ -603,14 +619,14 @@ class ComplexSigSpecification extends SigmaTestingCommons for (i <- 1 until neededExtraSecrets) { // provers with less than k secrets should fail prover.withSecrets(shuffledProvers.takeRight(i).map(_.dlogSecrets.head)) - .prove(prop, ctx, fakeMessage).isFailure shouldBe true + .prove(propTree, ctx, fakeMessage).isFailure shouldBe true } // prover with exactly k secrets should succeed val proverWithKSecrets = prover.withSecrets( shuffledProvers.takeRight(neededExtraSecrets).map(_.dlogSecrets.head)) - val prTry = proverWithKSecrets.prove(prop, ctx, fakeMessage) + val prTry = proverWithKSecrets.prove(propTree, ctx, fakeMessage) prTry shouldBe 'success - verifier.verify(prop, ctx, prTry.get, fakeMessage).get._1 shouldBe true + verifier.verify(propTree, ctx, prTry.get, fakeMessage).get._1 shouldBe true } } } @@ -644,14 +660,14 @@ class ComplexSigSpecification extends SigmaTestingCommons val c3 = CTHRESHOLD(2, Seq(unknownPdlog1, unknownPdlog2, unknownPdlog3)) val prop = CTHRESHOLD(2, Seq(c1, c2, c3)) - + val propTree = mkTestErgoTree(prop) val ctx = fakeContext - val pr = prover.prove(prop, ctx, fakeMessage).get + val pr = prover.prove(propTree, ctx, fakeMessage).get - otherProver.prove(prop, ctx, fakeMessage).isFailure shouldBe true + otherProver.prove(propTree, ctx, fakeMessage).isFailure shouldBe true - verifier.verify(prop, ctx, pr, fakeMessage).isSuccess shouldBe true + verifier.verify(propTree, ctx, pr, fakeMessage).isSuccess shouldBe true } } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/ContextEnrichingSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/ContextEnrichingSpecification.scala index b073d0f8ab..e490c71d3f 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/ContextEnrichingSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/ContextEnrichingSpecification.scala @@ -20,25 +20,27 @@ class ContextEnrichingSpecification extends SigmaTestingCommons val pubkey = prover.dlogSecrets.head.publicImage val env = Map("blake" -> Blake2b256(preimage.toArray), "pubkey" -> pubkey) - val compiledScript = compile(env, + val prop = compile(env, """{ | pubkey && blake2b256(getVar[Coll[Byte]](1).get) == blake |} """.stripMargin).asSigmaProp - val prop = SigmaAnd( + val propTree = mkTestErgoTree(prop) + + val propExpected = SigmaAnd( pubkey, EQ(CalcBlake2b256(GetVarByteArray(1).get), ByteArrayConstant(Blake2b256(preimage.toArray))).toSigmaProp ) - compiledScript shouldBe prop + prop shouldBe propExpected val ctx = ErgoLikeContextTesting.dummy(fakeSelf, activatedVersionInTests) - val pr = prover.prove(compiledScript, ctx, fakeMessage).get + val pr = prover.prove(propTree, ctx, fakeMessage).get val ctxv = ctx.withExtension(pr.extension) val verifier = new ErgoLikeTestInterpreter - verifier.verify(env, compiledScript, ctx, pr.proof, fakeMessage).map(_._1).getOrElse(false) shouldBe false //context w/out extensions - verifier.verify(env, compiledScript, ctxv, pr.proof, fakeMessage).get._1 shouldBe true + verifier.verify(env, propTree, ctx, pr.proof, fakeMessage).map(_._1).getOrElse(false) shouldBe false //context w/out extensions + verifier.verify(env, propTree, ctxv, pr.proof, fakeMessage).get._1 shouldBe true } property("context enriching mixed w. crypto 2") { @@ -48,29 +50,30 @@ class ContextEnrichingSpecification extends SigmaTestingCommons val pubkey = prover.dlogSecrets.head.publicImage val env = Map("blake" -> Blake2b256(preimage1.append(preimage2).toArray), "pubkey" -> pubkey) - val compiledScript = compile(env, + val prop = compile(env, """{ | pubkey && blake2b256(getVar[Coll[Byte]](1).get ++ getVar[Coll[Byte]](2).get) == blake |} """.stripMargin).asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaAnd( + val propExpected = SigmaAnd( pubkey, EQ( CalcBlake2b256(Append(GetVarByteArray(1).get, GetVarByteArray(2).get)), ByteArrayConstant(Blake2b256(preimage1.append(preimage2).toArray)) ).toSigmaProp ) - compiledScript shouldBe prop + prop shouldBe propExpected val ctx = ErgoLikeContextTesting.dummy(fakeSelf, activatedVersionInTests) - val pr = prover.prove(compiledScript, ctx, fakeMessage).get + val pr = prover.prove(propTree, ctx, fakeMessage).get val ctxv = ctx.withExtension(pr.extension) val verifier = new ErgoLikeTestInterpreter - verifier.verify(env, compiledScript, ctx, pr.proof, fakeMessage).map(_._1).getOrElse(false) shouldBe false //context w/out extensions - verifier.verify(env, compiledScript, ctxv, pr.proof, fakeMessage).get._1 shouldBe true + verifier.verify(env, propTree, ctx, pr.proof, fakeMessage).map(_._1).getOrElse(false) shouldBe false //context w/out extensions + verifier.verify(env, propTree, ctxv, pr.proof, fakeMessage).get._1 shouldBe true } property("prover enriching context - xor") { @@ -87,24 +90,25 @@ class ContextEnrichingSpecification extends SigmaTestingCommons .withContextExtender(k2, ByteArrayConstant(v2)) val env = Map("k1" -> k1.toInt, "k2" -> k2.toInt, "r" -> r) - val compiledScript = compile(env, + val prop = compile(env, "{ xor(getVar[Coll[Byte]](k1).get, getVar[Coll[Byte]](k2).get) == r }").asBoolValue.toSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = EQ(Xor(GetVarByteArray(k1).get, GetVarByteArray(k2).get), ByteArrayConstant(r)).toSigmaProp - compiledScript shouldBe prop + val propExpected = EQ(Xor(GetVarByteArray(k1).get, GetVarByteArray(k2).get), ByteArrayConstant(r)).toSigmaProp + prop shouldBe propExpected val ctx = ErgoLikeContextTesting.dummy(fakeSelf, activatedVersionInTests) - val pr = prover.prove(prop, ctx, fakeMessage).get + val pr = prover.prove(propTree, ctx, fakeMessage).get val ctxv = ctx.withExtension(pr.extension) val verifier = new ErgoLikeTestInterpreter //context w/out extensions assertExceptionThrown( - verifier.verify(env, prop, ctx, pr.proof, fakeMessage).get, + verifier.verify(env, propTree, ctx, pr.proof, fakeMessage).get, rootCause(_).isInstanceOf[ArrayIndexOutOfBoundsException] ) - verifier.verify(env, prop, ctxv, pr.proof, fakeMessage).get._1 shouldBe true + verifier.verify(env, propTree, ctxv, pr.proof, fakeMessage).get._1 shouldBe true } /** @@ -115,25 +119,26 @@ class ContextEnrichingSpecification extends SigmaTestingCommons val preimage = prover.contextExtenders(1).value.asInstanceOf[Coll[Byte]] val env = Map("blake" -> Blake2b256(preimage.toArray)) - val compiledScript = compile(env, + val prop = compile(env, """{ | blake2b256(getVar[Coll[Byte]](1).get) == blake |} """.stripMargin).asBoolValue.toSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = EQ(CalcBlake2b256(GetVarByteArray(1).get), ByteArrayConstant(Blake2b256(preimage.toArray))).toSigmaProp - compiledScript shouldBe prop + val propExpected = EQ(CalcBlake2b256(GetVarByteArray(1).get), ByteArrayConstant(Blake2b256(preimage.toArray))).toSigmaProp + prop shouldBe propExpected val ctx = ErgoLikeContextTesting.dummy(fakeSelf, activatedVersionInTests) - val pr = prover.prove(prop, ctx, fakeMessage).get + val pr = prover.prove(propTree, ctx, fakeMessage).get val ctxv = ctx.withExtension(pr.extension) val verifier = new ErgoLikeTestInterpreter //context w/out extensions - assertExceptionThrown(verifier.verify(env, prop, ctx, pr.proof, fakeMessage).get, + assertExceptionThrown(verifier.verify(env, propTree, ctx, pr.proof, fakeMessage).get, rootCause(_).isInstanceOf[ArrayIndexOutOfBoundsException]) - verifier.verify(env, prop, ctxv, pr.proof, fakeMessage).get._1 shouldBe true + verifier.verify(env, propTree, ctxv, pr.proof, fakeMessage).get._1 shouldBe true } property("prover enriching context 2") { @@ -142,27 +147,28 @@ class ContextEnrichingSpecification extends SigmaTestingCommons val preimage2 = prover.contextExtenders(2).value.asInstanceOf[Coll[Byte]] val env = Map("blake" -> Blake2b256(preimage2.append(preimage1).toArray)) - val compiledScript = compile(env, + val prop = compile(env, """{ | blake2b256(getVar[Coll[Byte]](2).get ++ getVar[Coll[Byte]](1).get) == blake |} """.stripMargin).asBoolValue.toSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = EQ(CalcBlake2b256(Append(GetVarByteArray(2).get, GetVarByteArray(1).get)), + val propExpected = EQ(CalcBlake2b256(Append(GetVarByteArray(2).get, GetVarByteArray(1).get)), ByteArrayConstant(Blake2b256(preimage2.append(preimage1).toArray))).toSigmaProp - compiledScript shouldBe prop + prop shouldBe propExpected val ctx = ErgoLikeContextTesting.dummy(fakeSelf, activatedVersionInTests) - val pr = prover.prove(prop, ctx, fakeMessage).get + val pr = prover.prove(propTree, ctx, fakeMessage).get val ctxv = ctx.withExtension(pr.extension) val verifier = new ErgoLikeTestInterpreter //context w/out extensions assertExceptionThrown( - verifier.verify(env, prop, ctx, pr.proof, fakeMessage).get, + verifier.verify(env, propTree, ctx, pr.proof, fakeMessage).get, rootCause(_).isInstanceOf[ArrayIndexOutOfBoundsException] ) - verifier.verify(env, prop, ctxv, pr.proof, fakeMessage).get._1 shouldBe true + verifier.verify(env, propTree, ctxv, pr.proof, fakeMessage).get._1 shouldBe true } } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/DistributedSigSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/DistributedSigSpecification.scala index 008ce2dd0b..6b9d79e4d6 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/DistributedSigSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/DistributedSigSpecification.scala @@ -42,9 +42,9 @@ class DistributedSigSpecification extends SigmaTestingCommons val pubkeyBob = proverB.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyAlice, "pubkeyB" -> pubkeyBob) - val prop: Values.Value[SSigmaProp.type] = compile(env, """pubkeyA && pubkeyB""").asSigmaProp + val prop = mkTestErgoTree(compile(env, """pubkeyA && pubkeyB""").asSigmaProp) - val hintsFromBob: HintsBag = proverB.generateCommitments(prop.treeWithSegregation, ctx) + val hintsFromBob: HintsBag = proverB.generateCommitments(prop, ctx) val bagA = HintsBag(hintsFromBob.realCommitments) val proofAlice = proverA.prove(prop, ctx, fakeMessage, bagA).get @@ -74,10 +74,10 @@ class DistributedSigSpecification extends SigmaTestingCommons val pubkeyCarol = proverC.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyAlice, "pubkeyB" -> pubkeyBob, "pubkeyC" -> pubkeyCarol) - val prop: Values.Value[SSigmaProp.type] = compile(env, """pubkeyA && pubkeyB && pubkeyC""").asSigmaProp + val prop = mkTestErgoTree(compile(env, """pubkeyA && pubkeyB && pubkeyC""").asSigmaProp) - val bobHints = proverB.generateCommitments(prop.treeWithSegregation, ctx) - val carolHints = proverC.generateCommitments(prop.treeWithSegregation, ctx) + val bobHints = proverB.generateCommitments(prop, ctx) + val carolHints = proverC.generateCommitments(prop, ctx) val dlBKnown: Hint = bobHints.realCommitments.head val dlCKnown: Hint = carolHints.realCommitments.head @@ -133,9 +133,10 @@ class DistributedSigSpecification extends SigmaTestingCommons val pubkeyCarol = proverC.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyAlice, "pubkeyB" -> pubkeyBob, "pubkeyC" -> pubkeyCarol) - val prop = compile(env, """atLeast(2, Coll(pubkeyA, pubkeyB, pubkeyC))""").asSigmaProp + val prop = mkTestErgoTree( + compile(env, """atLeast(2, Coll(pubkeyA, pubkeyB, pubkeyC))""").asSigmaProp) - val bobHints = proverB.generateCommitments(prop.treeWithSegregation, ctx) + val bobHints = proverB.generateCommitments(prop, ctx) val dlBKnown: Hint = bobHints.realCommitments.head val bagA = HintsBag(Seq(dlBKnown)) @@ -170,13 +171,14 @@ class DistributedSigSpecification extends SigmaTestingCommons val pubkeyDave = proverD.dlogSecrets.head.publicImage val env = Map("pubkeyA" -> pubkeyAlice, "pubkeyB" -> pubkeyBob, "pubkeyC" -> pubkeyCarol, "pubkeyD" -> pubkeyDave) - val prop = compile(env, """atLeast(3, Coll(pubkeyA, pubkeyB, pubkeyC, pubkeyD))""").asSigmaProp + val prop = mkTestErgoTree( + compile(env, """atLeast(3, Coll(pubkeyA, pubkeyB, pubkeyC, pubkeyD))""").asSigmaProp) // Alice, Bob and Carol are signing - val bobHints = proverB.generateCommitments(prop.treeWithSegregation, ctx) + val bobHints = proverB.generateCommitments(prop, ctx) val dlBKnown: Hint = bobHints.realCommitments.head - val carolHints = proverC.generateCommitments(prop.treeWithSegregation, ctx) + val carolHints = proverC.generateCommitments(prop, ctx) val dlCKnown: Hint = carolHints.realCommitments.head val bagA = HintsBag(Seq(dlBKnown, dlCKnown)) @@ -218,14 +220,19 @@ class DistributedSigSpecification extends SigmaTestingCommons val pubkeyCarol = proverC.dhSecrets.head.publicImage val pubkeyDave = proverD.dhSecrets.head.publicImage - val env = Map("pubkeyA" -> pubkeyAlice, "pubkeyB" -> pubkeyBob, "pubkeyC" -> pubkeyCarol, "pubkeyD" -> pubkeyDave) - val prop = compile(env, """atLeast(3, Coll(pubkeyA, pubkeyB, pubkeyC, pubkeyD))""").asSigmaProp + val env = Map( + "pubkeyA" -> pubkeyAlice, + "pubkeyB" -> pubkeyBob, + "pubkeyC" -> pubkeyCarol, + "pubkeyD" -> pubkeyDave) + val prop = mkTestErgoTree( + compile(env, """atLeast(3, Coll(pubkeyA, pubkeyB, pubkeyC, pubkeyD))""").asSigmaProp) // Alice, Bob and Carol are signing - val bobHints = proverB.generateCommitments(prop.treeWithSegregation, ctx) + val bobHints = proverB.generateCommitments(prop, ctx) val dlBKnown: Hint = bobHints.realCommitments.head - val carolHints = proverC.generateCommitments(prop.treeWithSegregation, ctx) + val carolHints = proverC.generateCommitments(prop, ctx) val dlCKnown: Hint = carolHints.realCommitments.head val bagA = HintsBag(Seq(dlBKnown, dlCKnown)) @@ -268,10 +275,11 @@ class DistributedSigSpecification extends SigmaTestingCommons val env = Map("pubkeyA" -> pubkeyAlice, "pubkeyB" -> pubkeyBob, "pubkeyC" -> pubkeyCarol, "pubkeyD" -> pubkeyDave, "pubkeyE" -> pubkeyEmma) - val prop = compile(env, """atLeast(2, Coll(pubkeyA, pubkeyB, pubkeyC, pubkeyD, pubkeyE))""").asSigmaProp + val prop = mkTestErgoTree(compile(env, + """atLeast(2, Coll(pubkeyA, pubkeyB, pubkeyC, pubkeyD, pubkeyE))""").asSigmaProp) //Alice and Dave are signing - val daveHints = proverD.generateCommitments(prop.treeWithSegregation, ctx) + val daveHints = proverD.generateCommitments(prop, ctx) val dlDKnown: Hint = daveHints.realCommitments.head val bagA = HintsBag(Seq(dlDKnown)) @@ -313,25 +321,25 @@ class DistributedSigSpecification extends SigmaTestingCommons "pubkeyD" -> pubkeyDave, "pubkeyE" -> pubkeyEmma, "pubkeyF" -> pubkeyFrank, "pubkeyG" -> pubkeyGerard, "pubkeyH" -> pubkeyHannah) val script = """atLeast(4, Coll(pubkeyA, pubkeyB, pubkeyC, pubkeyD, pubkeyE, pubkeyF, pubkeyG, pubkeyH))""" - val prop = compile(env, script).asSigmaProp + val prop = mkTestErgoTree(compile(env, script).asSigmaProp) // Alice, Bob, Gerard, and Hannah are signing, others are simulated // first, commitments are needed from real signers - val aliceHints = proverA.generateCommitments(prop.treeWithSegregation, ctx) + val aliceHints = proverA.generateCommitments(prop, ctx) val dlAKnown: Hint = aliceHints.realCommitments.head val secretCmtA: Hint = aliceHints.ownCommitments.head - val bobHints = proverB.generateCommitments(prop.treeWithSegregation, ctx) + val bobHints = proverB.generateCommitments(prop, ctx) val dlBKnown: Hint = bobHints.realCommitments.head val secretCmtB: Hint = bobHints.ownCommitments.head - val gerardHints = proverG.generateCommitments(prop.treeWithSegregation, ctx) + val gerardHints = proverG.generateCommitments(prop, ctx) val dlGKnown: Hint = gerardHints.realCommitments.head val secretCmtG: Hint = gerardHints.ownCommitments.head - val hannahHints = proverH.generateCommitments(prop.treeWithSegregation, ctx) + val hannahHints = proverH.generateCommitments(prop, ctx) val secretCmtH: Hint = hannahHints.ownCommitments.head val bagH = HintsBag(Seq(dlAKnown, dlBKnown, dlGKnown, secretCmtH)) @@ -396,16 +404,16 @@ class DistributedSigSpecification extends SigmaTestingCommons val env = Map("pubkeyA" -> pubkeyAlice, "pubkeyB" -> pubkeyBob, "pubkeyC" -> pubkeyCarol, "pubkeyD" -> pubkeyDave) val script = """(pubkeyA || pubkeyB) && (pubkeyC || pubkeyD)""" - val prop = compile(env, script).asSigmaProp + val prop = mkTestErgoTree(compile(env, script).asSigmaProp) //Alice and Dave are signing //first, commitments are needed from real signers - val aliceHints = proverA.generateCommitments(prop.treeWithSegregation, ctx) + val aliceHints = proverA.generateCommitments(prop, ctx) println(aliceHints) val secretCmtA: Hint = aliceHints.ownCommitments.head - val daveHints = proverD.generateCommitments(prop.treeWithSegregation, ctx) + val daveHints = proverD.generateCommitments(prop, ctx) val dlDKnown: Hint = daveHints.realCommitments.head val secretCmtD: Hint = daveHints.ownCommitments.head @@ -445,19 +453,19 @@ class DistributedSigSpecification extends SigmaTestingCommons "pubkeyD" -> pubkeyDave, "pubkeyE" -> pubkeyEmma, "pubkeyF" -> pubkeyFrank) val script = """atLeast(3, Coll(pubkeyA, pubkeyB, pubkeyC, pubkeyD, pubkeyE)) && (pubkeyB || pubkeyF)""".stripMargin - val prop = compile(env, script).asSigmaProp + val prop = mkTestErgoTree(compile(env, script).asSigmaProp) // Alice, Bob and Emma are signing // first, commitments are needed from real signers - val aliceHints = proverA.generateCommitments(prop.treeWithSegregation, ctx) + val aliceHints = proverA.generateCommitments(prop, ctx) val dlAKnown: Hint = aliceHints.realCommitments.head val secretCmtA: Hint = aliceHints.ownCommitments.head - val bobHints = proverB.generateCommitments(prop.treeWithSegregation, ctx) + val bobHints = proverB.generateCommitments(prop, ctx) val dlBKnown: Seq[Hint] = bobHints.realCommitments val secretCmtB: Seq[Hint] = bobHints.ownCommitments - val emmaHints = proverE.generateCommitments(prop.treeWithSegregation, ctx) + val emmaHints = proverE.generateCommitments(prop, ctx) val dlEKnown: Hint = emmaHints.realCommitments.head val secretCmtE: Hint = emmaHints.ownCommitments.head @@ -492,4 +500,33 @@ class DistributedSigSpecification extends SigmaTestingCommons verifier.verify(prop, ctx, validProofB, fakeMessage).get._1 shouldBe true } + property("distributed message signing - AND (2 out of 2)") { + val ctx = fakeContext + val proverA = new ErgoLikeTestProvingInterpreter + val proverB = new ErgoLikeTestProvingInterpreter + val verifier: ContextEnrichingTestProvingInterpreter = new ContextEnrichingTestProvingInterpreter + + val msg = "Let's have a deal".getBytes("UTF-8") + + val pubkeyAlice = proverA.dlogSecrets.head.publicImage + val pubkeyBob = proverB.dlogSecrets.head.publicImage + + val sigmaTree = CAND(Seq(pubkeyAlice, pubkeyBob)) + + val hintsFromBob: HintsBag = proverB.generateCommitments(sigmaTree) + val bagA = HintsBag(hintsFromBob.realCommitments) + + val sigAlice = proverA.signMessage(sigmaTree, msg, bagA).get + + val bagB = proverB.bagForMultisig(ctx, sigmaTree, sigAlice, Seq(pubkeyAlice)) + .addHint(hintsFromBob.ownCommitments.head) + + val sigBob = proverB.signMessage(sigmaTree, msg, bagB).get + + // Proof generated by Alice without getting Bob's part is not correct + verifier.verifySignature(sigmaTree, msg, sigAlice) shouldBe false + + // Compound proof from Bob is correct + verifier.verifySignature(sigmaTree, msg, sigBob) shouldBe true + } } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala index 3ea0bf0058..c53345bfd0 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala @@ -7,14 +7,13 @@ import org.ergoplatform.validation.ValidationException import org.scalatest.TryValues._ import scorex.crypto.hash.Blake2b256 import sigmastate.SCollection.SByteArray -import sigmastate.TrivialProp.{FalseProp, TrueProp} import sigmastate.Values._ import sigmastate._ import sigmastate.eval._ import sigmastate.interpreter.Interpreter._ import sigmastate.basics.DLogProtocol.ProveDlog import sigmastate.basics.ProveDHTuple -import sigmastate.helpers.{ErgoLikeTransactionTesting, ErgoLikeContextTesting, ErgoLikeTestInterpreter, ErgoLikeTestProvingInterpreter, SigmaTestingCommons, ContextEnrichingTestProvingInterpreter} +import sigmastate.helpers._ import sigmastate.helpers.TestingHelpers._ import sigmastate.interpreter.{ContextExtension, CostedProverResult} import sigmastate.lang.Terms._ @@ -39,17 +38,20 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val ctx = ErgoLikeContextTesting.dummy(fakeSelf, activatedVersionInTests) - val e = compile(Map("h1" -> h1.treeWithSegregation.bytes, "h2" -> h2.treeWithSegregation.bytes), "h1 == h1") + val e = compile(Map( + "h1" -> h1.treeWithSegregation(ergoTreeHeaderInTests).bytes, + "h2" -> h2.treeWithSegregation(ergoTreeHeaderInTests).bytes), + "h1 == h1") val exp = TrueLeaf e shouldBe exp val res = verifier.reduceToCrypto(ctx, exp).get._1 - res shouldBe TrueProp + res shouldBe TrivialProp.TrueProp val res2 = verifier.reduceToCrypto(ctx, - EQ(ByteArrayConstant(h1.treeWithSegregation.bytes), - ByteArrayConstant(h2.treeWithSegregation.bytes))).get._1 - res2 shouldBe FalseProp + EQ(ByteArrayConstant(h1.treeWithSegregation(ergoTreeHeaderInTests).bytes), + ByteArrayConstant(h2.treeWithSegregation(ergoTreeHeaderInTests).bytes))).get._1 + res2 shouldBe TrivialProp.FalseProp } property("DH tuple") { @@ -63,6 +65,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val ci = secret.commonInput val prop = SigmaPropConstant(ProveDHTuple(ci.g, ci.h, ci.u, ci.v)) + val propTree = mkTestErgoTree(prop) + val wrongProp = SigmaPropConstant(ProveDHTuple(ci.g, ci.h, ci.u, ci.u)) val env = Map("g" -> ci.g, "h" -> ci.h, "u" -> ci.u, "v" -> ci.v, "s" -> secret.publicImage) @@ -80,11 +84,11 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val pr = prover.prove(prop, ctx, fakeMessage).get - verifier.verify(prop, ctx, pr, fakeMessage).get._1 shouldBe true + val pr = prover.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage).get._1 shouldBe true - fakeProver.prove(prop, ctx, fakeMessage).isSuccess shouldBe false - prover.prove(wrongProp, ctx, fakeMessage).isSuccess shouldBe false + fakeProver.prove(propTree, ctx, fakeMessage).isSuccess shouldBe false + prover.prove(mkTestErgoTree(wrongProp), ctx, fakeMessage).isSuccess shouldBe false } property("DH tuple - simulation") { @@ -98,6 +102,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val env = Map("pubkeyA" -> pubkeyA, "pubdhB" -> pubdhB) val compiledProp = compile(env, """pubkeyA || pubdhB""").asSigmaProp + val compiledPropTree = mkTestErgoTree(compiledProp) val prop = SigmaOr(pubkeyA, pubdhB) compiledProp shouldBe prop @@ -110,8 +115,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA = proverA.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prA, fakeMessage).get._1 shouldBe true + val prA = proverA.prove(compiledPropTree, ctx, fakeMessage).get + verifier.verify(compiledPropTree, ctx, prA, fakeMessage).get._1 shouldBe true } property("DH tuple and DLOG") { @@ -125,6 +130,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val env = Map("pubkeyA" -> pubkeyA, "pubdhA" -> pubdhA) val compiledProp = compile(env, """pubkeyA && pubdhA""").asSigmaProp + val compiledPropTree = mkTestErgoTree(compiledProp) val prop = SigmaAnd(pubkeyA, pubdhA) compiledProp shouldBe prop @@ -137,11 +143,11 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val prA = proverA.prove(compiledProp, ctx, fakeMessage).get + val prA = proverA.prove(compiledPropTree, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, prA, fakeMessage).get._1 shouldBe true + verifier.verify(compiledPropTree, ctx, prA, fakeMessage).get._1 shouldBe true - proverB.prove(compiledProp, ctx, fakeMessage).isSuccess shouldBe false + proverB.prove(compiledPropTree, ctx, fakeMessage).isSuccess shouldBe false } // related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/428 @@ -159,8 +165,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val pubkeyB = proverB.dlogSecrets.head.publicImage val pubkeyB2 = proverB.dlogSecrets.head.publicImage - val newBox1 = new ErgoBoxCandidate(10, pubkeyB2, height) - val newBox2 = new ErgoBoxCandidate(10, pubkeyA2, height) + val newBox1 = new ErgoBoxCandidate(10, mkTestErgoTree(pubkeyB2), height) + val newBox2 = new ErgoBoxCandidate(10, mkTestErgoTree(pubkeyA2), height) val newBoxes = IndexedSeq(newBox1, newBox2) @@ -170,7 +176,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val spendingTransaction = createTransaction(newBoxes) - def mixingRequestProp(sender: ProveDlog, timeout: Int) = { + def mixingRequestProp(sender: ProveDlog, timeout: Int): ErgoTree = { val env = Map("sender" -> sender, "timeout" -> timeout, "properHash" -> properHash) val compiledProp = compile(env, """{ @@ -181,7 +187,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons | notTimePassed && blake2b256(outSumBytes) == properHash || timePassed && sender }""".stripMargin).asSigmaProp - compiledProp + mkTestErgoTree(compiledProp) } val ctx = ErgoLikeContextTesting( @@ -220,6 +226,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val verifier = new ErgoLikeTestInterpreter val pubkey = prover.dlogSecrets.head.publicImage + val pubkeyTree = mkTestErgoTree(pubkey) val env = Map("pubkey" -> pubkey) val prop = compile(env, @@ -227,6 +234,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons | val outValues = OUTPUTS.map({ (box: Box) => box.value }) | pubkey && outValues.fold(0L, { (x: Long, y: Long) => x + y }) > 20 }""".stripMargin).asSigmaProp + val propTree = mkTestErgoTree(prop) val propExp = SigmaAnd( Seq( @@ -241,8 +249,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons ) prop shouldBe propExp - val newBox1 = testBox(11, pubkey, 0) - val newBox2 = testBox(10, pubkey, 0) + val newBox1 = testBox(11, pubkeyTree, 0) + val newBox2 = testBox(10, pubkeyTree, 0) val newBoxes = IndexedSeq(newBox1, newBox2) val spendingTransaction = createTransaction(newBoxes) @@ -255,8 +263,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction, self = fakeSelf, activatedVersionInTests) - val pr = prover.prove(prop, ctx, fakeMessage).get - verifier.verify(prop, ctx, pr, fakeMessage) + val pr = prover.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage).getOrThrow } property("byindex") { @@ -264,15 +272,17 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val verifier = new ErgoLikeTestInterpreter val pubkey = prover.dlogSecrets.head.publicImage + val pubkeyTree = mkTestErgoTree(pubkey) val env = Map("pubkey" -> pubkey) - val compiledProp = compile(env, """pubkey && OUTPUTS(0).value > 10""").asSigmaProp + val prop = compile(env, """pubkey && OUTPUTS(0).value > 10""").asSigmaProp + val propTree = mkTestErgoTree(prop) - val prop = SigmaAnd(pubkey, BoolToSigmaProp(GT(ExtractAmount(ByIndex(Outputs, 0)), LongConstant(10)))) - compiledProp shouldBe prop + val propExp = SigmaAnd(pubkey, BoolToSigmaProp(GT(ExtractAmount(ByIndex(Outputs, 0)), LongConstant(10)))) + prop shouldBe propExp - val newBox1 = testBox(11, pubkey, 0) - val newBox2 = testBox(10, pubkey, 0) + val newBox1 = testBox(11, pubkeyTree, 0) + val newBox2 = testBox(10, pubkeyTree, 0) val newBoxes = IndexedSeq(newBox1, newBox2) val spendingTransaction = createTransaction(newBoxes) @@ -285,15 +295,15 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction, self = fakeSelf, activatedVersionInTests) - val pr = prover.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, pr, fakeMessage) + val pr = prover.prove(propTree, ctx, fakeMessage).get + verifier.verify(propTree, ctx, pr, fakeMessage).getOrThrow val fProp1 = SigmaAnd(pubkey, GT(ExtractAmount(ByIndex(Outputs, 0)), LongConstant(11))) - prover.prove(fProp1, ctx, fakeMessage).isSuccess shouldBe false + prover.prove(mkTestErgoTree(fProp1), ctx, fakeMessage).isSuccess shouldBe false val fProp2 = SigmaAnd(pubkey, GT(ExtractAmount(ByIndex(Outputs, 1)), LongConstant(11))) - prover.prove(fProp2, ctx, fakeMessage).isSuccess shouldBe false + prover.prove(mkTestErgoTree(fProp2), ctx, fakeMessage).isSuccess shouldBe false } property("P2SH") { @@ -310,20 +320,21 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val hashEquals = EQ(CalcBlake2b256(GetVarByteArray(scriptId).get), scriptHash) val scriptIsCorrect = DeserializeContext(scriptId, SSigmaProp) val prop = SigmaAnd(hashEquals, scriptIsCorrect) + val propTree = mkTestErgoTree(prop) val recipientProposition = SigmaPropConstant(new ContextEnrichingTestProvingInterpreter().dlogSecrets.head.publicImage) - val selfBox = testBox(20, ErgoScriptPredef.TrueProp, 0, Seq(), Map()) + val selfBox = testBox(20, TrueTree, 0, Seq(), Map()) val ctx = ErgoLikeContextTesting( currentHeight = 50, lastBlockUtxoRoot = AvlTreeData.dummy, minerPubkey = ErgoLikeContextTesting.dummyPubkey, boxesToSpend = IndexedSeq(selfBox), - createTransaction(testBox(1, recipientProposition, 0)), + createTransaction(testBox(1, mkTestErgoTree(recipientProposition), 0)), self = selfBox, activatedVersionInTests) - val proof = prover.prove(prop, ctx, fakeMessage).get + val proof = prover.prove(propTree, ctx, fakeMessage).get - (new ErgoLikeTestInterpreter).verify(prop, ctx, proof, fakeMessage).get._1 shouldBe true + (new ErgoLikeTestInterpreter).verify(propTree, ctx, proof, fakeMessage).get._1 shouldBe true } property("Prove keys from registers") { @@ -343,17 +354,18 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons | val pubkey2 = SELF.R5[GroupElement].get | proveDlog(pubkey1) && proveDlog(pubkey2) |}""".stripMargin).asSigmaProp + val propTree = mkTestErgoTree(prop) - val propTree = SigmaAnd( + val propExpected = SigmaAnd( CreateProveDlog(ExtractRegisterAs[SGroupElement.type](Self, regPubkey1).get), CreateProveDlog(ExtractRegisterAs[SGroupElement.type](Self, regPubkey2).get)) - prop shouldBe propTree + prop shouldBe propExpected - val newBox1 = testBox(10, pubkey3, 0) + val newBox1 = testBox(10, mkTestErgoTree(pubkey3), 0) val newBoxes = IndexedSeq(newBox1) val spendingTransaction = createTransaction(newBoxes) - val s1 = testBox(20, ErgoScriptPredef.TrueProp, 0, Seq(), + val s1 = testBox(20, TrueTree, 0, Seq(), Map(regPubkey1 -> GroupElementConstant(pubkey1.value), regPubkey2 -> GroupElementConstant(pubkey2.value))) @@ -365,12 +377,12 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction, self = s1, activatedVersionInTests) - val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).getOrThrow - verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true + val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), propTree, ctx, fakeMessage).getOrThrow + verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), propTree, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true //make sure that wrong case couldn't be proved - val s2 = testBox(20, ErgoScriptPredef.TrueProp, 0, Seq(), + val s2 = testBox(20, TrueTree, 0, Seq(), Map(regPubkey1 -> GroupElementConstant(pubkey1.value))) val wrongCtx = ErgoLikeContextTesting( currentHeight = 50, @@ -380,8 +392,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction, self = s2, activatedVersionInTests) - prover.prove(prop, wrongCtx, fakeMessage).isFailure shouldBe true - verifier.verify(prop, wrongCtx, pr, fakeMessage).isFailure shouldBe true + prover.prove(propTree, wrongCtx, fakeMessage).isFailure shouldBe true + verifier.verify(propTree, wrongCtx, pr, fakeMessage).isFailure shouldBe true } //p2sh with 160-bit hash function (which is about just cutting first 160 bits from 256-bit hash) @@ -404,20 +416,21 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons scriptHash) val scriptIsCorrect = DeserializeContext(scriptId, SSigmaProp) val prop = SigmaAnd(hashEquals.toSigmaProp, scriptIsCorrect) + val propTree = mkTestErgoTree(prop) - val recipientProposition = new ContextEnrichingTestProvingInterpreter().dlogSecrets.head.publicImage - val selfBox = testBox(20, TrueProp, 0, Seq(), Map()) + val recipientPubkey = new ContextEnrichingTestProvingInterpreter().dlogSecrets.head.publicImage + val selfBox = testBox(20, TrueTree, 0, Seq(), Map()) val ctx = ErgoLikeContextTesting( currentHeight = 50, lastBlockUtxoRoot = AvlTreeData.dummy, minerPubkey = ErgoLikeContextTesting.dummyPubkey, boxesToSpend = IndexedSeq(selfBox), - createTransaction(testBox(1, recipientProposition, 0)), + createTransaction(testBox(1, mkTestErgoTree(recipientPubkey), 0)), self = selfBox, activatedVersionInTests) - val proof = prover.prove(prop, ctx, fakeMessage).get + val proof = prover.prove(propTree, ctx, fakeMessage).get - (new ErgoLikeTestInterpreter).verify(prop, ctx, proof, fakeMessage).get._1 shouldBe true + (new ErgoLikeTestInterpreter).verify(propTree, ctx, proof, fakeMessage).get._1 shouldBe true } @@ -432,10 +445,13 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val pubkey1 = prover.dlogSecrets.head.publicImage val pubkey2 = prover.dlogSecrets(1).publicImage - val brother = testBox(10, pubkey1, 0) - val brotherWithWrongId = testBox(10, pubkey1, 0, boxIndex = 120: Short) + val brother = testBox(value = 10, ergoTree = mkTestErgoTree(pubkey1), creationHeight = 0) + val brotherWithWrongId = testBox(value = 10, + ergoTree = mkTestErgoTree(pubkey1), + creationHeight = 0, + boxIndex = 120: Short) - val newBox = testBox(20, pubkey2, 0) + val newBox = testBox(20, mkTestErgoTree(pubkey2), 0) val newBoxes = IndexedSeq(newBox) val spendingTransaction = createTransaction(newBoxes) @@ -447,6 +463,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons | val okIds = INPUTS(0).id == brother.id | okInputs && okIds }""".stripMargin).asBoolValue.toSigmaProp + val propTree = mkTestErgoTree(prop) val propExpected = BinAnd( EQ(SizeOf(Inputs), IntConstant(2)), @@ -458,7 +475,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val altProp = compile(altEnv, """INPUTS.size == 2 && INPUTS(0).id == friend.id""").asBoolValue.toSigmaProp altProp shouldBe prop - val s = testBox(10, prop, 0, Seq(), Map()) + val s = testBox(10, propTree, 0, Seq(), Map()) val ctx = ErgoLikeContextTesting( currentHeight = 50, @@ -468,8 +485,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction, self = s, activatedVersionInTests) - val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove_prop"), prop, ctx, fakeMessage).getOrThrow - verifier.verify(emptyEnv + (ScriptNameProp -> "verify_prop"), prop, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true + val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove_prop"), propTree, ctx, fakeMessage).getOrThrow + verifier.verify(emptyEnv + (ScriptNameProp -> "verify_prop"), propTree, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true val wrongCtx = ErgoLikeContextTesting( currentHeight = 50, @@ -479,8 +496,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction, self = s, activatedVersionInTests) - prover.prove(prop, wrongCtx, fakeMessage).isFailure shouldBe true - verifier.verify(prop, wrongCtx, pr, fakeMessage).getOrThrow._1 shouldBe false + prover.prove(propTree, wrongCtx, fakeMessage).isFailure shouldBe true + verifier.verify(propTree, wrongCtx, pr, fakeMessage).getOrThrow._1 shouldBe false val prop2 = compile(env, """{ @@ -488,10 +505,11 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons | val okIds = INPUTS(0).id == brother.id | okInputs && okIds }""".stripMargin).asBoolValue.toSigmaProp + val prop2Tree = mkTestErgoTree(prop2) - prover.prove(emptyEnv + (ScriptNameProp -> "prove_prop2"), prop2, ctx, fakeMessage).isFailure shouldBe true + prover.prove(emptyEnv + (ScriptNameProp -> "prove_prop2"), prop2Tree, ctx, fakeMessage).isFailure shouldBe true verifier - .verify(emptyEnv + (ScriptNameProp -> "verify_prop2"), prop2, ctx, pr, fakeMessage) + .verify(emptyEnv + (ScriptNameProp -> "verify_prop2"), prop2Tree, ctx, pr, fakeMessage) .getOrThrow._1 shouldBe false } @@ -506,10 +524,10 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val pubkey1 = prover.dlogSecrets.head.publicImage val pubkey2 = prover.dlogSecrets(1).publicImage - val friend = testBox(10, pubkey1, 0) - val friendWithWrongId = testBox(10, pubkey1, 0, boxIndex = 120: Short) + val friend = testBox(10, mkTestErgoTree(pubkey1), 0) + val friendWithWrongId = testBox(10, mkTestErgoTree(pubkey1), 0, boxIndex = 120: Short) - val newBox = testBox(20, pubkey2, 0) + val newBox = testBox(20, mkTestErgoTree(pubkey2), 0) val newBoxes = IndexedSeq(newBox) val spendingTransaction = createTransaction(newBoxes) @@ -521,6 +539,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons | def isFriend(inputBox: Box) = inputBox.id == friend.id | INPUTS.exists (isFriend) }""".stripMargin).asBoolValue.toSigmaProp + val propTree = mkTestErgoTree(prop) val propExpected = Exists(Inputs, FuncValue( @@ -538,7 +557,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val altProp = compile(env, "INPUTS.exists ({ (inputBox: Box) => inputBox.id == friend.id })").asBoolValue.toSigmaProp altProp shouldBe prop - val s = testBox(10, prop, 0, Seq(), Map()) + val s = testBox(10, propTree, 0, Seq(), Map()) val ctx1 = ErgoLikeContextTesting( currentHeight = 50, @@ -548,8 +567,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction, self = s, activatedVersionInTests) - val pr1 = prover.prove(prop, ctx1, fakeMessage).success.value - verifier.verify(prop, ctx1, pr1, fakeMessage).success.value._1 shouldBe true + val pr1 = prover.prove(propTree, ctx1, fakeMessage).success.value + verifier.verify(propTree, ctx1, pr1, fakeMessage).success.value._1 shouldBe true val ctx2 = ErgoLikeContextTesting( currentHeight = 50, @@ -559,11 +578,11 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction, self = s, activatedVersionInTests) - val pr2 = prover.prove(prop, ctx2, fakeMessage).success.value - verifier.verify(prop, ctx2, pr2, fakeMessage).success.value._1 shouldBe true + val pr2 = prover.prove(propTree, ctx2, fakeMessage).success.value + verifier.verify(propTree, ctx2, pr2, fakeMessage).success.value._1 shouldBe true - val pr3 = prover.prove(prop, ctx2, fakeMessage).success.value - verifier.verify(prop, ctx2, pr3, fakeMessage).success.value._1 shouldBe true + val pr3 = prover.prove(propTree, ctx2, fakeMessage).success.value + verifier.verify(propTree, ctx2, pr3, fakeMessage).success.value._1 shouldBe true val wrongCtx1 = ErgoLikeContextTesting( currentHeight = 50, @@ -573,8 +592,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction, self = s, activatedVersionInTests) - prover.prove(prop, wrongCtx1, fakeMessage).isFailure shouldBe true - verifier.verify(prop, wrongCtx1, pr1, fakeMessage).success.value._1 shouldBe false + prover.prove(propTree, wrongCtx1, fakeMessage).isFailure shouldBe true + verifier.verify(propTree, wrongCtx1, pr1, fakeMessage).success.value._1 shouldBe false } property("If") { @@ -582,6 +601,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val verifier = new ErgoLikeTestInterpreter val pubkey = prover.dlogSecrets.head.publicImage + val pubkeyTree = mkTestErgoTree(pubkey) val preimageHello = "hello world".getBytes("UTF-8") val preimageWrong = "wrong".getBytes("UTF-8") @@ -598,6 +618,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons | INPUTS(1).R4[Coll[Byte]].get | helloHash == blake2b256(preimage) }""".stripMargin).asBoolValue.toSigmaProp + val propTree = mkTestErgoTree(prop) val propExpected = EQ(ByteArrayConstant(helloHash), CalcBlake2b256( @@ -606,12 +627,12 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons ExtractRegisterAs[SByteArray](ByIndex(Inputs, 1), reg1).get))).toSigmaProp prop shouldBe propExpected - val input0 = testBox(10, pubkey, 0, Seq(), Map()) - val input1 = testBox(1, pubkey, 0, Seq(), Map(reg1 -> ByteArrayConstant(preimageHello))) - val input2 = testBox(1, pubkey, 0, Seq(), Map(reg1 -> ByteArrayConstant(preimageWrong))) - val input3 = testBox(10, prop, 0, Seq(), Map()) + val input0 = testBox(10, pubkeyTree, 0, Seq(), Map()) + val input1 = testBox(1, pubkeyTree, 0, Seq(), Map(reg1 -> ByteArrayConstant(preimageHello))) + val input2 = testBox(1, pubkeyTree, 0, Seq(), Map(reg1 -> ByteArrayConstant(preimageWrong))) + val input3 = testBox(10, propTree, 0, Seq(), Map()) - val output = testBox(22, pubkey, 0, Seq(), Map()) + val output = testBox(22, pubkeyTree, 0, Seq(), Map()) val spendingTransaction = createTransaction(output) @@ -623,8 +644,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons spendingTransaction, self = input3, activatedVersionInTests) - val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx1, fakeMessage).get - verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx1, pr, fakeMessage).get._1 shouldBe true + val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), propTree, ctx1, fakeMessage).get + verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), propTree, ctx1, pr, fakeMessage).get._1 shouldBe true val ctx2 = ErgoLikeContextTesting( currentHeight = 50, @@ -635,7 +656,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons input1, input2, input3), spendingTransaction, self = input3, activatedVersionInTests) - prover.prove(prop, ctx2, fakeMessage).isFailure shouldBe true + prover.prove(propTree, ctx2, fakeMessage).isFailure shouldBe true } property("DeserializeRegister value type mismatch") { @@ -644,7 +665,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val sigmaProp = SigmaPropConstant(prover.dlogSecrets.head.publicImage) // put SigmaProp into the register val regValue = ByteArrayConstant(ValueSerializer.serialize(sigmaProp)) - val box = testBox(20, TrueProp, 0, Seq(), Map(R4 -> regValue)) + val box = testBox(20, TrueTree, 0, Seq(), Map(R4 -> regValue)) // expect SBoolean in the register val prop = DeserializeRegister(R4, SBoolean).toSigmaProp @@ -654,11 +675,11 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons lastBlockUtxoRoot = AvlTreeData.dummy, minerPubkey = ErgoLikeContextTesting.dummyPubkey, boxesToSpend = IndexedSeq(box), - createTransaction(IndexedSeq(testBox(10, TrueProp, 0))), + createTransaction(IndexedSeq(testBox(10, TrueTree, 0))), self = box, activatedVersionInTests) an[RuntimeException] should be thrownBy - prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).getOrThrow + prover.prove(emptyEnv + (ScriptNameProp -> "prove"), mkTestErgoTree(prop), ctx, fakeMessage).getOrThrow } property("DeserializeContext value(script) type mismatch") { @@ -672,24 +693,27 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons LogicalNot(DeserializeContext(scriptId, scriptProp.tpe)), DeserializeContext(scriptId, scriptProp.tpe) ).toSigmaProp + val propTree = mkTestErgoTree(prop) - val box = testBox(20, ErgoScriptPredef.TrueProp, 0, Seq(), Map()) + val box = testBox(20, TrueTree, 0, Seq(), Map()) val ctx = ErgoLikeContextTesting( currentHeight = 50, lastBlockUtxoRoot = AvlTreeData.dummy, minerPubkey = ErgoLikeContextTesting.dummyPubkey, boxesToSpend = IndexedSeq(box), - createTransaction(IndexedSeq(testBox(10, TrueProp, 0))), + createTransaction(IndexedSeq(testBox(10, TrueTree, 0))), self = box, activatedVersionInTests) - val pr = prover.prove(prop, ctx, fakeMessage).get + val pr = prover.prove(propTree, ctx, fakeMessage).get // make sure verifier will fail on deserializing context with mismatched type // try to deserialize it as an expression with integer type val prop1 = EQ(DeserializeContext(scriptId, SInt), IntConstant(1)).toSigmaProp + val prop1Tree = mkTestErgoTree(prop1) + an[ValidationException] should be thrownBy - verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop1, ctx, pr, fakeMessage).get + verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop1Tree, ctx, pr, fakeMessage).get // make sure prover fails as well on deserializing context with mismatched type - an[ValidationException] should be thrownBy prover.prove(prop1, ctx, fakeMessage).get + an[ValidationException] should be thrownBy prover.prove(prop1Tree, ctx, fakeMessage).get } } @@ -707,7 +731,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons val script = "{ 1 + 2 }" val scriptProp = compile(Map.empty, script) // of Int type val scriptBytes = ValueSerializer.serialize(scriptProp) - val tree = ErgoTree.fromProposition(EQ(DeserializeContext(1, SInt), IntConstant(3)).toSigmaProp) + val tree = mkTestErgoTree(EQ(DeserializeContext(1, SInt), IntConstant(3)).toSigmaProp) prove(tree, script = 1.toByte -> ByteArrayConstant(scriptBytes)) } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/FuncVarSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/FuncVarSpecification.scala deleted file mode 100644 index 335a341483..0000000000 --- a/sigmastate/src/test/scala/sigmastate/utxo/FuncVarSpecification.scala +++ /dev/null @@ -1,29 +0,0 @@ -package sigmastate.utxo - -import org.ergoplatform.ErgoLikeContext -import sigmastate.Values.Constant -import sigmastate.eval.CFunc -import sigmastate.SType.AnyOps -import sigmastate.{SInt, SFunc} -import sigmastate.helpers.{SigmaTestingCommons, ContextEnrichingTestProvingInterpreter} -import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv} -import sigmastate.lang.Terms.ValueOps - -class FuncVarSpecification extends SigmaTestingCommons { - implicit lazy val IR = new TestingIRContext { - override val okPrintEvaluatedEntries: Boolean = false - } - - // TODO soft-fork: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/417 - ignore("Func context variable") { -// val scriptId = 21.toByte -// val code = compileWithCosting(emptyEnv, s"{ (x: Int) => x + 1 }") -// val ctx = ErgoLikeContext.dummy(fakeSelf) -// -// val prover = new ContextEnrichingTestProvingInterpreter() -// .withContextExtender(scriptId, Constant(CFunc[Int, Int](ctx, code).asWrappedType, SFunc(SInt, SInt))) -// val prop = compileWithCosting(emptyEnv, s"{ val f = getVar[Int => Int](1).get; f(10) > 0 }").asBoolValue.asSigmaProp -// val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).getOrThrow -// - } -} diff --git a/sigmastate/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala b/sigmastate/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala index f7864771e1..c4d32cfd39 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala @@ -1,6 +1,6 @@ package sigmastate.utxo -import org.ergoplatform.{ErgoLikeTransaction, ErgoBoxCandidate, _} +import org.ergoplatform._ import org.scalatest.prop.GeneratorDrivenPropertyChecks import org.scalatest.{PropSpec, Matchers} import scalan.util.BenchmarkUtil diff --git a/sigmastate/src/test/scala/sigmastate/utxo/ThresholdSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/ThresholdSpecification.scala index 2f3a2f1059..6443263507 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/ThresholdSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/ThresholdSpecification.scala @@ -4,11 +4,11 @@ import sigmastate.basics.DLogProtocol.{DLogProverInput, ProveDlog} import sigmastate.Values.{ConcreteCollection, FalseLeaf, IntConstant, SigmaPropConstant, SigmaPropValue, TrueLeaf} import sigmastate._ import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestInterpreter, ErgoLikeTransactionTesting, SigmaTestingCommons} -import sigmastate.lang.Terms._ import sigmastate.lang.exceptions.CosterException import sigmastate.utils.Helpers._ -class ThresholdSpecification extends SigmaTestingCommons { +class ThresholdSpecification extends SigmaTestingCommons + with CrossVersionProps { implicit lazy val IR = new TestingIRContext { override val okPrintEvaluatedEntries: Boolean = false } @@ -44,68 +44,64 @@ class ThresholdSpecification extends SigmaTestingCommons { val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC) // Basic compilation - val compiledProp1 = compile(env, """atLeast(2, Coll(pubkeyA, pubkeyB, pubkeyC))""") - val prop1 = AtLeast(2, pubkeyA, pubkeyB, pubkeyC) - compiledProp1 shouldBe prop1 + compileAndCheck(env, + """atLeast(2, Coll(pubkeyA, pubkeyB, pubkeyC))""", + AtLeast(2, pubkeyA, pubkeyB, pubkeyC)) // this example is from the white paper - val compiledProp2 = compile(env, + val (compiledTree2, compiledProp2) = compileAndCheck(env, """{ | val array = Coll(pubkeyA, pubkeyB, pubkeyC) | atLeast(array.size, array) - |}""".stripMargin).asSigmaProp + |}""".stripMargin, + AtLeast( + IntConstant(3), + ConcreteCollection(Array[SigmaPropValue](pubkeyA, pubkeyB, pubkeyC), SSigmaProp))) - - val prop2 = AtLeast(IntConstant(3), - ConcreteCollection(Array[SigmaPropValue](pubkeyA, pubkeyB, pubkeyC), SSigmaProp)) - compiledProp2 shouldBe prop2 - - val proof = proverABC.prove(compiledProp2, ctx, fakeMessage).get - verifier.verify(compiledProp2, ctx, proof, fakeMessage).get._1 shouldBe true + val proof = proverABC.prove(compiledTree2, ctx, fakeMessage).get + verifier.verify(compiledTree2, ctx, proof, fakeMessage).get._1 shouldBe true val nonWorkingProvers2 = Seq(proverA, proverB, proverC, proverAB, proverAC, proverBC, proverD) for (prover <- nonWorkingProvers2) { - prover.prove(compiledProp2, ctx, fakeMessage).isFailure shouldBe true + prover.prove(compiledTree2, ctx, fakeMessage).isFailure shouldBe true } val prop2And = CAND(Seq(pubkeyA, pubkeyB, pubkeyC)).toSigmaProp proverA.reduceToCrypto(ctx, compiledProp2).get._1 shouldBe proverA.reduceToCrypto(ctx, prop2And).get._1 // this example is from the white paper - val compiledProp3 = compile(env, + val (compiledTree3, compiledProp3) = compileAndCheck(env, """{ | val array = Coll(pubkeyA, pubkeyB, pubkeyC) | atLeast(1, array) - |}""".stripMargin).asSigmaProp - val prop3 = AtLeast(1, pubkeyA, pubkeyB, pubkeyC) - compiledProp3 shouldBe prop3 + |}""".stripMargin, + AtLeast(1, pubkeyA, pubkeyB, pubkeyC)) val workingProvers3 = Seq(proverA, proverB, proverC, proverAB, proverBC, proverAC, proverABC) for (prover <- workingProvers3) { - val proof = prover.prove(compiledProp3, ctx, fakeMessage).get - verifier.verify(compiledProp3, ctx, proof, fakeMessage).get._1 shouldBe true + val proof = prover.prove(compiledTree3, ctx, fakeMessage).get + verifier.verify(compiledTree3, ctx, proof, fakeMessage).get._1 shouldBe true } - proverD.prove(compiledProp3, ctx, fakeMessage).isFailure shouldBe true + proverD.prove(compiledTree3, ctx, fakeMessage).isFailure shouldBe true val prop3Or = COR(Seq(pubkeyA, pubkeyB, pubkeyC)).toSigmaProp proverA.reduceToCrypto(ctx, compiledProp3).get._1 shouldBe proverA.reduceToCrypto(ctx, prop3Or).get._1 - val compiledProp4 = compile(env, + val (compiledTree4, _) = compileAndCheck(env, """{ | val array = Coll(pubkeyA, pubkeyB, pubkeyC) | atLeast(2, array) - |}""".stripMargin).asSigmaProp - val prop4 = AtLeast(2, pubkeyA, pubkeyB, pubkeyC) - compiledProp4 shouldBe prop4 + |}""".stripMargin, + AtLeast(2, pubkeyA, pubkeyB, pubkeyC)) val workingProvers4 = Seq(proverAB, proverBC, proverAC, proverABC) for (prover <- workingProvers4) { - val proof = prover.prove(compiledProp4, ctx, fakeMessage).get - verifier.verify(compiledProp4, ctx, proof, fakeMessage).get._1 shouldBe true + val proof = prover.prove(compiledTree4, ctx, fakeMessage).get + verifier.verify(compiledTree4, ctx, proof, fakeMessage).get._1 shouldBe true } val nonWorkingProvers4 = Seq(proverA, proverB, proverC, proverD) for (prover <- nonWorkingProvers4) { - prover.prove(compiledProp4, ctx, fakeMessage).isFailure shouldBe true + prover.prove(compiledTree4, ctx, fakeMessage).isFailure shouldBe true } } @@ -171,23 +167,23 @@ class ThresholdSpecification extends SigmaTestingCommons { pReduced.mapOrThrow(_ => true) shouldBe true if (t.dlogOnlyVector.v.isEmpty) { // Case 0: no ProveDlogs in the test vector -- just booleans if (t.numTrue >= bound) { - pReduced.get._1 shouldBe TrueProp + pReduced.get._1 shouldBe TrivialProp.TrueProp case0TrueHit = true } else { - pReduced.get._1 shouldBe FalseProp + pReduced.get._1 shouldBe TrivialProp.FalseProp case0FalseHit = true } } else if (t.dlogOnlyVector.v.length == 1) { // Case 1: 1 ProveDlog in the test vector // Should be just true if numTrue>=bound if (t.numTrue >= bound) { - pReduced.get._1 shouldBe TrueProp + pReduced.get._1 shouldBe TrivialProp.TrueProp case1TrueHit = true } // Should be false if bound>numTrue + 1 else if (bound > t.numTrue + 1) { - pReduced.get._1 shouldBe FalseProp + pReduced.get._1 shouldBe TrivialProp.FalseProp case1FalseHit = true } // if bound is exactly numTrue+1, should be just dlog @@ -199,12 +195,12 @@ class ThresholdSpecification extends SigmaTestingCommons { else { // Case 2: more than 1 ProveDlogs in the test vector // Should be just true if numTrue>=bound if (t.numTrue >= bound) { - pReduced.get._1 shouldBe TrueProp + pReduced.get._1 shouldBe TrivialProp.TrueProp case2TrueHit = true } // Should be false if bound>numTrue + dlogOnlyVector.length else if (bound > t.numTrue + t.dlogOnlyVector.v.length) { - pReduced.get._1 shouldBe FalseProp + pReduced.get._1 shouldBe TrivialProp.FalseProp case2FalseHit = true } // if bound is exactly numTrue+dlogOnlyVector, should be just AND of all dlogs @@ -268,11 +264,9 @@ class ThresholdSpecification extends SigmaTestingCommons { val env = Map("pkA" -> pkA, "pkB" -> pkB, "pkC" -> pkC, "pkD" -> pkD, "pkE" -> pkE, "pkF" -> pkF, "pkG" -> pkG, "pkH" -> pkH, "pkI" -> pkI) - val compiledProp = compile(env, - """atLeast(3, Coll (pkA, pkB, pkC, pkD && pkE, pkF && pkG, pkH && pkI))""").asSigmaProp - val prop = AtLeast(3, pkA, pkB, pkC, SigmaAnd(pkD, pkE), SigmaAnd(pkF, pkG), SigmaAnd(pkH, pkI)) - - compiledProp shouldBe prop + val (compiledTree, _) = compileAndCheck(env, + """atLeast(3, Coll (pkA, pkB, pkC, pkD && pkE, pkF && pkG, pkH && pkI))""", + AtLeast(3, pkA, pkB, pkC, SigmaAnd(pkD, pkE), SigmaAnd(pkF, pkG), SigmaAnd(pkH, pkI))) val badProver = proverH.withSecrets(Seq(skB, skC, skE)) val goodProver1 = badProver.withSecrets(Seq(skD)) @@ -294,12 +288,11 @@ class ThresholdSpecification extends SigmaTestingCommons { for (prover <- goodProvers) { - val proof = prover.prove(compiledProp, ctx, fakeMessage).get - verifier.verify(compiledProp, ctx, proof, fakeMessage).get._1 shouldBe true + val proof = prover.prove(compiledTree, ctx, fakeMessage).get + verifier.verify(compiledTree, ctx, proof, fakeMessage).get._1 shouldBe true } - badProver.prove(compiledProp, ctx, fakeMessage).isFailure shouldBe true - + badProver.prove(compiledTree, ctx, fakeMessage).isFailure shouldBe true } property("threshold proving of different trees") { @@ -322,7 +315,6 @@ class ThresholdSpecification extends SigmaTestingCommons { val propComponents = Seq[SigmaPropValue](subProp1, subProp2, subProp3, subProp4, subProp5) val secrets = Seq(Seq(secret1), Seq(secret2), Seq(secret31), Seq(secret41, secret42), Seq(secret51, secret53)) - // the integer indicates how many subpropositions the prover can prove var provers = Seq[(Int, ContextEnrichingTestProvingInterpreter)]((0, new ContextEnrichingTestProvingInterpreter)) // create 32 different provers @@ -340,15 +332,15 @@ class ThresholdSpecification extends SigmaTestingCommons { val verifier = new ErgoLikeTestInterpreter def canProve(prover: ContextEnrichingTestProvingInterpreter, proposition: SigmaPropValue): Unit = { - val proof = prover.prove(proposition, ctx, fakeMessage).get - verifier.verify(proposition, ctx, proof, fakeMessage).get._1 shouldBe true + val tree = mkTestErgoTree(proposition) + val proof = prover.prove(tree, ctx, fakeMessage).get + verifier.verify(tree, ctx, proof, fakeMessage).get._1 shouldBe true } def cannotProve(prover: ContextEnrichingTestProvingInterpreter, proposition: SigmaPropValue): Unit = { - prover.prove(proposition, ctx, fakeMessage).isFailure shouldBe true + prover.prove(mkTestErgoTree(proposition), ctx, fakeMessage).isFailure shouldBe true } - var twoToi = 1 for (i <- 0 to secrets.length) { for (bound <- 1 to i) { diff --git a/sigmastate/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationSpecification.scala index f3a908e7bf..913f2a9295 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationSpecification.scala @@ -16,8 +16,10 @@ class BlockchainSimulationSpecification extends BlockchainSimulationTestingCommo implicit lazy val IR = new TestingIRContext + import ValidationState._ + property("apply one valid block") { - val state = ValidationState.initialState(activatedVersionInTests) + val state = ValidationState.initialState(activatedVersionInTests, initBlock(ergoTreeVersionInTests)) val miner = new ErgoLikeTestProvingInterpreter() val block = generateBlock(state, miner, 0) val updStateTry = state.applyBlock(block) @@ -25,7 +27,7 @@ class BlockchainSimulationSpecification extends BlockchainSimulationTestingCommo } property("too costly block") { - val state = ValidationState.initialState(activatedVersionInTests) + val state = ValidationState.initialState(activatedVersionInTests, initBlock(ergoTreeVersionInTests)) val miner = new ErgoLikeTestProvingInterpreter() val block = generateBlock(state, miner, 0) val updStateTry = state.applyBlock(block, maxCost = 1) @@ -33,22 +35,24 @@ class BlockchainSimulationSpecification extends BlockchainSimulationTestingCommo } property("apply many blocks") { - val state = ValidationState.initialState(activatedVersionInTests) + val state = ValidationState.initialState(activatedVersionInTests, initBlock(ergoTreeVersionInTests)) val miner = new ErgoLikeTestProvingInterpreter() checkState(state, miner, 0, randomDeepness) } property("apply many blocks with enriched context") { - val state = ValidationState.initialState(activatedVersionInTests) + val state = ValidationState.initialState(activatedVersionInTests, initBlock(ergoTreeVersionInTests)) val miner = new ErgoLikeTestProvingInterpreter() val varId = 1.toByte val prop = GetVarBoolean(varId).get.toSigmaProp // unable to spend boxes without correct context extension - an[RuntimeException] should be thrownBy checkState(state, miner, 0, randomDeepness, Some(prop)) + an[RuntimeException] should be thrownBy { + checkState(state, miner, 0, randomDeepness, Some(mkTestErgoTree(prop))) + } // spend boxes with context extension val contextExtension = ContextExtension(Map(varId -> TrueLeaf)) - checkState(state, miner, 0, randomDeepness, Some(prop), contextExtension) + checkState(state, miner, 0, randomDeepness, Some(mkTestErgoTree(prop)), contextExtension) } ignore(s"benchmarking applying many blocks (!!! ignored)") { @@ -56,7 +60,7 @@ class BlockchainSimulationSpecification extends BlockchainSimulationTestingCommo def bench(numberOfBlocks: Int): Unit = { - val state = ValidationState.initialState(activatedVersionInTests) + val state = ValidationState.initialState(activatedVersionInTests, initBlock(ergoTreeVersionInTests)) val miner = new ContextEnrichingTestProvingInterpreter() val (_, time) = (0 until numberOfBlocks).foldLeft(state -> 0L) { case ((s, timeAcc), h) => diff --git a/sigmastate/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationTestingCommons.scala b/sigmastate/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationTestingCommons.scala index fc8918652d..c465496004 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationTestingCommons.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationTestingCommons.scala @@ -42,7 +42,8 @@ trait BlockchainSimulationTestingCommons extends SigmaTestingCommons { height: Int, propOpt: Option[ErgoTree] = None, extension: ContextExtension = ContextExtension.empty): FullBlock = { - val prop: ErgoTree = propOpt.getOrElse(prover.dlogSecrets.head.publicImage.toSigmaProp) + val prop: ErgoTree = propOpt.getOrElse( + mkTestErgoTree(prover.dlogSecrets.head.publicImage.toSigmaProp)) val minerPubkey = prover.dlogSecrets.head.publicImage.pkBytes val boxesToSpend = state.boxesReader.randomBoxes(30 + height) @@ -146,16 +147,21 @@ object BlockchainSimulationTestingCommons extends SigmaTestingCommons { object ValidationState { type BatchProver = BatchAVLProver[Digest32, Blake2b256.type] - val initBlock = FullBlock( + def initBlock(scriptVersion: Byte) = FullBlock( (0 until 10).map { i => val txId = Blake2b256.hash(i.toString.getBytes ++ scala.util.Random.nextString(12).getBytes).toModifierId - val boxes = (1 to 50).map(_ => testBox(10, Values.TrueLeaf.toSigmaProp, i, Seq(), Map(), txId)) + val boxes = (1 to 50).map(_ => + testBox(10, + ErgoTree.fromProposition( + ErgoTree.headerWithVersion(scriptVersion), + Values.TrueLeaf.toSigmaProp), + i, Seq(), Map(), txId)) createTransaction(boxes) }, ErgoLikeContextTesting.dummyPubkey ) - def initialState(activatedVersion: Byte, block: FullBlock = initBlock)(implicit IR: IRContext): ValidationState = { + def initialState(activatedVersion: Byte, block: FullBlock)(implicit IR: IRContext): ValidationState = { val keySize = 32 val prover = new BatchProver(keySize, None) diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeTests.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeTests.scala index 112d492b14..63d8983e34 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeTests.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeTests.scala @@ -14,7 +14,6 @@ import sigmastate.eval.Extensions._ import sigmastate.lang.Terms.ValueOps import sigmastate.utxo._ import special.collection.Coll -import special.sigma.Extensions._ /** An example of an atomic ergo <=> asset exchange. * Let's assume that Alice is willing to buy 60 assets of type "token1" for 100 ergo coins, and Bob @@ -51,7 +50,7 @@ class AssetsAtomicExchangeTests extends SigmaTestingCommons { suite => def extractToken(box: Value[SBox.type]) = ByIndex( ExtractRegisterAs(box, ErgoBox.TokensRegId)(ErgoBox.STokensRegType).get, 0) - val expectedBuyerTree = BlockValue( + val expectedBuyerProp = BlockValue( Vector( ValDef(1, ByIndex(Outputs, 0)), // token @@ -73,7 +72,7 @@ class AssetsAtomicExchangeTests extends SigmaTestingCommons { suite => ).toSigmaProp )) ).asSigmaProp - buyerProp.ergoTree shouldBe ErgoTree.fromProposition(expectedBuyerTree) + buyerProp.ergoTree shouldBe mkTestErgoTree(expectedBuyerProp) } import contract.spec._ diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala index d223acc47c..f5e4718d05 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala @@ -2,7 +2,6 @@ package sigmastate.utxo.examples import org.ergoplatform.dsl.ContractSyntax.Token import special.sigma.Context -import org.ergoplatform.ErgoBox.R4 import special.collection.Coll import org.ergoplatform.dsl.{SigmaContractSyntax, ContractSpec, StdContracts} diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/AtomicSwapExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/AtomicSwapExampleSpecification.scala index eb60bbfa6f..efcade8731 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/AtomicSwapExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/AtomicSwapExampleSpecification.scala @@ -1,12 +1,12 @@ package sigmastate.utxo.examples -import org.ergoplatform.{ErgoLikeContext, ErgoLikeTransaction, Height} +import org.ergoplatform.Height import scorex.crypto.hash.Blake2b256 import scorex.utils.Random import sigmastate.Values._ import sigmastate._ -import interpreter.Interpreter._ -import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestInterpreter, ErgoLikeTransactionTesting, SigmaTestingCommons} +import sigmastate.interpreter.Interpreter._ +import sigmastate.helpers._ import sigmastate.lang.Terms._ import sigmastate.utxo.SizeOf @@ -51,12 +51,14 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons with CrossVersi | )) |}""".stripMargin).asSigmaProp + val prop1Tree = ErgoTree.fromProposition(ergoTreeHeaderInTests, prop1) + //chain1 script - val prop1Tree = SigmaOr( + val prop1Exp = SigmaOr( SigmaAnd(GT(Height, IntConstant(height1 + deadlineB)).toSigmaProp, pubkeyA), SigmaAnd(pubkeyB, EQ(CalcBlake2b256(GetVarByteArray(1).get), hx).toSigmaProp) ) - prop1 shouldBe prop1Tree + prop1 shouldBe prop1Exp val script2 = """{ @@ -71,9 +73,10 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons with CrossVersi |} """.stripMargin val prop2 = compile(env, script2).asSigmaProp + val prop2Tree = ErgoTree.fromProposition(ergoTreeHeaderInTests, prop2) //chain2 script - val prop2Tree = BlockValue( + val prop2Exp = BlockValue( Vector(ValDef(1, GetVarByteArray(1).get)), SigmaOr( SigmaAnd( @@ -91,7 +94,7 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons with CrossVersi ) ) - prop2 shouldBe prop2Tree + prop2 shouldBe prop2Exp //Preliminary checks: @@ -105,10 +108,10 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons with CrossVersi spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - proverB.prove(env, prop1, ctxf1, fakeMessage).isSuccess shouldBe false + proverB.prove(env, prop1Tree, ctxf1, fakeMessage).isSuccess shouldBe false //A can't withdraw her coins in chain1 (generate a valid proof) - proverA.prove(env, prop1, ctxf1, fakeMessage).isSuccess shouldBe false + proverA.prove(env, prop1Tree, ctxf1, fakeMessage).isSuccess shouldBe false //B cant't withdraw his coins in chain2 (generate a valid proof) val ctxf2 = ErgoLikeContextTesting( @@ -119,7 +122,7 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons with CrossVersi spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - proverB.prove(env, prop2, ctxf2, fakeMessage).isSuccess shouldBe false + proverB.prove(env, prop2Tree, ctxf2, fakeMessage).isSuccess shouldBe false //Successful run below: @@ -132,8 +135,8 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons with CrossVersi spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val pr = proverA.prove(env, prop2, ctx1, fakeMessage).get - verifier.verify(env, prop2, ctx1, pr, fakeMessage).get._1 shouldBe true + val pr = proverA.prove(env, prop2Tree, ctx1, fakeMessage).get + verifier.verify(env, prop2Tree, ctx1, pr, fakeMessage).get._1 shouldBe true //B extracts preimage x of hx val t = pr.extension.values(1) @@ -148,8 +151,8 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons with CrossVersi spendingTransaction = ErgoLikeTransactionTesting.dummy, self = fakeSelf, activatedVersionInTests) - val pr2 = proverB2.prove(env, prop1, ctx2, fakeMessage).get - verifier.verify(env, prop1, ctx2, pr2, fakeMessage).get._1 shouldBe true + val pr2 = proverB2.prove(env, prop1Tree, ctx2, fakeMessage).get + verifier.verify(env, prop1Tree, ctx2, pr2, fakeMessage).get._1 shouldBe true // Bad prover with x that is too long should fail // Replace x with a longer one and hx with the hash of this longer x in the script @@ -159,7 +162,8 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons with CrossVersi val badHx = ByteArrayConstant(Blake2b256(badX)) val badEnv = env + ("hx" -> badHx) val badProp2 = compile(badEnv, script2).asSigmaProp + val badProp2Tree = ErgoTree.fromProposition(ergoTreeHeaderInTests, badProp2) - badProverA.prove(badEnv, badProp2, ctx1, fakeMessage).isSuccess shouldBe false + badProverA.prove(badEnv, badProp2Tree, ctx1, fakeMessage).isSuccess shouldBe false } } \ No newline at end of file diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala index 97eee44ab6..abbf7a883c 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala @@ -2,7 +2,7 @@ package sigmastate.utxo.examples import org.ergoplatform._ import scorex.util.ScorexLogging -import sigmastate.Values.IntConstant +import sigmastate.Values.{IntConstant, ErgoTree} import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, SigmaTestingCommons} import sigmastate.helpers.TestingHelpers._ import sigmastate.interpreter.ContextExtension @@ -137,7 +137,9 @@ block 1600 in 1622 ms, 30000000000 coins remain, defs: 61661 val minerPubkey = minerImage.pkBytes val minerProp = minerImage - val initialBoxCandidate: ErgoBox = testBox(coinsTotal / 4, prop, 0, Seq(), Map(register -> IntConstant(-1))) + val initialBoxCandidate: ErgoBox = testBox(coinsTotal / 4, + ErgoTree.fromProposition(ergoTreeHeaderInTests, prop), + 0, Seq(), Map(register -> IntConstant(-1))) val initBlock = FullBlock(IndexedSeq(createTransaction(initialBoxCandidate)), minerPubkey) val genesisState = ValidationState.initialState(activatedVersionInTests, initBlock) val fromState = genesisState.boxesReader.byId(genesisState.boxesReader.allIds.head).get @@ -153,7 +155,7 @@ block 1600 in 1622 ms, 30000000000 coins remain, defs: 61661 val ut = if (emissionBox.value > s.oneEpochReduction) { val minerBox = new ErgoBoxCandidate(emissionAtHeight(height), minerProp, height, Colls.emptyColl, Map()) val newEmissionBox: ErgoBoxCandidate = - new ErgoBoxCandidate(emissionBox.value - minerBox.value, prop, height, Colls.emptyColl, Map(register -> IntConstant(height))) + new ErgoBoxCandidate(emissionBox.value - minerBox.value, mkTestErgoTree(prop), height, Colls.emptyColl, Map(register -> IntConstant(height))) UnsignedErgoLikeTransaction( IndexedSeq(new UnsignedInput(emissionBox.id)), @@ -176,7 +178,7 @@ block 1600 in 1622 ms, 30000000000 coins remain, defs: 61661 emissionBox, activatedVersionInTests, ContextExtension.empty) - val proverResult = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, context, ut.messageToSign).get + val proverResult = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), mkTestErgoTree(prop), context, ut.messageToSign).get ut.toSigned(IndexedSeq(proverResult)) } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/ColdWalletAdvContractExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/ColdWalletAdvContractExampleSpecification.scala index f033d4f6b2..14c0487495 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/ColdWalletAdvContractExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/ColdWalletAdvContractExampleSpecification.scala @@ -52,7 +52,7 @@ class ColdWalletAdvContractExampleSpecification extends SigmaTestingCommons // 3. make start of output box as max of all starts of the inputs // 4. output must contain at least one box of same type with min bal based on avbl1Key/avbl2Key - val script = compile(env, + val scriptProp = compile(env, """{ | val depth = HEIGHT - SELF.creationInfo._1 // number of confirmations | val start = min(depth, SELF.R4[Int].get) // height at which period started @@ -89,7 +89,8 @@ class ColdWalletAdvContractExampleSpecification extends SigmaTestingCommons | ) |}""".stripMargin).asSigmaProp - val address = Pay2SHAddress(script) + val scriptTree = mkTestErgoTree(scriptProp) + val address = Pay2SHAddress(scriptProp) // someone creates a transaction that outputs a box depositing money into the wallet. // In the example, we don't create the transaction; we just create a box below @@ -141,14 +142,14 @@ class ColdWalletAdvContractExampleSpecification extends SigmaTestingCommons val verifier = new ErgoLikeTestInterpreter - val proofAliceWithdraw = alice.prove(spendEnv, script, firstWithdrawContext1Key, fakeMessage).get.proof - verifier.verify(env, script, firstWithdrawContext1Key, proofAliceWithdraw, fakeMessage).get._1 shouldBe true + val proofAliceWithdraw = alice.prove(spendEnv, scriptTree, firstWithdrawContext1Key, fakeMessage).get.proof + verifier.verify(env, scriptTree, firstWithdrawContext1Key, proofAliceWithdraw, fakeMessage).get._1 shouldBe true - val proofBobWithdraw = bob.prove(env, script, firstWithdrawContext1Key, fakeMessage).get.proof - verifier.verify(env, script, firstWithdrawContext1Key, proofBobWithdraw, fakeMessage).get._1 shouldBe true + val proofBobWithdraw = bob.prove(env, scriptTree, firstWithdrawContext1Key, fakeMessage).get.proof + verifier.verify(env, scriptTree, firstWithdrawContext1Key, proofBobWithdraw, fakeMessage).get._1 shouldBe true - val proofCarolWithdraw = carol.prove(env, script, firstWithdrawContext1Key, fakeMessage).get.proof - verifier.verify(env, script, firstWithdrawContext1Key, proofCarolWithdraw, fakeMessage).get._1 shouldBe true + val proofCarolWithdraw = carol.prove(env, scriptTree, firstWithdrawContext1Key, fakeMessage).get.proof + verifier.verify(env, scriptTree, firstWithdrawContext1Key, proofCarolWithdraw, fakeMessage).get._1 shouldBe true // any two of Alice, Bob or Carol withdraws val firstWithdrawAmount2Key = depositAmount * percent2Key / 100 // less than or equal to percent @@ -176,8 +177,8 @@ class ColdWalletAdvContractExampleSpecification extends SigmaTestingCommons activatedVersionInTests ) - val proofAliceBobWithdraw = alice.withSecrets(bob.dlogSecrets).prove(spendEnv, script, firstWithdrawContext2Key, fakeMessage).get.proof - verifier.verify(env, script, firstWithdrawContext2Key, proofAliceBobWithdraw, fakeMessage).get._1 shouldBe true + val proofAliceBobWithdraw = alice.withSecrets(bob.dlogSecrets).prove(spendEnv, scriptTree, firstWithdrawContext2Key, fakeMessage).get.proof + verifier.verify(env, scriptTree, firstWithdrawContext2Key, proofAliceBobWithdraw, fakeMessage).get._1 shouldBe true } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/ColdWalletContractExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/ColdWalletContractExampleSpecification.scala index c0a860abbe..8a10c5745d 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/ColdWalletContractExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/ColdWalletContractExampleSpecification.scala @@ -39,7 +39,7 @@ class ColdWalletContractExampleSpecification extends SigmaTestingCommons ) // assume that person topping up address creates the box correctly... i.e., sets the correct value of start (in R4) - val script = compile(env, + val scriptProp = compile(env, """{ | val lastMinBal = SELF.R5[Long].get // min balance needed in this period | val depth = HEIGHT - SELF.creationInfo._1 // number of confirmations @@ -66,7 +66,8 @@ class ColdWalletContractExampleSpecification extends SigmaTestingCommons | ) |}""".stripMargin).asSigmaProp - val address = Pay2SHAddress(script) + val scriptTree = mkTestErgoTree(scriptProp) + val address = Pay2SHAddress(scriptTree) // someone creates a transaction that outputs a box depositing money into the wallet. // In the example, we don't create the transaction; we just create a box below @@ -105,11 +106,11 @@ class ColdWalletContractExampleSpecification extends SigmaTestingCommons activatedVersionInTests ) - val proofAliceAndBobWithdraw = alice.withSecrets(bob.dlogSecrets).prove(spendEnv, script, withdrawContextAliceandBob, fakeMessage).get.proof + val proofAliceAndBobWithdraw = alice.withSecrets(bob.dlogSecrets).prove(spendEnv, scriptTree, withdrawContextAliceandBob, fakeMessage).get.proof val verifier = new ErgoLikeTestInterpreter - verifier.verify(spendEnv, script, withdrawContextAliceandBob, proofAliceAndBobWithdraw, fakeMessage).get._1 shouldBe true + verifier.verify(spendEnv, scriptTree, withdrawContextAliceandBob, proofAliceAndBobWithdraw, fakeMessage).get._1 shouldBe true // One of Alice or Bob withdraws (1% max) val firstWithdrawAmount = depositAmount * percent / 100 // less than or eqaul to percent (1000) @@ -136,11 +137,11 @@ class ColdWalletContractExampleSpecification extends SigmaTestingCommons activatedVersionInTests ) - val proofAliceWithdraw = alice.prove(spendEnv, script, firstWithdrawContext, fakeMessage).get.proof - verifier.verify(env, script, firstWithdrawContext, proofAliceWithdraw, fakeMessage).get._1 shouldBe true + val proofAliceWithdraw = alice.prove(spendEnv, scriptTree, firstWithdrawContext, fakeMessage).get.proof + verifier.verify(env, scriptTree, firstWithdrawContext, proofAliceWithdraw, fakeMessage).get._1 shouldBe true - val proofBobWithdraw = bob.prove(env, script, firstWithdrawContext, fakeMessage).get.proof - verifier.verify(env, script, firstWithdrawContext, proofBobWithdraw, fakeMessage).get._1 shouldBe true + val proofBobWithdraw = bob.prove(env, scriptTree, firstWithdrawContext, fakeMessage).get.proof + verifier.verify(env, scriptTree, firstWithdrawContext, proofBobWithdraw, fakeMessage).get._1 shouldBe true // invalid (amount greater than allowed) val withdrawAmountInvalid = depositAmount * percent / 100 + 1 // more than percent @@ -167,10 +168,10 @@ class ColdWalletContractExampleSpecification extends SigmaTestingCommons ) an [AssertionError] should be thrownBy ( - alice.prove(spendEnv, script, withdrawContextInvalid, fakeMessage).get + alice.prove(spendEnv, scriptTree, withdrawContextInvalid, fakeMessage).get ) an [AssertionError] should be thrownBy ( - bob.prove(spendEnv, script, withdrawContextInvalid, fakeMessage).get + bob.prove(spendEnv, scriptTree, withdrawContextInvalid, fakeMessage).get ) // second withdraw (valid case) @@ -201,11 +202,11 @@ class ColdWalletContractExampleSpecification extends SigmaTestingCommons activatedVersionInTests ) - val proofAliceSecondWithdraw = alice.prove(spendEnv, script, secondWithdrawContext, fakeMessage).get.proof - verifier.verify(env, script, secondWithdrawContext, proofAliceSecondWithdraw, fakeMessage).get._1 shouldBe true + val proofAliceSecondWithdraw = alice.prove(spendEnv, scriptTree, secondWithdrawContext, fakeMessage).get.proof + verifier.verify(env, scriptTree, secondWithdrawContext, proofAliceSecondWithdraw, fakeMessage).get._1 shouldBe true - val proofBobSecondWithdraw = bob.prove(spendEnv, script, secondWithdrawContext, fakeMessage).get.proof - verifier.verify(env, script, secondWithdrawContext, proofBobSecondWithdraw, fakeMessage).get._1 shouldBe true + val proofBobSecondWithdraw = bob.prove(spendEnv, scriptTree, secondWithdrawContext, fakeMessage).get.proof + verifier.verify(env, scriptTree, secondWithdrawContext, proofBobSecondWithdraw, fakeMessage).get._1 shouldBe true } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/CoopExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/CoopExampleSpecification.scala index 3aa7968d19..76d485f91a 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/CoopExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/CoopExampleSpecification.scala @@ -1,11 +1,11 @@ package sigmastate.utxo.examples -import org.ergoplatform.{ErgoLikeContext, ErgoLikeTransaction, ErgoBox, ErgoScriptPredef} +import org.ergoplatform.{ErgoLikeContext, ErgoLikeTransaction, ErgoBox} import org.scalatest.Assertion import org.scalatest.TryValues._ -import sigmastate.basics.DLogProtocol.ProveDlog +import sigmastate.basics.DLogProtocol.{ProveDlog, DLogProverInput} import scorex.crypto.hash.Blake2b256 -import sigmastate.Values.{ByteArrayConstant, BooleanConstant, SigmaPropValue} +import sigmastate.Values.{ByteArrayConstant, ErgoTree, BooleanConstant} import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, SigmaTestingCommons, ErgoLikeTestInterpreter} import sigmastate.helpers.TestingHelpers._ import sigmastate.lang.Terms._ @@ -31,19 +31,19 @@ class CoopExampleSpecification extends SigmaTestingCommons self = self, activatedVersionInTests) } - def successProofTest(exp: SigmaPropValue, + def successProofTest(tree: ErgoTree, ctx: ErgoLikeContext, prover: ContextEnrichingTestProvingInterpreter, verifier: ErgoLikeTestInterpreter): Assertion = { - val proofResult = prover.prove(exp, ctx, fakeMessage) + val proofResult = prover.prove(tree, ctx, fakeMessage) proofResult should be a 'success - verifier.verify(exp, ctx, proofResult.success.value, fakeMessage) should be a 'success + verifier.verify(tree, ctx, proofResult.success.value, fakeMessage) should be a 'success } - def failingProofTest(exp: SigmaPropValue, + def failingProofTest(tree: ErgoTree, ctx: ErgoLikeContext, prover: ContextEnrichingTestProvingInterpreter): Assertion = { - prover.prove(exp, ctx, fakeMessage) should be a 'failure + prover.prove(tree, ctx, fakeMessage) should be a 'failure } property("commit to the threshold sig") { @@ -63,10 +63,16 @@ class CoopExampleSpecification extends SigmaTestingCommons val skC = coopC.dlogSecrets.head val skD = coopD.dlogSecrets.head - val pubkeyA = skA.publicImage - val pubkeyB = skB.publicImage - val pubkeyC = skC.publicImage - val pubkeyD = skD.publicImage + def pkWithTree(in: DLogProverInput): (ProveDlog, ErgoTree) = { + val pk = in.publicImage + val tree = ErgoTree.fromSigmaBoolean(ErgoTree.headerWithVersion(0), pk) + (pk, tree) + } + + val (pubkeyA, treeA) = pkWithTree(skA) + val (pubkeyB, treeB) = pkWithTree(skB) + val (pubkeyC, treeC) = pkWithTree(skC) + val (pubkeyD, treeD) = pkWithTree(skD) val toolA = new ContextEnrichingTestProvingInterpreter val toolB = new ContextEnrichingTestProvingInterpreter @@ -117,7 +123,7 @@ class CoopExampleSpecification extends SigmaTestingCommons "pubkeyConstr3" -> constructionRing(2) ) - val spendingProp1 = compile(spendingEnv, + val spendingProp1 = mkTestErgoTree(compile(spendingEnv, s""" |{ | val spendingSuccess = (pubkeyTool1 || pubkeyTool2 || pubkeyTool3 || pubkeyTool4) && businessKey @@ -126,14 +132,14 @@ class CoopExampleSpecification extends SigmaTestingCommons | | spendingSuccess || withdrawCondition |} - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) { val self = testBox(totalValue, spendingProp1, 0) - val output1 = testBox(totalValue / 4, pubkeyA, 0) - val output2 = testBox(totalValue / 4, pubkeyB, 0) - val output3 = testBox(totalValue / 4, pubkeyC, 0) - val output4 = testBox(totalValue / 4, pubkeyD, 0) + val output1 = testBox(totalValue / 4, treeA, 0) + val output2 = testBox(totalValue / 4, treeB, 0) + val output3 = testBox(totalValue / 4, treeC, 0) + val output4 = testBox(totalValue / 4, treeD, 0) val tx = mkTxFromOutputs(output1, output2, output3, output4) val ctx = mkCtx(5001, tx, self) successProofTest(spendingProp1, ctx, coopA, verifier) @@ -154,7 +160,7 @@ class CoopExampleSpecification extends SigmaTestingCommons "pubkeyConstr3" -> constructionRing(2) ) - val spendingProp2 = compile(spendingEnv2, + val spendingProp2 = mkTestErgoTree(compile(spendingEnv2, s""" |{ | val spendingSuccess = (pubkeyTool1 || pubkeyTool2 || pubkeyTool3 || pubkeyTool4) && businessKey @@ -163,17 +169,17 @@ class CoopExampleSpecification extends SigmaTestingCommons | | spendingSuccess || withdrawCondition |} - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) /** * Withdraw successfully */ { val self = testBox(totalValue, spendingProp2, 0) - val output1 = testBox(totalValue / 4, pubkeyA, 0) - val output2 = testBox(totalValue / 4, pubkeyB, 0) - val output3 = testBox(totalValue / 4, pubkeyC, 0) - val output4 = testBox(totalValue / 4, pubkeyD, 0) + val output1 = testBox(totalValue / 4, treeA, 0) + val output2 = testBox(totalValue / 4, treeB, 0) + val output3 = testBox(totalValue / 4, treeC, 0) + val output4 = testBox(totalValue / 4, treeD, 0) val tx = mkTxFromOutputs(output1, output2, output3, output4) val ctx = mkCtx(5001, tx, self) successProofTest(spendingProp2, ctx, coopA, verifier) @@ -184,8 +190,8 @@ class CoopExampleSpecification extends SigmaTestingCommons */ { val self = testBox(totalValue, spendingProp2, 0) - val output1 = testBox(totalValue / 2, pubkeyB, 0) - val output2 = testBox(totalValue / 2, pubkeyC, 0) + val output1 = testBox(totalValue / 2, treeB, 0) + val output2 = testBox(totalValue / 2, treeC, 0) val tx = mkTxFromOutputs(output1, output2) val ctx = mkCtx(5001, tx, self = self) failingProofTest(spendingProp2, ctx, coopA) @@ -196,17 +202,17 @@ class CoopExampleSpecification extends SigmaTestingCommons */ { val self = testBox(totalValue, spendingProp2, 0) - val output1 = testBox(totalValue / 4, pubkeyA, 0) - val output2 = testBox(totalValue / 4, pubkeyB, 0) - val output3 = testBox(totalValue / 4, pubkeyC, 0) - val output4 = testBox(totalValue / 4, pubkeyD, 0) + val output1 = testBox(totalValue / 4, treeA, 0) + val output2 = testBox(totalValue / 4, treeB, 0) + val output3 = testBox(totalValue / 4, treeC, 0) + val output4 = testBox(totalValue / 4, treeD, 0) val tx = mkTxFromOutputs(output1, output2, output3, output4) val ctx = mkCtx(5000, tx, self) failingProofTest(spendingProp2, ctx, coopA) } - val spendingProp3 = compile(spendingEnv, + val spendingProp3 = mkTestErgoTree(compile(spendingEnv, s""" | { | @@ -216,17 +222,17 @@ class CoopExampleSpecification extends SigmaTestingCommons | | spendingSuccess || withdrawCondition | } - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) /** * Will spend correctly if all the conditions are satisfied */ { val self = testBox(totalValue, spendingProp3, 0) - val output1 = testBox(totalValue / 4, pubkeyA, 0) - val output2 = testBox(totalValue / 4, pubkeyB, 0) - val output3 = testBox(totalValue / 4, pubkeyC, 0) - val output4 = testBox(totalValue / 4, pubkeyD, 0) + val output1 = testBox(totalValue / 4, treeA, 0) + val output2 = testBox(totalValue / 4, treeB, 0) + val output3 = testBox(totalValue / 4, treeC, 0) + val output4 = testBox(totalValue / 4, treeD, 0) val tx = mkTxFromOutputs(output1, output2, output3, output4) val ctx = mkCtx(5001, tx, self) successProofTest(spendingProp2, ctx, coopA, verifier) @@ -247,7 +253,7 @@ class CoopExampleSpecification extends SigmaTestingCommons "pubkeyConstr3" -> BooleanConstant(false) ) - val spendingProp4 = compile(spendingEnv3, + val spendingProp4 = mkTestErgoTree(compile(spendingEnv3, s""" | { | @@ -257,24 +263,24 @@ class CoopExampleSpecification extends SigmaTestingCommons | | spendingSuccess || withdrawCondition | } - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) { val self = testBox(totalValue, spendingProp4, 0) - val output1 = testBox(totalValue / 4, pubkeyA, 0) - val output2 = testBox(totalValue / 4, pubkeyB, 0) - val output3 = testBox(totalValue / 4, pubkeyC, 0) - val output4 = testBox(totalValue / 4, pubkeyD, 0) + val output1 = testBox(totalValue / 4, treeA, 0) + val output2 = testBox(totalValue / 4, treeB, 0) + val output3 = testBox(totalValue / 4, treeC, 0) + val output4 = testBox(totalValue / 4, treeD, 0) val tx = mkTxFromOutputs(output1, output2, output3, output4) val ctx = mkCtx(5001, tx, self) successProofTest(spendingProp4, ctx, coopA, verifier) } - val spendingProp5 = compile(spendingEnv, "businessKey").asSigmaProp + val spendingProp5 = mkTestErgoTree(compile(spendingEnv, "businessKey").asSigmaProp) { val self = testBox(totalValue, spendingProp5, 0) - val output = testBox(totalValue, businessKey, 0) + val output = testBox(totalValue, mkTestErgoTree(businessKey), 0) val tx = mkTxFromOutputs(output) val ctx = mkCtx(1, tx, self) failingProofTest(spendingProp5, ctx, coopA) @@ -289,12 +295,12 @@ class CoopExampleSpecification extends SigmaTestingCommons "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC, "pubkeyD" -> pubkeyD, - "spendingContract1Hash" -> ByteArrayConstant(Blake2b256(spendingProp1.treeWithSegregation.bytes)), - "spendingContract2Hash" -> ByteArrayConstant(Blake2b256(spendingProp3.treeWithSegregation.bytes)) + "spendingContract1Hash" -> ByteArrayConstant(Blake2b256(spendingProp1.bytes)), + "spendingContract2Hash" -> ByteArrayConstant(Blake2b256(spendingProp3.bytes)) ) // Basic compilation - val thresholdProp = compile(thresholdEnv, + val thresholdProp = mkTestErgoTree(compile(thresholdEnv, s""" { | val votingSuccess = atLeast(3, Coll(pubkeyA, pubkeyB, pubkeyC, pubkeyD)) | val properSpending = OUTPUTS(0).value >= ${toolValue}L && @@ -306,7 +312,7 @@ class CoopExampleSpecification extends SigmaTestingCommons | | (votingSuccess && properSpending) || withdrawCondition | } - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) /** @@ -318,7 +324,7 @@ class CoopExampleSpecification extends SigmaTestingCommons val output2 = testBox(constructionValue, spendingProp3, 0) val output3 = testBox(totalValue - toolValue - constructionValue, spendingProp5, 0) //hack for avoiding None.get exception. - val dummy = testBox(0L, ErgoScriptPredef.TrueProp, 0) + val dummy = testBox(0L, TrueTree, 0) val tx = mkTxFromOutputs(output1, output2, output3, dummy) val ctx = mkCtx(2000, tx, self) @@ -334,10 +340,10 @@ class CoopExampleSpecification extends SigmaTestingCommons */ { val self = testBox(totalValue + 1L, thresholdProp, 0) - val output0 = testBox(totalValue / 4, pubkeyA, 0) - val output1 = testBox(totalValue / 4, pubkeyB, 0) - val output2 = testBox(totalValue / 4, pubkeyC, 0) - val output3 = testBox(totalValue / 4, pubkeyD, 0) + val output0 = testBox(totalValue / 4, treeA, 0) + val output1 = testBox(totalValue / 4, treeB, 0) + val output2 = testBox(totalValue / 4, treeC, 0) + val output3 = testBox(totalValue / 4, treeD, 0) val tx = mkTxFromOutputs(output0, output1, output2, output3) val ctx = mkCtx(2000, tx, self) successProofTest(thresholdProp, ctx, business, verifier) @@ -348,10 +354,10 @@ class CoopExampleSpecification extends SigmaTestingCommons */ { val self = testBox(totalValue + 1L, thresholdProp, 0) - val output0 = testBox(totalValue / 4, pubkeyA, 0) - val output1 = testBox(totalValue / 4, pubkeyB, 0) - val output2 = testBox(totalValue / 4, pubkeyC, 0) - val output3 = testBox(totalValue / 4, pubkeyD, 0) + val output0 = testBox(totalValue / 4, treeA, 0) + val output1 = testBox(totalValue / 4, treeB, 0) + val output2 = testBox(totalValue / 4, treeC, 0) + val output3 = testBox(totalValue / 4, treeD, 0) val tx = mkTxFromOutputs(output0, output1, output2, output3) val ctx = mkCtx(1000, tx, self) failingProofTest(thresholdProp, ctx, business) @@ -359,14 +365,14 @@ class CoopExampleSpecification extends SigmaTestingCommons val inputEnv = Map( - "thresholdProp" -> ByteArrayConstant(Blake2b256(thresholdProp.treeWithSegregation.bytes)), + "thresholdProp" -> ByteArrayConstant(Blake2b256(thresholdProp.bytes)), "pubkeyA" -> pubkeyA ) - val inputProp = compile(inputEnv, + val inputProp = mkTestErgoTree(compile(inputEnv, s"""(OUTPUTS(0).value == $totalValue && blake2b256(OUTPUTS(0).propositionBytes) == thresholdProp) || | (HEIGHT > 1000 && pubkeyA) - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) /** * height not higher, total value is equal diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/DHTupleExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/DHTupleExampleSpecification.scala index 342aa15cfa..8cd017d6e9 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/DHTupleExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/DHTupleExampleSpecification.scala @@ -43,7 +43,7 @@ class DHTupleExampleSpecification extends SigmaTestingCommons "g_x" -> g_x ) - val script = compile(env, + val script = mkTestErgoTree(compile(env, """{ | val g_y = OUTPUTS(0).R4[GroupElement].get | val g_xy = OUTPUTS(0).R5[GroupElement].get @@ -51,7 +51,7 @@ class DHTupleExampleSpecification extends SigmaTestingCommons | proveDHTuple(g, g_x, g_y, g_xy) || // for bob | proveDHTuple(g, g_y, g_x, g_xy) // for alice |}""".stripMargin - ).asSigmaProp + ).asSigmaProp) val inBox = testBox(10, script, 50) @@ -70,7 +70,7 @@ class DHTupleExampleSpecification extends SigmaTestingCommons val carol = new ContextEnrichingTestProvingInterpreter val carolPubKey:ProveDlog = carol.dlogSecrets.head.publicImage - val outBox = testBox(10, carolPubKey, 70, Nil, + val outBox = testBox(10, mkTestErgoTree(carolPubKey), 70, Nil, Map( R4 -> g_y, R5 -> g_xy diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/DemurrageExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/DemurrageExampleSpecification.scala index 838bbf35a8..99f34e86c0 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/DemurrageExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/DemurrageExampleSpecification.scala @@ -11,6 +11,7 @@ import sigmastate.lang.Terms._ class DemurrageExampleSpecification extends SigmaTestingCommons with CrossVersionProps { + override val printVersions: Boolean = true implicit lazy val IR = new TestingIRContext /** @@ -53,7 +54,7 @@ class DemurrageExampleSpecification extends SigmaTestingCommons "regScript" -> regScript ) - val prop = compile(env, + val propTree = mkTestErgoTree(compile(env, """{ | val outIdx = getVar[Short](127).get | val out = OUTPUTS(outIdx) @@ -72,11 +73,11 @@ class DemurrageExampleSpecification extends SigmaTestingCommons | | anyOf(Coll(regScript, c1, c2)) | } - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) val inHeight = 0 val outValue = 100 - val approxSize = createBox(outValue, prop, inHeight).bytes.length + 2 + val approxSize = createBox(outValue, propTree, inHeight).bytes.length + 2 val inValue: Int = (outValue + demurrageCoeff * demurragePeriod * approxSize).toInt val ce = ContextExtension(Map(outIdxVarId -> ShortConstant(0))) @@ -84,8 +85,8 @@ class DemurrageExampleSpecification extends SigmaTestingCommons //case 1: demurrage time hasn't come yet val currentHeight1 = inHeight + demurragePeriod - 1 - val tx1 = createTransaction(createBox(outValue, prop, currentHeight1)) - val selfBox = createBox(inValue, prop, inHeight) + val tx1 = createTransaction(createBox(outValue, propTree, currentHeight1)) + val selfBox = createBox(inValue, propTree, inHeight) val ctx1 = ErgoLikeContextTesting( currentHeight1, lastBlockUtxoRoot = AvlTreeData.dummy, @@ -96,16 +97,16 @@ class DemurrageExampleSpecification extends SigmaTestingCommons extension = ce) //user can spend all the money - val uProof1 = userProver.prove(prop, ctx1, fakeMessage).get.proof - verifier.verify(emptyEnv, prop, ctx1, uProof1, fakeMessage).get._1 shouldBe true + val uProof1 = userProver.prove(propTree, ctx1, fakeMessage).get.proof + verifier.verify(emptyEnv, propTree, ctx1, uProof1, fakeMessage).get._1 shouldBe true //miner can't spend any money - minerProver.prove(prop, ctx1, fakeMessage).isSuccess shouldBe false - verifier.verify(prop, ctx1, NoProof, fakeMessage).get._1 shouldBe false + minerProver.prove(propTree, ctx1, fakeMessage).isSuccess shouldBe false + verifier.verify(propTree, ctx1, NoProof, fakeMessage).get._1 shouldBe false //case 2: demurrage time has come val currentHeight2 = inHeight + demurragePeriod - val tx2 = createTransaction(createBox(outValue, prop, currentHeight2)) + val tx2 = createTransaction(createBox(outValue, propTree, currentHeight2)) val ctx2 = ErgoLikeContextTesting( currentHeight2, lastBlockUtxoRoot = AvlTreeData.dummy, @@ -116,11 +117,11 @@ class DemurrageExampleSpecification extends SigmaTestingCommons extension = ce) //user can spend all the money - val uProof2 = userProver.prove(prop, ctx2, fakeMessage).get.proof - verifier.verify(env, prop, ctx2, uProof2, fakeMessage).get._1 shouldBe true + val uProof2 = userProver.prove(propTree, ctx2, fakeMessage).get.proof + verifier.verify(env, propTree, ctx2, uProof2, fakeMessage).get._1 shouldBe true //miner can spend "demurrageCoeff * demurragePeriod" tokens - val b = createBox(outValue, prop, currentHeight2) + val b = createBox(outValue, propTree, currentHeight2) val tx3 = createTransaction(b) val ctx3 = ErgoLikeContextTesting( currentHeight = currentHeight2, @@ -132,12 +133,12 @@ class DemurrageExampleSpecification extends SigmaTestingCommons assert(ctx3.spendingTransaction.outputs.head.propositionBytes sameElements ctx3.boxesToSpend(ctx3.selfIndex).propositionBytes) - val mProverRes1 = minerProver.prove(prop, ctx3, fakeMessage).get + val mProverRes1 = minerProver.prove(propTree, ctx3, fakeMessage).get val _ctx3: ErgoLikeContext = ctx3.withExtension(mProverRes1.extension) - verifier.verify(prop, _ctx3, mProverRes1, fakeMessage: Array[Byte]).get._1 shouldBe true + verifier.verify(propTree, _ctx3, mProverRes1, fakeMessage: Array[Byte]).get._1 shouldBe true //miner can't spend more - val b2 = createBox(outValue - 1, prop, currentHeight2) + val b2 = createBox(outValue - 1, propTree, currentHeight2) val tx4 = createTransaction(b2) val ctx4 = ErgoLikeContextTesting( currentHeight = currentHeight2, @@ -148,11 +149,11 @@ class DemurrageExampleSpecification extends SigmaTestingCommons self = selfBox, activatedVersionInTests, extension = ce) - minerProver.prove(prop, ctx4, fakeMessage).isSuccess shouldBe false - verifier.verify(prop, ctx4, NoProof, fakeMessage).get._1 shouldBe false + minerProver.prove(propTree, ctx4, fakeMessage).isSuccess shouldBe false + verifier.verify(propTree, ctx4, NoProof, fakeMessage).get._1 shouldBe false //miner can spend less - val tx5 = createTransaction(createBox(outValue + 1, prop, currentHeight2)) + val tx5 = createTransaction(createBox(outValue + 1, propTree, currentHeight2)) val ctx5 = ErgoLikeContextTesting( currentHeight = currentHeight2, @@ -163,14 +164,14 @@ class DemurrageExampleSpecification extends SigmaTestingCommons self = selfBox, activatedVersionInTests, extension = ce) - val mProof2 = minerProver.prove(prop, ctx5, fakeMessage).get - verifier.verify(prop, ctx5, mProof2, fakeMessage).get._1 shouldBe true + val mProof2 = minerProver.prove(propTree, ctx5, fakeMessage).get + verifier.verify(propTree, ctx5, mProof2, fakeMessage).get._1 shouldBe true //miner can destroy a box if it contains less than the storage fee val iv = inValue - outValue - val b3 = createBox(iv, ErgoScriptPredef.FalseProp, currentHeight2) + val b3 = createBox(iv, FalseTree, currentHeight2) val tx6 = createTransaction(b3) - val selfBox6 = createBox(iv, prop, inHeight) + val selfBox6 = createBox(iv, propTree, inHeight) val ctx6 = ErgoLikeContextTesting( currentHeight = currentHeight2, lastBlockUtxoRoot = AvlTreeData.dummy, @@ -180,8 +181,8 @@ class DemurrageExampleSpecification extends SigmaTestingCommons self = selfBox6, activatedVersionInTests, extension = ce) - val mProof3 = minerProver.prove(prop, ctx6, fakeMessage).get - verifier.verify(prop, ctx6, mProof3, fakeMessage).get._1 shouldBe true + val mProof3 = minerProver.prove(propTree, ctx6, fakeMessage).get + verifier.verify(propTree, ctx6, mProof3, fakeMessage).get._1 shouldBe true } } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/FsmExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/FsmExampleSpecification.scala index 2698231cb3..11170795a7 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/FsmExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/FsmExampleSpecification.scala @@ -127,10 +127,10 @@ class FsmExampleSpecification extends SigmaTestingCommons val finalScriptCorrect = TrueLeaf - val fsmScript = SigmaOr( + val fsmScript = mkTestErgoTree(SigmaOr( SigmaAnd(isMember, DeserializeContext(scriptVarId, SSigmaProp), preservation), //going through FSM SigmaAnd(finalStateCheck, finalScriptCorrect, DeserializeContext(scriptVarId, SSigmaProp)) //leaving FSM - ) + )) //creating a box in an initial state @@ -237,7 +237,7 @@ class FsmExampleSpecification extends SigmaTestingCommons //clearing FSM out of the box in the final state - val freeBox = testBox(100, ErgoScriptPredef.TrueProp, 0) + val freeBox = testBox(100, TrueTree, 0) avlProver.performOneOperation(Lookup(ADKey @@ (transition30 ++ script4Hash))) val transition30Proof = avlProver.generateProof() diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/IcoExample.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/IcoExample.scala index eb90bf297a..3774fce497 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/IcoExample.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/IcoExample.scala @@ -7,7 +7,7 @@ import org.ergoplatform._ import scorex.crypto.authds.{ADKey, ADValue} import scorex.crypto.authds.avltree.batch._ import scorex.crypto.hash.{Digest32, Blake2b256} -import sigmastate.Values.{AvlTreeConstant, IntArrayConstant, CollectionConstant, ByteArrayConstant, SigmaPropValue, GroupElementConstant} +import sigmastate.Values._ import sigmastate._ import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestProvingInterpreter, SigmaTestingCommons} import sigmastate.helpers.ErgoLikeContextTesting @@ -242,7 +242,7 @@ class IcoExample extends SigmaTestingCommons lazy val project = new ErgoLikeTestProvingInterpreter() private val miningRewardsDelay = 720 - private val feeProp = ErgoScriptPredef.feeProposition(miningRewardsDelay) + private val feeProp = ErgoScriptPredef.feeProposition(miningRewardsDelay) // create ErgoTree v0 private val feeBytes = feeProp.bytes val env = Map( @@ -302,10 +302,13 @@ class IcoExample extends SigmaTestingCommons | // properTreeModification && valuesCorrect && selfOutputCorrect && tokensPreserved |}""".stripMargin ).asBoolValue.toSigmaProp + def withdrawalTree = mkTestErgoTree(withdrawalScript) - lazy val wsHash = Blake2b256(ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(withdrawalScript)) + def wsHash = { + Blake2b256(ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(withdrawalTree)) + } - lazy val issuanceScript: SigmaPropValue = compile(env.updated("nextStageScriptHash", wsHash), + def issuanceScript: SigmaPropValue = compile(env.updated("nextStageScriptHash", wsHash), """{ | val openTree = SELF.R5[AvlTree].get | @@ -336,9 +339,12 @@ class IcoExample extends SigmaTestingCommons |}""".stripMargin ).asSigmaProp - lazy val issuanceHash = Blake2b256(ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(issuanceScript)) + def issuanceHash = { + val tree = mkTestErgoTree(issuanceScript) + Blake2b256(ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(tree)) + } - lazy val fundingScript: SigmaPropValue = compile(env.updated("nextStageScriptHash", issuanceHash), + def fundingScript: SigmaPropValue = compile(env.updated("nextStageScriptHash", issuanceHash), """{ | | val selfIndexIsZero = INPUTS(0).id == SELF.id @@ -375,20 +381,20 @@ class IcoExample extends SigmaTestingCommons |}""".stripMargin ).asBoolValue.toSigmaProp - - property("simple ico example - fundraising stage only") { val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None) val digest = avlProver.digest val initTreeData = SigmaDsl.avlTree(new AvlTreeData(digest, AvlTreeFlags.AllOperationsAllowed, 32, None)) - val projectBoxBefore = testBox(10, fundingScript, 0, Seq(), + val fundingTree = mkTestErgoTree(fundingScript) + + val projectBoxBefore = testBox(10, fundingTree, 0, Seq(), Map(R4 -> ByteArrayConstant(Array.fill(1)(0: Byte)), R5 -> AvlTreeConstant(initTreeData))) val funderBoxCount = 2000 val funderBoxes = (1 to funderBoxCount).map { _ => - testBox(10, Values.TrueLeaf.asSigmaProp, 0, Seq(), + testBox(10, TrueTree, 0, Seq(), Map(R4 -> ByteArrayConstant(Array.fill(32)(Random.nextInt(Byte.MaxValue).toByte)))) } @@ -403,7 +409,7 @@ class IcoExample extends SigmaTestingCommons val proof = avlProver.generateProof() val endTree = SigmaDsl.avlTree(new AvlTreeData(avlProver.digest, AvlTreeFlags.AllOperationsAllowed, 32, None)) - val projectBoxAfter = testBox(funderBoxCount * 10 - 1, fundingScript, 0, Seq(), + val projectBoxAfter = testBox(funderBoxCount * 10 - 1, fundingTree, 0, Seq(), Map(R4 -> ByteArrayConstant(Array.fill(1)(0: Byte)), R5 -> AvlTreeConstant(endTree))) val feeBox = testBox(1, feeProp, 0, Seq(), Map()) @@ -420,7 +426,7 @@ class IcoExample extends SigmaTestingCommons val projectProver = new ContextEnrichingTestProvingInterpreter() .withContextExtender(1, ByteArrayConstant(proof)) - val res = projectProver.prove(env, fundingScript, fundingContext, fakeMessage).get + val res = projectProver.prove(env, fundingTree, fundingContext, fakeMessage).get println("funding script cost: " + res.cost) println("lookup proof size: " + proof.length) @@ -432,19 +438,22 @@ class IcoExample extends SigmaTestingCommons val digest = avlProver.digest val openTreeData = SigmaDsl.avlTree(new AvlTreeData(digest, AvlTreeFlags.AllOperationsAllowed, 32, None)) - val projectBoxBeforeClosing = testBox(10, issuanceScript, 0, Seq(), + val issuanceTree = mkTestErgoTree(issuanceScript) + val projectBoxBeforeClosing = testBox(10, issuanceTree, 0, Seq(), Map(R4 -> ByteArrayConstant(Array.emptyByteArray), R5 -> AvlTreeConstant(openTreeData))) val tokenId = Digest32 @@ projectBoxBeforeClosing.id val closedTreeData = SigmaDsl.avlTree(new AvlTreeData(digest, AvlTreeFlags.RemoveOnly, 32, None)) - val projectBoxAfterClosing = testBox(1, withdrawalScript, 0, Seq(tokenId -> projectBoxBeforeClosing.value), + val projectBoxAfterClosing = testBox(1, withdrawalTree, 0, + Seq(tokenId -> projectBoxBeforeClosing.value), Map(R4 -> ByteArrayConstant(tokenId), R5 -> AvlTreeConstant(closedTreeData))) - val ergoWithdrawalBox = testBox(8, Values.TrueLeaf.asSigmaProp, 0, Seq(), Map()) + val ergoWithdrawalBox = testBox(8, TrueTree, 0, Seq(), Map()) val feeBox = testBox(1, feeProp, 0, Seq(), Map()) - val issuanceTx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(projectBoxAfterClosing, ergoWithdrawalBox, feeBox)) + val issuanceTx = ErgoLikeTransaction( + IndexedSeq(), IndexedSeq(projectBoxAfterClosing, ergoWithdrawalBox, feeBox)) val issuanceContext = ErgoLikeContextTesting( currentHeight = 1000, @@ -454,7 +463,7 @@ class IcoExample extends SigmaTestingCommons spendingTransaction = issuanceTx, self = projectBoxBeforeClosing, activatedVersionInTests) - val res = project.prove(env, issuanceScript, issuanceContext, fakeMessage).get + val res = project.prove(env, issuanceTree, issuanceContext, fakeMessage).get println("token issuance script cost: " + res.cost) } @@ -464,8 +473,8 @@ class IcoExample extends SigmaTestingCommons val funderBoxCount = 2000 val funderProps = (1 to funderBoxCount).map { _ => val keyPoint = CryptoConstants.dlogGroup.createRandomElement() - val prop = CreateProveDlog(GroupElementConstant(keyPoint)).asSigmaProp - val propBytes = DefaultSerializer.serializeErgoTree(prop) + val tree = mkTestErgoTree(CreateProveDlog(GroupElementConstant(keyPoint)).asSigmaProp) + val propBytes = DefaultSerializer.serializeErgoTree(tree) propBytes -> Longs.toByteArray(Random.nextInt(Int.MaxValue).toLong) } val funderKvs = funderProps.map { case (prop, v) => @@ -509,9 +518,11 @@ class IcoExample extends SigmaTestingCommons val totalTokenAmount = withdrawalAmounts.map(_._2).sum + 1 - val projectBoxBefore = testBox(11, withdrawalScript, 0, Seq(tokenId -> totalTokenAmount), + val projectBoxBefore = testBox(11, withdrawalTree, 0, + Seq(tokenId -> totalTokenAmount), Map(R4 -> ByteArrayConstant(tokenId), R5 -> AvlTreeConstant(fundersTree))) - val projectBoxAfter = testBox(1, withdrawalScript, 0, Seq(tokenId -> 1), + val projectBoxAfter = testBox(1, withdrawalTree, 0, + Seq(tokenId -> 1), Map(R4 -> ByteArrayConstant(tokenId), R5 -> AvlTreeConstant(finalTree))) val feeBox = testBox(1, feeProp, 0, Seq(), Map()) @@ -532,7 +543,7 @@ class IcoExample extends SigmaTestingCommons .withContextExtender(3, ByteArrayConstant(lookupProof)) .withContextExtender(4, IntArrayConstant((1 to withdrawalsCount).toArray)) - val res = projectProver.prove(env, withdrawalScript, fundingContext, fakeMessage).get + val res = projectProver.prove(env, withdrawalTree, fundingContext, fakeMessage).get println("withdrawal script cost: " + res.cost) println("remove proof size: " + removalProof.length) println("lookup proof size: " + lookupProof.length) diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala index 6d1d0862cc..faa9f2436f 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala @@ -177,7 +177,7 @@ class LetsSpecification extends SigmaTestingCommons with CrossVersionProps { sui val env = Map(ScriptNameProp -> "withdrawalScriptEnv", "letsToken" -> ByteArrayConstant(letsTokenId)) private val miningRewardsDelay = 720 - private val feeProp = ErgoScriptPredef.feeProposition(miningRewardsDelay) + private val feeProp = ErgoScriptPredef.feeProposition(miningRewardsDelay) // create ErgoTree v0 lazy val exchangeScript = compiler.compile(env, """{ @@ -227,10 +227,11 @@ class LetsSpecification extends SigmaTestingCommons with CrossVersionProps { sui | selfPubKey && properLetsToken && membersExist && diffCorrect && scriptsSaved |}""".stripMargin ).asSigmaProp + def exchangeTree = mkTestErgoTree(exchangeScript) - lazy val userContractHash = Blake2b256(ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(exchangeScript)) + def userContractHash = Blake2b256(ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(exchangeTree)) - lazy val managementScript = compiler.compile(env.updated("userContractHash", userContractHash), + def managementScript = compiler.compile(env.updated("userContractHash", userContractHash), """{ | | val selfOut = OUTPUTS(0) @@ -283,9 +284,12 @@ class LetsSpecification extends SigmaTestingCommons with CrossVersionProps { sui val digest = avlProver.digest val initTreeData = new AvlTreeData(digest, AvlTreeFlags.InsertOnly, 32, None) - val projectBoxBefore = testBox(10, managementScript, 0, + val managementTree = mkTestErgoTree(managementScript) + val projectBoxBefore = testBox(10, managementTree, 0, Seq(letsTokenId -> 1L), - Map(R4 -> AvlTreeConstant(SigmaDsl.avlTree(initTreeData)), R5 -> SigmaPropConstant(TrivialProp.TrueProp))) + Map( + R4 -> AvlTreeConstant(SigmaDsl.avlTree(initTreeData)), + R5 -> SigmaPropConstant(TrivialProp.TrueProp))) val userTokenId = Digest32 @@ projectBoxBefore.id @@ -294,11 +298,14 @@ class LetsSpecification extends SigmaTestingCommons with CrossVersionProps { sui val proof = avlProver.generateProof() val endTree = new AvlTreeData(avlProver.digest, AvlTreeFlags.InsertOnly, 32, None) - val projectBoxAfter = testBox(9, managementScript, 0, + val projectBoxAfter = testBox(9, managementTree, 0, Seq(letsTokenId -> 1L), - Map(R4 -> AvlTreeConstant(SigmaDsl.avlTree(endTree)), R5 -> SigmaPropConstant(TrivialProp.TrueProp))) + Map( + R4 -> AvlTreeConstant(SigmaDsl.avlTree(endTree)), + R5 -> SigmaPropConstant(TrivialProp.TrueProp))) + val feeBox = testBox(1, feeProp, 0, Seq(), Map()) - val userBox = testBox(1, exchangeScript, 0, Seq(userTokenId -> 1L), Map(R4 -> LongConstant(0))) + val userBox = testBox(1, exchangeTree, 0, Seq(userTokenId -> 1L), Map(R4 -> LongConstant(0))) val issuanceTx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(projectBoxAfter, userBox, feeBox)) @@ -313,7 +320,7 @@ class LetsSpecification extends SigmaTestingCommons with CrossVersionProps { sui val managementProver = new ContextEnrichingTestProvingInterpreter() .withContextExtender(1, ByteArrayConstant(proof)) - val res = managementProver.prove(env, managementScript, fundingContext, fakeMessage).get + val res = managementProver.prove(env, managementTree, fundingContext, fakeMessage).get println("new user script cost: " + res.cost) } @@ -333,21 +340,32 @@ class LetsSpecification extends SigmaTestingCommons with CrossVersionProps { sui avlProver.performOneOperation(Lookup(ADKey @@ userTokenId1)) val proof = avlProver.generateProof() - val directoryBox = testBox(10, managementScript, 0, + val managementTree = mkTestErgoTree(managementScript) + val directoryBox = testBox(10, managementTree, 0, Seq(letsTokenId -> 1L), - Map(R4 -> AvlTreeConstant(SigmaDsl.avlTree(initTreeData)), R5 -> SigmaPropConstant(TrivialProp.TrueProp))) + Map( + R4 -> AvlTreeConstant(SigmaDsl.avlTree(initTreeData)), + R5 -> SigmaPropConstant(TrivialProp.TrueProp))) val directoryDataInput = DataInput(directoryBox.id) - val userBoxBefore0 = testBox(1, exchangeScript, 0, Seq(userTokenId0 -> 1L), + val exchangeTree = mkTestErgoTree(exchangeScript) + val userBoxBefore0 = testBox(1, exchangeTree, 0, + Seq(userTokenId0 -> 1L), Map(R4 -> LongConstant(0), R5 -> SigmaPropConstant(TrivialProp.TrueProp))) - val userBoxBefore1 = testBox(1, exchangeScript, 0, Seq(userTokenId1 -> 1L), + val userBoxBefore1 = testBox(1, exchangeTree, 0, + Seq(userTokenId1 -> 1L), Map(R4 -> LongConstant(0), R5 -> SigmaPropConstant(TrivialProp.TrueProp))) - val userBoxAfter0 = testBox(1, exchangeScript, 0, Seq(userTokenId0 -> 1L), Map(R4 -> LongConstant(-5))) - val userBoxAfter1 = testBox(1, exchangeScript, 0, Seq(userTokenId1 -> 1L), Map(R4 -> LongConstant(5))) + val userBoxAfter0 = testBox(1, exchangeTree, 0, + Seq(userTokenId0 -> 1L), Map(R4 -> LongConstant(-5))) + val userBoxAfter1 = testBox(1, exchangeTree, 0, + Seq(userTokenId1 -> 1L), Map(R4 -> LongConstant(5))) - val issuanceTx = new ErgoLikeTransaction(IndexedSeq(), IndexedSeq(directoryDataInput), IndexedSeq(userBoxAfter0, userBoxAfter1)) + val issuanceTx = new ErgoLikeTransaction( + IndexedSeq(), + IndexedSeq(directoryDataInput), + IndexedSeq(userBoxAfter0, userBoxAfter1)) val exchangeContext = ErgoLikeContextTesting( currentHeight = 1000, @@ -362,7 +380,7 @@ class LetsSpecification extends SigmaTestingCommons with CrossVersionProps { sui val managementProver = new ContextEnrichingTestProvingInterpreter() .withContextExtender(1, ByteArrayConstant(proof)) - val res = managementProver.prove(env, exchangeScript, exchangeContext, fakeMessage).get + val res = managementProver.prove(env, exchangeTree, exchangeContext, fakeMessage).get println("exchange script cost: " + res.cost) } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala index a2bc75a44b..3a5d28b45c 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala @@ -32,9 +32,7 @@ class MASTExampleSpecification extends SigmaTestingCommons private val reg1 = ErgoBox.nonMandatoryRegisters.head /** - * * In the provided example simple branching by condition, based on number of inputs - * */ property("Merklized Abstract Syntax Tree - simple branching") { val scriptId = 21.toByte @@ -44,12 +42,17 @@ class MASTExampleSpecification extends SigmaTestingCommons val script1Hash = Blake2b256(script1Bytes) val script2Hash = Blake2b256(ValueSerializer.serialize(GT(SizeOf(Inputs).upcastTo(SLong), LongConstant(1)))) - val prop = AND(scriptIsCorrect, If(EQ(SizeOf(Inputs), 1), EQ(scriptHash, script1Hash), EQ(scriptHash, script2Hash))).toSigmaProp + val prop = mkTestErgoTree(AND( + scriptIsCorrect, + If( + EQ(SizeOf(Inputs), 1), + EQ(scriptHash, script1Hash), + EQ(scriptHash, script2Hash))).toSigmaProp) val input1 = testBox(20, prop, 0) val tx = UnsignedErgoLikeTransaction(IndexedSeq(input1).map(i => new UnsignedInput(i.id)), - IndexedSeq(testBox(1, ErgoScriptPredef.TrueProp, 0))) + IndexedSeq(testBox(1, TrueTree, 0))) val ctx = ErgoLikeContextTesting( currentHeight = 50, lastBlockUtxoRoot = AvlTreeData.dummy, @@ -69,10 +72,8 @@ class MASTExampleSpecification extends SigmaTestingCommons (new ErgoLikeTestInterpreter).verify(verifyEnv, prop, ctx, proof, fakeMessage).get._1 shouldBe true } - /** * In the provided example there are 5 different branches of a tree, each one require to reveal some secret. - * */ property("Merklized Abstract Syntax Tree") { val scriptId = 21.toByte @@ -100,10 +101,12 @@ class MASTExampleSpecification extends SigmaTestingCommons GetVarByteArray(proofId).get)).asOption[SByteArray] ) val scriptIsCorrect = DeserializeContext(scriptId, SBoolean) - val prop = AND(merklePathToScript, scriptIsCorrect).toSigmaProp + val prop = mkTestErgoTree(AND(merklePathToScript, scriptIsCorrect).toSigmaProp) val recipientProposition = new ContextEnrichingTestProvingInterpreter().dlogSecrets.head.publicImage - val selfBox = testBox(20, ErgoScriptPredef.TrueProp, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData))) + val selfBox = testBox(20, TrueTree, 0, + additionalTokens = Seq(), + additionalRegisters = Map(reg1 -> AvlTreeConstant(treeData))) val ctx = ErgoLikeContextTesting( currentHeight = 50, lastBlockUtxoRoot = AvlTreeData.dummy, diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/MixExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/MixExampleSpecification.scala index 1a7f6fb0e4..b626751312 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/MixExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/MixExampleSpecification.scala @@ -49,20 +49,20 @@ class MixExampleSpecification extends SigmaTestingCommons // y is Bob's secret key and h = g^y is kind of like his "public key" // The Diffie-Hellman solution is g_xy = g_y^x = g_x^y = g^xy. - val fullMixScript = compile(fullMixEnv, + val fullMixScript = mkTestErgoTree(compile(fullMixEnv, """{ | val c1 = SELF.R4[GroupElement].get | val c2 = SELF.R5[GroupElement].get | proveDlog(c2) || // either c2 is g^y | proveDHTuple(g, c1, gX, c2) // or c2 is u^y = g^xy |}""".stripMargin - ).asSigmaProp + ).asSigmaProp) val halfMixEnv = Map( ScriptNameProp -> "halfMixEnv", "g" -> g, "gX" -> gX, - "fullMixScriptHash" -> Blake2b256(fullMixScript.treeWithSegregation.bytes) + "fullMixScriptHash" -> Blake2b256(fullMixScript.bytes) ) // Note that below script allows Alice to spend the half-mix output anytime before Bob spends it. @@ -72,7 +72,7 @@ class MixExampleSpecification extends SigmaTestingCommons // The proveDHTuple instruction takes parameters (g, h, u, v) where g, h are generators (discrete log bases) // with u = g^x and v = h^x. Note that y = log_g(h), where y is Bob's secret. - val halfMixScript = compile(halfMixEnv, + val halfMixScript = mkTestErgoTree(compile(halfMixEnv, """{ | val c1 = OUTPUTS(0).R4[GroupElement].get | val c2 = OUTPUTS(0).R5[GroupElement].get @@ -88,7 +88,7 @@ class MixExampleSpecification extends SigmaTestingCommons | proveDHTuple(g, gX, c2, c1) | } |}""".stripMargin - ).asSigmaProp + ).asSigmaProp) ///////////////////////////////////////////////////////// diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala index 3e0b477302..c5fd41b6ae 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala @@ -163,7 +163,8 @@ class OracleExamplesSpecification extends SigmaTestingCommons val sinceHeight = 40 val timeout = 60 - val propAlice = withinTimeframe(sinceHeight, timeout, alicePubKey.isProven)(oracleProp).toSigmaProp + val propAlice = mkTestErgoTree( + withinTimeframe(sinceHeight, timeout, alicePubKey.isProven)(oracleProp).toSigmaProp) val sAlice = testBox(10, propAlice, 0, Seq(), Map(), boxIndex = 3) @@ -171,7 +172,8 @@ class OracleExamplesSpecification extends SigmaTestingCommons val propAlong = AND( EQ(SizeOf(Inputs), IntConstant(2)), EQ(ExtractId(ByIndex(Inputs, 0)), ByteArrayConstant(sAlice.id))) - val propBob = withinTimeframe(sinceHeight, timeout, bobPubKey.isProven)(propAlong).toSigmaProp + val propBob = mkTestErgoTree( + withinTimeframe(sinceHeight, timeout, bobPubKey.isProven)(propAlong).toSigmaProp) val sBob = testBox(10, propBob, 0, Seq(), Map(), boxIndex = 4) val ctx = ErgoLikeContextTesting( @@ -185,20 +187,22 @@ class OracleExamplesSpecification extends SigmaTestingCommons val alice = aliceTemplate .withContextExtender(22: Byte, BoxConstant(oracleBox)) .withContextExtender(23: Byte, ByteArrayConstant(proof)) - val prA = alice.prove(emptyEnv + (ScriptNameProp -> "alice_prove"), propAlice, ctx, fakeMessage).getOrThrow + val prA = alice.prove(emptyEnv + (ScriptNameProp -> "alice_prove"), + propAlice, ctx, fakeMessage).getOrThrow - val prB = bob.prove(emptyEnv + (ScriptNameProp -> "bob_prove"), propBob, ctx, fakeMessage).getOrThrow + val prB = bob.prove(emptyEnv + (ScriptNameProp -> "bob_prove"), + propBob, ctx, fakeMessage).getOrThrow val ctxv = ctx.withExtension(prA.extension) - verifier.verify(emptyEnv + (ScriptNameProp -> "alice_verify"), propAlice, ctxv, prA, fakeMessage).getOrThrow._1 shouldBe true + verifier.verify(emptyEnv + (ScriptNameProp -> "alice_verify"), + propAlice, ctxv, prA, fakeMessage).getOrThrow._1 shouldBe true - verifier.verify(emptyEnv + (ScriptNameProp -> "bob_verify"), propBob, ctx, prB, fakeMessage).getOrThrow._1 shouldBe true + verifier.verify(emptyEnv + (ScriptNameProp -> "bob_verify"), + propBob, ctx, prB, fakeMessage).getOrThrow._1 shouldBe true //todo: check timing conditions - write tests for height < 40 and >= 60 } - - /** * In previous example, Alice and Bob can use the same box with temperature written into multiple times (possibly, * in one block). Costs for a prover are high though. @@ -227,27 +231,37 @@ class OracleExamplesSpecification extends SigmaTestingCommons val oracleBox = testBox( value = 1L, - ergoTree = oraclePubKey, + ergoTree = mkTestErgoTree(oraclePubKey), creationHeight = 0, additionalRegisters = Map(reg1 -> LongConstant(temperature)) ) val contractLogic = OR( - AND(GT(ExtractRegisterAs[SLong.type](ByIndex(Inputs, 0), reg1).get, LongConstant(15)), alicePubKey.isProven), - AND(LE(ExtractRegisterAs[SLong.type](ByIndex(Inputs, 0), reg1).get, LongConstant(15)), bobPubKey.isProven) + AND( + GT( + ExtractRegisterAs[SLong.type](ByIndex(Inputs, 0), reg1).get, + LongConstant(15)), + alicePubKey.isProven), + AND( + LE( + ExtractRegisterAs[SLong.type](ByIndex(Inputs, 0), reg1).get, + LongConstant(15)), + bobPubKey.isProven) ) - val prop = AND( + val prop = mkTestErgoTree(AND( EQ(SizeOf(Inputs), IntConstant(3)), - EQ(ExtractScriptBytes(ByIndex(Inputs, 0)), ByteArrayConstant(ErgoTree.fromSigmaBoolean(oraclePubKey).bytes)), + EQ( + ExtractScriptBytes(ByIndex(Inputs, 0)), + ByteArrayConstant(mkTestErgoTree(oraclePubKey).bytes)), contractLogic - ).toSigmaProp + ).toSigmaProp) val sOracle = oracleBox val sAlice = testBox(10, prop, 0, Seq(), Map()) val sBob = testBox(10, prop, 0, Seq(), Map()) - val newBox1 = testBox(20, alicePubKey, 0) + val newBox1 = testBox(20, mkTestErgoTree(alicePubKey), 0) val newBoxes = IndexedSeq(newBox1) val spendingTransaction = createTransaction(newBoxes) @@ -293,16 +307,21 @@ class OracleExamplesSpecification extends SigmaTestingCommons |} """.stripMargin) - lazy val oracleSignature = proposition("oracleSignature", _ => pkOracle, "pkOracle") - lazy val aliceSignature = proposition("aliceSignature", _ => pkA, "pkA") - } + lazy val oracleSignature = proposition( + "oracleSignature", _ => pkOracle, "pkOracle", + scriptVersion = Some(0) // this version is required for `INPUTS(0).propositionBytes == pkOracle.propBytes` + ) - lazy val spec = TestContractSpec(suite)(new TestingIRContext) - lazy val oracle = spec.ProvingParty("Alice") - lazy val alice = spec.ProvingParty("Alice") - lazy val bob = spec.ProvingParty("Bob") + lazy val aliceSignature = proposition( + "aliceSignature", _ => pkA, "pkA") + } property("lightweight oracle example (ErgoDsl)") { + val spec = TestContractSpec(suite)(new TestingIRContext) + val oracle = spec.ProvingParty("Alice") + val alice = spec.ProvingParty("Alice") + val bob = spec.ProvingParty("Bob") + val temperature: Long = 18 val contract = OracleContract[spec.type](temperature, oracle, alice, bob)(spec) import contract.spec._ diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/RPSGameExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/RPSGameExampleSpecification.scala index 66a70e4380..454b6a7ec8 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/RPSGameExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/RPSGameExampleSpecification.scala @@ -56,7 +56,7 @@ class RPSGameExampleSpecification extends SigmaTestingCommons "k" -> h ) - val fullGameScript = compile(fullGameEnv, + val fullGameScript = mkTestErgoTree(compile(fullGameEnv, """{ | val s = getVar[Coll[Byte]](0).get // Alice's secret byte string s | val a = getVar[Byte](1).get // Alice's secret choice a (represented as a byte) @@ -75,18 +75,18 @@ class RPSGameExampleSpecification extends SigmaTestingCommons | } | } |}""".stripMargin - ).asSigmaProp + ).asSigmaProp) val halfGameEnv = Map( ScriptNameProp -> "halfGameScript", "alice" -> alicePubKey, - "fullGameScriptHash" -> Blake2b256(fullGameScript.treeWithSegregation.bytes) + "fullGameScriptHash" -> Blake2b256(fullGameScript.bytes) ) // Note that below script allows Alice to spend the half-game output anytime before Bob spends it. // We could also consider a more restricted version of the game where Alice is unable to spend the half-game output // before some minimum height. - val halfGameScript = compile(halfGameEnv, + val halfGameScript = mkTestErgoTree(compile(halfGameEnv, """{ | OUTPUTS.forall{(out:Box) => | val b = out.R4[Byte].get @@ -101,7 +101,7 @@ class RPSGameExampleSpecification extends SigmaTestingCommons | OUTPUTS(0).R7[SigmaProp].get == alice // Alice does not care for Bob's draw case | // Bob needs to ensure that OUTPUTS(1).R7 contains his public key |} - """.stripMargin).asBoolValue.toSigmaProp + """.stripMargin).asBoolValue.toSigmaProp) ///////////////////////////////////////////////////////// //// Alice starts creating a Half-Game diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/RevenueSharingExamplesSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/RevenueSharingExamplesSpecification.scala index 402c4470c3..17440752e4 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/RevenueSharingExamplesSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/RevenueSharingExamplesSpecification.scala @@ -1,10 +1,9 @@ package sigmastate.utxo.examples -import org.ergoplatform.dsl.{ContractSpec, SigmaContractSyntax, StdContracts, TestContractSpec} +import org.ergoplatform.dsl.{SigmaContractSyntax, ContractSpec, TestContractSpec, StdContracts} import sigmastate.eval.Extensions import sigmastate.helpers.SigmaTestingCommons -import special.collection.Coll -import special.sigma.{Box, Context} +import special.sigma.Context class RevenueSharingExamplesSpecification extends SigmaTestingCommons { suite => implicit lazy val IR = new TestingIRContext diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/ReversibleTxExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/ReversibleTxExampleSpecification.scala index 40084dd8ef..d1cca3d314 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/ReversibleTxExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/ReversibleTxExampleSpecification.scala @@ -82,13 +82,13 @@ class ReversibleTxExampleSpecification extends SigmaTestingCommons "carol" -> carolPubKey // this pub key can reverse payments ) - val withdrawScript = compile(withdrawEnv, + val withdrawScript = mkTestErgoTree(compile(withdrawEnv, """{ | val bob = SELF.R4[SigmaProp].get // Bob's key (or script) that Alice sent money to | val bobDeadline = SELF.R5[Int].get // after this height, Bob gets to spend unconditionally | | (bob && HEIGHT > bobDeadline) || (carol && HEIGHT <= bobDeadline) - |}""".stripMargin).asSigmaProp + |}""".stripMargin).asSigmaProp) val blocksIn24h = 500 val feeProposition = ErgoScriptPredef.feeProposition() @@ -98,10 +98,10 @@ class ReversibleTxExampleSpecification extends SigmaTestingCommons "blocksIn24h" -> blocksIn24h, "maxFee" -> 10L, "feePropositionBytes" -> feeProposition.bytes, - "withdrawScriptHash" -> Blake2b256(withdrawScript.treeWithSegregation.bytes) + "withdrawScriptHash" -> Blake2b256(withdrawScript.bytes) ) - val depositScript = compile(depositEnv, + val depositScript = mkTestErgoTree(compile(depositEnv, """{ | val isChange = {(b:Box) => b.propositionBytes == SELF.propositionBytes} | val isWithdraw = {(b:Box) => b.R5[Int].get >= HEIGHT + blocksIn24h && @@ -113,7 +113,7 @@ class ReversibleTxExampleSpecification extends SigmaTestingCommons | | alice && OUTPUTS.forall(isValidOut) && totalFeeAlt <= maxFee |}""".stripMargin - ).asSigmaProp + ).asSigmaProp) // Note: in above bobDeadline is stored in R5. After this height, Bob gets to spend unconditionally val depositAddress = Pay2SHAddress(depositScript) diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/Rule110Specification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/Rule110Specification.scala index 9619ead6c1..5a727f0ad0 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/Rule110Specification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/Rule110Specification.scala @@ -3,10 +3,10 @@ package sigmastate.utxo.examples import org.ergoplatform._ import scorex.crypto.hash.Blake2b256 import scorex.util._ -import sigmastate.Values.{BooleanConstant, ByteArrayConstant, ByteConstant, FalseLeaf, GetVarByteArray, IntConstant, LongConstant, TrueLeaf, Value} +import sigmastate.Values._ import sigmastate._ import sigmastate.eval._ -import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestInterpreter, SigmaTestingCommons} +import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, SigmaTestingCommons, ErgoLikeTestInterpreter} import sigmastate.helpers.TestingHelpers._ import sigmastate.interpreter.ContextExtension import sigmastate.lang.Terms._ @@ -53,8 +53,8 @@ class Rule110Specification extends SigmaTestingCommons | (OUTPUTS(0).propositionBytes == SELF.propositionBytes) }""".stripMargin).asBoolValue.toSigmaProp - val input = testBox(1, prop, 0, Seq(), Map(reg1 -> ByteArrayConstant(Array[Byte](0, 1, 1, 0, 1, 0)))) - val output = testBox(1, prop, 0, Seq(), Map(reg1 -> ByteArrayConstant(Array[Byte](1, 1, 1, 1, 1, 0)))) + val input = testBox(1, mkTestErgoTree(prop), 0, Seq(), Map(reg1 -> ByteArrayConstant(Array[Byte](0, 1, 1, 0, 1, 0)))) + val output = testBox(1, mkTestErgoTree(prop), 0, Seq(), Map(reg1 -> ByteArrayConstant(Array[Byte](1, 1, 1, 1, 1, 0)))) val tx = UnsignedErgoLikeTransaction(IndexedSeq(new UnsignedInput(input.id)), IndexedSeq(output)) val ctx = ErgoLikeContextTesting( @@ -65,8 +65,8 @@ class Rule110Specification extends SigmaTestingCommons tx, self = input, activatedVersionInTests).withCostLimit(maxCost) - val pr = prover.prove(prop, ctx, fakeMessage).get - verifier.verify(prop, ctx, pr, fakeMessage).get._1 shouldBe true + val pr = prover.prove(mkTestErgoTree(prop), ctx, fakeMessage).get + verifier.verify(mkTestErgoTree(prop), ctx, pr, fakeMessage).get._1 shouldBe true } @@ -206,14 +206,15 @@ class Rule110Specification extends SigmaTestingCommons val scriptIsCorrect = DeserializeContext(scriptId, SBoolean) val prop = AND(scriptIsCorrect, OR(normalCaseConditions, rightmostConditions, nLeftmostConditions, leftmostConditions)).toSigmaProp + val propTree = mkTestErgoTree(prop) // test normal case - val nIn0 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-2), YReg -> ByteConstant(0), ValReg -> t)) - val nIn1 = testBox(1, prop, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(-1), YReg -> ByteConstant(0), ValReg -> f)) - val nIn2 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(0), YReg -> ByteConstant(0), ValReg -> t)) - val nOut0 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-1), YReg -> ByteConstant(-1), ValReg -> t)) - val nOut1 = testBox(1, prop, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(-1), YReg -> ByteConstant(-1), ValReg -> t)) - val nOut2 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-1), YReg -> ByteConstant(-1), ValReg -> t)) + val nIn0 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-2), YReg -> ByteConstant(0), ValReg -> t)) + val nIn1 = testBox(1, propTree, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(-1), YReg -> ByteConstant(0), ValReg -> f)) + val nIn2 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(0), YReg -> ByteConstant(0), ValReg -> t)) + val nOut0 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-1), YReg -> ByteConstant(-1), ValReg -> t)) + val nOut1 = testBox(1, propTree, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(-1), YReg -> ByteConstant(-1), ValReg -> t)) + val nOut2 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-1), YReg -> ByteConstant(-1), ValReg -> t)) val nTx = UnsignedErgoLikeTransaction(IndexedSeq(nIn0, nIn1, nIn2).map(i => new UnsignedInput(i.id)), IndexedSeq(nOut0, nOut1, nOut2)) val nProver = new ContextEnrichingTestProvingInterpreter() @@ -227,15 +228,15 @@ class Rule110Specification extends SigmaTestingCommons nTx, self = nIn0, activatedVersionInTests) - val nProof = nProver.prove(prop, nCtx, fakeMessage).get - verifier.verify(prop, nCtx, nProof, fakeMessage).get._1 shouldBe true + val nProof = nProver.prove(propTree, nCtx, fakeMessage).get + verifier.verify(propTree, nCtx, nProof, fakeMessage).get._1 shouldBe true // test rightmost case - val rIn0 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-1), YReg -> ByteConstant(0), ValReg -> t)) - val rIn1 = testBox(1, prop, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(0), YReg -> ByteConstant(0), ValReg -> t)) - val rOut0 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(0), YReg -> ByteConstant(-1), ValReg -> t)) - val rOut1 = testBox(1, prop, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(0), YReg -> ByteConstant(-1), ValReg -> t)) - val rOut2 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(0), YReg -> ByteConstant(-1), ValReg -> t)) + val rIn0 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-1), YReg -> ByteConstant(0), ValReg -> t)) + val rIn1 = testBox(1, propTree, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(0), YReg -> ByteConstant(0), ValReg -> t)) + val rOut0 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(0), YReg -> ByteConstant(-1), ValReg -> t)) + val rOut1 = testBox(1, propTree, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(0), YReg -> ByteConstant(-1), ValReg -> t)) + val rOut2 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(0), YReg -> ByteConstant(-1), ValReg -> t)) val rTx = UnsignedErgoLikeTransaction(IndexedSeq(rIn0, rIn1).map(i => new UnsignedInput(i.id)), IndexedSeq(rOut0, rOut1, rOut2)) val rProver = new ContextEnrichingTestProvingInterpreter() @@ -249,15 +250,15 @@ class Rule110Specification extends SigmaTestingCommons rTx, self = rIn0, activatedVersionInTests) - val rProof = rProver.prove(prop, rCtx, fakeMessage).get - verifier.verify(prop, rCtx, rProof, fakeMessage).get._1 shouldBe true + val rProof = rProver.prove(propTree, rCtx, fakeMessage).get + verifier.verify(propTree, rCtx, rProof, fakeMessage).get._1 shouldBe true // test next to leftmost case - val lnIn0 = testBox(1, prop, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(-6), YReg -> ByteConstant(-6), ValReg -> t)) - val lnIn1 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-5), YReg -> ByteConstant(-6), ValReg -> t)) - val lnOut0 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-6), YReg -> ByteConstant(-7), ValReg -> t)) - val lnOut1 = testBox(1, prop, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(-6), YReg -> ByteConstant(-7), ValReg -> t)) - val lnOut2 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-6), YReg -> ByteConstant(-7), ValReg -> t)) + val lnIn0 = testBox(1, propTree, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(-6), YReg -> ByteConstant(-6), ValReg -> t)) + val lnIn1 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-5), YReg -> ByteConstant(-6), ValReg -> t)) + val lnOut0 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-6), YReg -> ByteConstant(-7), ValReg -> t)) + val lnOut1 = testBox(1, propTree, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(-6), YReg -> ByteConstant(-7), ValReg -> t)) + val lnOut2 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-6), YReg -> ByteConstant(-7), ValReg -> t)) val lnTx = UnsignedErgoLikeTransaction(IndexedSeq(lnIn0, lnIn1).map(i => new UnsignedInput(i.id)), IndexedSeq(lnOut0, lnOut1, lnOut2)) val lnProver = new ContextEnrichingTestProvingInterpreter() @@ -271,14 +272,14 @@ class Rule110Specification extends SigmaTestingCommons lnTx, self = lnIn0, activatedVersionInTests) - val lnProof = lnProver.prove(prop, lnCtx, fakeMessage).get - verifier.verify(prop, lnCtx, lnProof, fakeMessage).get._1 shouldBe true + val lnProof = lnProver.prove(propTree, lnCtx, fakeMessage).get + verifier.verify(propTree, lnCtx, lnProof, fakeMessage).get._1 shouldBe true // test leftmost case - val lIn0 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-6), YReg -> ByteConstant(-6), ValReg -> t)) - val lOut0 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-7), YReg -> ByteConstant(-7), ValReg -> t)) - val lOut1 = testBox(1, prop, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(-7), YReg -> ByteConstant(-7), ValReg -> t)) - val lOut2 = testBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-7), YReg -> ByteConstant(-7), ValReg -> t)) + val lIn0 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-6), YReg -> ByteConstant(-6), ValReg -> t)) + val lOut0 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-7), YReg -> ByteConstant(-7), ValReg -> t)) + val lOut1 = testBox(1, propTree, 0, Seq(), Map(MidReg -> t, XReg -> ByteConstant(-7), YReg -> ByteConstant(-7), ValReg -> t)) + val lOut2 = testBox(1, propTree, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-7), YReg -> ByteConstant(-7), ValReg -> t)) val lTx = UnsignedErgoLikeTransaction(IndexedSeq(lIn0).map(i => new UnsignedInput(i.id)), IndexedSeq(lOut0, lOut1, lOut2)) val lProver = new ContextEnrichingTestProvingInterpreter() @@ -292,8 +293,8 @@ class Rule110Specification extends SigmaTestingCommons lTx, self = lIn0, activatedVersionInTests) - val lProof = lProver.prove(prop, lCtx, fakeMessage).get - verifier.verify(prop, lCtx, lProof, fakeMessage).get._1 shouldBe true + val lProof = lProver.prove(propTree, lCtx, fakeMessage).get + verifier.verify(propTree, lCtx, lProof, fakeMessage).get._1 shouldBe true } @@ -390,7 +391,7 @@ class Rule110Specification extends SigmaTestingCommons row2, rule110 )).toSigmaProp - + val propTree = mkTestErgoTree(prop) val hash = Blake2b256 val txId = hash.hash(scala.util.Random.nextString(12).getBytes) @@ -402,7 +403,9 @@ class Rule110Specification extends SigmaTestingCommons val row = RowReg -> LongConstant(0) val column = ColumnReg -> LongConstant(col) val value = if (col == 15) ValueReg -> TrueLeaf else ValueReg -> FalseLeaf - testBox(0L, prop, 0, Nil, Map(row, column, value), txId.toModifierId, col.toShort) + testBox(0L, + propTree, + 0, Nil, Map(row, column, value), txId.toModifierId, col.toShort) } val initBlock = FullBlock( @@ -433,7 +436,7 @@ class Rule110Specification extends SigmaTestingCommons val value = ValueReg -> BooleanConstant.fromBoolean(calcRule110(lv, cv, rv)) - val c = new ErgoBoxCandidate(0L, prop, row, Colls.emptyColl, Map(RowReg -> LongConstant(row), ColumnReg -> LongConstant(col), value)) + val c = new ErgoBoxCandidate(0L, propTree, row, Colls.emptyColl, Map(RowReg -> LongConstant(row), ColumnReg -> LongConstant(col), value)) val ut = UnsignedErgoLikeTransaction( IndexedSeq(new UnsignedInput(left.id), new UnsignedInput(center.id), new UnsignedInput(right.id)), diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/TimedPaymentExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/TimedPaymentExampleSpecification.scala index d795f35bef..4345a0cd8a 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/TimedPaymentExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/TimedPaymentExampleSpecification.scala @@ -17,6 +17,7 @@ class TimedPaymentExampleSpecification extends SigmaTestingCommons import ErgoAddressEncoder._ implicit val ergoAddressEncoder: ErgoAddressEncoder = new ErgoAddressEncoder(TestnetNetworkPrefix) + property("Evaluation - Timed payment Tx Example") { val alice = new ContextEnrichingTestProvingInterpreter // customer at coffee shop @@ -30,9 +31,9 @@ class TimedPaymentExampleSpecification extends SigmaTestingCommons "alice" -> alicePubKey ) - val script = compile(env, + val script = mkTestErgoTree(compile(env, """{ alice && HEIGHT <= getVar[Int](1).get }""".stripMargin - ).asSigmaProp + ).asSigmaProp) val address = Pay2SHAddress(script) // The above is a "timed address". diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/TrustlessLETS.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/TrustlessLETS.scala index 501e5d10e8..347d3b74c9 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/TrustlessLETS.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/TrustlessLETS.scala @@ -9,6 +9,7 @@ import sigmastate.lang.Terms._ class TrustlessLETS1 extends SigmaTestingCommons { private implicit lazy val IR: TestingIRContext = new TestingIRContext + property("Evaluation - LETS1 Example") { val rateTokenID = Blake2b256("rate") @@ -22,7 +23,7 @@ class TrustlessLETS1 extends SigmaTestingCommons { "minWithdrawTime" -> minWithdrawTime ) - val memberBoxScript = compile(memberBoxEnv, + val memberBoxScript = mkTestErgoTree(compile(memberBoxEnv, """{ |val validRateOracle = CONTEXT.dataInputs(0).tokens(0)._1 == rateTokenID |val rate = CONTEXT.dataInputs(0).R4[Int].get @@ -71,17 +72,17 @@ class TrustlessLETS1 extends SigmaTestingCommons { | (pubKey && correctErgs) // ... or a signature is present and output box has correct ergs |) |}""".stripMargin - ).asSigmaProp + ).asSigmaProp) val tokenBoxEnv = Map( ScriptNameProp -> "tokenBoxEnv", "rateTokenID" -> rateTokenID, "letsTokenID" -> letsTokenID, "minErgsToJoin" -> minErgsToJoin, - "memberBoxScriptHash" -> Blake2b256(memberBoxScript.treeWithSegregation.bytes) + "memberBoxScriptHash" -> Blake2b256(memberBoxScript.bytes) ) - val tokenScript = compile(tokenBoxEnv, + val tokenScript = mkTestErgoTree(compile(tokenBoxEnv, """{ |// a tokenBox stores the membership tokens. |val tokenBox = OUTPUTS(0) // first output should contain remaining LETS tokens @@ -102,7 +103,7 @@ class TrustlessLETS1 extends SigmaTestingCommons { |tokenBox.tokens(0)._2 == SELF.tokens(0)._2 - numLetsBoxes && // quantity is preserved |tokenBox.propositionBytes == SELF.propositionBytes // script is preserved |} - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) val tokenBoxCreationHeight = 70 val tokenAmount = 10 // LongConstant(10) @@ -118,6 +119,7 @@ class TrustlessLETS2 extends SigmaTestingCommons { // Non-refundable ergs // Zero sum private implicit lazy val IR: TestingIRContext = new TestingIRContext + property("Evaluation - LETS2 Example") { val rateTokenID = Blake2b256("rate") @@ -130,7 +132,7 @@ class TrustlessLETS2 extends SigmaTestingCommons { "maxNegativeBalance" -> -10000 ) - val memberBoxScript = compile(memberBoxEnv, + val memberBoxScript = mkTestErgoTree(compile(memberBoxEnv, """{ |val inBalance = SELF.R4[Long].get |val pubKey = SELF.R5[SigmaProp].get @@ -159,7 +161,7 @@ class TrustlessLETS2 extends SigmaTestingCommons { |OUTPUTS(index).R5[SigmaProp].get == pubKey && |receiver || pubKey |}""".stripMargin - ).asSigmaProp + ).asSigmaProp) val trustedProver = new ContextEnrichingTestProvingInterpreter val trustedPubKey = trustedProver.dlogSecrets.head.publicImage @@ -170,10 +172,10 @@ class TrustlessLETS2 extends SigmaTestingCommons { "letsTokenID" -> letsTokenID, "minErgsToJoin" -> minErgsToJoin, "trustedPubKey" -> trustedPubKey, - "memberBoxScriptHash" -> Blake2b256(memberBoxScript.treeWithSegregation.bytes) + "memberBoxScriptHash" -> Blake2b256(memberBoxScript.bytes) ) - val tokenScript = compile(tokenBoxEnv, + val tokenScript = mkTestErgoTree(compile(tokenBoxEnv, """{ |val tokenBox = OUTPUTS(0) // first output should contain remaining LETS tokens and joining fee added |val letsBox = OUTPUTS(1) // second output contains membership box that is created @@ -204,7 +206,7 @@ class TrustlessLETS2 extends SigmaTestingCommons { | |memberSpend || trustedPubKeySpend |} - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) val tokenBoxCreationHeight = 70 val tokenAmount = 10 // LongConstant(10) @@ -221,6 +223,7 @@ class TrustlessLETS3 extends SigmaTestingCommons { // Positive sum private implicit lazy val IR: TestingIRContext = new TestingIRContext + property("Evaluation - LETS3 Example") { val rateTokenID = Blake2b256("rate") @@ -235,7 +238,7 @@ class TrustlessLETS3 extends SigmaTestingCommons { "minWithdrawTime" -> minWithdrawTime ) - val memberBoxScript = compile(memberBoxEnv, + val memberBoxScript = mkTestErgoTree(compile(memberBoxEnv, """{ |val validRateOracle = CONTEXT.dataInputs(0).tokens(0)._1 == rateTokenID |val rate = CONTEXT.dataInputs(0).R4[Int].get @@ -279,7 +282,7 @@ class TrustlessLETS3 extends SigmaTestingCommons { |OUTPUTS(index).R6[Long].get == SELF.R6[Long].get && // creation height |(receiver || (pubKey && correctErgs)) |}""".stripMargin - ).asSigmaProp + ).asSigmaProp) val trustedProver = new ContextEnrichingTestProvingInterpreter val trustedPubKey = trustedProver.dlogSecrets.head.publicImage @@ -290,10 +293,10 @@ class TrustlessLETS3 extends SigmaTestingCommons { "letsTokenID" -> letsTokenID, "minErgsToJoin" -> minErgsToJoin, "trustedPubKey" -> trustedPubKey, - "memberBoxScriptHash" -> Blake2b256(memberBoxScript.treeWithSegregation.bytes) + "memberBoxScriptHash" -> Blake2b256(memberBoxScript.bytes) ) - val tokenScript = compile(tokenBoxEnv, + val tokenScript = mkTestErgoTree(compile(tokenBoxEnv, """{ |val validRateOracle = CONTEXT.dataInputs(0).tokens(0)._1 == rateTokenID |val rate = CONTEXT.dataInputs(0).R4[Int].get @@ -318,7 +321,7 @@ class TrustlessLETS3 extends SigmaTestingCommons { | |validLetsBox && validTokenBox |} - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) val tokenBoxCreationHeight = 70 val tokenAmount = 10 // LongConstant(10) @@ -345,7 +348,7 @@ class TrustlessLETS4 extends SigmaTestingCommons { "letsTokenID" -> letsTokenID ) - val memberBoxScript = compile(memberBoxEnv, + val memberBoxScript = mkTestErgoTree(compile(memberBoxEnv, """{ |val inBalance = SELF.R4[Long].get // LETS balance of current input |val pubKey = SELF.R5[SigmaProp].get // Owner of the current input @@ -378,7 +381,7 @@ class TrustlessLETS4 extends SigmaTestingCommons { |OUTPUTS(index).R5[SigmaProp].get == pubKey && |receiver || pubKey |}""".stripMargin - ).asSigmaProp + ).asSigmaProp) val trustedProver = new ContextEnrichingTestProvingInterpreter val trustedPubKey = trustedProver.dlogSecrets.head.publicImage @@ -389,10 +392,10 @@ class TrustlessLETS4 extends SigmaTestingCommons { "letsTokenID" -> letsTokenID, "minErgsToJoin" -> minErgsToJoin, "trustedPubKey" -> trustedPubKey, - "memberBoxScriptHash" -> Blake2b256(memberBoxScript.treeWithSegregation.bytes) + "memberBoxScriptHash" -> Blake2b256(memberBoxScript.bytes) ) - val tokenScript = compile(tokenBoxEnv, + val tokenScript = mkTestErgoTree(compile(tokenBoxEnv, """{ |val validRateOracle = CONTEXT.dataInputs(0).tokens(0)._1 == rateTokenID |val rate = CONTEXT.dataInputs(0).R4[Int].get @@ -425,7 +428,7 @@ class TrustlessLETS4 extends SigmaTestingCommons { | |memberSpend || trustedPubKeySpend |} - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) val tokenBoxCreationHeight = 70 val tokenAmount = 10 // LongConstant(10) diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/XorGameExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/XorGameExampleSpecification.scala index b53aa6beb6..786a7ba5d8 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/XorGameExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/XorGameExampleSpecification.scala @@ -15,6 +15,7 @@ import sigmastate.lang.Terms._ class XorGameExampleSpecification extends SigmaTestingCommons with CrossVersionProps { private implicit lazy val IR: TestingIRContext = new TestingIRContext + /** XOR game: Alice creates a XOR game of "playAmount" ergs by creating a Half-game UTXO called the "halfGameOutput" output below. @@ -55,7 +56,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons "h" -> h ) - val fullGameScript = compile(fullGameEnv, + val fullGameScript = mkTestErgoTree(compile(fullGameEnv, """{ | val s = getVar[Coll[Byte]](0).get // Alice's secret byte string s | val a = getVar[Byte](1).get // Alice's secret bit a (represented as a byte) @@ -69,18 +70,18 @@ class XorGameExampleSpecification extends SigmaTestingCommons | } | } |}""".stripMargin - ).asSigmaProp + ).asSigmaProp) val halfGameEnv = Map( ScriptNameProp -> "halfGameScript", "alice" -> alicePubKey, - "fullGameScriptHash" -> Blake2b256(fullGameScript.treeWithSegregation.bytes) + "fullGameScriptHash" -> Blake2b256(fullGameScript.bytes) ) // Note that below script allows Alice to spend the half-game output anytime before Bob spends it. // We could also consider a more restricted version of the game where Alice is unable to spend the half-game output // before some minimum height. - val halfGameScript = compile(halfGameEnv, + val halfGameScript = mkTestErgoTree(compile(halfGameEnv, """{ | alice || { | val out = OUTPUTS(0) @@ -95,7 +96,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons | blake2b256(out.propositionBytes) == fullGameScriptHash | } |} - """.stripMargin).asSigmaProp + """.stripMargin).asSigmaProp) ///////////////////////////////////////////////////////// //// Alice starts creating a Half-Game @@ -122,7 +123,8 @@ class XorGameExampleSpecification extends SigmaTestingCommons // Alice pays to Carol. Game ends here val carol = new ContextEnrichingTestProvingInterpreter - val carolPubKey:ProveDlog = carol.dlogSecrets.head.publicImage + val carolPubKey: ProveDlog = carol.dlogSecrets.head.publicImage + val carolPubKeyTree = mkTestErgoTree(carolPubKey) val abortHalfGameHeight = halfGameCreationHeight + 10 // can be anything @@ -133,7 +135,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons // // val abortHalfGameOutput = ErgoBox(playAmount, carolPubKey, abortHalfGameHeight) // gives error - val abortHalfGameOutput = testBox(playAmount, carolPubKey, abortHalfGameHeight, Nil, + val abortHalfGameOutput = testBox(playAmount, carolPubKeyTree, abortHalfGameHeight, Nil, Map( R4 -> ByteConstant(0), // dummy data. Has to be given, even though not needed as per halfGameScript R5 -> SigmaPropConstant((new ContextEnrichingTestProvingInterpreter).dlogSecrets.head.publicImage), // dummy statement @@ -227,7 +229,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons // assume winner is paying to Carol // note that playAmount*2 below is not checked. It could be anything. - val gameOverOutput = testBox(playAmount*2, carolPubKey, gameOverHeight) + val gameOverOutput = testBox(playAmount*2, carolPubKeyTree, gameOverHeight) //normally this transaction would invalid (why?), but we're not checking it in this test val gameOverTx = createTransaction(gameOverOutput) @@ -255,7 +257,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons // assume Bob is paying to Carol // note that playAmount*2 below is not checked. It could be anything. - val defaultWinOutput = testBox(playAmount*2, carolPubKey, defaultWinHeight) + val defaultWinOutput = testBox(playAmount*2, carolPubKeyTree, defaultWinHeight) //normally this transaction would invalid (why?), but we're not checking it in this test val defaultWinTx = createTransaction(defaultWinOutput) diff --git a/sigmastate/src/test/scala/special/sigma/ContractsTestkit.scala b/sigmastate/src/test/scala/special/sigma/ContractsTestkit.scala index a01720b0d1..884e8523be 100644 --- a/sigmastate/src/test/scala/special/sigma/ContractsTestkit.scala +++ b/sigmastate/src/test/scala/special/sigma/ContractsTestkit.scala @@ -1,12 +1,13 @@ package special.sigma -import scalan._ import special.collection.{Coll, CollOverArrayBuilder} import scalan.RType -import sigmastate.{AvlTreeData, TrivialProp} +import sigmastate.Values.ErgoTree +import sigmastate.{AvlTreeData, Values} import sigmastate.eval._ import sigmastate.eval.Extensions._ import sigmastate.helpers.TestingHelpers._ +import scalan._ // imports implicit ClassTag trait ContractsTestkit { val R0 = 0.toByte; @@ -57,7 +58,9 @@ trait ContractsTestkit { val AliceId = Array[Byte](1) // 0x0001 def newAliceBox(id: Byte, value: Long): Box = { - val ergoBox = testBox(value, TrivialProp.TrueProp.toSigmaProp, 0, Seq(), Map()) + val ergoBox = testBox(value, + ErgoTree.fromProposition(Values.TrueSigmaProp), + creationHeight = 0, additionalTokens = Seq(), additionalRegisters = Map()) new CostingBox(false, ergoBox) } diff --git a/sigmastate/src/test/scala/special/sigma/SigmaDslSpecification.scala b/sigmastate/src/test/scala/special/sigma/SigmaDslSpecification.scala index a5ad065d45..2291d762b5 100644 --- a/sigmastate/src/test/scala/special/sigma/SigmaDslSpecification.scala +++ b/sigmastate/src/test/scala/special/sigma/SigmaDslSpecification.scala @@ -3,11 +3,10 @@ package special.sigma import java.lang.reflect.InvocationTargetException import java.math.BigInteger -import org.ergoplatform.ErgoScriptPredef.TrueProp import org.ergoplatform._ import org.ergoplatform.settings.ErgoAlgos -import org.scalacheck.Gen -import scalan.{ExactNumeric, RType} +import org.scalacheck.{Arbitrary, Gen} +import scalan.{ExactOrdering, ExactNumeric, RType} import scorex.crypto.authds.avltree.batch._ import scorex.crypto.authds.{ADDigest, ADKey, ADValue} import scorex.crypto.hash.{Digest32, Blake2b256} @@ -29,9 +28,12 @@ import sigmastate.utils.Helpers import sigmastate.utils.Helpers._ import sigmastate.helpers.TestingHelpers._ -import scala.util.{Success, Failure} +import scala.util.{Success, Failure, Try} import OrderingOps._ import org.ergoplatform.ErgoBox.AdditionalRegisters +import org.scalacheck.Arbitrary._ +import org.scalacheck.Gen.frequency +import scalan.RType._ import scorex.util.ModifierId import sigmastate.basics.ProveDHTuple @@ -46,6 +48,176 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui implicit def IR = createIR() + object TestData { + val BigIntZero: BigInt = CBigInt(new BigInteger("0", 16)) + val BigIntOne: BigInt = CBigInt(new BigInteger("1", 16)) + val BigIntMinusOne: BigInt = CBigInt(new BigInteger("-1", 16)) + val BigInt10: BigInt = CBigInt(new BigInteger("a", 16)) + val BigInt11: BigInt = CBigInt(new BigInteger("b", 16)) + + val ge1str = "03358d53f01276211f92d0aefbd278805121d4ff6eb534b777af1ee8abae5b2056" + val ge2str = "02dba7b94b111f3894e2f9120b577da595ec7d58d488485adf73bf4e153af63575" + val ge3str = "0290449814f5671172dd696a61b8aa49aaa4c87013f56165e27d49944e98bc414d" + + val ge1 = Helpers.decodeGroupElement(ge1str) + val ge2 = Helpers.decodeGroupElement(ge2str) + val ge3 = Helpers.decodeGroupElement(ge3str) + + val t1: AvlTree = CAvlTree( + AvlTreeData( + ADDigest @@ ErgoAlgos.decodeUnsafe("000183807f66b301530120ff7fc6bd6601ff01ff7f7d2bedbbffff00187fe89094"), + AvlTreeFlags(false, true, true), + 1, + Some(1) + ) + ) + val t2: AvlTree = CAvlTree( + AvlTreeData( + ADDigest @@ ErgoAlgos.decodeUnsafe("ff000d937f80ffd731ed802d24358001ff8080ff71007f00ad37e0a7ae43fff95b"), + AvlTreeFlags(false, false, false), + 32, + Some(64) + ) + ) + val t3: AvlTree = CAvlTree( + AvlTreeData( + ADDigest @@ ErgoAlgos.decodeUnsafe("3100d2e101ff01fc047c7f6f00ff80129df69a5090012f01ffca99f5bfff0c8036"), + AvlTreeFlags(true, false, false), + 128, + None + ) + ) + + val b1: Box = CostingBox( + false, + new ErgoBox( + 9223372036854775807L, + new ErgoTree( + 16.toByte, + Array( + SigmaPropConstant( + CSigmaProp( + ProveDlog( + Helpers.decodeECPoint( + "0297c44a12f4eb99a85d298fa3ba829b5b42b9f63798c980ece801cc663cc5fc9e" + ) + ) + ) + ) + ), + Right(ConstantPlaceholder(0, SSigmaProp)) + ), + Coll( + (Digest32 @@ (ErgoAlgos.decodeUnsafe("6e789ab7b2fffff12280a6cd01557f6fb22b7f80ff7aff8e1f7f15973d7f0001")), + 10000000L), + (Digest32 @@ (ErgoAlgos.decodeUnsafe("a3ff007f00057600808001ff8f8000019000ffdb806fff7cc0b6015eb37fa600")), + 500L) + ), + Map( + ErgoBox.R5 -> ByteArrayConstant(Helpers.decodeBytes("7fc87f7f01ff")), + ErgoBox.R4 -> FalseLeaf + ), + ModifierId @@ ("218301ae8000018008637f0021fb9e00018055486f0b514121016a00ff718080"), + 22588.toShort, + 677407 + ) + ) + + val b2: Box = CostingBox( + false, + new ErgoBox( + 12345L, + new ErgoTree( + 0.toByte, + Vector(), + Right( + BoolToSigmaProp( + AND( + ConcreteCollection( + Array( + FalseLeaf, + XorOf( + ConcreteCollection(Array(EQ(IntConstant(1), IntConstant(1)), FalseLeaf), SBoolean) + ) + ), + SBoolean + ) + ) + ) + ) + ), + Coll(), + Map( + ErgoBox.R5 -> ByteArrayConstant( + Helpers.decodeBytes( + "297000800b80f1d56c809a8c6affbed864b87f007f6f007f00ac00018c01c4fdff011088807f0100657f00f9ab0101ff6d65" + ) + ), + ErgoBox.R4 -> TrueLeaf, + ErgoBox.R7 -> LongConstant(9223372036854775807L), + ErgoBox.R6 -> LongConstant(2115927197107005906L) + ), + ModifierId @@ ("003bd5c630803cfff6c1ff7f7fb980ff136afc011f8080b8b04ad4dbda2d7f4e"), + 1.toShort, + 1000000 + ) + ) + + val preH1: PreHeader = CPreHeader( + 0.toByte, + Helpers.decodeBytes("7fff7fdd6f62018bae0001006d9ca888ff7f56ff8006573700a167f17f2c9f40"), + 6306290372572472443L, + -3683306095029417063L, + 1, + Helpers.decodeGroupElement("026930cb9972e01534918a6f6d6b8e35bc398f57140d13eb3623ea31fbd069939b"), + Helpers.decodeBytes("ff8087") + ) + + val preH2: PreHeader = preH1.asInstanceOf[CPreHeader].copy(height = 2) + + val treeData = AvlTreeData( + ADDigest @@ ( + ErgoAlgos.decodeUnsafe("010180017f7f7b7f720c00007f7f7f0f01e857a626f37f1483d06af8077a008080") + ), + AvlTreeFlags(false, true, false), + 728138553, + Some(2147483647) + ) + val h1: Header = CHeader( + Helpers.decodeBytes("957f008001808080ffe4ffffc8f3802401df40006aa05e017fa8d3f6004c804a"), + 0.toByte, + Helpers.decodeBytes("0180dd805b0000ff5400b997fd7f0b9b00de00fb03c47e37806a8186b94f07ff"), + Helpers.decodeBytes("01f07f60d100ffb970c3007f60ff7f24d4070bb8fffa7fca7f34c10001ffe39d"), + CAvlTree(treeData), + Helpers.decodeBytes("804101ff01000080a3ffbd006ac080098df132a7017f00649311ec0e00000100"), + 1L, + -1L, + 1, + Helpers.decodeBytes("e57f80885601b8ff348e01808000bcfc767f2dd37f0d01015030ec018080bc62"), + Helpers.decodeGroupElement("039bdbfa0b49cc6bef58297a85feff45f7bbeb500a9d2283004c74fcedd4bd2904"), + Helpers.decodeGroupElement("0361299207fa392231e23666f6945ae3e867b978e021d8d702872bde454e9abe9c"), + Helpers.decodeBytes("7f4f09012a807f01"), + CBigInt(new BigInteger("-e24990c47e15ed4d0178c44f1790cc72155d516c43c3e8684e75db3800a288", 16)), + Helpers.decodeBytes("7f0180") + ) + val h2: Header = h1.asInstanceOf[CHeader].copy(height = 2) + + } + import TestData._ + + prepareSamples[BigInt] + prepareSamples[GroupElement] + prepareSamples[AvlTree] + prepareSamples[Box] + prepareSamples[PreHeader] + prepareSamples[Header] + prepareSamples[(BigInt, BigInt)] + prepareSamples[(GroupElement, GroupElement)] + prepareSamples[(AvlTree, AvlTree)] + prepareSamples[(Box, Box)] + prepareSamples[(PreHeader, PreHeader)] + prepareSamples[(Header, Header)] + ///===================================================== /// Boolean type operations ///----------------------------------------------------- @@ -547,6 +719,134 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui )) } + def swapArgs[A](cases: Seq[((A, A), Expected[Boolean])], cost: Int) = + cases.map { case ((x, y), res) => ((y, x), res.copy(cost = cost)) } + + def newCasesFrom[A, R](cases: Seq[(A, A)])(getExpectedRes: (A, A) => R, cost: Int) = + cases.map { case (x, y) => + ((x, y), Expected(Success(getExpectedRes(x, y)), cost = 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)]) = { + val nameA = RType[A].name + val tpeA = Evaluation.rtypeToSType(tA) + verifyCases(cases, + existingFeature( + { (x: (A, A)) => expectedFunc(x._1, x._2) }, + s"""{ (x: ($nameA, $nameA)) => x._1 $opName x._2 }""".stripMargin, + { + val tPair = SPair(tpeA, tpeA) + FuncValue( + Array((1, tPair)), + op( + SelectField.typed[Value[SType]](ValUse(1, tPair), 1.toByte), + SelectField.typed[Value[SType]](ValUse(1, tPair), 2.toByte) + ) + ) + } + ), + preGeneratedSamples = Some(sampled.samples)) + } + + property("Byte LT, GT, NEQ") { + val o = ExactOrdering.ByteIsExactOrdering + def expect(v: Boolean) = Expected(Success(v), 36328) + val LT_cases: Seq[((Byte, Byte), Expected[Boolean])] = Seq( + (-128.toByte, -128.toByte) -> expect(false), + (-128.toByte, -127.toByte) -> expect(true), + (-128.toByte, -1.toByte) -> expect(true), + (-128.toByte, 0.toByte) -> expect(true), + (-128.toByte, 1.toByte) -> expect(true), + (-128.toByte, 127.toByte) -> expect(true), + (-120.toByte, -128.toByte) -> expect(false), + (-120.toByte, -121.toByte) -> expect(false), + (-120.toByte, -120.toByte) -> expect(false), + (-120.toByte, -82.toByte) -> expect(true), + (-103.toByte, -1.toByte) -> expect(true), + (-103.toByte, -0.toByte) -> expect(true), + (-103.toByte, 1.toByte) -> expect(true), + (-103.toByte, 127.toByte) -> expect(true), + (-1.toByte, -2.toByte) -> expect(false), + (-1.toByte, -1.toByte) -> expect(false), + (-1.toByte, 0.toByte) -> expect(true), + (-1.toByte, 1.toByte) -> expect(true), + (0.toByte, -128.toByte) -> expect(false), + (0.toByte, -1.toByte) -> expect(false), + (0.toByte, 0.toByte) -> expect(false), + (0.toByte, 1.toByte) -> expect(true), + (0.toByte, 60.toByte) -> expect(true), + (0.toByte, 127.toByte) -> expect(true), + (1.toByte, -1.toByte) -> expect(false), + (1.toByte, 0.toByte) -> expect(false), + (1.toByte, 26.toByte) -> expect(true), + (7.toByte, -32.toByte) -> expect(false), + (7.toByte, 0.toByte) -> expect(false), + (33.toByte, 1.toByte) -> expect(false), + (126.toByte, 127.toByte) -> expect(true), + (127.toByte, -128.toByte) -> expect(false), + (127.toByte, -47.toByte) -> expect(false), + (127.toByte, 127.toByte) -> expect(false) + ) + + verifyOp(LT_cases, "<", LT.apply)(_ < _) + + verifyOp(swapArgs(LT_cases, cost = 36342), ">", GT.apply)(_ > _) + + val neqCases = newCasesFrom(LT_cases.map(_._1))(_ != _, cost = 36337) + verifyOp(neqCases, "!=", NEQ.apply)(_ != _) + } + + property("Byte LE, GE") { + val o = ExactOrdering.ByteIsExactOrdering + def expect(v: Boolean) = Expected(Success(v), 36337) + val LE_cases: Seq[((Byte, Byte), Expected[Boolean])] = Seq( + (-128.toByte, -128.toByte) -> expect(true), + (-128.toByte, -127.toByte) -> expect(true), + (-128.toByte, -1.toByte) -> expect(true), + (-128.toByte, 0.toByte) -> expect(true), + (-128.toByte, 1.toByte) -> expect(true), + (-128.toByte, 127.toByte) -> expect(true), + (-120.toByte, -128.toByte) -> expect(false), + (-120.toByte, -121.toByte) -> expect(false), + (-120.toByte, -120.toByte) -> expect(true), + (-120.toByte, -82.toByte) -> expect(true), + (-103.toByte, -1.toByte) -> expect(true), + (-103.toByte, -0.toByte) -> expect(true), + (-103.toByte, 1.toByte) -> expect(true), + (-103.toByte, 127.toByte) -> expect(true), + (-1.toByte, -2.toByte) -> expect(false), + (-1.toByte, -1.toByte) -> expect(true), + (-1.toByte, 0.toByte) -> expect(true), + (-1.toByte, 1.toByte) -> expect(true), + (0.toByte, -128.toByte) -> expect(false), + (0.toByte, -1.toByte) -> expect(false), + (0.toByte, 0.toByte) -> expect(true), + (0.toByte, 1.toByte) -> expect(true), + (0.toByte, 60.toByte) -> expect(true), + (0.toByte, 127.toByte) -> expect(true), + (1.toByte, -1.toByte) -> expect(false), + (1.toByte, 0.toByte) -> expect(false), + (1.toByte, 1.toByte) -> expect(true), + (1.toByte, 26.toByte) -> expect(true), + (7.toByte, -32.toByte) -> expect(false), + (7.toByte, 0.toByte) -> expect(false), + (33.toByte, 1.toByte) -> expect(false), + (126.toByte, 127.toByte) -> expect(true), + (127.toByte, -128.toByte) -> expect(false), + (127.toByte, -47.toByte) -> expect(false), + (127.toByte, 127.toByte) -> expect(true) + ) + + verifyOp(LE_cases, "<=", LE.apply)(_ <= _) + + verifyOp(swapArgs(LE_cases, cost = 36336), ">=", GE.apply)(_ >= _) + } + property("Byte methods equivalence (new features)") { lazy val toBytes = newFeature((x: Byte) => x.toBytes, "{ (x: Byte) => x.toBytes }") lazy val toBits = newFeature((x: Byte) => x.toBits, "{ (x: Byte) => x.toBits }") @@ -756,6 +1056,100 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui )) } + property("Short LT, GT, NEQ") { + val o = ExactOrdering.ShortIsExactOrdering + def expect(v: Boolean) = Expected(Success(v), 36328) + val LT_cases: Seq[((Short, Short), Expected[Boolean])] = Seq( + (Short.MinValue, Short.MinValue) -> expect(false), + (Short.MinValue, (Short.MinValue + 1).toShort) -> expect(true), + (Short.MinValue, -1.toShort) -> expect(true), + (Short.MinValue, 0.toShort) -> expect(true), + (Short.MinValue, 1.toShort) -> expect(true), + (Short.MinValue, Short.MaxValue) -> expect(true), + (-120.toShort, Short.MinValue) -> expect(false), + (-120.toShort, -121.toShort) -> expect(false), + (-120.toShort, -120.toShort) -> expect(false), + (-120.toShort, -82.toShort) -> expect(true), + (-103.toShort, -1.toShort) -> expect(true), + (-103.toShort, -0.toShort) -> expect(true), + (-103.toShort, 1.toShort) -> expect(true), + (-103.toShort, Short.MaxValue) -> expect(true), + (-1.toShort, -2.toShort) -> expect(false), + (-1.toShort, -1.toShort) -> expect(false), + (-1.toShort, 0.toShort) -> expect(true), + (-1.toShort, 1.toShort) -> expect(true), + (0.toShort, Short.MinValue) -> expect(false), + (0.toShort, -1.toShort) -> expect(false), + (0.toShort, 0.toShort) -> expect(false), + (0.toShort, 1.toShort) -> expect(true), + (0.toShort, 60.toShort) -> expect(true), + (0.toShort, Short.MaxValue) -> expect(true), + (1.toShort, -1.toShort) -> expect(false), + (1.toShort, 0.toShort) -> expect(false), + (1.toShort, 26.toShort) -> expect(true), + (7.toShort, -32.toShort) -> expect(false), + (7.toShort, 0.toShort) -> expect(false), + (33.toShort, 1.toShort) -> expect(false), + (126.toShort, Short.MaxValue) -> expect(true), + (Short.MaxValue, Short.MinValue) -> expect(false), + (Short.MaxValue, -47.toShort) -> expect(false), + (Short.MaxValue, Short.MaxValue) -> expect(false) + ) + + verifyOp(LT_cases, "<", LT.apply)(_ < _) + + verifyOp(swapArgs(LT_cases, cost = 36342), ">", GT.apply)(_ > _) + + val neqCases = newCasesFrom(LT_cases.map(_._1))(_ != _, cost = 36337) + verifyOp(neqCases, "!=", NEQ.apply)(_ != _) + } + + property("Short LE, GE") { + val o = ExactOrdering.ShortIsExactOrdering + def expect(v: Boolean) = Expected(Success(v), 36337) + val LE_cases: Seq[((Short, Short), Expected[Boolean])] = Seq( + (Short.MinValue, Short.MinValue) -> expect(true), + (Short.MinValue, (Short.MinValue + 1).toShort) -> expect(true), + (Short.MinValue, -1.toShort) -> expect(true), + (Short.MinValue, 0.toShort) -> expect(true), + (Short.MinValue, 1.toShort) -> expect(true), + (Short.MinValue, Short.MaxValue) -> expect(true), + (-120.toShort, Short.MinValue) -> expect(false), + (-120.toShort, -121.toShort) -> expect(false), + (-120.toShort, -120.toShort) -> expect(true), + (-120.toShort, -82.toShort) -> expect(true), + (-103.toShort, -1.toShort) -> expect(true), + (-103.toShort, -0.toShort) -> expect(true), + (-103.toShort, 1.toShort) -> expect(true), + (-103.toShort, Short.MaxValue) -> expect(true), + (-1.toShort, -2.toShort) -> expect(false), + (-1.toShort, -1.toShort) -> expect(true), + (-1.toShort, 0.toShort) -> expect(true), + (-1.toShort, 1.toShort) -> expect(true), + (0.toShort, Short.MinValue) -> expect(false), + (0.toShort, -1.toShort) -> expect(false), + (0.toShort, 0.toShort) -> expect(true), + (0.toShort, 1.toShort) -> expect(true), + (0.toShort, 60.toShort) -> expect(true), + (0.toShort, Short.MaxValue) -> expect(true), + (1.toShort, -1.toShort) -> expect(false), + (1.toShort, 0.toShort) -> expect(false), + (1.toShort, 1.toShort) -> expect(true), + (1.toShort, 26.toShort) -> expect(true), + (7.toShort, -32.toShort) -> expect(false), + (7.toShort, 0.toShort) -> expect(false), + (33.toShort, 1.toShort) -> expect(false), + (126.toShort, Short.MaxValue) -> expect(true), + (Short.MaxValue, Short.MinValue) -> expect(false), + (Short.MaxValue, -47.toShort) -> expect(false), + (Short.MaxValue, Short.MaxValue) -> expect(true) + ) + + verifyOp(LE_cases, "<=", LE.apply)(_ <= _) + + verifyOp(swapArgs(LE_cases, cost = 36336), ">=", GE.apply)(_ >= _) + } + property("Short methods equivalence (new features)") { lazy val toBytes = newFeature((x: Short) => x.toBytes, "{ (x: Short) => x.toBytes }") lazy val toBits = newFeature((x: Short) => x.toBits, "{ (x: Short) => x.toBits }") @@ -962,6 +1356,100 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui ))) } + property("Int LT, GT, NEQ") { + val o = ExactOrdering.IntIsExactOrdering + def expect(v: Boolean) = Expected(Success(v), 36328) + val LT_cases: Seq[((Int, Int), Expected[Boolean])] = Seq( + (Int.MinValue, Int.MinValue) -> expect(false), + (Int.MinValue, (Int.MinValue + 1).toInt) -> expect(true), + (Int.MinValue, -1.toInt) -> expect(true), + (Int.MinValue, 0.toInt) -> expect(true), + (Int.MinValue, 1.toInt) -> expect(true), + (Int.MinValue, Int.MaxValue) -> expect(true), + (-120.toInt, Int.MinValue) -> expect(false), + (-120.toInt, -121.toInt) -> expect(false), + (-120.toInt, -120.toInt) -> expect(false), + (-120.toInt, -82.toInt) -> expect(true), + (-103.toInt, -1.toInt) -> expect(true), + (-103.toInt, -0.toInt) -> expect(true), + (-103.toInt, 1.toInt) -> expect(true), + (-103.toInt, Int.MaxValue) -> expect(true), + (-1.toInt, -2.toInt) -> expect(false), + (-1.toInt, -1.toInt) -> expect(false), + (-1.toInt, 0.toInt) -> expect(true), + (-1.toInt, 1.toInt) -> expect(true), + (0.toInt, Int.MinValue) -> expect(false), + (0.toInt, -1.toInt) -> expect(false), + (0.toInt, 0.toInt) -> expect(false), + (0.toInt, 1.toInt) -> expect(true), + (0.toInt, 60.toInt) -> expect(true), + (0.toInt, Int.MaxValue) -> expect(true), + (1.toInt, -1.toInt) -> expect(false), + (1.toInt, 0.toInt) -> expect(false), + (1.toInt, 26.toInt) -> expect(true), + (7.toInt, -32.toInt) -> expect(false), + (7.toInt, 0.toInt) -> expect(false), + (33.toInt, 1.toInt) -> expect(false), + (126.toInt, Int.MaxValue) -> expect(true), + (Int.MaxValue, Int.MinValue) -> expect(false), + (Int.MaxValue, -47.toInt) -> expect(false), + (Int.MaxValue, Int.MaxValue) -> expect(false) + ) + + verifyOp(LT_cases, "<", LT.apply)(_ < _) + + verifyOp(swapArgs(LT_cases, cost = 36342), ">", GT.apply)(_ > _) + + val neqCases = newCasesFrom(LT_cases.map(_._1))(_ != _, cost = 36337) + verifyOp(neqCases, "!=", NEQ.apply)(_ != _) + } + + property("Int LE, GE") { + val o = ExactOrdering.IntIsExactOrdering + def expect(v: Boolean) = Expected(Success(v), 36337) + val LE_cases: Seq[((Int, Int), Expected[Boolean])] = Seq( + (Int.MinValue, Int.MinValue) -> expect(true), + (Int.MinValue, (Int.MinValue + 1).toInt) -> expect(true), + (Int.MinValue, -1.toInt) -> expect(true), + (Int.MinValue, 0.toInt) -> expect(true), + (Int.MinValue, 1.toInt) -> expect(true), + (Int.MinValue, Int.MaxValue) -> expect(true), + (-120.toInt, Int.MinValue) -> expect(false), + (-120.toInt, -121.toInt) -> expect(false), + (-120.toInt, -120.toInt) -> expect(true), + (-120.toInt, -82.toInt) -> expect(true), + (-103.toInt, -1.toInt) -> expect(true), + (-103.toInt, -0.toInt) -> expect(true), + (-103.toInt, 1.toInt) -> expect(true), + (-103.toInt, Int.MaxValue) -> expect(true), + (-1.toInt, -2.toInt) -> expect(false), + (-1.toInt, -1.toInt) -> expect(true), + (-1.toInt, 0.toInt) -> expect(true), + (-1.toInt, 1.toInt) -> expect(true), + (0.toInt, Int.MinValue) -> expect(false), + (0.toInt, -1.toInt) -> expect(false), + (0.toInt, 0.toInt) -> expect(true), + (0.toInt, 1.toInt) -> expect(true), + (0.toInt, 60.toInt) -> expect(true), + (0.toInt, Int.MaxValue) -> expect(true), + (1.toInt, -1.toInt) -> expect(false), + (1.toInt, 0.toInt) -> expect(false), + (1.toInt, 1.toInt) -> expect(true), + (1.toInt, 26.toInt) -> expect(true), + (7.toInt, -32.toInt) -> expect(false), + (7.toInt, 0.toInt) -> expect(false), + (33.toInt, 1.toInt) -> expect(false), + (126.toInt, Int.MaxValue) -> expect(true), + (Int.MaxValue, Int.MinValue) -> expect(false), + (Int.MaxValue, -47.toInt) -> expect(false), + (Int.MaxValue, Int.MaxValue) -> expect(true) + ) + + verifyOp(LE_cases, "<=", LE.apply)(_ <= _) + + verifyOp(swapArgs(LE_cases, cost = 36336), ">=", GE.apply)(_ >= _) + } + property("Int methods equivalence (new features)") { lazy val toBytes = newFeature((x: Int) => x.toBytes, "{ (x: Int) => x.toBytes }") lazy val toBits = newFeature((x: Int) => x.toBits, "{ (x: Int) => x.toBits }") @@ -1169,6 +1657,100 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui ))) } + property("Long LT, GT, NEQ") { + val o = ExactOrdering.LongIsExactOrdering + def expect(v: Boolean) = Expected(Success(v), 36328) + val LT_cases: Seq[((Long, Long), Expected[Boolean])] = Seq( + (Long.MinValue, Long.MinValue) -> expect(false), + (Long.MinValue, (Long.MinValue + 1).toLong) -> expect(true), + (Long.MinValue, -1.toLong) -> expect(true), + (Long.MinValue, 0.toLong) -> expect(true), + (Long.MinValue, 1.toLong) -> expect(true), + (Long.MinValue, Long.MaxValue) -> expect(true), + (-120.toLong, Long.MinValue) -> expect(false), + (-120.toLong, -121.toLong) -> expect(false), + (-120.toLong, -120.toLong) -> expect(false), + (-120.toLong, -82.toLong) -> expect(true), + (-103.toLong, -1.toLong) -> expect(true), + (-103.toLong, -0.toLong) -> expect(true), + (-103.toLong, 1.toLong) -> expect(true), + (-103.toLong, Long.MaxValue) -> expect(true), + (-1.toLong, -2.toLong) -> expect(false), + (-1.toLong, -1.toLong) -> expect(false), + (-1.toLong, 0.toLong) -> expect(true), + (-1.toLong, 1.toLong) -> expect(true), + (0.toLong, Long.MinValue) -> expect(false), + (0.toLong, -1.toLong) -> expect(false), + (0.toLong, 0.toLong) -> expect(false), + (0.toLong, 1.toLong) -> expect(true), + (0.toLong, 60.toLong) -> expect(true), + (0.toLong, Long.MaxValue) -> expect(true), + (1.toLong, -1.toLong) -> expect(false), + (1.toLong, 0.toLong) -> expect(false), + (1.toLong, 26.toLong) -> expect(true), + (7.toLong, -32.toLong) -> expect(false), + (7.toLong, 0.toLong) -> expect(false), + (33.toLong, 1.toLong) -> expect(false), + (126.toLong, Long.MaxValue) -> expect(true), + (Long.MaxValue, Long.MinValue) -> expect(false), + (Long.MaxValue, -47.toLong) -> expect(false), + (Long.MaxValue, Long.MaxValue) -> expect(false) + ) + + verifyOp(LT_cases, "<", LT.apply)(_ < _) + + verifyOp(swapArgs(LT_cases, cost = 36342), ">", GT.apply)(_ > _) + + val neqCases = newCasesFrom(LT_cases.map(_._1))(_ != _, cost = 36337) + verifyOp(neqCases, "!=", NEQ.apply)(_ != _) + } + + property("Long LE, GE") { + val o = ExactOrdering.LongIsExactOrdering + def expect(v: Boolean) = Expected(Success(v), 36337) + val LE_cases: Seq[((Long, Long), Expected[Boolean])] = Seq( + (Long.MinValue, Long.MinValue) -> expect(true), + (Long.MinValue, (Long.MinValue + 1).toLong) -> expect(true), + (Long.MinValue, -1.toLong) -> expect(true), + (Long.MinValue, 0.toLong) -> expect(true), + (Long.MinValue, 1.toLong) -> expect(true), + (Long.MinValue, Long.MaxValue) -> expect(true), + (-120.toLong, Long.MinValue) -> expect(false), + (-120.toLong, -121.toLong) -> expect(false), + (-120.toLong, -120.toLong) -> expect(true), + (-120.toLong, -82.toLong) -> expect(true), + (-103.toLong, -1.toLong) -> expect(true), + (-103.toLong, -0.toLong) -> expect(true), + (-103.toLong, 1.toLong) -> expect(true), + (-103.toLong, Long.MaxValue) -> expect(true), + (-1.toLong, -2.toLong) -> expect(false), + (-1.toLong, -1.toLong) -> expect(true), + (-1.toLong, 0.toLong) -> expect(true), + (-1.toLong, 1.toLong) -> expect(true), + (0.toLong, Long.MinValue) -> expect(false), + (0.toLong, -1.toLong) -> expect(false), + (0.toLong, 0.toLong) -> expect(true), + (0.toLong, 1.toLong) -> expect(true), + (0.toLong, 60.toLong) -> expect(true), + (0.toLong, Long.MaxValue) -> expect(true), + (1.toLong, -1.toLong) -> expect(false), + (1.toLong, 0.toLong) -> expect(false), + (1.toLong, 1.toLong) -> expect(true), + (1.toLong, 26.toLong) -> expect(true), + (7.toLong, -32.toLong) -> expect(false), + (7.toLong, 0.toLong) -> expect(false), + (33.toLong, 1.toLong) -> expect(false), + (126.toLong, Long.MaxValue) -> expect(true), + (Long.MaxValue, Long.MinValue) -> expect(false), + (Long.MaxValue, -47.toLong) -> expect(false), + (Long.MaxValue, Long.MaxValue) -> expect(true) + ) + + verifyOp(LE_cases, "<=", LE.apply)(_ <= _) + + verifyOp(swapArgs(LE_cases, cost = 36336), ">=", GE.apply)(_ >= _) + } + property("Long methods equivalence (new features)") { lazy val toBytes = newFeature((x: Long) => x.toBytes, "{ (x: Long) => x.toBytes }") lazy val toBits = newFeature((x: Long) => x.toBits, "{ (x: Long) => x.toBits }") @@ -1339,6 +1921,116 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui )) } + property("BigInt LT, GT, NEQ") { + val o = NumericOps.BigIntIsExactOrdering + // TODO HF: this values have bitCount == 255 (see to256BitValueExact) + val BigIntMinValue = CBigInt(new BigInteger("-7F" + "ff" * 31, 16)) + 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), 36328) + + val LT_cases: Seq[((BigInt, BigInt), Expected[Boolean])] = Seq( + (BigIntMinValue, BigIntMinValue) -> expect(false), + (BigIntMinValue, BigIntMinValue.add(1.toBigInt)) -> expect(true), + (BigIntMinValue, -1.toBigInt) -> expect(true), + (BigIntMinValue, 0.toBigInt) -> expect(true), + (BigIntMinValue, 1.toBigInt) -> expect(true), + (BigIntMinValue, BigIntMaxValue) -> expect(true), + (-120.toBigInt, BigIntMinValue) -> expect(false), + (-120.toBigInt, -121.toBigInt) -> expect(false), + (-120.toBigInt, -120.toBigInt) -> expect(false), + (-120.toBigInt, -82.toBigInt) -> expect(true), + (-103.toBigInt, -1.toBigInt) -> expect(true), + (-103.toBigInt, -0.toBigInt) -> expect(true), + (-103.toBigInt, 1.toBigInt) -> expect(true), + (-103.toBigInt, BigIntMaxValue) -> expect(true), + (-1.toBigInt, -2.toBigInt) -> expect(false), + (-1.toBigInt, -1.toBigInt) -> expect(false), + (-1.toBigInt, 0.toBigInt) -> expect(true), + (-1.toBigInt, 1.toBigInt) -> expect(true), + (0.toBigInt, BigIntMinValue) -> expect(false), + (0.toBigInt, -1.toBigInt) -> expect(false), + (0.toBigInt, 0.toBigInt) -> expect(false), + (0.toBigInt, 1.toBigInt) -> expect(true), + (0.toBigInt, 60.toBigInt) -> expect(true), + (0.toBigInt, BigIntMaxValue) -> expect(true), + (1.toBigInt, -1.toBigInt) -> expect(false), + (1.toBigInt, 0.toBigInt) -> expect(false), + (1.toBigInt, 26.toBigInt) -> expect(true), + (7.toBigInt, -32.toBigInt) -> expect(false), + (7.toBigInt, 0.toBigInt) -> expect(false), + (33.toBigInt, 1.toBigInt) -> expect(false), + (126.toBigInt, BigIntMaxValue) -> expect(true), + (BigIntMaxValue, BigIntMinValue) -> expect(false), + (BigIntMaxValue, -47.toBigInt) -> expect(false), + (BigIntMaxValue, BigIntMaxValue) -> expect(false), + (BigIntMaxValue, BigIntOverlimit) -> expect(true), // TODO v5.0: reject this overlimit cases + (BigIntOverlimit, BigIntOverlimit) -> expect(false) + ) + + verifyOp(LT_cases, "<", LT.apply)(o.lt(_, _)) + + verifyOp(swapArgs(LT_cases, cost = 36342), ">", GT.apply)(o.gt(_, _)) + + val neqCases = newCasesFrom(LT_cases.map(_._1))(_ != _, cost = 36337) + verifyOp(neqCases, "!=", NEQ.apply)(_ != _) + } + + property("BigInt LE, GE") { + val o = NumericOps.BigIntIsExactOrdering + // TODO HF: this values have bitCount == 255 (see to256BitValueExact) + val BigIntMinValue = CBigInt(new BigInteger("-7F" + "ff" * 31, 16)) + 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), 36337) + + val LE_cases: Seq[((BigInt, BigInt), Expected[Boolean])] = Seq( + (BigIntMinValue, BigIntMinValue) -> expect(true), + (BigIntMinValue, BigIntMinValue.add(1.toBigInt)) -> expect(true), + (BigIntMinValue, -1.toBigInt) -> expect(true), + (BigIntMinValue, 0.toBigInt) -> expect(true), + (BigIntMinValue, 1.toBigInt) -> expect(true), + (BigIntMinValue, BigIntMaxValue) -> expect(true), + (-120.toBigInt, BigIntMinValue) -> expect(false), + (-120.toBigInt, -121.toBigInt) -> expect(false), + (-120.toBigInt, -120.toBigInt) -> expect(true), + (-120.toBigInt, -82.toBigInt) -> expect(true), + (-103.toBigInt, -1.toBigInt) -> expect(true), + (-103.toBigInt, -0.toBigInt) -> expect(true), + (-103.toBigInt, 1.toBigInt) -> expect(true), + (-103.toBigInt, BigIntMaxValue) -> expect(true), + (-1.toBigInt, -2.toBigInt) -> expect(false), + (-1.toBigInt, -1.toBigInt) -> expect(true), + (-1.toBigInt, 0.toBigInt) -> expect(true), + (-1.toBigInt, 1.toBigInt) -> expect(true), + (0.toBigInt, BigIntMinValue) -> expect(false), + (0.toBigInt, -1.toBigInt) -> expect(false), + (0.toBigInt, 0.toBigInt) -> expect(true), + (0.toBigInt, 1.toBigInt) -> expect(true), + (0.toBigInt, 60.toBigInt) -> expect(true), + (0.toBigInt, BigIntMaxValue) -> expect(true), + (1.toBigInt, -1.toBigInt) -> expect(false), + (1.toBigInt, 0.toBigInt) -> expect(false), + (1.toBigInt, 1.toBigInt) -> expect(true), + (1.toBigInt, 26.toBigInt) -> expect(true), + (7.toBigInt, -32.toBigInt) -> expect(false), + (7.toBigInt, 0.toBigInt) -> expect(false), + (33.toBigInt, 1.toBigInt) -> expect(false), + (126.toBigInt, BigIntMaxValue) -> expect(true), + (BigIntMaxValue, BigIntMinValue) -> expect(false), + (BigIntMaxValue, -47.toBigInt) -> expect(false), + (BigIntMaxValue, BigIntMaxValue) -> expect(true), + (BigIntMaxValue, BigIntOverlimit) -> expect(true), // TODO v5.0: reject this overlimit cases + (BigIntOverlimit, BigIntOverlimit) -> expect(true) + ) + + verifyOp(LE_cases, "<=", LE.apply)(o.lteq(_, _)) + + verifyOp(swapArgs(LE_cases, cost = 36336), ">=", GE.apply)(o.gteq(_, _)) + } + property("BigInt methods equivalence (new features)") { // TODO HF (2h): the behavior of `upcast` for BigInt is different from all other Numeric types // The `Upcast(bigInt, SBigInt)` node is never produced by ErgoScript compiler, but is still valid ErgoTree. @@ -1393,18 +2085,150 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui } } + /** Executed a series of test cases of NEQ operation verify using two _different_ + * data instances `x` and `y`. + * @param cost the expected cost of `verify` (the same for all cases) + */ + def verifyNeq[A: Ordering: Arbitrary: RType] + (x: A, y: A, cost: Int) + (copy: A => A, generateCases: Boolean = true) + (implicit sampled: Sampled[(A, A)]) = { + val copied_x = copy(x) + verifyOp(Seq( + (x, x) -> Expected(Success(false), cost), + (x, copied_x) -> Expected(Success(false), cost), + (copied_x, x) -> Expected(Success(false), cost), + (x, y) -> Expected(Success(true), cost), + (y, x) -> Expected(Success(true), cost) + ), + "!=", NEQ.apply)(_ != _, generateCases) + } + + property("NEQ of pre-defined types") { + verifyNeq(ge1, ge2, 36337)(_.asInstanceOf[CGroupElement].copy()) + verifyNeq(t1, t2, 36337)(_.asInstanceOf[CAvlTree].copy()) + verifyNeq(b1, b2, 36417)(_.asInstanceOf[CostingBox].copy()) + verifyNeq(preH1, preH2, 36337)(_.asInstanceOf[CPreHeader].copy()) + verifyNeq(h1, h2, 36337)(_.asInstanceOf[CHeader].copy()) + } + + property("NEQ of tuples of numerics") { + verifyNeq((0.toByte, 1.toByte), (1.toByte, 1.toByte), 36337)(_.copy()) + verifyNeq((0.toShort, 1.toByte), (1.toShort, 1.toByte), 36337)(_.copy()) + verifyNeq((0, 1.toByte), (1, 1.toByte), 36337)(_.copy()) + verifyNeq((0.toLong, 1.toByte), (1.toLong, 1.toByte), 36337)(_.copy()) + verifyNeq((0.toBigInt, 1.toByte), (1.toBigInt, 1.toByte), 36337)(_.copy()) + } + + property("NEQ of tuples of pre-defined types") { + verifyNeq((ge1, ge1), (ge1, ge2), 36337)(_.copy()) + verifyNeq((t1, t1), (t1, t2), 36337)(_.copy()) + verifyNeq((b1, b1), (b1, b2), 36497)(_.copy()) + verifyNeq((preH1, preH1), (preH1, preH2), 36337)(_.copy()) + verifyNeq((h1, h1), (h1, h2), 36337)(_.copy()) + } + + property("NEQ of nested tuples") { + verifyNeq((ge1, (t1, t1)), (ge1, (t1, t2)), 36337)(_.copy()) + verifyNeq((ge1, (t1, (b1, b1))), (ge1, (t1, (b1, b2))), 36497)(_.copy()) + verifyNeq((ge1, (t1, (b1, (preH1, preH1)))), (ge1, (t1, (b1, (preH1, preH2)))), 36417)(_.copy()) + verifyNeq((ge1, (t1, (b1, (preH1, (h1, h1))))), (ge1, (t1, (b1, (preH1, (h1, h2))))), 36427)(_.copy()) + + verifyNeq(((ge1, t1), t1), ((ge1, t1), t2), 36337)(_.copy()) + verifyNeq((((ge1, t1), b1), b1), (((ge1, t1), b1), b2), 36497)(_.copy()) + verifyNeq((((ge1, t1), b1), (preH1, preH1)), (((ge1, t1), b1), (preH1, preH2)), 36417)(_.copy()) + verifyNeq((((ge1, t1), b1), (preH1, (h1, h1))), (((ge1, t1), b1), (preH1, (h1, h2))), 36427)(_.copy()) + } + + property("NEQ of collections of pre-defined types") { + verifyNeq(Coll[Byte](), Coll(1.toByte), 36337)(cloneColl(_)) + verifyNeq(Coll[Byte](0, 1), Coll(1.toByte, 1.toByte), 36337)(cloneColl(_)) + + verifyNeq(Coll[Short](), Coll(1.toShort), 36337)(cloneColl(_)) + verifyNeq(Coll[Short](0), Coll(1.toShort), 36337)(cloneColl(_)) + + verifyNeq(Coll[Int](), Coll(1), 36337)(cloneColl(_)) + verifyNeq(Coll[Int](0), Coll(1), 36337)(cloneColl(_)) + + verifyNeq(Coll[Long](), Coll(1.toLong), 36337)(cloneColl(_)) + verifyNeq(Coll[Long](0), Coll(1.toLong), 36337)(cloneColl(_)) + + prepareSamples[Coll[BigInt]] + verifyNeq(Coll[BigInt](), Coll(1.toBigInt), 36337)(cloneColl(_)) + verifyNeq(Coll[BigInt](0.toBigInt), Coll(1.toBigInt), 36337)(cloneColl(_)) + + prepareSamples[Coll[GroupElement]] + verifyNeq(Coll[GroupElement](), Coll(ge1), 36337)(cloneColl(_)) + verifyNeq(Coll[GroupElement](ge1), Coll(ge2), 36337)(cloneColl(_)) + + prepareSamples[Coll[AvlTree]] + verifyNeq(Coll[AvlTree](), Coll(t1), 36337)(cloneColl(_)) + verifyNeq(Coll[AvlTree](t1), Coll(t2), 36337)(cloneColl(_)) + + { // since SBox.isConstantSize = false, the cost is different among cases + prepareSamples[Coll[AvlTree]] + val x = Coll[Box]() + val y = Coll(b1) + val copied_x = cloneColl(x) + verifyOp(Seq( + (x, x) -> Expected(Success(false), 36337), + (x, copied_x) -> Expected(Success(false), 36337), + (copied_x, x) -> Expected(Success(false), 36337), + (x, y) -> Expected(Success(true), 36377), + (y, x) -> Expected(Success(true), 36377) + ), + "!=", NEQ.apply)(_ != _, generateCases = false) + + verifyNeq(Coll[Box](b1), Coll(b2), 36417)(cloneColl(_), generateCases = false) + } + + prepareSamples[Coll[PreHeader]] + verifyNeq(Coll[PreHeader](), Coll(preH1), 36337)(cloneColl(_)) + verifyNeq(Coll[PreHeader](preH1), Coll(preH2), 36337)(cloneColl(_)) + + prepareSamples[Coll[Header]] + verifyNeq(Coll[Header](), Coll(h1), 36337)(cloneColl(_)) + verifyNeq(Coll[Header](h1), Coll(h2), 36337)(cloneColl(_)) + } + + property("NEQ of nested collections and tuples") { + prepareSamples[Coll[Int]] + prepareSamples[Coll[Coll[Int]]] + prepareSamples[Coll[Coll[Int]]] + + verifyNeq(Coll[Coll[Int]](), Coll(Coll[Int]()), 36337)(cloneColl(_)) + verifyNeq(Coll(Coll[Int]()), Coll(Coll[Int](1)), 36337)(cloneColl(_)) + verifyNeq(Coll(Coll[Int](1)), Coll(Coll[Int](2)), 36337)(cloneColl(_)) + verifyNeq(Coll(Coll[Int](1)), Coll(Coll[Int](1, 2)), 36337)(cloneColl(_)) + + prepareSamples[Coll[(Int, BigInt)]] + prepareSamples[Coll[Coll[(Int, BigInt)]]] + + verifyNeq(Coll(Coll((1, 10.toBigInt))), Coll(Coll((1, 11.toBigInt))), 36337)(cloneColl(_)) + verifyNeq(Coll(Coll(Coll((1, 10.toBigInt)))), Coll(Coll(Coll((1, 11.toBigInt)))), 36337)(cloneColl(_)) + verifyNeq( + (Coll( + (Coll( + (t1, Coll((1, 10.toBigInt), (1, 10.toBigInt))) + ), ge1) + ), preH1), + (Coll( + (Coll( + (t1, Coll((1, 10.toBigInt), (1, 11.toBigInt))) + ), ge1) + ), preH1), + 36337)(x => (cloneColl(x._1), x._2)) + } + property("GroupElement methods equivalence") { - val ge1 = "03358d53f01276211f92d0aefbd278805121d4ff6eb534b777af1ee8abae5b2056" - val ge2 = "02dba7b94b111f3894e2f9120b577da595ec7d58d488485adf73bf4e153af63575" - val ge3 = "0290449814f5671172dd696a61b8aa49aaa4c87013f56165e27d49944e98bc414d" verifyCases( { def success[T](v: T) = Expected(Success(v), 37905) Seq( - (Helpers.decodeGroupElement(ge1), success(Helpers.decodeBytes(ge1))), - (Helpers.decodeGroupElement(ge2), success(Helpers.decodeBytes(ge2))), - (Helpers.decodeGroupElement(ge3), success(Helpers.decodeBytes(ge3))), + (ge1, success(Helpers.decodeBytes(ge1str))), + (ge2, success(Helpers.decodeBytes(ge2str))), + (ge3, success(Helpers.decodeBytes(ge3str))), (SigmaDsl.groupGenerator, success(Helpers.decodeBytes("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"))), (SigmaDsl.groupIdentity, @@ -1422,9 +2246,9 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui { def success[T](v: T) = Expected(Success(v), 38340) Seq( - (Helpers.decodeGroupElement(ge1), success(true)), - (Helpers.decodeGroupElement(ge2), success(true)), - (Helpers.decodeGroupElement(ge3), success(true)), + (ge1, success(true)), + (ge2, success(true)), + (ge3, success(true)), (SigmaDsl.groupGenerator, success(true)), (SigmaDsl.groupIdentity, success(true)) ) @@ -1450,9 +2274,9 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui { def success[T](v: T) = Expected(Success(v), 36292) Seq( - (Helpers.decodeGroupElement(ge1), success(Helpers.decodeGroupElement("02358d53f01276211f92d0aefbd278805121d4ff6eb534b777af1ee8abae5b2056"))), - (Helpers.decodeGroupElement(ge2), success(Helpers.decodeGroupElement("03dba7b94b111f3894e2f9120b577da595ec7d58d488485adf73bf4e153af63575"))), - (Helpers.decodeGroupElement(ge3), success(Helpers.decodeGroupElement("0390449814f5671172dd696a61b8aa49aaa4c87013f56165e27d49944e98bc414d"))), + (ge1, success(Helpers.decodeGroupElement("02358d53f01276211f92d0aefbd278805121d4ff6eb534b777af1ee8abae5b2056"))), + (ge2, success(Helpers.decodeGroupElement("03dba7b94b111f3894e2f9120b577da595ec7d58d488485adf73bf4e153af63575"))), + (ge3, success(Helpers.decodeGroupElement("0390449814f5671172dd696a61b8aa49aaa4c87013f56165e27d49944e98bc414d"))), (SigmaDsl.groupGenerator, success(Helpers.decodeGroupElement("0379be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"))), (SigmaDsl.groupIdentity, success(Helpers.decodeGroupElement("000000000000000000000000000000000000000000000000000000000000000000"))) ) @@ -1472,14 +2296,14 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui { def success[T](v: T) = Expected(Success(v), 41484) Seq( - ((Helpers.decodeGroupElement(ge1), CBigInt(new BigInteger("-25c80b560dd7844e2efd10f80f7ee57d", 16))), + ((ge1, CBigInt(new BigInteger("-25c80b560dd7844e2efd10f80f7ee57d", 16))), success(Helpers.decodeGroupElement("023a850181b7b73f92a5bbfa0bfc78f5bbb6ff00645ddde501037017e1a2251e2e"))), - ((Helpers.decodeGroupElement(ge2), CBigInt(new BigInteger("2488741265082fb02b09f992be3dd8d60d2bbe80d9e2630", 16))), + ((ge2, CBigInt(new BigInteger("2488741265082fb02b09f992be3dd8d60d2bbe80d9e2630", 16))), success(Helpers.decodeGroupElement("032045b928fb7774a4cd9ef5fa8209f4e493cd4cc5bd536b52746a53871bf73431"))), - ((Helpers.decodeGroupElement(ge3), CBigInt(new BigInteger("-33e8fbdb13d2982e92583445e1fdcb5901a178a7aa1e100", 16))), + ((ge3, CBigInt(new BigInteger("-33e8fbdb13d2982e92583445e1fdcb5901a178a7aa1e100", 16))), success(Helpers.decodeGroupElement("036128efaf14d8ac2812a662f6494dc617b87986a3dc6b4a59440048a7ac7d2729"))), - ((Helpers.decodeGroupElement(ge3), CBigInt(new BigInteger("1", 16))), - success(Helpers.decodeGroupElement(ge3))) + ((ge3, CBigInt(new BigInteger("1", 16))), + success(ge3)) ) }, existingFeature({ (x: (GroupElement, BigInt)) => x._1.exp(x._2) }, @@ -1502,14 +2326,14 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui { def success[T](v: T) = Expected(Success(v), 36457) Seq( - ((Helpers.decodeGroupElement(ge1), Helpers.decodeGroupElement("03e132ca090614bd6c9f811e91f6daae61f16968a1e6c694ed65aacd1b1092320e")), + ((ge1, Helpers.decodeGroupElement("03e132ca090614bd6c9f811e91f6daae61f16968a1e6c694ed65aacd1b1092320e")), success(Helpers.decodeGroupElement("02bc48937b4a66f249a32dfb4d2efd0743dc88d46d770b8c5d39fd03325ba211df"))), - ((Helpers.decodeGroupElement(ge2), Helpers.decodeGroupElement("03e132ca090614bd6c9f811e91f6daae61f16968a1e6c694ed65aacd1b1092320e")), + ((ge2, Helpers.decodeGroupElement("03e132ca090614bd6c9f811e91f6daae61f16968a1e6c694ed65aacd1b1092320e")), success(Helpers.decodeGroupElement("0359c3bb2ac4ea4dbd7b1e09d7b11198141a3263834fb84a88039629ec1e9311d1"))), - ((Helpers.decodeGroupElement(ge3), Helpers.decodeGroupElement("03e132ca090614bd6c9f811e91f6daae61f16968a1e6c694ed65aacd1b1092320e")), + ((ge3, Helpers.decodeGroupElement("03e132ca090614bd6c9f811e91f6daae61f16968a1e6c694ed65aacd1b1092320e")), success(Helpers.decodeGroupElement("02eca42e28548d3fb9fa77cdd0c983066c3ad141ebb086b5044ce46b9ba9b5a714"))), - ((Helpers.decodeGroupElement(ge3), SigmaDsl.groupIdentity), - success(Helpers.decodeGroupElement(ge3))) + ((ge3, SigmaDsl.groupIdentity), + success(ge3)) ) }, existingFeature({ (x: (GroupElement, GroupElement)) => x._1.multiply(x._2) }, @@ -1541,31 +2365,6 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui ) ) } - val t1 = CAvlTree( - AvlTreeData( - ADDigest @@ ErgoAlgos.decodeUnsafe("000183807f66b301530120ff7fc6bd6601ff01ff7f7d2bedbbffff00187fe89094"), - AvlTreeFlags(false, true, true), - 1, - Some(1) - ) - ) - val t2 = CAvlTree( - AvlTreeData( - ADDigest @@ ErgoAlgos.decodeUnsafe("ff000d937f80ffd731ed802d24358001ff8080ff71007f00ad37e0a7ae43fff95b"), - AvlTreeFlags(false, false, false), - 32, - Some(64) - ) - ) - val t3 = CAvlTree( - AvlTreeData( - ADDigest @@ ErgoAlgos.decodeUnsafe("3100d2e101ff01fc047c7f6f00ff80129df69a5090012f01ffca99f5bfff0c8036"), - AvlTreeFlags(true, false, false), - 128, - None - ) - ) - verifyCases( { def success[T](v: T) = Expected(Success(v), 36182) @@ -1874,7 +2673,7 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui val keys = Colls.fromItems(key) val expRes = Colls.fromItems(valueOpt) - + { val input = (tree, (keys, proof)) getMany.checkExpected(input, success(expRes)) @@ -2350,81 +3149,6 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui // } property("Box properties equivalence") { - val b1 = CostingBox( - false, - new ErgoBox( - 9223372036854775807L, - new ErgoTree( - 16.toByte, - Array( - SigmaPropConstant( - CSigmaProp( - ProveDlog( - Helpers.decodeECPoint( - "0297c44a12f4eb99a85d298fa3ba829b5b42b9f63798c980ece801cc663cc5fc9e" - ) - ) - ) - ) - ), - Right(ConstantPlaceholder(0, SSigmaProp)) - ), - Coll( - (Digest32 @@ (ErgoAlgos.decodeUnsafe("6e789ab7b2fffff12280a6cd01557f6fb22b7f80ff7aff8e1f7f15973d7f0001")), - 10000000L), - (Digest32 @@ (ErgoAlgos.decodeUnsafe("a3ff007f00057600808001ff8f8000019000ffdb806fff7cc0b6015eb37fa600")), - 500L) - ), - Map( - ErgoBox.R5 -> ByteArrayConstant(Helpers.decodeBytes("7fc87f7f01ff")), - ErgoBox.R4 -> FalseLeaf - ), - ModifierId @@ ("218301ae8000018008637f0021fb9e00018055486f0b514121016a00ff718080"), - 22588.toShort, - 677407 - ) - ) - - val b2 = CostingBox( - false, - new ErgoBox( - 12345L, - new ErgoTree( - 0.toByte, - Vector(), - Right( - BoolToSigmaProp( - AND( - ConcreteCollection( - Array( - FalseLeaf, - XorOf( - ConcreteCollection(Array(EQ(IntConstant(1), IntConstant(1)), FalseLeaf), SBoolean) - ) - ), - SBoolean - ) - ) - ) - ) - ), - Coll(), - Map( - ErgoBox.R5 -> ByteArrayConstant( - Helpers.decodeBytes( - "297000800b80f1d56c809a8c6affbed864b87f007f6f007f00ac00018c01c4fdff011088807f0100657f00f9ab0101ff6d65" - ) - ), - ErgoBox.R4 -> TrueLeaf, - ErgoBox.R7 -> LongConstant(9223372036854775807L), - ErgoBox.R6 -> LongConstant(2115927197107005906L) - ), - ModifierId @@ ("003bd5c630803cfff6c1ff7f7fb980ff136afc011f8080b8b04ad4dbda2d7f4e"), - 1.toShort, - 1000000 - ) - ) - verifyCases( { def success[T](v: T) = Expected(Success(v), 35984) @@ -2548,7 +3272,7 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui property("Conditional access to registers") { def boxWithRegisters(regs: AdditionalRegisters): Box = { - SigmaDsl.Box(testBox(20, TrueProp, 0, Seq(), regs)) + SigmaDsl.Box(testBox(20, TrueTree, 0, Seq(), regs)) } val box1 = boxWithRegisters(Map( ErgoBox.R4 -> ByteConstant(0.toByte), @@ -2671,7 +3395,7 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui property("Advanced Box test") { val (tree, _) = createAvlTreeAndProver() - val box1 = SigmaDsl.Box(testBox(20, TrueProp, 0, Seq(), Map( + val box1 = SigmaDsl.Box(testBox(20, TrueTree, 0, Seq(), Map( ErgoBox.R4 -> ByteConstant(1.toByte), ErgoBox.R5 -> ShortConstant(1024.toShort), ErgoBox.R6 -> IntConstant(1024 * 1024), @@ -2680,7 +3404,7 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui ErgoBox.R9 -> AvlTreeConstant(tree) ))) - val box2 = SigmaDsl.Box(testBox(20, TrueProp, 0, Seq(), Map( + val box2 = SigmaDsl.Box(testBox(20, TrueTree, 0, Seq(), Map( ErgoBox.R4 -> ByteArrayConstant(Coll(1.toByte)) ))) @@ -2775,76 +3499,40 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui } property("PreHeader properties equivalence") { - val h1 = CPreHeader( - 0.toByte, - Helpers.decodeBytes("7fff7fdd6f62018bae0001006d9ca888ff7f56ff8006573700a167f17f2c9f40"), - 6306290372572472443L, - -3683306095029417063L, - 1, - Helpers.decodeGroupElement("026930cb9972e01534918a6f6d6b8e35bc398f57140d13eb3623ea31fbd069939b"), - Helpers.decodeBytes("ff8087") - ) - verifyCases( - Seq((h1, Expected(Success(0.toByte), cost = 37022))), + Seq((preH1, Expected(Success(0.toByte), cost = 37022))), existingPropTest("version", { (x: PreHeader) => x.version })) verifyCases( - Seq((h1, Expected(Success( + Seq((preH1, Expected(Success( Helpers.decodeBytes("7fff7fdd6f62018bae0001006d9ca888ff7f56ff8006573700a167f17f2c9f40")), cost = 36121))), existingPropTest("parentId", { (x: PreHeader) => x.parentId })) verifyCases( - Seq((h1, Expected(Success(6306290372572472443L), cost = 36147))), + Seq((preH1, Expected(Success(6306290372572472443L), cost = 36147))), existingPropTest("timestamp", { (x: PreHeader) => x.timestamp })) verifyCases( - Seq((h1, Expected(Success(-3683306095029417063L), cost = 36127))), + Seq((preH1, Expected(Success(-3683306095029417063L), cost = 36127))), existingPropTest("nBits", { (x: PreHeader) => x.nBits })) verifyCases( - Seq((h1, Expected(Success(1), cost = 36136))), + Seq((preH1, Expected(Success(1), cost = 36136))), existingPropTest("height", { (x: PreHeader) => x.height })) verifyCases( - Seq((h1, Expected(Success( + Seq((preH1, Expected(Success( Helpers.decodeGroupElement("026930cb9972e01534918a6f6d6b8e35bc398f57140d13eb3623ea31fbd069939b")), cost = 36255))), existingPropTest("minerPk", { (x: PreHeader) => x.minerPk })) verifyCases( - Seq((h1, Expected(Success(Helpers.decodeBytes("ff8087")), cost = 36249))), + Seq((preH1, Expected(Success(Helpers.decodeBytes("ff8087")), cost = 36249))), existingPropTest("votes", { (x: PreHeader) => x.votes })) } property("Header properties equivalence") { - val treeData = AvlTreeData( - ADDigest @@ ( - ErgoAlgos.decodeUnsafe("010180017f7f7b7f720c00007f7f7f0f01e857a626f37f1483d06af8077a008080") - ), - AvlTreeFlags(false, true, false), - 728138553, - Some(2147483647) - ) - val h1 = CHeader( - Helpers.decodeBytes("957f008001808080ffe4ffffc8f3802401df40006aa05e017fa8d3f6004c804a"), - 0.toByte, - Helpers.decodeBytes("0180dd805b0000ff5400b997fd7f0b9b00de00fb03c47e37806a8186b94f07ff"), - Helpers.decodeBytes("01f07f60d100ffb970c3007f60ff7f24d4070bb8fffa7fca7f34c10001ffe39d"), - CAvlTree(treeData), - Helpers.decodeBytes("804101ff01000080a3ffbd006ac080098df132a7017f00649311ec0e00000100"), - 1L, - -1L, - 1, - Helpers.decodeBytes("e57f80885601b8ff348e01808000bcfc767f2dd37f0d01015030ec018080bc62"), - Helpers.decodeGroupElement("039bdbfa0b49cc6bef58297a85feff45f7bbeb500a9d2283004c74fcedd4bd2904"), - Helpers.decodeGroupElement("0361299207fa392231e23666f6945ae3e867b978e021d8d702872bde454e9abe9c"), - Helpers.decodeBytes("7f4f09012a807f01"), - CBigInt(new BigInteger("-e24990c47e15ed4d0178c44f1790cc72155d516c43c3e8684e75db3800a288", 16)), - Helpers.decodeBytes("7f0180") - ) - verifyCases( Seq((h1, Expected(Success( Helpers.decodeBytes("957f008001808080ffe4ffffc8f3802401df40006aa05e017fa8d3f6004c804a")), @@ -4330,6 +5018,76 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui preGeneratedSamples = Some(samples)) } + property("Coll exists with nested If") { + val o = NumericOps.BigIntIsExactOrdering + verifyCases( + { + def success[T](v: T, c: Int) = Expected(Success(v), c) + Seq( + (Coll[BigInt](), success(false, 38955)), + (Coll[BigInt](BigIntZero), success(false, 39045)), + (Coll[BigInt](BigIntOne), success(true, 39045)), + (Coll[BigInt](BigIntZero, BigIntOne), success(true, 39135)), + (Coll[BigInt](BigIntZero, BigInt10), success(false, 39135)) + ) + }, + existingFeature( + { (x: Coll[BigInt]) => x.exists({ (b: BigInt) => + if (o.gt(b, BigIntZero)) o.lt(b, BigInt10) else false + }) + }, + "{ (x: Coll[BigInt]) => x.exists({(b: BigInt) => if (b > 0) b < 10 else false }) }", + FuncValue( + Array((1, SCollectionType(SBigInt))), + Exists( + ValUse(1, SCollectionType(SBigInt)), + FuncValue( + Array((3, SBigInt)), + If( + GT(ValUse(3, SBigInt), BigIntConstant(CBigInt(new BigInteger("0", 16)))), + LT(ValUse(3, SBigInt), BigIntConstant(CBigInt(new BigInteger("a", 16)))), + FalseLeaf + ) + ) + ) + ))) + } + + property("Coll forall with nested If") { + val o = NumericOps.BigIntIsExactOrdering + verifyCases( + { + def success[T](v: T, c: Int) = Expected(Success(v), c) + Seq( + (Coll[BigInt](), success(true, 38412)), + (Coll[BigInt](BigIntMinusOne), success(false, 38502)), + (Coll[BigInt](BigIntOne), success(true, 38502)), + (Coll[BigInt](BigIntZero, BigIntOne), success(true, 38592)), + (Coll[BigInt](BigIntZero, BigInt11), success(false, 38592)) + ) + }, + existingFeature( + { (x: Coll[BigInt]) => x.forall({ (b: BigInt) => + if (o.gteq(b, BigIntZero)) o.lteq(b, BigInt10) else false + }) + }, + "{ (x: Coll[BigInt]) => x.forall({(b: BigInt) => if (b >= 0) b <= 10 else false }) }", + FuncValue( + Array((1, SCollectionType(SBigInt))), + ForAll( + ValUse(1, SCollectionType(SBigInt)), + FuncValue( + Array((3, SBigInt)), + If( + GE(ValUse(3, SBigInt), BigIntConstant(CBigInt(new BigInteger("0", 16)))), + LE(ValUse(3, SBigInt), BigIntConstant(CBigInt(new BigInteger("a", 16)))), + FalseLeaf + ) + ) + ) + ))) + } + val collWithRangeGen = for { arr <- collGen[Int] l <- Gen.choose(0, arr.length - 1) @@ -4651,6 +5409,61 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui ))) } + property("Coll fold with nested If") { + val n = ExactNumeric.IntIsExactNumeric + verifyCases( + // (coll, initState) + { + def success[T](v: T, c: Int) = Expected(Success(v), c) + Seq( + ((Coll[Byte](), 0), success(0, 42037)), + ((Coll[Byte](), Int.MaxValue), success(Int.MaxValue, 42037)), + ((Coll[Byte](1), Int.MaxValue - 1), success(Int.MaxValue, 42197)), + ((Coll[Byte](1), Int.MaxValue), Expected(new ArithmeticException("integer overflow"))), + ((Coll[Byte](-1), Int.MinValue + 1), success(Int.MinValue + 1, 42197)), + ((Coll[Byte](-1), Int.MinValue), success(Int.MinValue, 42197)), + ((Coll[Byte](1, 2), 0), success(3, 42357)), + ((Coll[Byte](1, -1), 0), success(1, 42357)), + ((Coll[Byte](1, -1, 1), 0), success(2, 42517)) + ) + }, + existingFeature( + { (x: (Coll[Byte], Int)) => x._1.foldLeft(x._2, { i: (Int, Byte) => if (i._2 > 0) n.plus(i._1, i._2) else i._1 }) }, + "{ (x: (Coll[Byte], Int)) => x._1.fold(x._2, { (i1: Int, i2: Byte) => if (i2 > 0) i1 + i2 else i1 }) }", + FuncValue( + Array((1, SPair(SByteArray, SInt))), + Fold( + SelectField.typed[Value[SCollection[SByte.type]]](ValUse(1, SPair(SByteArray, SInt)), 1.toByte), + SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SByteArray, SInt)), 2.toByte), + FuncValue( + Array((3, SPair(SInt, SByte))), + BlockValue( + Array( + ValDef( + 5, + List(), + Upcast( + SelectField.typed[Value[SByte.type]](ValUse(3, SPair(SInt, SByte)), 2.toByte), + SInt + ) + ), + ValDef( + 6, + List(), + SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SByte)), 1.toByte) + ) + ), + If( + GT(ValUse(5, SInt), IntConstant(0)), + ArithOp(ValUse(6, SInt), ValUse(5, SInt), OpCode @@ (-102.toByte)), + ValUse(6, SInt) + ) + ) + ) + ) + ) )) + } + property("Coll indexOf method equivalence") { verifyCases( // (coll, (elem: Byte, from: Int)) @@ -4840,6 +5653,91 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui ))) } + property("Coll map with nested if") { + val n = ExactNumeric.IntIsExactNumeric + verifyCases( + { + def success[T](v: T, c: Int) = Expected(Success(v), c) + Seq( + (Coll[Int](), success(Coll[Int](), 39571)), + (Coll[Int](1), success(Coll[Int](2), 39671)), + (Coll[Int](-1), success(Coll[Int](1), 39671)), + (Coll[Int](1, -2), success(Coll[Int](2, 2), 39771)), + (Coll[Int](1, 2, Int.MaxValue), Expected(new ArithmeticException("integer overflow"))), + (Coll[Int](1, 2, Int.MinValue), Expected(new ArithmeticException("integer overflow"))) + ) + }, + existingFeature( + (x: Coll[Int]) => x.map({ (v: Int) => if (v > 0) n.plus(v, 1) else n.times(-1, v) }), + "{ (x: Coll[Int]) => x.map({ (v: Int) => if (v > 0) v + 1 else -1 * v }) }", + FuncValue( + Array((1, SCollectionType(SInt))), + MapCollection( + ValUse(1, SCollectionType(SInt)), + FuncValue( + Array((3, SInt)), + If( + GT(ValUse(3, SInt), IntConstant(0)), + ArithOp(ValUse(3, SInt), IntConstant(1), OpCode @@ (-102.toByte)), + ArithOp(IntConstant(-1), ValUse(3, SInt), OpCode @@ (-100.toByte)) + ) + ) + ) + ) )) + } + + property("Coll filter") { + val o = ExactOrdering.IntIsExactOrdering + verifyCases( + { + def success[T](v: T, c: Int) = Expected(Success(v), c) + Seq( + (Coll[Int](), success(Coll[Int](), 37223)), + (Coll[Int](1), success(Coll[Int](1), 37273)), + (Coll[Int](1, 2), success(Coll[Int](1, 2), 37323)), + (Coll[Int](1, 2, -1), success(Coll[Int](1, 2), 37373)), + (Coll[Int](1, -1, 2, -2), success(Coll[Int](1, 2), 37423)) + ) + }, + 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") { + val o = ExactOrdering.IntIsExactOrdering + verifyCases( + { + def success[T](v: T, c: Int) = Expected(Success(v), c) + Seq( + (Coll[Int](), success(Coll[Int](), 37797)), + (Coll[Int](1), success(Coll[Int](1), 37887)), + (Coll[Int](10), success(Coll[Int](), 37887)), + (Coll[Int](1, 2), success(Coll[Int](1, 2), 37977)), + (Coll[Int](1, 2, 0), success(Coll[Int](1, 2), 38067)), + (Coll[Int](1, -1, 2, -2, 11), success(Coll[Int](1, 2), 38247)) + ) + }, + 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") { val samples = genSamples(collWithRangeGen, DefaultMinSuccessful) verifyCases( @@ -4989,6 +5887,71 @@ class SigmaDslSpecification extends SigmaDslTesting with CrossVersionProps { sui ))) } + property("Option filter,map with nested If") { + def success[T](v: T, c: Int) = Expected(Success(v), c) + + val o = ExactOrdering.LongIsExactOrdering + verifyCases( + Seq( + (None -> success(None, 38736)), + (Some(0L) -> success(None, 38736)), + (Some(10L) -> success(Some(10L), 38736)), + (Some(11L) -> success(None, 38736))), + 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 }) }", + FuncValue( + Array((1, SOption(SLong))), + MethodCall.typed[Value[SOption[SLong.type]]]( + ValUse(1, SOption(SLong)), + SOption.getMethodByName("filter").withConcreteTypes(Map(STypeVar("T") -> SLong)), + Vector( + FuncValue( + Array((3, SLong)), + If( + GT(ValUse(3, SLong), LongConstant(0L)), + LE(ValUse(3, SLong), LongConstant(10L)), + FalseLeaf + ) + ) + ), + Map() + ) + ))) + + val n = ExactNumeric.LongIsExactNumeric + verifyCases( + Seq( + (None -> success(None, 39077)), + (Some(0L) -> success(Some(0L), 39077)), + (Some(10L) -> success(Some(10L), 39077)), + (Some(-1L) -> success(Some(-2L), 39077)), + (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 ) }, + "{ (x: Option[Long]) => x.map({ (v: Long) => if (v < 0) v - 1 else v }) }", + FuncValue( + Array((1, SOption(SLong))), + MethodCall.typed[Value[SOption[SLong.type]]]( + ValUse(1, SOption(SLong)), + SOption.getMethodByName("map").withConcreteTypes( + Map(STypeVar("T") -> SLong, STypeVar("R") -> SLong) + ), + Vector( + FuncValue( + Array((3, SLong)), + If( + LT(ValUse(3, SLong), LongConstant(0L)), + ArithOp(ValUse(3, SLong), LongConstant(1L), OpCode @@ (-103.toByte)), + ValUse(3, SLong) + ) + ) + ), + Map() + ) + ) )) + } + // TODO HF (3h): implement Option.fold property("Option new methods") { val isEmpty = newFeature({ (x: Option[Long]) => x.isEmpty }, diff --git a/sigmastate/src/test/scala/special/sigma/SigmaDslStaginTests.scala b/sigmastate/src/test/scala/special/sigma/SigmaDslStaginTests.scala index ba4047b1b2..8ba908b7b4 100644 --- a/sigmastate/src/test/scala/special/sigma/SigmaDslStaginTests.scala +++ b/sigmastate/src/test/scala/special/sigma/SigmaDslStaginTests.scala @@ -1,12 +1,11 @@ package special.sigma -import special.wrappers.WrappersTests import special.collection._ + import scala.language.reflectiveCalls -import scalan.{SigmaLibrary, BaseCtxTests, BaseLiftableTests} +import scalan.{BaseLiftableTests, BaseCtxTests} import sigmastate.eval.Extensions._ import sigmastate.eval.{IRContext, ErgoScriptTestkit} -import sigmastate.helpers.SigmaTestingCommons class SigmaDslStaginTests extends BaseCtxTests with ErgoScriptTestkit with BaseLiftableTests { class Ctx extends TestContext with IRContext with LiftableTestKit { diff --git a/sigmastate/src/test/scala/special/sigma/SigmaDslTesting.scala b/sigmastate/src/test/scala/special/sigma/SigmaDslTesting.scala index 580f9cd7c1..2917899a5a 100644 --- a/sigmastate/src/test/scala/special/sigma/SigmaDslTesting.scala +++ b/sigmastate/src/test/scala/special/sigma/SigmaDslTesting.scala @@ -17,6 +17,9 @@ import org.ergoplatform.validation.{ValidationRules, SigmaValidationSettings} import sigmastate.{eval, SSigmaProp, SType} import SType.AnyOps import org.ergoplatform.SigmaConstants.ScriptCostLimit +import org.scalacheck.Arbitrary._ +import org.scalacheck.Gen.frequency +import scalan.RType._ import sigmastate.basics.DLogProtocol.{ProveDlog, DLogProverInput} import sigmastate.basics.{SigmaProtocol, SigmaProtocolPrivateInput, SigmaProtocolCommonInput} import sigmastate.eval.{CompiletimeIRContext, Evaluation, CostingBox, SigmaDsl, IRContext, CostingDataContext} @@ -27,9 +30,11 @@ import sigmastate.helpers.{ErgoLikeContextTesting, SigmaPPrint} import sigmastate.helpers.TestingHelpers._ import sigmastate.interpreter.{ProverResult, ContextExtension, ProverInterpreter} import sigmastate.serialization.ValueSerializer +import sigmastate.serialization.generators.ObjectGenerators import sigmastate.utxo.{DeserializeContext, DeserializeRegister} -import special.collection.Coll +import special.collection.{Coll, CollType} +import scala.collection.mutable import scala.math.Ordering import scala.reflect.ClassTag @@ -37,7 +42,7 @@ class SigmaDslTesting extends PropSpec with PropertyChecks with Matchers with SigmaTestingData with SigmaContractSyntax - with SigmaTypeGens { suite => + with ObjectGenerators { suite => lazy val spec: ContractSpec = TestContractSpec(suite)(new TestingIRContext) @@ -623,7 +628,7 @@ class SigmaDslTesting extends PropSpec /** NOTE, this should be `def` to allow overriding of generatorDrivenConfig in derived Spec classes. */ def DefaultMinSuccessful: MinSuccessful = MinSuccessful(generatorDrivenConfig.minSuccessful) - val PrintTestCasesDefault: Boolean = false + val PrintTestCasesDefault: Boolean = false // true val FailOnTestVectorsDefault: Boolean = true private def checkResult[B](res: Try[B], expectedRes: Try[B], failOnTestVectors: Boolean): Unit = { @@ -702,11 +707,20 @@ class SigmaDslTesting extends PropSpec * @return array-backed ordered sequence of samples */ def genSamples[A: Arbitrary: Ordering: ClassTag](config: PropertyCheckConfigParam): Seq[A] = { + genSamples[A](config, Some(implicitly[Ordering[A]])) + } + + /** Generate samples with optional sorted order. + * @param config generation configuration + * @param optOrd optional ordering of the generated samples in the resuting sequence + * @return array-backed ordered sequence of samples + */ + def genSamples[A: Arbitrary: ClassTag](config: PropertyCheckConfigParam, optOrd: Option[Ordering[A]]): Seq[A] = { val inputs = scala.collection.mutable.ArrayBuilder.make[A]() forAll(config) { x: A => inputs += x } - inputs.result().sorted + optOrd.fold(inputs.result())(implicit ord => inputs.result.sorted) } /** Test the given samples or generate new samples using the given Arbitrary. @@ -735,6 +749,97 @@ class SigmaDslTesting extends PropSpec test(None, f, printTestCases) } + /** Represents generated samples for the type `A`. */ + abstract class Sampled[A] { + /** An instance of [[Arbitrary]] which is used to generate samples. */ + def arbitrary: Arbitrary[A] + + /** Return a sequence of samples. */ + def samples: Seq[A] + } + + /** Default implementation of [[Sampled]]. */ + case class SampledData[A](samples: Seq[A])(implicit val arbitrary: Arbitrary[A]) + extends Sampled[A] + + /** Arbitrary instance for each type descriptor. */ + private val arbitraryCache = new mutable.HashMap[RType[_], Arbitrary[_]] + + /** Lookup [[Arbitrary]] in the cache by type descriptor or create new instance and + * add it to the cache. + */ + def lookupArbitrary[A](t: RType[A]): Arbitrary[A] = (arbitraryCache.get(t) match { + case Some(arb) => arb + case None => + val arb = (t match { + case BooleanType => arbBool + case ByteType => arbByte + case ShortType => arbShort + case IntType => arbInt + case LongType => arbLong + case BigIntRType => arbBigInt + case GroupElementRType => arbGroupElement + case SigmaPropRType => arbSigmaProp + case BoxRType => arbBox + case PreHeaderRType => arbPreHeader + case HeaderRType => arbHeader + case AvlTreeRType => arbAvlTree + case AnyType => arbAnyVal + case UnitType => arbUnit + case p: PairType[a, b] => + implicit val arbA: Arbitrary[a] = lookupArbitrary[a](p.tFst) + implicit val arbB: Arbitrary[b] = lookupArbitrary[b](p.tSnd) + arbTuple2[a,b] + case opt: OptionType[a] => + Arbitrary(frequency((5, None), (5, for (x <- lookupArbitrary(opt.tA).arbitrary) yield Some(x)))) + case coll: CollType[a] => + implicit val elemArb: Arbitrary[a] = lookupArbitrary(coll.tItem) + implicit val elemT: RType[a] = coll.tItem + Arbitrary(collGen[a]) + }).asInstanceOf[Arbitrary[A]] + arbitraryCache.put(t, arb) + arb + }).asInstanceOf[Arbitrary[A]] + + /** Update cached [[Arbitrary]] with a new instance, which generates its data from the + * given [[Sampled]] instance (randomly selects oneOf sample). + */ + def updateArbitrary[A](t: RType[A], sampled: Sampled[A]) = { + t match { + case BigIntRType | GroupElementRType | SigmaPropRType | + BoxRType | PreHeaderRType | HeaderRType | AvlTreeRType | + _: CollType[_] | _: PairType[_,_] | _: OptionType[_] => + val newArb = Arbitrary(Gen.oneOf(sampled.samples)) + arbitraryCache.put(t, newArb) + case _ => + } + } + + /** Sampled test data from each data type. */ + private val sampledCache = new mutable.HashMap[RType[_], Sampled[_]] + + /** Lookup [[Sampled]] test data in the cache by type descriptor or create a new instance and + * add it to the cache. + */ + implicit def lookupSampled[A](implicit t: RType[A]): Sampled[A] = (sampledCache.get(t) match { + case Some(s) => s + case _ => + implicit val tagA = t.classTag + implicit val arb = lookupArbitrary(t) + val res = new SampledData[A]( + samples = genSamples[A](DefaultMinSuccessful, None)) + sampledCache.put(t, res) + updateArbitrary(t, res) + res + }).asInstanceOf[Sampled[A]] + + /** Call this function to prepare samples for the given type. + * They can later be retrieved using `lookupSampled`. */ + def prepareSamples[A](implicit t: RType[A]) = { + lookupSampled[A] + } + + /** Helper implementation for ordering samples. */ trait GroupElementOrdering extends Ordering[GroupElement] { /** Compares `x: ECPoint` string representation with `y: ECPoint` string for order. diff --git a/sigmastate/src/test/scala/special/sigma/SigmaExamplesTests.scala b/sigmastate/src/test/scala/special/sigma/SigmaExamplesTests.scala deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sigmastate/src/test/scala/special/sigma/SigmaTestingData.scala b/sigmastate/src/test/scala/special/sigma/SigmaTestingData.scala index 0568b8ec28..d5c21c9f64 100644 --- a/sigmastate/src/test/scala/special/sigma/SigmaTestingData.scala +++ b/sigmastate/src/test/scala/special/sigma/SigmaTestingData.scala @@ -1,24 +1,19 @@ package special.sigma -import org.ergoplatform.SigmaConstants.ScriptCostLimit -import org.ergoplatform.validation.ValidationRules -import sigmastate.interpreter.ContextExtension import org.scalacheck.Gen.containerOfN -import sigmastate.{AvlTreeFlags, TrivialProp} -import sigmastate.Values.{BooleanConstant, IntConstant} +import sigmastate.AvlTreeFlags import org.scalacheck.{Arbitrary, Gen} import sigmastate.helpers.SigmaTestingCommons -import sigmastate.helpers.TestingHelpers._ import sigmastate.eval._ import sigmastate.eval.Extensions._ -import org.ergoplatform.{ErgoLikeContext, DataInput, ErgoLikeTransaction, ErgoBox} import org.scalacheck.util.Buildable import scalan.RType import scorex.crypto.hash.{Digest32, Blake2b256} import scorex.crypto.authds.{ADKey, ADValue} +import sigmastate.serialization.generators.ObjectGenerators import special.collection.Coll -trait SigmaTestingData extends SigmaTestingCommons with SigmaTypeGens { +trait SigmaTestingData extends SigmaTestingCommons with ObjectGenerators { def collOfN[T: RType: Arbitrary](n: Int)(implicit b: Buildable[T, Array[T]]): Gen[Coll[T]] = { implicit val g: Gen[T] = Arbitrary.arbitrary[T] containerOfN[Array, T](n, g).map(Colls.fromArray(_)) diff --git a/sigmastate/src/test/scala/special/sigma/SigmaTypeGens.scala b/sigmastate/src/test/scala/special/sigma/SigmaTypeGens.scala deleted file mode 100644 index 3f33191ee2..0000000000 --- a/sigmastate/src/test/scala/special/sigma/SigmaTypeGens.scala +++ /dev/null @@ -1,17 +0,0 @@ -package special.sigma - -import org.scalacheck.{Arbitrary, Gen} -import sigmastate.serialization.generators.ObjectGenerators - -trait SigmaTypeGens extends ObjectGenerators { - import sigma.types._ - val genBoolean = Arbitrary.arbBool.arbitrary.map(CBoolean(_): Boolean) - implicit val arbBoolean = Arbitrary(genBoolean) - - val genByte = Arbitrary.arbByte.arbitrary.map(CByte(_): Byte) - implicit val arbByte = Arbitrary(genByte) - - val genInt = Arbitrary.arbInt.arbitrary.map(CInt(_): Int) - implicit val arbInt = Arbitrary(genInt) -} -