Skip to content

Commit

Permalink
feat: add BlockTxCount limit and BlockPayloadSize limit (#584)
Browse files Browse the repository at this point in the history
* update consensus/errors.go

* update core/error.go

* update core/types/block.go

* update rollup/rcfg/config.go

* update params/config.go

* update core/block_validator.go

* fix

* update miner/worker.go

* fix
  • Loading branch information
0xmountaintop authored Nov 28, 2023
1 parent c70a901 commit b639349
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 0 deletions.
3 changes: 3 additions & 0 deletions consensus/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,7 @@ var (
// ErrInvalidTerminalBlock is returned if a block is invalid wrt. the terminal
// total difficulty.
ErrInvalidTerminalBlock = errors.New("invalid terminal block")

// ErrInvalidTxCount is returned if a block contains too many transactions.
ErrInvalidTxCount = errors.New("invalid transaction count")
)
8 changes: 8 additions & 0 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
return ErrKnownBlock
}
// Check if block tx count is is smaller than the max count
if !v.config.Scroll.IsValidTxCount(len(block.Transactions())) {
return consensus.ErrInvalidTxCount
}
// Check if block payload size is smaller than the max size
if !v.config.Scroll.IsValidBlockSize(block.PayloadSize()) {
return ErrInvalidBlockPayloadSize
}

// Header validity is known at this point. Here we verify that uncles, transactions
// and withdrawals given in the block body match the header.
Expand Down
3 changes: 3 additions & 0 deletions core/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ var (
// ErrKnownBlock is returned when a block to import is already known locally.
ErrKnownBlock = errors.New("block already known")

// ErrInvalidBlockPayloadSize is returned when a block to import has an oversized payload.
ErrInvalidBlockPayloadSize = errors.New("invalid block payload size")

// ErrBannedHash is returned if a block to import is on the banned list.
ErrBannedHash = errors.New("banned hash")

Expand Down
12 changes: 12 additions & 0 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,18 @@ func (b *Block) Size() uint64 {
return uint64(c)
}

// PayloadSize returns the encoded storage size sum of all transactions in a block.
func (b *Block) PayloadSize() uint64 {
// add up all txs sizes
var totalSize uint64
for _, tx := range b.transactions {
if !tx.IsL1MessageTx() {
totalSize += tx.Size()
}
}
return totalSize
}

// SanityCheck can be used to prevent that unbounded fields are
// stuffed with junk data to add processing overhead
func (b *Block) SanityCheck() error {
Expand Down
20 changes: 20 additions & 0 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type environment struct {
signer types.Signer
state *state.StateDB // apply state changes here
tcount int // tx count in cycle
blockSize uint64 // approximate size of tx payload in bytes
gasPool *core.GasPool // available gas used to pack transactions
coinbase common.Address

Expand Down Expand Up @@ -722,6 +723,7 @@ func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase co
}
// Keep track of transactions which return errors so they can be removed
env.tcount = 0
env.blockSize = 0
return env, nil
}

Expand Down Expand Up @@ -834,6 +836,18 @@ func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAn
txs.Pop()
continue
}
// If we have collected enough transactions then we're done
// Originally we only limit l2txs count, but now strictly limit total txs number.
// log.Info("w.chainConfig", "w.chainConfig.Scroll", w.chainConfig.Scroll)
if !w.chainConfig.Scroll.IsValidTxCount(env.tcount + 1) {
log.Trace("Transaction count limit reached", "have", env.tcount, "want", w.chainConfig.Scroll.MaxTxPerBlock)
break
}
if !tx.IsL1MessageTx() && !w.chainConfig.Scroll.IsValidBlockSize(env.blockSize+tx.Size()) {
log.Trace("Block size limit reached", "have", env.blockSize, "want", w.chainConfig.Scroll.MaxTxPayloadBytesPerBlock, "tx", tx.Size())
txs.Pop() // skip transactions from this account
continue
}
// Error may be ignored here. The error has already been checked
// during transaction acceptance is the transaction pool.
from, _ := types.Sender(env.signer, tx)
Expand Down Expand Up @@ -861,6 +875,12 @@ func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAn
env.tcount++
txs.Shift()

if tx.IsL1MessageTx() {
} else {
// only consider block size limit for L2 transactions
env.blockSize += tx.Size()
}

default:
// Transaction is regarded as invalid, drop all consecutive transactions from
// the same sender because of `nonce-too-high` clause.
Expand Down
22 changes: 22 additions & 0 deletions params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,28 @@ type ChainConfig struct {
Ethash *EthashConfig `json:"ethash,omitempty"`
Clique *CliqueConfig `json:"clique,omitempty"`
IsDevMode bool `json:"isDev,omitempty"`

// Scroll genesis extension: enable scroll rollup-related traces & state transition
Scroll ScrollConfig `json:"scroll,omitempty"`
}

type ScrollConfig struct {
// Maximum number of transactions per block [optional]
MaxTxPerBlock *int `json:"maxTxPerBlock,omitempty"`

// Maximum tx payload size of blocks that we produce [optional]
MaxTxPayloadBytesPerBlock *int `json:"maxTxPayloadBytesPerBlock,omitempty"`
}

// IsValidTxCount returns whether the given block's transaction count is below the limit.
// This limit corresponds to the number of ECDSA signature checks that we can fit into the zkEVM.
func (s ScrollConfig) IsValidTxCount(count int) bool {
return s.MaxTxPerBlock == nil || count <= *s.MaxTxPerBlock
}

// IsValidBlockSize returns whether the given block's transaction payload size is below the limit.
func (s ScrollConfig) IsValidBlockSize(size uint64) bool {
return s.MaxTxPayloadBytesPerBlock == nil || size <= uint64(*s.MaxTxPayloadBytesPerBlock)
}

// EthashConfig is the consensus engine configs for proof-of-work based sealing.
Expand Down
5 changes: 5 additions & 0 deletions rollup/rcfg/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import (
// TODO:
// verify in consensus layer when decentralizing sequencer

var (
ScrollMaxTxPerBlock = 100
ScrollMaxTxPayloadBytesPerBlock = 120 * 1024
)

var (
// L2MessageQueueAddress is the address of the L2MessageQueue
// predeploy
Expand Down

0 comments on commit b639349

Please sign in to comment.