mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 02:40:45 +00:00
a bunch of changes. mostly bal persistence and removing bal from block body object. wip...
This commit is contained in:
parent
7036b1cb39
commit
3435849244
18 changed files with 158 additions and 84 deletions
|
|
@ -307,11 +307,7 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
|
||||||
|
|
||||||
var blockAccessListHash *common.Hash
|
var blockAccessListHash *common.Hash
|
||||||
body := types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}
|
body := types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}
|
||||||
if data.BlockAccessList != nil {
|
|
||||||
body.AccessList = data.BlockAccessList
|
|
||||||
balHash := data.BlockAccessList.Hash()
|
|
||||||
blockAccessListHash = &balHash
|
|
||||||
}
|
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
ParentHash: data.ParentHash,
|
ParentHash: data.ParentHash,
|
||||||
UncleHash: types.EmptyUncleHash,
|
UncleHash: types.EmptyUncleHash,
|
||||||
|
|
@ -336,7 +332,16 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
|
||||||
BlockAccessListHash: blockAccessListHash,
|
BlockAccessListHash: blockAccessListHash,
|
||||||
SlotNumber: data.SlotNumber,
|
SlotNumber: data.SlotNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if data.BlockAccessList != nil {
|
||||||
|
balHash := data.BlockAccessList.Hash()
|
||||||
|
header.BlockAccessListHash = &balHash
|
||||||
|
block := types.NewBlockWithHeader(header).WithBody(body).WithAccessList(data.BlockAccessList)
|
||||||
|
return block, nil
|
||||||
|
}
|
||||||
|
|
||||||
return types.NewBlockWithHeader(header).WithBody(body), nil
|
return types.NewBlockWithHeader(header).WithBody(body), nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockToExecutableData constructs the ExecutableData structure by filling the
|
// BlockToExecutableData constructs the ExecutableData structure by filling the
|
||||||
|
|
@ -360,6 +365,10 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
|
||||||
Withdrawals: block.Withdrawals(),
|
Withdrawals: block.Withdrawals(),
|
||||||
BlobGasUsed: block.BlobGasUsed(),
|
BlobGasUsed: block.BlobGasUsed(),
|
||||||
ExcessBlobGas: block.ExcessBlobGas(),
|
ExcessBlobGas: block.ExcessBlobGas(),
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
BlockAccessList: block.AccessList(),
|
||||||
|
>>>>>>> 959ade7689 (a bunch of changes. mostly bal persistence and removing bal from block body object. wip...)
|
||||||
SlotNumber: block.SlotNumber(),
|
SlotNumber: block.SlotNumber(),
|
||||||
BlockAccessList: block.Body().AccessList,
|
BlockAccessList: block.Body().AccessList,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
# https://github.com/ethereum/execution-spec-tests/releases/download/v5.1.0
|
# https://github.com/ethereum/execution-spec-tests/releases/download/v5.1.0
|
||||||
a3192784375acec7eaec492799d5c5d0c47a2909a3cc40178898e4ecd20cc416 fixtures_develop.tar.gz
|
a3192784375acec7eaec492799d5c5d0c47a2909a3cc40178898e4ecd20cc416 fixtures_develop.tar.gz
|
||||||
|
|
||||||
# version:spec-tests-bal v3.0.1
|
# version:spec-tests-bal v5.0.0
|
||||||
# https://github.com/ethereum/execution-spec-tests/releases
|
# https://github.com/ethereum/execution-spec-tests/releases
|
||||||
# https://github.com/ethereum/execution-spec-tests/releases/download/bal%40v3.0.1
|
# https://github.com/ethereum/execution-spec-tests/releases/download/bal%40v5.0.0
|
||||||
57d0f109f0557ec33d6ecd6cbd77b55415a658aefe583c4035157e1021ae512a fixtures_bal.tar.gz
|
17aecf8334da7f5d1025635c763a4be0dfbcdb0e659cc70a36e6a81bd3af06f2 fixtures_bal.tar.gz
|
||||||
|
|
||||||
# version:golang 1.25.1
|
# version:golang 1.25.1
|
||||||
# https://go.dev/dl/
|
# https://go.dev/dl/
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package beacon
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -357,9 +358,9 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
|
||||||
|
|
||||||
// FinalizeAndAssemble implements consensus.Engine, setting the final state and
|
// FinalizeAndAssemble implements consensus.Engine, setting the final state and
|
||||||
// assembling the block.
|
// assembling the block.
|
||||||
func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalization func()) (*types.Block, error) {
|
func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalizeAccessList func() *bal.BlockAccessList) (*types.Block, error) {
|
||||||
if !beacon.IsPoSHeader(header) {
|
if !beacon.IsPoSHeader(header) {
|
||||||
return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts, onFinalization)
|
return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts, nil)
|
||||||
}
|
}
|
||||||
shanghai := chain.Config().IsShanghai(header.Number, header.Time)
|
shanghai := chain.Config().IsShanghai(header.Number, header.Time)
|
||||||
if shanghai {
|
if shanghai {
|
||||||
|
|
@ -379,12 +380,15 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
||||||
// Assign the final state root to header.
|
// Assign the final state root to header.
|
||||||
header.Root = state.IntermediateRoot(true)
|
header.Root = state.IntermediateRoot(true)
|
||||||
|
|
||||||
if onFinalization != nil {
|
|
||||||
onFinalization()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble the final block.
|
// Assemble the final block.
|
||||||
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil
|
if onFinalizeAccessList != nil {
|
||||||
|
al := onFinalizeAccessList()
|
||||||
|
alHash := al.Hash()
|
||||||
|
header.BlockAccessListHash = &alHash
|
||||||
|
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)).WithAccessList(al), nil
|
||||||
|
} else {
|
||||||
|
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seal generates a new sealing request for the given input block and pushes
|
// Seal generates a new sealing request for the given input block and pushes
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
@ -581,7 +582,7 @@ func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
|
||||||
|
|
||||||
// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
|
// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
|
||||||
// nor block rewards given, and returns the final block.
|
// nor block rewards given, and returns the final block.
|
||||||
func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalize func()) (*types.Block, error) {
|
func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalizeAccessList func() *bal.BlockAccessList) (*types.Block, error) {
|
||||||
if len(body.Withdrawals) > 0 {
|
if len(body.Withdrawals) > 0 {
|
||||||
return nil, errors.New("clique does not support withdrawals")
|
return nil, errors.New("clique does not support withdrawals")
|
||||||
}
|
}
|
||||||
|
|
@ -591,10 +592,9 @@ func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
|
||||||
// Assign the final state root to header.
|
// Assign the final state root to header.
|
||||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||||
|
|
||||||
if onFinalize != nil {
|
if onFinalizeAccessList != nil {
|
||||||
onFinalize()
|
panic("access list embedding not enabled for clique consensus")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assemble and return the final block for sealing.
|
// Assemble and return the final block for sealing.
|
||||||
return types.NewBlock(header, &types.Body{Transactions: body.Transactions}, receipts, trie.NewStackTrie(nil)), nil
|
return types.NewBlock(header, &types.Body{Transactions: body.Transactions}, receipts, trie.NewStackTrie(nil)), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -92,7 +93,7 @@ type Engine interface {
|
||||||
//
|
//
|
||||||
// Note: The block header and state database might be updated to reflect any
|
// Note: The block header and state database might be updated to reflect any
|
||||||
// consensus rules that happen at finalization (e.g. block rewards).
|
// consensus rules that happen at finalization (e.g. block rewards).
|
||||||
FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalization func()) (*types.Block, error)
|
FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalizeAccessList func() *bal.BlockAccessList) (*types.Block, error)
|
||||||
|
|
||||||
// Seal generates a new sealing request for the given input block and pushes
|
// Seal generates a new sealing request for the given input block and pushes
|
||||||
// the result into the given channel.
|
// the result into the given channel.
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package ethash
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -513,7 +514,7 @@ func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.
|
||||||
|
|
||||||
// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
|
// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
|
||||||
// uncle rewards, setting the final state and assembling the block.
|
// uncle rewards, setting the final state and assembling the block.
|
||||||
func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalize func()) (*types.Block, error) {
|
func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalizeAccessList func() *bal.BlockAccessList) (*types.Block, error) {
|
||||||
if len(body.Withdrawals) > 0 {
|
if len(body.Withdrawals) > 0 {
|
||||||
return nil, errors.New("ethash does not support withdrawals")
|
return nil, errors.New("ethash does not support withdrawals")
|
||||||
}
|
}
|
||||||
|
|
@ -523,8 +524,8 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
||||||
// Assign the final state root to header.
|
// Assign the final state root to header.
|
||||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||||
|
|
||||||
if onFinalize != nil {
|
if onFinalizeAccessList != nil {
|
||||||
onFinalize()
|
panic("access list embedding not supported for ethash consenus")
|
||||||
}
|
}
|
||||||
// Header seems complete, assemble into a block and return
|
// Header seems complete, assemble into a block and return
|
||||||
return types.NewBlock(header, &types.Body{Transactions: body.Transactions, Uncles: body.Uncles}, receipts, trie.NewStackTrie(nil)), nil
|
return types.NewBlock(header, &types.Body{Transactions: body.Transactions, Uncles: body.Uncles}, receipts, trie.NewStackTrie(nil)), nil
|
||||||
|
|
|
||||||
|
|
@ -116,10 +116,10 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
// TODO: verify that this check isn't also done elsewhere
|
// TODO: verify that this check isn't also done elsewhere
|
||||||
return fmt.Errorf("block access list hash not set in header")
|
return fmt.Errorf("block access list hash not set in header")
|
||||||
}
|
}
|
||||||
if block.Body().AccessList != nil {
|
if block.AccessList() != nil {
|
||||||
if *block.Header().BlockAccessListHash != block.Body().AccessList.Hash() {
|
if *block.Header().BlockAccessListHash != block.AccessList().Hash() {
|
||||||
return fmt.Errorf("access list hash mismatch. local: %x. remote: %x\n", block.Body().AccessList.Hash(), *block.Header().BlockAccessListHash)
|
return fmt.Errorf("access list hash mismatch. local: %x. remote: %x\n", block.AccessList().Hash(), *block.Header().BlockAccessListHash)
|
||||||
} else if err := block.Body().AccessList.Validate(len(block.Transactions())); err != nil {
|
} else if err := block.AccessList().Validate(len(block.Transactions())); err != nil {
|
||||||
return fmt.Errorf("invalid block access list: %v", err)
|
return fmt.Errorf("invalid block access list: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +133,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if experimental.bal is not enabled, block headers cannot have access list hash and bodies cannot have access lists.
|
// if experimental.bal is not enabled, block headers cannot have access list hash and bodies cannot have access lists.
|
||||||
if block.Body().AccessList != nil {
|
if block.AccessList() != nil {
|
||||||
return fmt.Errorf("access list not allowed in block body if not in amsterdam or experimental.bal is set")
|
return fmt.Errorf("access list not allowed in block body if not in amsterdam or experimental.bal is set")
|
||||||
} else if block.Header().BlockAccessListHash != nil {
|
} else if block.Header().BlockAccessListHash != nil {
|
||||||
return fmt.Errorf("access list hash in block header not allowed when experimental.bal is set")
|
return fmt.Errorf("access list hash in block header not allowed when experimental.bal is set")
|
||||||
|
|
|
||||||
|
|
@ -2201,7 +2201,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
||||||
}
|
}
|
||||||
// TODO: need to check that the block is also postcancun if it contained an access list?
|
// TODO: need to check that the block is also postcancun if it contained an access list?
|
||||||
// this should be checked during decoding (?)
|
// this should be checked during decoding (?)
|
||||||
blockHasAccessList := block.Body().AccessList != nil
|
blockHasAccessList := block.AccessList() != nil
|
||||||
// only construct and embed BALs in the block if:
|
// only construct and embed BALs in the block if:
|
||||||
// * it has been enabled for testing purposes (preAmsterdam/postCancun blocks with experimental.bal)
|
// * it has been enabled for testing purposes (preAmsterdam/postCancun blocks with experimental.bal)
|
||||||
// * we are after Amsterdam and the block was provided with bal omitted
|
// * we are after Amsterdam and the block was provided with bal omitted
|
||||||
|
|
@ -2276,7 +2276,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
||||||
// Disable tracing for prefetcher executions.
|
// Disable tracing for prefetcher executions.
|
||||||
vmCfg := bc.cfg.VmConfig
|
vmCfg := bc.cfg.VmConfig
|
||||||
vmCfg.Tracer = nil
|
vmCfg.Tracer = nil
|
||||||
if block.Body().AccessList == nil {
|
if block.AccessList() == nil {
|
||||||
// only use the state prefetcher for non-BAL blocks.
|
// only use the state prefetcher for non-BAL blocks.
|
||||||
bc.prefetcher.Prefetch(block, throwaway, vmCfg, &interrupt)
|
bc.prefetcher.Prefetch(block, throwaway, vmCfg, &interrupt)
|
||||||
}
|
}
|
||||||
|
|
@ -2369,13 +2369,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
||||||
}
|
}
|
||||||
// very ugly... deepcopy the block body before setting the block access
|
block = block.WithAccessList(balTracer.AccessList().ToEncodingObj())
|
||||||
// list on it to prevent mutating the block instance passed by the caller.
|
|
||||||
existingBody := block.Body()
|
|
||||||
block = block.WithBody(*existingBody)
|
|
||||||
existingBody = block.Body()
|
|
||||||
existingBody.AccessList = balTracer.AccessList().ToEncodingObj()
|
|
||||||
block = block.WithBody(*existingBody)
|
|
||||||
} else if enableBALFork {
|
} else if enableBALFork {
|
||||||
|
|
||||||
computedAccessList := balTracer.AccessList().ToEncodingObj()
|
computedAccessList := balTracer.AccessList().ToEncodingObj()
|
||||||
|
|
@ -2387,16 +2381,12 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
||||||
bc.reportBadBlock(block, res, err)
|
bc.reportBadBlock(block, res, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if block.Body().AccessList == nil {
|
if block.AccessList() == nil {
|
||||||
// very ugly... deep copy the block body before setting the block access
|
// attach the computed access list to the block so it gets persisted
|
||||||
// list on it to prevent mutating the block instance passed by the caller.
|
// when the block is written to disk
|
||||||
existingBody := block.Body()
|
block = block.WithAccessList(computedAccessList)
|
||||||
block = block.WithBody(*existingBody)
|
} else if block.AccessList().Hash() != computedAccessListHash {
|
||||||
existingBody = block.Body()
|
err := fmt.Errorf("block access list hash mismatch (remote=%x computed=%x)", block.AccessList().Hash(), computedAccessListHash)
|
||||||
existingBody.AccessList = computedAccessList
|
|
||||||
block = block.WithBody(*existingBody)
|
|
||||||
} else if block.Body().AccessList.Hash() != computedAccessListHash {
|
|
||||||
err := fmt.Errorf("block access list hash mismatch (remote=%x computed=%x)", block.Body().AccessList.Hash(), computedAccessListHash)
|
|
||||||
bc.reportBadBlock(block, res, err)
|
bc.reportBadBlock(block, res, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||||
"math/big"
|
"math/big"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
|
@ -421,6 +422,17 @@ func WriteBodyRLP(db ethdb.KeyValueWriter, hash common.Hash, number uint64, rlp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WriteAccessListRLP(db ethdb.KeyValueWriter, hash common.Hash, number uint64, rlp rlp.RawValue) {
|
||||||
|
if err := db.Put(accessListKey(number, hash), rlp); err != nil {
|
||||||
|
log.Crit("failed to store block access list", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadAccessListRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
|
||||||
|
data, _ := db.Get(accessListKey(number, hash))
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
// HasBody verifies the existence of a block body corresponding to the hash.
|
// HasBody verifies the existence of a block body corresponding to the hash.
|
||||||
func HasBody(db ethdb.Reader, hash common.Hash, number uint64) bool {
|
func HasBody(db ethdb.Reader, hash common.Hash, number uint64) bool {
|
||||||
if isCanon(db, number, hash) {
|
if isCanon(db, number, hash) {
|
||||||
|
|
@ -455,6 +467,25 @@ func WriteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64, body *t
|
||||||
WriteBodyRLP(db, hash, number, data)
|
WriteBodyRLP(db, hash, number, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadAccessList(db ethdb.Reader, hash common.Hash, number uint64) (al *bal.BlockAccessList) {
|
||||||
|
data := ReadAccessListRLP(db, hash, number)
|
||||||
|
if data != nil {
|
||||||
|
err := rlp.DecodeBytes(data, al)
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("failed to RLP decode access list", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return al
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteAccessList(db ethdb.KeyValueWriter, hash common.Hash, number uint64, al *bal.BlockAccessList) {
|
||||||
|
data, err := rlp.EncodeToBytes(al)
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("failed to RLP encode block access list", "err", err)
|
||||||
|
}
|
||||||
|
WriteAccessListRLP(db, hash, number, data)
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteBody removes all block body data associated with a hash.
|
// DeleteBody removes all block body data associated with a hash.
|
||||||
func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
|
func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
|
||||||
if err := db.Delete(blockBodyKey(number, hash)); err != nil {
|
if err := db.Delete(blockBodyKey(number, hash)); err != nil {
|
||||||
|
|
@ -659,13 +690,26 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block {
|
||||||
if body == nil {
|
if body == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return types.NewBlockWithHeader(header).WithBody(*body)
|
|
||||||
|
block := types.NewBlockWithHeader(header).WithBody(*body)
|
||||||
|
|
||||||
|
// TODO: only read the access list if the bal hash is set in the header.
|
||||||
|
// I do it here regardless in order to support --experimental.bal which
|
||||||
|
// doesn't expect bal hash to be set in header in order to be compatible
|
||||||
|
// with importing mainnet blocks augmented with BALs
|
||||||
|
accessList := ReadAccessList(db, hash, number)
|
||||||
|
if accessList != nil {
|
||||||
|
block = block.WithAccessList(accessList)
|
||||||
|
}
|
||||||
|
|
||||||
|
return block
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteBlock serializes a block into the database, header and body separately.
|
// WriteBlock serializes a block into the database, header and body separately.
|
||||||
func WriteBlock(db ethdb.KeyValueWriter, block *types.Block) {
|
func WriteBlock(db ethdb.KeyValueWriter, block *types.Block) {
|
||||||
WriteBody(db, block.Hash(), block.NumberU64(), block.Body())
|
WriteBody(db, block.Hash(), block.NumberU64(), block.Body())
|
||||||
WriteHeader(db, block.Header())
|
WriteHeader(db, block.Header())
|
||||||
|
panic("TODO write access list if it exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteAncientBlocks writes entire block data into ancient store and returns the total written size.
|
// WriteAncientBlocks writes entire block data into ancient store and returns the total written size.
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ var (
|
||||||
headerNumberPrefix = []byte("H") // headerNumberPrefix + hash -> num (uint64 big endian)
|
headerNumberPrefix = []byte("H") // headerNumberPrefix + hash -> num (uint64 big endian)
|
||||||
|
|
||||||
blockBodyPrefix = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body
|
blockBodyPrefix = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body
|
||||||
|
accessListPrefix = []byte("z")
|
||||||
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
|
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
|
||||||
|
|
||||||
txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
|
txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
|
||||||
|
|
@ -209,6 +210,11 @@ func blockBodyKey(number uint64, hash common.Hash) []byte {
|
||||||
return append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
return append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// accessListKey = accessListPrefix + num (uint64 big endian) + hash
|
||||||
|
func accessListKey(number uint64, hash common.Hash) []byte {
|
||||||
|
return append(append(accessListPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||||
|
}
|
||||||
|
|
||||||
// blockReceiptsKey = blockReceiptsPrefix + num (uint64 big endian) + hash
|
// blockReceiptsKey = blockReceiptsPrefix + num (uint64 big endian) + hash
|
||||||
func blockReceiptsKey(number uint64, hash common.Hash) []byte {
|
func blockReceiptsKey(number uint64, hash common.Hash) []byte {
|
||||||
return append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
return append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ type BALReader struct {
|
||||||
// NewBALReader constructs a new reader from an access list. db is expected to have been instantiated with a reader.
|
// NewBALReader constructs a new reader from an access list. db is expected to have been instantiated with a reader.
|
||||||
func NewBALReader(block *types.Block, reader Reader) *BALReader {
|
func NewBALReader(block *types.Block, reader Reader) *BALReader {
|
||||||
r := &BALReader{accesses: make(map[common.Address]*bal.AccountAccess), block: block}
|
r := &BALReader{accesses: make(map[common.Address]*bal.AccountAccess), block: block}
|
||||||
for _, acctDiff := range *block.Body().AccessList {
|
for _, acctDiff := range *block.AccessList() {
|
||||||
r.accesses[acctDiff.Address] = &acctDiff
|
r.accesses[acctDiff.Address] = &acctDiff
|
||||||
}
|
}
|
||||||
r.prestateReader.schedule(reader, r.ModifiedAccounts())
|
r.prestateReader.schedule(reader, r.ModifiedAccounts())
|
||||||
|
|
|
||||||
|
|
@ -462,6 +462,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
|
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
|
||||||
t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas)
|
t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas)
|
||||||
}
|
}
|
||||||
|
fmt.Printf("gas used %d\n", gas)
|
||||||
st.gasRemaining -= gas
|
st.gasRemaining -= gas
|
||||||
|
|
||||||
if rules.IsEIP4762 {
|
if rules.IsEIP4762 {
|
||||||
|
|
@ -568,8 +569,10 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("2 used gas is %d, %d\n", st.gasUsed(), peakGasUsed)
|
||||||
|
|
||||||
return &ExecutionResult{
|
return &ExecutionResult{
|
||||||
UsedGas: st.gasUsed(),
|
UsedGas: peakGasUsed,
|
||||||
MaxUsedGas: peakGasUsed,
|
MaxUsedGas: peakGasUsed,
|
||||||
Err: vmerr,
|
Err: vmerr,
|
||||||
ReturnData: ret,
|
ReturnData: ret,
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,8 @@ func makeTestConstructionBAL() *AccessListBuilder {
|
||||||
// TestBALEncoding tests that a populated access list can be encoded/decoded correctly.
|
// TestBALEncoding tests that a populated access list can be encoded/decoded correctly.
|
||||||
func TestBALEncoding(t *testing.T) {
|
func TestBALEncoding(t *testing.T) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
bal := makeTestConstructionBAL()
|
balBuilder := makeTestConstructionBAL()
|
||||||
|
bal := balBuilder.FinalizedAccesses
|
||||||
err := bal.EncodeRLP(&buf)
|
err := bal.EncodeRLP(&buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("encoding failed: %v\n", err)
|
t.Fatalf("encoding failed: %v\n", err)
|
||||||
|
|
@ -136,7 +137,7 @@ func makeTestAccountAccess(sort bool) AccountAccess {
|
||||||
}
|
}
|
||||||
if sort {
|
if sort {
|
||||||
slices.SortFunc(storageWrites, func(a, b encodingSlotWrites) int {
|
slices.SortFunc(storageWrites, func(a, b encodingSlotWrites) int {
|
||||||
return bytes.Compare(a.Slot[:], b.Slot[:])
|
return bytes.Compare(a.Slot.inner.Bytes(), b.Slot.inner.Bytes())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,7 +174,7 @@ func makeTestAccountAccess(sort bool) AccountAccess {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var encodedStorageReads []EncodedStorage
|
var encodedStorageReads []*EncodedStorage
|
||||||
for _, slot := range storageReads {
|
for _, slot := range storageReads {
|
||||||
encodedStorageReads = append(encodedStorageReads, newEncodedStorageFromHash(slot))
|
encodedStorageReads = append(encodedStorageReads, newEncodedStorageFromHash(slot))
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +221,7 @@ func TestBlockAccessListCopy(t *testing.T) {
|
||||||
// Make sure the mutations on copy won't affect the origin
|
// Make sure the mutations on copy won't affect the origin
|
||||||
for _, aa := range cpyCpy {
|
for _, aa := range cpyCpy {
|
||||||
for i := 0; i < len(aa.StorageReads); i++ {
|
for i := 0; i < len(aa.StorageReads); i++ {
|
||||||
aa.StorageReads[i] = testrand.Bytes(32)
|
aa.StorageReads[i] = &EncodedStorage{new(uint256.Int).SetBytes(testrand.Bytes(32))}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(list, cpy) {
|
if !reflect.DeepEqual(list, cpy) {
|
||||||
|
|
@ -230,8 +231,9 @@ func TestBlockAccessListCopy(t *testing.T) {
|
||||||
|
|
||||||
func TestBlockAccessListValidation(t *testing.T) {
|
func TestBlockAccessListValidation(t *testing.T) {
|
||||||
// Validate the block access list after RLP decoding
|
// Validate the block access list after RLP decoding
|
||||||
|
testBALMaxIndex := 8
|
||||||
enc := makeTestBAL(true)
|
enc := makeTestBAL(true)
|
||||||
if err := enc.Validate(); err != nil {
|
if err := enc.Validate(testBALMaxIndex); err != nil {
|
||||||
t.Fatalf("Unexpected validation error: %v", err)
|
t.Fatalf("Unexpected validation error: %v", err)
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
@ -243,14 +245,14 @@ func TestBlockAccessListValidation(t *testing.T) {
|
||||||
if err := dec.DecodeRLP(rlp.NewStream(bytes.NewReader(buf.Bytes()), 0)); err != nil {
|
if err := dec.DecodeRLP(rlp.NewStream(bytes.NewReader(buf.Bytes()), 0)); err != nil {
|
||||||
t.Fatalf("Unexpected RLP-decode error: %v", err)
|
t.Fatalf("Unexpected RLP-decode error: %v", err)
|
||||||
}
|
}
|
||||||
if err := dec.Validate(); err != nil {
|
if err := dec.Validate(testBALMaxIndex); err != nil {
|
||||||
t.Fatalf("Unexpected validation error: %v", err)
|
t.Fatalf("Unexpected validation error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the derived block access list
|
// Validate the derived block access list
|
||||||
cBAL := makeTestConstructionBAL()
|
cBAL := makeTestConstructionBAL().FinalizedAccesses
|
||||||
listB := cBAL.ToEncodingObj()
|
listB := cBAL.ToEncodingObj()
|
||||||
if err := listB.Validate(); err != nil {
|
if err := listB.Validate(testBALMaxIndex); err != nil {
|
||||||
t.Fatalf("Unexpected validation error: %v", err)
|
t.Fatalf("Unexpected validation error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -182,8 +182,7 @@ func (h *Header) EmptyReceipts() bool {
|
||||||
type Body struct {
|
type Body struct {
|
||||||
Transactions []*Transaction
|
Transactions []*Transaction
|
||||||
Uncles []*Header
|
Uncles []*Header
|
||||||
Withdrawals []*Withdrawal `rlp:"optional"`
|
Withdrawals []*Withdrawal `rlp:"optional"`
|
||||||
AccessList *bal.BlockAccessList `rlp:"optional,nil"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block represents an Ethereum block.
|
// Block represents an Ethereum block.
|
||||||
|
|
@ -287,15 +286,17 @@ func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher ListHasher
|
||||||
b.withdrawals = slices.Clone(withdrawals)
|
b.withdrawals = slices.Clone(withdrawals)
|
||||||
}
|
}
|
||||||
|
|
||||||
if body.AccessList != nil {
|
|
||||||
balHash := body.AccessList.Hash()
|
|
||||||
b.header.BlockAccessListHash = &balHash
|
|
||||||
b.accessList = body.AccessList
|
|
||||||
}
|
|
||||||
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewBlockWithAccessList(header *Header, body *Body, receipts []*Receipt, accessList *bal.BlockAccessList, hasher ListHasher) *Block {
|
||||||
|
block := NewBlock(header, body, receipts, hasher)
|
||||||
|
block.accessList = accessList
|
||||||
|
balHash := accessList.Hash()
|
||||||
|
block.header.BlockAccessListHash = &balHash
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
|
||||||
// CopyHeader creates a deep copy of a block header.
|
// CopyHeader creates a deep copy of a block header.
|
||||||
func CopyHeader(h *Header) *Header {
|
func CopyHeader(h *Header) *Header {
|
||||||
cpy := *h
|
cpy := *h
|
||||||
|
|
@ -367,15 +368,16 @@ func (b *Block) EncodeRLP(w io.Writer) error {
|
||||||
// Body returns the non-header content of the block.
|
// Body returns the non-header content of the block.
|
||||||
// Note the returned data is not an independent copy.
|
// Note the returned data is not an independent copy.
|
||||||
func (b *Block) Body() *Body {
|
func (b *Block) Body() *Body {
|
||||||
return &Body{b.transactions, b.uncles, b.withdrawals, b.accessList}
|
return &Body{b.transactions, b.uncles, b.withdrawals}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessors for body data. These do not return a copy because the content
|
// Accessors for body data. These do not return a copy because the content
|
||||||
// of the body slices does not affect the cached hash/size in block.
|
// of the body slices does not affect the cached hash/size in block.
|
||||||
|
|
||||||
func (b *Block) Uncles() []*Header { return b.uncles }
|
func (b *Block) Uncles() []*Header { return b.uncles }
|
||||||
func (b *Block) Transactions() Transactions { return b.transactions }
|
func (b *Block) Transactions() Transactions { return b.transactions }
|
||||||
func (b *Block) Withdrawals() Withdrawals { return b.withdrawals }
|
func (b *Block) Withdrawals() Withdrawals { return b.withdrawals }
|
||||||
|
func (b *Block) AccessList() *bal.BlockAccessList { return b.accessList }
|
||||||
|
|
||||||
func (b *Block) Transaction(hash common.Hash) *Transaction {
|
func (b *Block) Transaction(hash common.Hash) *Transaction {
|
||||||
for _, transaction := range b.transactions {
|
for _, transaction := range b.transactions {
|
||||||
|
|
@ -522,16 +524,30 @@ func (b *Block) WithBody(body Body) *Block {
|
||||||
uncles: make([]*Header, len(body.Uncles)),
|
uncles: make([]*Header, len(body.Uncles)),
|
||||||
withdrawals: slices.Clone(body.Withdrawals),
|
withdrawals: slices.Clone(body.Withdrawals),
|
||||||
}
|
}
|
||||||
if body.AccessList != nil {
|
|
||||||
balCopy := body.AccessList.Copy()
|
|
||||||
block.accessList = &balCopy
|
|
||||||
}
|
|
||||||
for i := range body.Uncles {
|
for i := range body.Uncles {
|
||||||
block.uncles[i] = CopyHeader(body.Uncles[i])
|
block.uncles[i] = CopyHeader(body.Uncles[i])
|
||||||
}
|
}
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithAccessList returns a copy of the block with the access list embedded.
|
||||||
|
// It does not set the access list hash in the header of the returned block.
|
||||||
|
// TODO: ^ when support for --experimental.bal is removed, this function should set the access list hash in the header
|
||||||
|
func (b *Block) WithAccessList(accessList *bal.BlockAccessList) *Block {
|
||||||
|
alCopy := accessList.Copy()
|
||||||
|
block := &Block{
|
||||||
|
header: b.header,
|
||||||
|
transactions: slices.Clone(b.transactions),
|
||||||
|
uncles: make([]*Header, len(b.uncles)),
|
||||||
|
withdrawals: slices.Clone(b.withdrawals),
|
||||||
|
accessList: &alCopy,
|
||||||
|
}
|
||||||
|
for i := range b.uncles {
|
||||||
|
block.uncles[i] = CopyHeader(b.uncles[i])
|
||||||
|
}
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
|
||||||
// Hash returns the keccak256 hash of b's header.
|
// Hash returns the keccak256 hash of b's header.
|
||||||
// The hash is computed on the first call and cached thereafter.
|
// The hash is computed on the first call and cached thereafter.
|
||||||
func (b *Block) Hash() common.Hash {
|
func (b *Block) Hash() common.Hash {
|
||||||
|
|
|
||||||
|
|
@ -514,8 +514,8 @@ func (b *EthAPIBackend) BlockAccessListByNumberOrHash(number rpc.BlockNumberOrHa
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return nil, fmt.Errorf("block not found")
|
return nil, fmt.Errorf("block not found")
|
||||||
}
|
}
|
||||||
if block.Body().AccessList == nil {
|
if block.AccessList() == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return block.Body().AccessList.StringableRepresentation(), nil
|
return block.AccessList().StringableRepresentation(), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,6 @@ func (f *fetchResult) body() types.Body {
|
||||||
Transactions: f.Transactions,
|
Transactions: f.Transactions,
|
||||||
Uncles: f.Uncles,
|
Uncles: f.Uncles,
|
||||||
Withdrawals: f.Withdrawals,
|
Withdrawals: f.Withdrawals,
|
||||||
AccessList: f.AccessList,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -970,8 +970,8 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param
|
||||||
if block.Withdrawals() != nil {
|
if block.Withdrawals() != nil {
|
||||||
fields["withdrawals"] = block.Withdrawals()
|
fields["withdrawals"] = block.Withdrawals()
|
||||||
}
|
}
|
||||||
if block.Body().AccessList != nil {
|
if block.AccessList() != nil {
|
||||||
fields["accessList"] = block.Body().AccessList
|
fields["accessList"] = block.AccessList()
|
||||||
}
|
}
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -147,9 +148,6 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
body := types.Body{Transactions: work.txs, Withdrawals: genParam.withdrawals}
|
body := types.Body{Transactions: work.txs, Withdrawals: genParam.withdrawals}
|
||||||
if work.alTracer != nil {
|
|
||||||
body.AccessList = work.alTracer.AccessList().ToEncodingObj()
|
|
||||||
}
|
|
||||||
|
|
||||||
allLogs := make([]*types.Log, 0)
|
allLogs := make([]*types.Log, 0)
|
||||||
for _, r := range work.receipts {
|
for _, r := range work.receipts {
|
||||||
|
|
@ -184,11 +182,12 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay
|
||||||
// I considered trying to instantiate the beacon consensus engine with a tracer.
|
// I considered trying to instantiate the beacon consensus engine with a tracer.
|
||||||
// however, the BAL tracer instance is used once per block, while the engine object
|
// however, the BAL tracer instance is used once per block, while the engine object
|
||||||
// lives for the entire time the client is running.
|
// lives for the entire time the client is running.
|
||||||
onBlockFinalization := func() {
|
onBlockFinalization := func() *bal.BlockAccessList {
|
||||||
if miner.chainConfig.IsAmsterdam(work.header.Number, work.header.Time) {
|
if miner.chainConfig.IsAmsterdam(work.header.Number, work.header.Time) {
|
||||||
work.alTracer.OnBlockFinalization()
|
work.alTracer.OnBlockFinalization()
|
||||||
body.AccessList = work.alTracer.AccessList().ToEncodingObj()
|
return work.alTracer.AccessList().ToEncodingObj()
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts, onBlockFinalization)
|
block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts, onBlockFinalization)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue