Skip to content

Commit

Permalink
Merge branch 'version-1.5.x' into node-micro-block-inv-absence
Browse files Browse the repository at this point in the history
  • Loading branch information
xrtm000 authored Nov 20, 2023
2 parents 309ee34 + c7245d6 commit cacc4e0
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 170 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ class AcceptFailedScriptActivationSuite extends BaseTransactionSuite with NTPTim
smartMatcherFee,
100L,
ts,
ts + Order.MaxLiveTime,
ts + 2.days.toMillis,
smartMatcherFee
)
.explicitGet()
Expand All @@ -314,7 +314,7 @@ class AcceptFailedScriptActivationSuite extends BaseTransactionSuite with NTPTim
smartMatcherFee,
100L,
ts,
ts + Order.MaxLiveTime,
ts + 2.days.toMillis,
smartMatcherFee
)
.explicitGet()
Expand Down Expand Up @@ -375,7 +375,7 @@ class AcceptFailedScriptActivationSuite extends BaseTransactionSuite with NTPTim
10L,
100L,
ts,
ts + Order.MaxLiveTime,
ts + 2.days.toMillis,
smartMatcherFee,
matcherFeeAssetId = IssuedAsset(ByteStr.decodeBase58(feeAsset).get)
)
Expand All @@ -390,7 +390,7 @@ class AcceptFailedScriptActivationSuite extends BaseTransactionSuite with NTPTim
10L,
100L,
ts,
ts + Order.MaxLiveTime,
ts + 2.days.toMillis,
smartMatcherFee,
matcherFeeAssetId = IssuedAsset(ByteStr.decodeBase58(feeAsset).get)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,31 +121,6 @@ class FailedTransactionGrpcSuite extends GrpcBaseTransactionSuite with FailedTra
sender.setScript(contract, Right(Some(script)), setScriptFee, waitForTx = true)
}

test("InvokeScriptTransaction: insufficient action fees propagates failed transaction") {
val invokeFee = 0.005.waves
val setAssetScriptMinFee = setAssetScriptFee + smartFee * 2
val priorityFee = setAssetScriptMinFee + invokeFee

updateAssetScript(result = true, smartAsset, contract, setAssetScriptMinFee)

for (typeName <- Seq("transfer", "issue", "reissue", "burn")) {
updateTikTok("unknown", setAssetScriptMinFee)

overflowBlock()
sendTxsAndThenPriorityTx(
_ =>
sender
.broadcastInvokeScript(
caller,
Recipient().withPublicKeyHash(contractAddr),
Some(FUNCTION_CALL(FunctionHeader.User("tikTok"), List.empty)),
fee = invokeFee
),
() => updateTikTok(typeName, priorityFee, waitForTx = false)
)((txs, _) => assertFailedTxs(txs))
}
}

test("InvokeScriptTransaction: invoke script error in payment asset propagates failed transaction") {
val invokeFee = 0.005.waves + smartFee
val setAssetScriptMinFee = setAssetScriptFee + smartFee
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ package com.wavesplatform.it.sync.transactions
import com.typesafe.config.Config
import com.wavesplatform.api.http.ApiError.TransactionNotAllowedByAssetScript
import com.wavesplatform.api.http.DebugMessage
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.common.utils.EitherExt2
import com.wavesplatform.it.api.SyncHttpApi.*
import com.wavesplatform.it.api.{StateChanges, TransactionStatus}
import com.wavesplatform.it.sync.*
import com.wavesplatform.it.transactions.BaseTransactionSuite
import com.wavesplatform.lang.v1.compiler.Terms
import com.wavesplatform.lang.v1.estimator.v3.ScriptEstimatorV3
import com.wavesplatform.state.{BooleanDataEntry, StringDataEntry}
import com.wavesplatform.state.StringDataEntry
import com.wavesplatform.test.*
import com.wavesplatform.transaction.assets.exchange.AssetPair
import com.wavesplatform.transaction.smart.script.ScriptCompiler
Expand Down Expand Up @@ -118,52 +115,6 @@ class FailedTransactionSuite extends BaseTransactionSuite with CancelAfterFailur
sender.setScript(contract, Some(script), setScriptFee, waitForTx = true).id
}

test("InvokeScriptTransaction: insufficient action fees propagates failed transaction") {
val invokeFee = 0.005.waves
val setAssetScriptMinFee = setAssetScriptFee + smartFee
val priorityFee = setAssetScriptMinFee + invokeFee

updateAssetScript(result = true, smartAsset, contract, setAssetScriptMinFee)

for (typeName <- Seq("transfer", "issue", "reissue", "burn")) {
updateTikTok("unknown", setAssetScriptMinFee)

val prevBalance = sender.balance(caller.toAddress.toString).balance
val prevAssetBalance = sender.assetBalance(contractAddress, smartAsset)
val prevAssets = sender.assetsBalance(contractAddress)

overflowBlock()
sendTxsAndThenPriorityTx(
_ => sender.invokeScript(caller, contractAddress, Some("tikTok"), fee = invokeFee)._1.id,
() => updateTikTok(typeName, priorityFee, waitForTx = false)
) { (txs, priorityTx) =>
logPriorityTx(priorityTx)

val failed = assertFailedTxs(txs)

sender.balance(caller.toAddress.toString).balance shouldBe prevBalance - txs.size * invokeFee
sender.assetBalance(contractAddress, smartAsset) shouldBe prevAssetBalance
sender.assetsBalance(contractAddress).balances should contain theSameElementsAs prevAssets.balances

val (scriptInvokedInfo, issuedInfo) =
if (typeName == "issue")
("", " with 1 assets issued")
else
(" with 1 total scripts invoked", "")

val minFee = if (typeName == "issue") invokeFee + issueFee else invokeFee + smartFee
val text = s"Fee in WAVES for InvokeScriptTransaction ($invokeFee in WAVES)" +
s"$scriptInvokedInfo$issuedInfo does not exceed minimal value of $minFee WAVES."

failed.foreach { s =>
checkStateChange(sender.stateChanges(s.id), 2, text)
}

failed
}
}
}

test("InvokeScriptTransaction: reject transactions if account script failed") {
val invokeFee = 0.005.waves
val setAssetScriptMinFee = setAssetScriptFee + smartFee
Expand Down Expand Up @@ -212,50 +163,6 @@ class FailedTransactionSuite extends BaseTransactionSuite with CancelAfterFailur
}
}

test("InvokeScriptTransaction: transactionHeightById returns only succeed transactions") {
val invokeFee = 0.005.waves + smartFee
val setAssetScriptMinFee = setAssetScriptFee + smartFee
val priorityFee = setAssetScriptMinFee + invokeFee

updateAccountScript(None, caller, setScriptFee + smartFee)
updateTikTok("reissue", setAssetScriptMinFee)
updateAssetScript(result = true, smartAsset, contract, setAssetScriptMinFee)
waitForEmptyUtx()
overflowBlock()

val failedTxs = sendTxsAndThenPriorityTx(
_ => sender.invokeScript(caller, contractAddress, Some("tikTok"), fee = invokeFee)._1.id,
() => updateAssetScript(result = false, smartAsset, contract, priorityFee)
) { (txs, priorityTx) =>
logPriorityTx(priorityTx)
assertFailedTxs(txs)
}

checkTransactionHeightById(failedTxs)
}

test("ExchangeTransaction: transaction validates as failed when asset script fails") {
val Precondition(amountAsset, priceAsset, buyFeeAsset, sellFeeAsset) =
exchangePreconditions(
Some(ScriptCompiler.compile("true", ScriptEstimatorV3(fixOverflow = true, overhead = false)).explicitGet()._1.bytes().base64)
)

val assetPair = AssetPair.createAssetPair(amountAsset, priceAsset).get
val fee = 0.003.waves + 4 * smartFee
val sellMatcherFee = fee / 100000L
val buyMatcherFee = fee / 100000L

val (assetScript, _) =
ScriptCompiler.compile("if true then throw(\"error\") else false", ScriptEstimatorV3(fixOverflow = true, overhead = false)).explicitGet()
val scriptTx = sender.setAssetScript(priceAsset, buyerAddress, script = Some(assetScript.bytes().base64))
nodes.waitForHeightAriseAndTxPresent(scriptTx.id)

val tx = mkExchange(buyer, seller, matcher, assetPair, fee, buyFeeAsset, sellFeeAsset, buyMatcherFee, sellMatcherFee)
val result = sender.signedValidate(tx.json())
(result \ "valid").as[Boolean] shouldBe false
(result \ "error").as[String] should include("not allowed by script of the asset")
}

test("ExchangeTransaction: invalid exchange tx when asset script fails on broadcast") {
val init = Seq(
sender.setScript(firstKeyPair, None, setScriptFee + smartFee).id,
Expand Down Expand Up @@ -309,38 +216,6 @@ class FailedTransactionSuite extends BaseTransactionSuite with CancelAfterFailur
private def waitForTxs(txs: Seq[String]): Unit =
nodes.waitFor("preconditions", 500.millis)(_.transactionStatus(txs).forall(_.status == "confirmed"))(_.forall(identity))

private def checkStateChange(info: StateChanges, code: Int, text: String, strict: Boolean = false): Unit = {
info.stateChanges shouldBe defined
info.stateChanges.get.issues.size shouldBe 0
info.stateChanges.get.reissues.size shouldBe 0
info.stateChanges.get.burns.size shouldBe 0
info.stateChanges.get.error shouldBe defined
info.stateChanges.get.error.get.code shouldBe code
if (strict)
info.stateChanges.get.error.get.text shouldBe text
else
info.stateChanges.get.error.get.text should include(text)
}

private def checkTransactionHeightById(failedTxs: Seq[TransactionStatus]): Unit = {
val defineTxs = failedTxs.map { status =>
sender
.invokeScript(
caller,
contractAddress,
Some("defineTxHeight"),
List(Terms.CONST_BYTESTR(ByteStr.decodeBase58(status.id).get).explicitGet()),
fee = invokeFee
)
._1
.id
}

waitForTxs(defineTxs)

failedTxs.foreach(status => sender.getDataByKey(contractAddress, status.id) shouldBe BooleanDataEntry(status.id, value = false))
}

private def exchangePreconditions(initScript: Option[String]): Precondition = {
val transfers = Seq(
sender.transfer(sender.keyPair, sellerAddress.toAddress.toString, 100.waves).id,
Expand Down
4 changes: 2 additions & 2 deletions node/src/test/scala/com/wavesplatform/RxScheduler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ trait RxScheduler extends BeforeAndAfterAll { _: Suite =>

def test[A](f: => Future[A]): A = Await.result(f, 10.seconds)

def send[A](p: Observer[A])(a: A): Future[Ack] =
def send[A](p: Observer[A], timeout: Int = 500)(a: A): Future[Ack] =
p.onNext(a)
.map(ack => {
Thread.sleep(500)
Thread.sleep(timeout)
ack
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class RxExtensionLoaderSpec extends FreeSpec with RxScheduler with BlockGen {
"should blacklist GetSignatures timeout" in withExtensionLoader(Seq.tabulate(100)(byteStr), 1.millis) { (_, _, _, ccsw, _) =>
val ch = new EmbeddedChannel()
test(for {
_ <- send(ccsw)(ChannelClosedAndSyncWith(None, Some(BestChannel(ch, 1: BigInt))))
_ <- send(ccsw, timeout = 1000)(ChannelClosedAndSyncWith(None, Some(BestChannel(ch, 1: BigInt))))
} yield {
ch.isOpen shouldBe false
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import com.wavesplatform.lang.v1.compiler.TestCompiler
import com.wavesplatform.state.diffs.FeeValidation.{FeeConstants, FeeUnit}
import com.wavesplatform.test.*
import com.wavesplatform.transaction.Asset.IssuedAsset
import com.wavesplatform.transaction.smart.InvokeScriptTransaction.Payment
import com.wavesplatform.transaction.TxHelpers.*
import com.wavesplatform.transaction.smart.InvokeScriptTransaction
import com.wavesplatform.transaction.smart.InvokeScriptTransaction.Payment
import com.wavesplatform.transaction.{Transaction, TransactionType, TxHelpers}
import org.scalatest.{EitherValues, Inside}

Expand All @@ -26,10 +27,7 @@ class InvokeActionsFeeTest extends PropSpec with Inside with WithState with DBCa

private val verifier: Script =
TestCompiler(V4).compileExpression(
s""" {-# STDLIB_VERSION 4 #-}
| {-# SCRIPT_TYPE ASSET #-}
| {-# CONTENT_TYPE EXPRESSION #-}
|
s"""
| !(sigVerify_32Kb(base58'', base58'', base58'') ||
| sigVerify_32Kb(base58'', base58'', base58'') ||
| sigVerify_32Kb(base58'', base58'', base58''))
Expand All @@ -38,13 +36,13 @@ class InvokeActionsFeeTest extends PropSpec with Inside with WithState with DBCa

private def dApp(asset: IssuedAsset): Script =
TestCompiler(V4).compileContract(s"""
| @Callable(i)
| func default() =
| [
| ScriptTransfer(i.caller, 1, base58'$asset'),
| Burn(base58'$asset', 1),
| Reissue(base58'$asset', 1, false)
| ]
| @Callable(i)
| func default() =
| [
| ScriptTransfer(i.caller, 1, base58'$asset'),
| Burn(base58'$asset', 1),
| Reissue(base58'$asset', 1, false)
| ]
""".stripMargin)

private val paymentPreconditions: (Seq[AddrWithBalance], List[Transaction], () => InvokeScriptTransaction, () => InvokeScriptTransaction) = {
Expand All @@ -64,6 +62,33 @@ class InvokeActionsFeeTest extends PropSpec with Inside with WithState with DBCa
(balances, List(issue, transfer1, transfer2, setVerifier, setDApp), invokeFromScripted, invokeFromNonScripted)
}

property("insufficient action fees propagates failed transaction before RIDE V5 activation") {
withDomain(RideV4, AddrWithBalance.enoughBalances(secondSigner)) { d =>
val issueTx = issue(script = Some(TestCompiler(V4).compileExpression("true")))
val asset = IssuedAsset(issueTx.id())
val dApp = TestCompiler(V4).compileContract(
s"""
| @Callable(i)
| func transfer() = [ScriptTransfer(i.caller, 1, base58'$asset')]
|
| @Callable(i)
| func reissue() = [Reissue(base58'$asset', 1, true)]
|
| @Callable(i)
| func burn() = [Burn(base58'$asset', 1)]
|
| @Callable(i)
| func issue() = [Issue("name", "", 1000, 4, true, unit, 0)]
""".stripMargin
)
d.appendBlock(issueTx, setScript(secondSigner, dApp))
d.appendAndAssertFailed(invoke(func = Some("transfer")), "with 1 total scripts invoked does not exceed minimal value of 900000 WAVES")
d.appendAndAssertFailed(invoke(func = Some("reissue")), "with 1 total scripts invoked does not exceed minimal value of 900000 WAVES")
d.appendAndAssertFailed(invoke(func = Some("burn")), "with 1 total scripts invoked does not exceed minimal value of 900000 WAVES")
d.appendAndAssertFailed(invoke(func = Some("issue")), "with 1 assets issued does not exceed minimal value of 100500000 WAVES")
}
}

property(s"fee for asset scripts is not required after activation ${BlockchainFeatures.SynchronousCalls}") {
val (balances, preparingTxs, invokeFromScripted, invokeFromNonScripted) = paymentPreconditions
withDomain(fsWithV5, balances) { d =>
Expand Down

0 comments on commit cacc4e0

Please sign in to comment.