diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index e3aad2273f5..13f107d6120 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -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)) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index db56c94e118..19dd62b6f4c 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -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 } diff --git a/consensus/clique/verifier.go b/consensus/clique/verifier.go index 3a629a73de1..eb70b2b63ec 100644 --- a/consensus/clique/verifier.go +++ b/consensus/clique/verifier.go @@ -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) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 356256f9b02..2a6321dc608 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -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 diff --git a/consensus/serenity/serenity.go b/consensus/serenity/serenity.go index 8575abe5aa8..788939c6706 100644 --- a/consensus/serenity/serenity.go +++ b/consensus/serenity/serenity.go @@ -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 } diff --git a/core/blockchain.go b/core/blockchain.go index b6174c9c078..136fa82355e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -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 } } diff --git a/core/chain_makers.go b/core/chain_makers.go index b8069078055..959f78073d1 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -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) diff --git a/core/genesis_write.go b/core/genesis_write.go index 36e29e1cc44..838102f6fcd 100644 --- a/core/genesis_write.go +++ b/core/genesis_write.go @@ -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 } } diff --git a/eth/stagedsync/stage_mining_exec.go b/eth/stagedsync/stage_mining_exec.go index dadf967835f..a5525ad4135 100644 --- a/eth/stagedsync/stage_mining_exec.go +++ b/eth/stagedsync/stage_mining_exec.go @@ -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 } diff --git a/turbo/transactions/tracing.go b/turbo/transactions/tracing.go index 2f3e416f792..a1ac24d56a6 100644 --- a/turbo/transactions/tracing.go +++ b/turbo/transactions/tracing.go @@ -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)) }