mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-07 23:48:36 +00:00
core: implement EIP-8254: Cap deposit requests per block
This commit is contained in:
parent
aaa2b66285
commit
94f55e5575
6 changed files with 89 additions and 19 deletions
|
|
@ -339,7 +339,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
for _, receipt := range receipts {
|
for _, receipt := range receipts {
|
||||||
allLogs = append(allLogs, receipt.Logs...)
|
allLogs = append(allLogs, receipt.Logs...)
|
||||||
}
|
}
|
||||||
if err := core.ParseDepositLogs(&requests, allLogs, chainConfig); err != nil {
|
if err := core.ParseDepositLogs(&requests, allLogs, chainConfig, vmContext.BlockNumber, vmContext.Time); err != nil {
|
||||||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
|
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
|
||||||
}
|
}
|
||||||
// EIP-7002
|
// EIP-7002
|
||||||
|
|
|
||||||
|
|
@ -322,7 +322,7 @@ func (b *BlockGen) collectRequests(readonly bool) (requests [][]byte) {
|
||||||
for _, r := range b.receipts {
|
for _, r := range b.receipts {
|
||||||
blockLogs = append(blockLogs, r.Logs...)
|
blockLogs = append(blockLogs, r.Logs...)
|
||||||
}
|
}
|
||||||
if err := ParseDepositLogs(&requests, blockLogs, b.cm.config); err != nil {
|
if err := ParseDepositLogs(&requests, blockLogs, b.cm.config, b.header.Number, b.header.Time); err != nil {
|
||||||
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
|
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
|
||||||
}
|
}
|
||||||
// create EVM for system calls
|
// create EVM for system calls
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ func postExecution(ctx context.Context, config *params.ChainConfig, block *types
|
||||||
if config.IsPrague(block.Number(), block.Time()) {
|
if config.IsPrague(block.Number(), block.Time()) {
|
||||||
requests = [][]byte{}
|
requests = [][]byte{}
|
||||||
// EIP-6110
|
// EIP-6110
|
||||||
if err := ParseDepositLogs(&requests, allLogs, config); err != nil {
|
if err := ParseDepositLogs(&requests, allLogs, config, block.Number(), block.Time()); err != nil {
|
||||||
return requests, fmt.Errorf("failed to parse deposit logs: %w", err)
|
return requests, fmt.Errorf("failed to parse deposit logs: %w", err)
|
||||||
}
|
}
|
||||||
// EIP-7002
|
// EIP-7002
|
||||||
|
|
@ -347,21 +347,47 @@ func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var depositTopic = common.HexToHash("0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5")
|
// DepositTopic is the topic hash of the EIP-6110 DepositEvent.
|
||||||
|
var DepositTopic = common.HexToHash("0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5")
|
||||||
|
|
||||||
|
// IsDepositLog reports whether the log is an EIP-6110 deposit event emitted
|
||||||
|
// by the given deposit contract address.
|
||||||
|
func IsDepositLog(log *types.Log, depositContract common.Address) bool {
|
||||||
|
return log.Address == depositContract && len(log.Topics) > 0 && log.Topics[0] == DepositTopic
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountDepositLogs returns the number of EIP-6110 deposit events present in
|
||||||
|
// the given logs.
|
||||||
|
func CountDepositLogs(logs []*types.Log, depositContract common.Address) int {
|
||||||
|
count := 0
|
||||||
|
for _, log := range logs {
|
||||||
|
if IsDepositLog(log, depositContract) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
|
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
|
||||||
// BeaconDepositContract.
|
// BeaconDepositContract. From the Amsterdam fork onwards the number of
|
||||||
func ParseDepositLogs(requests *[][]byte, logs []*types.Log, config *params.ChainConfig) error {
|
// deposits per block is capped to params.MaxDepositRequestsPerBlock by
|
||||||
|
// EIP-8254.
|
||||||
|
func ParseDepositLogs(requests *[][]byte, logs []*types.Log, config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) error {
|
||||||
deposits := make([]byte, 1) // note: first byte is 0x00 (== deposit request type)
|
deposits := make([]byte, 1) // note: first byte is 0x00 (== deposit request type)
|
||||||
|
count := 0
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
if log.Address == config.DepositContractAddress && len(log.Topics) > 0 && log.Topics[0] == depositTopic {
|
if IsDepositLog(log, config.DepositContractAddress) {
|
||||||
request, err := types.DepositLogToRequest(log.Data)
|
request, err := types.DepositLogToRequest(log.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to parse deposit data: %v", err)
|
return fmt.Errorf("unable to parse deposit data: %v", err)
|
||||||
}
|
}
|
||||||
deposits = append(deposits, request...)
|
deposits = append(deposits, request...)
|
||||||
|
count++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if config.IsAmsterdam(blockNumber, blockTime) && count > params.MaxDepositRequestsPerBlock {
|
||||||
|
return fmt.Errorf("too many deposit requests in block: have %d, max %d", count, params.MaxDepositRequestsPerBlock)
|
||||||
|
}
|
||||||
if len(deposits) > 1 {
|
if len(deposits) > 1 {
|
||||||
*requests = append(*requests, deposits)
|
*requests = append(*requests, deposits)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -398,7 +398,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
if sim.chainConfig.IsPrague(header.Number, header.Time) {
|
if sim.chainConfig.IsPrague(header.Number, header.Time) {
|
||||||
requests = [][]byte{}
|
requests = [][]byte{}
|
||||||
// EIP-6110
|
// EIP-6110
|
||||||
if err := core.ParseDepositLogs(&requests, allLogs, sim.chainConfig); err != nil {
|
if err := core.ParseDepositLogs(&requests, allLogs, sim.chainConfig, header.Number, header.Time); err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
// EIP-7002
|
// EIP-7002
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@ var (
|
||||||
errBlockInterruptedByNewHead = errors.New("new head arrived while building block")
|
errBlockInterruptedByNewHead = errors.New("new head arrived while building block")
|
||||||
errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block")
|
errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block")
|
||||||
errBlockInterruptedByTimeout = errors.New("timeout while building block")
|
errBlockInterruptedByTimeout = errors.New("timeout while building block")
|
||||||
|
|
||||||
|
// errDepositCapExceeded is returned when including a transaction would
|
||||||
|
// push the block over the EIP-8254 deposit-request cap.
|
||||||
|
errDepositCapExceeded = errors.New("deposit request cap exceeded")
|
||||||
)
|
)
|
||||||
|
|
||||||
// maxBlobsPerBlock returns the maximum number of blobs per block.
|
// maxBlobsPerBlock returns the maximum number of blobs per block.
|
||||||
|
|
@ -66,11 +70,12 @@ type environment struct {
|
||||||
coinbase common.Address
|
coinbase common.Address
|
||||||
evm *vm.EVM
|
evm *vm.EVM
|
||||||
|
|
||||||
header *types.Header
|
header *types.Header
|
||||||
txs []*types.Transaction
|
txs []*types.Transaction
|
||||||
receipts []*types.Receipt
|
receipts []*types.Receipt
|
||||||
sidecars []*types.BlobTxSidecar
|
sidecars []*types.BlobTxSidecar
|
||||||
blobs int
|
blobs int
|
||||||
|
depositRequests int // running count of EIP-6110 deposit requests, capped by EIP-8254
|
||||||
|
|
||||||
witness *stateless.Witness
|
witness *stateless.Witness
|
||||||
}
|
}
|
||||||
|
|
@ -212,7 +217,7 @@ func (miner *Miner) generateWork(ctx context.Context, genParam *generateParams,
|
||||||
if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) {
|
if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) {
|
||||||
requests = [][]byte{}
|
requests = [][]byte{}
|
||||||
// EIP-6110 deposits
|
// EIP-6110 deposits
|
||||||
if err := core.ParseDepositLogs(&requests, allLogs, miner.chainConfig); err != nil {
|
if err := core.ParseDepositLogs(&requests, allLogs, miner.chainConfig, work.header.Number, work.header.Time); err != nil {
|
||||||
return &newPayloadResult{err: err}
|
return &newPayloadResult{err: err}
|
||||||
}
|
}
|
||||||
// EIP-7002
|
// EIP-7002
|
||||||
|
|
@ -372,10 +377,13 @@ func (miner *Miner) commitTransaction(ctx context.Context, env *environment, tx
|
||||||
if tx.Type() == types.BlobTxType {
|
if tx.Type() == types.BlobTxType {
|
||||||
return miner.commitBlobTransaction(env, tx)
|
return miner.commitBlobTransaction(env, tx)
|
||||||
}
|
}
|
||||||
receipt, err := miner.applyTransaction(env, tx)
|
receipt, snap, gp, err := miner.applyTransaction(env, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := miner.checkDepositCap(env, receipt, snap, gp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
env.txs = append(env.txs, tx)
|
env.txs = append(env.txs, tx)
|
||||||
env.receipts = append(env.receipts, receipt)
|
env.receipts = append(env.receipts, receipt)
|
||||||
env.size += tx.Size()
|
env.size += tx.Size()
|
||||||
|
|
@ -396,10 +404,13 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio
|
||||||
if env.blobs+len(sc.Blobs) > maxBlobs {
|
if env.blobs+len(sc.Blobs) > maxBlobs {
|
||||||
return errors.New("max data blobs reached")
|
return errors.New("max data blobs reached")
|
||||||
}
|
}
|
||||||
receipt, err := miner.applyTransaction(env, tx)
|
receipt, snap, gp, err := miner.applyTransaction(env, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := miner.checkDepositCap(env, receipt, snap, gp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
txNoBlob := tx.WithoutBlobTxSidecar()
|
txNoBlob := tx.WithoutBlobTxSidecar()
|
||||||
env.txs = append(env.txs, txNoBlob)
|
env.txs = append(env.txs, txNoBlob)
|
||||||
env.receipts = append(env.receipts, receipt)
|
env.receipts = append(env.receipts, receipt)
|
||||||
|
|
@ -412,7 +423,9 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyTransaction runs the transaction. If execution fails, state and gas pool are reverted.
|
// applyTransaction runs the transaction. If execution fails, state and gas pool are reverted.
|
||||||
func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*types.Receipt, error) {
|
// On success the pre-execution snapshot/gas-pool checkpoint are returned so the
|
||||||
|
// caller can revert if a post-execution constraint (e.g. EIP-8254 deposit cap) fails.
|
||||||
|
func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*types.Receipt, int, *core.GasPool, error) {
|
||||||
var (
|
var (
|
||||||
snap = env.state.Snapshot()
|
snap = env.state.Snapshot()
|
||||||
gp = env.gasPool.Snapshot()
|
gp = env.gasPool.Snapshot()
|
||||||
|
|
@ -421,10 +434,32 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*
|
||||||
if err != nil {
|
if err != nil {
|
||||||
env.state.RevertToSnapshot(snap)
|
env.state.RevertToSnapshot(snap)
|
||||||
env.gasPool.Set(gp)
|
env.gasPool.Set(gp)
|
||||||
return nil, err
|
return nil, 0, nil, err
|
||||||
}
|
}
|
||||||
env.header.GasUsed = env.gasPool.Used()
|
env.header.GasUsed = env.gasPool.Used()
|
||||||
return receipt, nil
|
return receipt, snap, gp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkDepositCap enforces the EIP-8254 cap on deposit requests per block.
|
||||||
|
// If including the receipt would push the running deposit count over
|
||||||
|
// params.MaxDepositRequestsPerBlock, the state and gas pool are reverted to
|
||||||
|
// the pre-execution checkpoint and errDepositCapExceeded is returned.
|
||||||
|
func (miner *Miner) checkDepositCap(env *environment, receipt *types.Receipt, snap int, gp *core.GasPool) error {
|
||||||
|
if !miner.chainConfig.IsAmsterdam(env.header.Number, env.header.Time) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
added := core.CountDepositLogs(receipt.Logs, miner.chainConfig.DepositContractAddress)
|
||||||
|
if added == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if env.depositRequests+added > params.MaxDepositRequestsPerBlock {
|
||||||
|
env.state.RevertToSnapshot(snap)
|
||||||
|
env.gasPool.Set(gp)
|
||||||
|
env.header.GasUsed = env.gasPool.Used()
|
||||||
|
return errDepositCapExceeded
|
||||||
|
}
|
||||||
|
env.depositRequests += added
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (miner *Miner) commitTransactions(ctx context.Context, env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
func (miner *Miner) commitTransactions(ctx context.Context, env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
||||||
|
|
@ -522,6 +557,13 @@ func (miner *Miner) commitTransactions(ctx context.Context, env *environment, pl
|
||||||
|
|
||||||
err := miner.commitTransaction(ctx, env, tx)
|
err := miner.commitTransaction(ctx, env, tx)
|
||||||
switch {
|
switch {
|
||||||
|
case errors.Is(err, errDepositCapExceeded):
|
||||||
|
// EIP-8254: including this tx would push the block past the
|
||||||
|
// deposit-request cap. Skip this sender; subsequent senders may
|
||||||
|
// still produce non-deposit-bearing transactions that fit.
|
||||||
|
log.Trace("Skipping tx that would exceed deposit-request cap", "hash", ltx.Hash, "sender", from)
|
||||||
|
txs.Pop()
|
||||||
|
|
||||||
case errors.Is(err, core.ErrNonceTooLow):
|
case errors.Is(err, core.ErrNonceTooLow):
|
||||||
// New head notification data race between the transaction pool and miner, shift
|
// New head notification data race between the transaction pool and miner, shift
|
||||||
log.Trace("Skipping transaction with low nonce", "hash", ltx.Hash, "sender", from, "nonce", tx.Nonce())
|
log.Trace("Skipping transaction with low nonce", "hash", ltx.Hash, "sender", from, "nonce", tx.Nonce())
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,8 @@ const (
|
||||||
HistoryServeWindow = 8191 // Number of blocks to serve historical block hashes for, EIP-2935.
|
HistoryServeWindow = 8191 // Number of blocks to serve historical block hashes for, EIP-2935.
|
||||||
|
|
||||||
MaxBlockSize = 8_388_608 // maximum size of an RLP-encoded block
|
MaxBlockSize = 8_388_608 // maximum size of an RLP-encoded block
|
||||||
|
|
||||||
|
MaxDepositRequestsPerBlock = 8192 // Maximum number of EIP-6110 deposit requests per block, EIP-8254.
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bls12381G1MultiExpDiscountTable is the gas discount table for BLS12-381 G1 multi exponentiation operation
|
// Bls12381G1MultiExpDiscountTable is the gas discount table for BLS12-381 G1 multi exponentiation operation
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue