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

[6.0] Fix for lazyness in getOrElse could cause disagreement between 6.0 and < 6.0 nodes, activation details and revised checkSoftForkCondition #1043

Open
wants to merge 29 commits into
base: v6.0.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ac11237
CheckAndGetMethod/CheckAndGetMethodV6, versioned methodById
kushti Oct 15, 2024
e9e59e0
Merge branch 'v6.0.0' of github.com:ScorexFoundation/sigmastate-inter…
kushti Oct 29, 2024
901c868
1007 & 1008 replacement & versioning
kushti Oct 29, 2024
b3a10a5
1007 rule update
kushti Nov 14, 2024
491f878
versioned rulesSpecs
kushti Nov 15, 2024
234c8fb
merging w. 6.0.0
kushti Dec 5, 2024
f482814
6.0 specific serialization removed
kushti Dec 6, 2024
c1dc254
ergoTreeVersion removed from VersionContext
kushti Dec 6, 2024
2effbba
removing checkType parameter which is always true
kushti Dec 6, 2024
8993b3a
ergo tree version removed from withVersions
kushti Dec 6, 2024
22ce03b
unused env removed from reductionWithDeserialize
kushti Dec 6, 2024
e2720be
tree version based checks for lazy default
kushti Dec 11, 2024
59225d3
tree version based versioning
kushti Dec 13, 2024
2f557e1
back to activated script version for serializers
kushti Dec 13, 2024
988f42b
fixing LSV5 tests
kushti Dec 16, 2024
a14a257
fixing TestingInterpreterSpecification
kushti Dec 17, 2024
11a4d3e
activationType flag for LSV* tests
kushti Dec 18, 2024
592a68c
fixing LSV6 tests
kushti Dec 18, 2024
e9f24c0
MethodCallSerializerSpecification fix
kushti Dec 19, 2024
7aad66f
merging w. 6.0-serialization branch
kushti Dec 19, 2024
d8839f9
activation type constants
kushti Dec 19, 2024
f59f704
fromBlockVersion
kushti Dec 20, 2024
905448b
fromBlockVersion fix
kushti Dec 20, 2024
91b3b98
versioning in serializeErgoTree
kushti Dec 23, 2024
bce9f91
Merge branch 'i904' of github.com:ScorexFoundation/sigmastate-interpr…
kushti Dec 25, 2024
ce205f4
post-merge fix
kushti Dec 26, 2024
f6b801f
replacedrule fix
kushti Dec 26, 2024
15a3096
full replacedrule id check
kushti Dec 26, 2024
8aa8002
fix checkmethod rule test
kushti Jan 10, 2025
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
9 changes: 8 additions & 1 deletion core/shared/src/main/scala/sigma/VersionContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ case class VersionContext(activatedVersion: Byte, ergoTreeVersion: Byte) {

/** @return true, if the activated script version of Ergo protocol on the network is
* including v6.0 update. */
def isV6SoftForkActivated: Boolean = activatedVersion >= V6SoftForkVersion
def isV3OrLaterErgoTreeVersion: Boolean = ergoTreeVersion >= V6SoftForkVersion

def isV6Activated: Boolean = activatedVersion >= V6SoftForkVersion

}

object VersionContext {
Expand Down Expand Up @@ -104,4 +107,8 @@ object VersionContext {
}
}

def fromBlockVersion(blockVersion: Byte): VersionContext = {
VersionContext((blockVersion - 1).toByte, (blockVersion - 1).toByte)
}

}
26 changes: 13 additions & 13 deletions core/shared/src/main/scala/sigma/ast/SType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ object SType {
/** All pre-defined types should be listed here. Note, NoType is not listed.
* Should be in sync with sigmastate.lang.Types.predefTypes. */
def allPredefTypes: Seq[SType] = {
if(VersionContext.current.isV6SoftForkActivated) {
if(VersionContext.current.isV3OrLaterErgoTreeVersion) {
v6PredefTypes
} else {
v5PredefTypes
Expand Down Expand Up @@ -164,7 +164,7 @@ object SType {

private val v6TypesMap = v6Types.map { t => (t.typeId, t) }.toMap

def types: Map[Byte, STypeCompanion] = if (VersionContext.current.isV6SoftForkActivated) {
def types: Map[Byte, STypeCompanion] = if (VersionContext.current.isV3OrLaterErgoTreeVersion) {
v6TypesMap
} else {
v5TypesMap
Expand All @@ -191,7 +191,7 @@ object SType {
case SInt => x.isInstanceOf[Int]
case SLong => x.isInstanceOf[Long]
case SBigInt => x.isInstanceOf[BigInt]
case SUnsignedBigInt if VersionContext.current.isV6SoftForkActivated => x.isInstanceOf[UnsignedBigInt]
case SUnsignedBigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => x.isInstanceOf[UnsignedBigInt]
case SGroupElement => x.isInstanceOf[GroupElement]
case SSigmaProp => x.isInstanceOf[SigmaProp]
case SBox => x.isInstanceOf[Box]
Expand Down Expand Up @@ -409,8 +409,8 @@ case object SByte extends SPrimType with SEmbeddable with SNumericType with SMon
case s: Short => s.toByteExact
case i: Int => i.toByteExact
case l: Long => l.toByteExact
case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toByte // toByteExact from int is called under the hood
case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toByte // toByteExact from int is called under the hood
case bi: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => bi.toByte // toByteExact from int is called under the hood
case ubi: UnsignedBigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => ubi.toByte // toByteExact from int is called under the hood
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
Expand All @@ -432,8 +432,8 @@ case object SShort extends SPrimType with SEmbeddable with SNumericType with SMo
case s: Short => s
case i: Int => i.toShortExact
case l: Long => l.toShortExact
case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toShort // toShortExact from int is called under the hood
case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toShort // toShortExact from int is called under the hood
case bi: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => bi.toShort // toShortExact from int is called under the hood
case ubi: UnsignedBigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => ubi.toShort // toShortExact from int is called under the hood
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
Expand All @@ -457,8 +457,8 @@ case object SInt extends SPrimType with SEmbeddable with SNumericType with SMono
case s: Short => s.toInt
case i: Int => i
case l: Long => l.toIntExact
case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toInt
case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toInt
case bi: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => bi.toInt
case ubi: UnsignedBigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => ubi.toInt
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
Expand All @@ -484,8 +484,8 @@ case object SLong extends SPrimType with SEmbeddable with SNumericType with SMon
case s: Short => s.toLong
case i: Int => i.toLong
case l: Long => l
case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toLong
case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toLong
case bi: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => bi.toLong
case ubi: UnsignedBigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => ubi.toLong
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
Expand All @@ -512,7 +512,7 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM
case x: Short => CBigInt(BigInteger.valueOf(x.toLong))
case x: Int => CBigInt(BigInteger.valueOf(x.toLong))
case x: Long => CBigInt(BigInteger.valueOf(x))
case x: BigInt if VersionContext.current.isV6SoftForkActivated => x
case x: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => x
case _ => sys.error(s"Cannot upcast value $v to the type $this")
}
}
Expand All @@ -524,7 +524,7 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM
case x: Short => CBigInt(BigInteger.valueOf(x.toLong))
case x: Int => CBigInt(BigInteger.valueOf(x.toLong))
case x: Long => CBigInt(BigInteger.valueOf(x))
case x: BigInt if VersionContext.current.isV6SoftForkActivated => x
case x: BigInt if VersionContext.current.isV3OrLaterErgoTreeVersion => x
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/shared/src/main/scala/sigma/data/CollsOverArrays.scala
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil
case obj: CollOverArray[_] if obj.tItem == this.tItem =>
java.util.Objects.deepEquals(obj.toArray, this.toArray)
case obj: PairColl[Any, Any] if obj.tItem == this.tItem =>
if (VersionContext.current.isV6SoftForkActivated) {
if (VersionContext.current.isV3OrLaterErgoTreeVersion) {
equalsPairCollWithCollOverArray(obj, this.asInstanceOf[CollOverArray[Any]])
} else {
false
Expand Down Expand Up @@ -282,7 +282,7 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R
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) {
if (VersionContext.current.isV3OrLaterErgoTreeVersion) {
equalsPairCollWithCollOverArray(this.asInstanceOf[PairColl[Any, Any]], that)
} else {
false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class CoreDataSerializer {
val data = v.asInstanceOf[BigInt].toBigInteger.toByteArray
w.putUShort(data.length)
w.putBytes(data)
case SUnsignedBigInt if VersionContext.current.isV6SoftForkActivated =>
case SUnsignedBigInt if VersionContext.current.isV6Activated =>
val data = BigIntegers.asUnsignedByteArray(v.asInstanceOf[CUnsignedBigInt].wrappedValue)
w.putUShort(data.length)
w.putBytes(data)
Expand Down Expand Up @@ -73,7 +73,7 @@ class CoreDataSerializer {
i += 1
}

case SOption(elemType) if VersionContext.current.isV6SoftForkActivated =>
case SOption(elemType) if VersionContext.current.isV6Activated =>
val o = v.asInstanceOf[Option[elemType.WrappedType]]
w.putOption(o){case (w, v) =>
serialize(v, elemType, w)
Expand Down Expand Up @@ -113,7 +113,7 @@ class CoreDataSerializer {
}
val valueBytes = r.getBytes(size)
CBigInt(new BigInteger(valueBytes))
case SUnsignedBigInt if VersionContext.current.isV6SoftForkActivated =>
case SUnsignedBigInt if VersionContext.current.isV6Activated =>
val size: Short = r.getUShort().toShort
if (size > SBigInt.MaxSizeInBytes) {
throw SerializerException(s"BigInt value doesn't not fit into ${SBigInt.MaxSizeInBytes} bytes: $size")
Expand All @@ -135,7 +135,7 @@ class CoreDataSerializer {
}.toArray[Any]
val coll = Colls.fromArray(arr)(sigma.AnyType)
Evaluation.toDslTuple(coll, tuple)
case tOption: SOption[_] if VersionContext.current.isV6SoftForkActivated =>
case tOption: SOption[_] if VersionContext.current.isV6Activated =>
r.getOption[tOption.ElemWrappedType] {
deserialize(tOption.elemType, r).asInstanceOf[tOption.ElemWrappedType]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import sigma.VersionContext
import sigma.ast.SCollectionType.{CollectionTypeCode, NestedCollectionTypeCode}
import sigma.ast._
import sigma.util.safeNewArray
import sigma.validation.ValidationRules.{CheckPrimitiveTypeCode, CheckTypeCode}
import sigma.validation.ValidationRules.{CheckPrimitiveTypeCode, CheckPrimitiveTypeCodeV6, CheckTypeCode, CheckTypeCodeV6}

import java.nio.charset.StandardCharsets

Expand All @@ -14,7 +14,12 @@ class TypeSerializer {
import TypeSerializer._

def getEmbeddableType(code: Int): SType = {
CheckPrimitiveTypeCode(code.toByte)
// todo : add unsigned bit int to embeddable id to type
if (VersionContext.current.isV6Activated) {
CheckPrimitiveTypeCodeV6(code.toByte)
} else {
CheckPrimitiveTypeCode(code.toByte)
}
embeddableIdToType(code)
}

Expand Down Expand Up @@ -200,7 +205,7 @@ class TypeSerializer {
case SHeader.typeCode => SHeader
case SPreHeader.typeCode => SPreHeader
case SGlobal.typeCode => SGlobal
case SFunc.FuncTypeCode if VersionContext.current.isV6SoftForkActivated =>
case SFunc.FuncTypeCode if VersionContext.current.isV3OrLaterErgoTreeVersion =>
val tdLength = r.getUByte()

val tDom = (1 to tdLength).map { _ =>
Expand All @@ -215,9 +220,13 @@ class TypeSerializer {
}
SFunc(tDom, tRange, tpeParams)
case _ =>
// todo: 6.0: replace 1008 check with identical behavior but other opcode, to activate
// ReplacedRule(1008 -> new opcode) during 6.0 activation
CheckTypeCode(c.toByte)
// the #1008 check replaced with one with identical behavior but different opcode (1018), to activate
// ReplacedRule(1008 -> 1018) during 6.0 activation
if (VersionContext.current.isV6Activated) {
CheckTypeCodeV6(c.toByte)
} else {
CheckTypeCode(c.toByte)
}
NoType
}
}
Expand All @@ -243,7 +252,7 @@ object TypeSerializer extends TypeSerializer {
/** The list of embeddable types, i.e. types that can be combined with type constructor for optimized encoding.
* For each embeddable type `T`, and type constructor `C`, the type `C[T]` can be represented by single byte. */
def embeddableIdToType = {
if (VersionContext.current.isV6SoftForkActivated) {
if (VersionContext.current.isV3OrLaterErgoTreeVersion) {
embeddableV6
} else {
embeddableV5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ case object DisabledRule extends RuleStatus {
* @see `ValidationSettings.isSoftFork`
* @param newRuleId id of a new rule which replaces the rule marked with this status
*/
case class ReplacedRule(newRuleId: Short) extends RuleStatus {
case class ReplacedRule(newRuleId: Short) extends RuleStatus {
val statusCode: Byte = RuleStatus.ReplacedRuleCode
}

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

import sigma.VersionContext

/**
* Configuration of validation. Each `ValidationRule` instance should be
* implemented as an `object` to facilitate type-safe usage. It then should be
Expand Down Expand Up @@ -48,7 +50,11 @@ abstract class SigmaValidationSettings extends Iterable[(Short, (ValidationRule,
def isSoftFork(ruleId: Short, ve: ValidationException): Boolean = {
val infoOpt = get(ruleId)
infoOpt match {
case Some((_, ReplacedRule(_))) => true
case Some((vr, ReplacedRule(_))) => if ((vr.id == 1011 || vr.id == 1007 || vr.id == 1008) && VersionContext.current.isV6Activated) {
false
} else {
true
}
case Some((rule, status)) => rule.isSoftFork(this, rule.id, status, ve.args)
case None => false
}
Expand Down
43 changes: 34 additions & 9 deletions core/shared/src/main/scala/sigma/validation/ValidationRules.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package sigma.validation

import sigma.SigmaException
import sigma.{SigmaException, VersionContext}
import sigma.ast.{SGlobal, SOption, TypeCodes}
import sigma.serialization.{ReaderPositionLimitExceeded, SerializerException}
import sigma.util.Extensions.toUByte
Expand Down Expand Up @@ -77,7 +77,7 @@ object ValidationRules {
/** The id of the first validation rule. Can be used as the beginning of the rules id range. */
val FirstRuleId = 1000.toShort

object CheckPrimitiveTypeCode extends ValidationRule(1007,
class CheckPrimitiveTypeCodeTemplate(ruleId: Short) extends ValidationRule(ruleId,
"Check the primitive type code is supported or is added via soft-fork")
with SoftForkWhenCodeAdded {
override protected lazy val settings: SigmaValidationSettings = coreSettings
Expand All @@ -93,10 +93,14 @@ object ValidationRules {
}
}

object CheckTypeCode extends ValidationRule(1008,
object CheckPrimitiveTypeCode extends CheckPrimitiveTypeCodeTemplate(1007)

object CheckPrimitiveTypeCodeV6 extends CheckPrimitiveTypeCodeTemplate(1017)

class CheckTypeCodeTemplate(ruleId: Short) extends ValidationRule(ruleId,
"Check the non-primitive type code is supported or is added via soft-fork")
with SoftForkWhenCodeAdded {
override protected lazy val settings: SigmaValidationSettings = coreSettings
override protected def settings: SigmaValidationSettings = coreSettings

final def apply[T](typeCode: Byte): Unit = {
checkRule()
Expand All @@ -109,10 +113,14 @@ object ValidationRules {
}
}

object CheckTypeCode extends CheckTypeCodeTemplate(1008)

object CheckTypeCodeV6 extends CheckTypeCodeTemplate(1018)

object CheckSerializableTypeCode extends ValidationRule(1009,
"Check the data values of the type (given by type code) can be serialized")
with SoftForkWhenReplaced {
override protected lazy val settings: SigmaValidationSettings = coreSettings
override protected def settings: SigmaValidationSettings = coreSettings

/** Creates an exception which is used as a cause when throwing a ValidationException. */
def throwValidationException(typeCode: Byte): Nothing = {
Expand Down Expand Up @@ -141,7 +149,7 @@ object ValidationRules {
object CheckTypeWithMethods extends ValidationRule(1010,
"Check the type (given by type code) supports methods")
with SoftForkWhenCodeAdded {
override protected lazy val settings: SigmaValidationSettings = coreSettings
override protected def settings: SigmaValidationSettings = coreSettings

final def apply[T](typeCode: Byte, cond: Boolean): Unit = {
checkRule()
Expand All @@ -160,7 +168,7 @@ object ValidationRules {
*/
object CheckPositionLimit extends ValidationRule(1014,
"Check that the Reader has not exceeded the position limit.") with SoftForkWhenReplaced {
override protected lazy val settings: SigmaValidationSettings = coreSettings
override protected def settings: SigmaValidationSettings = coreSettings

/** Wraps the given cause into [[ValidationException]] and throws it. */
def throwValidationException(cause: ReaderPositionLimitExceeded): Nothing = {
Expand All @@ -183,21 +191,38 @@ object ValidationRules {
}
}

private val ruleSpecs: Seq[ValidationRule] = Seq(
private val ruleSpecsV5: Seq[ValidationRule] = Seq(
CheckPrimitiveTypeCode,
CheckTypeCode,
CheckSerializableTypeCode,
CheckTypeWithMethods,
CheckPositionLimit
)

private val ruleSpecsV6: Seq[ValidationRule] = Seq(
CheckPrimitiveTypeCodeV6,
CheckTypeCodeV6,
CheckSerializableTypeCode,
CheckTypeWithMethods,
CheckPositionLimit
)

private def ruleSpecs: Seq[ValidationRule] = {
if(VersionContext.current.isV6Activated) {
ruleSpecsV6
} else {
ruleSpecsV5
}
}

/** Validation settings that correspond to the current version of the ErgoScript implementation.
* Different version of the code will have a different set of rules here.
* This variable is globally available and can be use wherever checking of the rules is necessary.
* This is immutable data structure, it can be augmented with RuleStates from block extension
* sections of the blockchain, but that augmentation is only available in stateful context.
*/
val coreSettings: SigmaValidationSettings = new MapSigmaValidationSettings({
// todo: versioned cache here for efficiency
def coreSettings: SigmaValidationSettings = new MapSigmaValidationSettings({
val map = ruleSpecs.map(r => r.id -> (r, EnabledRule)).toMap
assert(map.size == ruleSpecs.size, s"Duplicate ruleIds ${ruleSpecs.groupBy(_.id).filter(g => g._2.length > 1)}")
map
Expand Down
Loading
Loading