Skip to content

Commit d7c0785

Browse files
authored
NODE-2640 Fixed estimation with lazy refsCosts in EstimatorContext (#3929)
1 parent 2bf1e98 commit d7c0785

File tree

7 files changed

+50
-21
lines changed

7 files changed

+50
-21
lines changed

lang/shared/src/main/scala/com/wavesplatform/lang/v1/estimator/v3/EstimatorContext.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import shapeless.{Lens, lens}
1010
private[v3] case class EstimatorContext(
1111
funcs: Map[FunctionHeader, (Coeval[Long], Set[String])],
1212
usedRefs: Set[String] = Set(),
13-
refsCosts: Map[String, Long] = Map(),
13+
refsCosts: Map[String, EvalM[Long]] = Map(),
1414
globalFunctionsCosts: Map[String, Long] = Map(), //
1515
globalLetsCosts: Map[String, Long] = Map(), // only for globalDeclarationsMode
1616
globalLetEvals: Map[String, EvalM[Long]] = Map() //

lang/shared/src/main/scala/com/wavesplatform/lang/v1/estimator/v3/ScriptEstimatorV3.scala

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.wavesplatform.lang.v1.estimator.v3
22

33
import cats.implicits.{toBifunctorOps, toFoldableOps, toTraverseOps}
4-
import cats.{Id, Monad}
54
import cats.syntax.functor.*
5+
import cats.{Id, Monad}
66
import com.wavesplatform.lang.v1.FunctionHeader
77
import com.wavesplatform.lang.v1.FunctionHeader.User
88
import com.wavesplatform.lang.v1.compiler.Terms.*
@@ -100,14 +100,11 @@ case class ScriptEstimatorV3(fixOverflow: Boolean, overhead: Boolean, letFixes:
100100
}
101101

102102
private def beforeNextExprEval(let: LET, eval: EvalM[Long]): EvalM[Unit] =
103-
for {
104-
cost <- local(eval)
105-
_ <- update(ctx =>
106-
usedRefs
107-
.modify(ctx)(_ - let.name)
108-
.copy(refsCosts = ctx.refsCosts + (let.name -> cost))
109-
)
110-
} yield ()
103+
update(ctx =>
104+
usedRefs
105+
.modify(ctx)(_ - let.name)
106+
.copy(refsCosts = ctx.refsCosts + (let.name -> local(eval)))
107+
)
111108

112109
private def afterNextExprEval(let: LET, startCtx: EstimatorContext): EvalM[Unit] =
113110
update(ctx =>
@@ -181,10 +178,11 @@ case class ScriptEstimatorV3(fixOverflow: Boolean, overhead: Boolean, letFixes:
181178
(argsCosts, _) <- withUsedRefs(args.traverse(evalHoldingFuncs(_, activeFuncArgs)))
182179
argsCostsSum <- argsCosts.foldM(0L)(sum)
183180
bodyCostV = bodyCost.value()
184-
correctedBodyCost =
185-
if (!overhead && !letFixes && bodyCostV == 0) 1
186-
else if (letFixes && bodyCostV == 0 && isBlankFunc(bodyUsedRefs, ctx.refsCosts)) 1
187-
else bodyCostV
181+
correctedBodyCost <-
182+
if (bodyCostV != 0) const(bodyCostV)
183+
else if (overhead) zero
184+
else if (!overhead && !letFixes) const(1L)
185+
else isBlankFunc(bodyUsedRefs, ctx.refsCosts).map(if (_) 1L else 0L)
188186
result <- sum(argsCostsSum, correctedBodyCost)
189187
} yield result
190188

@@ -207,8 +205,10 @@ case class ScriptEstimatorV3(fixOverflow: Boolean, overhead: Boolean, letFixes:
207205
raiseError[Id, EstimatorContext, EstimationError, (Coeval[Long], Set[EstimationError])](s"function '$header' not found")
208206
)
209207

210-
private def isBlankFunc(usedRefs: Set[String], refsCosts: Map[String, Long]): Boolean =
211-
!usedRefs.exists(refsCosts.get(_).exists(_ > 0))
208+
private def isBlankFunc(usedRefs: Set[String], refsCosts: Map[String, EvalM[Long]]): EvalM[Boolean] =
209+
usedRefs.toSeq
210+
.existsM(refsCosts.get(_).existsM(_.map(_ > 0)))
211+
.map(!_)
212212

213213
private def evalHoldingFuncs(
214214
expr: EXPR,

lang/tests/src/test/scala/com/wavesplatform/lang/estimator/EstimatorGlobalVarTest.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package com.wavesplatform.lang.estimator
2-
import com.wavesplatform.lang.directives.values.{Expression, V6}
2+
import com.wavesplatform.lang.directives.values.{Expression, V4, V6}
33
import com.wavesplatform.lang.utils
44
import com.wavesplatform.lang.utils.functionCosts
55
import com.wavesplatform.lang.v1.FunctionHeader.{Native, User}
@@ -130,4 +130,15 @@ class EstimatorGlobalVarTest extends ScriptEstimatorTestBase(ScriptEstimatorV3(f
130130
estimate(script) shouldBe Right(3)
131131
estimateFixed(script) shouldBe Right(3)
132132
}
133+
134+
property("blank function call with/without overhead before let fixes") {
135+
Seq(false, true).foreach(overhead =>
136+
ScriptEstimatorV3(fixOverflow = true, overhead, letFixes = false)(
137+
lets,
138+
functionCosts(V4),
139+
compile("func f() = true\nf()")
140+
) shouldBe Right(1)
141+
// with overhead 1 for "true", without — for blank function call
142+
)
143+
}
133144
}

node-it/src/test/scala/com/wavesplatform/it/repl/ReplTest.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,10 @@ class ReplTest extends BaseTransactionSuite with FailedTransactionSuiteLike[Stri
178178
| \\)
179179
| timestamp = \\d+
180180
| vrf = base58'[$Base58Alphabet]+'
181-
| height = $height
182181
| generationSignature = base58'[$Base58Alphabet]+'
183182
| generatorPublicKey = base58'[$Base58Alphabet]+${"" /*miner.publicKey*/}'
183+
| height = $height
184+
| rewards = \\[\\]
184185
|\\)
185186
""".trim.stripMargin
186187

node-it/src/test/scala/com/wavesplatform/it/sync/smartcontract/RideReplBlockchainFunctionsSuite.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,10 @@ class RideReplBlockchainFunctionsSuite extends BaseTransactionSuite {
182182
| )
183183
| timestamp = ${bi.timestamp}
184184
| vrf = base58'${bi.vrf.get}'
185-
| height = ${bi.height}
186185
| generationSignature = base58'${bi.generationSignature.get}'
187186
| generatorPublicKey = base58'${bi.generatorPublicKey}'
187+
| height = ${bi.height}
188+
| rewards = []
188189
|)
189190
""".trim.stripMargin
190191
)

node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/DAppVerifierRestrictionsTest.scala

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.wavesplatform.lang.v1.estimator.v3.ScriptEstimatorV3
1414
import com.wavesplatform.protobuf.dapp.DAppMeta
1515
import com.wavesplatform.test.*
1616
import com.wavesplatform.transaction.TxHelpers
17+
import com.wavesplatform.transaction.TxHelpers.{defaultSigner, setScript}
1718
import org.scalatest.EitherValues
1819

1920
class DAppVerifierRestrictionsTest extends PropSpec with WithDomain with EitherValues {
@@ -196,7 +197,7 @@ class DAppVerifierRestrictionsTest extends PropSpec with WithDomain with EitherV
196197
def estimateScript(script: Script): Option[Long] = {
197198
val estimator = ScriptEstimatorV3.latest
198199

199-
Script.estimate(script, estimator, fixEstimateOfVerifier = false, useContractVerifierLimit = false).toOption
200+
Script.estimate(script, estimator, fixEstimateOfVerifier = false, useContractVerifierLimit = false).toOption
200201
}
201202

202203
val script1 = createScript(
@@ -226,4 +227,19 @@ class DAppVerifierRestrictionsTest extends PropSpec with WithDomain with EitherV
226227
estimateScript(script4) shouldBe defined
227228
estimateScript(script5) shouldBe defined
228229
}
230+
231+
property("An old buggy check that was in effect before RideV6 should not cause an error if a variable is not used in a @Callable") {
232+
val script = TestCompiler(V5).compileContract(
233+
"""
234+
| func call() = {
235+
| let asset = invoke(addressFromStringValue(""), "", nil, nil)
236+
| nil
237+
| }
238+
|
239+
| @Verifier(tx)
240+
| func verify() = sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
241+
""".stripMargin
242+
)
243+
withDomain(RideV5, AddrWithBalance.enoughBalances(defaultSigner))(_.appendAndAssertSucceed(setScript(defaultSigner, script)))
244+
}
229245
}

repl/shared/src/main/scala/com/wavesplatform/lang/v1/repl/package.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ package object repl {
1717
val internalVarPrefixes: Set[Char] = Set('@', '$')
1818
val internalFuncPrefix: String = "_"
1919

20-
val version = V6
20+
val version = StdLibVersion.VersionDic.latest
2121
val directives: DirectiveSet = DirectiveSet(version, Account, DApp).explicitGet()
2222

2323
val initialCtx: CTX[Environment] =

0 commit comments

Comments
 (0)