Skip to content

Commit

Permalink
SC-655 Remove illegal reference to extract() in V4 (#3197)
Browse files Browse the repository at this point in the history
  • Loading branch information
xrtm000 authored Jul 16, 2020
1 parent dfdeb1d commit 399539f
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,15 @@ class EvaluatorV2(
update(argsWithExpr).flatMap(_ => root(argsWithExpr, update, unusedArgsComplexity, parentBlocks))
}
.getOrElse {
val objectType = ctx.ec.typeDefs(name).asInstanceOf[CASETYPEREF] // todo handle absence
val fields = objectType.fields.map(_._1) zip fc.args.asInstanceOf[List[EVALUATED]]
root(CaseObj(objectType, fields.toMap), update, unusedArgsComplexity, parentBlocks)
val caseType =
ctx.ec.typeDefs.get(name) match {
case Some(caseType: CASETYPEREF) => Coeval.now(caseType)
case _ => Coeval.raiseError(new NoSuchElementException(s"Function or type '$name' not found"))
}
caseType.flatMap { objectType =>
val fields = objectType.fields.map(_._1) zip fc.args.asInstanceOf[List[EVALUATED]]
root(CaseObj(objectType, fields.toMap), update, unusedArgsComplexity, parentBlocks)
}
} else
Coeval.now(unusedArgsComplexity)
}
Expand Down Expand Up @@ -219,7 +225,8 @@ class EvaluatorV2(
}
}
.onErrorHandle { e =>
if (!wasLogged) ctx.l(let.name)(Left(e.getMessage))
val error = if (e.getMessage != null) e.getMessage else e.toString
if (!wasLogged) ctx.l(let.name)(Left(error))
throw e
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ object Functions {
}
}

private def withExtract[C[_[_]]](f: BaseFunction[C]): BaseFunction[C] = {
private def withExtract[C[_[_]]](f: BaseFunction[C], version: StdLibVersion): BaseFunction[C] = {
val args = f.signature.args.zip(f.args).map {
case ((name, ty), _) => ("@" ++ name, ty)
}
Expand All @@ -482,7 +482,8 @@ object Functions {
f.signature.result.asInstanceOf[UNION].typeList.find(_ != UNIT).get,
args: _*
) {
FUNCTION_CALL(PureContext.extract, List(FUNCTION_CALL(f.header, args.map(a => REF(a._1)).toList)))
val extractF = if (version >= V4) PureContext.value else PureContext.extract
FUNCTION_CALL(extractF, List(FUNCTION_CALL(f.header, args.map(a => REF(a._1)).toList)))
}
}

Expand All @@ -501,7 +502,7 @@ object Functions {
getBinaryByIndexF(v),
getStringByIndexF(v),
if (v >= V4) addressFromStringV4 else addressFromStringF(v)
).map(withExtract)
).map(withExtract(_, v))

def txByIdF(proofsEnabled: Boolean, version: StdLibVersion): BaseFunction[Environment] =
NativeFunction.withEnvironment[Environment](
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ class EvaluatorV2Test extends PropSpec with PropertyChecks with ScriptGen with M
)
)

an[NoSuchElementException] should be thrownBy eval(expr, limit = 100)
(the[NoSuchElementException] thrownBy eval(expr, limit = 100)).getMessage shouldBe "A definition of 'b' not found"

val expr2 =
BLOCK(
Expand All @@ -525,7 +525,7 @@ class EvaluatorV2Test extends PropSpec with PropertyChecks with ScriptGen with M
)
)

an[NoSuchElementException] should be thrownBy eval(expr2, limit = 100)
(the[NoSuchElementException] thrownBy eval(expr2, limit = 100)).getMessage shouldBe "Function or type 'b' not found"
}

property("function context leak") {
Expand All @@ -548,7 +548,7 @@ class EvaluatorV2Test extends PropSpec with PropertyChecks with ScriptGen with M
f() + x
*/

an[NoSuchElementException] should be thrownBy eval(expr, limit = 100)
(the[NoSuchElementException] thrownBy eval(expr, limit = 100)).getMessage shouldBe "A definition of 'x' not found"

val expr2 = BLOCK(
FUNC("f", Nil, BLOCK(FUNC("g", Nil, CONST_LONG(1)), FUNCTION_CALL(FunctionHeader.User("g"), Nil))),
Expand All @@ -569,7 +569,7 @@ class EvaluatorV2Test extends PropSpec with PropertyChecks with ScriptGen with M
f() + g()
*/

an[NoSuchElementException] should be thrownBy eval(expr2, limit = 100)
(the[NoSuchElementException] thrownBy eval(expr2, limit = 100)).getMessage shouldBe "Function or type 'g' not found"
}

property("if block by step") {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.wavesplatform.it.sync.smartcontract
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.common.utils.EitherExt2
import com.wavesplatform.it.api.SyncHttpApi._
import com.wavesplatform.it.sync.{setScriptFee, _}
import com.wavesplatform.it.transactions.BaseTransactionSuite
import com.wavesplatform.lang.v1.compiler.Terms.CONST_BOOLEAN
import com.wavesplatform.lang.v1.estimator.v3.ScriptEstimatorV3
import com.wavesplatform.state.BinaryDataEntry
import com.wavesplatform.transaction.TxVersion
import com.wavesplatform.transaction.smart.script.ScriptCompiler

// because of SC-655 bug
class InvokeSmartAssetFailSuite extends BaseTransactionSuite {
private val caller = firstAddress
private val dApp = secondAddress

val dAppText =
"""
|{-# STDLIB_VERSION 4 #-}
|{-# CONTENT_TYPE DAPP #-}
|{-# SCRIPT_TYPE ACCOUNT #-}
|
|let bob = addressFromPublicKey(base58'BzFTfc4TB9s25d8b3sfhptj4STZafEM2FNkR5kQ8mJeA')
|
|@Callable(i)
|func some(fail: Boolean) = {
| let issue = Issue("asset", "test asset", 500, 2, true)
| let assetId = if fail then this.getBinaryValue("assetId") else issue.calculateAssetId()
|
| let result = [
| BinaryEntry("bin", i.transactionId),
| BooleanEntry("bool", true),
| IntegerEntry("int", i.fee),
| StringEntry("str", i.caller.toString()),
| DeleteEntry("remove")
| ]
|
| if fail then {
| result ++ [
| Reissue(assetId, 10, false)
| ]
| } else {
| result ++ [
| issue,
| Reissue(assetId, 10, false),
| Burn(assetId, 5),
| SponsorFee(assetId, 2),
| ScriptTransfer(bob, 7, assetId)
| ]
| }
|
|}
""".stripMargin

test("extracted funcs") {
val assetId = ByteStr.decodeBase58(sender.issue(caller, waitForTx = true).id).get
val data = List(BinaryDataEntry("assetId", assetId))
val dataFee = calcDataFee(data, TxVersion.V2)
sender.putData(dApp, data, fee = dataFee, waitForTx = true)

val script = ScriptCompiler.compile(dAppText, ScriptEstimatorV3).explicitGet()._1.bytes().base64
sender.setScript(dApp, Some(script), setScriptFee, waitForTx = true)

val tx = sender.invokeScript(caller, dApp, Some("some"), List(CONST_BOOLEAN(true)), waitForTx = true)
sender.debugStateChanges(tx._1.id).stateChanges.get.error.get.text shouldBe "Asset was issued by other address"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,11 @@ class ContextFunctionsTest extends PropSpec with PropertyChecks with WithState w
}

property("reading from data transaction array by key") {
forAll(preconditionsAndPayments) {
case (_, _, _, tx, _, _) =>
forAll(for {
version <- Gen.oneOf(DirectiveDictionary[StdLibVersion].all.filter(_ >= V3))
preconditions <- preconditionsAndPayments
} yield (version, preconditions)) {
case (version, (_, _, _, tx, _, _)) =>
val int = tx.data(0)
val bool = tx.data(1)
val bin = tx.data(2)
Expand All @@ -102,10 +105,10 @@ class ContextFunctionsTest extends PropSpec with PropertyChecks with WithState w
| case tx: DataTransaction => {
| let d = tx.data
|
| let int = extract(getInteger(d, "${int.key}"))
| let bool = extract(getBoolean(d, "${bool.key}"))
| let bin = extract(getBinary(d, "${bin.key}"))
| let str = extract(getString(d, "${str.key}"))
| let int = value(getInteger(d, "${int.key}"))
| let bool = value(getBoolean(d, "${bool.key}"))
| let bin = value(getBinary(d, "${bin.key}"))
| let str = value(getString(d, "${str.key}"))
|
| let intV = getIntegerValue(d, "${int.key}")
| let boolV = getBooleanValue(d, "${bool.key}")
Expand All @@ -117,10 +120,10 @@ class ContextFunctionsTest extends PropSpec with PropertyChecks with WithState w
| let okBin = bin == base58'${Base58.encode(bin.asInstanceOf[BinaryDataEntry].value.arr)}'
| let okStr = str == "${str.value}"
|
| let okIntV = int + 1 == ${int.value} + 1
| let okBoolV = bool || true == ${bool.value} || true
| let okBinV = bin == base58'${Base58.encode(bin.asInstanceOf[BinaryDataEntry].value.arr)}'
| let okStrV = str + "" == "${str.value}"
| let okIntV = intV + 1 == ${int.value} + 1
| let okBoolV = boolV || true == ${bool.value} || true
| let okBinV = binV == base58'${Base58.encode(bin.asInstanceOf[BinaryDataEntry].value.arr)}'
| let okStrV = strV + "" == "${str.value}"
|
| let badInt = isDefined(getInteger(d, "${bool.key}"))
| let badBool = isDefined(getBoolean(d, "${bin.key}"))
Expand All @@ -137,7 +140,7 @@ class ContextFunctionsTest extends PropSpec with PropertyChecks with WithState w
|}
|""".stripMargin,
Coproduct(tx),
V3
version
)
result shouldBe evaluated(true)
}
Expand Down

0 comments on commit 399539f

Please sign in to comment.