Skip to content

Commit

Permalink
SMethod tests (#508)
Browse files Browse the repository at this point in the history
* Add constants table

* Remove comments

* Add some supporting info

* Remove unchecked const

* Add some tests for numeric and boolean

* Add more checks

* Simplfy test for byteArrayToBigInt

* Test Box and Context

* Remove uncompleted methods

* Test Coll

* Fix Coll typer tests

* Fix comments

* Some improvements, add TODO for BigInt test

* Add getVar test

* Finish testing

* Empower apply test

* Add STuple size test

* Restrict tuple methods

* Make it better

* Mute advanced tuple operations typer test

* add ir builder for Coll.append method (Append IR node);

* Fix types.scala according new changes

* Enable modular operations tests
  • Loading branch information
Eugene Gostkin authored and aslesarenko committed Jun 3, 2019
1 parent 4b3ee12 commit d62d0ba
Show file tree
Hide file tree
Showing 10 changed files with 526 additions and 50 deletions.
6 changes: 3 additions & 3 deletions src/main/scala/org/ergoplatform/ErgoBox.scala
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ object ErgoBox {
val size: Short = 32
}

val MaxBoxSize: Int = 64 * 1024
val MaxBoxSize: Int = ErgoConstants.MaxBoxSize.get

val STokenType = STuple(SByteArray, SLong)
val STokensRegType = SCollection(STokenType)
Expand Down Expand Up @@ -133,9 +133,9 @@ object ErgoBox {
val TokensRegId: MandatoryRegisterId = R2
val ReferenceRegId: MandatoryRegisterId = R3

val MaxTokens: Byte = 4
val MaxTokens: Byte = ErgoConstants.MaxTokens.get

val maxRegisters = 10
val maxRegisters: Int = ErgoConstants.MaxRegisters.get
val mandatoryRegisters: Vector[MandatoryRegisterId] = Vector(R0, R1, R2, R3)
val nonMandatoryRegisters: Vector[NonMandatoryRegisterId] = Vector(R4, R5, R6, R7, R8, R9)
val startingNonMandatoryIndex: Byte = nonMandatoryRegisters.head.number
Expand Down
66 changes: 66 additions & 0 deletions src/main/scala/org/ergoplatform/ErgoConstants.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.ergoplatform

import sigmastate.{AtLeast, SBigInt, SPrimType}

case class SizeConstant[T: Numeric](value: T, id: Short, description: String) {
def get: T = value
}

/**
* Fundamental constants that are used in sigma's logic and checks
*/
object ErgoConstants {

object MaxInputSize extends SizeConstant[Int](1024 * 1024 * 1, 1,
"Input size should not be greater then provided value") {
}

object MaxTreeDepth extends SizeConstant[Int](110, 2,
"Max tree depth should not be greater then provided value") {
}

object MaxByteArrayLength extends SizeConstant[Int](10000, 3,
"Max bytearray length") {
}

object MaxTokens extends SizeConstant[Byte](4, 6,
"Tokens count should not be greater than provided value") {
}

object MaxRegisters extends SizeConstant[Int](10, 7,
"Registers count should not be greater than provided value") {
}

object MaxBoxSize extends SizeConstant[Int](64 * 1024, 8,
"Box size should not be greater than provided value") {
}

object MaxBigIntSizeInBytes extends SizeConstant[Long](32L, 9,
"BigInt size in bytes should not be greater than provided value") {
}

object MaxTupleLength extends SizeConstant[Int](255, 10,
"Tuple length should not be greater than provided value") {
}

object MaxHeaders extends SizeConstant[Int](10, 11,
"Headers count should not be greater than provided value") {
}

object MaxChildrenCountForAtLeastOp extends SizeConstant[Int](255, 12,
"Max children count should not be greater than provided value") {
}

val ConstTable: Seq[SizeConstant[_]] = Seq(
MaxInputSize,
MaxTreeDepth,
MaxByteArrayLength,
MaxTokens,
MaxRegisters,
MaxBoxSize,
MaxBigIntSizeInBytes,
MaxTupleLength,
MaxHeaders,
MaxChildrenCountForAtLeastOp
)
}
2 changes: 1 addition & 1 deletion src/main/scala/org/ergoplatform/ErgoLikeContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ object ErgoLikeContext {
val dummyPreHeader: PreHeader = null

/** Maximimum number of headers in `headers` collection of the context. */
val MaxHeaders = 10
val MaxHeaders = ErgoConstants.MaxHeaders.get

def apply(currentHeight: Height,
lastBlockUtxoRoot: AvlTreeData,
Expand Down
11 changes: 6 additions & 5 deletions src/main/scala/sigmastate/interpreter/Interpreter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ package sigmastate.interpreter

import java.util

import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{strategy, rule, everywherebu}
import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{everywherebu, rule, strategy}
import org.bitbucket.inkytonik.kiama.rewriting.Strategy
import sigmastate.basics.DLogProtocol.{FirstDLogProverMessage, DLogInteractiveProver}
import org.ergoplatform.ErgoConstants
import sigmastate.basics.DLogProtocol.{DLogInteractiveProver, FirstDLogProverMessage}
import scorex.util.ScorexLogging
import sigmastate.SCollection.SByteArray
import sigmastate.Values._
import sigmastate.eval.{IRContext, Sized}
import sigmastate.lang.Terms.ValueOps
import sigmastate.basics._
import sigmastate.interpreter.Interpreter.{VerificationResult, ScriptEnv}
import sigmastate.lang.exceptions.InterpreterException
import sigmastate.interpreter.Interpreter.{ScriptEnv, VerificationResult}
import sigmastate.lang.exceptions.{CosterException, InterpreterException}
import sigmastate.serialization.ValueSerializer
import sigmastate.utxo.DeserializeContext
import sigmastate.{SType, _}
Expand All @@ -28,7 +29,7 @@ trait Interpreter extends ScorexLogging {

type ProofT = UncheckedTree

final val MaxByteArrayLength = 10000
final val MaxByteArrayLength = ErgoConstants.MaxByteArrayLength.get

/**
* Max cost of a script interpreter can accept
Expand Down
5 changes: 3 additions & 2 deletions src/main/scala/sigmastate/serialization/SigmaSerializer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package sigmastate.serialization

import java.nio.ByteBuffer

import org.ergoplatform.ErgoConstants
import org.ergoplatform.validation.SigmaValidationSettings
import scorex.util.ByteArrayBuilder
import sigmastate.lang.exceptions.SerializerException
Expand All @@ -12,8 +13,8 @@ object SigmaSerializer {
type Position = Int
type Consumed = Int

val MaxInputSize: Int = 1024 * 1024 * 1
val MaxTreeDepth: Int = 110
val MaxInputSize: Int = ErgoConstants.MaxInputSize.get
val MaxTreeDepth: Int = ErgoConstants.MaxTreeDepth.get

/** Helper function to be use in serializers.
* Starting position is marked and then used to compute number of consumed bytes.
Expand Down
5 changes: 3 additions & 2 deletions src/main/scala/sigmastate/trees.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package sigmastate

import org.ergoplatform.ErgoConstants
import org.ergoplatform.validation.SigmaValidationSettings
import scorex.crypto.hash.{Sha256, Blake2b256, CryptographicHash32}
import sigmastate.Operations._
import sigmastate.SCollection.{SIntArray, SByteArray}
import sigmastate.SOption.SIntOption
import sigmastate.Values._
import sigmastate.basics.{SigmaProtocol, SigmaProtocolPrivateInput, SigmaProtocolCommonInput}
import sigmastate.basics.{SigmaProtocol, SigmaProtocolCommonInput, SigmaProtocolPrivateInput}
import sigmastate.serialization.OpCodes._
import sigmastate.serialization._
import sigmastate.utxo.{Transformer, SimpleTransformerCompanion}
Expand Down Expand Up @@ -268,7 +269,7 @@ case class AtLeast(bound: Value[SInt.type], input: Value[SCollection[SSigmaProp.

object AtLeast extends ValueCompanion {
override def opCode: OpCode = AtLeastCode
val MaxChildrenCount = 255
val MaxChildrenCount: Int = ErgoConstants.MaxChildrenCountForAtLeastOp.get

def apply(bound: Value[SInt.type], children: Seq[SigmaPropValue]): AtLeast =
AtLeast(bound, ConcreteCollection(children.toIndexedSeq))
Expand Down
33 changes: 27 additions & 6 deletions src/main/scala/sigmastate/types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -560,10 +560,13 @@ case object SBoolean extends SPrimType with SEmbeddable with SLogical with SProd
override def typeId = typeCode
override def ancestors: Seq[SType] = Nil
val ToByte = "toByte"
protected override def getMethods() = super.getMethods() ++ Seq(
protected override def getMethods() = super.getMethods()
/* TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
++ Seq(
SMethod(this, ToByte, SFunc(this, SByte), 1)
.withInfo(PropertyCall, "Convert true to 1 and false to 0"),
)
*/
override def mkConstant(v: Boolean): Value[SBoolean.type] = BooleanConstant(v)
override def dataSize(v: SType#WrappedType): Long = 1
override def isConstantSize = true
Expand Down Expand Up @@ -665,7 +668,7 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM
val RelationOpType = SFunc(Vector(SBigInt, SBigInt), SBoolean)

/** The maximum size of BigInteger value in byte array representation. */
val MaxSizeInBytes: Long = 32L
val MaxSizeInBytes: Long = ErgoConstants.MaxBigIntSizeInBytes.get

override def dataSize(v: SType#WrappedType): Long = MaxSizeInBytes

Expand Down Expand Up @@ -709,7 +712,8 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM
ModQMethod,
PlusModQMethod,
MinusModQMethod,
MultModQMethod,
// TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
// MultModQMethod,
)
}

Expand All @@ -731,8 +735,10 @@ case object SGroupElement extends SProduct with SPrimType with SEmbeddable with
override def typeId = typeCode
override def coster: Option[CosterFactory] = Some(Coster(_.GroupElementCoster))
protected override def getMethods(): Seq[SMethod] = super.getMethods() ++ Seq(
/* TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
SMethod(this, "isIdentity", SFunc(this, SBoolean), 1)
.withInfo(PropertyCall, "Checks if this value is identity element of the eliptic curve group."),
*/
SMethod(this, "getEncoded", SFunc(IndexedSeq(this), SByteArray), 2)
.withIRInfo(MethodCallIrBuilder)
.withInfo(PropertyCall, "Get an encoding of the point value."),
Expand Down Expand Up @@ -906,7 +912,9 @@ object SOption extends STypeCompanion {
IsDefinedMethod,
GetMethod,
GetOrElseMethod,
/* TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
FoldMethod,
*/
MapMethod,
FilterMethod,
)
Expand Down Expand Up @@ -1025,9 +1033,12 @@ object SCollection extends STypeCompanion with MethodByNameUnapply {
ArgInfo("p", "the predicate used to test elements."))

val AppendMethod = SMethod(this, "append", SFunc(IndexedSeq(ThisType, ThisType), ThisType, Seq(paramIV)), 9)
.withIRInfo({
case (builder, obj, _, Seq(xs), _) =>
builder.mkAppend(obj.asCollection[SType], xs.asCollection[SType])
})
.withInfo(Append, "Puts the elements of other collection after the elements of this collection (concatenation of 2 collections)",
ArgInfo("other", "the collection to append at the end of this"))

val ApplyMethod = SMethod(this, "apply", SFunc(IndexedSeq(ThisType, SInt), tIV, Seq(tIV)), 10)
.withInfo(ByIndex,
"""The element at given index.
Expand Down Expand Up @@ -1138,26 +1149,34 @@ object SCollection extends STypeCompanion with MethodByNameUnapply {
FilterMethod,
AppendMethod,
ApplyMethod,
/* TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
BitShiftLeftMethod,
BitShiftRightMethod,
BitShiftRightZeroedMethod,
*/
IndicesMethod,
FlatMapMethod,
PatchMethod,
UpdatedMethod,
UpdateManyMethod,
/*TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
UnionSetsMethod,
DiffMethod,
IntersectMethod,
PrefixLengthMethod,
*/
IndexOfMethod,
/* TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
LastIndexOfMethod,
FindMethod,
*/
ZipMethod,
/* TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
DistinctMethod,
StartsWithMethod,
EndsWithMethod,
MapReduceMethod,
*/
)
def apply[T <: SType](elemType: T): SCollection[T] = SCollectionType(elemType)
def apply[T <: SType](implicit elemType: T, ov: Overload1): SCollection[T] = SCollectionType(elemType)
Expand Down Expand Up @@ -1255,15 +1274,17 @@ object STuple extends STypeCompanion {

lazy val colMethods = {
val subst = Map(SCollection.tIV -> SAny)
SCollection.methods.map { m =>
// TODO: implement other
val activeMethods = Set(1.toByte, 10.toByte)
SCollection.methods.filter(m => activeMethods.contains(m.methodId)).map { m =>
m.copy(stype = SigmaTyper.applySubst(m.stype, subst).asFunc)
}
}

def methods: Seq[SMethod] = sys.error(s"Shouldn't be called.")

def apply(items: SType*): STuple = STuple(items.toIndexedSeq)
val MaxTupleLength = 255
val MaxTupleLength: Int = ErgoConstants.MaxTupleLength.get
private val componentNames = Array.tabulate(MaxTupleLength){ i => s"_${i + 1}" }
def componentNameByIndex(i: Int): String =
try componentNames(i)
Expand Down
7 changes: 4 additions & 3 deletions src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ trait SigmaTestingCommons extends PropSpec
}
}

def func[A: RType, B: RType](func: String)(implicit IR: IRContext): A => B = {
def func[A: RType, B: RType](func: String, bindings: (Byte, EvaluatedValue[_ <: SType])*)(implicit IR: IRContext): A => B = {
import IR._
import IR.Context._;
val tA = RType[A]
Expand All @@ -130,8 +130,9 @@ trait SigmaTestingCommons extends PropSpec
(in: A) => {
implicit val cA = tA.classTag
val x = fromPrimView(in)
val context = ErgoLikeContext.dummy(createBox(0, TrueProp))
.withBindings(1.toByte -> Constant[SType](x.asInstanceOf[SType#WrappedType], tpeA))
val context =
ErgoLikeContext.dummy(createBox(0, TrueProp))
.withBindings(1.toByte -> Constant[SType](x.asInstanceOf[SType#WrappedType], tpeA)).withBindings(bindings: _*)
val calcCtx = context.toSigmaContext(IR, isCost = false)
val (res, _) = valueFun(calcCtx)
res.asInstanceOf[B]
Expand Down
17 changes: 13 additions & 4 deletions src/test/scala/sigmastate/lang/SigmaTyperTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,13 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
typecheck(env, "(1, 2L).size") shouldBe SInt
typecheck(env, "(1, 2L)(0)") shouldBe SInt
typecheck(env, "(1, 2L)(1)") shouldBe SLong
typecheck(env, "{ (a: Int) => (1, 2L)(a) }") shouldBe SFunc(IndexedSeq(SInt), SAny)
}

// TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
ignore("tuple advanced operations") {
typecheck(env, "(1, 2L).getOrElse(2, 3)") shouldBe SAny
typecheck(env, "(1, 2L).slice(0, 2)") shouldBe SCollection(SAny)
typecheck(env, "{ (a: Int) => (1, 2L)(a) }") shouldBe SFunc(IndexedSeq(SInt), SAny)
}

property("types") {
Expand Down Expand Up @@ -240,8 +244,10 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
typecheck(env, "{ (a: Int) => { val b = a + 1; b } }") shouldBe SFunc(IndexedSeq(SInt), SInt)
typecheck(env, "{ (a: Int, box: Box) => a + box.value }") shouldBe
SFunc(IndexedSeq(SInt, SBox), SLong)
/* TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
typecheck(env, "{ (p: (Int, GroupElement), box: Box) => p._1 > box.value && p._2.isIdentity }") shouldBe
SFunc(IndexedSeq(STuple(SInt, SGroupElement), SBox), SBoolean)
*/
typecheck(env, "{ (p: (Int, SigmaProp), box: Box) => p._1 > box.value && p._2.isProven }") shouldBe
SFunc(IndexedSeq(STuple(SInt, SSigmaProp), SBox), SBoolean)

Expand Down Expand Up @@ -585,21 +591,24 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
typefail(env, "true >>> false", 1, 1)
}

property("Collection.BitShiftLeft") {
// TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
ignore("Collection.BitShiftLeft") {
typecheck(env, "Coll(1,2) << 2") shouldBe SCollection(SInt)
an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) << true")
an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) << 2L")
an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) << (2L, 3)")
}

property("Collection.BitShiftRight") {
// TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
ignore("Collection.BitShiftRight") {
typecheck(env, "Coll(1,2) >> 2") shouldBe SCollection(SInt)
an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) >> 2L")
an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) >> true")
an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) >> (2L, 3)")
}

property("Collection.BitShiftRightZeroed") {
// TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
ignore("Collection.BitShiftRightZeroed") {
typecheck(env, "Coll(true, false) >>> 2") shouldBe SCollection(SBoolean)
an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) >>> 2")
an [TyperException] should be thrownBy typecheck(env, "Coll(true, false) >>> true")
Expand Down
Loading

0 comments on commit d62d0ba

Please sign in to comment.