Skip to content

Commit

Permalink
Merge pull request #556 from ScorexFoundation/v2.2.1
Browse files Browse the repository at this point in the history
v2.2.1
  • Loading branch information
catena2w authored Jun 28, 2019
2 parents 8b09260 + 686c7ff commit a0238fb
Show file tree
Hide file tree
Showing 23 changed files with 242 additions and 110 deletions.
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ val scorexUtil = "org.scorexfoundation" %% "scorex-util" % "0.1.4"
val macroCompat = "org.typelevel" %% "macro-compat" % "1.1.1"
val paradise = "org.scalamacros" %% "paradise" % "2.1.0" cross CrossVersion.full

val specialVersion = "master-4178b526-SNAPSHOT"
val specialVersion = "master-61e8ec8c-SNAPSHOT"
val specialCommon = "io.github.scalan" %% "common" % specialVersion
val specialCore = "io.github.scalan" %% "core" % specialVersion
val specialLibrary = "io.github.scalan" %% "library" % specialVersion
Expand Down Expand Up @@ -201,7 +201,7 @@ lazy val sigma = (project in file("."))
.settings(commonSettings: _*)

def runErgoTask(task: String, sigmastateVersion: String, log: Logger): Unit = {
val ergoBranch = "v2.2-faster-costing"
val ergoBranch = "master"
val sbtEnvVars = Seq("BUILD_ENV" -> "test", "SIGMASTATE_VERSION" -> sigmastateVersion)

log.info(s"Testing current build in Ergo (branch $ergoBranch):")
Expand Down
15 changes: 15 additions & 0 deletions sigma-impl/src/main/scala/sigma/util/Extensions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,21 @@ object Extensions {
* @since Mainnet
*/
def multInverseModQ: BigInt = ???

/** Checks this {@code BigInteger} can be cust to 256 bit two's-compliment representation,
* checking for lost information. If the value of this {@code BigInteger}
* is out of the range of the 256 bits, then an {@code ArithmeticException} is thrown.
*
* @return this {@code BigInteger} if the check is successful
* @throws ArithmeticException if the value of {@code this} will
* not exactly fit in a 256 bit range.
* @see BigInteger#longValueExact
*/
@inline final def to256BitValueExact: BigInteger = {
if (x.bitLength() <= 255) x
else
throw new ArithmeticException("BigInteger out of 256 bit range");
}
}

implicit class OptionOps[T](val opt: Option[T]) extends AnyVal {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import scalan.{RType, Internal, NeverInline, Reified}
import scorex.crypto.hash.{Sha256, Blake2b256}
import special.SpecialPredef
import special.collection._
import sigma.util.Extensions.BigIntegerOps

class TestSigmaDslBuilder extends SigmaDslBuilder {
// manual fix
Expand Down Expand Up @@ -53,11 +54,7 @@ class TestSigmaDslBuilder extends SigmaDslBuilder {

@NeverInline
def byteArrayToBigInt(bytes: Coll[Byte]): BigInt = {
val dlogGroupOrder = __curve__.getN
val bi = new BigInteger(1, bytes.toArray)
if (bi.compareTo(dlogGroupOrder) == 1) {
throw new RuntimeException(s"BigInt value exceeds the order of the dlog group (${__curve__}). Expected to be less than: $dlogGroupOrder, actual: $bi")
}
val bi = new BigInteger(bytes.toArray).to256BitValueExact
this.BigInt(bi)
}

Expand Down
9 changes: 5 additions & 4 deletions sigma-impl/src/main/scala/special/sigma/TestBigInt.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package special.sigma

import special.collection.{Coll}
import java.math.BigInteger
import sigma.util.Extensions.BigIntegerOps

abstract class TestBigInt(private[sigma] val value: BigInteger) extends BigInt {
val dsl: TestSigmaDslBuilder = new TestSigmaDslBuilder
Expand Down Expand Up @@ -31,11 +32,11 @@ abstract class TestBigInt(private[sigma] val value: BigInteger) extends BigInt {

override def signum: Int = value.signum()

override def add(that: BigInt): BigInt = dsl.BigInt(value.add(that.value))
override def add(that: BigInt): BigInt = dsl.BigInt(value.add(that.value).to256BitValueExact)

override def subtract(that: BigInt): BigInt = dsl.BigInt(value.subtract(that.value))
override def subtract(that: BigInt): BigInt = dsl.BigInt(value.subtract(that.value).to256BitValueExact)

override def multiply(that: BigInt): BigInt = dsl.BigInt(value.multiply(that.value))
override def multiply(that: BigInt): BigInt = dsl.BigInt(value.multiply(that.value).to256BitValueExact)

override def divide(that: BigInt): BigInt = dsl.BigInt(value.divide(that.value))

Expand All @@ -47,5 +48,5 @@ abstract class TestBigInt(private[sigma] val value: BigInteger) extends BigInt {

override def max(that: BigInt): BigInt = dsl.BigInt(value.max(that.value))

override def negate(): BigInt = dsl.BigInt(value.negate())
override def negate(): BigInt = dsl.BigInt(value.negate().to256BitValueExact)
}
8 changes: 5 additions & 3 deletions src/main/scala/sigmastate/eval/Evaluation.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package sigmastate.eval

import java.lang.Math
import java.math.BigInteger

import org.bouncycastle.math.ec.ECPoint
Expand Down Expand Up @@ -477,7 +478,7 @@ trait Evaluation extends RuntimeCosting { IR: IRContext =>

@inline def += (n: Int) = {
// println(s"${_currentCost} + $n")
this._currentCost += n
this._currentCost = java.lang.Math.addExact(this._currentCost, n)
}
@inline def currentCost: Int = _currentCost
@inline def resetCost() = { _currentCost = initialCost }
Expand Down Expand Up @@ -572,7 +573,7 @@ trait Evaluation extends RuntimeCosting { IR: IRContext =>
if (costLimit.isDefined) {
val limit = costLimit.get
val loopCost = if (_loopStack.isEmpty) 0 else _loopStack.head.accumulatedCost
val accumulatedCost = cost + loopCost
val accumulatedCost = java.lang.Math.addExact(cost, loopCost)
if (accumulatedCost > limit) {
// if (cost < limit)
// println(s"FAIL FAST in loop: $accumulatedCost > $limit")
Expand Down Expand Up @@ -600,7 +601,8 @@ trait Evaluation extends RuntimeCosting { IR: IRContext =>

if (_loopStack.nonEmpty && _loopStack.head.body == body) {
// every time we exit the body of the loop we need to update accumulated cost
_loopStack.head.accumulatedCost += deltaCost
val h = _loopStack.head
h.accumulatedCost = java.lang.Math.addExact(h.accumulatedCost, deltaCost)
}
}

Expand Down
55 changes: 55 additions & 0 deletions src/main/scala/sigmastate/eval/ExactNumeric.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package sigmastate.eval

import sigma.util.Extensions._

import scala.math.Numeric.{IntIsIntegral, ByteIsIntegral, ShortIsIntegral, LongIsIntegral}

/** Numeric operations with overflow checks.
* Raise exception when overflow is detected.
* Each instance of this typeclass overrides three methods `plus`, `minus`, `times`.
* All other methods are implemented by delegating to the corresponding Numeric instance from
* standard Scala library.
*/
trait ExactNumeric[T] extends Numeric[T] {
val n: Numeric[T]
override def negate(x: T): T = n.negate(x)
override def fromInt(x: Int): T = n.fromInt(x)
override def toInt(x: T): Int = n.toInt(x)
override def toLong(x: T): Long = n.toLong(x)
override def toFloat(x: T): Float = n.toFloat(x)
override def toDouble(x: T): Double = n.toDouble(x)
override def compare(x: T, y: T): Int = n.compare(x, y)
}

/** ExactNumeric instances for all types. */
object ExactNumeric {

object ByteIsExactNumeric extends ExactNumeric[Byte] {
val n = ByteIsIntegral
override def plus(x: Byte, y: Byte): Byte = x.addExact(y)
override def minus(x: Byte, y: Byte): Byte = x.subtractExact(y)
override def times(x: Byte, y: Byte): Byte = x.multiplyExact(y)
}

object ShortIsExactNumeric extends ExactNumeric[Short] {
val n = ShortIsIntegral
override def plus(x: Short, y: Short): Short = x.addExact(y)
override def minus(x: Short, y: Short): Short = x.subtractExact(y)
override def times(x: Short, y: Short): Short = x.multiplyExact(y)
}

object IntIsExactNumeric extends ExactNumeric[Int] {
val n = IntIsIntegral
override def plus(x: Int, y: Int): Int = Math.addExact(x, y)
override def minus(x: Int, y: Int): Int = Math.subtractExact(x, y)
override def times(x: Int, y: Int): Int = Math.multiplyExact(x, y)
}

object LongIsExactNumeric extends ExactNumeric[Long] {
val n = LongIsIntegral
override def plus(x: Long, y: Long): Long = Math.addExact(x, y)
override def minus(x: Long, y: Long): Long = Math.subtractExact(x, y)
override def times(x: Long, y: Long): Long = Math.multiplyExact(x, y)
}

}
4 changes: 3 additions & 1 deletion src/main/scala/sigmastate/eval/IRContext.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package sigmastate.eval

import java.lang.{Math => JMath}
import sigmastate.SType
import sigmastate.Values.{Value, SValue}
import sigmastate.interpreter.Interpreter.ScriptEnv
Expand Down Expand Up @@ -135,7 +136,8 @@ trait IRContext extends Evaluation with TreeBuilding {
!!!(s"Estimated cost $estimatedCost should be equal $accCost")
}

val totalCost = initCost + (estimatedCost * CostTable.costFactorIncrease / CostTable.costFactorDecrease)
val scaledCost = JMath.multiplyExact(estimatedCost.toLong, CostTable.costFactorIncrease.toLong) / CostTable.costFactorDecrease
val totalCost = JMath.addExact(initCost, scaledCost)
if (totalCost > maxCost) {
throw new CostLimitException(totalCost, msgCostLimitError(totalCost, maxCost), None)
}
Expand Down
30 changes: 19 additions & 11 deletions src/main/scala/sigmastate/eval/RuntimeCosting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import special.sigma.{GroupElementRType, AvlTreeRType, BigIntegerRType, BoxRType
import special.sigma.Extensions._
import org.ergoplatform.validation.ValidationRules._
import scalan.util.ReflectionUtil
import sigmastate.eval.ExactNumeric._

import scala.collection.mutable

Expand Down Expand Up @@ -108,7 +109,7 @@ trait RuntimeCosting extends CostingRules { IR: IRContext =>
var outputComputedResults: Boolean = false

/** Whether to perform extended checks of correctness, expected invariants and data consistency.
* Since it may add substantial overhead, tt shouldn't be used in production. */
* NOTE: Since it may add substantial overhead, set it to `false` before using in production. */
val debugModeSanityChecks: Boolean = false

// /** Pass configuration which is used by default in IRContext. */
Expand Down Expand Up @@ -675,10 +676,6 @@ trait RuntimeCosting extends CostingRules { IR: IRContext =>
mkCostedColl(col.value, col.value.length, col.cost)

case OpCost(_, id, args, cost) =>
if (debugModeSanityChecks) {
if (args.contains(cost))
!!!(s"Invalid OpCost($id, $args, $cost)")
}
val zero = IntZero
if (isCostingProcess && cost == zero && args.length == 1 && args(0).rhs.isInstanceOf[OpCost]) {
args(0) // Rule: OpCode(_,_, Seq(x @ OpCode(...)), 0) ==> x,
Expand All @@ -693,9 +690,13 @@ trait RuntimeCosting extends CostingRules { IR: IRContext =>
OpCost(lamVar, id, nonZeroArgs, cost)
}
res
} else
} else {
if (debugModeSanityChecks) {
if (args.contains(cost))
!!!(s"Invalid OpCost($id, $args, $cost)")
}
super.rewriteDef(d)

}
case _ =>
super.rewriteDef(d)
}
Expand Down Expand Up @@ -930,10 +931,10 @@ trait RuntimeCosting extends CostingRules { IR: IRContext =>

import NumericOps._
private lazy val elemToNumericMap = Map[Elem[_], Numeric[_]](
(ByteElement, numeric[Byte]),
(ShortElement, numeric[Short]),
(IntElement, numeric[Int]),
(LongElement, numeric[Long]),
(ByteElement, ByteIsExactNumeric),
(ShortElement, ShortIsExactNumeric),
(IntElement, IntIsExactNumeric),
(LongElement, LongIsExactNumeric),
(bigIntElement, numeric[SBigInt])
)
private lazy val elemToIntegralMap = Map[Elem[_], Integral[_]](
Expand All @@ -950,10 +951,17 @@ trait RuntimeCosting extends CostingRules { IR: IRContext =>
(LongElement, implicitly[Ordering[Long]]),
(bigIntElement, implicitly[Ordering[SBigInt]])
)
private lazy val elemToExactNumeric = Map[Elem[_], ExactNumeric[_]](
(ByteElement, ByteIsExactNumeric),
(ShortElement, ShortIsExactNumeric),
(IntElement, IntIsExactNumeric),
(LongElement, LongIsExactNumeric),
)

def elemToNumeric [T](e: Elem[T]): Numeric[T] = elemToNumericMap(e).asInstanceOf[Numeric[T]]
def elemToIntegral[T](e: Elem[T]): Integral[T] = elemToIntegralMap(e).asInstanceOf[Integral[T]]
def elemToOrdering[T](e: Elem[T]): Ordering[T] = elemToOrderingMap(e).asInstanceOf[Ordering[T]]
def elemToExactNumeric[T](e: Elem[T]): ExactNumeric[T] = elemToExactNumeric(e).asInstanceOf[ExactNumeric[T]]

def opcodeToEndoBinOp[T](opCode: Byte, eT: Elem[T]): EndoBinOp[T] = opCode match {
case OpCodes.PlusCode => NumericPlus(elemToNumeric(eT))(eT)
Expand Down
5 changes: 5 additions & 0 deletions src/main/scala/sigmastate/eval/TreeBuilding.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ trait TreeBuilding extends RuntimeCosting { IR: IRContext =>
import WOption._
import WECPoint._
import AvlTree._
import GroupElement._

private val ContextM = ContextMethods
private val SigmaM = SigmaPropMethods
Expand All @@ -42,6 +43,7 @@ trait TreeBuilding extends RuntimeCosting { IR: IRContext =>
private val OM = WOptionMethods
private val BIM = BigIntMethods
private val AvlM = AvlTreeMethods
private val GM = GroupElementMethods

/** Describes assignment of valIds for symbols which become ValDefs.
* Each ValDef in current scope have entry in this map */
Expand Down Expand Up @@ -396,6 +398,9 @@ trait TreeBuilding extends RuntimeCosting { IR: IRContext =>
val items = fields.map { case (n, v) => recurse(v) }
mkTuple(items)

case GM.exp(In(obj), In(arg)) =>
mkExponentiate(obj.asGroupElement, arg.asBigInt)

// Fallback MethodCall rule: should be the last in this list of cases
case Def(MethodCall(objSym, m, argSyms, _)) =>
val obj = recurse[SType](objSym)
Expand Down
9 changes: 4 additions & 5 deletions src/main/scala/sigmastate/interpreter/Interpreter.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sigmastate.interpreter

import java.util
import java.lang.{Math => JMath}

import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{strategy, rule, everywherebu}
import org.bitbucket.inkytonik.kiama.rewriting.Strategy
Expand All @@ -13,13 +14,11 @@ import sigmastate.lang.Terms.ValueOps
import sigmastate.basics._
import sigmastate.interpreter.Interpreter.{VerificationResult, ScriptEnv}
import sigmastate.lang.exceptions.{InterpreterException, CostLimitException}
import sigmastate.serialization.{ValueSerializer, ErgoTreeSerializer, SigmaSerializer}
import sigmastate.serialization.{ValueSerializer, SigmaSerializer}
import sigmastate.utxo.DeserializeContext
import sigmastate.{SType, _}
import org.ergoplatform.validation.ValidationRules._
import scalan.util.BenchmarkUtil
import sigmastate.serialization.ErgoTreeSerializer.DefaultSerializer
import sigmastate.utils.Helpers

import scala.util.Try

Expand All @@ -40,7 +39,7 @@ trait Interpreter extends ScorexLogging {
val script = ValueSerializer.deserialize(r)
val scriptComplexity = r.complexity

val currCost = context.initCost + scriptComplexity
val currCost = JMath.addExact(context.initCost, scriptComplexity)
val remainingLimit = context.costLimit - currCost
if (remainingLimit <= 0)
throw new CostLimitException(currCost, msgCostLimitError(currCost, context.costLimit), None)
Expand Down Expand Up @@ -201,7 +200,7 @@ trait Interpreter extends ScorexLogging {
message: Array[Byte]): Try[VerificationResult] = {
val (res, t) = BenchmarkUtil.measureTime(Try {

val initCost = tree.complexity + context.initCost
val initCost = JMath.addExact(tree.complexity.toLong, context.initCost)
val remainingLimit = context.costLimit - initCost
if (remainingLimit <= 0)
throw new CostLimitException(initCost, msgCostLimitError(initCost, context.costLimit), None)
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/sigmastate/serialization/DataSerializer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ object DataSerializer {
new String(bytes, StandardCharsets.UTF_8)
case SBigInt =>
val size: Short = r.getUShort().toShort
if (size > SBigInt.MaxSizeInBytes)
throw new SerializerException(s"BigInt value doesn't not fit into ${SBigInt.MaxSizeInBytes} bytes: $size")
val valueBytes = r.getBytes(size)
SigmaDsl.BigInt(new BigInteger(valueBytes))
case SGroupElement =>
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/sigmastate/types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -686,9 +686,9 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM
.withIRInfo(MethodCallIrBuilder)
.withInfo(MethodCall, "Multiply this number with \\lst{other} by module Q.", ArgInfo("other", "Number to multiply with this."))
protected override def getMethods() = super.getMethods() ++ Seq(
ModQMethod,
PlusModQMethod,
MinusModQMethod,
// ModQMethod,
// PlusModQMethod,
// MinusModQMethod,
// TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
// MultModQMethod,
)
Expand Down
Loading

0 comments on commit a0238fb

Please sign in to comment.