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] Serialization versioning #1041

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
21 changes: 9 additions & 12 deletions core/shared/src/main/scala/sigma/VersionContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ import scala.util.DynamicVariable
* thread.
*
* @param activatedVersion Currently activated script version == Block.headerVersion - 1
* @param ergoTreeVersion version of the currently executed ErgoTree
*
* @see
*/
case class VersionContext(activatedVersion: Byte, ergoTreeVersion: Byte) {
require(ergoTreeVersion <= activatedVersion,
s"In a valid VersionContext ergoTreeVersion must never exceed activatedVersion: $this")
case class VersionContext(activatedVersion: Byte) {

/** @return true, if the activated script version of Ergo protocol on the network is
* greater than v1. */
Expand Down Expand Up @@ -51,8 +48,7 @@ object VersionContext {
val V6SoftForkVersion: Byte = 3

private val _defaultContext = VersionContext(
activatedVersion = 1 /* v4.x */,
ergoTreeVersion = 1
activatedVersion = 1
)

/** Universally accessible version context which is used to version the code
Expand Down Expand Up @@ -87,21 +83,22 @@ object VersionContext {
* necessary versions of Ergo protocol and ErgoTree.
*
* @param activatedVersion Currently activated script version == Block.headerVersion - 1
* @param ergoTreeVersion ErgoTree version to be set on the current thread
* @param block block of code to execute
* @return result of block execution
*/
def withVersions[T](activatedVersion: Byte, ergoTreeVersion: Byte)(block: => T): T =
_versionContext.withValue(VersionContext(activatedVersion, ergoTreeVersion))(block)
def withScriptVersion[T](activatedVersion: Byte)(block: => T): T =
_versionContext.withValue(VersionContext(activatedVersion))(block)

/** Checks the version context has the given versions*/
def checkVersions(activatedVersion: Byte, ergoTreeVersion: Byte) = {
def checkVersion(activatedVersion: Byte): Unit = {
val ctx = VersionContext.current
if (ctx.activatedVersion != activatedVersion || ctx.ergoTreeVersion != ergoTreeVersion) {
val expected = VersionContext(activatedVersion, ergoTreeVersion)
if (ctx.activatedVersion != activatedVersion) {
val expected = VersionContext(activatedVersion)
throw new IllegalStateException(
s"Global VersionContext.current = ${ctx} while expected $expected.")
}
}

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

}
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 =>
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) =>
val o = v.asInstanceOf[Option[elemType.WrappedType]]
w.putOption(o){case (w, v) =>
serialize(v, elemType, w)
Expand Down
4 changes: 2 additions & 2 deletions core/shared/src/test/scala/sigma/CollsTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class CollsTests extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers
equalLengthMapped(pairs, squared(inc)) // due to problem with append
}
}
VersionContext.withVersions(VersionContext.JitActivationVersion, VersionContext.JitActivationVersion) {
VersionContext.withScriptVersion(VersionContext.JitActivationVersion) {
// TODO v5.0: make it work
// equalLengthMapped(pairs, squared(inc)) // problem fixed in v5.0
}
Expand All @@ -75,7 +75,7 @@ class CollsTests extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers
equalLengthMapped(pairs.append(pairs), squared(inc)) // due to problem with append
}
}
VersionContext.withVersions(VersionContext.JitActivationVersion, VersionContext.JitActivationVersion) {
VersionContext.withScriptVersion(VersionContext.JitActivationVersion) {
// TODO v5.0: make it work
// equalLengthMapped(pairs.append(pairs), squared(inc)) // problem fixed in v5.0
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ trait VersionTestingProperty extends AnyPropSpec with VersionTesting {
(implicit pos: Position): Unit = {
super.property(testName, testTags:_*) {
forEachScriptAndErgoTreeVersion(activatedVersions, ergoTreeVersions) {
VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) {
VersionContext.withScriptVersion(activatedVersionInTests) {
testFun_Run(testName, testFun)
}
}
Expand Down
3 changes: 2 additions & 1 deletion data/shared/src/main/scala/sigma/ast/ErgoTree.scala
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ object ErgoTree {
* 3) write the `tree` to the Writer's buffer obtaining `treeBytes`;
* 4) deserialize `tree` with ConstantPlaceholders.
*
* @param headerFlags additional header flags to combine with
* @param header additional header flags to combine with
* ConstantSegregationHeader flag.
* @param prop expression to be transformed into ErgoTree
* */
Expand Down Expand Up @@ -411,4 +411,5 @@ object ErgoTree {
def fromBytes(bytes: Array[Byte]): ErgoTree = {
ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ object DataSerializer extends CoreDataSerializer {
case SBox =>
val b = v.asInstanceOf[CBox]
ErgoBox.sigmaSerializer.serialize(b.ebox, w.asInstanceOf[SigmaByteWriter])
case SHeader if VersionContext.current.isV6SoftForkActivated =>
case SHeader =>
val h = v.asInstanceOf[CHeader]
ErgoHeader.sigmaSerializer.serialize(h.ergoHeader, w.asInstanceOf[SigmaByteWriter])
case _ =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,6 @@ class ErgoTreeSerializer {
}

def deserializeErgoTree(r: SigmaByteReader, maxTreeSizeBytes: Int): ErgoTree = {
deserializeErgoTree(r, maxTreeSizeBytes, true)
}

private[sigma] def deserializeErgoTree(r: SigmaByteReader, maxTreeSizeBytes: Int, checkType: Boolean): ErgoTree = {
val startPos = r.position
val previousPositionLimit = r.positionLimit
r.positionLimit = r.position + maxTreeSizeBytes
Expand All @@ -158,9 +154,7 @@ class ErgoTreeSerializer {
val isUsingBlockchainContext = r.wasUsingBlockchainContext // == true if there was a node using the blockchain context
r.wasUsingBlockchainContext = wasUsingBlockchainContext_saved

if (checkType) {
CheckDeserializedScriptIsSigmaProp(root)
}
CheckDeserializedScriptIsSigmaProp(root)

r.constantStore = previousConstantStore
// now we know the end position of propositionBytes, read them all at once into array
Expand Down Expand Up @@ -395,4 +389,4 @@ class ErgoTreeSerializer {

object ErgoTreeSerializer {
val DefaultSerializer = new ErgoTreeSerializer
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,10 @@ class CErgoTreeEvaluator(

/** Evaluates the given expression in the given data environment. */
def eval(env: DataEnv, exp: SValue): Any = {
VersionContext.checkVersions(context.activatedScriptVersion, context.currentErgoTreeVersion)
VersionContext.checkVersion(context.activatedScriptVersion)
require(context.currentErgoTreeVersion <= context.activatedScriptVersion,
s"ergoTreeVersion must never exceed activatedVersion: $this")

CErgoTreeEvaluator.currentEvaluator.withValue(this) {
exp.evalTo[Any](env)(this)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ trait Interpreter {
ctx: CTX,
env: ScriptEnv): ReductionResult = {
val context = ctx.withErgoTreeVersion(ergoTree.version).asInstanceOf[CTX]
VersionContext.withVersions(context.activatedScriptVersion, ergoTree.version) {
VersionContext.withScriptVersion(context.activatedScriptVersion) {
val prop = propositionFromErgoTree(ergoTree, context)

val res = prop match {
Expand All @@ -217,7 +217,7 @@ trait Interpreter {
ReductionResult(sb, resCost)
case _ if !ergoTree.hasDeserialize =>
val ctx = context.asInstanceOf[ErgoLikeContext]
val res = VersionContext.withVersions(ctx.activatedScriptVersion, ergoTree.version) {
val res = VersionContext.withScriptVersion(ctx.activatedScriptVersion) {
CErgoTreeEvaluator.evalToCrypto(ctx, ergoTree, evalSettings)
}
res
Expand All @@ -239,16 +239,15 @@ trait Interpreter {
/** Performs reduction of proposition which contains deserialization operations. */
private def reductionWithDeserialize(ergoTree: ErgoTree,
prop: SigmaPropValue,
context: CTX,
env: ScriptEnv): ReductionResult = {
context: CTX): ReductionResult = {
implicit val vs: SigmaValidationSettings = context.validationSettings
val res = VersionContext.withVersions(context.activatedScriptVersion, ergoTree.version) {
val res = VersionContext.withScriptVersion(context.activatedScriptVersion) {
val deserializeSubstitutionCost = java7.compat.Math.multiplyExact(ergoTree.bytes.length, CostPerTreeByte)
val currCost = addCostChecked(context.initCost, deserializeSubstitutionCost, context.costLimit)
val context1 = context.withInitCost(currCost).asInstanceOf[CTX]
val (propTree, context2) = trySoftForkable[(SigmaPropValue, CTX)](whenSoftFork = (TrueSigmaProp, context1)) {
// Before ErgoTree V3 the deserialization cost was not added to the total cost
applyDeserializeContextJITC(if (VersionContext.current.activatedVersion >= VersionContext.V6SoftForkVersion) {
applyDeserializeContextJITC(if (VersionContext.current.isV6SoftForkActivated) {
context1
} else {
context
Expand Down Expand Up @@ -359,7 +358,7 @@ trait Interpreter {
case Some(resWhenSoftFork) => return Success(resWhenSoftFork)
case None => // proceed normally
}
VersionContext.withVersions(context.activatedScriptVersion, ergoTree.version) {
VersionContext.withScriptVersion(context.activatedScriptVersion) {
// NOTE, ergoTree.complexity is not acrued to the cost in v5.0
val reduced = fullReduction(ergoTree, context, env)
reduced.value match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils {
case None => // proceed normally
}

VersionContext.withVersions(context.activatedScriptVersion, ergoTree.version) {
VersionContext.withScriptVersion(context.activatedScriptVersion) {
val (resValue, resCost) = {
val reduced = fullReduction(ergoTree, context, env)
val fullCost = addCryptoCost(reduced.value, reduced.cost, context.costLimit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class DataSerializerSpecification extends SerializationSpecification {

withVersion match {
case Some(ver) =>
VersionContext.withVersions(ver, 1) {
VersionContext.withScriptVersion(ver) {
test()
}
case None =>
Expand Down Expand Up @@ -122,14 +122,14 @@ class DataSerializerSpecification extends SerializationSpecification {
val tT = Evaluation.stypeToRType(tpe)

an[Exception] should be thrownBy (
VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
VersionContext.withScriptVersion((VersionContext.V6SoftForkVersion - 1).toByte) {
forAll { in: T#WrappedType =>
roundtrip[SType](Some(in).asWrappedType, SOption(tpe))
roundtrip[SOption[SCollection[T]]](Some(Colls.fromItems(in)(tT)), SOption(SCollectionType(tpe)))
}
})

VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
VersionContext.withScriptVersion(VersionContext.V6SoftForkVersion) {
forAll { in: T#WrappedType =>
roundtrip[SType](Some(in).asWrappedType, SOption(tpe))
roundtrip[SOption[T]](None, SOption(tpe))
Expand Down Expand Up @@ -189,12 +189,12 @@ class DataSerializerSpecification extends SerializationSpecification {
}

property("nuanced versioned test for header roundtrip") {
VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
VersionContext.withScriptVersion(VersionContext.V6SoftForkVersion) {
forAll { x: Header => roundtrip[SHeader.type](x, SHeader) }
}

an[SerializerException] should be thrownBy (
VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
VersionContext.withScriptVersion((VersionContext.V6SoftForkVersion - 1).toByte) {
val h = headerGen.sample.get
roundtrip[SHeader.type](h, SHeader)
})
Expand All @@ -219,7 +219,7 @@ class DataSerializerSpecification extends SerializationSpecification {
Colls.emptyColl
)

VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
VersionContext.withScriptVersion(VersionContext.V6SoftForkVersion) {
roundtrip[SHeader.type](header, SHeader)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ class MethodCallSerializerSpecification extends SerializationSpecification {
roundTripTest(expr)
}

VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
VersionContext.withScriptVersion(VersionContext.V6SoftForkVersion) {
code
}

a[SerializerException] should be thrownBy (
VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
VersionContext.withScriptVersion((VersionContext.V6SoftForkVersion - 1).toByte) {
code
}
)
Expand All @@ -65,12 +65,12 @@ class MethodCallSerializerSpecification extends SerializationSpecification {
roundTripTest(expr)
}

VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
VersionContext.withScriptVersion(VersionContext.V6SoftForkVersion) {
code
}

an[ValidationException] should be thrownBy (
VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
VersionContext.withScriptVersion((VersionContext.V6SoftForkVersion - 1).toByte) {
code
}
)
Expand All @@ -87,12 +87,12 @@ class MethodCallSerializerSpecification extends SerializationSpecification {
roundTripTest(expr)
}

VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
VersionContext.withScriptVersion(VersionContext.V6SoftForkVersion) {
code
}

an[ValidationException] should be thrownBy (
VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
VersionContext.withScriptVersion((VersionContext.V6SoftForkVersion - 1).toByte) {
code
}
)
Expand All @@ -111,12 +111,12 @@ class MethodCallSerializerSpecification extends SerializationSpecification {

println(SGlobalMethods.deserializeToMethod.hasExplicitTypeArgs)

VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
VersionContext.withScriptVersion(VersionContext.V6SoftForkVersion) {
code
}

an[Exception] should be thrownBy (
VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
VersionContext.withScriptVersion((VersionContext.V6SoftForkVersion - 1).toByte) {
code
})
}
Expand All @@ -133,12 +133,12 @@ class MethodCallSerializerSpecification extends SerializationSpecification {
}

// should be ok
VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
VersionContext.withScriptVersion(VersionContext.V6SoftForkVersion) {
code
}

an[ValidationException] should be thrownBy (
VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
VersionContext.withScriptVersion((VersionContext.V6SoftForkVersion - 1).toByte) {
code
})
}
Expand All @@ -154,12 +154,12 @@ class MethodCallSerializerSpecification extends SerializationSpecification {
roundTripTest(expr)
}

VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
VersionContext.withScriptVersion(VersionContext.V6SoftForkVersion) {
code
}

an[ValidationException] should be thrownBy (
VersionContext.withVersions((VersionContext.V6SoftForkVersion - 1).toByte, 1) {
VersionContext.withScriptVersion((VersionContext.V6SoftForkVersion - 1).toByte) {
code
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ trait SerializationSpecification extends AnyPropSpec
}
withVersion match {
case Some(ver) =>
VersionContext.withVersions(ver, 0) {
VersionContext.withScriptVersion(ver) {
test()
}
case None =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ trait CrossVersionProps extends AnyPropSpecLike with TestsBase {
System.gc()
}
forEachScriptAndErgoTreeVersion(activatedVersions, ergoTreeVersions) {
VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) {
VersionContext.withScriptVersion(activatedVersionInTests) {
testFun_Run(testName, testFun)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class BasicOpsTests extends AnyFunSuite with ContractsTestkit with Matchers {
coster = accumulator, DefaultProfiler, es)

val msg = Colls.fromArray(Base16.decode("0a101b8c6a4f2e").get)
VersionContext.withVersions(VersionContext.V6SoftForkVersion, VersionContext.V6SoftForkVersion) {
VersionContext.withScriptVersion(VersionContext.V6SoftForkVersion) {
val res = MethodCall(Global, SGlobalMethods.xorMethod,
IndexedSeq(ByteArrayConstant(msg), ByteArrayConstant(msg)), Map.empty)
.evalTo[sigma.Coll[Byte]](Map.empty)(evaluator)
Expand Down Expand Up @@ -125,7 +125,7 @@ class BasicOpsTests extends AnyFunSuite with ContractsTestkit with Matchers {
constants = ErgoTree.EmptyConstants,
coster = accumulator, DefaultProfiler, es)

VersionContext.withVersions(VersionContext.V6SoftForkVersion, VersionContext.V6SoftForkVersion) {
VersionContext.withScriptVersion(VersionContext.V6SoftForkVersion) {
val res = MethodCall(Global, SGlobalMethods.powHitMethod,
IndexedSeq(IntConstant(k), ByteArrayConstant(msg), ByteArrayConstant(nonce),
ByteArrayConstant(hbs), IntConstant(N)), Map.empty)
Expand Down
Loading
Loading