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

NODE-2528 Typed errors replacing exceptions in RIDE sources #3896

Merged
merged 13 commits into from
Nov 28, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AddressFromPublicKeyBenchmark {
@State(Scope.Benchmark)
class PkSt extends EthHelpers {
val ds = DirectiveSet(V6, Account, Expression).fold(null, identity)
val ctx = lazyContexts((ds, true, true)).value().evaluationContext(EnvironmentFunctionsBenchmark.environment)
val ctx = lazyContexts((ds, true, true, true)).value().evaluationContext(EnvironmentFunctionsBenchmark.environment)

val wavesPk = ByteStr(curve25519.generateKeypair._2)
val exprWaves = TestCompiler(V6).compileExpression(s"addressFromPublicKey(base58'$wavesPk')").expr.asInstanceOf[EXPR]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ class BigIntOpsBenchmark {
@State(Scope.Benchmark)
class BigIntOpsSt {
val ds = DirectiveSet(StdLibVersion.VersionDic.all.max, Account, Expression).fold(null, identity)
val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())
val ctx = lazyContexts((ds, true, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())

val max = CONST_BIGINT(PureContext.BigIntMax)
val prevMax = CONST_BIGINT(PureContext.BigIntMax - 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class BigIntToStringBenchmark {
@State(Scope.Benchmark)
class BigIntToStringSt {
val ds = DirectiveSet(V5, Account, Expression).fold(null, identity)
val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())
val ctx = lazyContexts((ds, true, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())

val expr = FUNCTION_CALL(
Native(BIGINT_TO_STRING),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class FoldBenchmark {
@State(Scope.Benchmark)
class FoldSt {
val ds = DirectiveSet(V5, Account, Expression).fold(null, identity)
val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())
val ctx = lazyContexts((ds, true, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())

val function = "func f(acc: Boolean, elem: ByteVector) = acc && sigVerify(elem, base58'', base58'')"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class FractionIntBenchmark {
@State(Scope.Benchmark)
class St {
val ds = DirectiveSet(V6, Account, Expression).fold(null, identity)
val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())
val ctx = lazyContexts((ds, true, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())

val max = Long.MaxValue
val maxSqrt = 3037000499L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class PowBigIntBenchmark {
@State(Scope.Benchmark)
class PowBigIntSt {
val ds = DirectiveSet(V5, Account, Expression).fold(null, identity)
val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())
val ctx = lazyContexts((ds, true, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())

val max = PureContext.BigIntMax
val min = PureContext.BigIntMin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class PowIntBenchmark {
@State(Scope.Benchmark)
class PowIntSt {
val ds = DirectiveSet(V5, Account, Expression).fold(null, identity)
val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())
val ctx = lazyContexts((ds, true, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())

val max = Long.MaxValue

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ class PureFunctionsRebenchmark {

object PureFunctionsRebenchmark {
val context: EvaluationContext[Environment, Id] =
lazyContexts((DirectiveSet(V5, Account, Expression).explicitGet(), true, true))()
lazyContexts((DirectiveSet(V5, Account, Expression).explicitGet(), true, true, true))()
.evaluationContext(Common.emptyBlockchainEnvironment())

val eval: EXPR => (Log[Id], Int, Either[ExecutionError, EVALUATED]) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class SqrtCbrtBigIntBenchmark {
@State(Scope.Benchmark)
class SqrtBigIntSt {
val ds = DirectiveSet(V5, Account, Expression).fold(null, identity)
val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())
val ctx = lazyContexts((ds, true, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())

val max = PureContext.BigIntMax
val min = PureContext.BigIntMin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class SqrtIntBenchmark {
@State(Scope.Benchmark)
class SqrtIntSt {
val ds = DirectiveSet(V5, Account, Expression).fold(null, identity)
val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())
val ctx = lazyContexts((ds, true, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment())

val expr1 = compile(s"pow(${Long.MaxValue}, 0, 5, 1, 8, DOWN)")
val expr2 = compile(s"pow(${Long.MaxValue}, 8, 5, 1, 8, DOWN)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ object FastBase58 extends BaseXXEncDec {
outArray(outIndex) = longValue & 0xffffffffL
}

// called only from Try structure, see BaseXXEncDec.tryDecode(str: String)
if (base58EncMask > 0) throw new IllegalArgumentException("Output number too big (carry to the next int32)")
if ((outArray(0) & zeroMask) != 0) throw new IllegalArgumentException("Output number too big (last int32 filled too far)")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,22 @@ package object utils {
): Coeval[(Either[ValidationError, (EVALUATED, Log[Id])], Int)] = ???
}

val lazyContexts: Map[(DirectiveSet, Boolean, Boolean), Coeval[CTX[Environment]]] =
val lazyContexts: Map[(DirectiveSet, Boolean, Boolean, Boolean), Coeval[CTX[Environment]]] =
(for {
version <- DirectiveDictionary[StdLibVersion].all
scriptType <- DirectiveDictionary[ScriptType].all
contentType <- DirectiveDictionary[ContentType].all if contentType != DApp || (contentType == DApp && version >= V3 && scriptType == Account)
useNewPowPrecision <- Seq(false, true)
fixBigScriptField <- Seq(false, true)
typedError <- Seq(false, true)
} yield {
val ds = DirectiveSet(version, scriptType, contentType).explicitGet()
val ctx = Coeval.evalOnce(
PureContext.build(version, useNewPowPrecision).withEnvironment[Environment] |+|
CryptoContext.build(Global, version).withEnvironment[Environment] |+|
WavesContext.build(Global, ds, fixBigScriptField)
CryptoContext.build(Global, version, typedError).withEnvironment[Environment] |+|
WavesContext.build(Global, ds, fixBigScriptField, typedError)
)
(ds, useNewPowPrecision, fixBigScriptField) -> ctx
(ds, useNewPowPrecision, fixBigScriptField, typedError) -> ctx
}).toMap

private val lazyFunctionCosts: Map[DirectiveSet, Coeval[Map[FunctionHeader, Coeval[Long]]]] =
Expand Down Expand Up @@ -165,7 +166,7 @@ package object utils {
ScriptType.isAssetScript(isTokenContext),
if (isContract) DApp else Expression
)
lazyContexts((ds.explicitGet(), true, true)).value()
lazyContexts((ds.explicitGet(), true, true, true)).value()
}

def compilerContext(version: StdLibVersion, cType: ContentType, isAssetScript: Boolean): CompilerContext = {
Expand All @@ -174,7 +175,7 @@ package object utils {
}

def compilerContext(ds: DirectiveSet): CompilerContext =
lazyContexts((ds.copy(imports = Imports()), true, true))().compilerContext
lazyContexts((ds.copy(imports = Imports()), true, true, true))().compilerContext

def getDecompilerContext(v: StdLibVersion, cType: ContentType): DecompilerContext =
combinedContext((v, cType)).decompilerContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ object BaseGlobal {
def apply(n: Int): T =
if (from + n < until) arr(from + n)
else throw new ArrayIndexOutOfBoundsException(n)
// should be never thrown due to passing Random.nextInt(arr.size) at the single point of call

def partitionInPlace(p: T => Boolean): (ArrayView[T], ArrayView[T]) = {
var upper = until - 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ class EvaluatorV2(
evaluated
} -> unusedComplexity
}
case f: Simple[Environment] => Coeval((f.evaluate(ctx.ec.environment, args), limit - cost))
case f: Simple[Environment] =>
Coeval((f.evaluate(ctx.ec.environment, args), limit - cost))
}
for {
(result, unusedComplexity) <- EvaluationResult(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import cats.implicits.*
import cats.{Id, Monad}
import com.wavesplatform.common.merkle.Merkle.createRoot
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.lang.{ExecutionError, CommonError}
import com.wavesplatform.lang.directives.values.{StdLibVersion, V3, *}
import com.wavesplatform.lang.directives.values.*
import com.wavesplatform.lang.v1.compiler.Terms.*
import com.wavesplatform.lang.v1.compiler.Types.*
import com.wavesplatform.lang.v1.compiler.{CompilerContext, Terms}
Expand All @@ -15,8 +14,10 @@ import com.wavesplatform.lang.v1.evaluator.FunctionIds.*
import com.wavesplatform.lang.v1.evaluator.ctx.impl.crypto.RSA.DigestAlgorithm
import com.wavesplatform.lang.v1.evaluator.ctx.{BaseFunction, EvaluationContext, NativeFunction}
import com.wavesplatform.lang.v1.{BaseGlobal, CTX}
import com.wavesplatform.lang.{CommonError, ExecutionError}

import scala.collection.mutable
import scala.util.Try

object CryptoContext {

Expand All @@ -30,7 +31,7 @@ object CryptoContext {
UNION.create(rsaHashAlgs(v), if (v > V3 && v < V6) Some("RsaDigestAlgs") else None)

private val rsaHashLib = {
import com.wavesplatform.lang.v1.evaluator.ctx.impl.crypto.RSA._
import com.wavesplatform.lang.v1.evaluator.ctx.impl.crypto.RSA.*
rsaTypeNames.zip(List(NONE, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, SHA3224, SHA3256, SHA3384, SHA3512)).toMap
}

Expand All @@ -41,17 +42,17 @@ object CryptoContext {
private def digestAlgValue(tpe: CASETYPEREF): ContextfulVal[NoContext] =
ContextfulVal.pure(CaseObj(tpe, Map.empty))

def build(global: BaseGlobal, version: StdLibVersion): CTX[NoContext] =
def build(global: BaseGlobal, version: StdLibVersion, typedError: Boolean = true): CTX[NoContext] =
ctxCache.getOrElse(
(global, version),
(global, version, typedError),
ctxCache.synchronized {
ctxCache.getOrElseUpdate((global, version), buildNew(global, version))
ctxCache.getOrElseUpdate((global, version, typedError), buildNew(global, version, typedError))
}
)

private val ctxCache = mutable.AnyRefMap.empty[(BaseGlobal, StdLibVersion), CTX[NoContext]]
private val ctxCache = mutable.AnyRefMap.empty[(BaseGlobal, StdLibVersion, Boolean), CTX[NoContext]]

private def buildNew(global: BaseGlobal, version: StdLibVersion): CTX[NoContext] = {
private def buildNew(global: BaseGlobal, version: StdLibVersion, typedError: Boolean): CTX[NoContext] = {
def functionFamily(
startId: Short,
nameByLimit: Int => String,
Expand Down Expand Up @@ -359,7 +360,7 @@ object CryptoContext {
case xs => notImplemented[Id, EVALUATED](s"checkMerkleProof(merkleRoot: ByteVector, merkleProof: ByteVector, valueBytes: ByteVector)", xs)
}

val createMerkleRootF: BaseFunction[NoContext] =
def createMerkleRootF(typedError: Boolean): BaseFunction[NoContext] =
NativeFunction(
"createMerkleRoot",
30,
Expand All @@ -370,16 +371,16 @@ object CryptoContext {
("index", LONG)
) {
case xs @ ARR(proof) :: CONST_BYTESTR(value) :: CONST_LONG(index) :: Nil =>
val filteredProofs = proof.collect {
case bs @ CONST_BYTESTR(v) if v.size == 32 => bs
}

if (value.size == 32 && proof.length <= 16 && filteredProofs.size == proof.size) {
CONST_BYTESTR(ByteStr(createRoot(value.arr, Math.toIntExact(index), filteredProofs.reverse.map(_.bs.arr))))
val sizeCheckedProofs = proof.collect { case bs @ CONST_BYTESTR(v) if v.size == 32 => bs }
if (value.size == 32 && proof.length <= 16 && sizeCheckedProofs.size == proof.size) {
def r = createRoot(value.arr, Math.toIntExact(index), sizeCheckedProofs.reverse.map(_.bs.arr))
(if (typedError) Try(r).toEither else Right(r))
.leftMap(e => (if (e.getMessage != null) e.getMessage else "error"): ExecutionError)
.flatMap(r => CONST_BYTESTR(ByteStr(r)))
} else {
notImplemented[Id, EVALUATED](s"createMerkleRoot(merkleProof: ByteVector, valueBytes: ByteVector)", xs)
notImplemented[Id, EVALUATED](s"createMerkleRoot(merkleProof: ByteVector, valueBytes: ByteVector, index: Int)", xs)
}
case xs => notImplemented[Id, EVALUATED](s"createMerkleRoot(merkleProof: ByteVector, valueBytes: ByteVector)", xs)
case xs => notImplemented[Id, EVALUATED](s"createMerkleRoot(merkleProof: ByteVector, valueBytes: ByteVector, index: Int)", xs)
}

def toBase16StringF(checkLength: Boolean): BaseFunction[NoContext] = NativeFunction("toBase16String", 10, TOBASE16, STRING, ("bytes", BYTESTR)) {
Expand Down Expand Up @@ -549,11 +550,11 @@ object CryptoContext {
fromBase16StringF(checkLength = false)
)

def fromV4Functions(version: StdLibVersion) =
def fromV4Functions(version: StdLibVersion, typedError: Boolean) =
Array(
bls12Groth16VerifyF,
bn256Groth16VerifyF,
createMerkleRootF,
createMerkleRootF(typedError),
ecrecover, // new in V4
rsaVerifyF,
toBase16StringF(checkLength = true),
Expand All @@ -562,8 +563,8 @@ object CryptoContext {

val fromV1Ctx = CTX[NoContext](Seq(), Map(), v1Functions)
val fromV3Ctx = fromV1Ctx |+| CTX[NoContext](v3Types, v3Vars, v3Functions)
val fromV4Ctx = fromV1Ctx |+| CTX[NoContext](v4Types, v4Vars, fromV4Functions(V4))
val fromV6Ctx = fromV1Ctx |+| CTX[NoContext](v6Types, v4Vars, fromV4Functions(V6))
val fromV4Ctx = fromV1Ctx |+| CTX[NoContext](v4Types, v4Vars, fromV4Functions(V4, typedError))
val fromV6Ctx = fromV1Ctx |+| CTX[NoContext](v6Types, v4Vars, fromV4Functions(V6, typedError))

version match {
case V1 | V2 => fromV1Ctx
Expand All @@ -573,9 +574,9 @@ object CryptoContext {
}
}

def evalContext[F[_]: Monad](global: BaseGlobal, version: StdLibVersion): EvaluationContext[NoContext, F] =
build(global, version).evaluationContext[F]
def evalContext[F[_]: Monad](global: BaseGlobal, version: StdLibVersion, typedError: Boolean): EvaluationContext[NoContext, F] =
build(global, version, typedError).evaluationContext[F]

def compilerContext(global: BaseGlobal, version: StdLibVersion): CompilerContext =
build(global, version).compilerContext
def compilerContext(global: BaseGlobal, version: StdLibVersion, typedError: Boolean): CompilerContext =
build(global, version, typedError).compilerContext
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ object PureContext {
val MaxListLengthV4 = 1000

// As an optimization, JVM might throw an ArithmeticException with empty stack trace and null message.
// The workaround below retrows an exception with the message explicitly set.
// The workaround below rethrows an exception with the message explicitly set.
lazy val divLong: BaseFunction[NoContext] =
createTryOp(DIV_OP, LONG, LONG, DIV_LONG) { (a, b) =>
try Math.floorDiv(a, b)
Expand Down
Loading