Skip to content

Commit

Permalink
Merge branch 'v6.0.0' of github.com:ScorexFoundation/sigmastate-inter…
Browse files Browse the repository at this point in the history
…preter into i904
  • Loading branch information
kushti committed Oct 29, 2024
2 parents ac11237 + b074b28 commit e9e59e0
Show file tree
Hide file tree
Showing 28 changed files with 823 additions and 178 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
*.fdb_latexmk
*.gz


yarn.lock
*.log
yarn.lock
Expand Down
11 changes: 11 additions & 0 deletions core/shared/src/main/scala/sigma/SigmaDsl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,17 @@ trait Context {
*/
def getVar[T](id: Byte)(implicit cT: RType[T]): Option[T]

/**
* A variant of `getVar` to extract a context variable by id and type from any input
*
* @param inputIndex - input index
* @param id - context variable id
* @tparam T - expected type of the variable
* @return Some(value) if the variable is defined in the context AND has the given type.
* None otherwise
*/
def getVarFromInput[T](inputIndex: Short, id: Byte)(implicit cT: RType[T]): Option[T]

def vars: Coll[AnyValue]

/** Maximum version of ErgoTree currently activated on the network.
Expand Down
93 changes: 72 additions & 21 deletions core/shared/src/main/scala/sigma/data/CollsOverArrays.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package sigma.data

import debox.{Buffer, cfor}
import sigma.Evaluation.stypeToRType
import sigma.data.CollOverArray.equalsPairCollWithCollOverArray
import sigma.data.RType._
import sigma.util.{CollectionUtil, MaxArrayLength, safeConcatArrays_v5}
import sigma.{Coll, CollBuilder, PairColl, VersionContext, requireSameLength}
Expand All @@ -12,7 +14,9 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil
s"Cannot create collection with size ${toArray.length} greater than $MaxArrayLength")

override def tItem: RType[A] = tA

@inline def length: Int = toArray.length

@inline def apply(i: Int): A = toArray.apply(i)

override def isEmpty: Boolean = length == 0
Expand All @@ -29,8 +33,11 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil
}

def foreach(f: A => Unit): Unit = toArray.foreach(f)

def exists(p: A => Boolean): Boolean = toArray.exists(p)

def forall(p: A => Boolean): Boolean = toArray.forall(p)

def filter(p: A => Boolean): Coll[A] = builder.fromArray(toArray.filter(p))

def foldLeft[B](zero: B, op: ((B, A)) => B): B = toArray.foldLeft(zero)((b, a) => op((b, a)))
Expand Down Expand Up @@ -117,12 +124,14 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil
override def unionSet(that: Coll[A]): Coll[A] = {
val set = debox.Set.ofSize[A](this.length)
val res = Buffer.ofSize[A](this.length)

@inline def addItemToSet(x: A) = {
if (!set(x)) {
set.add(x)
res += x
}
}

def addToSet(arr: Array[A]) = {
val limit = arr.length
cfor(0)(_ < limit, _ + 1) { i =>
Expand All @@ -139,14 +148,42 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil

override def equals(obj: scala.Any): Boolean = (this eq obj.asInstanceOf[AnyRef]) || (obj match {
case obj: CollOverArray[_] if obj.tItem == this.tItem =>
java.util.Objects.deepEquals(obj.toArray, toArray)
java.util.Objects.deepEquals(obj.toArray, this.toArray)
case obj: PairColl[Any, Any] if obj.tItem == this.tItem =>
if (VersionContext.current.isV6SoftForkActivated) {
equalsPairCollWithCollOverArray(obj, this.asInstanceOf[CollOverArray[Any]])
} else {
false
}
case _ => false
})

override def hashCode() = CollectionUtil.deepHashCode(toArray)
override def hashCode(): Int = CollectionUtil.deepHashCode(toArray)
}

object CollOverArray {

// comparing PairColl and CollOverArray instances
private[data] def equalsPairCollWithCollOverArray(pc: PairColl[Any, Any], coa: CollOverArray[Any]): Boolean = {
val ls = pc.ls
val rs = pc.rs
val ts = coa.toArray
if (ts.length == ls.length && ts.isInstanceOf[Array[(Any, Any)]]) {
val ta = ts.asInstanceOf[Array[(Any, Any)]]
var eq = true
cfor(0)(_ < ta.length && eq, _ + 1) { i =>
eq = java.util.Objects.deepEquals(ta(i)._1, ls(i)) && java.util.Objects.deepEquals(ta(i)._2, rs(i))
}
eq
} else {
false
}
}

}

private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
private[sigma] class CollOverArrayBuilder extends CollBuilder {
builder =>

@inline override def pairColl[@specialized A, @specialized B](as: Coll[A], bs: Coll[B]): PairColl[A, B] = {
if (VersionContext.current.isJitActivated) {
Expand All @@ -170,20 +207,20 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
}
}

private def fromBoxedPairs[A, B](seq: Seq[(A, B)])(implicit tA: RType[A], tB: RType[B]): PairColl[A,B] = {
private def fromBoxedPairs[A, B](seq: Seq[(A, B)])(implicit tA: RType[A], tB: RType[B]): PairColl[A, B] = {
val len = seq.length
val resA = Array.ofDim[A](len)(tA.classTag)
val resB = Array.ofDim[B](len)(tB.classTag)
cfor(0)(_ < len, _ + 1) { i =>
val item = seq.apply(i).asInstanceOf[(A,B)]
val item = seq.apply(i).asInstanceOf[(A, B)]
resA(i) = item._1
resB(i) = item._2
}
pairCollFromArrays(resA, resB)(tA, tB)
}

override def fromItems[T](items: T*)(implicit cT: RType[T]): Coll[T] = cT match {
case pt: PairType[a,b] =>
case pt: PairType[a, b] =>
val tA = pt.tFst
val tB = pt.tSnd
fromBoxedPairs(items)(tA, tB)
Expand All @@ -192,16 +229,16 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
}

override def fromArray[@specialized T: RType](arr: Array[T]): Coll[T] = RType[T] match {
case pt: PairType[a,b] =>
case pt: PairType[a, b] =>
val tA = pt.tFst
val tB = pt.tSnd
fromBoxedPairs[a,b](arr.asInstanceOf[Array[(a,b)]])(tA, tB)
fromBoxedPairs[a, b](arr.asInstanceOf[Array[(a, b)]])(tA, tB)
case _ =>
new CollOverArray(arr, builder)
}

override def replicate[@specialized T: RType](n: Int, v: T): Coll[T] = RType[T] match {
case pt: PairType[a,b] =>
case pt: PairType[a, b] =>
val tA = pt.tFst
val tB = pt.tSnd
val tuple = v.asInstanceOf[(a, b)]
Expand All @@ -210,8 +247,8 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
fromArray(Array.fill(n)(v))
}

override def unzip[@specialized A, @specialized B](xs: Coll[(A,B)]): (Coll[A], Coll[B]) = xs match {
case pa: PairColl[_,_] => (pa.ls, pa.rs)
override def unzip[@specialized A, @specialized B](xs: Coll[(A, B)]): (Coll[A], Coll[B]) = xs match {
case pa: PairColl[_, _] => (pa.ls, pa.rs)
case _ =>
val limit = xs.length
implicit val tA = xs.tItem.tFst
Expand All @@ -230,7 +267,7 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
left.zip(right).map { case (l, r) => (l ^ r).toByte }

override def emptyColl[T](implicit cT: RType[T]): Coll[T] = cT match {
case pt: PairType[a,b] =>
case pt: PairType[a, b] =>
val ls = emptyColl(pt.tFst)
val rs = emptyColl(pt.tSnd)
pairColl(ls, rs).asInstanceOf[Coll[T]]
Expand All @@ -239,24 +276,36 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder =>
}
}

class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R]) extends PairColl[L,R] {
class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R]) extends PairColl[L, R] {

override def equals(that: scala.Any) = (this eq that.asInstanceOf[AnyRef]) || (that match {
case that: PairColl[_,_] if that.tItem == this.tItem => ls == that.ls && rs == that.rs
override def equals(that: scala.Any): Boolean = (this eq that.asInstanceOf[AnyRef]) || (that match {
case that: PairColl[_, _] if that.tItem == this.tItem =>
ls == that.ls && rs == that.rs
case that: CollOverArray[Any] if that.tItem == this.tItem =>
if (VersionContext.current.isV6SoftForkActivated) {
equalsPairCollWithCollOverArray(this.asInstanceOf[PairColl[Any, Any]], that)
} else {
false
}
case _ => false
})

override def hashCode() = ls.hashCode() * 41 + rs.hashCode()

@inline implicit def tL: RType[L] = ls.tItem

@inline implicit def tR: RType[R] = rs.tItem

override lazy val tItem: RType[(L, R)] = {
RType.pairRType(tL, tR)
}

override def builder: CollBuilder = ls.builder

override def toArray: Array[(L, R)] = ls.toArray.zip(rs.toArray)

@inline override def length: Int = if (ls.length <= rs.length) ls.length else rs.length

@inline override def apply(i: Int): (L, R) = (ls(i), rs(i))

override def isEmpty: Boolean = length == 0
Expand Down Expand Up @@ -304,7 +353,7 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R
true
}

override def filter(p: ((L, R)) => Boolean): Coll[(L,R)] = {
override def filter(p: ((L, R)) => Boolean): Coll[(L, R)] = {
val len = ls.length
val resL: Buffer[L] = Buffer.empty[L](ls.tItem.classTag)
val resR: Buffer[R] = Buffer.empty[R](rs.tItem.classTag)
Expand Down Expand Up @@ -333,9 +382,9 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R
state
}

override def slice(from: Int, until: Int): PairColl[L,R] = builder.pairColl(ls.slice(from, until), rs.slice(from, until))
override def slice(from: Int, until: Int): PairColl[L, R] = builder.pairColl(ls.slice(from, until), rs.slice(from, until))

def append(other: Coll[(L, R)]): Coll[(L,R)] = {
def append(other: Coll[(L, R)]): Coll[(L, R)] = {
val arrs = builder.unzip(other)
builder.pairColl(ls.append(arrs._1), rs.append(arrs._2))
}
Expand All @@ -352,7 +401,7 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R
}
}

def zip[@specialized B](ys: Coll[B]): PairColl[(L,R), B] = builder.pairColl(this, ys)
def zip[@specialized B](ys: Coll[B]): PairColl[(L, R), B] = builder.pairColl(this, ys)

def startsWith(ys: Coll[(L, R)]): Boolean = ys match {
case yp: PairOfCols[L, R] => ls.startsWith(yp.ls) && rs.startsWith(yp.rs)
Expand Down Expand Up @@ -408,18 +457,20 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R
}

override def unionSet(that: Coll[(L, R)]): Coll[(L, R)] = {
val set = new java.util.HashSet[(L,R)](32)
val set = new java.util.HashSet[(L, R)](32)
implicit val ctL = ls.tItem.classTag
implicit val ctR = rs.tItem.classTag
val resL = Buffer.empty[L]
val resR = Buffer.empty[R]
def addToSet(item: (L,R)) = {

def addToSet(item: (L, R)) = {
if (!set.contains(item)) {
set.add(item)
resL += item._1
resR += item._2
}
}

var i = 0
val thisLen = math.min(ls.length, rs.length)
while (i < thisLen) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ object ReflectionData {
mkMethod(clazz, "getVar", Array[Class[_]](classOf[Byte], classOf[RType[_]])) { (obj, args) =>
obj.asInstanceOf[Context].getVar(args(0).asInstanceOf[Byte])(args(1).asInstanceOf[RType[_]])
},
mkMethod(clazz, "getVarFromInput", Array[Class[_]](classOf[Short], classOf[Byte], classOf[RType[_]])) { (obj, args) =>
obj.asInstanceOf[Context].getVarFromInput(args(0).asInstanceOf[Short], args(1).asInstanceOf[Byte])(args(2).asInstanceOf[RType[_]])
},
mkMethod(clazz, "headers", Array[Class[_]]()) { (obj, _) =>
obj.asInstanceOf[Context].headers
}
Expand Down
12 changes: 12 additions & 0 deletions data/shared/src/main/scala/sigma/ast/SMethod.scala
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,18 @@ object SMethod {
(implicit cT: ClassTag[T], cA1: ClassTag[A1], cA2: ClassTag[A2]): RMethod =
RClass(cT.runtimeClass).getMethod(methodName, cA1.runtimeClass, cA2.runtimeClass)

/** Return [[Method]] descriptor for the given `methodName` on the given `cT` type.
* @param methodName the name of the method to lookup
* @param cT the class where to search the methodName
* @param cA1 the class of the method's first argument
* @param cA2 the class of the method's second argument
* @param cA3 the class of the method's third argument
*/
def javaMethodOf[T, A1, A2, A3]
(methodName: String)
(implicit cT: ClassTag[T], cA1: ClassTag[A1], cA2: ClassTag[A2], cA3: ClassTag[A3]): RMethod =
RClass(cT.runtimeClass).getMethod(methodName, cA1.runtimeClass, cA2.runtimeClass, cA3.runtimeClass)

/** Default fallback method call recognizer which builds MethodCall ErgoTree nodes. */
val MethodCallIrBuilder: PartialFunction[(SigmaBuilder, SValue, SMethod, Seq[SValue], STypeSubst), SValue] = {
case (builder, obj, method, args, tparamSubst) =>
Expand Down
13 changes: 13 additions & 0 deletions data/shared/src/main/scala/sigma/ast/SigmaPredef.scala
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,18 @@ object SigmaPredef {
Seq(ArgInfo("varId", "\\lst{Byte} identifier of context variable")))
)

val GetVarFromInputFunc = PredefinedFunc("getVarFromInput",
Lambda(Array(paramT), Array("inputId" -> SShort, "varId" -> SByte), SOption(tT), None),
PredefFuncInfo(
{ case (Ident(_, SFunc(_, SOption(rtpe), _)), Seq(inputId: Constant[SNumericType]@unchecked, varId: Constant[SNumericType]@unchecked)) =>
mkMethodCall(Context, SContextMethods.getVarFromInputMethod, IndexedSeq(SShort.downcast(inputId.value.asInstanceOf[AnyVal]), SByte.downcast(varId.value.asInstanceOf[AnyVal])), Map(tT -> rtpe))
}),
OperationInfo(MethodCall,
"Get context variable with given \\lst{varId} and type.",
Seq(ArgInfo("inputId", "\\lst{Byte} index of input to read context variable from"),
ArgInfo("varId", "\\lst{Byte} identifier of context variable")))
)

def PKFunc(networkPrefix: NetworkPrefix) = PredefinedFunc("PK",
Lambda(Array("input" -> SString), SSigmaProp, None),
PredefFuncInfo(
Expand Down Expand Up @@ -468,6 +480,7 @@ object SigmaPredef {
ExecuteFromVarFunc,
ExecuteFromSelfRegFunc,
SerializeFunc,
GetVarFromInputFunc,
FromBigEndianBytesFunc
).map(f => f.name -> f).toMap

Expand Down
42 changes: 39 additions & 3 deletions data/shared/src/main/scala/sigma/ast/methods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1681,16 +1681,52 @@ case object SContextMethods extends MonoTypeMethods {
lazy val selfBoxIndexMethod = propertyCall("selfBoxIndex", SInt, 8, FixedCost(JitCost(20)))
lazy val lastBlockUtxoRootHashMethod = property("LastBlockUtxoRootHash", SAvlTree, 9, LastBlockUtxoRootHash)
lazy val minerPubKeyMethod = property("minerPubKey", SByteArray, 10, MinerPubkey)
lazy val getVarMethod = SMethod(

lazy val getVarV5Method = SMethod(
this, "getVar", SFunc(ContextFuncDom, SOption(tT), Array(paramT)), 11, GetVar.costKind)
.withInfo(GetVar, "Get context variable with given \\lst{varId} and type.",
ArgInfo("varId", "\\lst{Byte} identifier of context variable"))

protected override def getMethods() = super.getMethods() ++ Seq(
lazy val getVarV6Method = SMethod(
this, "getVar", SFunc(ContextFuncDom, SOption(tT), Array(paramT)), 11, GetVar.costKind, Seq(tT))
.withIRInfo(
MethodCallIrBuilder,
javaMethodOf[Context, Byte, RType[_]]("getVar"),
{ mtype => Array(mtype.tRange.asOption[SType].elemType) })
.withInfo(MethodCall, "Get context variable with given \\lst{varId} and type.")

lazy val getVarFromInputMethod = SMethod(
this, "getVarFromInput", SFunc(Array(SContext, SShort, SByte), SOption(tT), Array(paramT)), 12, GetVar.costKind, Seq(tT))
.withIRInfo(
MethodCallIrBuilder,
javaMethodOf[Context, Short, Byte, RType[_]]("getVarFromInput"),
{ mtype => Array(mtype.tRange.asOption[SType].elemType) })
.withInfo(MethodCall, "Get context variable with given \\lst{varId} and type.",
ArgInfo("inputIdx", "Index of input to read variable from."),
ArgInfo("varId", "Index of variable.")
)

private lazy val commonMethods = super.getMethods() ++ Array(
dataInputsMethod, headersMethod, preHeaderMethod, inputsMethod, outputsMethod, heightMethod, selfMethod,
selfBoxIndexMethod, lastBlockUtxoRootHashMethod, minerPubKeyMethod, getVarMethod
selfBoxIndexMethod, lastBlockUtxoRootHashMethod, minerPubKeyMethod
)

private lazy val v5Methods = commonMethods ++ Seq(
getVarV5Method
)

private lazy val v6Methods = commonMethods ++ Seq(
getVarV6Method, getVarFromInputMethod
)

protected override def getMethods(): Seq[SMethod] = {
if (VersionContext.current.isV6SoftForkActivated) {
v6Methods
} else {
v5Methods
}
}

/** Names of methods which provide blockchain context.
* This value can be reused where necessary to avoid allocations. */
val BlockchainContextMethodNames: IndexedSeq[String] = Array(
Expand Down
Loading

0 comments on commit e9e59e0

Please sign in to comment.