Skip to content

Commit

Permalink
NODE-2515 Corrected validation of transaction version (#3886)
Browse files Browse the repository at this point in the history
  • Loading branch information
xrtm000 authored Oct 6, 2023
1 parent d4a0841 commit 7688483
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ object PBTransactions {
val data = Data.InvokeScript(toPBInvokeScriptData(dappAddress, fcOpt, payment))
PBTransactions.create(sender, chainId, fee.value, feeAssetId, timestamp, version, proofs, data)

case tx @ vt.assets.UpdateAssetInfoTransaction(version, sender, assetId, name, description, timestamp, fee, feeAssetId, proofs, chainId) =>
case vt.assets.UpdateAssetInfoTransaction(version, sender, assetId, name, description, timestamp, fee, feeAssetId, proofs, chainId) =>
val data = UpdateAssetInfoTransactionData()
.withAssetId(assetId.id.toByteString)
.withName(name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,13 @@ object CommonValidation {
}

val versionsBarrier = tx match {
case v: VersionedTransaction if !TransactionParsers.versionIsCorrect(v) && blockchain.isFeatureActivated(TransactionStateSnapshot) =>
Left(UnsupportedTypeAndVersion(v.tpe.id.toByte, v.version))

case p: PBSince if p.isProtobufVersion =>
activationBarrier(BlockchainFeatures.BlockV5)

case v: VersionedTransaction if !TransactionParsers.all.contains((v.tpe.id.toByte, v.version)) =>
case v: VersionedTransaction if !TransactionParsers.versionIsCorrect(v) =>
Left(UnsupportedTypeAndVersion(v.tpe.id.toByte, v.version))

case _ =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ object TransactionParsers {
SetAssetScriptTransaction,
InvokeScriptTransaction,
TransferTransaction,
InvokeExpressionTransaction
InvokeExpressionTransaction,
UpdateAssetInfoTransaction
).flatMap { x =>
x.supportedVersions.map { version =>
((x.typeId, version), x)
Expand Down Expand Up @@ -79,4 +80,7 @@ object TransactionParsers {
tx <- if (bytes(0) == 0) modernParseBytes else oldParseBytes
} yield tx
}

def versionIsCorrect(tx: Transaction & VersionedTransaction): Boolean =
TransactionParsers.all.contains((tx.tpe.id.toByte, tx.version))
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import com.wavesplatform.account.{AddressScheme, KeyPair, PrivateKey, PublicKey}
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.crypto
import com.wavesplatform.lang.ValidationError
import com.wavesplatform.transaction.*
import com.wavesplatform.transaction.Asset.IssuedAsset
import com.wavesplatform.transaction._
import com.wavesplatform.transaction.serialization.impl.{BaseTxJson, PBTransactionSerializer}
import com.wavesplatform.transaction.validation._
import com.wavesplatform.transaction.validation.*
import com.wavesplatform.transaction.validation.impl.UpdateAssetInfoTxValidator
import monix.eval.Coeval
import play.api.libs.json.{JsObject, Json}

import scala.util.{Failure, Success, Try}

case class UpdateAssetInfoTransaction(
version: TxVersion,
sender: PublicKey,
Expand Down Expand Up @@ -45,8 +47,11 @@ case class UpdateAssetInfoTransaction(
)
}

object UpdateAssetInfoTransaction {
val supportedVersions: Set[TxVersion] = Set(1)
object UpdateAssetInfoTransaction extends TransactionParser {
type TransactionT = UpdateAssetInfoTransaction

override val typeId: TxType = 17: Byte
override val supportedVersions: Set[TxVersion] = Set(1)

implicit def sign(tx: UpdateAssetInfoTransaction, privateKey: PrivateKey): UpdateAssetInfoTransaction =
tx.copy(proofs = Proofs(crypto.sign(privateKey, tx.bodyBytes())))
Expand Down Expand Up @@ -94,4 +99,12 @@ object UpdateAssetInfoTransaction {
): Either[ValidationError, UpdateAssetInfoTransaction] =
create(version, sender.publicKey, assetId, name, description, timestamp, feeAmount, feeAsset, Proofs.empty, chainId)
.map(_.signWith(sender.privateKey))

override def parseBytes(bytes: Array[Byte]): Try[UpdateAssetInfoTransaction] =
PBTransactionSerializer
.parseBytes(bytes)
.flatMap {
case tx: UpdateAssetInfoTransaction => Success(tx)
case tx: Transaction => Failure(UnexpectedTransaction(typeId, tx.tpe.id.toByte))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.wavesplatform.state.diffs

import com.wavesplatform.db.WithDomain
import com.wavesplatform.db.WithState.AddrWithBalance
import com.wavesplatform.lang.directives.values.V6
import com.wavesplatform.lang.v1.compiler.TestCompiler
import com.wavesplatform.test.DomainPresets.*
import com.wavesplatform.test.{PropSpec, produce}
import com.wavesplatform.transaction.Asset.{IssuedAsset, Waves}
import com.wavesplatform.transaction.TxHelpers.*
import com.wavesplatform.transaction.TxVersion.*
import com.wavesplatform.transaction.assets.exchange.OrderType.*
import com.wavesplatform.transaction.{Transaction, TxVersion}

class TransactionVersionValidationTest extends PropSpec with WithDomain {
private val script = TestCompiler(V6).compileExpression("true")
private val issueTx1 = issue(script = Some(script))
private val issueTx2 = issue()
private val leaseTx = lease()
private val setDApp = setScript(
secondSigner,
TestCompiler(V6).compileContract(
"""
| @Callable(i)
| func default() = []
""".stripMargin
)
)
private val preconditions = Seq(issueTx1, issueTx2, leaseTx, setDApp)

private val asset = IssuedAsset(issueTx1.id())
private val asset2 = IssuedAsset(issueTx2.id())
private val order1 = order(BUY, asset, Waves, price = 123456789, version = V1)
private val order2 = order(SELL, asset, Waves, price = 123456789, version = V1)

private val txsByMaxVersion: Seq[(TxVersion, TxVersion => Transaction)] =
Seq(
(V3, v => transfer(version = v)),
(V3, v => issue(version = v)),
(V3, v => reissue(asset, version = v)),
(V3, v => burn(asset, version = v)),
(V3, v => lease(version = v)),
(V3, v => leaseCancel(leaseTx.id(), version = v)),
(V3, v => createAlias("alias", version = v)),
(V3, v => exchange(order1, order2, version = v)),
(V2, v => data(defaultSigner, Seq(), version = v)),
(V2, v => invoke(version = v)),
(V2, v => massTransfer(version = v, fee = 200_000)),
(V2, v => setAssetScript(defaultSigner, asset, script, version = v)),
(V2, v => setScript(defaultSigner, script, version = v)),
(V2, v => sponsor(asset2, version = v)),
(V1, v => updateAssetInfo(asset.id, version = v))
)

property("zero and negative tx versions are forbidden before and after snapshot activation") {
Seq(BlockRewardDistribution, TransactionStateSnapshot).foreach(settings =>
withDomain(
settings.configure(_.copy(minAssetInfoUpdateInterval = 1)),
AddrWithBalance.enoughBalances(defaultSigner, secondSigner)
) { d =>
d.appendBlock(preconditions*)
txsByMaxVersion.foreach { case (_, tx) =>
d.appendBlockE(tx(0: Byte)) should produce("Bad transaction")
d.appendBlockE(tx(-1: Byte)) should produce("Bad transaction")
}
}
)
}

property("max tx version is available before and after snapshot activation") {
Seq(BlockRewardDistribution, TransactionStateSnapshot).foreach(settings =>
withDomain(
settings.configure(_.copy(minAssetInfoUpdateInterval = 1)),
AddrWithBalance.enoughBalances(defaultSigner, secondSigner)
) { d =>
d.appendBlock(preconditions*)
d.appendAndAssertSucceed(txsByMaxVersion.map { case (maxVersion, tx) => tx(maxVersion) }*)
}
)
}

property("more than max tx version is available before snapshot activation") {
withDomain(
BlockRewardDistribution.configure(_.copy(minAssetInfoUpdateInterval = 1)),
AddrWithBalance.enoughBalances(defaultSigner, secondSigner)
) { d =>
d.appendBlock(preconditions*)
d.appendAndAssertSucceed(txsByMaxVersion.map { case (maxVersion, tx) => tx((maxVersion + 1).toByte) }*)
}
}

property("more than max tx version is forbidden after snapshot activation") {
withDomain(
TransactionStateSnapshot.configure(_.copy(minAssetInfoUpdateInterval = 1)),
AddrWithBalance.enoughBalances(defaultSigner, secondSigner)
) { d =>
d.appendBlock(preconditions*)
txsByMaxVersion.foreach { case (maxVersion, tx) =>
d.appendBlockE(tx((maxVersion + 1).toByte)) should produce("Bad transaction")
}
}
}
}

0 comments on commit 7688483

Please sign in to comment.