Skip to content

Commit

Permalink
Block size limit (#2174)
Browse files Browse the repository at this point in the history
* Block Size Limit (5mb, gingerbreadP2)
  • Loading branch information
gastonponti committed Aug 22, 2023
1 parent b48d271 commit d27c2ad
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 6 deletions.
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

0 comments on commit d27c2ad

Please sign in to comment.