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
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
@@ -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
@@ -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.
3 changes: 3 additions & 0 deletions core/error.go
Original file line number Diff line number Diff line change
@@ -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")

12 changes: 12 additions & 0 deletions core/types/block.go
Original file line number Diff line number Diff line change
@@ -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 {
20 changes: 20 additions & 0 deletions miner/worker.go
Original file line number Diff line number Diff line change
@@ -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

@@ -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
}

@@ -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)
@@ -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.
22 changes: 22 additions & 0 deletions params/config.go
Original file line number Diff line number Diff line change
@@ -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.
5 changes: 5 additions & 0 deletions rollup/rcfg/config.go
Original file line number Diff line number Diff line change
@@ -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