mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
tests for tx size limit (32 KB)
This commit is contained in:
parent
db79143a13
commit
4fcbb92354
2 changed files with 62 additions and 2 deletions
|
|
@ -223,6 +223,7 @@ type TxPool struct {
|
|||
currentState *state.StateDB // Current state in the blockchain head
|
||||
pendingNonces *txNoncer // Pending state tracking virtual nonces
|
||||
currentMaxGas uint64 // Current gas limit for transaction caps
|
||||
maxTxSize uint64 // Maximal size of allowed transaction in bytes
|
||||
|
||||
locals *accountSet // Set of local transaction to exempt from eviction rules
|
||||
journal *txJournal // Journal of local transaction to back up to disk
|
||||
|
|
@ -270,6 +271,9 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block
|
|||
reorgDoneCh: make(chan chan struct{}),
|
||||
reorgShutdownCh: make(chan struct{}),
|
||||
gasPrice: new(big.Int).SetUint64(config.PriceLimit),
|
||||
|
||||
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks
|
||||
maxTxSize: 32 * 1024,
|
||||
}
|
||||
pool.locals = newAccountSet(pool.signer)
|
||||
for _, addr := range config.Locals {
|
||||
|
|
@ -510,8 +514,8 @@ func (pool *TxPool) local() map[common.Address]types.Transactions {
|
|||
// validateTx checks whether a transaction is valid according to the consensus
|
||||
// rules and adheres to some heuristic limits of the local node (price and size).
|
||||
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
|
||||
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks
|
||||
if tx.Size() > 32*1024 {
|
||||
// Reject transactions over defined size to prevent DOS attacks
|
||||
if uint64(tx.Size()) > pool.maxTxSize {
|
||||
return ErrOversizedData
|
||||
}
|
||||
// Transactions can't be negative. This may never happen using RLP decoded
|
||||
|
|
|
|||
|
|
@ -77,6 +77,13 @@ func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ec
|
|||
return tx
|
||||
}
|
||||
|
||||
func pricedDataTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey, numDataBytes uint64) *types.Transaction {
|
||||
data := make([]byte, numDataBytes)
|
||||
rand.Read(data)
|
||||
tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(0), gaslimit, gasprice, data), types.HomesteadSigner{}, key)
|
||||
return tx
|
||||
}
|
||||
|
||||
func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
|
||||
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||
|
|
@ -754,6 +761,55 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Test the limit on transaction size is enforced correctly.
|
||||
// This test verifies every transaction having allowed size
|
||||
// is added to the pool, and longer transactions are rejected.
|
||||
func TestAllowedTxSize(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create a test account and fund it
|
||||
pool, key := setupTxPool()
|
||||
defer pool.Stop()
|
||||
|
||||
account, _ := deriveSender(transaction(0, 0, key))
|
||||
pool.currentState.AddBalance(account, big.NewInt(1024*int64(pool.currentMaxGas)))
|
||||
|
||||
// Compute maximal data size for transactions (lower bound).
|
||||
// It is assumed the fields in the transaction (except of the data) are:
|
||||
// nonce : at most 32 bytes
|
||||
// gasPrice : at most 32 bytes
|
||||
// gasLimit : at most 32 bytes
|
||||
// To address : 20 bytes
|
||||
// value : at most 32 bytes
|
||||
// signature : 65 bytes
|
||||
// All those fields are summed up to at most 213 bytes.
|
||||
txSizeWithoutData := uint64(213)
|
||||
maxDataSize := pool.maxTxSize - txSizeWithoutData
|
||||
|
||||
// Increase block gas limit to infinity
|
||||
pool.currentMaxGas = 2 << 60
|
||||
|
||||
// Try adding a transaction with maximal allowed size
|
||||
if err := pool.validateTx(pricedDataTransaction(0, pool.currentMaxGas, big.NewInt(0), key, maxDataSize), true); err != nil {
|
||||
t.Fatalf("failed to add transaction of size close to maximal: %d, %v", int(pricedDataTransaction(0, pool.currentMaxGas, big.NewInt(1), key, maxDataSize).Size()), err)
|
||||
}
|
||||
|
||||
// Try adding a transaction with random allowed size
|
||||
if err := pool.validateTx(pricedDataTransaction(0, pool.currentMaxGas, big.NewInt(0), key, uint64(rand.Intn(int(maxDataSize)))), true); err != nil {
|
||||
t.Fatalf("failed to add transaction of random allowed size: %v", err)
|
||||
}
|
||||
|
||||
// Try adding a transaction of minimal not allowed size
|
||||
if pool.validateTx(pricedDataTransaction(0, pool.currentMaxGas, big.NewInt(0), key, pool.maxTxSize), true) == nil {
|
||||
t.Fatalf("expected rejection on slightly oversize transaction")
|
||||
}
|
||||
|
||||
// Try adding a transaction of random not allowed size
|
||||
if pool.validateTx(pricedDataTransaction(0, pool.currentMaxGas, big.NewInt(1), key, maxDataSize+1+uint64(rand.Intn(int(10*pool.maxTxSize)))), true) == nil {
|
||||
t.Fatalf("expected rejection on oversize transaction")
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that if the transaction count belonging to multiple accounts go above
|
||||
// some threshold, the higher transactions are dropped to prevent DOS attacks.
|
||||
//
|
||||
|
|
|
|||
Loading…
Reference in a new issue