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
|
currentState *state.StateDB // Current state in the blockchain head
|
||||||
pendingNonces *txNoncer // Pending state tracking virtual nonces
|
pendingNonces *txNoncer // Pending state tracking virtual nonces
|
||||||
currentMaxGas uint64 // Current gas limit for transaction caps
|
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
|
locals *accountSet // Set of local transaction to exempt from eviction rules
|
||||||
journal *txJournal // Journal of local transaction to back up to disk
|
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{}),
|
reorgDoneCh: make(chan chan struct{}),
|
||||||
reorgShutdownCh: make(chan struct{}),
|
reorgShutdownCh: make(chan struct{}),
|
||||||
gasPrice: new(big.Int).SetUint64(config.PriceLimit),
|
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)
|
pool.locals = newAccountSet(pool.signer)
|
||||||
for _, addr := range config.Locals {
|
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
|
// 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).
|
// rules and adheres to some heuristic limits of the local node (price and size).
|
||||||
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
|
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
|
||||||
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks
|
// Reject transactions over defined size to prevent DOS attacks
|
||||||
if tx.Size() > 32*1024 {
|
if uint64(tx.Size()) > pool.maxTxSize {
|
||||||
return ErrOversizedData
|
return ErrOversizedData
|
||||||
}
|
}
|
||||||
// Transactions can't be negative. This may never happen using RLP decoded
|
// 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
|
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) {
|
func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
|
||||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
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
|
// Tests that if the transaction count belonging to multiple accounts go above
|
||||||
// some threshold, the higher transactions are dropped to prevent DOS attacks.
|
// some threshold, the higher transactions are dropped to prevent DOS attacks.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue