mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 15:46:43 +00:00
feat: add block transaction count limit (#216)
* feat: add block transaction count limit * add tests * nit
This commit is contained in:
parent
e3e0078d1b
commit
30f4f57f07
5 changed files with 83 additions and 3 deletions
|
|
@ -34,4 +34,7 @@ var (
|
|||
// ErrInvalidNumber is returned if a block's number doesn't equal its parent's
|
||||
// plus one.
|
||||
ErrInvalidNumber = errors.New("invalid block number")
|
||||
|
||||
// ErrInvalidTxCount is returned if a block contains too many transactions.
|
||||
ErrInvalidTxCount = errors.New("invalid transaction count")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
|||
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
|
||||
return ErrKnownBlock
|
||||
}
|
||||
if !v.config.IsValidTxCount(len(block.Transactions())) {
|
||||
return consensus.ErrInvalidTxCount
|
||||
}
|
||||
// Header validity is known at this point, check the uncles and transactions
|
||||
header := block.Header()
|
||||
if err := v.engine.VerifyUncles(v.bc, block); err != nil {
|
||||
|
|
|
|||
|
|
@ -3177,3 +3177,64 @@ func TestFeeVault(t *testing.T) {
|
|||
t.Fatalf("fee vault balance incorrect: expected %d, got %d", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
// TestTransactionCountLimit tests that the chain reject blocks with too many transactions.
|
||||
func TestTransactionCountLimit(t *testing.T) {
|
||||
// Create config that allows at most 1 transaction per block
|
||||
config := params.TestChainConfig
|
||||
config.MaxTxPerBlock = new(int)
|
||||
*config.MaxTxPerBlock = 1
|
||||
|
||||
var (
|
||||
engine = ethash.NewFaker()
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||
funds = big.NewInt(1000000000000000)
|
||||
gspec = &Genesis{Config: config, Alloc: GenesisAlloc{address: {Balance: funds}}}
|
||||
genesis = gspec.MustCommit(db)
|
||||
)
|
||||
|
||||
addTx := func(b *BlockGen) {
|
||||
tx := types.NewTransaction(b.TxNonce(address), address, big.NewInt(0), 50000, b.header.BaseFee, nil)
|
||||
signed, _ := types.SignTx(tx, types.HomesteadSigner{}, key)
|
||||
b.AddTx(signed)
|
||||
}
|
||||
|
||||
// Initialize blockchain
|
||||
blockchain, err := NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create new chain manager: %v", err)
|
||||
}
|
||||
defer blockchain.Stop()
|
||||
|
||||
// Insert empty block
|
||||
block1, _ := GenerateChain(config, genesis, ethash.NewFaker(), db, 1, func(i int, b *BlockGen) {
|
||||
// empty
|
||||
})
|
||||
|
||||
if _, err := blockchain.InsertChain(block1); err != nil {
|
||||
t.Fatalf("failed to insert chain: %v", err)
|
||||
}
|
||||
|
||||
// Insert block with 1 transaction
|
||||
block2, _ := GenerateChain(config, genesis, ethash.NewFaker(), db, 1, func(i int, b *BlockGen) {
|
||||
addTx(b)
|
||||
})
|
||||
|
||||
if _, err := blockchain.InsertChain(block2); err != nil {
|
||||
t.Fatalf("failed to insert chain: %v", err)
|
||||
}
|
||||
|
||||
// Insert block with 2 transactions
|
||||
block3, _ := GenerateChain(config, genesis, ethash.NewFaker(), db, 1, func(i int, b *BlockGen) {
|
||||
addTx(b)
|
||||
addTx(b)
|
||||
})
|
||||
|
||||
_, err = blockchain.InsertChain(block3)
|
||||
|
||||
if !errors.Is(err, consensus.ErrInvalidTxCount) {
|
||||
t.Fatalf("error mismatch: have: %v, want: %v", err, consensus.ErrInvalidTxCount)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -818,6 +818,11 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
|
|||
}
|
||||
return atomic.LoadInt32(interrupt) == commitInterruptNewHead
|
||||
}
|
||||
// If we have collected enough transactions then we're done
|
||||
if !w.chainConfig.IsValidTxCount(w.current.tcount + 1) {
|
||||
log.Trace("Transaction count limit reached", "have", w.current.tcount, "want", w.chainConfig.MaxTxPerBlock)
|
||||
break
|
||||
}
|
||||
// If we don't have enough gas for any further transactions then we're done
|
||||
if w.current.gasPool.Gas() < params.TxGas {
|
||||
log.Trace("Not enough gas for further transactions", "have", w.current.gasPool, "want", params.TxGas)
|
||||
|
|
|
|||
|
|
@ -258,16 +258,16 @@ var (
|
|||
//
|
||||
// This configuration is intentionally not using keyed fields to force anyone
|
||||
// adding flags to the config to also have to set these fields.
|
||||
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, false, nil, true, true}
|
||||
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, false, nil, true, true, nil}
|
||||
|
||||
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
|
||||
// and accepted by the Ethereum core developers into the Clique consensus.
|
||||
//
|
||||
// This configuration is intentionally not using keyed fields to force anyone
|
||||
// adding flags to the config to also have to set these fields.
|
||||
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, false, nil, true, true}
|
||||
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, false, nil, true, true, nil}
|
||||
|
||||
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, false, &common.Address{123}, true, true}
|
||||
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, false, &common.Address{123}, true, true, nil}
|
||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||
)
|
||||
|
||||
|
|
@ -367,6 +367,9 @@ type ChainConfig struct {
|
|||
|
||||
// Scroll genesis extension: enable EIP-1559 in tx pool, EnableEIP2718 should be true too.
|
||||
EnableEIP1559 bool `json:"enableEIP1559,omitempty"`
|
||||
|
||||
// Scroll genesis extension: Maximum number of transactions per block [optional]
|
||||
MaxTxPerBlock *int `json:"maxTxPerBlock,omitempty"`
|
||||
}
|
||||
|
||||
// EthashConfig is the consensus engine configs for proof-of-work based sealing.
|
||||
|
|
@ -494,6 +497,11 @@ func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *bi
|
|||
return parentTotalDiff.Cmp(c.TerminalTotalDifficulty) < 0 && totalDiff.Cmp(c.TerminalTotalDifficulty) >= 0
|
||||
}
|
||||
|
||||
// IsValidTxCount returns whether the given block's transaction count is below the limit.
|
||||
func (c *ChainConfig) IsValidTxCount(count int) bool {
|
||||
return c.MaxTxPerBlock == nil || count <= *c.MaxTxPerBlock
|
||||
}
|
||||
|
||||
// CheckCompatible checks whether scheduled fork transitions have been imported
|
||||
// with a mismatching chain configuration.
|
||||
func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError {
|
||||
|
|
|
|||
Loading…
Reference in a new issue