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

Prohibition for using 6.0 types in register and context extension vars #1047

Open
wants to merge 7 commits into
base: v6.0.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.ergoplatform

import debox.cfor
import org.ergoplatform.ErgoBox._
import org.ergoplatform.validation.ValidationRules.CheckV6Type
import scorex.util.encode.Base16
import scorex.util.{ModifierId, bytesToId}
import sigma.Extensions.{ArrayOps, CollOps}
Expand Down Expand Up @@ -228,6 +229,7 @@ object ErgoBoxCandidate {
cfor(0)(_ < nRegs, _ + 1) { iReg =>
val reg = ErgoBox.nonMandatoryRegisters(iReg)
val v = r.getValue().asInstanceOf[EvaluatedValue[SType]] // READ
CheckV6Type(v)
b += ((reg, v)) // don't use `->` since it incur additional wrapper overhead
}
r.positionLimit = previousPositionLimit
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.ergoplatform.validation

import sigma.SigmaException
import sigma.ast.{DeserializeContext, ErgoTree, MethodsContainer, SMethod}
import sigma.ast.{Constant, DeserializeContext, ErgoTree, EvaluatedCollection, EvaluatedValue, GroupGenerator, MethodsContainer, SHeader, SMethod, SType, SUnsignedBigInt}
import sigma.ast.TypeCodes.LastConstantCode
import sigma.serialization.{InvalidOpCode, SerializerException}
import sigma.util.Extensions.toUByte
Expand Down Expand Up @@ -155,6 +155,39 @@ object ValidationRules {
override protected lazy val settings: SigmaValidationSettings = currentSettings
}

// todo: recheck id after merge
object CheckV6Type extends ValidationRule(1016,
"Check the type has the declared method.") {
override protected lazy val settings: SigmaValidationSettings = currentSettings

final def apply[T](v: EvaluatedValue[_]): Unit = {
checkRule()

def v6TypeCheck(tpe: SType) = {
if (tpe.isOption || tpe.typeCode == SHeader.typeCode || tpe.typeCode == SUnsignedBigInt.typeCode) {
throwValidationException(
new SerializerException(s"V6 type used in register or context var extension: $tpe"),
Array[Any](tpe))
}
}
v match {
case c: Constant[_] => v6TypeCheck(c.tpe)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems it is possible to serialize/parse Tuple with v6 type

  property("impossible to use v6 types in box registers") {
    val trueProp = ErgoTreePredef.TrueProp(ErgoTree.defaultHeaderWithVersion(3))

    val b = new ErgoBoxCandidate(1L, trueProp, 1,
                  additionalRegisters = Map(R4 -> Tuple(UnsignedBigIntConstant(new BigInteger("1")), IntConstant(1))))
    VersionContext.withVersions(3, 3) {
      val bs = ErgoBoxCandidate.serializer.toBytes(b)
      a[sigma.validation.ValidationException] should be thrownBy ErgoBoxCandidate.serializer.fromBytes(bs)
    }
}

doesn't throw exception

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SethDusek fixed, the reason was c.elementType being SAny for Tuple. Made test for UBI as second tuple element, and collection as well

case c: EvaluatedCollection[_, _] => v6TypeCheck(c.elementType)
case GroupGenerator =>
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the motivation to add and check this rule?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that deserialization of values in registers and context extension is not versioned, so newly supported serializable types (Header, Option[], UnsignedBigInt) can't be put there (but serialized as Coll[Byte] value can be put there to be used with Global.deserialize )

}

override def isSoftFork(vs: SigmaValidationSettings,
ruleId: Short,
status: RuleStatus,
args: Seq[Any]): Boolean = (status, args) match {
case (ChangedRule(newValue), Seq(objType: MethodsContainer, methodId: Byte)) =>
val key = Array(objType.ownerType.typeId, methodId)
newValue.grouped(2).exists(java.util.Arrays.equals(_, key))
case _ => false
}
}

val ruleSpecs: Seq[ValidationRule] = Seq(
CheckDeserializedScriptType,
CheckDeserializedScriptIsSigmaProp,
Expand All @@ -171,7 +204,8 @@ object ValidationRules {
CheckHeaderSizeBit,
CheckCostFuncOperation,
CheckPositionLimit,
CheckLoopLevelInCostFunction
CheckLoopLevelInCostFunction,
CheckV6Type
)

/** Validation settings that correspond to the current version of the ErgoScript implementation.
Expand Down
2 changes: 1 addition & 1 deletion data/shared/src/main/scala/sigma/ast/values.scala
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ trait PerItemCostValueCompanion extends ValueCompanion {
*
* @see Constant, ConcreteCollection, Tuple
*/
abstract class EvaluatedValue[+S <: SType] extends Value[S] {
sealed trait EvaluatedValue[+S <: SType] extends Value[S] {
/** The evaluated data value of the corresponding underlying data type. */
val value: S#WrappedType

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package sigma.interpreter

import org.ergoplatform.validation.ValidationRules.CheckV6Type
import sigma.ast.{EvaluatedValue, SType}
import sigma.interpreter.ContextExtension.VarBinding
import sigma.serialization.{SigmaByteReader, SigmaByteWriter, SigmaSerializer}
Expand Down Expand Up @@ -49,7 +50,12 @@ object ContextExtension {
if (extSize < 0)
error(s"Negative amount of context extension values: $extSize")
val values = (0 until extSize)
.map(_ => (r.getByte(), r.getValue().asInstanceOf[EvaluatedValue[_ <: SType]]))
.map{_ =>
val k = r.getByte()
val v = r.getValue().asInstanceOf[EvaluatedValue[_ <: SType]]
CheckV6Type(v)
(k, v)
}
ContextExtension(values.toMap)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package sigma.serialization
import java.nio.ByteBuffer
import scorex.util.ByteArrayBuilder
import scorex.util.serialization._
import sigma.ast.{Constant, EvaluatedCollection, EvaluatedValue, GroupGenerator, SHeader, SType, SUnsignedBigInt}
import sigma.data.SigmaConstants
import sigma.serialization.SigmaByteWriter.{FixedCostCallback, PerItemCostCallback}
import sigma.serialization.ValueCodes.OpCode
Expand Down
6 changes: 4 additions & 2 deletions sc/shared/src/test/scala/sigma/SigmaDslTesting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import debox.cfor
import org.ergoplatform._
import org.ergoplatform.dsl.{ContractSpec, SigmaContractSyntax, TestContractSpec}
import org.ergoplatform.validation.ValidationRules
import org.ergoplatform.validation.ValidationRules.CheckV6Type
import org.scalacheck.Arbitrary._
import org.scalacheck.Gen.frequency
import org.scalacheck.{Arbitrary, Gen}
Expand Down Expand Up @@ -390,8 +391,9 @@ class SigmaDslTesting extends AnyPropSpec
parsed.bytes shouldBe box.bytes
}
catch {
case ValidationException(_, r: CheckSerializableTypeCode.type, Seq(SOption.OptionTypeCode), _) =>
// ignore the problem with Option serialization, but test all the other cases
// ignore the problem with Option serialization, but test all the other cases
case ValidationException(_, _: CheckV6Type.type, Seq(SOption(_)), _) =>
case ValidationException(_, _: CheckSerializableTypeCode.type, Seq(SOption.OptionTypeCode), _) =>
}

ErgoLikeContextTesting.dummy(box, activatedVersionInTests)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sigma.serialization

import org.ergoplatform.ErgoBoxCandidate
import org.ergoplatform.ErgoBox.R4
import org.ergoplatform.{ErgoBoxCandidate, ErgoTreePredef}
import org.scalacheck.Gen
import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert}
import scorex.crypto.authds.{ADKey, ADValue}
Expand All @@ -11,7 +12,7 @@ import sigma.data.{AvlTreeData, AvlTreeFlags, CAND, SigmaBoolean}
import sigma.util.{BenchmarkUtil, safeNewArray}
import sigma.validation.ValidationException
import sigma.validation.ValidationRules.CheckPositionLimit
import sigma.{Colls, Environment}
import sigma.{Colls, Environment, VersionContext}
import sigma.ast._
import sigma.ast.syntax._
import sigmastate._
Expand All @@ -25,6 +26,7 @@ import sigmastate.helpers.{CompilerTestingCommons, ErgoLikeContextTesting, ErgoL
import sigma.serialization.OpCodes._
import sigmastate.utils.Helpers._

import java.math.BigInteger
import java.nio.ByteBuffer
import scala.collection.immutable.Seq
import scala.collection.mutable
Expand Down Expand Up @@ -425,4 +427,24 @@ class DeserializationResilience extends DeserializationResilienceTesting {
// NOTE, even though performOneOperation fails, some AvlTree$ methods used in Interpreter
// (remove_eval, update_eval, contains_eval) won't throw, while others will.
}


property("impossible to use v6 types in box registers") {
val trueProp = ErgoTreePredef.TrueProp(ErgoTree.defaultHeaderWithVersion(3))

val b = new ErgoBoxCandidate(1L, trueProp, 1,
additionalRegisters = Map(R4 -> UnsignedBigIntConstant(new BigInteger("2"))))
VersionContext.withVersions(3, 3) {
val bs = ErgoBoxCandidate.serializer.toBytes(b)
a[sigma.validation.ValidationException] should be thrownBy ErgoBoxCandidate.serializer.fromBytes(bs)
}

val b2 = new ErgoBoxCandidate(1L, trueProp, 1,
additionalRegisters = Map(R4 -> Constant[SOption[SInt.type]](Some(2), SOption(SInt))))
VersionContext.withVersions(3, 3) {
val bs2 = ErgoBoxCandidate.serializer.toBytes(b2)
a[sigma.validation.ValidationException] should be thrownBy ErgoBoxCandidate.serializer.fromBytes(bs2)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@ import sigmastate._
import sigma.ast.syntax._
import sigma.data.{AvlTreeData, CBox, ProveDHTuple, ProveDlog, TrivialProp}
import sigma.util.Extensions.EcpOps
import sigma.validation.ValidationException
import sigma.validation.{ReplacedRule, ValidationException, ValidationRules}
import sigmastate.eval._
import sigmastate.interpreter.Interpreter._
import sigmastate.helpers._
import sigmastate.helpers.TestingHelpers._
import sigma.interpreter.ContextExtension.VarBinding
import sigma.eval.Extensions.SigmaBooleanOps
import sigma.interpreter.{ContextExtension, CostedProverResult}
import sigma.interpreter.{ContextExtension, CostedProverResult, ProverResult}
import sigma.serialization.{SerializationSpecification, ValueSerializer}
import sigmastate.utils.Helpers._

import java.math.BigInteger

class ErgoLikeInterpreterSpecification extends CompilerTestingCommons
with SerializationSpecification
with CompilerCrossVersionProps {
Expand Down Expand Up @@ -761,6 +763,27 @@ class ErgoLikeInterpreterSpecification extends CompilerTestingCommons
prove(tree, script = 1.toByte -> ByteArrayConstant(scriptBytes))
}

property("DeserializeContext can return expression of UnsignedBigInt type in 6.0") {
def prove(ergoTree: ErgoTree, script: VarBinding) = {
val boxToSpend = testBox(10, ergoTree, creationHeight = 5)
val updVs = ValidationRules.coreSettings.updated(1007.toShort, ReplacedRule(1017.toShort))
val ctx = ErgoLikeContextTesting.dummy(boxToSpend, 2)
.withExtension(
ContextExtension(Seq(script).toMap)) // provide script bytes in context variable
.withValidationSettings(updVs)

val prover = new ErgoLikeTestProvingInterpreter()
prover.prove(ergoTree, ctx, fakeMessage).getOrThrow
}

val script = """{unsignedBigInt("0")}"""
val scriptProp = VersionContext.withVersions(3,2){compile(Map.empty, script)} // of Int type
val scriptBytes = VersionContext.withVersions(3,2){ValueSerializer.serialize(scriptProp)}
val tree = VersionContext.withVersions(3,2){ErgoTree.fromProposition(ErgoTree.defaultHeaderWithVersion(2),
EQ(DeserializeContext(1, SUnsignedBigInt), UnsignedBigIntConstant(new BigInteger("0"))).toSigmaProp)}
prove(tree, script = 1.toByte -> ByteArrayConstant(scriptBytes))
}

property("non-const ProveDHT") {
import sigma.crypto.CryptoConstants.dlogGroup
compile(Map("gA" -> dlogGroup.generator.toGroupElement),
Expand Down
Loading