eip-4844: setting header's excess_data_gas, verifiying eip-4844 headers (#7308)

In this PR Header's ExcessDataGas is set to the actual value, but it's
still unused. It will be used to compute data fee for eip-4844 data
blobs, logic of which will be added in later PRs. Also eip-4844 header
verification logic added.
This commit is contained in:
racytech 2023-04-16 14:12:40 +06:00 committed by GitHub
parent 4c8c709408
commit 7aa217f015
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 80 additions and 17 deletions

View File

@ -719,14 +719,13 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx types.Transac
b.pendingState.Prepare(tx.Hash(), libcommon.Hash{}, len(b.pendingBlock.Transactions()))
//fmt.Printf("==== Start producing block %d, header: %d\n", b.pendingBlock.NumberU64(), b.pendingHeader.Number.Uint64())
excessDataGas := b.pendingHeader.ParentExcessDataGas(b.getHeader)
if _, _, err := core.ApplyTransaction(
b.m.ChainConfig, core.GetHashFn(b.pendingHeader, b.getHeader), b.m.Engine,
&b.pendingHeader.Coinbase, b.gasPool,
b.pendingState, state.NewNoopWriter(),
b.pendingHeader, tx,
&b.pendingHeader.GasUsed, vm.Config{},
excessDataGas); err != nil {
b.pendingHeader.ParentExcessDataGas(b.getHeader)); err != nil {
return err
}
//fmt.Printf("==== Start producing block %d\n", (b.prependBlock.NumberU64() + 1))

View File

@ -29,7 +29,7 @@ import (
"time"
"github.com/goccy/go-json"
"github.com/hashicorp/golang-lru/v2"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/ledgerwatch/erigon-lib/chain"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/kv"
@ -40,6 +40,7 @@ import (
"github.com/ledgerwatch/erigon/common/debug"
"github.com/ledgerwatch/erigon/common/hexutil"
"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/consensus/misc"
"github.com/ledgerwatch/erigon/core/state"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/types/accounts"
@ -373,6 +374,13 @@ func (c *Clique) Finalize(config *chain.Config, header *types.Header, state *sta
) (types.Transactions, types.Receipts, error) {
// No block rewards in PoA, so the state remains as is and uncles are dropped
header.UncleHash = types.CalcUncleHash(nil)
if config.IsCancun(header.Time) {
if parent := chain.GetHeaderByHash(header.ParentHash); parent != nil {
header.SetExcessDataGas(misc.CalcExcessDataGas(parent.ExcessDataGas, misc.CountBlobs(txs)))
} else {
header.SetExcessDataGas(new(big.Int))
}
}
return txs, r, nil
}

View File

@ -130,6 +130,14 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainHeaderReader, header
// Verify the header's EIP-1559 attributes.
return err
}
if !chain.Config().IsCancun(header.Time) {
if header.ExcessDataGas != nil {
return fmt.Errorf("invalid excessDataGas before fork: have %v, expected 'nil'", header.ExcessDataGas)
}
} else if err := misc.VerifyEip4844Header(chain.Config(), parent, header); err != nil {
// Verify the header's EIP-4844 attributes.
return err
}
// Retrieve the snapshot needed to verify this header and cache it
snap, err := c.Snapshot(chain, number-1, header.ParentHash, parents)

View File

@ -239,6 +239,14 @@ func VerifyHeaderBasics(chain consensus.ChainHeaderReader, header, parent *types
// Verify the header's EIP-1559 attributes.
return err
}
if !chain.Config().IsCancun(header.Time) {
if header.ExcessDataGas != nil {
return fmt.Errorf("invalid excessDataGas before fork: have %v, expected 'nil'", header.ExcessDataGas)
}
} else if err := misc.VerifyEip4844Header(chain.Config(), parent, header); err != nil {
// Verify the header's EIP-4844 attributes.
return err
}
// Verify that the block number is parent's +1
if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
@ -561,6 +569,13 @@ func (ethash *Ethash) Finalize(config *chain.Config, header *types.Header, state
) (types.Transactions, types.Receipts, error) {
// Accumulate any block and uncle rewards and commit the final state root
accumulateRewards(config, state, header, uncles)
if config.IsCancun(header.Time) {
if parent := chain.GetHeaderByHash(header.ParentHash); parent != nil {
header.SetExcessDataGas(misc.CalcExcessDataGas(parent.ExcessDataGas, misc.CountBlobs(txs)))
} else {
header.SetExcessDataGas(new(big.Int))
}
}
return txs, r, nil
}
@ -602,6 +617,9 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash libcommon.Hash) {
if header.BaseFee != nil {
enc = append(enc, header.BaseFee)
}
if header.ExcessDataGas != nil {
enc = append(enc, header.ExcessDataGas)
}
rlp.Encode(hasher, enc)
hasher.Sum(hash[:0])
return hash

View File

@ -145,6 +145,13 @@ func (s *Serenity) Finalize(config *chain.Config, header *types.Header, state *s
state.AddBalance(w.Address, amountInWei)
}
}
if config.IsCancun(header.Time) {
parent := chain.GetHeaderByHash(header.ParentHash)
if parent == nil {
return nil, nil, fmt.Errorf("Could not find the parent of block %v to get excess data gas", header.Number.Uint64())
}
header.SetExcessDataGas(misc.CalcExcessDataGas(parent.ExcessDataGas, misc.CountBlobs(txs)))
}
return txs, r, nil
}
@ -227,6 +234,15 @@ func (s *Serenity) verifyHeader(chain consensus.ChainHeaderReader, header, paren
if !shanghai && header.WithdrawalsHash != nil {
return consensus.ErrUnexpectedWithdrawals
}
if !chain.Config().IsCancun(header.Time) {
if header.ExcessDataGas != nil {
return fmt.Errorf("invalid excessDataGas before fork: have %v, expected 'nil'", header.ExcessDataGas)
}
} else if err := misc.VerifyEip4844Header(chain.Config(), parent, header); err != nil {
// Verify the header's EIP-4844 attributes.
return err
}
return nil
}

View File

@ -104,7 +104,7 @@ func ExecuteBlockEphemerally(
}
}
if !vmConfig.ReadOnly {
if err := InitializeBlockExecution(engine, chainReader, block.Header(), block.Transactions(), block.Uncles(), chainConfig, ibs, nil); err != nil {
if err := InitializeBlockExecution(engine, chainReader, block.Header(), block.Transactions(), block.Uncles(), chainConfig, ibs, excessDataGas); err != nil {
return nil, err
}
}
@ -165,7 +165,7 @@ func ExecuteBlockEphemerally(
}
if !vmConfig.ReadOnly {
txs := block.Transactions()
if _, _, _, err := FinalizeBlockExecution(engine, stateReader, block.Header(), txs, block.Uncles(), stateWriter, chainConfig, ibs, receipts, block.Withdrawals(), chainReader, false, nil); err != nil {
if _, _, _, err := FinalizeBlockExecution(engine, stateReader, block.Header(), txs, block.Uncles(), stateWriter, chainConfig, ibs, receipts, block.Withdrawals(), chainReader, false, excessDataGas); err != nil {
return nil, err
}
}
@ -215,7 +215,7 @@ func ExecuteBlockEphemerallyBor(
excessDataGas = ph.ExcessDataGas
}
if !vmConfig.ReadOnly {
if err := InitializeBlockExecution(engine, chainReader, block.Header(), block.Transactions(), block.Uncles(), chainConfig, ibs, nil); err != nil {
if err := InitializeBlockExecution(engine, chainReader, block.Header(), block.Transactions(), block.Uncles(), chainConfig, ibs, excessDataGas); err != nil {
return nil, err
}
}
@ -276,7 +276,7 @@ func ExecuteBlockEphemerallyBor(
}
if !vmConfig.ReadOnly {
txs := block.Transactions()
if _, _, _, err := FinalizeBlockExecution(engine, stateReader, block.Header(), txs, block.Uncles(), stateWriter, chainConfig, ibs, receipts, block.Withdrawals(), chainReader, false, nil); err != nil {
if _, _, _, err := FinalizeBlockExecution(engine, stateReader, block.Header(), txs, block.Uncles(), stateWriter, chainConfig, ibs, receipts, block.Withdrawals(), chainReader, false, excessDataGas); err != nil {
return nil, err
}
}

View File

@ -116,9 +116,8 @@ func (b *BlockGen) AddTxWithChain(getHeader func(hash libcommon.Hash, number uin
if b.gasPool == nil {
b.SetCoinbase(libcommon.Address{})
}
excessDataGas := b.parent.ExcessDataGas()
b.ibs.Prepare(tx.Hash(), libcommon.Hash{}, len(b.txs))
receipt, _, err := ApplyTransaction(b.config, GetHashFn(b.header, getHeader), engine, &b.header.Coinbase, b.gasPool, b.ibs, state.NewNoopWriter(), b.header, tx, &b.header.GasUsed, vm.Config{}, excessDataGas)
receipt, _, err := ApplyTransaction(b.config, GetHashFn(b.header, getHeader), engine, &b.header.Coinbase, b.gasPool, b.ibs, state.NewNoopWriter(), b.header, tx, &b.header.GasUsed, vm.Config{}, b.parent.ExcessDataGas())
if err != nil {
panic(err)
}
@ -130,9 +129,8 @@ func (b *BlockGen) AddFailedTxWithChain(getHeader func(hash libcommon.Hash, numb
if b.gasPool == nil {
b.SetCoinbase(libcommon.Address{})
}
excessDataGas := b.parent.ExcessDataGas()
b.ibs.Prepare(tx.Hash(), libcommon.Hash{}, len(b.txs))
receipt, _, err := ApplyTransaction(b.config, GetHashFn(b.header, getHeader), engine, &b.header.Coinbase, b.gasPool, b.ibs, state.NewNoopWriter(), b.header, tx, &b.header.GasUsed, vm.Config{}, excessDataGas)
receipt, _, err := ApplyTransaction(b.config, GetHashFn(b.header, getHeader), engine, &b.header.Coinbase, b.gasPool, b.ibs, state.NewNoopWriter(), b.header, tx, &b.header.GasUsed, vm.Config{}, b.parent.ExcessDataGas())
_ = err // accept failed transactions
b.txs = append(b.txs, tx)
b.receipts = append(b.receipts, receipt)

View File

@ -545,7 +545,7 @@ func GenesisToBlock(g *types.Genesis, tmpDir string) (*types.Block, *state.Intra
}
if len(account.Constructor) > 0 {
if _, err = SysCreate(addr, account.Constructor, *g.Config, statedb, head, nil /*excessDataGas*/); err != nil {
if _, err = SysCreate(addr, account.Constructor, *g.Config, statedb, head, g.ExcessDataGas); err != nil {
return
}
}

View File

@ -172,7 +172,12 @@ func SpawnMiningExecStage(s *StageState, tx kv.RwTx, cfg MiningExecCfg, quit <-c
}
var err error
_, current.Txs, current.Receipts, err = core.FinalizeBlockExecution(cfg.engine, stateReader, current.Header, current.Txs, current.Uncles, stateWriter, &cfg.chainConfig, ibs, current.Receipts, current.Withdrawals, ChainReaderImpl{config: &cfg.chainConfig, tx: tx, blockReader: cfg.blockReader}, true, nil)
parentHeader := getHeader(current.Header.ParentHash, current.Header.Number.Uint64()-1)
var excessDataGas *big.Int
if parentHeader != nil {
excessDataGas = parentHeader.ExcessDataGas
}
_, current.Txs, current.Receipts, err = core.FinalizeBlockExecution(cfg.engine, stateReader, current.Header, current.Txs, current.Uncles, stateWriter, &cfg.chainConfig, ibs, current.Receipts, current.Withdrawals, ChainReaderImpl{config: &cfg.chainConfig, tx: tx, blockReader: cfg.blockReader}, true, excessDataGas)
if err != nil {
return err
}

View File

@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"math/big"
"time"
jsoniter "github.com/json-iterator/go"
@ -25,6 +26,7 @@ import (
"github.com/ledgerwatch/erigon/eth/tracers/logger"
"github.com/ledgerwatch/erigon/turbo/rpchelper"
"github.com/ledgerwatch/erigon/turbo/services"
"github.com/ledgerwatch/log/v3"
)
type BlockGetter interface {
@ -53,7 +55,16 @@ func ComputeTxEnv(ctx context.Context, engine consensus.EngineReader, block *typ
return h
}
header := block.HeaderNoCopy()
BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil, nil /*excessDataGas*/)
parentHeader, err := headerReader.HeaderByHash(ctx, dbtx, header.ParentHash)
if err != nil {
// TODO(eip-4844): Do we need to propagate this error?
log.Error("Can't get parent block's header:", err)
}
var excessDataGas *big.Int
if parentHeader != nil {
excessDataGas = parentHeader.ExcessDataGas
}
BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil, excessDataGas)
// Recompute transactions up to the target index.
signer := types.MakeSigner(cfg, block.NumberU64())
@ -64,7 +75,7 @@ func ComputeTxEnv(ctx context.Context, engine consensus.EngineReader, block *typ
msg, _ := txn.AsMessage(*signer, block.BaseFee(), rules)
if msg.FeeCap().IsZero() && engine != nil {
syscall := func(contract libcommon.Address, data []byte) ([]byte, error) {
return core.SysCallContract(contract, data, *cfg, statedb, header, engine, true /* constCall */, nil /*excessDataGas*/)
return core.SysCallContract(contract, data, *cfg, statedb, header, engine, true /* constCall */, excessDataGas)
}
msg.SetIsFree(engine.IsServiceTransaction(msg.From(), syscall))
}
@ -77,7 +88,7 @@ func ComputeTxEnv(ctx context.Context, engine consensus.EngineReader, block *typ
consensusHeaderReader := stagedsync.NewChainReaderImpl(cfg, dbtx, nil)
core.InitializeBlockExecution(engine.(consensus.Engine), consensusHeaderReader, header, block.Transactions(), block.Uncles(), cfg, statedb, nil)
core.InitializeBlockExecution(engine.(consensus.Engine), consensusHeaderReader, header, block.Transactions(), block.Uncles(), cfg, statedb, excessDataGas)
for idx, txn := range block.Transactions() {
select {
@ -91,7 +102,7 @@ func ComputeTxEnv(ctx context.Context, engine consensus.EngineReader, block *typ
msg, _ := txn.AsMessage(*signer, block.BaseFee(), rules)
if msg.FeeCap().IsZero() && engine != nil {
syscall := func(contract libcommon.Address, data []byte) ([]byte, error) {
return core.SysCallContract(contract, data, *cfg, statedb, header, engine, true /* constCall */, nil /*excessDataGas*/)
return core.SysCallContract(contract, data, *cfg, statedb, header, engine, true /* constCall */, excessDataGas)
}
msg.SetIsFree(engine.IsServiceTransaction(msg.From(), syscall))
}