Skip to content

Commit

Permalink
Merge pull request #347 from ScorexFoundation/i324-typer-layer
Browse files Browse the repository at this point in the history
Add missing non-method ops (typer layer)
  • Loading branch information
greenhat authored Jan 17, 2019
2 parents 02c2f51 + c83ce4c commit 0c05a82
Show file tree
Hide file tree
Showing 33 changed files with 750 additions and 413 deletions.
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ credentials ++= (for {
lazy val sigma = (project in file(".")).settings(commonSettings: _*)

def runErgoTask(task: String, sigmastateVersion: String, log: Logger): Unit = {
val ergoBranch = "v2.0"
val ergoBranch = "network-prefix-in-compiler"
log.info(s"Testing current build in Ergo (branch $ergoBranch):")
val cwd = new File("").absolutePath
val ergoPath = new File(cwd + "/ergo-tests/")
Expand All @@ -140,7 +140,7 @@ def runErgoTask(task: String, sigmastateVersion: String, log: Logger): Unit = {

log.info(s"Running Ergo tests in $ergoPath with Sigmastate version $sigmastateVersion")
val res = Process(Seq("sbt", task), ergoPath, "SIGMASTATE_VERSION" -> sigmastateVersion) !

if (res != 0) sys.error(s"Ergo $task failed!")
}

Expand Down
13 changes: 10 additions & 3 deletions src/main/scala/org/ergoplatform/ErgoAddress.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package org.ergoplatform
import java.util

import com.google.common.primitives.Ints
import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
import sigmastate.basics.DLogProtocol.ProveDlog
import scorex.crypto.hash.{Blake2b256, Digest32}
import scorex.util.encode.Base58
import sigmastate.Values.{ConcreteCollection, ConstantNode, IntConstant, Value, GetVarByteArray}
import sigmastate.Values.{ConcreteCollection, ConstantNode, GetVarByteArray, IntConstant, Value}
import sigmastate._
import sigmastate.serialization.{ErgoTreeSerializer, ValueSerializer}
import sigmastate.utxo.{DeserializeContext, Slice}
Expand Down Expand Up @@ -162,7 +163,7 @@ object Pay2SAddress {
}


case class ErgoAddressEncoder(networkPrefix: Byte) {
case class ErgoAddressEncoder(networkPrefix: NetworkPrefix) {

import ErgoAddressEncoder._

Expand All @@ -177,10 +178,16 @@ case class ErgoAddressEncoder(networkPrefix: Byte) {
Base58.encode(withNetworkByte ++ checksum)
}

def isTestnetAddress(addrHeadByte: Byte): Boolean = addrHeadByte > TestnetNetworkPrefix
def isMainnetAddress(addrHeadByte: Byte): Boolean = addrHeadByte < TestnetNetworkPrefix

def fromString(addrStr: String): Try[ErgoAddress] = Base58.decode(addrStr).flatMap { bytes =>
Try {
val headByte = bytes.head
require(headByte >= networkPrefix)
networkPrefix match {
case TestnetNetworkPrefix => require(isTestnetAddress(headByte), "Trying to decode mainnet address in testnet")
case MainnetNetworkPrefix => require(isMainnetAddress(headByte), "Trying to decode testnet address in mainnet")
}
val addressType = (headByte - networkPrefix).toByte
val (withoutChecksum, checksum) = bytes.splitAt(bytes.length - ChecksumLength)

Expand Down
9 changes: 0 additions & 9 deletions src/main/scala/org/ergoplatform/ErgoLikeContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package org.ergoplatform

import org.ergoplatform.ErgoBox.ReferenceRegId
import org.ergoplatform.ErgoLikeContext.Height
import org.ergoplatform.ErgoLikeContext.Metadata.NetworkPrefix
import sigmastate.Values._
import sigmastate._
import sigmastate.eval.{CostingAvlTree, CostingDataContext, Evaluation, CostingBox}
Expand Down Expand Up @@ -55,14 +54,6 @@ object ErgoLikeContext {

val dummyPubkey: Array[Byte] = Array.fill(32)(0: Byte)

case class Metadata(networkPrefix: NetworkPrefix)

object Metadata {
type NetworkPrefix = Byte
val MainnetNetworkPrefix: NetworkPrefix = 0.toByte
val TestnetNetworkPrefix: NetworkPrefix = 16.toByte
}

def apply(currentHeight: Height,
lastBlockUtxoRoot: AvlTreeData,
minerPubkey: Array[Byte],
Expand Down
13 changes: 7 additions & 6 deletions src/main/scala/org/ergoplatform/ErgoScriptPredef.scala
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package org.ergoplatform

import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
import sigmastate.SCollection.SByteArray
import sigmastate.Values.{LongConstant, FuncValue, Value, ByteArrayConstant, IntConstant, ErgoTree, ValUse, ConcreteCollection}
import sigmastate.Values.{ByteArrayConstant, ConcreteCollection, ErgoTree, FuncValue, IntConstant, LongConstant, ValUse, Value}
import sigmastate.basics.DLogProtocol.ProveDlog
import sigmastate.eval.IRContext
import sigmastate.interpreter.Interpreter.ScriptEnv
import sigmastate.lang.{TransformingSigmaBuilder, SigmaCompiler}
import sigmastate.lang.{SigmaCompiler, TransformingSigmaBuilder}
import sigmastate.lang.Terms.ValueOps
import sigmastate.utxo.{ExtractRegisterAs, _}
import sigmastate.{SLong, _}

object ErgoScriptPredef {
import sigmastate.interpreter.Interpreter._
val compiler = new SigmaCompiler(TransformingSigmaBuilder)

def compileWithCosting(env: ScriptEnv, code: String)(implicit IR: IRContext): Value[SType] = {
def compileWithCosting(env: ScriptEnv, code: String, networkPrefix: NetworkPrefix)(implicit IR: IRContext): Value[SType] = {
val compiler = new SigmaCompiler(networkPrefix, TransformingSigmaBuilder)
val interProp = compiler.typecheck(env, code)
val IR.Pair(calcF, _) = IR.doCosting(env, interProp)
IR.buildTree(calcF)
Expand Down Expand Up @@ -50,7 +51,7 @@ object ErgoScriptPredef {
* (v2) INPUTS.flatMap(box => box.tokens).filter(t => t._1 == tokenId).sum >= thresholdAmount
* (v3) INPUTS.map(box => box.tokens.find(t => t._1 == tokenId).map(t => t._2).getOrElse(0)).sum >= thresholdAmount
*/
def tokenThresholdScript(tokenId: Array[Byte], thresholdAmount: Long)(implicit IR: IRContext): Value[SBoolean.type] = {
def tokenThresholdScript(tokenId: Array[Byte], thresholdAmount: Long, networkPrefix: NetworkPrefix)(implicit IR: IRContext): Value[SBoolean.type] = {
val env = emptyEnv + ("tokenId" -> tokenId, "thresholdAmount" -> thresholdAmount)
val res = compileWithCosting(env,
"""{
Expand All @@ -66,7 +67,7 @@ object ErgoScriptPredef {
| val total = sumValues(tokenAmounts)
| total >= thresholdAmount
|}
""".stripMargin )
""".stripMargin, networkPrefix)
res.asBoolValue
}

Expand Down
47 changes: 0 additions & 47 deletions src/main/scala/sigmastate/eval/CompiletimeCosting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,53 +29,6 @@ trait CompiletimeCosting extends RuntimeCosting { IR: Evaluation =>
case _: DLogProtocol.ProveDlog | _: ProveDHTuple =>
eval(SigmaPropConstant(node.asSigmaBoolean))

// Rule: allOf(arr) --> AND(arr)
case Terms.Apply(AllSym, Seq(arr: Value[SCollection[SBoolean.type]]@unchecked)) =>
eval(mkAND(arr))

// Rule: anyOf(arr) --> OR(arr)
case Terms.Apply(AnySym, Seq(arr: Value[SCollection[SBoolean.type]]@unchecked)) =>
eval(mkOR(arr))

// Rule: atLeast(bound, arr) --> AtLeast(bound, arr)
case Terms.Apply(AtLeastSym, Seq(bound: SValue, arr: Value[SCollection[SSigmaProp.type]]@unchecked)) =>
eval(mkAtLeast(bound.asIntValue, arr))

case Terms.Apply(Blake2b256Sym, Seq(arg: Value[SByteArray]@unchecked)) =>
eval(mkCalcBlake2b256(arg))

case Terms.Apply(Sha256Sym, Seq(arg: Value[SByteArray]@unchecked)) =>
eval(mkCalcSha256(arg))

case Terms.Apply(IsMemberSym, Seq(tree: Value[SAvlTree.type]@unchecked, key: Value[SByteArray]@unchecked, proof: Value[SByteArray]@unchecked)) =>
eval(mkIsMember(tree, key, proof))

case Terms.Apply(ProveDlogSym, Seq(g: Value[SGroupElement.type]@unchecked)) =>
eval(mkProveDlog(g))

case Terms.Apply(LongToByteArraySym, Seq(arg: Value[SLong.type]@unchecked)) =>
eval(mkLongToByteArray(arg))

case Terms.Apply(ByteArrayToBigIntSym, Seq(arr: Value[SByteArray]@unchecked)) =>
eval(mkByteArrayToBigInt(arr))

case Terms.Apply(SigmaPropSym, Seq(bool: Value[SBoolean.type]@unchecked)) =>
eval(mkBoolToSigmaProp(bool))

case Terms.Apply(ProveDHTupleSym, Seq(g, h, u, v)) =>
eval(SigmaPropConstant(
mkProveDiffieHellmanTuple(
g.asGroupElement,
h.asGroupElement,
u.asGroupElement,
v.asGroupElement)))

case Terms.Apply(TreeModificationsSym, Seq(tree: Value[SAvlTree.type]@unchecked, operations: Value[SByteArray]@unchecked, proof: Value[SByteArray]@unchecked)) =>
eval(mkTreeModifications(tree, operations, proof))

case Terms.Apply(TreeLookupSym, Seq(tree: Value[SAvlTree.type]@unchecked, key: Value[SByteArray]@unchecked, proof: Value[SByteArray]@unchecked)) =>
eval(mkTreeLookup(tree, key, proof))

case sigmastate.Upcast(Constant(value, _), toTpe: SNumericType) =>
eval(mkConstant(toTpe.upcast(value.asInstanceOf[AnyVal]), toTpe))

Expand Down
8 changes: 1 addition & 7 deletions src/main/scala/sigmastate/eval/RuntimeCosting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import scalan.compilation.GraphVizConfig
import SType._
import scorex.crypto.hash.{Blake2b256, Sha256}
import sigmastate.interpreter.Interpreter.ScriptEnv
import sigmastate.lang.{SigmaCompiler, Terms}
import sigmastate.lang.Terms
import scalan.staged.Slicing
import sigmastate.basics.{DLogProtocol, ProveDHTuple}

Expand Down Expand Up @@ -558,7 +558,6 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
/** Should be specified in the final cake */
val builder: sigmastate.lang.SigmaBuilder
import builder._
lazy val compiler = new SigmaCompiler(builder)

var _colBuilder: Rep[ColBuilder] = _
var _costedBuilder: Rep[CostedBuilder] = _
Expand Down Expand Up @@ -1490,11 +1489,6 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
}
}

def cost(env: ScriptEnv, code: String): Rep[Context => Costed[SType#WrappedType]] = {
val typed = compiler.typecheck(env, code)
cost(env, typed)
}

def cost(env: ScriptEnv, typed: SValue): Rep[Context => Costed[SType#WrappedType]] = {
val cg = buildCostedGraph[SType](env.map { case (k, v) => (k: Any, builder.liftAny(v).get) }, typed)
cg
Expand Down
4 changes: 4 additions & 0 deletions src/main/scala/sigmastate/eval/TreeBuilding.scala
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
mkBoolToSigmaProp(cond.asBoolValue)
case SDBM.byteArrayToBigInt(_, colSym) =>
mkByteArrayToBigInt(recurse(colSym))
case SDBM.sha256(_, colSym) =>
mkCalcSha256(recurse(colSym))
case SDBM.blake2b256(_, colSym) =>
mkCalcBlake2b256(recurse(colSym))
case SDBM.treeModifications(_, treeSym, opsColSym, proofColSym) =>
Expand All @@ -312,6 +314,8 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
mkTreeLookup(recurse(treeSym), recurse(keySym), recurse(proofColSym))
case SDBM.longToByteArray(_, longSym) =>
mkLongToByteArray(recurse(longSym))
case SDBM.decodePoint(_, colSym) =>
mkDecodePoint(recurse(colSym))

case Def(IfThenElseLazy(condSym, thenPSym, elsePSym)) =>
val Seq(cond, thenP, elseP) = Seq(condSym, thenPSym, elsePSym).map(recurse)
Expand Down
68 changes: 27 additions & 41 deletions src/main/scala/sigmastate/lang/SigmaBinder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,43 @@ import org.bitbucket.inkytonik.kiama.rewriting.Rewriter._
import sigmastate.lang.Terms._
import sigmastate._
import Values._
import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
import org.ergoplatform._
import scorex.util.encode.Base58
import sigmastate.interpreter.Interpreter.ScriptEnv
import sigmastate.lang.exceptions.{BinderException, InvalidTypeArguments, InvalidArguments}
import sigmastate.lang.SigmaPredef.PredefinedFuncRegistry
import sigmastate.lang.exceptions.{BinderException, InvalidArguments, InvalidTypeArguments}
import sigmastate.serialization.ValueSerializer

class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder) {
/**
* @param env
* @param builder
* @param networkPrefix network prefix to decode an ergo address from string (PK op)
*/
class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder,
networkPrefix: NetworkPrefix,
predefFuncRegistry: PredefinedFuncRegistry) {
import SigmaBinder._
import SigmaPredef._
import builder._

private val PKFunc = predefFuncRegistry.PKFunc(networkPrefix)

/** Rewriting of AST with respect to environment to resolve all references to global names
* and infer their types. */
private def eval(e: SValue, env: ScriptEnv): SValue = rewrite(reduce(strategy[SValue]({
case Ident(n, NoType) => env.get(n) match {
case Some(v) => Option(liftAny(v).get)
case None => predefinedEnv.get(n) match {
case Some(v) => Some(Ident(n, v.tpe))
case None => n match {
case "HEIGHT" => Some(Height)
case "MinerPubkey" => Some(MinerPubkey)
case "INPUTS" => Some(Inputs)
case "OUTPUTS" => Some(Outputs)
case "LastBlockUtxoRootHash" => Some(LastBlockUtxoRootHash)
case "EmptyByteArray" => Some(ByteArrayConstant(Array.emptyByteArray))
case "SELF" => Some(Self)
case "None" => Some(mkNoneValue(NoType))
case _ => None
}
case None => n match {
case "HEIGHT" => Some(Height)
case "MinerPubkey" => Some(MinerPubkey)
case "INPUTS" => Some(Inputs)
case "OUTPUTS" => Some(Outputs)
case "LastBlockUtxoRootHash" => Some(LastBlockUtxoRootHash)
case "EmptyByteArray" => Some(ByteArrayConstant(Array.emptyByteArray))
case "SELF" => Some(Self)
case "None" => Some(mkNoneValue(NoType))
case _ => None
}
}

Expand Down Expand Up @@ -78,19 +86,6 @@ class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder) {
throw new InvalidArguments(s"Invalid arguments for max: $args")
}

// Rule getVar[T](id) --> GetVar(id)
case e @ Apply(ApplyTypes(GetVarSym, targs), args) =>
if (targs.length != 1 || args.length != 1)
error(s"Wrong number of arguments in $e: expected one type argument and one variable id")
val id = args.head match {
case LongConstant(i) => SByte.downcast(i)
case IntConstant(i) => SByte.downcast(i)
case ShortConstant(i) => SByte.downcast(i)
case ByteConstant(i) => i
case v => error(s"invalid type for var id, expected numeric, got $v")
}
Some(mkGetVar(id, targs.head))

// Rule: lambda (...) = ... --> lambda (...): T = ...
case lam @ Lambda(params, args, t, Some(body)) =>
require(params.isEmpty)
Expand All @@ -113,19 +108,10 @@ class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder) {
Some(newBlock)
else
None
case e @ Apply(ApplyTypes(DeserializeSym, targs), args) =>
if (targs.length != 1)
throw new InvalidTypeArguments(s"Wrong number of type arguments in $e: expected one type argument")
if (args.length != 1)
throw new InvalidArguments(s"Wrong number of arguments in $e: expected one argument")
val str = args.head match {
case StringConstant(s) => s
case _ =>
throw new InvalidArguments(s"invalid argument in $e: expected a string constant")
}
val bytes = Base58.decode(str).get
Some(
ValueSerializer.deserialize(bytes))

case Apply(PKFunc.symNoType, args) =>
Some(PKFunc.irBuilder(PKFunc.sym, args))

})))(e)

def bind(e: SValue): SValue =
Expand Down
15 changes: 9 additions & 6 deletions src/main/scala/sigmastate/lang/SigmaBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.math.BigInteger
import org.ergoplatform.ErgoBox
import org.ergoplatform.ErgoBox.RegisterId
import sigmastate.SCollection.SByteArray
import sigmastate.Values.{BigIntValue, BlockItem, BlockValue, BoolValue, ConcreteCollection, Constant, ConstantNode, ConstantPlaceholder, FalseLeaf, FuncValue, GroupElementValue, NoneValue, SValue, SigmaBoolean, SigmaPropValue, SomeValue, TaggedVariable, TaggedVariableNode, TrueLeaf, Tuple, ValUse, Value}
import sigmastate.Values.{BigIntValue, BlockItem, BlockValue, BoolValue, ConcreteCollection, Constant, ConstantNode, ConstantPlaceholder, FalseLeaf, FuncValue, GroupElementValue, NoneValue, SValue, SigmaBoolean, SigmaPropValue, SomeValue, StringConstant, TaggedVariable, TaggedVariableNode, TrueLeaf, Tuple, ValUse, Value}
import sigmastate._
import sigmastate.interpreter.CryptoConstants
import sigmastate.lang.Constraints.{TypeConstraint2, onlyNumeric2, sameType2}
Expand Down Expand Up @@ -179,7 +179,7 @@ trait SigmaBuilder {
def mkConstantPlaceholder[T <: SType](id: Int, tpe: T): Value[SType]
def mkCollectionConstant[T <: SType](values: Array[T#WrappedType],
elementType: T): Constant[SCollection[T]]
def mkStringConcat(left: Value[SString.type], right: Value[SString.type]): Value[SString.type]
def mkStringConcat(left: Constant[SString.type], right: Constant[SString.type]): Value[SString.type]

def mkGetVar[T <: SType](varId: Byte, tpe: T): Value[SOption[T]]
def mkOptionGet[T <: SType](input: Value[SOption[T]]): Value[T]
Expand All @@ -197,8 +197,9 @@ trait SigmaBuilder {
def mkBitOr[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
def mkBitAnd[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
def mkBitXor[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
def mkBitShiftRight[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
def mkBitShiftLeft[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
def mkBitShiftRight[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T]
def mkBitShiftLeft[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T]
def mkBitShiftRightZeroed[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T]

def liftAny(v: Any): Nullable[SValue] = v match {
case arr: Array[Boolean] => Nullable(mkCollectionConstant[SBoolean.type](arr, SBoolean))
Expand Down Expand Up @@ -520,8 +521,8 @@ class StdSigmaBuilder extends SigmaBuilder {
elementType: T): Constant[SCollection[T]] =
ConstantNode[SCollection[T]](values, SCollection(elementType))

override def mkStringConcat(left: Value[SString.type], right: Value[SString.type]): Value[SString.type] =
StringConcat(left, right)
override def mkStringConcat(left: Constant[SString.type], right: Constant[SString.type]): Value[SString.type] =
StringConstant(left.value + right.value)

override def mkGetVar[T <: SType](varId: Byte, tpe: T): Value[SOption[T]] =
GetVar(varId, tpe)
Expand Down Expand Up @@ -568,6 +569,8 @@ class StdSigmaBuilder extends SigmaBuilder {
override def mkBitShiftLeft[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T] =
BitOp(bits, shift, OpCodes.BitShiftLeftCode)

override def mkBitShiftRightZeroed[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T] =
BitOp(bits, shift, OpCodes.BitShiftRightZeroedCode)
}

trait TypeConstraintCheck {
Expand Down
Loading

0 comments on commit 0c05a82

Please sign in to comment.