Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NODE-2520 Corrected fail/reject on transfer action balance error #3897

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.wavesplatform.account.{Address, AddressOrAlias, PublicKey}
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.common.utils.EitherExt2
import com.wavesplatform.features.BlockchainFeatures
import com.wavesplatform.features.BlockchainFeatures.{BlockRewardDistribution, BlockV5, RideV6, SynchronousCalls}
import com.wavesplatform.features.BlockchainFeatures.*
import com.wavesplatform.features.EstimatorProvider.*
import com.wavesplatform.features.InvokeScriptSelfPaymentPolicyProvider.*
import com.wavesplatform.features.ScriptTransferValidationProvider.*
Expand Down Expand Up @@ -514,17 +514,17 @@ object InvokeDiffsCommon {
e
)
)
).flatMap(nextDiff =>
).flatMap(portfolioSnapshot =>
blockchain
.assetScript(a)
.fold {
val r = checkAsset(blockchain, id)
.map(_ => nextDiff)
.map(_ => portfolioSnapshot)
.leftMap(FailedTransactionError.dAppExecution(_, 0): ValidationError)
TracedResult(r)
} { case AssetScriptInfo(script, complexity) =>
val assetVerifierSnapshot =
if (blockchain.disallowSelfPayment) nextDiff
if (blockchain.disallowSelfPayment) portfolioSnapshot
else
StateSnapshot
.build(
Expand All @@ -549,9 +549,11 @@ object InvokeDiffsCommon {
tx.timestamp,
tx.txId
)
val assetValidationDiff = for {
_ <- BalanceDiffValidation.cond(blockchain, _.isFeatureActivated(BlockchainFeatures.RideV6))(assetVerifierSnapshot)
assetValidationDiff <- validatePseudoTxWithSmartAssetScript(blockchain, tx)(
val assetValidationSnapshot = for {
_ <- BalanceDiffValidation
.cond(blockchain, _.isFeatureActivated(RideV6))(assetVerifierSnapshot)
.leftMap(e => if (blockchain.isFeatureActivated(LightNode)) FailedTransactionError.asFailedScriptError(e) else e)
snapshot <- validatePseudoTxWithSmartAssetScript(blockchain, tx)(
pseudoTx,
a.id,
assetVerifierSnapshot,
Expand All @@ -560,10 +562,10 @@ object InvokeDiffsCommon {
complexityLimit,
enableExecutionLog
)
} yield assetValidationDiff
val errorOpt = assetValidationDiff.fold(Some(_), _ => None)
} yield snapshot
val errorOpt = assetValidationSnapshot.fold(Some(_), _ => None)
TracedResult(
assetValidationDiff.map(d => nextDiff.setScriptsComplexity(d.scriptsComplexity)),
assetValidationSnapshot.map(d => portfolioSnapshot.setScriptsComplexity(d.scriptsComplexity)),
List(AssetVerifierTrace(id, errorOpt, AssetContext.Transfer))
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.wavesplatform.state.diffs.ci

import com.wavesplatform.db.WithDomain
import com.wavesplatform.db.WithState.AddrWithBalance
import com.wavesplatform.features.BlockchainFeatures.{LightNode, RideV6}
import com.wavesplatform.lang.directives.values.V5
import com.wavesplatform.lang.v1.compiler.TestCompiler
import com.wavesplatform.test.DomainPresets.{RideV5, WavesSettingsOps}
import com.wavesplatform.test.{PropSpec, produce}
import com.wavesplatform.transaction.Asset.IssuedAsset
import com.wavesplatform.transaction.TxHelpers.*

class InvokeTransferBalanceErrorTest extends PropSpec with WithDomain {
private val assetFailScript = TestCompiler(V5).compileExpression(
s"""
| strict c = ${(1 to 5).map(_ => "sigVerify(base58'', base58'', base58'')").mkString(" || ")}
| if (true) then throw() else true
""".stripMargin
)

property("invoke is always rejected with a lack of funds without execution of ScriptTransfer script after RideV6, corrected after LightNode") {
val issueTx = issue(signer(10), script = Some(assetFailScript))
val asset = IssuedAsset(issueTx.id())
val dApp = TestCompiler(V5).compileContract(
s"""
| @Callable(i)
| func default() = {
| [ScriptTransfer(i.caller, 1, base58'$asset')]
| }
|
| @Callable(i)
| func complex() = {
| strict c = ${(1 to 6).map(_ => "sigVerify(base58'', base58'', base58'')").mkString(" || ")}
| [ScriptTransfer(i.caller, 1, base58'$asset')]
| }
""".stripMargin
)
withDomain(
RideV5.setFeaturesHeight(RideV6 -> 6, LightNode -> 7),
AddrWithBalance.enoughBalances(secondSigner, signer(10))
) { d =>
d.appendBlock(issueTx)
d.appendBlock(setScript(secondSigner, dApp))

// RideV5 — always failed
d.appendAndAssertFailed(invoke(), "Transaction is not allowed by script of the asset")
d.appendAndAssertFailed(invoke(func = Some("complex")), "Transaction is not allowed by script of the asset")

// RideV6 — always rejected
d.appendBlockE(invoke()) should produce("negative asset balance")
d.appendBlockE(invoke(func = Some("complex"))) should produce("negative asset balance")

// LightNode — rejected or failed
d.appendBlock()
d.appendBlockE(invoke()) should produce("negative asset balance")
d.appendAndAssertFailed(invoke(func = Some("complex")), "negative asset balance")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@ import com.wavesplatform.state.StringDataEntry
import com.wavesplatform.state.TxMeta.Status
import com.wavesplatform.state.diffs.FeeValidation.{FeeConstants, FeeUnit}
import com.wavesplatform.test.*
import com.wavesplatform.test.DomainPresets.RideV5
import com.wavesplatform.transaction.Asset.{IssuedAsset, Waves}
import com.wavesplatform.transaction.TxHelpers.*
import com.wavesplatform.transaction.smart.InvokeScriptTransaction.Payment
import com.wavesplatform.transaction.{TransactionType, TxHelpers}

class RideV5FailRejectTest extends PropSpec with WithDomain {
import DomainPresets.*

private val assetFailScript = TestCompiler(V5).compileExpression(
s"""
| strict c = ${(1 to 5).map(_ => "sigVerify(base58'', base58'', base58'')").mkString(" || ")}
Expand Down Expand Up @@ -107,32 +106,6 @@ class RideV5FailRejectTest extends PropSpec with WithDomain {
}
}

property("invoke is rejected with a lack of funds without execution of ScriptTransfer script only after RideV6") {
val issueTx = issue(signer(10), script = Some(assetFailScript))
val asset = IssuedAsset(issueTx.id())
val dApp = TestCompiler(V5).compileContract(
s"""
| @Callable(i)
| func default() = [
| ScriptTransfer(i.caller, 1, base58'$asset')
| ]
""".stripMargin
)
val invokeTx = invoke()
withDomain(RideV5, AddrWithBalance.enoughBalances(secondSigner, signer(10))) { d =>
d.appendBlock(issueTx)
d.appendBlock(setScript(secondSigner, dApp))
d.appendAndAssertFailed(invokeTx, "Transaction is not allowed by script of the asset")
}

// TODO: move test after bug fix NODE-2520
withDomain(RideV6, AddrWithBalance.enoughBalances(secondSigner, signer(10))) { d =>
d.appendBlock(issueTx)
d.appendBlock(setScript(secondSigner, dApp))
d.appendBlockE(invokeTx) should produce("negative asset balance")
}
}

property("failed invoke doesn't affect state") {
withDomain(RideV5, AddrWithBalance.enoughBalances(secondSigner, signer(10))) { d =>
val failAssetIssue = issue(script = Some(assetFailScript))
Expand Down