Skip to content

Commit

Permalink
Merge pull request #670 from ScorexFoundation/regression-tests
Browse files Browse the repository at this point in the history
Cross version testing support (part 2) (spam tests passed)
  • Loading branch information
aslesarenko authored Jul 27, 2020
2 parents a7a599d + b00b233 commit ddfd0fd
Show file tree
Hide file tree
Showing 15 changed files with 2,327 additions and 691 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ version in ThisBuild := {
git.gitUncommittedChanges in ThisBuild := true

val bouncycastleBcprov = "org.bouncycastle" % "bcprov-jdk15on" % "1.64"
val scrypto = "org.scorexfoundation" %% "scrypto" % "2.1.7"
val scrypto = "org.scorexfoundation" %% "scrypto" % "2.1.9"
val scorexUtil = "org.scorexfoundation" %% "scorex-util" % "0.1.6"
val macroCompat = "org.typelevel" %% "macro-compat" % "1.1.1"
val paradise = "org.scalamacros" %% "paradise" % "2.1.0" cross CrossVersion.full
Expand Down
2 changes: 1 addition & 1 deletion common/src/main/scala/scalan/TypeDesc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import scala.reflect.ClassTag
import scala.annotation.implicitNotFound

/** Base type for all runtime type descriptors. */
@implicitNotFound(msg = "No Elem available for ${A}.")
@implicitNotFound(msg = "No RType available for ${A}.")
abstract class RType[A] {
/** Class tag suitable for construct instances of Array[A]. */
def classTag: ClassTag[A]
Expand Down
14 changes: 11 additions & 3 deletions sigma-api/src/main/scala/special/sigma/SigmaDsl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ trait BigInt {
/**
* Returns the minimum of this BigInteger and {@code val}.
*
* @param val value with which the minimum is to be computed.
* @param that value with which the minimum is to be computed.
* @return the BigInteger whose value is the lesser of this BigInteger and
* { @code val}. If they are equal, either may be returned.
*/
Expand All @@ -180,7 +180,7 @@ trait BigInt {
/**
* Returns the maximum of this BigInteger and {@code val}.
*
* @param val value with which the maximum is to be computed.
* @param that value with which the maximum is to be computed.
* @return the BigInteger whose value is the greater of this and
* { @code val}. If they are equal, either may be returned.
*/
Expand Down Expand Up @@ -277,6 +277,9 @@ trait AnyValue {
def tVal: RType[Any]
}

/** Runtime representation of Ergo boxes used during execution of ErgoTree operations.
* @see [[org.ergoplatform.ErgoBox]]
*/
@scalan.Liftable
@WithMethodCallRecognizers
trait Box {
Expand Down Expand Up @@ -410,6 +413,8 @@ trait Box {
*
* Please note that standard hash function from `scorex.crypto.hash` is used, and height is stored along with root hash of
* the tree, thus `digest` size is always CryptoConstants.hashLength + 1 bytes.
*
* This interface is used as runtime representation of the AvlTree type of ErgoTree.
*/
@scalan.Liftable
trait AvlTree {
Expand Down Expand Up @@ -601,7 +606,9 @@ trait Header {
def votes: Coll[Byte] //3 bytes
}

/** Represents data available in Sigma language using `CONTEXT` global variable*/
/** Runtime representation of Context ErgoTree type.
* Represents data available in Sigma language using `CONTEXT` global variable.
*/
@scalan.Liftable
@WithMethodCallRecognizers
trait Context {
Expand Down Expand Up @@ -690,6 +697,7 @@ trait SigmaContract {
(implicit cT: RType[T]): Coll[Byte] = this.builder.substConstants(scriptBytes, positions, newValues)
}

/** Runtime representation of Global ErgoTree type. */
@scalan.Liftable
@WithMethodCallRecognizers
trait SigmaDslBuilder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ class TestSigmaDslBuilder extends SigmaDslBuilder {
def anyZK(props: Coll[SigmaProp]): SigmaProp = MockSigma(props.exists(p => p.isValid))

@NeverInline
override def xorOf(conditions: Coll[Boolean]): Boolean = conditions.toArray.distinct.length == 2
override def xorOf(conditions: Coll[Boolean]): Boolean = {
// TODO HF: see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/640
conditions.toArray.distinct.length == 2
}

@NeverInline
def sigmaProp(b: Boolean): SigmaProp = MockSigma(b)
Expand Down
76 changes: 53 additions & 23 deletions sigmastate/src/main/scala/sigmastate/eval/CostingDataContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,55 @@ import org.bouncycastle.math.ec.ECPoint
import org.ergoplatform.{ErgoBox, SigmaConstants}
import org.ergoplatform.validation.ValidationRules
import scorex.crypto.authds.avltree.batch._
import scorex.crypto.authds.{ADDigest, ADKey, ADValue, SerializedAdProof}
import scorex.crypto.authds.{ADDigest, ADKey, SerializedAdProof, ADValue}
import sigmastate.SCollection.SByteArray
import sigmastate.{TrivialProp, _}
import sigmastate.Values.{Constant, ConstantNode, ErgoTree, EvaluatedValue, SValue, SigmaBoolean, Value}
import sigmastate.Values.{Constant, EvaluatedValue, SValue, ConstantNode, Value, ErgoTree, SigmaBoolean}
import sigmastate.interpreter.CryptoConstants.EcPointType
import sigmastate.interpreter.{CryptoConstants, Interpreter}
import special.collection.{CCostedBuilder, CSizeOption, Coll, CollType, CostedBuilder, Size, SizeColl, SizeOption}
import special.sigma.{Box, _}
import special.collection.{Size, CSizeOption, SizeColl, CCostedBuilder, CollType, SizeOption, CostedBuilder, Coll}
import special.sigma._
import sigmastate.eval.Extensions._
import spire.syntax.all.cfor

import scala.util.{Failure, Success}
import scala.util.{Success, Failure}
import scalan.RType
import scorex.crypto.hash.{Blake2b256, Digest32, Sha256}
import scorex.crypto.hash.{Digest32, Sha256, Blake2b256}
import sigmastate.basics.DLogProtocol.ProveDlog
import sigmastate.basics.ProveDHTuple
import sigmastate.lang.Terms.OperationId
import sigmastate.serialization.ErgoTreeSerializer.DefaultSerializer
import sigmastate.serialization.{GroupElementSerializer, SigmaSerializer}
import sigmastate.serialization.{SigmaSerializer, GroupElementSerializer}
import special.Types.TupleType

import scala.reflect.ClassTag

/** Interface implmented by wrappers to provide access to the underlying wrapped value. */
trait WrapperOf[T] {
/** The data value wrapped by this wrapper. */
def wrappedValue: T
}

/** A default implementation of [[BigInt]] interface.
* @see [[BigInt]] for detailed descriptions
*/
case class CBigInt(override val wrappedValue: BigInteger) extends TestBigInt(wrappedValue) with WrapperOf[BigInteger] {
override val dsl = CostingSigmaDslBuilder
}

/** A default implementation of [[GroupElement]] interface.
* @see [[GroupElement]] for detailed descriptions
*/
case class CGroupElement(override val wrappedValue: EcPointType) extends TestGroupElement(wrappedValue) with WrapperOf[ECPoint] {
override val dsl = CostingSigmaDslBuilder

override def getEncoded: Coll[Byte] = dsl.Colls.fromArray(GroupElementSerializer.toBytes(wrappedValue))

}

/** A default implementation of [[SigmaProp]] interface.
* @see [[SigmaProp]] for detailed descriptions
*/
case class CSigmaProp(sigmaTree: SigmaBoolean) extends SigmaProp with WrapperOf[SigmaBoolean] {
override def wrappedValue: SigmaBoolean = sigmaTree

Expand Down Expand Up @@ -83,17 +94,18 @@ case class CSigmaProp(sigmaTree: SigmaBoolean) extends SigmaProp with WrapperOf[
override def toString: String = s"SigmaProp(${wrappedValue.showToString})"
}

/** A default implementation of [[AvlTree]] interface.
* @see [[AvlTree]] for detailed descriptions
*/
case class CAvlTree(treeData: AvlTreeData) extends AvlTree with WrapperOf[AvlTreeData] {
val builder = CostingSigmaDslBuilder
val Colls = builder.Colls

override def wrappedValue: AvlTreeData = treeData

def startingDigest: Coll[Byte] = Colls.fromArray(treeData.digest)
override def keyLength: Int = treeData.keyLength

def keyLength: Int = treeData.keyLength

def enabledOperations = treeData.treeFlags.serializeToByte
override def enabledOperations = treeData.treeFlags.serializeToByte

override def isInsertAllowed: Boolean = treeData.treeFlags.insertAllowed

Expand All @@ -106,15 +118,11 @@ case class CAvlTree(treeData: AvlTreeData) extends AvlTree with WrapperOf[AvlTre
this.copy(treeData = td)
}

def valueLengthOpt: Option[Int] = treeData.valueLengthOpt

def cost: Int = 1

def dataSize: Long = SAvlTree.dataSize(treeData.asInstanceOf[SType#WrappedType])
override def valueLengthOpt: Option[Int] = treeData.valueLengthOpt

override def digest: Coll[Byte] = Colls.fromArray(treeData.digest)

def updateDigest(newDigest: Coll[Byte]): AvlTree = {
override def updateDigest(newDigest: Coll[Byte]): AvlTree = {
val td = treeData.copy(digest = ADDigest @@ newDigest.toArray)
this.copy(treeData = td)
}
Expand All @@ -123,53 +131,56 @@ case class CAvlTree(treeData: AvlTreeData) extends AvlTree with WrapperOf[AvlTre
val adProof = SerializedAdProof @@ proof.toArray
val bv = new BatchAVLVerifier[Digest32, Blake2b256.type](
treeData.digest, adProof,
treeData.keyLength, treeData.valueLengthOpt)
treeData.keyLength, treeData.valueLengthOpt) {
/** Override default logging which outputs stack trace to the console. */
override protected def logError(t: Throwable): Unit = {}
}
bv
}

override def contains(key: Coll[Byte], proof: Coll[Byte]): Boolean = {
val keyBytes = key.toArray
val bv = createVerifier(proof)
bv.performOneOperation(Lookup(ADKey @@ keyBytes)) match {
case Failure(_) => false
case Success(r) => r match {
case Some(_) => true
case _ => false
}
case Failure(_) => false
}
}

override def get(key: Coll[Byte], proof: Coll[Byte]): Option[Coll[Byte]] = {
val keyBytes = key.toArray
val bv = createVerifier(proof)
bv.performOneOperation(Lookup(ADKey @@ keyBytes)) match {
case Failure(_) => Interpreter.error(s"Tree proof is incorrect $treeData")
case Success(r) => r match {
case Some(v) => Some(Colls.fromArray(v))
case _ => None
}
case Failure(_) => Interpreter.error(s"Tree proof is incorrect $treeData")
}
}

override def getMany(keys: Coll[Coll[Byte]], proof: Coll[Byte]): Coll[Option[Coll[Byte]]] = {
val bv = createVerifier(proof)
keys.map { key =>
bv.performOneOperation(Lookup(ADKey @@ key.toArray)) match {
case Failure(_) => Interpreter.error(s"Tree proof is incorrect $treeData")
case Success(r) => r match {
case Some(v) => Some(Colls.fromArray(v))
case _ => None
}
case Failure(_) => Interpreter.error(s"Tree proof is incorrect $treeData")
}
}
}

override def insert(operations: Coll[(Coll[Byte], Coll[Byte])], proof: Coll[Byte]): Option[AvlTree] = {
override def insert(entries: Coll[(Coll[Byte], Coll[Byte])], proof: Coll[Byte]): Option[AvlTree] = {
if (!isInsertAllowed) {
None
} else {
val bv = createVerifier(proof)
operations.forall { case (key, value) =>
entries.forall { case (key, value) =>
val insertRes = bv.performOneOperation(Insert(ADKey @@ key.toArray, ADValue @@ value.toArray))
if (insertRes.isFailure) {
Interpreter.error(s"Incorrect insert for $treeData (key: $key, value: $value, digest: $digest): ${insertRes.failed.get}}")
Expand Down Expand Up @@ -249,6 +260,9 @@ class EvalSizeBuilder extends CSizeBuilder {
}
}

/** A default implementation of [[Box]] interface.
* @see [[Box]] for detailed descriptions
*/
case class CostingBox(isCost: Boolean, val ebox: ErgoBox) extends Box with WrapperOf[ErgoBox] {
val builder = CostingSigmaDslBuilder

Expand Down Expand Up @@ -404,6 +418,9 @@ object CFunc {
val maxCost = 1000
}

/** A default implementation of [[PreHeader]] interface.
* @see [[PreHeader]] for detailed descriptions
*/
case class CPreHeader(
version: Byte,
parentId: Coll[Byte],
Expand All @@ -414,6 +431,9 @@ case class CPreHeader(
votes: Coll[Byte]
) extends PreHeader {}

/** A default implementation of [[Header]] interface.
* @see [[Header]] for detailed descriptions
*/
case class CHeader(
id: Coll[Byte],
version: Byte,
Expand All @@ -438,6 +458,9 @@ object CHeader {
val NonceSize: Int = SigmaConstants.AutolykosPowSolutionNonceArraySize.value
}

/** A default implementation of [[CostModel]] interface.
* @see [[CostModel]] for detailed descriptions
*/
class CCostModel extends CostModel {
private def costOf(opName: String, opType: SFunc): Int = {
val operId = OperationId(opName, opType)
Expand Down Expand Up @@ -470,6 +493,10 @@ class CCostModel extends CostModel {
def PubKeySize: Long = CryptoConstants.EncodedGroupElementLength
}


/** A default implementation of [[SigmaDslBuilder]] interface.
* @see [[SigmaDslBuilder]] for detailed descriptions
*/
class CostingSigmaDslBuilder extends TestSigmaDslBuilder { dsl =>
implicit val validationSettings = ValidationRules.currentSettings

Expand Down Expand Up @@ -612,6 +639,9 @@ class CostingSigmaDslBuilder extends TestSigmaDslBuilder { dsl =>

object CostingSigmaDslBuilder extends CostingSigmaDslBuilder

/** A default implementation of [[Context]] interface.
* @see [[Context]] for detailed descriptions
*/
case class CostingDataContext(
_dataInputs: Coll[Box],
override val headers: Coll[Header],
Expand Down
12 changes: 12 additions & 0 deletions sigmastate/src/main/scala/sigmastate/lang/Terms.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ object Terms {
def apply(name: String): Ident = Ident(name, NoType)
}

// TODO HF: move to sigmastate.Values
case class Apply(func: Value[SType], args: IndexedSeq[Value[SType]]) extends Value[SType] {
override def companion = Apply
override lazy val tpe: SType = func.tpe match {
Expand Down Expand Up @@ -173,6 +174,17 @@ object Terms {
}
object MethodCall extends ValueCompanion {
override def opCode: OpCode = OpCodes.MethodCallCode

/** Helper constructor which allows to cast the resulting node to the specified
* [[sigmastate.Values.Value]] type `T`.
* @see [[sigmastate.lang.Terms.MethodCall]]
*/
def typed[T <: SValue](obj: Value[SType],
method: SMethod,
args: IndexedSeq[Value[SType]],
typeSubst: Map[STypeVar, SType]): T = {
MethodCall(obj, method, args, typeSubst).asInstanceOf[T]
}
}
object PropertyCall extends ValueCompanion {
override def opCode: OpCode = OpCodes.PropertyCallCode
Expand Down
11 changes: 10 additions & 1 deletion sigmastate/src/main/scala/sigmastate/types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.util

import org.ergoplatform._
import org.ergoplatform.validation._
import scalan.RType
import scalan.{RType, Nullable}
import scalan.RType.GeneralType
import sigmastate.SType.{TypeCode, AnyOps}
import sigmastate.interpreter.CryptoConstants
Expand Down Expand Up @@ -1294,6 +1294,15 @@ object STuple extends STypeCompanion {
}
}

/** Helper constuctor/extractor for tuples of two types. */
object SPair {
def apply(l: SType, r: SType) = STuple(Vector(l, r))
def unapply(t: STuple): Nullable[(SType, SType)] = t match {
case STuple(IndexedSeq(l, r)) => Nullable((l, r))
case _ => Nullable.None
}
}

case class SFunc(tDom: IndexedSeq[SType], tRange: SType, tpeParams: Seq[STypeParam] = Nil)
extends SType with SGenericType
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class CostingSpecification extends SigmaTestingData {

val printCosts = true

val (key1, _, avlProver) = sampleAvlProver
val (key1, _, _, avlProver) = sampleAvlProver
val keys = Colls.fromItems(key1)
val key2 = keyCollGen.sample.get
avlProver.performOneOperation(Lookup(ADKey @@ key1.toArray))
Expand Down
Loading

0 comments on commit ddfd0fd

Please sign in to comment.