From a22e9f56180a777085b565fa462c52744346ba9d Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Thu, 12 Oct 2023 01:39:33 +0300 Subject: [PATCH 01/11] Typo --- .../wavesplatform/lang/v1/evaluator/ctx/impl/PureContext.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/PureContext.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/PureContext.scala index 262e9b5ea0..2268cd3ba0 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/PureContext.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/PureContext.scala @@ -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) From d2ffb9aff7fba45dde34234e53295549617aadcb Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 16 Oct 2023 05:32:28 +0300 Subject: [PATCH 02/11] Adapted and tested invoke() and caseObjToRecipient() --- .../wavesplatform/lang/utils/package.scala | 11 +- .../lang/v1/evaluator/EvaluatorV2.scala | 3 +- .../evaluator/ctx/impl/waves/Functions.scala | 251 +++++++++++------- .../ctx/impl/waves/WavesContext.scala | 50 ++-- .../lang/v1/compiler/TestCompiler.scala | 6 +- .../api/http/utils/UtilsEvaluator.scala | 2 +- .../state/diffs/invoke/CachedDAppCTX.scala | 12 +- .../transaction/smart/BlockchainContext.scala | 10 +- .../smart/script/ScriptRunner.scala | 9 +- .../diffs/smart/RideExceptionsTest.scala | 115 ++++++++ .../smart/predef/ContextFunctionsTest.scala | 2 +- .../smart/predef/MatcherBlockchainTest.scala | 3 +- .../predef/TransactionBindingsTest.scala | 4 +- .../state/diffs/smart/predef/package.scala | 3 +- .../smart/scenarios/BalancesV4Test.scala | 4 +- ...NotaryControlledTransferScenarioTest.scala | 2 +- .../IssueTransactionV2Specification.scala | 3 +- .../estimator/FunctionComplexityTest.scala | 3 +- .../UserFunctionComplexityTest.scala | 9 +- 19 files changed, 344 insertions(+), 158 deletions(-) create mode 100644 node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala index c65012ac24..d1886b393e 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala @@ -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) + 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]]]] = @@ -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 = { @@ -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 diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/EvaluatorV2.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/EvaluatorV2.scala index aed5720e7c..7935c6fab7 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/EvaluatorV2.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/EvaluatorV2.scala @@ -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( diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala index 19c7987285..9ac11afd55 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala @@ -1,5 +1,7 @@ package com.wavesplatform.lang.v1.evaluator.ctx.impl.waves +import cats.data.EitherT +import cats.implicits.toTraverseOps import cats.syntax.applicative.* import cats.syntax.either.* import cats.syntax.functor.* @@ -11,11 +13,11 @@ import com.wavesplatform.lang.v1.FunctionHeader.{Native, User} import com.wavesplatform.lang.v1.compiler.Terms.* import com.wavesplatform.lang.v1.compiler.Types.* import com.wavesplatform.lang.v1.evaluator.FunctionIds.* +import com.wavesplatform.lang.v1.evaluator.ctx.impl.* import com.wavesplatform.lang.v1.evaluator.ctx.impl.EnvironmentFunctions.AddressLength import com.wavesplatform.lang.v1.evaluator.ctx.impl.converters.* import com.wavesplatform.lang.v1.evaluator.ctx.impl.waves.Bindings.{scriptTransfer as _, *} import com.wavesplatform.lang.v1.evaluator.ctx.impl.waves.Types.* -import com.wavesplatform.lang.v1.evaluator.ctx.impl.* import com.wavesplatform.lang.v1.evaluator.ctx.{BaseFunction, NativeFunction, UserFunction} import com.wavesplatform.lang.v1.evaluator.{ContextfulNativeFunction, ContextfulUserFunction, FunctionIds, Log} import com.wavesplatform.lang.v1.traits.domain.{Issue, Lease, Recipient} @@ -411,13 +413,14 @@ object Functions { case xs => notImplemented[Id, EVALUATED](s"toString(a: Address)", xs) } - private def caseObjToRecipient(c: CaseObj): Recipient = c.caseType.name match { - case addressType.name => Recipient.Address(c.fields("bytes").asInstanceOf[CONST_BYTESTR].bs) - case aliasType.name => Recipient.Alias(c.fields("alias").asInstanceOf[CONST_STRING].s) - case t => throw new IllegalArgumentException(s"Unexpected recipient type $t") - } + private def caseObjToRecipient(c: CaseObj, typedError: Boolean): Either[ExecutionError, Recipient] = + c.caseType.name match { + case addressType.name => Right(Recipient.Address(c.fields("bytes").asInstanceOf[CONST_BYTESTR].bs)) + case aliasType.name => Right(Recipient.Alias(c.fields("alias").asInstanceOf[CONST_STRING].s)) + case t => if (typedError) Left(s"Unexpected recipient type $t") else throw new IllegalArgumentException(s"Unexpected recipient type $t") + } - val assetBalanceF: BaseFunction[Environment] = + def assetBalanceF(typedError: Boolean): BaseFunction[Environment] = NativeFunction.withEnvironment[Environment]( "assetBalance", Map[StdLibVersion, Long](V1 -> 100L, V2 -> 100L, V3 -> 100L, V4 -> 10L), @@ -434,16 +437,24 @@ object Functions { override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = args match { case (c: CaseObj) :: u :: Nil if u == unit => - env.accountBalanceOf(caseObjToRecipient(c), None).map(_.map(CONST_LONG).leftMap(CommonError(_))) + caseObjToRecipient(c, typedError) + .fold( + _.asLeft[EVALUATED].pure[F], + r => env.accountBalanceOf(r, None).map(_.map(CONST_LONG).leftMap(CommonError(_))) + ) case (c: CaseObj) :: CONST_BYTESTR(assetId: ByteStr) :: Nil => - env.accountBalanceOf(caseObjToRecipient(c), Some(assetId.arr)).map(_.map(CONST_LONG).leftMap(CommonError(_))) + caseObjToRecipient(c, typedError) + .fold( + _.asLeft[EVALUATED].pure[F], + r => env.accountBalanceOf(r, Some(assetId.arr)).map(_.map(CONST_LONG).leftMap(CommonError(_))) + ) case xs => notImplemented[F, EVALUATED](s"assetBalance(a: Address|Alias, u: ByteVector|Unit)", xs) } } } - val assetBalanceV4F: BaseFunction[Environment] = + def assetBalanceV4F(typedError: Boolean): BaseFunction[Environment] = NativeFunction.withEnvironment[Environment]( "assetBalance", 10, @@ -456,14 +467,18 @@ object Functions { override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = args match { case (c: CaseObj) :: CONST_BYTESTR(assetId: ByteStr) :: Nil => - env.accountBalanceOf(caseObjToRecipient(c), Some(assetId.arr)).map(_.map(CONST_LONG).leftMap(CommonError(_))) + caseObjToRecipient(c, typedError) + .fold( + _.asLeft[EVALUATED].pure[F], + r => env.accountBalanceOf(r, Some(assetId.arr)).map(_.map(CONST_LONG).leftMap(CommonError(_))) + ) case xs => notImplemented[F, EVALUATED](s"assetBalance(a: Address|Alias, u: ByteVector)", xs) } } } - val wavesBalanceV4F: BaseFunction[Environment] = + def wavesBalanceV4F(typedError: Boolean): BaseFunction[Environment] = NativeFunction.withEnvironment[Environment]( "wavesBalance", 10, @@ -475,20 +490,25 @@ object Functions { override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = args match { case (c: CaseObj) :: Nil => - env - .accountWavesBalanceOf(caseObjToRecipient(c)) - .map( - _.map(b => - CaseObj( - balanceDetailsType, - Map( - "available" -> CONST_LONG(b.available), - "regular" -> CONST_LONG(b.regular), - "generating" -> CONST_LONG(b.generating), - "effective" -> CONST_LONG(b.effective) + caseObjToRecipient(c, typedError) + .fold( + _.asLeft[EVALUATED].pure[F], + r => + env + .accountWavesBalanceOf(r) + .map( + _.map(b => + CaseObj( + balanceDetailsType, + Map( + "available" -> CONST_LONG(b.available), + "regular" -> CONST_LONG(b.regular), + "generating" -> CONST_LONG(b.generating), + "effective" -> CONST_LONG(b.effective) + ) + ) + ).leftMap(CommonError(_)) ) - ) - ).leftMap(CommonError(_)) ) case xs => notImplemented[F, EVALUATED](s"wavesBalance(a: Address|Alias)", xs) @@ -522,9 +542,9 @@ object Functions { } } - val wavesBalanceF: BaseFunction[Environment] = + def wavesBalanceF(typedError: Boolean): BaseFunction[Environment] = UserFunction("wavesBalance", 109, LONG, ("@addressOrAlias", addressOrAliasType)) { - FUNCTION_CALL(assetBalanceF.header, List(REF("@addressOrAlias"), REF(GlobalValNames.Unit))) + FUNCTION_CALL(assetBalanceF(typedError).header, List(REF("@addressOrAlias"), REF(GlobalValNames.Unit))) } val txHeightByIdF: BaseFunction[Environment] = @@ -573,7 +593,7 @@ object Functions { } } - def callDAppF(reentrant: Boolean): BaseFunction[Environment] = { + def callDAppF(reentrant: Boolean, typedError: Boolean): BaseFunction[Environment] = { val (id, name) = if (reentrant) (CALLDAPPREENTRANT, "reentrantInvoke") else (CALLDAPP, "invoke") NativeFunction.withEnvironment[Environment]( name, @@ -595,52 +615,82 @@ object Functions { args: List[EVALUATED], availableComplexity: Int )(implicit m: Monad[CoevalF[F, *]]): Coeval[F[(Either[ExecutionError, (EVALUATED, Log[F])], Int)]] = { - val dAppBytes = args match { - case (dApp: CaseObj) :: _ if dApp.caseType == addressType => - dApp.fields("bytes") match { - case CONST_BYTESTR(d) => d.pure[F] - case a => throw new IllegalArgumentException(s"Unexpected address bytes $a") - } - case (dApp: CaseObj) :: _ if dApp.caseType == aliasType => - (dApp.fields("alias"): @unchecked) match { - case CONST_STRING(a) => env.resolveAlias(a).map(_.explicitGet().bytes) - } - case args => throw new IllegalArgumentException(s"Unexpected recipient args $args") - } - val name = args match { - case _ :: CONST_STRING(name) :: _ => name - case _ :: CaseObj(UNIT, _) :: _ => "default" - case args => throw new IllegalArgumentException(s"Unexpected input args $args") - } - args match { - case _ :: _ :: ARR(args) :: ARR(payments) :: Nil => - env - .callScript( - Recipient.Address(dAppBytes.asInstanceOf[ByteStr]), - name, - args.toList, - payments.map { + def errorE[R](message: String): Either[ExecutionError, R] = + if (typedError) (message: ExecutionError).asLeft[R] + else throw new IllegalArgumentException(message) + def errorF[R](message: String): F[Either[ExecutionError, R]] = + errorE[R](message).pure[F] + + val processedArgs = for { + dAppBytes <- EitherT[F, ExecutionError, ByteStr](args match { + case (dApp: CaseObj) :: _ if dApp.caseType == addressType => + dApp.fields.get("bytes") match { + case Some(CONST_BYTESTR(d)) => d.asRight[ExecutionError].pure[F] + case a => errorF(s"Unexpected address bytes $a") + } + case (dApp: CaseObj) :: _ if dApp.caseType == aliasType => + dApp.fields.get("alias") match { + case Some(CONST_STRING(a)) => + if (typedError) + env.resolveAlias(a).map(_.bimap(CommonError(_): ExecutionError, _.bytes)) + else + env.resolveAlias(a).map(_.explicitGet().bytes.asRight[ExecutionError]) + case arg => + errorF(s"Unexpected alias arg $arg") + } + case arg :: _ => + errorF(s"Unexpected recipient arg $arg") + }) + name <- EitherT[F, ExecutionError, String](args match { + case _ :: CONST_STRING(name) :: _ => name.asRight[ExecutionError].pure[F] + case _ :: CaseObj(UNIT, _) :: _ => "default".asRight[ExecutionError].pure[F] + case _ :: arg :: _ => errorF(s"Unexpected name arg $arg") + }) + payments <- EitherT[F, ExecutionError, Seq[(Option[Array[Byte]], Long)]](args match { + case _ :: _ :: _ :: ARR(payments) :: Nil => + (payments: Seq[EVALUATED]) + .traverse { case p: CaseObj if p.caseType == paymentType => - (List("assetId", "amount").map(p.fields): @unchecked) match { - case CONST_BYTESTR(a) :: CONST_LONG(v) :: Nil => (Some(a.arr), v) - case CaseObj(UNIT, _) :: CONST_LONG(v) :: Nil => (None, v) + List("assetId", "amount").flatMap(p.fields.get) match { + case CONST_BYTESTR(a) :: CONST_LONG(v) :: Nil => Right((Some(a.arr), v)) + case CaseObj(UNIT, _) :: CONST_LONG(v) :: Nil => Right((None, v)) + case args => errorE(s"Unexpected payment args $args") } - case arg => throw new IllegalArgumentException(s"Unexpected payment arg $arg") - }, - availableComplexity, - reentrant - ) - .map(_.map { case (result, spentComplexity) => - val mappedError = result.leftMap { - case reject: FailOrRejectError => reject - case other => CommonError("Nested invoke error", Some(other)) + case arg => + errorE(s"Unexpected payment arg $arg") } - (mappedError, availableComplexity - spentComplexity) - }) - case xs => - val err = - notImplemented[F, (EVALUATED, Log[F])](s"invoke(dApp: Address, function: String, args: List[Any], payments: List[Payment])", xs) - Coeval.now(err.map((_, 0))) + .pure[F] + case args => + (s"Unexpected args $args": ExecutionError).asLeft[Seq[(Option[Array[Byte]], Long)]].pure[F] + }) + } yield (dAppBytes, name, payments) + m.flatMap(Coeval(processedArgs.value)) { + case Left(error) => + (error.asLeft[(EVALUATED, Log[F])], availableComplexity).pure[F].pure[Coeval] + case Right((dAppBytes, name, payments)) => + args match { + case _ :: _ :: ARR(passedArgs) :: _ :: Nil => + env + .callScript( + Recipient.Address(dAppBytes), + name, + passedArgs.toList, + payments, + availableComplexity, + reentrant + ) + .map(_.map { case (result, spentComplexity) => + val mappedError = result.leftMap { + case reject: FailOrRejectError => reject + case other => CommonError("Nested invoke error", Some(other)): ExecutionError + } + (mappedError, availableComplexity - spentComplexity) + }) + case xs => + val err = + notImplemented[F, (EVALUATED, Log[F])](s"invoke(dApp: Address, func: String, args: List[Any], payments: List[Payment])", xs) + Coeval.now(err.map((_, 0))) + } } } } @@ -873,7 +923,7 @@ object Functions { Right(CaseObj(leaseActionType, typedArgs)) } - val calculateLeaseId: BaseFunction[Environment] = + def calculateLeaseId(typedError: Boolean): BaseFunction[Environment] = NativeFunction.withEnvironment[Environment]( "calculateLeaseId", 1, @@ -886,31 +936,32 @@ object Functions { override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = args match { case CaseObj(`leaseActionType`, fields) :: Nil => - val recipient = caseObjToRecipient(fields(FieldNames.LeaseRecipient).asInstanceOf[CaseObj]) - val r = recipient match { - case Recipient.Address(bytes) if bytes.arr.length > AddressLength => - Left(CommonError(s"Address bytes length=${bytes.arr.length} exceeds limit=$AddressLength"): ExecutionError) - case Recipient.Alias(name) if name.length > MaxAliasLength => - Left(CommonError(s"Alias name length=${name.length} exceeds limit=$MaxAliasLength"): ExecutionError) - case _ => - CONST_BYTESTR( - Lease.calculateId( - Lease( - recipient, - fields(FieldNames.LeaseAmount).asInstanceOf[CONST_LONG].t, - fields(FieldNames.LeaseNonce).asInstanceOf[CONST_LONG].t - ), - env.txId + caseObjToRecipient(fields(FieldNames.LeaseRecipient).asInstanceOf[CaseObj], typedError) + .flatMap { + case Recipient.Address(bytes) if bytes.arr.length > AddressLength => + Left(CommonError(s"Address bytes length=${bytes.arr.length} exceeds limit=$AddressLength"): ExecutionError) + case Recipient.Alias(name) if name.length > MaxAliasLength => + Left(CommonError(s"Alias name length=${name.length} exceeds limit=$MaxAliasLength"): ExecutionError) + case recipient => + CONST_BYTESTR( + Lease.calculateId( + Lease( + recipient, + fields(FieldNames.LeaseAmount).asInstanceOf[CONST_LONG].t, + fields(FieldNames.LeaseNonce).asInstanceOf[CONST_LONG].t + ), + env.txId + ) ) - ) - } - r.pure[F] - case xs => notImplemented[F, EVALUATED](s"calculateLeaseId(l: Lease)", xs) + } + .pure[F] + case xs => + notImplemented[F, EVALUATED](s"calculateLeaseId(l: Lease)", xs) } } } - def accountScriptHashF(global: BaseGlobal): BaseFunction[Environment] = { + def accountScriptHashF(global: BaseGlobal, typedError: Boolean): BaseFunction[Environment] = { val name = "scriptHash" val resType = UNION(BYTESTR, UNIT) val arg = ("account", addressOrAliasType) @@ -929,13 +980,17 @@ object Functions { override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = args match { case List(addr: CaseObj) => - env - .accountScript(caseObjToRecipient(addr)) - .map( - _.map(si => CONST_BYTESTR(ByteStr(global.blake2b256(si.bytes().arr)))) - .getOrElse(Right(unit)) + caseObjToRecipient(addr, typedError) + .fold( + _.asLeft[EVALUATED].pure[F], + recipient => + env + .accountScript(recipient) + .map( + _.map(si => CONST_BYTESTR(ByteStr(global.blake2b256(si.bytes().arr)))) + .getOrElse(Right(unit)) + ) ) - case xs => notImplemented[F, EVALUATED](s"scriptHash(account: AddressOrAlias))", xs) } diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala index ce8829ea19..99c52ca2f1 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala @@ -13,8 +13,8 @@ import com.wavesplatform.lang.v1.traits.* import com.wavesplatform.lang.v1.{BaseGlobal, CTX} object WavesContext { - def build(global: BaseGlobal, ds: DirectiveSet, fixBigScriptField: Boolean): CTX[Environment] = - invariableCtx |+| variableCtx(global, ds, fixBigScriptField) + def build(global: BaseGlobal, ds: DirectiveSet, fixBigScriptField: Boolean, typedError: Boolean): CTX[Environment] = + invariableCtx |+| variableCtx(global, ds, fixBigScriptField, typedError) private val commonFunctions = Array( @@ -26,22 +26,22 @@ object WavesContext { addressFromRecipientF ) - private val balanceV123Functions = + private def balanceV123Functions(typedError: Boolean) = Array( - assetBalanceF, - wavesBalanceF + assetBalanceF(typedError), + wavesBalanceF(typedError) ) - private val balanceV4Functions = + private def balanceV4Functions(typedError: Boolean) = Array( - assetBalanceV4F, - wavesBalanceV4F + assetBalanceV4F(typedError), + wavesBalanceV4F(typedError) ) private val invariableCtx = CTX(Seq(), Map(height), commonFunctions) - private def variableCtx(global: BaseGlobal, ds: DirectiveSet, fixBigScriptField: Boolean): CTX[Environment] = { + private def variableCtx(global: BaseGlobal, ds: DirectiveSet, fixBigScriptField: Boolean, typedError: Boolean): CTX[Environment] = { val isTokenContext = ds.scriptType == Asset val proofsEnabled = !isTokenContext val version = ds.stdLibVersion @@ -50,7 +50,7 @@ object WavesContext { CTX( types, variableVars(isTokenContext, version, ds.contentType, proofsEnabled, fixBigScriptField), - variableFuncs(global, ds, typeDefs, proofsEnabled) + variableFuncs(global, ds, typeDefs, proofsEnabled, typedError) ) } @@ -62,25 +62,25 @@ object WavesContext { stringFromAddressF ) - private def fromV4Funcs(proofsEnabled: Boolean, version: StdLibVersion, typeDefs: Map[String, FINAL]) = + private def fromV4Funcs(proofsEnabled: Boolean, typedError: Boolean, version: StdLibVersion, typeDefs: Map[String, FINAL]) = fromV3Funcs(proofsEnabled, version, typeDefs) ++ Array( calculateAssetIdF, transactionFromProtoBytesF(proofsEnabled, version, typeDefs), simplifiedIssueActionConstructor, detailedIssueActionConstructor - ) ++ balanceV4Functions + ) ++ balanceV4Functions(typedError: Boolean) - private def fromV5Funcs(proofsEnabled: Boolean, ds: DirectiveSet, typeDefs: Map[String, FINAL]) = { + private def fromV5Funcs(proofsEnabled: Boolean, typedError: Boolean, ds: DirectiveSet, typeDefs: Map[String, FINAL]) = { val v5Funcs = Array( simplifiedLeaseActionConstructor, detailedLeaseActionConstructor, - calculateLeaseId, + calculateLeaseId(typedError), isDataStorageUntouchedF ) val dAppFuncs = if (ds.contentType == DApp || ds.scriptType == Call) - Array(callDAppF(reentrant = false), callDAppF(reentrant = true)) + Array(callDAppF(reentrant = false, typedError), callDAppF(reentrant = true, typedError)) else Array[BaseFunction[Environment]]() @@ -90,11 +90,11 @@ object WavesContext { else Array[BaseFunction[Environment]]() - fromV4Funcs(proofsEnabled, ds.stdLibVersion, typeDefs) ++ v5Funcs ++ dAppFuncs ++ accountFuncs + fromV4Funcs(proofsEnabled, typedError, ds.stdLibVersion, typeDefs) ++ v5Funcs ++ dAppFuncs ++ accountFuncs } - private def fromV8Funcs(proofsEnabled: Boolean, ds: DirectiveSet, typeDefs: Map[String, FINAL]) = - fromV5Funcs(proofsEnabled, ds, typeDefs) :+ calculateDelay + private def fromV8Funcs(proofsEnabled: Boolean, typedError: Boolean, ds: DirectiveSet, typeDefs: Map[String, FINAL]) = + fromV5Funcs(proofsEnabled, typedError, ds, typeDefs) :+ calculateDelay private def selfCallFunctions(v: StdLibVersion) = Array( @@ -104,7 +104,7 @@ object WavesContext { getStringFromStateSelfF ) ++ extractedStateSelfFuncs(v) - private def variableFuncs(global: BaseGlobal, ds: DirectiveSet, typeDefs: Map[String, FINAL], proofsEnabled: Boolean) = { + private def variableFuncs(global: BaseGlobal, ds: DirectiveSet, typeDefs: Map[String, FINAL], proofsEnabled: Boolean, typedError: Boolean) = { val version = ds.stdLibVersion val commonFuncs = Array( @@ -118,15 +118,15 @@ object WavesContext { getStringByIndexF(version), if (version >= V4) addressFromStringV4 else addressFromStringF(version), if (version >= V6) addressFromPublicKeyNative else addressFromPublicKeyF(version) - ) ++ (if (version >= V5) Array(accountScriptHashF(global)) else Array()) + ) ++ (if (version >= V5) Array(accountScriptHashF(global, typedError)) else Array()) val versionSpecificFuncs = version match { - case V1 | V2 => Array(txByIdF(proofsEnabled, version)) ++ balanceV123Functions - case V3 => fromV3Funcs(proofsEnabled, version, typeDefs) ++ balanceV123Functions - case V4 => fromV4Funcs(proofsEnabled, version, typeDefs) - case V5 | V6 | V7 => fromV5Funcs(proofsEnabled, ds, typeDefs) - case _ => fromV8Funcs(proofsEnabled, ds, typeDefs) + case V1 | V2 => Array(txByIdF(proofsEnabled, version)) ++ balanceV123Functions(typedError) + case V3 => fromV3Funcs(proofsEnabled, version, typeDefs) ++ balanceV123Functions(typedError) + case V4 => fromV4Funcs(proofsEnabled, typedError, version, typeDefs) + case V5 | V6 | V7 => fromV5Funcs(proofsEnabled, typedError, ds, typeDefs) + case _ => fromV8Funcs(proofsEnabled, typedError, ds, typeDefs) } commonFuncs ++ versionSpecificFuncs } diff --git a/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala b/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala index deebef973c..81cb87382b 100644 --- a/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala +++ b/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala @@ -25,10 +25,10 @@ class TestCompiler(version: StdLibVersion) { private lazy val compilerContext = (baseCompilerContext |+| - WavesContext.build(Global, DirectiveSet(version, Account, DAppType).explicitGet(), fixBigScriptField = true)).compilerContext + WavesContext.build(Global, DirectiveSet(version, Account, DAppType).explicitGet(), fixBigScriptField = true, typedError = true)).compilerContext private lazy val expressionContext: CTX[Environment] = - WavesContext.build(Global, DirectiveSet(version, Account, Expression).explicitGet(), fixBigScriptField = true) + WavesContext.build(Global, DirectiveSet(version, Account, Expression).explicitGet(), fixBigScriptField = true, typedError = true) private lazy val expressionCompilerContext = (baseCompilerContext |+| @@ -36,7 +36,7 @@ class TestCompiler(version: StdLibVersion) { private lazy val assetCompilerContext = (baseCompilerContext |+| - WavesContext.build(Global, DirectiveSet(version, Asset, Expression).explicitGet(), fixBigScriptField = true)).compilerContext + WavesContext.build(Global, DirectiveSet(version, Asset, Expression).explicitGet(), fixBigScriptField = true, typedError = true)).compilerContext def compile( script: String, diff --git a/node/src/main/scala/com/wavesplatform/api/http/utils/UtilsEvaluator.scala b/node/src/main/scala/com/wavesplatform/api/http/utils/UtilsEvaluator.scala index 6fcc4fe687..e0252ddfc8 100644 --- a/node/src/main/scala/com/wavesplatform/api/http/utils/UtilsEvaluator.scala +++ b/node/src/main/scala/com/wavesplatform/api/http/utils/UtilsEvaluator.scala @@ -109,7 +109,7 @@ object UtilsEvaluator { currentSnapshot = paymentsSnapshot, invocationRoot = DAppEnvironment.InvocationTreeTracker(DAppEnvironment.DAppInvocation(dAppAddress, null, Nil)) ) - ctx = BlockchainContext.build(ds, environment, fixUnicodeFunctions = true, useNewPowPrecision = true, fixBigScriptField = true) + ctx = BlockchainContext.build(ds, environment, fixUnicodeFunctions = true, useNewPowPrecision = true, fixBigScriptField = true, typedError = true) dApp = ContractScriptCompactor.decompact(script.expr.asInstanceOf[DApp]) expr <- dAppToExpr(dApp) limitedResult <- EvaluatorV2 diff --git a/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala b/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala index 93b026f1db..e2f94060e1 100644 --- a/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala +++ b/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala @@ -2,7 +2,7 @@ package com.wavesplatform.state.diffs.invoke import cats.syntax.semigroup.* import com.wavesplatform.common.utils.EitherExt2 -import com.wavesplatform.features.BlockchainFeatures.{ConsensusImprovements, SynchronousCalls} +import com.wavesplatform.features.BlockchainFeatures.{ConsensusImprovements, LightNode, SynchronousCalls} import com.wavesplatform.lang.Global import com.wavesplatform.lang.directives.values.{Account, DApp, StdLibVersion, V3} import com.wavesplatform.lang.directives.{DirectiveDictionary, DirectiveSet} @@ -13,16 +13,17 @@ import com.wavesplatform.lang.v1.traits.Environment import com.wavesplatform.state.Blockchain object CachedDAppCTX { - private val cache: Map[(StdLibVersion, Boolean, Boolean), InvariableContext] = + private val cache: Map[(StdLibVersion, Boolean, Boolean, Boolean), InvariableContext] = (for { version <- DirectiveDictionary[StdLibVersion].all.filter(_ >= V3) useNewPowPrecision <- Seq(true, false) fixBigScriptField <- Seq(true, false) + typedError <- Seq(true, false) } yield { val ctx = PureContext.build(version, useNewPowPrecision).withEnvironment[Environment] |+| CryptoContext.build(Global, version).withEnvironment[Environment] |+| - WavesContext.build(Global, DirectiveSet(version, Account, DApp).explicitGet(), fixBigScriptField) - ((version, useNewPowPrecision, fixBigScriptField), InvariableContext(ctx)) + WavesContext.build(Global, DirectiveSet(version, Account, DApp).explicitGet(), fixBigScriptField, typedError) + ((version, useNewPowPrecision, fixBigScriptField, typedError), InvariableContext(ctx)) }).toMap def get(version: StdLibVersion, b: Blockchain): InvariableContext = @@ -30,7 +31,8 @@ object CachedDAppCTX { ( version, b.isFeatureActivated(SynchronousCalls) && b.height > b.settings.functionalitySettings.enforceTransferValidationAfter, - b.isFeatureActivated(ConsensusImprovements) + b.isFeatureActivated(ConsensusImprovements), + b.isFeatureActivated(LightNode) ) ) } diff --git a/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala b/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala index edb981637a..f428753890 100644 --- a/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala +++ b/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala @@ -34,7 +34,8 @@ object BlockchainContext { txId: ByteStr, fixUnicodeFunctions: Boolean, useNewPowPrecision: Boolean, - fixBigScriptField: Boolean + fixBigScriptField: Boolean, + typedError: Boolean ): Either[String, EvaluationContext[Environment, Id]] = DirectiveSet( version, @@ -42,7 +43,7 @@ object BlockchainContext { ContentType.isDApp(isContract) ).map { ds => val environment = new WavesEnvironment(nByte, in, h, blockchain, address, ds, txId) - build(ds, environment, fixUnicodeFunctions, useNewPowPrecision, fixBigScriptField) + build(ds, environment, fixUnicodeFunctions, useNewPowPrecision, fixBigScriptField, typedError) } def build( @@ -50,7 +51,8 @@ object BlockchainContext { environment: Environment[Id], fixUnicodeFunctions: Boolean, useNewPowPrecision: Boolean, - fixBigScriptField: Boolean + fixBigScriptField: Boolean, + typedError: Boolean ): EvaluationContext[Environment, Id] = cache .synchronized( @@ -59,7 +61,7 @@ object BlockchainContext { { _ => PureContext.build(ds.stdLibVersion, useNewPowPrecision).withEnvironment[Environment] |+| CryptoContext.build(Global, ds.stdLibVersion).withEnvironment[Environment] |+| - WavesContext.build(Global, ds, fixBigScriptField) + WavesContext.build(Global, ds, fixBigScriptField, typedError) } ) ) diff --git a/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala b/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala index 1b6802082c..a8f8ef53e0 100644 --- a/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala +++ b/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala @@ -54,7 +54,8 @@ object ScriptRunner { blockchain.newEvaluatorMode, blockchain.isFeatureActivated(RideV6), enableExecutionLog, - blockchain.isFeatureActivated(ConsensusImprovements) + blockchain.isFeatureActivated(ConsensusImprovements), + blockchain.isFeatureActivated(LightNode) ) def applyGeneric( @@ -72,7 +73,8 @@ object ScriptRunner { newEvaluatorMode: Boolean, checkWeakPk: Boolean, enableExecutionLog: Boolean, - fixBigScriptField: Boolean + fixBigScriptField: Boolean, + typedError: Boolean ): (Log[Id], Int, Either[ExecutionError, EVALUATED]) = { def evalVerifier( @@ -97,7 +99,8 @@ object ScriptRunner { txId, fixUnicodeFunctions, useNewPowPrecision, - fixBigScriptField + fixBigScriptField, + typedError ) } yield (ds, ctx) diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala new file mode 100644 index 0000000000..bc70ee2787 --- /dev/null +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala @@ -0,0 +1,115 @@ +package com.wavesplatform.state.diffs.smart + +import com.wavesplatform.block.Block +import com.wavesplatform.common.state.ByteStr +import com.wavesplatform.common.utils.EitherExt2 +import com.wavesplatform.db.WithDomain +import com.wavesplatform.db.WithState.AddrWithBalance +import com.wavesplatform.features.BlockchainFeatures.LightNode +import com.wavesplatform.lang.contract.DApp +import com.wavesplatform.lang.contract.DApp.{CallableAnnotation, CallableFunction} +import com.wavesplatform.lang.directives.values.V7 +import com.wavesplatform.lang.script.ContractScript.ContractScriptImpl +import com.wavesplatform.lang.v1.FunctionHeader.{Native, User} +import com.wavesplatform.lang.v1.compiler.Terms.* +import com.wavesplatform.lang.v1.compiler.TestCompiler +import com.wavesplatform.lang.v1.evaluator.FunctionIds.{ACCOUNTWAVESBALANCE, CALLDAPP} +import com.wavesplatform.protobuf.dapp.DAppMeta +import com.wavesplatform.test.DomainPresets.{TransactionStateSnapshot, WavesSettingsOps} +import com.wavesplatform.test.{PropSpec, produce} +import com.wavesplatform.transaction.TxHelpers.* + +class RideExceptionsTest extends PropSpec with WithDomain { + property("throwing java exception from ride functions should correctly fail or reject invoke after light node activation") { + assert( + FUNCTION_CALL(Native(ACCOUNTWAVESBALANCE), List(REF("unit"))), + "Unexpected recipient type Unit", + rejectBefore = false + ) + assert( + FUNCTION_CALL(Native(CALLDAPP), List(CONST_LONG(1), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1))), + "Unexpected recipient arg", + rejectBefore = true + ) + assert( + FUNCTION_CALL(Native(CALLDAPP), List(FUNCTION_CALL(User("Address"), List(CONST_LONG(1))), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1))), + "Unexpected address bytes", + rejectBefore = true + ) + assert( + FUNCTION_CALL( + Native(CALLDAPP), + List(FUNCTION_CALL(User("Alias"), List(CONST_STRING("alias").explicitGet())), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1)) + ), + "Alias 'alias:T:alias' does not exists", + rejectBefore = true + ) + assert( + FUNCTION_CALL( + Native(CALLDAPP), + List(FUNCTION_CALL(User("Alias"), List(CONST_LONG(1))), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1)) + ), + "Unexpected alias arg", + rejectBefore = true + ) + assert( + FUNCTION_CALL( + Native(CALLDAPP), + List(FUNCTION_CALL(User("Address"), List(CONST_BYTESTR(ByteStr.empty).explicitGet())), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1)) + ), + "Unexpected name arg", + rejectBefore = true + ) + assert( + FUNCTION_CALL( + Native(CALLDAPP), + List( + FUNCTION_CALL(User("Address"), List(CONST_BYTESTR(ByteStr.empty).explicitGet())), + REF("unit"), + CONST_LONG(1), + ARR(Vector(CONST_LONG(1)), limited = false).explicitGet() + ) + ), + "Unexpected payment arg", + rejectBefore = true + ) + } + + private def assert(expr: EXPR, error: String, rejectBefore: Boolean): Block = + withDomain(TransactionStateSnapshot.setFeaturesHeight(LightNode -> 6), AddrWithBalance.enoughBalances(defaultSigner, secondSigner)) { d => + val func = FUNC("default", Nil, expr) + val dApp = DApp(DAppMeta(), Nil, List(CallableFunction(CallableAnnotation("i"), func)), None) + d.appendBlock(setScript(secondSigner, ContractScriptImpl(V7, dApp))) + + // before activation + if (rejectBefore) + d.appendBlockE(invoke()) should produce(error) + else + d.appendAndAssertFailed(invoke(), error) + + // before activation with enough complexity to fail + val complexCond = TestCompiler(V7).compileExpression(s"${(1 to 6).map(_ => "sigVerify(base58'', base58'', base58'')").mkString(" || ")}") + val complexExpr = IF(complexCond.expr, TRUE, expr) + val complexFunc = FUNC("default", Nil, complexExpr) + val complexDApp = DApp(DAppMeta(), Nil, List(CallableFunction(CallableAnnotation("i"), complexFunc)), None) + d.appendBlock(setScript(secondSigner, ContractScriptImpl(V7, complexDApp))) + if (rejectBefore) + d.appendBlockE(invoke()) should produce(error) + else + d.appendAndAssertFailed(invoke(), error) + + // after activation + d.blockchain.isFeatureActivated(LightNode) shouldBe false + d.appendBlock(setScript(secondSigner, ContractScriptImpl(V7, dApp))) + if (rejectBefore) { + d.appendBlock() + d.appendBlock() + } + d.blockchain.isFeatureActivated(LightNode) shouldBe true + d.appendBlockE(invoke()) should produce(error) + + // after activation with enough complexity to fail + d.appendBlock(setScript(secondSigner, ContractScriptImpl(V7, complexDApp))) + d.appendAndAssertFailed(invoke(), error) + } +} diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala index 87a67f9824..93421558a2 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala @@ -837,7 +837,7 @@ class ContextFunctionsTest extends PropSpec with WithDomain with EthHelpers { val ctx = PureContext.build(version, useNewPowPrecision = true).withEnvironment[Environment] |+| CryptoContext.build(Global, version).withEnvironment[Environment] |+| - WavesContext.build(Global, DirectiveSet(version, Account, DApp).explicitGet(), fixBigScriptField = true) + WavesContext.build(Global, DirectiveSet(version, Account, DApp).explicitGet(), fixBigScriptField = true, typedError = true) val compiledScript = ContractScript(version, ContractCompiler(ctx.compilerContext, expr, version).explicitGet()).explicitGet() val setScriptTx = TxHelpers.setScript(recipient, compiledScript) diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala index 96a8a45c23..5342861cd6 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala @@ -102,7 +102,8 @@ class MatcherBlockchainTest extends PropSpec with MockFactory with WithDomain { newEvaluatorMode = true, checkWeakPk = true, enableExecutionLog = false, - fixBigScriptField = true + fixBigScriptField = true, + typedError = true ) ._3 shouldBe Right(CONST_BOOLEAN(true)) } diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala index 79618f62b3..e656c46816 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala @@ -869,7 +869,7 @@ class TransactionBindingsTest extends PropSpec with PathMockFactory with EitherV val ctx = PureContext.build(V2, useNewPowPrecision = true).withEnvironment[Environment] |+| CryptoContext.build(Global, V2).withEnvironment[Environment] |+| - WavesContext.build(Global, DirectiveSet(V2, AssetType, Expression).explicitGet(), fixBigScriptField = true) + WavesContext.build(Global, DirectiveSet(V2, AssetType, Expression).explicitGet(), fixBigScriptField = true, typedError = true) val environment = new WavesEnvironment( chainId, @@ -900,7 +900,7 @@ class TransactionBindingsTest extends PropSpec with PathMockFactory with EitherV val ctx = PureContext.build(V2, useNewPowPrecision = true).withEnvironment[Environment] |+| CryptoContext.build(Global, V2).withEnvironment[Environment] |+| - WavesContext.build(Global, directives, fixBigScriptField = true) + WavesContext.build(Global, directives, fixBigScriptField = true, typedError = true) val env = new WavesEnvironment( chainId, diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/package.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/package.scala index 43b9d510d8..b30b93ea1d 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/package.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/package.scala @@ -42,7 +42,8 @@ package object predef { ByteStr.empty, fixUnicodeFunctions = true, useNewPowPrecision = true, - fixBigScriptField = true + fixBigScriptField = true, + typedError = true ) r <- EvaluatorV1().apply[T](evalContext, typedExpr).leftMap(_.message) } yield r diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala index ed46169e84..9304036a88 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala @@ -121,7 +121,7 @@ class BalancesV4Test extends PropSpec with WithState { val directives = DirectiveSet(V4, AssetType, Expression).explicitGet() PureContext.build(V4, useNewPowPrecision = true).withEnvironment[Environment] |+| CryptoContext.build(Global, V4).withEnvironment[Environment] |+| - WavesContext.build(Global, directives, fixBigScriptField = true) + WavesContext.build(Global, directives, fixBigScriptField = true, typedError = true) } val script = @@ -183,7 +183,7 @@ class BalancesV4Test extends PropSpec with WithState { val directives = DirectiveSet(V4, AssetType, Expression).explicitGet() PureContext.build(V4, useNewPowPrecision = true).withEnvironment[Environment] |+| CryptoContext.build(Global, V4).withEnvironment[Environment] |+| - WavesContext.build(Global, directives, fixBigScriptField = true) + WavesContext.build(Global, directives, fixBigScriptField = true, typedError = true) } val script = diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/NotaryControlledTransferScenarioTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/NotaryControlledTransferScenarioTest.scala index 89152e2fab..fe5f3795c5 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/NotaryControlledTransferScenarioTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/NotaryControlledTransferScenarioTest.scala @@ -83,7 +83,7 @@ class NotaryControlledTransferScenarioTest extends PropSpec with WithState { private val dummyEvalContext: EvaluationContext[Environment, Id] = { val ds = DirectiveSet(V1, Asset, Expression).explicitGet() val environment = new WavesEnvironment(chainId, Coeval(???), null, EmptyBlockchain, null, ds, ByteStr.empty) - lazyContexts((ds, true, true))().evaluationContext(environment) + lazyContexts((ds, true, true, true))().evaluationContext(environment) } private def eval(code: String) = { diff --git a/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala b/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala index b65704bf30..20506b6dab 100644 --- a/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala +++ b/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala @@ -141,7 +141,8 @@ class IssueTransactionV2Specification extends PropSpec with WithNewDBForEachTest WavesContext.build( Global, DirectiveSet(V3, Account, Expression).explicitGet(), - fixBigScriptField = true + fixBigScriptField = true, + typedError = true ) ) ) diff --git a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala index 8c2e91273e..8e04304986 100644 --- a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala +++ b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala @@ -45,7 +45,8 @@ class FunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { WavesContext.build( Global, DirectiveSet(version, Account, Expression).explicitGet(), - fixBigScriptField = true + fixBigScriptField = true, + typedError = true ) ) ) diff --git a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala index 6e5d2cc7ca..6c338c3bfa 100644 --- a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala +++ b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala @@ -36,7 +36,8 @@ class UserFunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { WavesContext.build( Global, DirectiveSet(V1, Account, Expression).explicitGet(), - fixBigScriptField = true + fixBigScriptField = true, + typedError = true ) ) ) @@ -103,7 +104,8 @@ class UserFunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { WavesContext.build( Global, DirectiveSet(V2, Account, Expression).explicitGet(), - fixBigScriptField = true + fixBigScriptField = true, + typedError = true ) ) ) @@ -170,7 +172,8 @@ class UserFunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { WavesContext.build( Global, DirectiveSet(V3, Account, Expression).explicitGet(), - fixBigScriptField = true + fixBigScriptField = true, + typedError = true ) ) ) From 09d97f6e4affd64e39425299b74e4430801852a0 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 16 Oct 2023 05:33:23 +0300 Subject: [PATCH 03/11] Typo --- .../it/sync/smartcontract/InvokeMultiplePaymentsSuite.scala | 2 +- .../com/wavesplatform/transaction/TxValidationError.scala | 4 ++-- .../wavesplatform/state/diffs/ci/LeaseActionDiffTest.scala | 2 +- .../state/diffs/ci/ScriptTransferByAliasTest.scala | 2 +- .../wavesplatform/state/diffs/smart/RideExceptionsTest.scala | 2 +- .../smart/scenarios/AddressFromRecipientScenarioTest.scala | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/node-it/src/test/scala/com/wavesplatform/it/sync/smartcontract/InvokeMultiplePaymentsSuite.scala b/node-it/src/test/scala/com/wavesplatform/it/sync/smartcontract/InvokeMultiplePaymentsSuite.scala index 98360c47a8..c79de4138c 100644 --- a/node-it/src/test/scala/com/wavesplatform/it/sync/smartcontract/InvokeMultiplePaymentsSuite.scala +++ b/node-it/src/test/scala/com/wavesplatform/it/sync/smartcontract/InvokeMultiplePaymentsSuite.scala @@ -44,7 +44,7 @@ class InvokeMultiplePaymentsSuite extends BaseTransactionSuite with CancelAfterF sender.balance(callerAddress).balance shouldBe callerBalance - smartMinFee } - test("script should sheck if alias not exists") { + test("script should sheck if alias not exist") { val alias = "unknown" assertBadRequestAndMessage( diff --git a/node/src/main/scala/com/wavesplatform/transaction/TxValidationError.scala b/node/src/main/scala/com/wavesplatform/transaction/TxValidationError.scala index 5d4f1cabc5..eb8d61aa53 100644 --- a/node/src/main/scala/com/wavesplatform/transaction/TxValidationError.scala +++ b/node/src/main/scala/com/wavesplatform/transaction/TxValidationError.scala @@ -32,8 +32,8 @@ object TxValidationError { case class BlockFromFuture(ts: Long) extends ValidationError case class AlreadyInTheState(txId: ByteStr, txHeight: Int) extends ValidationError case class AccountBalanceError(errs: Map[Address, String]) extends ValidationError - case class AliasDoesNotExist(a: Alias) extends ValidationError { override def toString: String = s"Alias '$a' does not exists." } - case class AliasIsDisabled(a: Alias) extends ValidationError + case class AliasDoesNotExist(a: Alias) extends ValidationError { override def toString: String = s"Alias '$a' does not exist." } + case class AliasIsDisabled(a: Alias) extends ValidationError case class OrderValidationError(order: Order, err: String) extends ValidationError case class SenderIsBlacklisted(addr: String) extends ValidationError case class Mistiming(err: String) extends ValidationError diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/ci/LeaseActionDiffTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/ci/LeaseActionDiffTest.scala index 3f952dad9a..f86f7890e1 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/ci/LeaseActionDiffTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/ci/LeaseActionDiffTest.scala @@ -543,7 +543,7 @@ class LeaseActionDiffTest extends PropSpec with WithDomain { TestBlock.create(Seq(invoke)), v5Features ) { case (diff, _) => - diff.errorMessage(invoke.id()).get.text shouldBe "Alias 'alias:T:alias2' does not exists." + diff.errorMessage(invoke.id()).get.text shouldBe "Alias 'alias:T:alias2' does not exist." } } diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/ci/ScriptTransferByAliasTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/ci/ScriptTransferByAliasTest.scala index 04db51ad1e..f1ba5fb0ea 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/ci/ScriptTransferByAliasTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/ci/ScriptTransferByAliasTest.scala @@ -103,7 +103,7 @@ class ScriptTransferByAliasTest extends PropSpec with WithDomain { """.stripMargin ) d.appendBlock(setScript(secondSigner, dApp)) - d.appendBlockE(invoke()) should produce("Alias 'alias:T:alias' does not exists") + d.appendBlockE(invoke()) should produce("Alias 'alias:T:alias' does not exist") } } } diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala index bc70ee2787..7a7684d2fe 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala @@ -41,7 +41,7 @@ class RideExceptionsTest extends PropSpec with WithDomain { Native(CALLDAPP), List(FUNCTION_CALL(User("Alias"), List(CONST_STRING("alias").explicitGet())), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1)) ), - "Alias 'alias:T:alias' does not exists", + "Alias 'alias:T:alias' does not exist", rejectBefore = true ) assert( diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/AddressFromRecipientScenarioTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/AddressFromRecipientScenarioTest.scala index 93e5646af9..8e7ea048ec 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/AddressFromRecipientScenarioTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/AddressFromRecipientScenarioTest.scala @@ -49,7 +49,7 @@ class AddressFromRecipientScenarioTest extends PropSpec with WithState { val (gen, _, _, transferViaAlias) = preconditionsAndAliasCreations assertDiffAndState(Seq(TestBlock.create(gen)), TestBlock.create(Seq())) { case (_, state) => - runScript(script, transferViaAlias, state) should produce(" does not exists") + runScript(script, transferViaAlias, state) should produce(" does not exist") } } } From fc48db4fad61c53b887a84ed6b1960ace7d03152 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 16 Oct 2023 05:48:16 +0300 Subject: [PATCH 04/11] Better code --- .../evaluator/ctx/impl/waves/Functions.scala | 111 ++++++++++-------- 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala index 9ac11afd55..86f30ccac4 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala @@ -413,11 +413,15 @@ object Functions { case xs => notImplemented[Id, EVALUATED](s"toString(a: Address)", xs) } + private def errorE[R](message: String, typedError: Boolean): Either[ExecutionError, R] = + if (typedError) (message: ExecutionError).asLeft[R] + else throw new IllegalArgumentException(message) + private def caseObjToRecipient(c: CaseObj, typedError: Boolean): Either[ExecutionError, Recipient] = c.caseType.name match { case addressType.name => Right(Recipient.Address(c.fields("bytes").asInstanceOf[CONST_BYTESTR].bs)) case aliasType.name => Right(Recipient.Alias(c.fields("alias").asInstanceOf[CONST_STRING].s)) - case t => if (typedError) Left(s"Unexpected recipient type $t") else throw new IllegalArgumentException(s"Unexpected recipient type $t") + case t => errorE(s"Unexpected recipient type $t", typedError) } def assetBalanceF(typedError: Boolean): BaseFunction[Environment] = @@ -600,7 +604,7 @@ object Functions { Map[StdLibVersion, Long](V5 -> 75L), id, ANY, - ("dapp", addressOrAliasType), + ("dApp", addressOrAliasType), ("name", optionString), ("args", LIST(ANY)), ("payments", listPayment) @@ -608,65 +612,66 @@ object Functions { new ContextfulNativeFunction.Extended[Environment]( name, ANY, - Seq(("dapp", BYTESTR), ("name", STRING), ("args", LIST(ANY)), ("payments", listPayment)) + Seq(("dApp", BYTESTR), ("name", STRING), ("args", LIST(ANY)), ("payments", listPayment)) ) { override def evaluate[F[_]: Monad]( env: Environment[F], args: List[EVALUATED], availableComplexity: Int - )(implicit m: Monad[CoevalF[F, *]]): Coeval[F[(Either[ExecutionError, (EVALUATED, Log[F])], Int)]] = { - def errorE[R](message: String): Either[ExecutionError, R] = - if (typedError) (message: ExecutionError).asLeft[R] - else throw new IllegalArgumentException(message) + )(implicit monad: Monad[CoevalF[F, *]]): Coeval[F[(Either[ExecutionError, (EVALUATED, Log[F])], Int)]] = { def errorF[R](message: String): F[Either[ExecutionError, R]] = - errorE[R](message).pure[F] + errorE[R](message, typedError).pure[F] val processedArgs = for { - dAppBytes <- EitherT[F, ExecutionError, ByteStr](args match { - case (dApp: CaseObj) :: _ if dApp.caseType == addressType => - dApp.fields.get("bytes") match { - case Some(CONST_BYTESTR(d)) => d.asRight[ExecutionError].pure[F] - case a => errorF(s"Unexpected address bytes $a") - } - case (dApp: CaseObj) :: _ if dApp.caseType == aliasType => - dApp.fields.get("alias") match { - case Some(CONST_STRING(a)) => - if (typedError) - env.resolveAlias(a).map(_.bimap(CommonError(_): ExecutionError, _.bytes)) - else - env.resolveAlias(a).map(_.explicitGet().bytes.asRight[ExecutionError]) - case arg => - errorF(s"Unexpected alias arg $arg") - } - case arg :: _ => - errorF(s"Unexpected recipient arg $arg") - }) - name <- EitherT[F, ExecutionError, String](args match { - case _ :: CONST_STRING(name) :: _ => name.asRight[ExecutionError].pure[F] - case _ :: CaseObj(UNIT, _) :: _ => "default".asRight[ExecutionError].pure[F] - case _ :: arg :: _ => errorF(s"Unexpected name arg $arg") - }) - payments <- EitherT[F, ExecutionError, Seq[(Option[Array[Byte]], Long)]](args match { - case _ :: _ :: _ :: ARR(payments) :: Nil => - (payments: Seq[EVALUATED]) - .traverse { - case p: CaseObj if p.caseType == paymentType => - List("assetId", "amount").flatMap(p.fields.get) match { - case CONST_BYTESTR(a) :: CONST_LONG(v) :: Nil => Right((Some(a.arr), v)) - case CaseObj(UNIT, _) :: CONST_LONG(v) :: Nil => Right((None, v)) - case args => errorE(s"Unexpected payment args $args") - } + dAppBytes <- EitherT[F, ExecutionError, ByteStr]( + args match { + case (dApp: CaseObj) :: _ if dApp.caseType == addressType => + dApp.fields.get("bytes") match { + case Some(CONST_BYTESTR(d)) => d.asRight[ExecutionError].pure[F] + case a => errorF(s"Unexpected address bytes $a") + } + case (dApp: CaseObj) :: _ if dApp.caseType == aliasType => + dApp.fields.get("alias") match { + case Some(CONST_STRING(a)) => + if (typedError) + env.resolveAlias(a).map(_.bimap(CommonError(_): ExecutionError, _.bytes)) + else + env.resolveAlias(a).map(_.explicitGet().bytes.asRight[ExecutionError]) case arg => - errorE(s"Unexpected payment arg $arg") + errorF(s"Unexpected alias arg $arg") } - .pure[F] - case args => - (s"Unexpected args $args": ExecutionError).asLeft[Seq[(Option[Array[Byte]], Long)]].pure[F] - }) + case arg :: _ => + errorF(s"Unexpected recipient arg $arg") + } + ) + name <- EitherT[F, ExecutionError, String]( + args match { + case _ :: CONST_STRING(name) :: _ => name.asRight[ExecutionError].pure[F] + case _ :: CaseObj(UNIT, _) :: _ => "default".asRight[ExecutionError].pure[F] + case _ :: arg :: _ => errorF(s"Unexpected name arg $arg") + } + ) + payments <- EitherT[F, ExecutionError, Seq[(Option[Array[Byte]], Long)]]( + args match { + case _ :: _ :: _ :: ARR(payments) :: Nil => + (payments: Seq[EVALUATED]) + .traverse { + case p: CaseObj if p.caseType == paymentType => + List("assetId", "amount").flatMap(p.fields.get) match { + case CONST_BYTESTR(a) :: CONST_LONG(v) :: Nil => Right((Some(a.arr), v)) + case CaseObj(UNIT, _) :: CONST_LONG(v) :: Nil => Right((None, v)) + case args => errorE(s"Unexpected payment args $args", typedError) + } + case arg => + errorE(s"Unexpected payment arg $arg", typedError) + } + .pure[F] + case args => + (s"Unexpected args $args": ExecutionError).asLeft[Seq[(Option[Array[Byte]], Long)]].pure[F] + } + ) } yield (dAppBytes, name, payments) - m.flatMap(Coeval(processedArgs.value)) { - case Left(error) => - (error.asLeft[(EVALUATED, Log[F])], availableComplexity).pure[F].pure[Coeval] + monad.flatMap(Coeval(processedArgs.value)) { case Right((dAppBytes, name, payments)) => args match { case _ :: _ :: ARR(passedArgs) :: _ :: Nil => @@ -687,10 +692,12 @@ object Functions { (mappedError, availableComplexity - spentComplexity) }) case xs => - val err = - notImplemented[F, (EVALUATED, Log[F])](s"invoke(dApp: Address, func: String, args: List[Any], payments: List[Payment])", xs) + val signature = "invoke(dApp: Address, func: String, args: List[Any], payments: List[Payment])" + val err = notImplemented[F, (EVALUATED, Log[F])](signature, xs) Coeval.now(err.map((_, 0))) } + case Left(error) => + (error.asLeft[(EVALUATED, Log[F])], availableComplexity).pure[F].pure[Coeval] } } } From 2dc1b92afcf2e59526b8652b063185748772a2ae Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 16 Oct 2023 06:30:05 +0300 Subject: [PATCH 05/11] Adapted createMerkleRoot() --- .../common/utils/FastBase58.scala | 1 + .../wavesplatform/lang/utils/package.scala | 2 +- .../v1/evaluator/ctx/impl/CryptoContext.scala | 51 ++++++++++--------- .../ctx/impl/waves/WavesContext.scala | 2 +- .../lang/v1/compiler/TestCompiler.scala | 2 +- .../lang/doc/FunctionComplexityDocTest.scala | 4 +- .../lang/doc/ObjectTypesDocTest.scala | 2 +- .../lang/evaluator/EvaluatorSpec.scala | 4 +- .../lang/evaluator/EvaluatorV2Test.scala | 2 +- .../com/wavesplatform/utils/MerkleTest.scala | 2 +- .../state/diffs/invoke/CachedDAppCTX.scala | 2 +- .../transaction/smart/BlockchainContext.scala | 2 +- .../diffs/smart/RideExceptionsTest.scala | 26 +++++++++- .../smart/predef/ContextFunctionsTest.scala | 2 +- .../predef/TransactionBindingsTest.scala | 4 +- .../smart/scenarios/BalancesV4Test.scala | 4 +- .../IssueTransactionV2Specification.scala | 2 +- .../estimator/FunctionComplexityTest.scala | 2 +- .../UserFunctionComplexityTest.scala | 6 +-- 19 files changed, 74 insertions(+), 48 deletions(-) diff --git a/lang/shared/src/main/scala/com/wavesplatform/common/utils/FastBase58.scala b/lang/shared/src/main/scala/com/wavesplatform/common/utils/FastBase58.scala index 05024ebd27..1590f02191 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/common/utils/FastBase58.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/common/utils/FastBase58.scala @@ -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)") } diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala index d1886b393e..6223495733 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala @@ -76,7 +76,7 @@ package object utils { val ds = DirectiveSet(version, scriptType, contentType).explicitGet() val ctx = Coeval.evalOnce( PureContext.build(version, useNewPowPrecision).withEnvironment[Environment] |+| - CryptoContext.build(Global, version).withEnvironment[Environment] |+| + CryptoContext.build(Global, version, typedError).withEnvironment[Environment] |+| WavesContext.build(Global, ds, fixBigScriptField, typedError) ) (ds, useNewPowPrecision, fixBigScriptField, typedError) -> ctx diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/CryptoContext.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/CryptoContext.scala index 4c5968fca6..1854e26a3b 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/CryptoContext.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/CryptoContext.scala @@ -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} @@ -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 { @@ -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 } @@ -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, @@ -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, @@ -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)) { @@ -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), @@ -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 @@ -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 } diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala index 99c52ca2f1..b75ed16f26 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala @@ -13,7 +13,7 @@ import com.wavesplatform.lang.v1.traits.* import com.wavesplatform.lang.v1.{BaseGlobal, CTX} object WavesContext { - def build(global: BaseGlobal, ds: DirectiveSet, fixBigScriptField: Boolean, typedError: Boolean): CTX[Environment] = + def build(global: BaseGlobal, ds: DirectiveSet, fixBigScriptField: Boolean, typedError: Boolean = true): CTX[Environment] = invariableCtx |+| variableCtx(global, ds, fixBigScriptField, typedError) private val commonFunctions = diff --git a/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala b/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala index 81cb87382b..6711c41f7c 100644 --- a/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala +++ b/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala @@ -21,7 +21,7 @@ import scala.collection.mutable class TestCompiler(version: StdLibVersion) { private lazy val baseCompilerContext = PureContext.build(version, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, version).withEnvironment[Environment] + CryptoContext.build(Global, version, typedError = true).withEnvironment[Environment] private lazy val compilerContext = (baseCompilerContext |+| diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/doc/FunctionComplexityDocTest.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/doc/FunctionComplexityDocTest.scala index 05f07ab6a8..13db32b351 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/doc/FunctionComplexityDocTest.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/doc/FunctionComplexityDocTest.scala @@ -102,7 +102,7 @@ class FunctionComplexityDocTest extends PropSpec { property("JS API functions") { lazyContexts - .flatMap { case ((ds, _, _), _) => + .flatMap { case ((ds, _, _, _), _) => API .allFunctions(ds.stdLibVersion.id, ds.scriptType == Asset, ds.contentType == DApp) .map((_, ds.stdLibVersion)) @@ -114,7 +114,7 @@ class FunctionComplexityDocTest extends PropSpec { property("JS API vars") { lazyContexts - .flatMap { case ((ds, _, _), _) => + .flatMap { case ((ds, _, _, _), _) => API .allVars(ds.stdLibVersion.id, ds.scriptType == Asset, ds.contentType == DApp) .map((_, ds.stdLibVersion)) diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/doc/ObjectTypesDocTest.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/doc/ObjectTypesDocTest.scala index e7bada12fa..e8f6190366 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/doc/ObjectTypesDocTest.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/doc/ObjectTypesDocTest.scala @@ -19,7 +19,7 @@ class ObjectTypesDocTest extends PropSpec { fields.map { case (name, t) => s"$name: $t" }.mkString("\n\n", "\n", "\n\n") property("all object types") { - lazyContexts.foreach { case ((ds, _, _), ctx) => + lazyContexts.foreach { case ((ds, _, _, _), ctx) => ctx().types .collect { case CASETYPEREF(name, fields, _) => val codeFields = fields.map { case (name, t) => (name, t.toString) } diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorSpec.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorSpec.scala index 8a56d49c8e..3b370ce8f9 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorSpec.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorSpec.scala @@ -73,13 +73,13 @@ abstract class EvaluatorSpec extends PropSpec with ScriptGen with Inside { } private def evalExpr(expr: EXPR, version: StdLibVersion, useNewPowPrecision: Boolean): (Log[Id], Int, Either[ExecutionError, EVALUATED]) = { - val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), useNewPowPrecision, true)).value() + val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), useNewPowPrecision, true, true)).value() val evalCtx = ctx.evaluationContext(Common.emptyBlockchainEnvironment()) EvaluatorV2.applyCompleted(evalCtx, expr, LogExtraInfo(), version, correctFunctionCallScope = true, newMode = true, enableExecutionLog = false) } def compile(code: String, version: StdLibVersion): Either[String, EXPR] = { - val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), true, true)).value() + val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), true, true, true)).value() val parsed = Parser.parseExpr(code).get.value ExpressionCompiler(ctx.compilerContext, parsed, allowIllFormedStrings = true).map(_._1) } diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV2Test.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV2Test.scala index cd7b4ff324..37be313bd2 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV2Test.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV2Test.scala @@ -20,7 +20,7 @@ import scala.util.Random class EvaluatorV2Test extends PropSpec with Inside { private val version = V4 - private val ctx = lazyContexts((DirectiveSet(version, Account, DApp).explicitGet(), true, true))() + private val ctx = lazyContexts((DirectiveSet(version, Account, DApp).explicitGet(), true, true, true))() private val environment = Common.emptyBlockchainEnvironment() private def evalEither(expr: EXPR, limit: Int, newMode: Boolean): Either[String, (EXPR, Int)] = diff --git a/lang/tests/src/test/scala/com/wavesplatform/utils/MerkleTest.scala b/lang/tests/src/test/scala/com/wavesplatform/utils/MerkleTest.scala index 23c3ae9942..8429e836cd 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/utils/MerkleTest.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/utils/MerkleTest.scala @@ -107,7 +107,7 @@ class MerkleTest extends PropSpec { private def eval(code: String, version: StdLibVersion = V3): Either[String, EVALUATED] = { val untyped = Parser.parseExpr(code).get.value - val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), true, true))() + val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), true, true, true))() val evalCtx = ctx.evaluationContext[Id](Common.emptyBlockchainEnvironment()) val typed = ExpressionCompiler(ctx.compilerContext, untyped) typed.flatMap(v => EvaluatorV2.applyCompleted(evalCtx, v._1, LogExtraInfo(), version, true, true, false)._3.leftMap(_.toString)) diff --git a/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala b/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala index e2f94060e1..fc07388187 100644 --- a/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala +++ b/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala @@ -21,7 +21,7 @@ object CachedDAppCTX { typedError <- Seq(true, false) } yield { val ctx = PureContext.build(version, useNewPowPrecision).withEnvironment[Environment] |+| - CryptoContext.build(Global, version).withEnvironment[Environment] |+| + CryptoContext.build(Global, version, typedError).withEnvironment[Environment] |+| WavesContext.build(Global, DirectiveSet(version, Account, DApp).explicitGet(), fixBigScriptField, typedError) ((version, useNewPowPrecision, fixBigScriptField, typedError), InvariableContext(ctx)) }).toMap diff --git a/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala b/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala index f428753890..2389569387 100644 --- a/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala +++ b/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala @@ -60,7 +60,7 @@ object BlockchainContext { (ds.stdLibVersion, fixUnicodeFunctions, useNewPowPrecision, fixBigScriptField, ds), { _ => PureContext.build(ds.stdLibVersion, useNewPowPrecision).withEnvironment[Environment] |+| - CryptoContext.build(Global, ds.stdLibVersion).withEnvironment[Environment] |+| + CryptoContext.build(Global, ds.stdLibVersion, typedError).withEnvironment[Environment] |+| WavesContext.build(Global, ds, fixBigScriptField, typedError) } ) diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala index 7a7684d2fe..b16315f733 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala @@ -13,7 +13,7 @@ import com.wavesplatform.lang.script.ContractScript.ContractScriptImpl import com.wavesplatform.lang.v1.FunctionHeader.{Native, User} import com.wavesplatform.lang.v1.compiler.Terms.* import com.wavesplatform.lang.v1.compiler.TestCompiler -import com.wavesplatform.lang.v1.evaluator.FunctionIds.{ACCOUNTWAVESBALANCE, CALLDAPP} +import com.wavesplatform.lang.v1.evaluator.FunctionIds.{ACCOUNTWAVESBALANCE, CALLDAPP, CREATE_MERKLE_ROOT} import com.wavesplatform.protobuf.dapp.DAppMeta import com.wavesplatform.test.DomainPresets.{TransactionStateSnapshot, WavesSettingsOps} import com.wavesplatform.test.{PropSpec, produce} @@ -73,6 +73,30 @@ class RideExceptionsTest extends PropSpec with WithDomain { "Unexpected payment arg", rejectBefore = true ) + assert( + FUNCTION_CALL( + Native(CREATE_MERKLE_ROOT), + List( + ARR(Vector.fill(16)(CONST_BYTESTR(ByteStr.fill(32)(1)).explicitGet()), true).explicitGet(), + CONST_BYTESTR(ByteStr.fill(32)(1)).explicitGet(), + CONST_LONG(Long.MaxValue) + ) + ), + "integer overflow", + rejectBefore = false + ) + assert( + FUNCTION_CALL( + Native(CREATE_MERKLE_ROOT), + List( + ARR(Vector.fill(1)(CONST_BYTESTR(ByteStr.fill(32)(1)).explicitGet()), true).explicitGet(), + CONST_BYTESTR(ByteStr.fill(32)(1)).explicitGet(), + CONST_LONG(100) + ) + ), + "Index 100 out of range allowed by proof list length 1", + rejectBefore = false + ) } private def assert(expr: EXPR, error: String, rejectBefore: Boolean): Block = diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala index 93421558a2..9f6d1ac7d2 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala @@ -836,7 +836,7 @@ class ContextFunctionsTest extends PropSpec with WithDomain with EthHelpers { val ctx = PureContext.build(version, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, version).withEnvironment[Environment] |+| + CryptoContext.build(Global, version, typedError = true).withEnvironment[Environment] |+| WavesContext.build(Global, DirectiveSet(version, Account, DApp).explicitGet(), fixBigScriptField = true, typedError = true) val compiledScript = ContractScript(version, ContractCompiler(ctx.compilerContext, expr, version).explicitGet()).explicitGet() diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala index e656c46816..38df65ac7a 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala @@ -868,7 +868,7 @@ class TransactionBindingsTest extends PropSpec with PathMockFactory with EitherV val directives = DirectiveSet(V2, AssetType, Expression).explicitGet() val ctx = PureContext.build(V2, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, V2).withEnvironment[Environment] |+| + CryptoContext.build(Global, V2, typedError = true).withEnvironment[Environment] |+| WavesContext.build(Global, DirectiveSet(V2, AssetType, Expression).explicitGet(), fixBigScriptField = true, typedError = true) val environment = new WavesEnvironment( @@ -899,7 +899,7 @@ class TransactionBindingsTest extends PropSpec with PathMockFactory with EitherV val ctx = PureContext.build(V2, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, V2).withEnvironment[Environment] |+| + CryptoContext.build(Global, V2, typedError = true).withEnvironment[Environment] |+| WavesContext.build(Global, directives, fixBigScriptField = true, typedError = true) val env = new WavesEnvironment( diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala index 9304036a88..c881c8f752 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala @@ -120,7 +120,7 @@ class BalancesV4Test extends PropSpec with WithState { val ctx = { val directives = DirectiveSet(V4, AssetType, Expression).explicitGet() PureContext.build(V4, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, V4).withEnvironment[Environment] |+| + CryptoContext.build(Global, V4, typedError = true).withEnvironment[Environment] |+| WavesContext.build(Global, directives, fixBigScriptField = true, typedError = true) } @@ -182,7 +182,7 @@ class BalancesV4Test extends PropSpec with WithState { val ctx = { val directives = DirectiveSet(V4, AssetType, Expression).explicitGet() PureContext.build(V4, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, V4).withEnvironment[Environment] |+| + CryptoContext.build(Global, V4, typedError = true).withEnvironment[Environment] |+| WavesContext.build(Global, directives, fixBigScriptField = true, typedError = true) } diff --git a/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala b/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala index 20506b6dab..237fc14781 100644 --- a/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala +++ b/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala @@ -137,7 +137,7 @@ class IssueTransactionV2Specification extends PropSpec with WithNewDBForEachTest .combineAll( Seq( PureContext.build(V3, useNewPowPrecision = true).withEnvironment[Environment], - CryptoContext.build(Global, V3).withEnvironment[Environment], + CryptoContext.build(Global, V3, typedError = true).withEnvironment[Environment], WavesContext.build( Global, DirectiveSet(V3, Account, Expression).explicitGet(), diff --git a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala index 8e04304986..c70b14a7bc 100644 --- a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala +++ b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala @@ -41,7 +41,7 @@ class FunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { .combineAll( Seq( PureContext.build(version, useNewPowPrecision = true).withEnvironment[Environment], - CryptoContext.build(Global, version).withEnvironment[Environment], + CryptoContext.build(Global, version, typedError = true).withEnvironment[Environment], WavesContext.build( Global, DirectiveSet(version, Account, Expression).explicitGet(), diff --git a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala index 6c338c3bfa..3d73df6880 100644 --- a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala +++ b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala @@ -32,7 +32,7 @@ class UserFunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { .combineAll( Seq( PureContext.build(V1, useNewPowPrecision = true).withEnvironment[Environment], - CryptoContext.build(Global, V1).withEnvironment[Environment], + CryptoContext.build(Global, V1, typedError = true).withEnvironment[Environment], WavesContext.build( Global, DirectiveSet(V1, Account, Expression).explicitGet(), @@ -100,7 +100,7 @@ class UserFunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { .combineAll( Seq( PureContext.build(V2, useNewPowPrecision = true).withEnvironment[Environment], - CryptoContext.build(Global, V2).withEnvironment[Environment], + CryptoContext.build(Global, V2, typedError = true).withEnvironment[Environment], WavesContext.build( Global, DirectiveSet(V2, Account, Expression).explicitGet(), @@ -168,7 +168,7 @@ class UserFunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { .combineAll( Seq( PureContext.build(V3, useNewPowPrecision = true).withEnvironment[Environment], - CryptoContext.build(Global, V3).withEnvironment[Environment], + CryptoContext.build(Global, V3, typedError = true).withEnvironment[Environment], WavesContext.build( Global, DirectiveSet(V3, Account, Expression).explicitGet(), From c3ad45505342ff2c93596a89ce2b433fead79feb Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 16 Oct 2023 07:16:32 +0300 Subject: [PATCH 06/11] Commented --- .../src/main/scala/com/wavesplatform/lang/v1/BaseGlobal.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/BaseGlobal.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/BaseGlobal.scala index a7992fcfd4..b4c538f106 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/BaseGlobal.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/BaseGlobal.scala @@ -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 From 08fc2c7c1026f9647ee3efb84ccd021412b9a100 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 16 Oct 2023 07:29:44 +0300 Subject: [PATCH 07/11] Test verifier --- .../diffs/smart/RideExceptionsTest.scala | 60 ++++++++++++------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala index b16315f733..385c9b0e77 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala @@ -1,6 +1,5 @@ package com.wavesplatform.state.diffs.smart -import com.wavesplatform.block.Block import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils.EitherExt2 import com.wavesplatform.db.WithDomain @@ -10,6 +9,7 @@ import com.wavesplatform.lang.contract.DApp import com.wavesplatform.lang.contract.DApp.{CallableAnnotation, CallableFunction} import com.wavesplatform.lang.directives.values.V7 import com.wavesplatform.lang.script.ContractScript.ContractScriptImpl +import com.wavesplatform.lang.script.v1.ExprScript.ExprScriptImpl import com.wavesplatform.lang.v1.FunctionHeader.{Native, User} import com.wavesplatform.lang.v1.compiler.Terms.* import com.wavesplatform.lang.v1.compiler.TestCompiler @@ -29,12 +29,14 @@ class RideExceptionsTest extends PropSpec with WithDomain { assert( FUNCTION_CALL(Native(CALLDAPP), List(CONST_LONG(1), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1))), "Unexpected recipient arg", - rejectBefore = true + rejectBefore = true, + checkVerifier = false ) assert( FUNCTION_CALL(Native(CALLDAPP), List(FUNCTION_CALL(User("Address"), List(CONST_LONG(1))), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1))), "Unexpected address bytes", - rejectBefore = true + rejectBefore = true, + checkVerifier = false ) assert( FUNCTION_CALL( @@ -42,7 +44,8 @@ class RideExceptionsTest extends PropSpec with WithDomain { List(FUNCTION_CALL(User("Alias"), List(CONST_STRING("alias").explicitGet())), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1)) ), "Alias 'alias:T:alias' does not exist", - rejectBefore = true + rejectBefore = true, + checkVerifier = false ) assert( FUNCTION_CALL( @@ -50,7 +53,8 @@ class RideExceptionsTest extends PropSpec with WithDomain { List(FUNCTION_CALL(User("Alias"), List(CONST_LONG(1))), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1)) ), "Unexpected alias arg", - rejectBefore = true + rejectBefore = true, + checkVerifier = false ) assert( FUNCTION_CALL( @@ -58,7 +62,8 @@ class RideExceptionsTest extends PropSpec with WithDomain { List(FUNCTION_CALL(User("Address"), List(CONST_BYTESTR(ByteStr.empty).explicitGet())), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1)) ), "Unexpected name arg", - rejectBefore = true + rejectBefore = true, + checkVerifier = false ) assert( FUNCTION_CALL( @@ -71,7 +76,8 @@ class RideExceptionsTest extends PropSpec with WithDomain { ) ), "Unexpected payment arg", - rejectBefore = true + rejectBefore = true, + checkVerifier = false ) assert( FUNCTION_CALL( @@ -99,41 +105,53 @@ class RideExceptionsTest extends PropSpec with WithDomain { ) } - private def assert(expr: EXPR, error: String, rejectBefore: Boolean): Block = - withDomain(TransactionStateSnapshot.setFeaturesHeight(LightNode -> 6), AddrWithBalance.enoughBalances(defaultSigner, secondSigner)) { d => + private def assert(expr: EXPR, error: String, rejectBefore: Boolean, checkVerifier: Boolean = true) = + withDomain( + TransactionStateSnapshot.setFeaturesHeight(LightNode -> 7), + AddrWithBalance.enoughBalances(defaultSigner, secondSigner, signer(2)) + ) { d => val func = FUNC("default", Nil, expr) val dApp = DApp(DAppMeta(), Nil, List(CallableFunction(CallableAnnotation("i"), func)), None) d.appendBlock(setScript(secondSigner, ContractScriptImpl(V7, dApp))) - // before activation - if (rejectBefore) + // dApp before activation + if (rejectBefore) { d.appendBlockE(invoke()) should produce(error) - else + d.appendBlock() + } else d.appendAndAssertFailed(invoke(), error) - // before activation with enough complexity to fail + // dApp before activation with enough complexity to fail val complexCond = TestCompiler(V7).compileExpression(s"${(1 to 6).map(_ => "sigVerify(base58'', base58'', base58'')").mkString(" || ")}") val complexExpr = IF(complexCond.expr, TRUE, expr) val complexFunc = FUNC("default", Nil, complexExpr) val complexDApp = DApp(DAppMeta(), Nil, List(CallableFunction(CallableAnnotation("i"), complexFunc)), None) d.appendBlock(setScript(secondSigner, ContractScriptImpl(V7, complexDApp))) - if (rejectBefore) + if (rejectBefore) { d.appendBlockE(invoke()) should produce(error) - else + d.appendBlock() + } else d.appendAndAssertFailed(invoke(), error) - // after activation + // verifier before activation + if (checkVerifier) { + d.appendBlock(setScript(signer(2), ExprScriptImpl(V7, false, complexExpr))) + d.appendBlockE(transfer(signer(2), defaultAddress)) should produce(error) + } else + d.appendBlock() + + // dApp after activation d.blockchain.isFeatureActivated(LightNode) shouldBe false d.appendBlock(setScript(secondSigner, ContractScriptImpl(V7, dApp))) - if (rejectBefore) { - d.appendBlock() - d.appendBlock() - } d.blockchain.isFeatureActivated(LightNode) shouldBe true d.appendBlockE(invoke()) should produce(error) - // after activation with enough complexity to fail + // dApp after activation with enough complexity to fail d.appendBlock(setScript(secondSigner, ContractScriptImpl(V7, complexDApp))) d.appendAndAssertFailed(invoke(), error) + + // verifier after activation + if (checkVerifier) + d.appendBlockE(transfer(signer(2), defaultAddress)) should produce(error) } } From c5f374cfd0b91746c46666eeae918fe80e0857c3 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 16 Oct 2023 12:19:48 +0300 Subject: [PATCH 08/11] Additional tests --- .../v1/evaluator/ctx/impl/waves/Functions.scala | 3 +++ .../state/diffs/smart/RideExceptionsTest.scala | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala index 86f30ccac4..cf38917991 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala @@ -642,6 +642,8 @@ object Functions { } case arg :: _ => errorF(s"Unexpected recipient arg $arg") + case args => + errorF(s"Unexpected args $args") } ) name <- EitherT[F, ExecutionError, String]( @@ -649,6 +651,7 @@ object Functions { case _ :: CONST_STRING(name) :: _ => name.asRight[ExecutionError].pure[F] case _ :: CaseObj(UNIT, _) :: _ => "default".asRight[ExecutionError].pure[F] case _ :: arg :: _ => errorF(s"Unexpected name arg $arg") + case args => errorF(s"Unexpected args $args") } ) payments <- EitherT[F, ExecutionError, Seq[(Option[Array[Byte]], Long)]]( diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala index 385c9b0e77..18c9497a19 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/RideExceptionsTest.scala @@ -13,7 +13,7 @@ import com.wavesplatform.lang.script.v1.ExprScript.ExprScriptImpl import com.wavesplatform.lang.v1.FunctionHeader.{Native, User} import com.wavesplatform.lang.v1.compiler.Terms.* import com.wavesplatform.lang.v1.compiler.TestCompiler -import com.wavesplatform.lang.v1.evaluator.FunctionIds.{ACCOUNTWAVESBALANCE, CALLDAPP, CREATE_MERKLE_ROOT} +import com.wavesplatform.lang.v1.evaluator.FunctionIds.* import com.wavesplatform.protobuf.dapp.DAppMeta import com.wavesplatform.test.DomainPresets.{TransactionStateSnapshot, WavesSettingsOps} import com.wavesplatform.test.{PropSpec, produce} @@ -26,6 +26,21 @@ class RideExceptionsTest extends PropSpec with WithDomain { "Unexpected recipient type Unit", rejectBefore = false ) + assert( + FUNCTION_CALL(Native(ACCOUNTASSETONLYBALANCE), List(REF("unit"), CONST_BYTESTR(ByteStr.empty).explicitGet())), + "Unexpected recipient type Unit", + rejectBefore = false + ) + assert( + FUNCTION_CALL(Native(ACCOUNTSCRIPTHASH), List(REF("unit"))), + "Unexpected recipient type Unit", + rejectBefore = false + ) + assert( + FUNCTION_CALL(Native(CALCULATE_LEASE_ID), List(FUNCTION_CALL(User("Lease"), List(REF("unit"))))), + "Unexpected recipient type Unit", + rejectBefore = false + ) assert( FUNCTION_CALL(Native(CALLDAPP), List(CONST_LONG(1), CONST_LONG(1), CONST_LONG(1), CONST_LONG(1))), "Unexpected recipient arg", From b17c144b437dc28963321f16e0ca30f31f375616 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 16 Oct 2023 12:57:32 +0300 Subject: [PATCH 09/11] Fixed errors --- .../wavesplatform/lang/v1/AddressFromPublicKeyBenchmark.scala | 2 +- .../scala/com/wavesplatform/lang/v1/BigIntOpsBenchmark.scala | 2 +- .../com/wavesplatform/lang/v1/BigIntToStringBenchmark.scala | 2 +- .../test/scala/com/wavesplatform/lang/v1/FoldBenchmark.scala | 2 +- .../scala/com/wavesplatform/lang/v1/FractionIntBenchmark.scala | 2 +- .../scala/com/wavesplatform/lang/v1/PowBigIntBenchmark.scala | 2 +- .../test/scala/com/wavesplatform/lang/v1/PowIntBenchmark.scala | 2 +- .../com/wavesplatform/lang/v1/PureFunctionsRebenchmark.scala | 2 +- .../com/wavesplatform/lang/v1/SqrtCbrtBigIntBenchmark.scala | 2 +- .../test/scala/com/wavesplatform/lang/v1/SqrtIntBenchmark.scala | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/AddressFromPublicKeyBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/AddressFromPublicKeyBenchmark.scala index 44d9a0be37..68618a626f 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/AddressFromPublicKeyBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/AddressFromPublicKeyBenchmark.scala @@ -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] diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntOpsBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntOpsBenchmark.scala index 0ae875124d..f955faae68 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntOpsBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntOpsBenchmark.scala @@ -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) diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntToStringBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntToStringBenchmark.scala index 200dfbb3e6..320fb3a205 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntToStringBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntToStringBenchmark.scala @@ -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), diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/FoldBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/FoldBenchmark.scala index dcea787f8d..8613c9f7b0 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/FoldBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/FoldBenchmark.scala @@ -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'')" diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/FractionIntBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/FractionIntBenchmark.scala index 05457b8df3..331d3507fb 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/FractionIntBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/FractionIntBenchmark.scala @@ -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 diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowBigIntBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowBigIntBenchmark.scala index b3781478b6..26d3adbf25 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowBigIntBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowBigIntBenchmark.scala @@ -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 diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowIntBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowIntBenchmark.scala index eba1402213..b04bd2e5c8 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowIntBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowIntBenchmark.scala @@ -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 diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PureFunctionsRebenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PureFunctionsRebenchmark.scala index 9a777dc665..dacd2a3d09 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PureFunctionsRebenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PureFunctionsRebenchmark.scala @@ -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]) = diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtCbrtBigIntBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtCbrtBigIntBenchmark.scala index 326a88dd01..43b26d101e 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtCbrtBigIntBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtCbrtBigIntBenchmark.scala @@ -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 diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtIntBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtIntBenchmark.scala index b2b6b332a0..fffd9e8a3e 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtIntBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtIntBenchmark.scala @@ -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)") From 4885cf51ca480c2fa11aaab55cc901efa2c1dea3 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Tue, 17 Oct 2023 15:40:41 +0300 Subject: [PATCH 10/11] ThrownError extends ExecutionError --- .../v1/AddressFromPublicKeyBenchmark.scala | 2 +- .../lang/v1/BigIntOpsBenchmark.scala | 2 +- .../lang/v1/BigIntToStringBenchmark.scala | 2 +- .../lang/v1/EvaluatorV2Benchmark.scala | 11 ++-- .../wavesplatform/lang/v1/FoldBenchmark.scala | 2 +- .../lang/v1/FractionIntBenchmark.scala | 14 ++-- .../lang/v1/PowBigIntBenchmark.scala | 2 +- .../lang/v1/PowIntBenchmark.scala | 2 +- .../lang/v1/PureFunctionsRebenchmark.scala | 2 +- .../lang/v1/SqrtCbrtBigIntBenchmark.scala | 2 +- .../lang/v1/SqrtIntBenchmark.scala | 2 +- .../com/wavesplatform/lang/v1/package.scala | 11 +++- .../wavesplatform/lang/ExecutionError.scala | 1 + .../wavesplatform/lang/utils/package.scala | 13 ++-- .../lang/v1/evaluator/ContractEvaluator.scala | 21 ++++-- .../lang/v1/evaluator/EvaluatorV2.scala | 52 ++++++++++----- .../v1/evaluator/ctx/impl/CryptoContext.scala | 36 +++++----- .../evaluator/ctx/impl/waves/Functions.scala | 65 ++++++++----------- .../ctx/impl/waves/WavesContext.scala | 50 +++++++------- .../lang/v1/compiler/TestCompiler.scala | 8 +-- .../lang/ContractIntegrationTest.scala | 14 +++- .../wavesplatform/lang/IntegrationTest.scala | 11 +++- .../lang/doc/FunctionComplexityDocTest.scala | 4 +- .../lang/doc/ObjectTypesDocTest.scala | 2 +- .../lang/estimator/package.scala | 3 +- .../lang/evaluator/EvaluatorSpec.scala | 15 ++++- .../lang/evaluator/EvaluatorV1V2Test.scala | 6 +- .../lang/evaluator/EvaluatorV2Test.scala | 5 +- .../com/wavesplatform/utils/MerkleTest.scala | 4 +- .../api/http/utils/UtilsEvaluator.scala | 5 +- .../state/diffs/invoke/CachedDAppCTX.scala | 14 ++-- .../state/diffs/invoke/InvokeScriptDiff.scala | 4 +- .../invoke/InvokeScriptTransactionDiff.scala | 5 +- .../transaction/smart/BlockchainContext.scala | 12 ++-- .../smart/script/ScriptRunner.scala | 12 ++-- .../smart/predef/ContextFunctionsTest.scala | 4 +- .../smart/predef/MatcherBlockchainTest.scala | 3 +- .../predef/TransactionBindingsTest.scala | 8 +-- .../state/diffs/smart/predef/package.scala | 3 +- .../smart/scenarios/BalancesV4Test.scala | 8 +-- ...NotaryControlledTransferScenarioTest.scala | 2 +- .../IssueTransactionV2Specification.scala | 5 +- .../estimator/FunctionComplexityTest.scala | 5 +- .../UserFunctionComplexityTest.scala | 15 ++--- 44 files changed, 260 insertions(+), 209 deletions(-) diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/AddressFromPublicKeyBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/AddressFromPublicKeyBenchmark.scala index 68618a626f..44d9a0be37 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/AddressFromPublicKeyBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/AddressFromPublicKeyBenchmark.scala @@ -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, true)).value().evaluationContext(EnvironmentFunctionsBenchmark.environment) + val ctx = lazyContexts((ds, true, true)).value().evaluationContext(EnvironmentFunctionsBenchmark.environment) val wavesPk = ByteStr(curve25519.generateKeypair._2) val exprWaves = TestCompiler(V6).compileExpression(s"addressFromPublicKey(base58'$wavesPk')").expr.asInstanceOf[EXPR] diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntOpsBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntOpsBenchmark.scala index f955faae68..0ae875124d 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntOpsBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntOpsBenchmark.scala @@ -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, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) + val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) val max = CONST_BIGINT(PureContext.BigIntMax) val prevMax = CONST_BIGINT(PureContext.BigIntMax - 1) diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntToStringBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntToStringBenchmark.scala index 320fb3a205..200dfbb3e6 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntToStringBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/BigIntToStringBenchmark.scala @@ -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, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) + val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) val expr = FUNCTION_CALL( Native(BIGINT_TO_STRING), diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/EvaluatorV2Benchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/EvaluatorV2Benchmark.scala index 85b60437dc..f9770b1630 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/EvaluatorV2Benchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/EvaluatorV2Benchmark.scala @@ -1,25 +1,24 @@ package com.wavesplatform.lang.v1 -import java.util.concurrent.TimeUnit -import cats.Id import com.wavesplatform.lang.Common import com.wavesplatform.lang.directives.values.{V1, V3} import com.wavesplatform.lang.v1.EvaluatorV2Benchmark.* import com.wavesplatform.lang.v1.compiler.Terms.{EXPR, IF, TRUE} import com.wavesplatform.lang.v1.compiler.TestCompiler import com.wavesplatform.lang.v1.evaluator.EvaluatorV2 -import com.wavesplatform.lang.v1.evaluator.ctx.{DisabledLogEvaluationContext, EvaluationContext} +import com.wavesplatform.lang.v1.evaluator.ctx.DisabledLogEvaluationContext import com.wavesplatform.lang.v1.evaluator.ctx.impl.PureContext import com.wavesplatform.lang.v1.traits.Environment import org.openjdk.jmh.annotations.* import org.openjdk.jmh.infra.Blackhole +import java.util.concurrent.TimeUnit import scala.annotation.tailrec object EvaluatorV2Benchmark { - val pureContext: CTX[Environment] = PureContext.build(V1, useNewPowPrecision = true).withEnvironment[Environment] - val pureEvalContext: EvaluationContext[Environment, Id] = pureContext.evaluationContext(Common.emptyBlockchainEnvironment()) - val evaluatorV2: EvaluatorV2 = new EvaluatorV2(DisabledLogEvaluationContext(pureEvalContext), V1, true, true, false) + val pureContext = PureContext.build(V1, useNewPowPrecision = true).withEnvironment[Environment] + val pureEvalContext = pureContext.evaluationContext(Common.emptyBlockchainEnvironment()) + val evaluatorV2 = new EvaluatorV2(DisabledLogEvaluationContext(pureEvalContext), V1, Int.MaxValue, true, false, true, true, true) } @OutputTimeUnit(TimeUnit.MILLISECONDS) diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/FoldBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/FoldBenchmark.scala index 8613c9f7b0..dcea787f8d 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/FoldBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/FoldBenchmark.scala @@ -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, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) + val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) val function = "func f(acc: Boolean, elem: ByteVector) = acc && sigVerify(elem, base58'', base58'')" diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/FractionIntBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/FractionIntBenchmark.scala index 331d3507fb..8c23d783ab 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/FractionIntBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/FractionIntBenchmark.scala @@ -20,28 +20,28 @@ import org.openjdk.jmh.infra.Blackhole @Measurement(iterations = 10, time = 1) class FractionIntBenchmark { @Benchmark - def fraction1(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr1, LogExtraInfo(), V5, true, true, false)) + def fraction1(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr1, LogExtraInfo(), V5, true, true, false, true)) @Benchmark - def fraction2(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr2, LogExtraInfo(), V5, true, true, false)) + def fraction2(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr2, LogExtraInfo(), V5, true, true, false, true)) @Benchmark - def fraction3(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr3, LogExtraInfo(), V5, true, true, false)) + def fraction3(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr3, LogExtraInfo(), V5, true, true, false, true)) @Benchmark - def fraction1Round(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr1Round, LogExtraInfo(), V5, true, true, false)) + def fraction1Round(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr1Round, LogExtraInfo(), V5, true, true, false, true)) @Benchmark - def fraction2Round(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr2Round, LogExtraInfo(), V5, true, true, false)) + def fraction2Round(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr2Round, LogExtraInfo(), V5, true, true, false, true)) @Benchmark - def fraction3Round(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr3Round, LogExtraInfo(), V5, true, true, false)) + def fraction3Round(bh: Blackhole, s: St): Unit = bh.consume(EvaluatorV2.applyCompleted(s.ctx, s.expr3Round, LogExtraInfo(), V5, true, true, false, true)) } @State(Scope.Benchmark) class St { val ds = DirectiveSet(V6, Account, Expression).fold(null, identity) - val ctx = lazyContexts((ds, true, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) + val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) val max = Long.MaxValue val maxSqrt = 3037000499L diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowBigIntBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowBigIntBenchmark.scala index 26d3adbf25..b3781478b6 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowBigIntBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowBigIntBenchmark.scala @@ -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, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) + val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) val max = PureContext.BigIntMax val min = PureContext.BigIntMin diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowIntBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowIntBenchmark.scala index b04bd2e5c8..eba1402213 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowIntBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PowIntBenchmark.scala @@ -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, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) + val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) val max = Long.MaxValue diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PureFunctionsRebenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PureFunctionsRebenchmark.scala index dacd2a3d09..9a777dc665 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/PureFunctionsRebenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/PureFunctionsRebenchmark.scala @@ -218,7 +218,7 @@ class PureFunctionsRebenchmark { object PureFunctionsRebenchmark { val context: EvaluationContext[Environment, Id] = - lazyContexts((DirectiveSet(V5, Account, Expression).explicitGet(), true, true, true))() + lazyContexts((DirectiveSet(V5, Account, Expression).explicitGet(), true, true))() .evaluationContext(Common.emptyBlockchainEnvironment()) val eval: EXPR => (Log[Id], Int, Either[ExecutionError, EVALUATED]) = diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtCbrtBigIntBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtCbrtBigIntBenchmark.scala index 43b26d101e..326a88dd01 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtCbrtBigIntBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtCbrtBigIntBenchmark.scala @@ -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, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) + val ctx = lazyContexts((ds, true, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) val max = PureContext.BigIntMax val min = PureContext.BigIntMin diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtIntBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtIntBenchmark.scala index fffd9e8a3e..b2b6b332a0 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtIntBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/SqrtIntBenchmark.scala @@ -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, true)).value().evaluationContext(Common.emptyBlockchainEnvironment()) + val ctx = lazyContexts((ds, 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)") diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/package.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/package.scala index 95367b95d8..eedd9024c0 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/package.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/package.scala @@ -31,5 +31,14 @@ package object v1 { expr: EXPR, stdLibVersion: StdLibVersion = StdLibVersion.VersionDic.all.max ): (Log[Id], Int, Either[ExecutionError, Terms.EVALUATED]) = - EvaluatorV2.applyCompleted(ctx, expr, LogExtraInfo(), stdLibVersion, newMode = true, correctFunctionCallScope = true, enableExecutionLog = false) + EvaluatorV2.applyCompleted( + ctx, + expr, + LogExtraInfo(), + stdLibVersion, + newMode = true, + correctFunctionCallScope = true, + enableExecutionLog = false, + fixedThrownError = true + ) } diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/ExecutionError.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/ExecutionError.scala index d02bdd7a91..63dfdfea2e 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/ExecutionError.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/ExecutionError.scala @@ -7,4 +7,5 @@ case class CommonError(details: String, cause: Option[ValidationError] = None) e override def toString: String = s"CommonError($message)" override def message: String = cause.map(_.toString).getOrElse(details) } +case class ThrownError(message: String) extends ExecutionError case class FailOrRejectError(message: String, skipInvokeComplexity: Boolean = true) extends ExecutionError with ValidationError diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala index 6223495733..c65012ac24 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala @@ -64,22 +64,21 @@ package object utils { ): Coeval[(Either[ValidationError, (EVALUATED, Log[Id])], Int)] = ??? } - val lazyContexts: Map[(DirectiveSet, Boolean, Boolean, Boolean), Coeval[CTX[Environment]]] = + val lazyContexts: Map[(DirectiveSet, 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, typedError).withEnvironment[Environment] |+| - WavesContext.build(Global, ds, fixBigScriptField, typedError) + CryptoContext.build(Global, version).withEnvironment[Environment] |+| + WavesContext.build(Global, ds, fixBigScriptField) ) - (ds, useNewPowPrecision, fixBigScriptField, typedError) -> ctx + (ds, useNewPowPrecision, fixBigScriptField) -> ctx }).toMap private val lazyFunctionCosts: Map[DirectiveSet, Coeval[Map[FunctionHeader, Coeval[Long]]]] = @@ -166,7 +165,7 @@ package object utils { ScriptType.isAssetScript(isTokenContext), if (isContract) DApp else Expression ) - lazyContexts((ds.explicitGet(), true, true, true)).value() + lazyContexts((ds.explicitGet(), true, true)).value() } def compilerContext(version: StdLibVersion, cType: ContentType, isAssetScript: Boolean): CompilerContext = { @@ -175,7 +174,7 @@ package object utils { } def compilerContext(ds: DirectiveSet): CompilerContext = - lazyContexts((ds.copy(imports = Imports()), true, true, true))().compilerContext + lazyContexts((ds.copy(imports = Imports()), true, true))().compilerContext def getDecompilerContext(v: StdLibVersion, cType: ContentType): DecompilerContext = combinedContext((v, cType)).decompilerContext diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ContractEvaluator.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ContractEvaluator.scala index 531b5e6576..f66b0202f1 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ContractEvaluator.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ContractEvaluator.scala @@ -119,7 +119,8 @@ object ContractEvaluator { limit: Int, correctFunctionCallScope: Boolean, newMode: Boolean, - enableExecutionLog: Boolean + enableExecutionLog: Boolean, + fixedThrownError: Boolean ): Coeval[Either[(ExecutionError, Int, Log[Id]), (ScriptResult, Log[Id])]] = Coeval .now(buildExprFromInvocation(dApp, i, version).leftMap((_, limit, Nil))) @@ -134,7 +135,8 @@ object ContractEvaluator { limit, correctFunctionCallScope, newMode, - enableExecutionLog + enableExecutionLog, + fixedThrownError ) case Left(error) => Coeval.now(Left(error)) } @@ -148,10 +150,21 @@ object ContractEvaluator { limit: Int, correctFunctionCallScope: Boolean, newMode: Boolean, - enableExecutionLog: Boolean + enableExecutionLog: Boolean, + fixedThrownError: Boolean ): Coeval[Either[(ExecutionError, Int, Log[Id]), (ScriptResult, Log[Id])]] = EvaluatorV2 - .applyLimitedCoeval(expr, logExtraInfo, limit, ctx, version, correctFunctionCallScope, newMode, enableExecutionLog = enableExecutionLog) + .applyLimitedCoeval( + expr, + logExtraInfo, + limit, + ctx, + version, + correctFunctionCallScope, + newMode, + enableExecutionLog = enableExecutionLog, + fixedThrownError = fixedThrownError + ) .map(_.flatMap { case (expr, unusedComplexity, log) => val result = expr match { diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/EvaluatorV2.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/EvaluatorV2.scala index 7935c6fab7..77c16ee5f5 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/EvaluatorV2.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/EvaluatorV2.scala @@ -9,20 +9,13 @@ import com.wavesplatform.lang.v1.FunctionHeader import com.wavesplatform.lang.v1.compiler.Terms.* import com.wavesplatform.lang.v1.compiler.Types.CASETYPEREF import com.wavesplatform.lang.v1.evaluator.ContextfulNativeFunction.{Extended, Simple} -import com.wavesplatform.lang.v1.evaluator.ctx.{ - DisabledLogEvaluationContext, - EnabledLogEvaluationContext, - EvaluationContext, - LoggedEvaluationContext, - NativeFunction, - UserFunction -} import com.wavesplatform.lang.v1.evaluator.ContractEvaluator.LogExtraInfo -import com.wavesplatform.lang.v1.evaluator.EvaluatorV2.logFunc import com.wavesplatform.lang.v1.evaluator.EvaluatorV2.LogKeys.* +import com.wavesplatform.lang.v1.evaluator.EvaluatorV2.logFunc import com.wavesplatform.lang.v1.evaluator.ctx.impl.waves.Bindings +import com.wavesplatform.lang.v1.evaluator.ctx.* import com.wavesplatform.lang.v1.traits.Environment -import com.wavesplatform.lang.{CommonError, ExecutionError} +import com.wavesplatform.lang.{CommonError, ExecutionError, ThrownError} import monix.eval.Coeval import shapeless.syntax.std.tuple.* @@ -32,10 +25,12 @@ import scala.collection.mutable.ListBuffer class EvaluatorV2( val ctx: LoggedEvaluationContext[Environment, Id], val stdLibVersion: StdLibVersion, + val limit: Int, val correctFunctionCallScope: Boolean, val newMode: Boolean, val enableExecutionLog: Boolean, - val checkConstructorArgsTypes: Boolean = false + val checkConstructorArgsTypes: Boolean, + val fixedThrownError: Boolean ) { private val overheadCost: Int = if (newMode) 0 else 1 @@ -117,7 +112,14 @@ class EvaluatorV2( (result, unusedComplexity) <- EvaluationResult( evaluation .map { case (result, evaluatedComplexity) => - result.bimap((_, evaluatedComplexity), (_, evaluatedComplexity)) + result.bimap( + { + case e: ThrownError if !fixedThrownError && function.ev.isInstanceOf[Extended[Environment]] => (e, this.limit) + case e: ThrownError if !fixedThrownError => (e, 0) + case e => (e, evaluatedComplexity) + }, + (_, evaluatedComplexity) + ) } .onErrorHandleWith { case _: SecurityException => @@ -360,7 +362,8 @@ object EvaluatorV2 { correctFunctionCallScope: Boolean, newMode: Boolean, checkConstructorArgsTypes: Boolean = false, - enableExecutionLog: Boolean = false + enableExecutionLog: Boolean = false, + fixedThrownError: Boolean ): Coeval[Either[(ExecutionError, Int, Log[Id]), (EXPR, Int, Log[Id])]] = { val log = ListBuffer[LogItem[Id]]() @@ -371,7 +374,16 @@ object EvaluatorV2 { } var ref = expr.deepCopy.value logCall(loggedCtx, logExtraInfo, ref, enableExecutionLog) - new EvaluatorV2(loggedCtx, stdLibVersion, correctFunctionCallScope, newMode, enableExecutionLog, checkConstructorArgsTypes) + new EvaluatorV2( + loggedCtx, + stdLibVersion, + limit, + correctFunctionCallScope, + newMode, + enableExecutionLog, + checkConstructorArgsTypes, + fixedThrownError + ) .root(ref, v => EvaluationResult { ref = v }, limit, Nil) .map((ref, _)) .value @@ -390,7 +402,8 @@ object EvaluatorV2 { correctFunctionCallScope: Boolean, newMode: Boolean, handleExpr: EXPR => Either[ExecutionError, EVALUATED], - enableExecutionLog: Boolean + enableExecutionLog: Boolean, + fixedThrownError: Boolean ): (Log[Id], Int, Either[ExecutionError, EVALUATED]) = EvaluatorV2 .applyLimitedCoeval( @@ -401,7 +414,8 @@ object EvaluatorV2 { stdLibVersion, correctFunctionCallScope, newMode, - enableExecutionLog = enableExecutionLog + enableExecutionLog = enableExecutionLog, + fixedThrownError = fixedThrownError ) .value() .fold( @@ -421,7 +435,8 @@ object EvaluatorV2 { stdLibVersion: StdLibVersion, correctFunctionCallScope: Boolean, newMode: Boolean, - enableExecutionLog: Boolean + enableExecutionLog: Boolean, + fixedThrownError: Boolean ): (Log[Id], Int, Either[ExecutionError, EVALUATED]) = applyOrDefault( ctx, @@ -432,7 +447,8 @@ object EvaluatorV2 { correctFunctionCallScope, newMode, expr => Left(s"Unexpected incomplete evaluation result $expr"), - enableExecutionLog + enableExecutionLog, + fixedThrownError ) private def logCall( diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/CryptoContext.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/CryptoContext.scala index 1854e26a3b..52b0a4a6a9 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/CryptoContext.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/CryptoContext.scala @@ -14,7 +14,7 @@ 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 com.wavesplatform.lang.{CommonError, ExecutionError, ThrownError} import scala.collection.mutable import scala.util.Try @@ -42,17 +42,17 @@ object CryptoContext { private def digestAlgValue(tpe: CASETYPEREF): ContextfulVal[NoContext] = ContextfulVal.pure(CaseObj(tpe, Map.empty)) - def build(global: BaseGlobal, version: StdLibVersion, typedError: Boolean = true): CTX[NoContext] = + def build(global: BaseGlobal, version: StdLibVersion): CTX[NoContext] = ctxCache.getOrElse( - (global, version, typedError), + (global, version), ctxCache.synchronized { - ctxCache.getOrElseUpdate((global, version, typedError), buildNew(global, version, typedError)) + ctxCache.getOrElseUpdate((global, version), buildNew(global, version)) } ) - private val ctxCache = mutable.AnyRefMap.empty[(BaseGlobal, StdLibVersion, Boolean), CTX[NoContext]] + private val ctxCache = mutable.AnyRefMap.empty[(BaseGlobal, StdLibVersion), CTX[NoContext]] - private def buildNew(global: BaseGlobal, version: StdLibVersion, typedError: Boolean): CTX[NoContext] = { + private def buildNew(global: BaseGlobal, version: StdLibVersion): CTX[NoContext] = { def functionFamily( startId: Short, nameByLimit: Int => String, @@ -360,7 +360,7 @@ object CryptoContext { case xs => notImplemented[Id, EVALUATED](s"checkMerkleProof(merkleRoot: ByteVector, merkleProof: ByteVector, valueBytes: ByteVector)", xs) } - def createMerkleRootF(typedError: Boolean): BaseFunction[NoContext] = + val createMerkleRootF: BaseFunction[NoContext] = NativeFunction( "createMerkleRoot", 30, @@ -373,9 +373,9 @@ object CryptoContext { case xs @ ARR(proof) :: CONST_BYTESTR(value) :: CONST_LONG(index) :: Nil => 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) + Try(createRoot(value.arr, Math.toIntExact(index), sizeCheckedProofs.reverse.map(_.bs.arr))) + .toEither + .leftMap(e => ThrownError(if (e.getMessage != null) e.getMessage else "error")) .flatMap(r => CONST_BYTESTR(ByteStr(r))) } else { notImplemented[Id, EVALUATED](s"createMerkleRoot(merkleProof: ByteVector, valueBytes: ByteVector, index: Int)", xs) @@ -550,11 +550,11 @@ object CryptoContext { fromBase16StringF(checkLength = false) ) - def fromV4Functions(version: StdLibVersion, typedError: Boolean) = + def fromV4Functions(version: StdLibVersion) = Array( bls12Groth16VerifyF, bn256Groth16VerifyF, - createMerkleRootF(typedError), + createMerkleRootF, ecrecover, // new in V4 rsaVerifyF, toBase16StringF(checkLength = true), @@ -563,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, typedError)) - val fromV6Ctx = fromV1Ctx |+| CTX[NoContext](v6Types, v4Vars, fromV4Functions(V6, typedError)) + val fromV4Ctx = fromV1Ctx |+| CTX[NoContext](v4Types, v4Vars, fromV4Functions(V4)) + val fromV6Ctx = fromV1Ctx |+| CTX[NoContext](v6Types, v4Vars, fromV4Functions(V6)) version match { case V1 | V2 => fromV1Ctx @@ -574,9 +574,9 @@ object CryptoContext { } } - def evalContext[F[_]: Monad](global: BaseGlobal, version: StdLibVersion, typedError: Boolean): EvaluationContext[NoContext, F] = - build(global, version, typedError).evaluationContext[F] + def evalContext[F[_]: Monad](global: BaseGlobal, version: StdLibVersion): EvaluationContext[NoContext, F] = + build(global, version).evaluationContext[F] - def compilerContext(global: BaseGlobal, version: StdLibVersion, typedError: Boolean): CompilerContext = - build(global, version, typedError).compilerContext + def compilerContext(global: BaseGlobal, version: StdLibVersion): CompilerContext = + build(global, version).compilerContext } diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala index cf38917991..62b9397a6d 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala @@ -23,7 +23,7 @@ import com.wavesplatform.lang.v1.evaluator.{ContextfulNativeFunction, Contextful import com.wavesplatform.lang.v1.traits.domain.{Issue, Lease, Recipient} import com.wavesplatform.lang.v1.traits.{DataType, Environment} import com.wavesplatform.lang.v1.{BaseGlobal, FunctionHeader} -import com.wavesplatform.lang.{CoevalF, CommonError, ExecutionError, FailOrRejectError} +import com.wavesplatform.lang.{CoevalF, CommonError, ExecutionError, FailOrRejectError, ThrownError} import monix.eval.Coeval import shapeless.Coproduct.unsafeGet @@ -413,18 +413,14 @@ object Functions { case xs => notImplemented[Id, EVALUATED](s"toString(a: Address)", xs) } - private def errorE[R](message: String, typedError: Boolean): Either[ExecutionError, R] = - if (typedError) (message: ExecutionError).asLeft[R] - else throw new IllegalArgumentException(message) - - private def caseObjToRecipient(c: CaseObj, typedError: Boolean): Either[ExecutionError, Recipient] = + private def caseObjToRecipient(c: CaseObj): Either[ExecutionError, Recipient] = c.caseType.name match { case addressType.name => Right(Recipient.Address(c.fields("bytes").asInstanceOf[CONST_BYTESTR].bs)) case aliasType.name => Right(Recipient.Alias(c.fields("alias").asInstanceOf[CONST_STRING].s)) - case t => errorE(s"Unexpected recipient type $t", typedError) + case t => Left(ThrownError(s"Unexpected recipient type $t")) } - def assetBalanceF(typedError: Boolean): BaseFunction[Environment] = + val assetBalanceF: BaseFunction[Environment] = NativeFunction.withEnvironment[Environment]( "assetBalance", Map[StdLibVersion, Long](V1 -> 100L, V2 -> 100L, V3 -> 100L, V4 -> 10L), @@ -441,13 +437,13 @@ object Functions { override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = args match { case (c: CaseObj) :: u :: Nil if u == unit => - caseObjToRecipient(c, typedError) + caseObjToRecipient(c) .fold( _.asLeft[EVALUATED].pure[F], r => env.accountBalanceOf(r, None).map(_.map(CONST_LONG).leftMap(CommonError(_))) ) case (c: CaseObj) :: CONST_BYTESTR(assetId: ByteStr) :: Nil => - caseObjToRecipient(c, typedError) + caseObjToRecipient(c) .fold( _.asLeft[EVALUATED].pure[F], r => env.accountBalanceOf(r, Some(assetId.arr)).map(_.map(CONST_LONG).leftMap(CommonError(_))) @@ -458,7 +454,7 @@ object Functions { } } - def assetBalanceV4F(typedError: Boolean): BaseFunction[Environment] = + val assetBalanceV4F: BaseFunction[Environment] = NativeFunction.withEnvironment[Environment]( "assetBalance", 10, @@ -471,7 +467,7 @@ object Functions { override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = args match { case (c: CaseObj) :: CONST_BYTESTR(assetId: ByteStr) :: Nil => - caseObjToRecipient(c, typedError) + caseObjToRecipient(c) .fold( _.asLeft[EVALUATED].pure[F], r => env.accountBalanceOf(r, Some(assetId.arr)).map(_.map(CONST_LONG).leftMap(CommonError(_))) @@ -482,7 +478,7 @@ object Functions { } } - def wavesBalanceV4F(typedError: Boolean): BaseFunction[Environment] = + val wavesBalanceV4F: BaseFunction[Environment] = NativeFunction.withEnvironment[Environment]( "wavesBalance", 10, @@ -494,7 +490,7 @@ object Functions { override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = args match { case (c: CaseObj) :: Nil => - caseObjToRecipient(c, typedError) + caseObjToRecipient(c) .fold( _.asLeft[EVALUATED].pure[F], r => @@ -546,9 +542,9 @@ object Functions { } } - def wavesBalanceF(typedError: Boolean): BaseFunction[Environment] = + val wavesBalanceF: BaseFunction[Environment] = UserFunction("wavesBalance", 109, LONG, ("@addressOrAlias", addressOrAliasType)) { - FUNCTION_CALL(assetBalanceF(typedError).header, List(REF("@addressOrAlias"), REF(GlobalValNames.Unit))) + FUNCTION_CALL(assetBalanceF.header, List(REF("@addressOrAlias"), REF(GlobalValNames.Unit))) } val txHeightByIdF: BaseFunction[Environment] = @@ -597,7 +593,7 @@ object Functions { } } - def callDAppF(reentrant: Boolean, typedError: Boolean): BaseFunction[Environment] = { + def callDAppF(reentrant: Boolean): BaseFunction[Environment] = { val (id, name) = if (reentrant) (CALLDAPPREENTRANT, "reentrantInvoke") else (CALLDAPP, "invoke") NativeFunction.withEnvironment[Environment]( name, @@ -619,8 +615,8 @@ object Functions { args: List[EVALUATED], availableComplexity: Int )(implicit monad: Monad[CoevalF[F, *]]): Coeval[F[(Either[ExecutionError, (EVALUATED, Log[F])], Int)]] = { - def errorF[R](message: String): F[Either[ExecutionError, R]] = - errorE[R](message, typedError).pure[F] + def thrown[R](message: String): F[Either[ExecutionError, R]] = + (ThrownError(message): ExecutionError).asLeft[R].pure[F] val processedArgs = for { dAppBytes <- EitherT[F, ExecutionError, ByteStr]( @@ -628,30 +624,25 @@ object Functions { case (dApp: CaseObj) :: _ if dApp.caseType == addressType => dApp.fields.get("bytes") match { case Some(CONST_BYTESTR(d)) => d.asRight[ExecutionError].pure[F] - case a => errorF(s"Unexpected address bytes $a") + case a => thrown(s"Unexpected address bytes $a") } case (dApp: CaseObj) :: _ if dApp.caseType == aliasType => dApp.fields.get("alias") match { - case Some(CONST_STRING(a)) => - if (typedError) - env.resolveAlias(a).map(_.bimap(CommonError(_): ExecutionError, _.bytes)) - else - env.resolveAlias(a).map(_.explicitGet().bytes.asRight[ExecutionError]) - case arg => - errorF(s"Unexpected alias arg $arg") + case Some(CONST_STRING(a)) => env.resolveAlias(a).map(_.bimap(ThrownError, _.bytes)) + case arg => thrown(s"Unexpected alias arg $arg") } case arg :: _ => - errorF(s"Unexpected recipient arg $arg") + thrown(s"Unexpected recipient arg $arg") case args => - errorF(s"Unexpected args $args") + thrown(s"Unexpected args $args") } ) name <- EitherT[F, ExecutionError, String]( args match { case _ :: CONST_STRING(name) :: _ => name.asRight[ExecutionError].pure[F] case _ :: CaseObj(UNIT, _) :: _ => "default".asRight[ExecutionError].pure[F] - case _ :: arg :: _ => errorF(s"Unexpected name arg $arg") - case args => errorF(s"Unexpected args $args") + case _ :: arg :: _ => thrown(s"Unexpected name arg $arg") + case args => thrown(s"Unexpected args $args") } ) payments <- EitherT[F, ExecutionError, Seq[(Option[Array[Byte]], Long)]]( @@ -663,10 +654,10 @@ object Functions { List("assetId", "amount").flatMap(p.fields.get) match { case CONST_BYTESTR(a) :: CONST_LONG(v) :: Nil => Right((Some(a.arr), v)) case CaseObj(UNIT, _) :: CONST_LONG(v) :: Nil => Right((None, v)) - case args => errorE(s"Unexpected payment args $args", typedError) + case args => Left(ThrownError(s"Unexpected payment args $args"): ExecutionError) } case arg => - errorE(s"Unexpected payment arg $arg", typedError) + Left(ThrownError(s"Unexpected payment arg $arg"): ExecutionError) } .pure[F] case args => @@ -933,7 +924,7 @@ object Functions { Right(CaseObj(leaseActionType, typedArgs)) } - def calculateLeaseId(typedError: Boolean): BaseFunction[Environment] = + val calculateLeaseId: BaseFunction[Environment] = NativeFunction.withEnvironment[Environment]( "calculateLeaseId", 1, @@ -946,7 +937,7 @@ object Functions { override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = args match { case CaseObj(`leaseActionType`, fields) :: Nil => - caseObjToRecipient(fields(FieldNames.LeaseRecipient).asInstanceOf[CaseObj], typedError) + caseObjToRecipient(fields(FieldNames.LeaseRecipient).asInstanceOf[CaseObj]) .flatMap { case Recipient.Address(bytes) if bytes.arr.length > AddressLength => Left(CommonError(s"Address bytes length=${bytes.arr.length} exceeds limit=$AddressLength"): ExecutionError) @@ -971,7 +962,7 @@ object Functions { } } - def accountScriptHashF(global: BaseGlobal, typedError: Boolean): BaseFunction[Environment] = { + def accountScriptHashF(global: BaseGlobal): BaseFunction[Environment] = { val name = "scriptHash" val resType = UNION(BYTESTR, UNIT) val arg = ("account", addressOrAliasType) @@ -990,7 +981,7 @@ object Functions { override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = args match { case List(addr: CaseObj) => - caseObjToRecipient(addr, typedError) + caseObjToRecipient(addr) .fold( _.asLeft[EVALUATED].pure[F], recipient => diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala index b75ed16f26..ce8829ea19 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala @@ -13,8 +13,8 @@ import com.wavesplatform.lang.v1.traits.* import com.wavesplatform.lang.v1.{BaseGlobal, CTX} object WavesContext { - def build(global: BaseGlobal, ds: DirectiveSet, fixBigScriptField: Boolean, typedError: Boolean = true): CTX[Environment] = - invariableCtx |+| variableCtx(global, ds, fixBigScriptField, typedError) + def build(global: BaseGlobal, ds: DirectiveSet, fixBigScriptField: Boolean): CTX[Environment] = + invariableCtx |+| variableCtx(global, ds, fixBigScriptField) private val commonFunctions = Array( @@ -26,22 +26,22 @@ object WavesContext { addressFromRecipientF ) - private def balanceV123Functions(typedError: Boolean) = + private val balanceV123Functions = Array( - assetBalanceF(typedError), - wavesBalanceF(typedError) + assetBalanceF, + wavesBalanceF ) - private def balanceV4Functions(typedError: Boolean) = + private val balanceV4Functions = Array( - assetBalanceV4F(typedError), - wavesBalanceV4F(typedError) + assetBalanceV4F, + wavesBalanceV4F ) private val invariableCtx = CTX(Seq(), Map(height), commonFunctions) - private def variableCtx(global: BaseGlobal, ds: DirectiveSet, fixBigScriptField: Boolean, typedError: Boolean): CTX[Environment] = { + private def variableCtx(global: BaseGlobal, ds: DirectiveSet, fixBigScriptField: Boolean): CTX[Environment] = { val isTokenContext = ds.scriptType == Asset val proofsEnabled = !isTokenContext val version = ds.stdLibVersion @@ -50,7 +50,7 @@ object WavesContext { CTX( types, variableVars(isTokenContext, version, ds.contentType, proofsEnabled, fixBigScriptField), - variableFuncs(global, ds, typeDefs, proofsEnabled, typedError) + variableFuncs(global, ds, typeDefs, proofsEnabled) ) } @@ -62,25 +62,25 @@ object WavesContext { stringFromAddressF ) - private def fromV4Funcs(proofsEnabled: Boolean, typedError: Boolean, version: StdLibVersion, typeDefs: Map[String, FINAL]) = + private def fromV4Funcs(proofsEnabled: Boolean, version: StdLibVersion, typeDefs: Map[String, FINAL]) = fromV3Funcs(proofsEnabled, version, typeDefs) ++ Array( calculateAssetIdF, transactionFromProtoBytesF(proofsEnabled, version, typeDefs), simplifiedIssueActionConstructor, detailedIssueActionConstructor - ) ++ balanceV4Functions(typedError: Boolean) + ) ++ balanceV4Functions - private def fromV5Funcs(proofsEnabled: Boolean, typedError: Boolean, ds: DirectiveSet, typeDefs: Map[String, FINAL]) = { + private def fromV5Funcs(proofsEnabled: Boolean, ds: DirectiveSet, typeDefs: Map[String, FINAL]) = { val v5Funcs = Array( simplifiedLeaseActionConstructor, detailedLeaseActionConstructor, - calculateLeaseId(typedError), + calculateLeaseId, isDataStorageUntouchedF ) val dAppFuncs = if (ds.contentType == DApp || ds.scriptType == Call) - Array(callDAppF(reentrant = false, typedError), callDAppF(reentrant = true, typedError)) + Array(callDAppF(reentrant = false), callDAppF(reentrant = true)) else Array[BaseFunction[Environment]]() @@ -90,11 +90,11 @@ object WavesContext { else Array[BaseFunction[Environment]]() - fromV4Funcs(proofsEnabled, typedError, ds.stdLibVersion, typeDefs) ++ v5Funcs ++ dAppFuncs ++ accountFuncs + fromV4Funcs(proofsEnabled, ds.stdLibVersion, typeDefs) ++ v5Funcs ++ dAppFuncs ++ accountFuncs } - private def fromV8Funcs(proofsEnabled: Boolean, typedError: Boolean, ds: DirectiveSet, typeDefs: Map[String, FINAL]) = - fromV5Funcs(proofsEnabled, typedError, ds, typeDefs) :+ calculateDelay + private def fromV8Funcs(proofsEnabled: Boolean, ds: DirectiveSet, typeDefs: Map[String, FINAL]) = + fromV5Funcs(proofsEnabled, ds, typeDefs) :+ calculateDelay private def selfCallFunctions(v: StdLibVersion) = Array( @@ -104,7 +104,7 @@ object WavesContext { getStringFromStateSelfF ) ++ extractedStateSelfFuncs(v) - private def variableFuncs(global: BaseGlobal, ds: DirectiveSet, typeDefs: Map[String, FINAL], proofsEnabled: Boolean, typedError: Boolean) = { + private def variableFuncs(global: BaseGlobal, ds: DirectiveSet, typeDefs: Map[String, FINAL], proofsEnabled: Boolean) = { val version = ds.stdLibVersion val commonFuncs = Array( @@ -118,15 +118,15 @@ object WavesContext { getStringByIndexF(version), if (version >= V4) addressFromStringV4 else addressFromStringF(version), if (version >= V6) addressFromPublicKeyNative else addressFromPublicKeyF(version) - ) ++ (if (version >= V5) Array(accountScriptHashF(global, typedError)) else Array()) + ) ++ (if (version >= V5) Array(accountScriptHashF(global)) else Array()) val versionSpecificFuncs = version match { - case V1 | V2 => Array(txByIdF(proofsEnabled, version)) ++ balanceV123Functions(typedError) - case V3 => fromV3Funcs(proofsEnabled, version, typeDefs) ++ balanceV123Functions(typedError) - case V4 => fromV4Funcs(proofsEnabled, typedError, version, typeDefs) - case V5 | V6 | V7 => fromV5Funcs(proofsEnabled, typedError, ds, typeDefs) - case _ => fromV8Funcs(proofsEnabled, typedError, ds, typeDefs) + case V1 | V2 => Array(txByIdF(proofsEnabled, version)) ++ balanceV123Functions + case V3 => fromV3Funcs(proofsEnabled, version, typeDefs) ++ balanceV123Functions + case V4 => fromV4Funcs(proofsEnabled, version, typeDefs) + case V5 | V6 | V7 => fromV5Funcs(proofsEnabled, ds, typeDefs) + case _ => fromV8Funcs(proofsEnabled, ds, typeDefs) } commonFuncs ++ versionSpecificFuncs } diff --git a/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala b/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala index 6711c41f7c..deebef973c 100644 --- a/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala +++ b/lang/testkit/src/main/scala/com/wavesplatform/lang/v1/compiler/TestCompiler.scala @@ -21,14 +21,14 @@ import scala.collection.mutable class TestCompiler(version: StdLibVersion) { private lazy val baseCompilerContext = PureContext.build(version, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, version, typedError = true).withEnvironment[Environment] + CryptoContext.build(Global, version).withEnvironment[Environment] private lazy val compilerContext = (baseCompilerContext |+| - WavesContext.build(Global, DirectiveSet(version, Account, DAppType).explicitGet(), fixBigScriptField = true, typedError = true)).compilerContext + WavesContext.build(Global, DirectiveSet(version, Account, DAppType).explicitGet(), fixBigScriptField = true)).compilerContext private lazy val expressionContext: CTX[Environment] = - WavesContext.build(Global, DirectiveSet(version, Account, Expression).explicitGet(), fixBigScriptField = true, typedError = true) + WavesContext.build(Global, DirectiveSet(version, Account, Expression).explicitGet(), fixBigScriptField = true) private lazy val expressionCompilerContext = (baseCompilerContext |+| @@ -36,7 +36,7 @@ class TestCompiler(version: StdLibVersion) { private lazy val assetCompilerContext = (baseCompilerContext |+| - WavesContext.build(Global, DirectiveSet(version, Asset, Expression).explicitGet(), fixBigScriptField = true, typedError = true)).compilerContext + WavesContext.build(Global, DirectiveSet(version, Asset, Expression).explicitGet(), fixBigScriptField = true)).compilerContext def compile( script: String, diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/ContractIntegrationTest.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/ContractIntegrationTest.scala index f4d504ccf7..f53431ea3e 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/ContractIntegrationTest.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/ContractIntegrationTest.scala @@ -175,7 +175,8 @@ class ContractIntegrationTest extends PropSpec with Inside { Int.MaxValue, correctFunctionCallScope = true, newMode = false, - enableExecutionLog = true + enableExecutionLog = true, + fixedThrownError = true ) .value() .leftMap { case (e, _, log) => (e, log) } @@ -190,7 +191,16 @@ class ContractIntegrationTest extends PropSpec with Inside { compiled.decs, compiled.verifierFuncOpt.get, EvaluatorV2 - .applyCompleted(ctx.evaluationContext(environment), _, _, V3, correctFunctionCallScope = true, newMode = false, enableExecutionLog = false), + .applyCompleted( + ctx.evaluationContext(environment), + _, + _, + V3, + correctFunctionCallScope = true, + newMode = false, + enableExecutionLog = false, + fixedThrownError = true + ), txObject ) ._3 diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/IntegrationTest.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/IntegrationTest.scala index 4985b44bba..1905a9fa6a 100755 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/IntegrationTest.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/IntegrationTest.scala @@ -93,7 +93,16 @@ class IntegrationTest extends PropSpec with Inside { val evalCtx = ctx.evaluationContext(env).asInstanceOf[EvaluationContext[Environment, Id]] compiled.flatMap(v => EvaluatorV2 - .applyCompleted(evalCtx, v._1, LogExtraInfo(), version, correctFunctionCallScope = true, newMode = true, enableExecutionLog = false) + .applyCompleted( + evalCtx, + v._1, + LogExtraInfo(), + version, + correctFunctionCallScope = true, + newMode = true, + enableExecutionLog = false, + fixedThrownError = true + ) ._3 .bimap(_.message, _.asInstanceOf[T]) ) diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/doc/FunctionComplexityDocTest.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/doc/FunctionComplexityDocTest.scala index 13db32b351..05f07ab6a8 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/doc/FunctionComplexityDocTest.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/doc/FunctionComplexityDocTest.scala @@ -102,7 +102,7 @@ class FunctionComplexityDocTest extends PropSpec { property("JS API functions") { lazyContexts - .flatMap { case ((ds, _, _, _), _) => + .flatMap { case ((ds, _, _), _) => API .allFunctions(ds.stdLibVersion.id, ds.scriptType == Asset, ds.contentType == DApp) .map((_, ds.stdLibVersion)) @@ -114,7 +114,7 @@ class FunctionComplexityDocTest extends PropSpec { property("JS API vars") { lazyContexts - .flatMap { case ((ds, _, _, _), _) => + .flatMap { case ((ds, _, _), _) => API .allVars(ds.stdLibVersion.id, ds.scriptType == Asset, ds.contentType == DApp) .map((_, ds.stdLibVersion)) diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/doc/ObjectTypesDocTest.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/doc/ObjectTypesDocTest.scala index e8f6190366..e7bada12fa 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/doc/ObjectTypesDocTest.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/doc/ObjectTypesDocTest.scala @@ -19,7 +19,7 @@ class ObjectTypesDocTest extends PropSpec { fields.map { case (name, t) => s"$name: $t" }.mkString("\n\n", "\n", "\n\n") property("all object types") { - lazyContexts.foreach { case ((ds, _, _, _), ctx) => + lazyContexts.foreach { case ((ds, _, _), ctx) => ctx().types .collect { case CASETYPEREF(name, fields, _) => val codeFields = fields.map { case (name, t) => (name, t.toString) } diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/estimator/package.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/estimator/package.scala index 505857d05d..5f7bf55867 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/estimator/package.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/estimator/package.scala @@ -28,7 +28,8 @@ package object estimator { V3, correctFunctionCallScope = true, overhead, - enableExecutionLog = false + enableExecutionLog = false, + fixedThrownError = true ) def evaluatorV2AsEstimator(overhead: Boolean): ScriptEstimator = new ScriptEstimator { diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorSpec.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorSpec.scala index 3b370ce8f9..4b1cf9590b 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorSpec.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorSpec.scala @@ -73,13 +73,22 @@ abstract class EvaluatorSpec extends PropSpec with ScriptGen with Inside { } private def evalExpr(expr: EXPR, version: StdLibVersion, useNewPowPrecision: Boolean): (Log[Id], Int, Either[ExecutionError, EVALUATED]) = { - val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), useNewPowPrecision, true, true)).value() + val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), useNewPowPrecision, true)).value() val evalCtx = ctx.evaluationContext(Common.emptyBlockchainEnvironment()) - EvaluatorV2.applyCompleted(evalCtx, expr, LogExtraInfo(), version, correctFunctionCallScope = true, newMode = true, enableExecutionLog = false) + EvaluatorV2.applyCompleted( + evalCtx, + expr, + LogExtraInfo(), + version, + correctFunctionCallScope = true, + newMode = true, + enableExecutionLog = false, + fixedThrownError = true + ) } def compile(code: String, version: StdLibVersion): Either[String, EXPR] = { - val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), true, true, true)).value() + val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), true, true)).value() val parsed = Parser.parseExpr(code).get.value ExpressionCompiler(ctx.compilerContext, parsed, allowIllFormedStrings = true).map(_._1) } diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV1V2Test.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV1V2Test.scala index 3c0dbc8745..6499fcefe2 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV1V2Test.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV1V2Test.scala @@ -75,7 +75,8 @@ class EvaluatorV1V2Test extends PropSpec with EitherValues { implicitly[StdLibVersion], correctFunctionCallScope = true, newMode = true, - enableExecutionLog = false + enableExecutionLog = false, + fixedThrownError = true ) ._3 .asInstanceOf[Either[ExecutionError, T]] @@ -101,7 +102,8 @@ class EvaluatorV1V2Test extends PropSpec with EitherValues { implicitly[StdLibVersion], correctFunctionCallScope = true, newMode = true, - enableExecutionLog = true + enableExecutionLog = true, + fixedThrownError = true ) evaluatorV2Result shouldBe evaluatorV1Result.bimap(_._1, _._1) diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV2Test.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV2Test.scala index 37be313bd2..02c24fe2e9 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV2Test.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/evaluator/EvaluatorV2Test.scala @@ -20,7 +20,7 @@ import scala.util.Random class EvaluatorV2Test extends PropSpec with Inside { private val version = V4 - private val ctx = lazyContexts((DirectiveSet(version, Account, DApp).explicitGet(), true, true, true))() + private val ctx = lazyContexts((DirectiveSet(version, Account, DApp).explicitGet(), true, true))() private val environment = Common.emptyBlockchainEnvironment() private def evalEither(expr: EXPR, limit: Int, newMode: Boolean): Either[String, (EXPR, Int)] = @@ -32,7 +32,8 @@ class EvaluatorV2Test extends PropSpec with Inside { ctx.evaluationContext(environment), version, correctFunctionCallScope = true, - newMode + newMode, + fixedThrownError = true ) .value() .bimap(_._1.message, { case (result, complexity, _) => (result, complexity) }) diff --git a/lang/tests/src/test/scala/com/wavesplatform/utils/MerkleTest.scala b/lang/tests/src/test/scala/com/wavesplatform/utils/MerkleTest.scala index 8429e836cd..b50669e964 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/utils/MerkleTest.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/utils/MerkleTest.scala @@ -107,10 +107,10 @@ class MerkleTest extends PropSpec { private def eval(code: String, version: StdLibVersion = V3): Either[String, EVALUATED] = { val untyped = Parser.parseExpr(code).get.value - val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), true, true, true))() + val ctx = lazyContexts((DirectiveSet(version, Account, Expression).explicitGet(), true, true))() val evalCtx = ctx.evaluationContext[Id](Common.emptyBlockchainEnvironment()) val typed = ExpressionCompiler(ctx.compilerContext, untyped) - typed.flatMap(v => EvaluatorV2.applyCompleted(evalCtx, v._1, LogExtraInfo(), version, true, true, false)._3.leftMap(_.toString)) + typed.flatMap(v => EvaluatorV2.applyCompleted(evalCtx, v._1, LogExtraInfo(), version, true, true, false, true)._3.leftMap(_.toString)) } private def scriptSrc(root: Array[Byte], proof: Array[Byte], value: Array[Byte]): String = { diff --git a/node/src/main/scala/com/wavesplatform/api/http/utils/UtilsEvaluator.scala b/node/src/main/scala/com/wavesplatform/api/http/utils/UtilsEvaluator.scala index e0252ddfc8..e206812767 100644 --- a/node/src/main/scala/com/wavesplatform/api/http/utils/UtilsEvaluator.scala +++ b/node/src/main/scala/com/wavesplatform/api/http/utils/UtilsEvaluator.scala @@ -109,7 +109,7 @@ object UtilsEvaluator { currentSnapshot = paymentsSnapshot, invocationRoot = DAppEnvironment.InvocationTreeTracker(DAppEnvironment.DAppInvocation(dAppAddress, null, Nil)) ) - ctx = BlockchainContext.build(ds, environment, fixUnicodeFunctions = true, useNewPowPrecision = true, fixBigScriptField = true, typedError = true) + ctx = BlockchainContext.build(ds, environment, fixUnicodeFunctions = true, useNewPowPrecision = true, fixBigScriptField = true) dApp = ContractScriptCompactor.decompact(script.expr.asInstanceOf[DApp]) expr <- dAppToExpr(dApp) limitedResult <- EvaluatorV2 @@ -122,7 +122,8 @@ object UtilsEvaluator { correctFunctionCallScope = blockchain.checkEstimatorSumOverflow, newMode = blockchain.newEvaluatorMode, checkConstructorArgsTypes = true, - enableExecutionLog = true + enableExecutionLog = true, + fixedThrownError = true ) .value() .leftMap { case (err, _, log) => InvokeRejectError(err.message, log) } diff --git a/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala b/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala index fc07388187..93b026f1db 100644 --- a/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala +++ b/node/src/main/scala/com/wavesplatform/state/diffs/invoke/CachedDAppCTX.scala @@ -2,7 +2,7 @@ package com.wavesplatform.state.diffs.invoke import cats.syntax.semigroup.* import com.wavesplatform.common.utils.EitherExt2 -import com.wavesplatform.features.BlockchainFeatures.{ConsensusImprovements, LightNode, SynchronousCalls} +import com.wavesplatform.features.BlockchainFeatures.{ConsensusImprovements, SynchronousCalls} import com.wavesplatform.lang.Global import com.wavesplatform.lang.directives.values.{Account, DApp, StdLibVersion, V3} import com.wavesplatform.lang.directives.{DirectiveDictionary, DirectiveSet} @@ -13,17 +13,16 @@ import com.wavesplatform.lang.v1.traits.Environment import com.wavesplatform.state.Blockchain object CachedDAppCTX { - private val cache: Map[(StdLibVersion, Boolean, Boolean, Boolean), InvariableContext] = + private val cache: Map[(StdLibVersion, Boolean, Boolean), InvariableContext] = (for { version <- DirectiveDictionary[StdLibVersion].all.filter(_ >= V3) useNewPowPrecision <- Seq(true, false) fixBigScriptField <- Seq(true, false) - typedError <- Seq(true, false) } yield { val ctx = PureContext.build(version, useNewPowPrecision).withEnvironment[Environment] |+| - CryptoContext.build(Global, version, typedError).withEnvironment[Environment] |+| - WavesContext.build(Global, DirectiveSet(version, Account, DApp).explicitGet(), fixBigScriptField, typedError) - ((version, useNewPowPrecision, fixBigScriptField, typedError), InvariableContext(ctx)) + CryptoContext.build(Global, version).withEnvironment[Environment] |+| + WavesContext.build(Global, DirectiveSet(version, Account, DApp).explicitGet(), fixBigScriptField) + ((version, useNewPowPrecision, fixBigScriptField), InvariableContext(ctx)) }).toMap def get(version: StdLibVersion, b: Blockchain): InvariableContext = @@ -31,8 +30,7 @@ object CachedDAppCTX { ( version, b.isFeatureActivated(SynchronousCalls) && b.height > b.settings.functionalitySettings.enforceTransferValidationAfter, - b.isFeatureActivated(ConsensusImprovements), - b.isFeatureActivated(LightNode) + b.isFeatureActivated(ConsensusImprovements) ) ) } diff --git a/node/src/main/scala/com/wavesplatform/state/diffs/invoke/InvokeScriptDiff.scala b/node/src/main/scala/com/wavesplatform/state/diffs/invoke/InvokeScriptDiff.scala index e5edbd8b43..7bfa1c601c 100644 --- a/node/src/main/scala/com/wavesplatform/state/diffs/invoke/InvokeScriptDiff.scala +++ b/node/src/main/scala/com/wavesplatform/state/diffs/invoke/InvokeScriptDiff.scala @@ -8,6 +8,7 @@ import cats.syntax.traverseFilter.* import com.wavesplatform.account.* import com.wavesplatform.common.state.ByteStr import com.wavesplatform.features.BlockchainFeatures +import com.wavesplatform.features.BlockchainFeatures.LightNode import com.wavesplatform.features.EstimatorProvider.EstimatorBlockchainExt import com.wavesplatform.features.EvaluatorFixProvider.* import com.wavesplatform.features.FunctionCallPolicyProvider.* @@ -389,7 +390,8 @@ object InvokeScriptDiff { limit, blockchain.correctFunctionCallScope, blockchain.newEvaluatorMode, - enableExecutionLog + enableExecutionLog, + blockchain.isFeatureActivated(LightNode) ) .map( _.leftMap[ValidationError] { diff --git a/node/src/main/scala/com/wavesplatform/state/diffs/invoke/InvokeScriptTransactionDiff.scala b/node/src/main/scala/com/wavesplatform/state/diffs/invoke/InvokeScriptTransactionDiff.scala index 5673c35cdb..78c08900af 100644 --- a/node/src/main/scala/com/wavesplatform/state/diffs/invoke/InvokeScriptTransactionDiff.scala +++ b/node/src/main/scala/com/wavesplatform/state/diffs/invoke/InvokeScriptTransactionDiff.scala @@ -8,7 +8,7 @@ import com.wavesplatform.account.* import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils.EitherExt2 import com.wavesplatform.features.BlockchainFeatures -import com.wavesplatform.features.BlockchainFeatures.RideV6 +import com.wavesplatform.features.BlockchainFeatures.{LightNode, RideV6} import com.wavesplatform.features.EstimatorProvider.* import com.wavesplatform.features.EvaluatorFixProvider.* import com.wavesplatform.features.FunctionCallPolicyProvider.* @@ -334,7 +334,8 @@ object InvokeScriptTransactionDiff { startLimit, blockchain.correctFunctionCallScope, blockchain.newEvaluatorMode, - enableExecutionLog + enableExecutionLog, + blockchain.isFeatureActivated(LightNode) ) .runAttempt() .leftMap(error => (error.getMessage: ExecutionError, 0, Nil: Log[Id])) diff --git a/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala b/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala index 2389569387..edb981637a 100644 --- a/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala +++ b/node/src/main/scala/com/wavesplatform/transaction/smart/BlockchainContext.scala @@ -34,8 +34,7 @@ object BlockchainContext { txId: ByteStr, fixUnicodeFunctions: Boolean, useNewPowPrecision: Boolean, - fixBigScriptField: Boolean, - typedError: Boolean + fixBigScriptField: Boolean ): Either[String, EvaluationContext[Environment, Id]] = DirectiveSet( version, @@ -43,7 +42,7 @@ object BlockchainContext { ContentType.isDApp(isContract) ).map { ds => val environment = new WavesEnvironment(nByte, in, h, blockchain, address, ds, txId) - build(ds, environment, fixUnicodeFunctions, useNewPowPrecision, fixBigScriptField, typedError) + build(ds, environment, fixUnicodeFunctions, useNewPowPrecision, fixBigScriptField) } def build( @@ -51,8 +50,7 @@ object BlockchainContext { environment: Environment[Id], fixUnicodeFunctions: Boolean, useNewPowPrecision: Boolean, - fixBigScriptField: Boolean, - typedError: Boolean + fixBigScriptField: Boolean ): EvaluationContext[Environment, Id] = cache .synchronized( @@ -60,8 +58,8 @@ object BlockchainContext { (ds.stdLibVersion, fixUnicodeFunctions, useNewPowPrecision, fixBigScriptField, ds), { _ => PureContext.build(ds.stdLibVersion, useNewPowPrecision).withEnvironment[Environment] |+| - CryptoContext.build(Global, ds.stdLibVersion, typedError).withEnvironment[Environment] |+| - WavesContext.build(Global, ds, fixBigScriptField, typedError) + CryptoContext.build(Global, ds.stdLibVersion).withEnvironment[Environment] |+| + WavesContext.build(Global, ds, fixBigScriptField) } ) ) diff --git a/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala b/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala index a8f8ef53e0..04962fc6f1 100644 --- a/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala +++ b/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala @@ -54,8 +54,7 @@ object ScriptRunner { blockchain.newEvaluatorMode, blockchain.isFeatureActivated(RideV6), enableExecutionLog, - blockchain.isFeatureActivated(ConsensusImprovements), - blockchain.isFeatureActivated(LightNode) + blockchain.isFeatureActivated(ConsensusImprovements) ) def applyGeneric( @@ -73,8 +72,7 @@ object ScriptRunner { newEvaluatorMode: Boolean, checkWeakPk: Boolean, enableExecutionLog: Boolean, - fixBigScriptField: Boolean, - typedError: Boolean + fixBigScriptField: Boolean ): (Log[Id], Int, Either[ExecutionError, EVALUATED]) = { def evalVerifier( @@ -99,8 +97,7 @@ object ScriptRunner { txId, fixUnicodeFunctions, useNewPowPrecision, - fixBigScriptField, - typedError + fixBigScriptField ) } yield (ds, ctx) @@ -138,7 +135,8 @@ object ScriptRunner { correctFunctionCallScope = checkEstimatorSumOverflow, newMode = newEvaluatorMode, onExceed, - enableExecutionLog + enableExecutionLog, + fixedThrownError = blockchain.isFeatureActivated(LightNode) ) (log, limit - unusedComplexity, result) diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala index 9f6d1ac7d2..87a67f9824 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/ContextFunctionsTest.scala @@ -836,8 +836,8 @@ class ContextFunctionsTest extends PropSpec with WithDomain with EthHelpers { val ctx = PureContext.build(version, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, version, typedError = true).withEnvironment[Environment] |+| - WavesContext.build(Global, DirectiveSet(version, Account, DApp).explicitGet(), fixBigScriptField = true, typedError = true) + CryptoContext.build(Global, version).withEnvironment[Environment] |+| + WavesContext.build(Global, DirectiveSet(version, Account, DApp).explicitGet(), fixBigScriptField = true) val compiledScript = ContractScript(version, ContractCompiler(ctx.compilerContext, expr, version).explicitGet()).explicitGet() val setScriptTx = TxHelpers.setScript(recipient, compiledScript) diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala index 5342861cd6..96a8a45c23 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala @@ -102,8 +102,7 @@ class MatcherBlockchainTest extends PropSpec with MockFactory with WithDomain { newEvaluatorMode = true, checkWeakPk = true, enableExecutionLog = false, - fixBigScriptField = true, - typedError = true + fixBigScriptField = true ) ._3 shouldBe Right(CONST_BOOLEAN(true)) } diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala index 38df65ac7a..79618f62b3 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/TransactionBindingsTest.scala @@ -868,8 +868,8 @@ class TransactionBindingsTest extends PropSpec with PathMockFactory with EitherV val directives = DirectiveSet(V2, AssetType, Expression).explicitGet() val ctx = PureContext.build(V2, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, V2, typedError = true).withEnvironment[Environment] |+| - WavesContext.build(Global, DirectiveSet(V2, AssetType, Expression).explicitGet(), fixBigScriptField = true, typedError = true) + CryptoContext.build(Global, V2).withEnvironment[Environment] |+| + WavesContext.build(Global, DirectiveSet(V2, AssetType, Expression).explicitGet(), fixBigScriptField = true) val environment = new WavesEnvironment( chainId, @@ -899,8 +899,8 @@ class TransactionBindingsTest extends PropSpec with PathMockFactory with EitherV val ctx = PureContext.build(V2, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, V2, typedError = true).withEnvironment[Environment] |+| - WavesContext.build(Global, directives, fixBigScriptField = true, typedError = true) + CryptoContext.build(Global, V2).withEnvironment[Environment] |+| + WavesContext.build(Global, directives, fixBigScriptField = true) val env = new WavesEnvironment( chainId, diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/package.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/package.scala index b30b93ea1d..43b9d510d8 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/package.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/package.scala @@ -42,8 +42,7 @@ package object predef { ByteStr.empty, fixUnicodeFunctions = true, useNewPowPrecision = true, - fixBigScriptField = true, - typedError = true + fixBigScriptField = true ) r <- EvaluatorV1().apply[T](evalContext, typedExpr).leftMap(_.message) } yield r diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala index c881c8f752..ed46169e84 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/BalancesV4Test.scala @@ -120,8 +120,8 @@ class BalancesV4Test extends PropSpec with WithState { val ctx = { val directives = DirectiveSet(V4, AssetType, Expression).explicitGet() PureContext.build(V4, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, V4, typedError = true).withEnvironment[Environment] |+| - WavesContext.build(Global, directives, fixBigScriptField = true, typedError = true) + CryptoContext.build(Global, V4).withEnvironment[Environment] |+| + WavesContext.build(Global, directives, fixBigScriptField = true) } val script = @@ -182,8 +182,8 @@ class BalancesV4Test extends PropSpec with WithState { val ctx = { val directives = DirectiveSet(V4, AssetType, Expression).explicitGet() PureContext.build(V4, useNewPowPrecision = true).withEnvironment[Environment] |+| - CryptoContext.build(Global, V4, typedError = true).withEnvironment[Environment] |+| - WavesContext.build(Global, directives, fixBigScriptField = true, typedError = true) + CryptoContext.build(Global, V4).withEnvironment[Environment] |+| + WavesContext.build(Global, directives, fixBigScriptField = true) } val script = diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/NotaryControlledTransferScenarioTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/NotaryControlledTransferScenarioTest.scala index fe5f3795c5..89152e2fab 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/NotaryControlledTransferScenarioTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/scenarios/NotaryControlledTransferScenarioTest.scala @@ -83,7 +83,7 @@ class NotaryControlledTransferScenarioTest extends PropSpec with WithState { private val dummyEvalContext: EvaluationContext[Environment, Id] = { val ds = DirectiveSet(V1, Asset, Expression).explicitGet() val environment = new WavesEnvironment(chainId, Coeval(???), null, EmptyBlockchain, null, ds, ByteStr.empty) - lazyContexts((ds, true, true, true))().evaluationContext(environment) + lazyContexts((ds, true, true))().evaluationContext(environment) } private def eval(code: String) = { diff --git a/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala b/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala index 237fc14781..b65704bf30 100644 --- a/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala +++ b/node/src/test/scala/com/wavesplatform/transaction/IssueTransactionV2Specification.scala @@ -137,12 +137,11 @@ class IssueTransactionV2Specification extends PropSpec with WithNewDBForEachTest .combineAll( Seq( PureContext.build(V3, useNewPowPrecision = true).withEnvironment[Environment], - CryptoContext.build(Global, V3, typedError = true).withEnvironment[Environment], + CryptoContext.build(Global, V3).withEnvironment[Environment], WavesContext.build( Global, DirectiveSet(V3, Account, Expression).explicitGet(), - fixBigScriptField = true, - typedError = true + fixBigScriptField = true ) ) ) diff --git a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala index c70b14a7bc..8c2e91273e 100644 --- a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala +++ b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/FunctionComplexityTest.scala @@ -41,12 +41,11 @@ class FunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { .combineAll( Seq( PureContext.build(version, useNewPowPrecision = true).withEnvironment[Environment], - CryptoContext.build(Global, version, typedError = true).withEnvironment[Environment], + CryptoContext.build(Global, version).withEnvironment[Environment], WavesContext.build( Global, DirectiveSet(version, Account, Expression).explicitGet(), - fixBigScriptField = true, - typedError = true + fixBigScriptField = true ) ) ) diff --git a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala index 3d73df6880..6e5d2cc7ca 100644 --- a/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala +++ b/node/src/test/scala/com/wavesplatform/transaction/smart/script/estimator/UserFunctionComplexityTest.scala @@ -32,12 +32,11 @@ class UserFunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { .combineAll( Seq( PureContext.build(V1, useNewPowPrecision = true).withEnvironment[Environment], - CryptoContext.build(Global, V1, typedError = true).withEnvironment[Environment], + CryptoContext.build(Global, V1).withEnvironment[Environment], WavesContext.build( Global, DirectiveSet(V1, Account, Expression).explicitGet(), - fixBigScriptField = true, - typedError = true + fixBigScriptField = true ) ) ) @@ -100,12 +99,11 @@ class UserFunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { .combineAll( Seq( PureContext.build(V2, useNewPowPrecision = true).withEnvironment[Environment], - CryptoContext.build(Global, V2, typedError = true).withEnvironment[Environment], + CryptoContext.build(Global, V2).withEnvironment[Environment], WavesContext.build( Global, DirectiveSet(V2, Account, Expression).explicitGet(), - fixBigScriptField = true, - typedError = true + fixBigScriptField = true ) ) ) @@ -168,12 +166,11 @@ class UserFunctionComplexityTest(estimator: ScriptEstimator) extends PropSpec { .combineAll( Seq( PureContext.build(V3, useNewPowPrecision = true).withEnvironment[Environment], - CryptoContext.build(Global, V3, typedError = true).withEnvironment[Environment], + CryptoContext.build(Global, V3).withEnvironment[Environment], WavesContext.build( Global, DirectiveSet(V3, Account, Expression).explicitGet(), - fixBigScriptField = true, - typedError = true + fixBigScriptField = true ) ) ) From e8f807e7b7b4eb2a97efbae043141be3b0331138 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Tue, 17 Oct 2023 17:15:44 +0300 Subject: [PATCH 11/11] Adapted for ScriptRunner.applyGeneric() --- .../transaction/smart/script/ScriptRunner.scala | 8 +++++--- .../state/diffs/smart/predef/MatcherBlockchainTest.scala | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala b/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala index 04962fc6f1..3d19d95f3d 100644 --- a/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala +++ b/node/src/main/scala/com/wavesplatform/transaction/smart/script/ScriptRunner.scala @@ -54,7 +54,8 @@ object ScriptRunner { blockchain.newEvaluatorMode, blockchain.isFeatureActivated(RideV6), enableExecutionLog, - blockchain.isFeatureActivated(ConsensusImprovements) + blockchain.isFeatureActivated(ConsensusImprovements), + blockchain.isFeatureActivated(LightNode) ) def applyGeneric( @@ -72,7 +73,8 @@ object ScriptRunner { newEvaluatorMode: Boolean, checkWeakPk: Boolean, enableExecutionLog: Boolean, - fixBigScriptField: Boolean + fixBigScriptField: Boolean, + fixedThrownError: Boolean ): (Log[Id], Int, Either[ExecutionError, EVALUATED]) = { def evalVerifier( @@ -136,7 +138,7 @@ object ScriptRunner { newMode = newEvaluatorMode, onExceed, enableExecutionLog, - fixedThrownError = blockchain.isFeatureActivated(LightNode) + fixedThrownError ) (log, limit - unusedComplexity, result) diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala index 96a8a45c23..77e52a6ebe 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/MatcherBlockchainTest.scala @@ -102,7 +102,8 @@ class MatcherBlockchainTest extends PropSpec with MockFactory with WithDomain { newEvaluatorMode = true, checkWeakPk = true, enableExecutionLog = false, - fixBigScriptField = true + fixBigScriptField = true, + fixedThrownError = true ) ._3 shouldBe Right(CONST_BOOLEAN(true)) }