mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-16 18:00:46 +00:00
core/rawdb: BAL storage layer (#34064)
Add persistent storage for Block Access Lists (BALs) in `core/rawdb/`. This provides read/write/delete accessors for BALs in the active key-value store. --------- Co-authored-by: Jared Wasinger <j-wasinger@hotmail.com> Co-authored-by: Gary Rong <garyrong0905@gmail.com>
This commit is contained in:
parent
965bd6b6a0
commit
dc3794e3dc
10 changed files with 270 additions and 69 deletions
|
|
@ -275,12 +275,22 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify the existence / non-existence of Amsterdam-specific header fields
|
||||||
amsterdam := chain.Config().IsAmsterdam(header.Number, header.Time)
|
amsterdam := chain.Config().IsAmsterdam(header.Number, header.Time)
|
||||||
if amsterdam && header.SlotNumber == nil {
|
if amsterdam {
|
||||||
return errors.New("header is missing slotNumber")
|
if header.BlockAccessListHash == nil {
|
||||||
}
|
return errors.New("header is missing block access list hash")
|
||||||
if !amsterdam && header.SlotNumber != nil {
|
}
|
||||||
return fmt.Errorf("invalid slotNumber: have %d, expected nil", *header.SlotNumber)
|
if header.SlotNumber == nil {
|
||||||
|
return errors.New("header is missing slotNumber")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if header.BlockAccessListHash != nil {
|
||||||
|
return fmt.Errorf("invalid block access list hash: have %x, expected nil", *header.BlockAccessListHash)
|
||||||
|
}
|
||||||
|
if header.SlotNumber != nil {
|
||||||
|
return fmt.Errorf("invalid slotNumber: have %d, expected nil", *header.SlotNumber)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
@ -605,6 +606,55 @@ func DeleteReceipts(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasAccessList verifies the existence of a block access list for a block.
|
||||||
|
func HasAccessList(db ethdb.Reader, hash common.Hash, number uint64) bool {
|
||||||
|
has, _ := db.Has(accessListKey(number, hash))
|
||||||
|
return has
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadAccessListRLP retrieves the RLP-encoded block access list for a block from KV.
|
||||||
|
func ReadAccessListRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
|
||||||
|
data, _ := db.Get(accessListKey(number, hash))
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadAccessList retrieves and decodes the block access list for a block.
|
||||||
|
func ReadAccessList(db ethdb.Reader, hash common.Hash, number uint64) *bal.BlockAccessList {
|
||||||
|
data := ReadAccessListRLP(db, hash, number)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
b := new(bal.BlockAccessList)
|
||||||
|
if err := rlp.DecodeBytes(data, b); err != nil {
|
||||||
|
log.Error("Invalid BAL RLP", "hash", hash, "err", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteAccessList RLP-encodes and stores a block access list in the active KV store.
|
||||||
|
func WriteAccessList(db ethdb.KeyValueWriter, hash common.Hash, number uint64, b *bal.BlockAccessList) {
|
||||||
|
bytes, err := rlp.EncodeToBytes(b)
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("Failed to encode BAL", "err", err)
|
||||||
|
}
|
||||||
|
WriteAccessListRLP(db, hash, number, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteAccessListRLP stores a pre-encoded block access list in the active KV store.
|
||||||
|
func WriteAccessListRLP(db ethdb.KeyValueWriter, hash common.Hash, number uint64, encoded rlp.RawValue) {
|
||||||
|
if err := db.Put(accessListKey(number, hash), encoded); err != nil {
|
||||||
|
log.Crit("Failed to store BAL", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAccessList removes a block access list from the active KV store.
|
||||||
|
func DeleteAccessList(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
|
||||||
|
if err := db.Delete(accessListKey(number, hash)); err != nil {
|
||||||
|
log.Crit("Failed to delete BAL", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ReceiptLogs is a barebone version of ReceiptForStorage which only keeps
|
// ReceiptLogs is a barebone version of ReceiptForStorage which only keeps
|
||||||
// the list of logs. When decoding a stored receipt into this object we
|
// the list of logs. When decoding a stored receipt into this object we
|
||||||
// avoid creating the bloom filter.
|
// avoid creating the bloom filter.
|
||||||
|
|
@ -659,13 +709,25 @@ 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)
|
||||||
|
|
||||||
|
// Best-effort assembly of the block access list from the database.
|
||||||
|
if header.BlockAccessListHash != nil {
|
||||||
|
al := ReadAccessList(db, hash, number)
|
||||||
|
block = block.WithAccessListUnsafe(al)
|
||||||
|
}
|
||||||
|
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())
|
hash, number := block.Hash(), block.NumberU64()
|
||||||
|
WriteBody(db, hash, number, block.Body())
|
||||||
WriteHeader(db, block.Header())
|
WriteHeader(db, block.Header())
|
||||||
|
|
||||||
|
if accessList := block.AccessList(); accessList != nil {
|
||||||
|
WriteAccessList(db, hash, number, accessList)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,12 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/keccak"
|
"github.com/ethereum/go-ethereum/crypto/keccak"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests block header storage and retrieval operations.
|
// Tests block header storage and retrieval operations.
|
||||||
|
|
@ -899,3 +901,78 @@ func TestHeadersRLPStorage(t *testing.T) {
|
||||||
checkSequence(1, 1) // Only block 1
|
checkSequence(1, 1) // Only block 1
|
||||||
checkSequence(1, 2) // Genesis + block 1
|
checkSequence(1, 2) // Genesis + block 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeTestBAL(t *testing.T) (rlp.RawValue, *bal.BlockAccessList) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
cb := bal.NewConstructionBlockAccessList()
|
||||||
|
addr := common.HexToAddress("0x1111111111111111111111111111111111111111")
|
||||||
|
cb.AccountRead(addr)
|
||||||
|
cb.StorageRead(addr, common.BytesToHash([]byte{0x01}))
|
||||||
|
cb.StorageWrite(0, addr, common.BytesToHash([]byte{0x02}), common.BytesToHash([]byte{0xaa}))
|
||||||
|
cb.BalanceChange(0, addr, uint256.NewInt(100))
|
||||||
|
cb.NonceChange(addr, 0, 1)
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := cb.EncodeRLP(&buf); err != nil {
|
||||||
|
t.Fatalf("failed to encode BAL: %v", err)
|
||||||
|
}
|
||||||
|
encoded := buf.Bytes()
|
||||||
|
|
||||||
|
var decoded bal.BlockAccessList
|
||||||
|
if err := rlp.DecodeBytes(encoded, &decoded); err != nil {
|
||||||
|
t.Fatalf("failed to decode BAL: %v", err)
|
||||||
|
}
|
||||||
|
return encoded, &decoded
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestBALStorage tests write/read/delete of BALs in the KV store.
|
||||||
|
func TestBALStorage(t *testing.T) {
|
||||||
|
db := NewMemoryDatabase()
|
||||||
|
|
||||||
|
hash := common.BytesToHash([]byte{0x03, 0x14})
|
||||||
|
number := uint64(42)
|
||||||
|
|
||||||
|
// Check that no BAL exists in a new database.
|
||||||
|
if HasAccessList(db, hash, number) {
|
||||||
|
t.Fatal("BAL found in new database")
|
||||||
|
}
|
||||||
|
if b := ReadAccessList(db, hash, number); b != nil {
|
||||||
|
t.Fatalf("non existent BAL returned: %v", b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write a BAL and verify it can be read back.
|
||||||
|
encoded, testBAL := makeTestBAL(t)
|
||||||
|
WriteAccessList(db, hash, number, testBAL)
|
||||||
|
|
||||||
|
if !HasAccessList(db, hash, number) {
|
||||||
|
t.Fatal("HasAccessList returned false after write")
|
||||||
|
}
|
||||||
|
if blob := ReadAccessListRLP(db, hash, number); len(blob) == 0 {
|
||||||
|
t.Fatal("ReadAccessListRLP returned empty after write")
|
||||||
|
}
|
||||||
|
if b := ReadAccessList(db, hash, number); b == nil {
|
||||||
|
t.Fatal("ReadAccessList returned nil after write")
|
||||||
|
} else if b.Hash() != testBAL.Hash() {
|
||||||
|
t.Fatalf("BAL hash mismatch: got %x, want %x", b.Hash(), testBAL.Hash())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also test WriteAccessListRLP with pre-encoded data.
|
||||||
|
hash2 := common.BytesToHash([]byte{0x03, 0x15})
|
||||||
|
WriteAccessListRLP(db, hash2, number, encoded)
|
||||||
|
if b := ReadAccessList(db, hash2, number); b == nil {
|
||||||
|
t.Fatal("ReadAccessList returned nil after WriteAccessListRLP")
|
||||||
|
} else if b.Hash() != testBAL.Hash() {
|
||||||
|
t.Fatalf("BAL hash mismatch after WriteAccessListRLP: got %x, want %x", b.Hash(), testBAL.Hash())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the BAL and verify it's gone.
|
||||||
|
DeleteAccessList(db, hash, number)
|
||||||
|
|
||||||
|
if HasAccessList(db, hash, number) {
|
||||||
|
t.Fatal("HasAccessList returned true after delete")
|
||||||
|
}
|
||||||
|
if b := ReadAccessList(db, hash, number); b != nil {
|
||||||
|
t.Fatalf("deleted BAL returned: %v", b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -413,6 +413,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||||
tds stat
|
tds stat
|
||||||
numHashPairings stat
|
numHashPairings stat
|
||||||
hashNumPairings stat
|
hashNumPairings stat
|
||||||
|
blockAccessList stat
|
||||||
legacyTries stat
|
legacyTries stat
|
||||||
stateLookups stat
|
stateLookups stat
|
||||||
accountTries stat
|
accountTries stat
|
||||||
|
|
@ -484,6 +485,9 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||||
numHashPairings.add(size)
|
numHashPairings.add(size)
|
||||||
case bytes.HasPrefix(key, headerNumberPrefix) && len(key) == (len(headerNumberPrefix)+common.HashLength):
|
case bytes.HasPrefix(key, headerNumberPrefix) && len(key) == (len(headerNumberPrefix)+common.HashLength):
|
||||||
hashNumPairings.add(size)
|
hashNumPairings.add(size)
|
||||||
|
case bytes.HasPrefix(key, accessListPrefix) && len(key) == len(accessListPrefix)+8+common.HashLength:
|
||||||
|
blockAccessList.add(size)
|
||||||
|
|
||||||
case IsLegacyTrieNode(key, it.Value()):
|
case IsLegacyTrieNode(key, it.Value()):
|
||||||
legacyTries.add(size)
|
legacyTries.add(size)
|
||||||
case bytes.HasPrefix(key, stateIDPrefix) && len(key) == len(stateIDPrefix)+common.HashLength:
|
case bytes.HasPrefix(key, stateIDPrefix) && len(key) == len(stateIDPrefix)+common.HashLength:
|
||||||
|
|
@ -625,6 +629,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||||
{"Key-Value store", "Difficulties (deprecated)", tds.sizeString(), tds.countString()},
|
{"Key-Value store", "Difficulties (deprecated)", tds.sizeString(), tds.countString()},
|
||||||
{"Key-Value store", "Block number->hash", numHashPairings.sizeString(), numHashPairings.countString()},
|
{"Key-Value store", "Block number->hash", numHashPairings.sizeString(), numHashPairings.countString()},
|
||||||
{"Key-Value store", "Block hash->number", hashNumPairings.sizeString(), hashNumPairings.countString()},
|
{"Key-Value store", "Block hash->number", hashNumPairings.sizeString(), hashNumPairings.countString()},
|
||||||
|
{"Key-Value store", "Block accessList", blockAccessList.sizeString(), blockAccessList.countString()},
|
||||||
{"Key-Value store", "Transaction index", txLookups.sizeString(), txLookups.countString()},
|
{"Key-Value store", "Transaction index", txLookups.sizeString(), txLookups.countString()},
|
||||||
{"Key-Value store", "Log index filter-map rows", filterMapRows.sizeString(), filterMapRows.countString()},
|
{"Key-Value store", "Log index filter-map rows", filterMapRows.sizeString(), filterMapRows.countString()},
|
||||||
{"Key-Value store", "Log index last-block-of-map", filterMapLastBlock.sizeString(), filterMapLastBlock.countString()},
|
{"Key-Value store", "Log index last-block-of-map", filterMapLastBlock.sizeString(), filterMapLastBlock.countString()},
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,7 @@ var (
|
||||||
|
|
||||||
blockBodyPrefix = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body
|
blockBodyPrefix = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body
|
||||||
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
|
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
|
||||||
|
accessListPrefix = []byte("j") // accessListPrefix + num (uint64 big endian) + hash -> block access list
|
||||||
|
|
||||||
txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
|
txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
|
||||||
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
|
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
|
||||||
|
|
@ -214,6 +215,11 @@ func blockReceiptsKey(number uint64, hash common.Hash) []byte {
|
||||||
return append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
return append(append(blockReceiptsPrefix, 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()...)
|
||||||
|
}
|
||||||
|
|
||||||
// txLookupKey = txLookupPrefix + hash
|
// txLookupKey = txLookupPrefix + hash
|
||||||
func txLookupKey(hash common.Hash) []byte {
|
func txLookupKey(hash common.Hash) []byte {
|
||||||
return append(txLookupPrefix, hash.Bytes()...)
|
return append(txLookupPrefix, hash.Bytes()...)
|
||||||
|
|
|
||||||
|
|
@ -350,9 +350,12 @@ func (e *BlockAccessList) PrettyPrint() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy returns a deep copy of the access list
|
// Copy returns a deep copy of the access list
|
||||||
func (e *BlockAccessList) Copy() (res BlockAccessList) {
|
func (e *BlockAccessList) Copy() *BlockAccessList {
|
||||||
for _, accountAccess := range e.Accesses {
|
cpy := &BlockAccessList{
|
||||||
res.Accesses = append(res.Accesses, accountAccess.Copy())
|
Accesses: make([]AccountAccess, 0, len(e.Accesses)),
|
||||||
}
|
}
|
||||||
return
|
for _, accountAccess := range e.Accesses {
|
||||||
|
cpy.Accesses = append(cpy.Accesses, accountAccess.Copy())
|
||||||
|
}
|
||||||
|
return cpy
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -190,8 +190,8 @@ func makeTestAccountAccess(sort bool) AccountAccess {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeTestBAL(sort bool) BlockAccessList {
|
func makeTestBAL(sort bool) *BlockAccessList {
|
||||||
list := BlockAccessList{}
|
list := &BlockAccessList{}
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
list.Accesses = append(list.Accesses, makeTestAccountAccess(sort))
|
list.Accesses = append(list.Accesses, makeTestAccountAccess(sort))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -99,6 +100,9 @@ type Header struct {
|
||||||
// RequestsHash was added by EIP-7685 and is ignored in legacy headers.
|
// RequestsHash was added by EIP-7685 and is ignored in legacy headers.
|
||||||
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
||||||
|
|
||||||
|
// BlockAccessListHash was added by EIP-7928 and is ignored in legacy headers.
|
||||||
|
BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"`
|
||||||
|
|
||||||
// SlotNumber was added by EIP-7843 and is ignored in legacy headers.
|
// SlotNumber was added by EIP-7843 and is ignored in legacy headers.
|
||||||
SlotNumber *uint64 `json:"slotNumber" rlp:"optional"`
|
SlotNumber *uint64 `json:"slotNumber" rlp:"optional"`
|
||||||
}
|
}
|
||||||
|
|
@ -204,6 +208,7 @@ type Block struct {
|
||||||
uncles []*Header
|
uncles []*Header
|
||||||
transactions Transactions
|
transactions Transactions
|
||||||
withdrawals Withdrawals
|
withdrawals Withdrawals
|
||||||
|
accessList *bal.BlockAccessList
|
||||||
|
|
||||||
// caches
|
// caches
|
||||||
hash atomic.Pointer[common.Hash]
|
hash atomic.Pointer[common.Hash]
|
||||||
|
|
@ -358,9 +363,10 @@ func (b *Block) Body() *Body {
|
||||||
// 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 {
|
||||||
|
|
@ -513,6 +519,24 @@ func (b *Block) WithBody(body Body) *Block {
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithAccessList returns a copy of the block with the given access list embedded.
|
||||||
|
func (b *Block) WithAccessList(accessList *bal.BlockAccessList) *Block {
|
||||||
|
return b.WithAccessListUnsafe(accessList.Copy())
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAccessListUnsafe returns a copy of the block with the given access list
|
||||||
|
// embedded. Note that the access list is not deep-copied; use WithAccessList
|
||||||
|
// if the provided list may be modified by other actors.
|
||||||
|
func (b *Block) WithAccessListUnsafe(accessList *bal.BlockAccessList) *Block {
|
||||||
|
return &Block{
|
||||||
|
header: b.header,
|
||||||
|
transactions: b.transactions,
|
||||||
|
uncles: b.uncles,
|
||||||
|
withdrawals: b.withdrawals,
|
||||||
|
accessList: accessList,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
|
|
|
||||||
|
|
@ -16,29 +16,30 @@ var _ = (*headerMarshaling)(nil)
|
||||||
// MarshalJSON marshals as JSON.
|
// MarshalJSON marshals as JSON.
|
||||||
func (h Header) MarshalJSON() ([]byte, error) {
|
func (h Header) MarshalJSON() ([]byte, error) {
|
||||||
type Header struct {
|
type Header struct {
|
||||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||||
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
|
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
|
||||||
Coinbase common.Address `json:"miner"`
|
Coinbase common.Address `json:"miner"`
|
||||||
Root common.Hash `json:"stateRoot" gencodec:"required"`
|
Root common.Hash `json:"stateRoot" gencodec:"required"`
|
||||||
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
|
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
|
||||||
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
|
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||||
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
||||||
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
|
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
|
||||||
Number *hexutil.Big `json:"number" gencodec:"required"`
|
Number *hexutil.Big `json:"number" gencodec:"required"`
|
||||||
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
||||||
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
Time hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
Time hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||||
Extra hexutil.Bytes `json:"extraData" gencodec:"required"`
|
Extra hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||||
MixDigest common.Hash `json:"mixHash"`
|
MixDigest common.Hash `json:"mixHash"`
|
||||||
Nonce BlockNonce `json:"nonce"`
|
Nonce BlockNonce `json:"nonce"`
|
||||||
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
||||||
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
||||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
|
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
|
||||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
|
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
|
||||||
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||||
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
||||||
SlotNumber *hexutil.Uint64 `json:"slotNumber" rlp:"optional"`
|
BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"`
|
||||||
Hash common.Hash `json:"hash"`
|
SlotNumber *hexutil.Uint64 `json:"slotNumber" rlp:"optional"`
|
||||||
|
Hash common.Hash `json:"hash"`
|
||||||
}
|
}
|
||||||
var enc Header
|
var enc Header
|
||||||
enc.ParentHash = h.ParentHash
|
enc.ParentHash = h.ParentHash
|
||||||
|
|
@ -62,6 +63,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
|
||||||
enc.ExcessBlobGas = (*hexutil.Uint64)(h.ExcessBlobGas)
|
enc.ExcessBlobGas = (*hexutil.Uint64)(h.ExcessBlobGas)
|
||||||
enc.ParentBeaconRoot = h.ParentBeaconRoot
|
enc.ParentBeaconRoot = h.ParentBeaconRoot
|
||||||
enc.RequestsHash = h.RequestsHash
|
enc.RequestsHash = h.RequestsHash
|
||||||
|
enc.BlockAccessListHash = h.BlockAccessListHash
|
||||||
enc.SlotNumber = (*hexutil.Uint64)(h.SlotNumber)
|
enc.SlotNumber = (*hexutil.Uint64)(h.SlotNumber)
|
||||||
enc.Hash = h.Hash()
|
enc.Hash = h.Hash()
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
|
|
@ -70,28 +72,29 @@ func (h Header) MarshalJSON() ([]byte, error) {
|
||||||
// UnmarshalJSON unmarshals from JSON.
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
func (h *Header) UnmarshalJSON(input []byte) error {
|
func (h *Header) UnmarshalJSON(input []byte) error {
|
||||||
type Header struct {
|
type Header struct {
|
||||||
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
|
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
|
||||||
UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"`
|
UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"`
|
||||||
Coinbase *common.Address `json:"miner"`
|
Coinbase *common.Address `json:"miner"`
|
||||||
Root *common.Hash `json:"stateRoot" gencodec:"required"`
|
Root *common.Hash `json:"stateRoot" gencodec:"required"`
|
||||||
TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"`
|
TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"`
|
||||||
ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"`
|
ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||||
Bloom *Bloom `json:"logsBloom" gencodec:"required"`
|
Bloom *Bloom `json:"logsBloom" gencodec:"required"`
|
||||||
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
|
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
|
||||||
Number *hexutil.Big `json:"number" gencodec:"required"`
|
Number *hexutil.Big `json:"number" gencodec:"required"`
|
||||||
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
||||||
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||||
Extra *hexutil.Bytes `json:"extraData" gencodec:"required"`
|
Extra *hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||||
MixDigest *common.Hash `json:"mixHash"`
|
MixDigest *common.Hash `json:"mixHash"`
|
||||||
Nonce *BlockNonce `json:"nonce"`
|
Nonce *BlockNonce `json:"nonce"`
|
||||||
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
||||||
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
||||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
|
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
|
||||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
|
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
|
||||||
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||||
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
||||||
SlotNumber *hexutil.Uint64 `json:"slotNumber" rlp:"optional"`
|
BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"`
|
||||||
|
SlotNumber *hexutil.Uint64 `json:"slotNumber" rlp:"optional"`
|
||||||
}
|
}
|
||||||
var dec Header
|
var dec Header
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -172,6 +175,9 @@ func (h *Header) UnmarshalJSON(input []byte) error {
|
||||||
if dec.RequestsHash != nil {
|
if dec.RequestsHash != nil {
|
||||||
h.RequestsHash = dec.RequestsHash
|
h.RequestsHash = dec.RequestsHash
|
||||||
}
|
}
|
||||||
|
if dec.BlockAccessListHash != nil {
|
||||||
|
h.BlockAccessListHash = dec.BlockAccessListHash
|
||||||
|
}
|
||||||
if dec.SlotNumber != nil {
|
if dec.SlotNumber != nil {
|
||||||
h.SlotNumber = (*uint64)(dec.SlotNumber)
|
h.SlotNumber = (*uint64)(dec.SlotNumber)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,9 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
|
||||||
_tmp4 := obj.ExcessBlobGas != nil
|
_tmp4 := obj.ExcessBlobGas != nil
|
||||||
_tmp5 := obj.ParentBeaconRoot != nil
|
_tmp5 := obj.ParentBeaconRoot != nil
|
||||||
_tmp6 := obj.RequestsHash != nil
|
_tmp6 := obj.RequestsHash != nil
|
||||||
_tmp7 := obj.SlotNumber != nil
|
_tmp7 := obj.BlockAccessListHash != nil
|
||||||
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
_tmp8 := obj.SlotNumber != nil
|
||||||
|
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 || _tmp8 {
|
||||||
if obj.BaseFee == nil {
|
if obj.BaseFee == nil {
|
||||||
w.Write(rlp.EmptyString)
|
w.Write(rlp.EmptyString)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -54,42 +55,49 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
|
||||||
w.WriteBigInt(obj.BaseFee)
|
w.WriteBigInt(obj.BaseFee)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 || _tmp8 {
|
||||||
if obj.WithdrawalsHash == nil {
|
if obj.WithdrawalsHash == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
w.WriteBytes(obj.WithdrawalsHash[:])
|
w.WriteBytes(obj.WithdrawalsHash[:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
if _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 || _tmp8 {
|
||||||
if obj.BlobGasUsed == nil {
|
if obj.BlobGasUsed == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
w.WriteUint64((*obj.BlobGasUsed))
|
w.WriteUint64((*obj.BlobGasUsed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
if _tmp4 || _tmp5 || _tmp6 || _tmp7 || _tmp8 {
|
||||||
if obj.ExcessBlobGas == nil {
|
if obj.ExcessBlobGas == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
w.WriteUint64((*obj.ExcessBlobGas))
|
w.WriteUint64((*obj.ExcessBlobGas))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp5 || _tmp6 || _tmp7 {
|
if _tmp5 || _tmp6 || _tmp7 || _tmp8 {
|
||||||
if obj.ParentBeaconRoot == nil {
|
if obj.ParentBeaconRoot == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
w.WriteBytes(obj.ParentBeaconRoot[:])
|
w.WriteBytes(obj.ParentBeaconRoot[:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp6 || _tmp7 {
|
if _tmp6 || _tmp7 || _tmp8 {
|
||||||
if obj.RequestsHash == nil {
|
if obj.RequestsHash == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
w.WriteBytes(obj.RequestsHash[:])
|
w.WriteBytes(obj.RequestsHash[:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp7 {
|
if _tmp7 || _tmp8 {
|
||||||
|
if obj.BlockAccessListHash == nil {
|
||||||
|
w.Write([]byte{0x80})
|
||||||
|
} else {
|
||||||
|
w.WriteBytes(obj.BlockAccessListHash[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _tmp8 {
|
||||||
if obj.SlotNumber == nil {
|
if obj.SlotNumber == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue