diff --git a/sigmastate/src/test/scala/sigmastate/CostingSpecification.scala b/sigmastate/src/test/scala/sigmastate/CostingSpecification.scala index e03f20900f..8b0e4552b7 100644 --- a/sigmastate/src/test/scala/sigmastate/CostingSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/CostingSpecification.scala @@ -2,7 +2,7 @@ package sigmastate import org.ergoplatform.SigmaConstants.ScriptCostLimit import org.ergoplatform.validation.ValidationRules -import org.ergoplatform.{ErgoLikeContext, ErgoBox} +import org.ergoplatform.{ErgoBox, ErgoLikeContext} import scorex.crypto.authds.avltree.batch.Lookup import scorex.crypto.authds.{ADDigest, ADKey} import scorex.crypto.hash.Blake2b256 @@ -13,11 +13,12 @@ import sigmastate.eval._ import sigmastate.helpers.TestingHelpers._ import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter} import sigmastate.interpreter.ContextExtension -import sigmastate.interpreter.Interpreter.{ScriptNameProp, ScriptEnv, emptyEnv} +import sigmastate.interpreter.Interpreter.{ScriptEnv, ScriptNameProp, emptyEnv} import sigmastate.utxo.CostTable import sigmastate.utxo.CostTable._ -import special.sigma.{SigmaTestingData, AvlTree} +import special.sigma.{AvlTree, SigmaTestingData} import sigmastate.lang.Terms.ValueOps +import sigmastate.lang.exceptions.CostLimitException class CostingSpecification extends SigmaTestingData with CrossVersionProps { implicit lazy val IR = new TestingIRContext { @@ -408,8 +409,7 @@ class CostingSpecification extends SigmaTestingData with CrossVersionProps { property("ErgoTree with SigmaPropConstant costs") { val d = new TestData; import d._ - def testTree(tree: ErgoTree, initCost: Long, expectedCost: Long) = { - val ctx = context.withInitCost(initCost) + def proveAndVerify(ctx: ErgoLikeContext, tree: ErgoTree, expectedCost: Long) = { val pr = interpreter.prove(tree, ctx, fakeMessage).get pr.cost shouldBe expectedCost @@ -422,19 +422,34 @@ class CostingSpecification extends SigmaTestingData with CrossVersionProps { val tree1 = ErgoTree.fromSigmaBoolean(pkA) // without segregation val tree2 = ErgoTree.withSegregation(pkA) // with segregation, have different `complexity` - testTree(tree1, 0, 10141) - testTree(tree2, 0, 10161) + { + val ctx = context.withInitCost(0) + proveAndVerify(ctx, tree1, expectedCost = 10141) + proveAndVerify(ctx, tree2, expectedCost = 10161) + } + + { + val ctx = context.withInitCost(10000) + proveAndVerify(ctx, tree1, expectedCost = 20141) + proveAndVerify(ctx, tree2, expectedCost = 20161) + } - testTree(tree1, context.initCost, 20141) - testTree(tree2, context.initCost, 20161) + { + val ctx = context.withInitCost(10000).withCostLimit(20000) + assertExceptionThrown( + proveAndVerify(ctx, tree1, expectedCost = 20141), + exceptionLike[CostLimitException]( + "Estimated execution cost", "exceeds the limit") + ) + } // more complex tree without Deserialize val tree3 = ErgoTree.fromProposition(compiler .compile(env, "{ sigmaProp(HEIGHT == 2) }") .asSigmaProp) - testTree(tree3, 0, 541) - testTree(tree3, context.initCost, 10541) + proveAndVerify(context.withInitCost(0), tree3, expectedCost = 541) + proveAndVerify(context.withInitCost(10000), tree3, expectedCost = 10541) } property("laziness of AND, OR costs") { diff --git a/sigmastate/src/test/scala/sigmastate/helpers/NegativeTesting.scala b/sigmastate/src/test/scala/sigmastate/helpers/NegativeTesting.scala index 3fc245b684..a4bda66032 100644 --- a/sigmastate/src/test/scala/sigmastate/helpers/NegativeTesting.scala +++ b/sigmastate/src/test/scala/sigmastate/helpers/NegativeTesting.scala @@ -3,6 +3,7 @@ package sigmastate.helpers import org.scalatest.Matchers import scala.annotation.tailrec +import scala.reflect.ClassTag trait NegativeTesting extends Matchers { @@ -33,4 +34,16 @@ trait NegativeTesting extends Matchers { if (t.getCause == null) t else rootCause(t.getCause) + /** Creates an assertion which checks the given type and message contents. + * + * @tparam E expected type of exception + * @param msgParts expected parts of the exception message + * @return the assertion which can be used in assertExceptionThrown method + */ + def exceptionLike[E <: Throwable : ClassTag] + (msgParts: String*): Throwable => Boolean = { + case t: E => msgParts.forall(t.getMessage.contains(_)) + case _ => false + } + }