diff --git a/core/shared/src/main/scala/sigma/data/CAnyValue.scala b/core/shared/src/main/scala/sigma/data/CAnyValue.scala new file mode 100644 index 0000000000..9c10dfbbe2 --- /dev/null +++ b/core/shared/src/main/scala/sigma/data/CAnyValue.scala @@ -0,0 +1,18 @@ +package sigma.data + +import sigma.AnyValue +import sigma.data.OverloadHack.Overloaded1 + +import scala.annotation.unused + +/** Default implementation of AnyValue interface. */ +case class CAnyValue[A](value: A, tVal: RType[Any]) extends AnyValue { + def tA: RType[A] = tVal.asInstanceOf[RType[A]] + + override def toString = s"TestValue($value)" +} + +object CAnyValue { + def apply[A](value: A)(implicit t: RType[A], @unused o: Overloaded1): CAnyValue[A] = + new CAnyValue(value, t.asInstanceOf[RType[Any]]) +} \ No newline at end of file diff --git a/interpreter/shared/src/main/scala/sigmastate/eval/CBox.scala b/interpreter/shared/src/main/scala/sigmastate/eval/CBox.scala new file mode 100644 index 0000000000..e544faea31 --- /dev/null +++ b/interpreter/shared/src/main/scala/sigmastate/eval/CBox.scala @@ -0,0 +1,95 @@ +package sigmastate.eval + +import org.ergoplatform.ErgoBox +import scorex.utils.Ints +import sigma.Evaluation.stypeToRType +import sigma.ast.SCollection.SByteArray +import sigma.ast.{SInt, STuple, SType} +import sigma.data.{CAnyValue, RType, WrapperOf} +import sigma.{AnyValue, Box, Coll, Colls} +import sigmastate.Values.{ConstantNode, EvaluatedValue, SValue} +import sigmastate.eval.CBox.regs +import sigmastate.eval.Extensions.toAnyValue + +import java.util.Arrays + +/** A default implementation of [[Box]] interface. + * + * @see [[Box]] for detailed descriptions + */ +case class CBox(ebox: ErgoBox) extends Box with WrapperOf[ErgoBox] { + val builder = CSigmaDslBuilder + + val value = ebox.value + lazy val id : Coll[Byte] = Colls.fromArray(ebox.id) + lazy val bytes : Coll[Byte] = Colls.fromArray(ebox.bytes) + lazy val bytesWithoutRef : Coll[Byte] = Colls.fromArray(ebox.bytesWithNoRef) + lazy val propositionBytes: Coll[Byte] = Colls.fromArray(ebox.propositionBytes) + lazy val registers : Coll[AnyValue] = regs(ebox) + + override def wrappedValue: ErgoBox = ebox + + override def getReg[T](i: Int)(implicit tT: RType[T]): Option[T] = { + if (i < 0 || i >= registers.length) return None + val value = registers(i) + 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 getReg[${tT.name}]($i): invalid type of value $value at id=$i") + } + } else None + } + + override def creationInfo: (Int, Coll[Byte]) = { + this.getReg[(Int, Coll[Byte])](3).get.asInstanceOf[Any] match { + case info: Tuple2[Int, Coll[Byte]]@unchecked => info + case ConstantNode(arr: Array[Any], STuple(IndexedSeq(SInt, SByteArray))) if arr.length == 2 => + (arr(0).asInstanceOf[Int], builder.Colls.fromArray(arr(1).asInstanceOf[Array[Byte]])) + case v => + sys.error(s"Invalid value $v of creationInfo register R3") + } + } + + override def tokens: Coll[(Coll[Byte], Long)] = { + this.getReg[Coll[(Coll[Byte], Long)]](ErgoBox.R2.asIndex).get + } + + override def executeFromRegister[T](regId: Byte) + (implicit cT: RType[T]): T = ??? // TODO implement + + override def hashCode(): Int = Ints.fromByteArray(id.toArray) + + override def equals(obj: Any): Boolean = (this eq obj.asInstanceOf[AnyRef]) || (obj != null && { + obj match { + case obj: Box => Arrays.equals(id.toArray, obj.id.toArray) + case _ => + // this case was missing in v4.x, however has never been a problem + // Thus, v5.0 interpreter will not fail (while v4.x would fail here) + false + } + }) +} + +object CBox { + def regs(ebox: ErgoBox): Coll[AnyValue] = { + val res = new Array[AnyValue](ErgoBox.maxRegisters) + + def checkNotYetDefined(id: Int, newValue: SValue) = + require(res(id) == null, s"register $id is defined more then once: previous value ${res(id)}, new value $newValue") + + for ( (k, v: EvaluatedValue[t]) <- ebox.additionalRegisters ) { + checkNotYetDefined(k.number, v) + res(k.number) = toAnyValue(v.value)(stypeToRType(v.tpe)) + } + for ( r <- ErgoBox.mandatoryRegisters ) { + val regId = r.number + val v = ebox.get(r).get.asInstanceOf[EvaluatedValue[SType]] + checkNotYetDefined(regId, v) + res(regId) = toAnyValue(v.value)(stypeToRType(v.tpe)) + } + Colls.fromArray(res) + } +} \ No newline at end of file diff --git a/interpreter/shared/src/main/scala/sigmastate/eval/CContext.scala b/interpreter/shared/src/main/scala/sigmastate/eval/CContext.scala index d87082a99b..a89ff4b4d4 100644 --- a/interpreter/shared/src/main/scala/sigmastate/eval/CContext.scala +++ b/interpreter/shared/src/main/scala/sigmastate/eval/CContext.scala @@ -60,103 +60,6 @@ object AvlTreeVerifier { } } -/** Default implementation of AnyValue interface. */ -case class CAnyValue[A](value: A, tVal: RType[Any]) extends AnyValue { - def tA: RType[A] = tVal.asInstanceOf[RType[A]] - override def toString = s"TestValue($value)" -} - -object CAnyValue { - def apply[A](value: A)(implicit t: RType[A], @unused o: Overloaded1): CAnyValue[A] = - new CAnyValue(value, t.asInstanceOf[RType[Any]]) -} - -import sigmastate.eval.CBox._ - -/** A default implementation of [[Box]] interface. - * @see [[Box]] for detailed descriptions - */ -case class CBox(ebox: ErgoBox) extends Box with WrapperOf[ErgoBox] { - val builder = CSigmaDslBuilder - - val value = ebox.value - lazy val id: Coll[Byte] = Colls.fromArray(ebox.id) - lazy val bytes: Coll[Byte] = Colls.fromArray(ebox.bytes) - lazy val bytesWithoutRef: Coll[Byte] = Colls.fromArray(ebox.bytesWithNoRef) - lazy val propositionBytes: Coll[Byte] = Colls.fromArray(ebox.propositionBytes) - lazy val registers: Coll[AnyValue] = regs(ebox) - - override def wrappedValue: ErgoBox = ebox - - override def getReg[T](i: Int)(implicit tT: RType[T]): Option[T] = { - if (i < 0 || i >= registers.length) return None - val value = registers(i) - 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 getReg[${tT.name}]($i): invalid type of value $value at id=$i") - } - } else None - } - - override def creationInfo: (Int, Coll[Byte]) = { - this.getReg[(Int, Coll[Byte])](3).get.asInstanceOf[Any] match { - case info: Tuple2[Int, Coll[Byte]]@unchecked => info - case ConstantNode(arr: Array[Any], STuple(IndexedSeq(SInt, SByteArray))) if arr.length == 2 => - (arr(0).asInstanceOf[Int], builder.Colls.fromArray(arr(1).asInstanceOf[Array[Byte]])) - case v => - sys.error(s"Invalid value $v of creationInfo register R3") - } - } - - override def tokens: Coll[(Coll[Byte], Long)] = { - this.getReg[Coll[(Coll[Byte], Long)]](ErgoBox.R2.asIndex).get - } - - override def executeFromRegister[T](regId: Byte)(implicit cT: RType[T]): T = ??? // TODO implement - - override def hashCode(): Int = Ints.fromByteArray(id.toArray) - - override def equals(obj: Any): Boolean = (this eq obj.asInstanceOf[AnyRef]) || (obj != null && { - obj match { - case obj: Box => Arrays.equals(id.toArray, obj.id.toArray) - case _ => - // this case was missing in v4.x, however has never been a problem - // Thus, v5.0 interpreter will not fail (while v4.x would fail here) - false - } - }) -} - -object CBox { - - import Evaluation._ - - def regs(ebox: ErgoBox): Coll[AnyValue] = { - val res = new Array[AnyValue](ErgoBox.maxRegisters) - - def checkNotYetDefined(id: Int, newValue: SValue) = - require(res(id) == null, s"register $id is defined more then once: previous value ${res(id)}, new value $newValue") - - for ((k, v: EvaluatedValue[t]) <- ebox.additionalRegisters) { - checkNotYetDefined(k.number, v) - res(k.number) = toAnyValue(v.value)(stypeToRType(v.tpe)) - } - - for (r <- ErgoBox.mandatoryRegisters) { - val regId = r.number - val v = ebox.get(r).get.asInstanceOf[EvaluatedValue[SType]] - checkNotYetDefined(regId, v) - res(regId) = toAnyValue(v.value)(stypeToRType(v.tpe)) - } - Colls.fromArray(res) - } - -} - /** This class represents context variable and register value of a functional type A => B. * When variable or register is accessed using `getVar[A => B](id).get` or * `box.getReg[A => B].get an instance of this class is returned. diff --git a/interpreter/shared/src/main/scala/sigmastate/eval/Extensions.scala b/interpreter/shared/src/main/scala/sigmastate/eval/Extensions.scala index 9ec065942b..f8a58964e8 100644 --- a/interpreter/shared/src/main/scala/sigmastate/eval/Extensions.scala +++ b/interpreter/shared/src/main/scala/sigmastate/eval/Extensions.scala @@ -8,7 +8,7 @@ import scorex.crypto.authds.{ADKey, ADValue} import scorex.util.encode.Base16 import sigma.ast.SType.AnyOps import sigma.ast.{SBoolean, SCollection, SCollectionType, SType} -import sigma.data.{Nullable, RType, SigmaBoolean} +import sigma.data.{CAnyValue, Nullable, RType, SigmaBoolean} import sigma.{Coll, _} import sigmastate.Platform import sigmastate.Values.{Constant, ConstantNode, SigmaPropConstant, SigmaPropValue, Value} diff --git a/interpreter/shared/src/main/scala/sigmastate/utils/Helpers.scala b/interpreter/shared/src/main/scala/sigmastate/utils/Helpers.scala index 2f3f057204..1e867cff28 100644 --- a/interpreter/shared/src/main/scala/sigmastate/utils/Helpers.scala +++ b/interpreter/shared/src/main/scala/sigmastate/utils/Helpers.scala @@ -3,11 +3,11 @@ package sigmastate.utils import debox.cfor import io.circe.Decoder import org.ergoplatform.settings.ErgoAlgos -import sigma.data.{OverloadHack, RType} +import sigma.data.{CAnyValue, OverloadHack, RType} import scorex.utils.Ints import sigma.crypto.EcPointType import sigma.{Coll, Colls, Environment, GroupElement} -import sigmastate.eval.{CAnyValue, SigmaDsl} +import sigmastate.eval.SigmaDsl import java.util import java.util.concurrent.locks.Lock diff --git a/interpreter/shared/src/test/scala/sigmastate/lang/SigmaBuilderTest.scala b/interpreter/shared/src/test/scala/sigmastate/lang/SigmaBuilderTest.scala index ad8eea574d..95ee94c680 100644 --- a/interpreter/shared/src/test/scala/sigmastate/lang/SigmaBuilderTest.scala +++ b/interpreter/shared/src/test/scala/sigmastate/lang/SigmaBuilderTest.scala @@ -3,12 +3,12 @@ package sigmastate.lang import org.scalatest.matchers.should.Matchers import org.scalatest.propspec.AnyPropSpec import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import sigma.data.{CAvlTree, Nullable, RType} +import sigma.data.{CAnyValue, CAvlTree, Nullable, RType} import sigma.{Environment, VersionContext} import sigmastate.Values._ import sigmastate._ import sigma.Extensions.ArrayOps -import sigmastate.eval.{CAnyValue, CBox, SigmaDsl} +import sigmastate.eval.{CBox, SigmaDsl} import sigmastate.exceptions.ConstraintFailed import sigmastate.serialization.OpCodes import sigma.SigmaTestingData diff --git a/parsers/shared/src/test/scala/sigmastate/lang/LangTests.scala b/parsers/shared/src/test/scala/sigmastate/lang/LangTests.scala index 55e3759089..ee3d046753 100644 --- a/parsers/shared/src/test/scala/sigmastate/lang/LangTests.scala +++ b/parsers/shared/src/test/scala/sigmastate/lang/LangTests.scala @@ -14,7 +14,7 @@ import sigmastate.eval._ import sigmastate.helpers.NegativeTesting import sigma.Coll import sigma.ast._ -import sigma.data.{ProveDHTuple, ProveDlog, SigmaBoolean} +import sigma.data.{CAnyValue, ProveDHTuple, ProveDlog, SigmaBoolean} import sigma.util.Extensions.BigIntegerOps trait LangTests extends Matchers with NegativeTesting { diff --git a/sc/shared/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala b/sc/shared/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala index 0b26809e3b..90bf013059 100644 --- a/sc/shared/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala +++ b/sc/shared/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala @@ -7,14 +7,14 @@ import sigmastate.interpreter.{CostedProverResult, ProverResult} import scala.collection.mutable.ArrayBuffer import org.ergoplatform.ErgoBox.{NonMandatoryRegisterId, TokenId} -import sigma.data.{AvlTreeData, CSigmaProp, Nullable} +import sigma.data.{AvlTreeData, CAnyValue, CSigmaProp, Nullable} import scala.util.Try import org.ergoplatform.{ErgoBox, ErgoLikeContext} import org.ergoplatform.dsl.ContractSyntax.{ErgoScript, Proposition, Token} import sigma.ast.SType import sigmastate.Values.{ErgoTree, EvaluatedValue} -import sigmastate.eval.{CAnyValue, IRContext} +import sigmastate.eval.IRContext import sigmastate.helpers.{CompilerTestingCommons, ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestInterpreter} import sigmastate.helpers.TestingHelpers._ import sigmastate.lang.Terms.ValueOps diff --git a/sc/shared/src/test/scala/sigmastate/eval/ExampleContracts.scala b/sc/shared/src/test/scala/sigmastate/eval/ExampleContracts.scala index 913a82167f..ac9e6aac07 100644 --- a/sc/shared/src/test/scala/sigmastate/eval/ExampleContracts.scala +++ b/sc/shared/src/test/scala/sigmastate/eval/ExampleContracts.scala @@ -1,6 +1,7 @@ package sigmastate.eval import scalan.BaseCtxTests +import sigma.data.CAnyValue trait ExampleContracts extends ErgoScriptTestkit { self: BaseCtxTests => diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 3d35322a38..1a236fa31a 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -6,12 +6,12 @@ import sigma.Extensions.ArrayOps import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps import sigma.ast._ -import sigma.data.AvlTreeData +import sigma.data.{AvlTreeData, CAnyValue} import sigma.util.StringUtil._ import sigmastate.Values._ import sigmastate._ import sigmastate.crypto.CryptoConstants -import sigmastate.eval.{CAnyValue, InvalidType} +import sigmastate.eval.InvalidType import sigmastate.helpers.TestingHelpers._ import sigmastate.helpers.{CompilerTestingCommons, ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTestInterpreter} import sigmastate.interpreter.ContextExtension.VarBinding diff --git a/sc/shared/src/test/scala/sigmastate/utxo/SigmaCompilerSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/SigmaCompilerSpecification.scala index 07565bbff9..8809e22836 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/SigmaCompilerSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/SigmaCompilerSpecification.scala @@ -1,8 +1,8 @@ package sigmastate.utxo import sigma.ast.SType +import sigma.data.CAnyValue import sigmastate.Values._ -import sigmastate.eval.CAnyValue import sigmastate.helpers.CompilerTestingCommons import sigmastate.interpreter.Interpreter.ScriptEnv import sigmastate.lang.Terms._ diff --git a/sdk/shared/src/main/scala/org/ergoplatform/sdk/DataJsonEncoder.scala b/sdk/shared/src/main/scala/org/ergoplatform/sdk/DataJsonEncoder.scala index a384129ec3..fef67a2704 100644 --- a/sdk/shared/src/main/scala/org/ergoplatform/sdk/DataJsonEncoder.scala +++ b/sdk/shared/src/main/scala/org/ergoplatform/sdk/DataJsonEncoder.scala @@ -6,7 +6,7 @@ import io.circe.syntax._ import org.ergoplatform.ErgoBox import org.ergoplatform.ErgoBox.{NonMandatoryRegisterId, Token} import org.ergoplatform.settings.ErgoAlgos -import sigma.data.RType +import sigma.data.{CAnyValue, RType} import scorex.util._ import sigmastate.Values.{Constant, EvaluatedValue} import sigmastate.lang.SigmaParser diff --git a/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala b/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala index f3afb17553..0b35fd2462 100644 --- a/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala +++ b/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala @@ -4,7 +4,7 @@ package org.ergoplatform.sdk import java.math.BigInteger import org.scalacheck.Arbitrary._ import org.scalacheck.Gen -import sigma.data.{RType, SigmaBoolean, TupleColl} +import sigma.data.{CAnyValue, RType, SigmaBoolean, TupleColl} import sigma.ast._ import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps