All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sigmastate.eval.CContext.scala Maven / Gradle / Ivy

The newest version!
package sigmastate.eval

import debox.cfor
import sigma.Extensions.ArrayOps
import sigma._
import sigma.data._
import sigma.exceptions.InvalidType

import scala.annotation.unused
import scala.reflect.ClassTag

/** A default implementation of [[Context]] interface.
  * @see [[Context]] for detailed descriptions
  */
case class CContext(
    _dataInputs: Coll[Box],
    override val headers: Coll[Header],
    override val preHeader: PreHeader,
    inputs: Coll[Box],
    outputs: Coll[Box],
    height: Int,
    selfBox: Box,
    private val selfIndex: Int,
    lastBlockUtxoRootHash: AvlTree,
    _minerPubKey: Coll[Byte],
    vars: Coll[AnyValue],
    override val activatedScriptVersion: Byte,
    override val currentErgoTreeVersion: Byte
) extends Context {
  @inline override def builder: SigmaDslBuilder = CSigmaDslBuilder

  @inline override def HEIGHT: Int = height

  @inline override def SELF: Box = selfBox

  @inline override def dataInputs: Coll[Box] = _dataInputs

  @inline override def INPUTS = inputs

  @inline override def OUTPUTS = outputs

  @inline override def LastBlockUtxoRootHash = lastBlockUtxoRootHash

  @inline override def minerPubKey = _minerPubKey

  override def selfBoxIndex: Int = {
    if (VersionContext.current.isJitActivated) {
      // starting from v5.0 this is fixed
      selfIndex
    } else {
      // this used to be a bug in v4.x (https://github.com/ScorexFoundation/sigmastate-interpreter/issues/603)
      -1
    }
  }

  override def getVar[T](id: Byte)(implicit tT: RType[T]): Option[T] = {
    @unused // avoid warning about unused ctA
    implicit val tag: ClassTag[T] = tT.classTag
    if (id < 0 || id >= vars.length) return None
    val value = vars(id)
    if (value != null) {
      // once the value is not null it should be of the right type
      value match {
        case value: CAnyValue[_] if value.value != null && value.tA == tT =>
          Some(value.value.asInstanceOf[T])
        case _ =>
          throw new InvalidType(s"Cannot getVar[${tT.name}]($id): invalid type of value $value at id=$id")
      }
    } else None
  }

  /** Return a new context instance with variables collection updated.
    * @param bindings  a new binding of the context variables with new values.
    * @return a new instance (if `bindings` non-empty) with the specified bindings.
    *         other existing bindings are copied to the new instance
    */
  def withUpdatedVars(bindings: (Int, AnyValue)*): CContext = {
    if (bindings.isEmpty) return this

    val ids = bindings.map(_._1).toArray
    val values = bindings.map(_._2).toArray
    val maxVarId = ids.max  // INV: ids is not empty
    val requiredNewLength = maxVarId + 1

    val newVars = if (vars.length < requiredNewLength) {
      // grow vars collection
      val currVars = vars.toArray
      val buf = new Array[AnyValue](requiredNewLength)
      Array.copy(currVars, 0, buf, 0, currVars.length)
      cfor(0)(_ < ids.length, _ + 1) { i =>
        buf(ids(i)) = values(i)
      }
      buf.toColl
    } else {
      vars.updateMany(ids.toColl, values.toColl)
    }

    this.copy(vars = newVars)
  }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy