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 32372cc06db..839504d7c00 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 @@ -2,7 +2,7 @@ package com.wavesplatform.lang.evaluator import cats.syntax.either.* import com.wavesplatform.common.utils.EitherExt2 -import com.wavesplatform.lang.Common +import com.wavesplatform.lang.{Common, CommonError} import com.wavesplatform.lang.directives.DirectiveSet import com.wavesplatform.lang.directives.values.* import com.wavesplatform.lang.utils.lazyContexts @@ -1251,4 +1251,59 @@ class EvaluatorV2Test extends PropSpec with Inside { evalOld(script2, 100) shouldBe ((TRUE, "true", 5)) // 3 conditions + ref twice evalNew(script2, 100) shouldBe ((TRUE, "true", 3)) // 3 function call } + + property("throw with message complexity") { + val script = + """ + |func a() = throw("xxx") # 1 + | + |func f() = + | if (1 == 1) # 1 + | then a() + | else false + | + |f() + """.stripMargin + + var r = EvaluatorV2 + .applyLimitedCoeval( + compile(script), + LogExtraInfo(), + 10, + ctx.evaluationContext(environment), + V6, + correctFunctionCallScope = true, + newMode = true + ) + .value() + r shouldBe Left(_: CommonError, 8, _: List[Any]) + } + + property("throw without message complexity") { + val script = + """ + |func a() = throw() # 1 + | + |func f() = + | if (1 == 1) # 1 + | then a() + | else false + | + |f() + """.stripMargin + + var r = EvaluatorV2 + .applyLimitedCoeval( + compile(script), + LogExtraInfo(), + 10, + ctx.evaluationContext(environment), + V6, + correctFunctionCallScope = true, + newMode = true + ) + .value() + r shouldBe Left(_: CommonError, 8, _: List[Any]) + } } + diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/ci/sync/SyncInvokeDiffTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/ci/sync/SyncInvokeDiffTest.scala index 0c355a040c3..7bba251439e 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/ci/sync/SyncInvokeDiffTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/ci/sync/SyncInvokeDiffTest.scala @@ -7,7 +7,7 @@ import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils.EitherExt2 import com.wavesplatform.db.{DBCacheSettings, WithDomain} import com.wavesplatform.lagonaki.mocks.TestBlock -import com.wavesplatform.lang.directives.values.V5 +import com.wavesplatform.lang.directives.values.{V5, V6} import com.wavesplatform.lang.script.Script import com.wavesplatform.lang.v1.compiler.TestCompiler import com.wavesplatform.lang.v1.estimator.v3.ScriptEstimatorV3 @@ -25,6 +25,7 @@ class SyncInvokeDiffTest extends PropSpec with WithDomain with DBCacheSettings w import DomainPresets._ private val fsWithV5 = RideV5.blockchainSettings.functionalitySettings + private val fsWithV6 = RideV6.blockchainSettings.functionalitySettings private val invoker = TxHelpers.signer(0) private val dApp = TxHelpers.signer(1) @@ -1313,4 +1314,128 @@ class SyncInvokeDiffTest extends PropSpec with WithDomain with DBCacheSettings w bc.balance(thirdAcc.toAddress, IssuedAsset(paymentIssue.id())) shouldBe paymentAssetAmount } } + + property("Throw with message inside invoke") { + val script = + TestCompiler(V6).compileContract( + s""" + | @Callable(i) + | func bar() = throw("fail") # 1 (throw) + """.stripMargin + ) + + val script1 = + TestCompiler(V6).compileContract( + s""" + | @Callable(i) + | func foo() = { + | strict a = 1${" + 1" * 1000} # 1001 = 1000 (+) + 1 (strict) + | strict r = invoke(Alias("alias"), "bar", [], []) # 77 = 75 (invoke) + 1 (Alias) + 1 (strict) + | [] + | } + """.stripMargin + ) + + val gTx1 = TxHelpers.genesis(dAppAddress) + val gTx2 = TxHelpers.genesis(invokerAddress) + val gTx3 = TxHelpers.genesis(thirdAcc.toAddress) + + val aliasTx1 = TxHelpers.createAlias("alias", thirdAcc) + val ssTx = TxHelpers.setScript(dApp, script1) + val ssTx1 = TxHelpers.setScript(thirdAcc, script) + val invoke = TxHelpers.invoke(dAppAddress, Some("foo"), Nil, Nil, fee = TestValues.invokeFee(issues = 0)) + val genesisTxs = Seq(gTx1, gTx2, gTx3, aliasTx1, ssTx1, ssTx) + + assertDiffAndState(Seq(TestBlock.create(genesisTxs)), TestBlock.create(Seq(invoke), Block.ProtoBlockVersion), fsWithV6) { + case (diff, _) => + diff.scriptsComplexity shouldBe 1079 + } + } + + property("Throw with message inside callable") { + val script = + TestCompiler(V6).compileContract( + s""" + | @Callable(i) + | func foo() = { + | let a = 1${" + 1" * 1000} # 1000 (+) + | if (a == 1) then [] else throw("xxx") # 2 = 1 (==) + 1 (throw) + | } + """.stripMargin + ) + + val gTx1 = TxHelpers.genesis(dAppAddress) + val gTx2 = TxHelpers.genesis(invokerAddress) + + val ssTx = TxHelpers.setScript(dApp, script) + val invoke = TxHelpers.invoke(dAppAddress, Some("foo"), Nil, Nil, fee = TestValues.invokeFee(issues = 0)) + val genesisTxs = Seq(gTx1, gTx2, ssTx) + + assertDiffAndState(Seq(TestBlock.create(genesisTxs)), TestBlock.create(Seq(invoke), Block.ProtoBlockVersion), fsWithV6) { + case (diff, _) => + diff.scriptsComplexity shouldBe 1002 + } + } + + property("Throw without message inside invoke") { + val script = + TestCompiler(V6).compileContract( + s""" + | @Callable(i) + | func bar() = throw() # 1 (throw) + """.stripMargin + ) + + val script1 = + TestCompiler(V6).compileContract( + s""" + | @Callable(i) + | func foo() = { + | strict a = 1${" + 1" * 1000} # 1001 = 1000 (+) + 1 (strict) + | strict r = invoke(Alias("alias"), "bar", [], []) # 77 = 75 (invoke) + 1 (Alias) + 1 (strict) + | [] + | } + """.stripMargin + ) + + val gTx1 = TxHelpers.genesis(dAppAddress) + val gTx2 = TxHelpers.genesis(invokerAddress) + val gTx3 = TxHelpers.genesis(thirdAcc.toAddress) + + val aliasTx1 = TxHelpers.createAlias("alias", thirdAcc) + val ssTx = TxHelpers.setScript(dApp, script1) + val ssTx1 = TxHelpers.setScript(thirdAcc, script) + val invoke = TxHelpers.invoke(dAppAddress, Some("foo"), Nil, Nil, fee = TestValues.invokeFee(issues = 0)) + val genesisTxs = Seq(gTx1, gTx2, gTx3, aliasTx1, ssTx1, ssTx) + + assertDiffAndState(Seq(TestBlock.create(genesisTxs)), TestBlock.create(Seq(invoke), Block.ProtoBlockVersion), fsWithV6) { + case (diff, _) => + diff.scriptsComplexity shouldBe 1079 + } + } + + property("Throw without message inside callable") { + val script = + TestCompiler(V6).compileContract( + s""" + | @Callable(i) + | func foo() = { + | let a = 1${" + 1" * 1000} # 1000 (+) + | if (a == 1) then [] else throw() # 2 = 1 (==) + 1 (throw) + | } + """.stripMargin + ) + + val gTx1 = TxHelpers.genesis(dAppAddress) + val gTx2 = TxHelpers.genesis(invokerAddress) + + val ssTx = TxHelpers.setScript(dApp, script) + val invoke = TxHelpers.invoke(dAppAddress, Some("foo"), Nil, Nil, fee = TestValues.invokeFee(issues = 0)) + val genesisTxs = Seq(gTx1, gTx2, ssTx) + + assertDiffAndState(Seq(TestBlock.create(genesisTxs)), TestBlock.create(Seq(invoke), Block.ProtoBlockVersion), fsWithV6) { + case (diff, _) => + diff.scriptsComplexity shouldBe 1002 + } + } }