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

Block size limit #2174

Merged
merged 8 commits into from
Aug 17, 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
7 changes: 7 additions & 0 deletions consensus/istanbul/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,13 @@ func (sb *Backend) Verify(proposal istanbul.Proposal) (*istanbulCore.StateProces
}
}

if sb.chain.Config().IsGingerbreadP2(block.Number()) {
if err := core.ValidateBlockSize(block, params.MaxTxDataPerBlock); err != nil {
sb.logger.Error("verify - Error in validating txs block size", "err", err)
return nil, 0, err
}
}

// Apply this block's transactions to update the state
receipts, logs, usedGas, err := sb.processBlock(block, state)
if err != nil {
Expand Down
16 changes: 16 additions & 0 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
}
return consensus.ErrPrunedAncestor
}
if v.config.IsGingerbreadP2(block.Number()) {
if err := ValidateBlockSize(block, params.MaxTxDataPerBlock); err != nil {
return err
}
}
return nil
}

func ValidateBlockSize(block *types.Block, blockSize uint64) error {
bytesBlock := new(BytesBlock).SetLimit(blockSize)

for _, tx := range block.Transactions() {
if err := bytesBlock.SubBytes(uint64(tx.Size())); err != nil {
return err
}
}
return nil
}

Expand Down
38 changes: 38 additions & 0 deletions core/bytesblock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package core

import (
"fmt"
"math"
)

// BytesBlock tracks the amount of bytes available during execution of the transactions
// in a block. The zero value is a block with zero bytes available.
type BytesBlock uint64

// SetLimit makes bytes available to use.
func (bp *BytesBlock) SetLimit(amount uint64) *BytesBlock {
if uint64(*bp) > math.MaxUint64-amount {
panic("block's bytes pushed above uint64")
}
*(*uint64)(bp) += amount
return bp
}

// SubBytes deducts the given amount from the block if enough bytes are
// available and returns an error otherwise.
func (bp *BytesBlock) SubBytes(amount uint64) error {
if uint64(*bp) < amount {
return ErrBytesLimitReached
}
*(*uint64)(bp) -= amount
return nil
}

// BytesLeft returns the amount of gas remaining in the pool.
func (bp *BytesBlock) BytesLeft() uint64 {
return uint64(*bp)
}

func (bp *BytesBlock) String() string {
return fmt.Sprintf("%d", *bp)
}
4 changes: 4 additions & 0 deletions core/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ var (
// by a transaction is higher than what's left in the block.
ErrGasLimitReached = errors.New("gas limit reached")

// ErrBytesLimitReached is returned if the amount of bytes required
// by a transaction is higher than what's left in the block.
ErrBytesLimitReached = errors.New("block's bytes limit reached")

// ErrInsufficientFundsForTransfer is returned if the transaction sender doesn't
// have enough funds for transfer(topmost call only).
// Note that the check for this is done after buying the gas.
Expand Down
11 changes: 11 additions & 0 deletions core/state_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,13 @@ func TestStateProcessorErrors(t *testing.T) {
},
want: "could not apply tx 0 [0xd82a0c2519acfeac9a948258c47e784acd20651d9d80f9a1c67b4137651c3a24]: insufficient funds for gas * price + value + gatewayFee: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 2431633873983640103894990685182446064918669677978451844828609264166175722438635000",
},
{
name: "ErrBytesLimitReached",
txs: []*types.Transaction{
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas+params.TxDataZeroGas*params.MaxTxDataPerBlock, big.NewInt(875000000), nil, nil, nil, getBigData(int(params.MaxTxDataPerBlock))),
},
want: ErrBytesLimitReached.Error(),
},
} {
block := GenerateBadBlock(genesis, mockEngine.NewFaker(), tt.txs, gspec.Config)
_, err := blockchain.InsertChain(types.Blocks{block})
Expand Down Expand Up @@ -348,8 +355,12 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
receipts = append(receipts, receipt)
cumulativeGas += tx.Gas()
}
header.GasUsed = cumulativeGas
header.Root = common.BytesToHash(hasher.Sum(nil))
// Assemble and return the final block for sealing
return types.NewBlock(header, txs, receipts, nil, trie.NewStackTrie(nil))
}

func getBigData(length int) []byte {
return make([]byte, length)
}
27 changes: 22 additions & 5 deletions miner/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ import (
type blockState struct {
signer types.Signer

state *state.StateDB // apply state changes here
tcount int // tx count in cycle
gasPool *core.GasPool // available gas used to pack transactions
gasLimit uint64
sysCtx *core.SysContractCallCtx
state *state.StateDB // apply state changes here
tcount int // tx count in cycle
gasPool *core.GasPool // available gas used to pack transactions
bytesBlock *core.BytesBlock // available bytes used to pack transactions
gasLimit uint64
sysCtx *core.SysContractCallCtx

header *types.Header
txs []*types.Transaction
Expand Down Expand Up @@ -121,6 +122,9 @@ func prepareBlock(w *worker) (*blockState, error) {
parentVmRunner := w.chain.NewEVMRunner(parent.Header(), state.Copy())
header.BaseFee = misc.CalcBaseFee(w.chainConfig, parent.Header(), parentVmRunner)
}
if w.chainConfig.IsGingerbreadP2(header.Number) {
b.bytesBlock = new(core.BytesBlock).SetLimit(params.MaxTxDataPerBlock)
}
b.sysCtx = core.NewSysContractCallCtx(header, state.Copy(), w.chain)

// Play our part in generating the random beacon.
Expand Down Expand Up @@ -255,6 +259,12 @@ loop:
txs.Pop()
continue
}
// Same short-circuit of the gas above, but for bytes in the block (b.bytesBlock != nil => GingerbreadP2)
if b.bytesBlock != nil && b.bytesBlock.BytesLeft() < uint64(tx.Size()) {
log.Trace("Skipping transaction which requires more bytes than is left in the block", "hash", tx.Hash(), "bytes", b.bytesBlock.BytesLeft(), "txbytes", uint64(tx.Size()))
txs.Pop()
continue
}
// Error may be ignored here. The error has already been checked
// during transaction acceptance is the transaction pool.
//
Expand Down Expand Up @@ -298,6 +308,13 @@ loop:
// Everything ok, collect the logs and shift in the next transaction from the same account
coalescedLogs = append(coalescedLogs, logs...)
b.tcount++
// bytesBlock != nil => GingerbreadP2
if b.bytesBlock != nil {
if err := b.bytesBlock.SubBytes(uint64(tx.Size())); err != nil {
// This should never happen because we are validating before that we have enough space
return err
}
}
txs.Shift()

default:
Expand Down
3 changes: 2 additions & 1 deletion params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ const (
ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have.
InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks.

MaxCodeSize = 65536 // Maximum bytecode to permit for a contract (2^16)
MaxCodeSize = 65536 // Maximum bytecode to permit for a contract (2^16)
MaxTxDataPerBlock uint64 = 1024 * 1024 * 5 // Maximum size of all the rlp encoded transactions of a block (5mb) [Gingerbread]

// Precompiled contract gas prices

Expand Down