-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #758 from ScorexFoundation/v5.0-finalize
Release Candidate v5.0
- Loading branch information
Showing
126 changed files
with
9,469 additions
and
2,757 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package sigmastate | ||
|
||
import sigmastate.VersionContext.JitActivationVersion | ||
|
||
import scala.util.DynamicVariable | ||
|
||
/** Represent currently activated protocol version and currently executed ErgoTree version. | ||
* | ||
* This parameters, once set in DynamicVariable can be accessed everywhere on the current | ||
* 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") | ||
|
||
/** @return true, if the activated script version of Ergo protocol on the network is | ||
* greater than v1. */ | ||
def isJitActivated: Boolean = activatedVersion >= JitActivationVersion | ||
|
||
/** @return true, if the version of ErgoTree being executed greater than v1. */ | ||
def isErgoTreeVersionGreaterV1: Boolean = | ||
ergoTreeVersion >= JitActivationVersion | ||
} | ||
|
||
object VersionContext { | ||
/** Maximum version of ErgoTree supported by this interpreter release. | ||
* See version bits in `ErgoTree.header` for more details. | ||
* This value should be increased with each new protocol update via soft-fork. | ||
* The following values are used for current and upcoming forks: | ||
* - version 3.x this value must be 0 | ||
* - in v4.0 must be 1 | ||
* - in v5.x must be 2 | ||
* etc. | ||
*/ | ||
val MaxSupportedScriptVersion: Byte = 2 // supported versions 0, 1, 2 | ||
|
||
/** The first version of ErgoTree starting from which the JIT costing interpreter must be used. | ||
* It must also be used for all subsequent versions (3, 4, etc). | ||
*/ | ||
val JitActivationVersion: Byte = 2 | ||
|
||
private val _defaultContext = VersionContext( | ||
activatedVersion = 1/* v4.x */, | ||
ergoTreeVersion = 1 | ||
) | ||
|
||
/** Universally accessible version context which is used to version the code | ||
* across the whole repository. | ||
* | ||
* The default value represent activated Ergo protocol and highest ErgoTree version. | ||
*/ | ||
private val _versionContext: DynamicVariable[VersionContext] = | ||
new DynamicVariable[VersionContext](_defaultContext) | ||
|
||
/** Returns the current VersionContext attached to the current thread. | ||
* Each thread can have only one current version context at any time, which can be | ||
* changed using `withVersions` method. | ||
* | ||
* @see withVersions() | ||
*/ | ||
def current: VersionContext = { | ||
val ctx = _versionContext.value | ||
if (ctx == null) | ||
throw new IllegalStateException( | ||
s"VersionContext is not specified on thread ${Thread.currentThread().getId}") | ||
ctx | ||
} | ||
|
||
/** Executes the given block under the given version context attached to the current thread. | ||
* | ||
* The typical usage is to use `VersionContext.withVersions(activatedVersion, | ||
* treeVersion) {...}` when the block of code needs to be executed with the given | ||
* versions. | ||
* | ||
* For example, sigmastate.Interpreter uses it to execute operations according to the | ||
* 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) | ||
|
||
/** Checks the version context has the given versions*/ | ||
def checkVersions(activatedVersion: Byte, ergoTreeVersion: Byte) = { | ||
val ctx = VersionContext.current | ||
if (ctx.activatedVersion != activatedVersion || ctx.ergoTreeVersion != ergoTreeVersion) { | ||
val expected = VersionContext(activatedVersion, ergoTreeVersion) | ||
throw new IllegalStateException( | ||
s"Global VersionContext.current = ${ctx} while expected $expected.") | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package sigmastate | ||
|
||
import scalan.util.CollectionUtil | ||
|
||
import scala.reflect.ClassTag | ||
|
||
object util { | ||
/** Maximum length of an allocatable array. */ | ||
val MaxArrayLength: Int = 100000 | ||
|
||
private def checkLength[A](len: Int)(implicit tA: ClassTag[A]) = { | ||
if (len > MaxArrayLength) | ||
throw new RuntimeException( | ||
s"Cannot allocate array of $tA with $len items: max limit is $MaxArrayLength") | ||
} | ||
|
||
/** Allocates a new array with `len` items of type `A`. | ||
* Should be used instead of `new Array[A](n)` or `Array.ofDim[A](n)` | ||
*/ | ||
final def safeNewArray[A](len: Int)(implicit tA: ClassTag[A]): Array[A] = { | ||
checkLength[A](len) | ||
new Array[A](len) | ||
} | ||
|
||
/** Concatenate two arrays checking length limit of the resulting array. | ||
* Should be used in implementation of Coll operations of v5.0 and above. */ | ||
final def safeConcatArrays_v5[A](arr1: Array[A], arr2: Array[A])(implicit tA: ClassTag[A]): Array[A] = { | ||
checkLength[A](arr1.length + arr2.length) | ||
CollectionUtil.concatArrays_v5(arr1, arr2) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package sigmastate | ||
|
||
import spire.syntax.all.cfor | ||
|
||
import scala.util.DynamicVariable | ||
|
||
trait VersionTesting { | ||
|
||
protected val activatedVersions: Seq[Byte] = | ||
(0 to VersionContext.MaxSupportedScriptVersion).map(_.toByte).toArray[Byte] | ||
|
||
private[sigmastate] val _currActivatedVersion = new DynamicVariable[Byte](0) | ||
def activatedVersionInTests: Byte = _currActivatedVersion.value | ||
|
||
/** Checks if the current activated script version used in tests corresponds to v4.x. */ | ||
def isActivatedVersion4: Boolean = activatedVersionInTests < VersionContext.JitActivationVersion | ||
|
||
val ergoTreeVersions: Seq[Byte] = | ||
(0 to VersionContext.MaxSupportedScriptVersion).map(_.toByte).toArray[Byte] | ||
|
||
private[sigmastate] val _currErgoTreeVersion = new DynamicVariable[Byte](0) | ||
|
||
/** Current ErgoTree version assigned dynamically. */ | ||
def ergoTreeVersionInTests: Byte = _currErgoTreeVersion.value | ||
|
||
/** Executes the given block for each combination of _currActivatedVersion and | ||
* _currErgoTreeVersion assigned to dynamic variables. | ||
*/ | ||
def forEachScriptAndErgoTreeVersion | ||
(activatedVers: Seq[Byte], ergoTreeVers: Seq[Byte]) | ||
(block: => Unit): Unit = { | ||
cfor(0)(_ < activatedVers.length, _ + 1) { i => | ||
val activatedVersion = activatedVers(i) | ||
// setup each activated version | ||
_currActivatedVersion.withValue(activatedVersion) { | ||
|
||
cfor(0)( | ||
i => i < ergoTreeVers.length && ergoTreeVers(i) <= activatedVersion, | ||
_ + 1) { j => | ||
val treeVersion = ergoTreeVers(j) | ||
// for each tree version up to currently activated, set it up and execute block | ||
_currErgoTreeVersion.withValue(treeVersion)(block) | ||
} | ||
|
||
} | ||
} | ||
} | ||
|
||
/** Helper method which executes the given `block` once for each `activatedVers`. | ||
* The method sets the dynamic variable activatedVersionInTests with is then available | ||
* in the block. | ||
*/ | ||
def forEachActivatedScriptVersion(activatedVers: Seq[Byte])(block: => Unit): Unit = { | ||
cfor(0)(_ < activatedVers.length, _ + 1) { i => | ||
val activatedVersion = activatedVers(i) | ||
_currActivatedVersion.withValue(activatedVersion)(block) | ||
} | ||
} | ||
|
||
/** Helper method which executes the given `block` once for each `ergoTreeVers`. | ||
* The method sets the dynamic variable ergoTreeVersionInTests with is then available | ||
* in the block. | ||
*/ | ||
def forEachErgoTreeVersion(ergoTreeVers: Seq[Byte])(block: => Unit): Unit = { | ||
cfor(0)(_ < ergoTreeVers.length, _ + 1) { i => | ||
val version = ergoTreeVers(i) | ||
_currErgoTreeVersion.withValue(version)(block) | ||
} | ||
} | ||
|
||
val printVersions: Boolean = false | ||
|
||
protected def testFun_Run(testName: String, testFun: => Any): Unit = { | ||
def msg = s"""property("$testName")(ActivatedVersion = $activatedVersionInTests; ErgoTree version = $ergoTreeVersionInTests)""" | ||
if (printVersions) println(msg) | ||
try testFun | ||
catch { | ||
case t: Throwable => | ||
if (!printVersions) { | ||
// wasn't printed, print it now | ||
println(msg) | ||
} | ||
throw t | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.