Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing non-method ops (typer layer) #347

Merged
merged 17 commits into from
Jan 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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