Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add BlockTxCount limit and BlockPayloadSize limit #584

Merged
merged 9 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading