mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
ethclient/lightclient: more comments and minor changes
This commit is contained in:
parent
37950cad34
commit
e2afe317e6
3 changed files with 48 additions and 11 deletions
|
|
@ -54,6 +54,7 @@ func (c *Client) closeBlocksAndHeaders() {
|
||||||
c.blockRequests.close()
|
c.blockRequests.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getHeader returns the header with the given block hash.
|
||||||
func (c *Client) getHeader(ctx context.Context, hash common.Hash) (*types.Header, error) {
|
func (c *Client) getHeader(ctx context.Context, hash common.Hash) (*types.Header, error) {
|
||||||
if header, ok := c.headerCache.Get(hash); ok {
|
if header, ok := c.headerCache.Get(hash); ok {
|
||||||
return header, nil
|
return header, nil
|
||||||
|
|
@ -84,15 +85,25 @@ func (c *Client) getHeader(ctx context.Context, hash common.Hash) (*types.Header
|
||||||
return header, err
|
return header, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getPayloadHeader returns the payload header with the given block hash.
|
||||||
|
// Note that types.Header and the CL execution payload header (btypes.ExecutionHeader)
|
||||||
|
// both contain the information relevant to the light client but they are not
|
||||||
|
// interchangeable. Payload headers are received from head/finality updates and
|
||||||
|
// are cached but they are not obtainable later on demand as they are not directly
|
||||||
|
// chained to each other by hash reference. If reverse syncing is required then
|
||||||
|
// EL headers should be used.
|
||||||
func (c *Client) getPayloadHeader(hash common.Hash) *btypes.ExecutionHeader {
|
func (c *Client) getPayloadHeader(hash common.Hash) *btypes.ExecutionHeader {
|
||||||
pheader, _ := c.payloadHeaderCache.Get(hash)
|
pheader, _ := c.payloadHeaderCache.Get(hash)
|
||||||
return pheader
|
return pheader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addPayloadHeader caches the given payload header.
|
||||||
func (c *Client) addPayloadHeader(header *btypes.ExecutionHeader) {
|
func (c *Client) addPayloadHeader(header *btypes.ExecutionHeader) {
|
||||||
c.payloadHeaderCache.Add(header.BlockHash(), header)
|
c.payloadHeaderCache.Add(header.BlockHash(), header)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getBlock returns the block with the given hash. If the block has been retrieved
|
||||||
|
// from the server then the transaction inclusion positions are also cached.
|
||||||
func (c *Client) getBlock(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
func (c *Client) getBlock(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
||||||
if block, ok := c.blockCache.Get(hash); ok {
|
if block, ok := c.blockCache.Get(hash); ok {
|
||||||
return block, nil
|
return block, nil
|
||||||
|
|
@ -149,7 +160,8 @@ func (c *Client) requestBlock(ctx context.Context, hash common.Hash) (*types.Blo
|
||||||
return block, nil
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO de-duplicate json block decoding
|
// decodeBlock decodes a JSON encoded block.
|
||||||
|
//TODO de-duplicate
|
||||||
func decodeBlock(raw json.RawMessage) (*types.Block, error) {
|
func decodeBlock(raw json.RawMessage) (*types.Block, error) {
|
||||||
// Decode header and transactions.
|
// Decode header and transactions.
|
||||||
var head *types.Header
|
var head *types.Header
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// recentCanonicalLength specifies the maximum number of most recent number to hash
|
||||||
|
// associations stored in the recent map
|
||||||
const recentCanonicalLength = 256
|
const recentCanonicalLength = 256
|
||||||
|
|
||||||
// canonicalChainFields defines Client fields related to canonical chain tracking.
|
// canonicalChainFields defines Client fields related to canonical chain tracking.
|
||||||
|
|
@ -40,13 +42,13 @@ type canonicalChainFields struct {
|
||||||
recent map[uint64]common.Hash // nil while head == nil
|
recent map[uint64]common.Hash // nil while head == nil
|
||||||
recentTail uint64 // if recent != nil then recent hashes are available from recentTail to head
|
recentTail uint64 // if recent != nil then recent hashes are available from recentTail to head
|
||||||
tailFetchCh, closeCh chan struct{}
|
tailFetchCh, closeCh chan struct{}
|
||||||
finalized *lru.Cache[uint64, common.Hash] // finalized but not recent hashes
|
cache *lru.Cache[uint64, common.Hash] // older than recentTail
|
||||||
requests *requestMap[uint64, common.Hash] // requested; neither recent nor cached finalized
|
requests *requestMap[uint64, common.Hash] // requested; neither recent nor cached
|
||||||
}
|
}
|
||||||
|
|
||||||
// initCanonicalChain initializes the structures related to canonical chain tracking.
|
// initCanonicalChain initializes the structures related to canonical chain tracking.
|
||||||
func (c *Client) initCanonicalChain() {
|
func (c *Client) initCanonicalChain() {
|
||||||
c.finalized = lru.NewCache[uint64, common.Hash](10000)
|
c.cache = lru.NewCache[uint64, common.Hash](10000)
|
||||||
c.requests = newRequestMap[uint64, common.Hash](nil)
|
c.requests = newRequestMap[uint64, common.Hash](nil)
|
||||||
c.tailFetchCh = make(chan struct{})
|
c.tailFetchCh = make(chan struct{})
|
||||||
c.closeCh = make(chan struct{})
|
c.closeCh = make(chan struct{})
|
||||||
|
|
@ -59,6 +61,8 @@ func (c *Client) closeCanonicalChain() {
|
||||||
close(c.closeCh)
|
close(c.closeCh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setHead sets a new head for the canonical chain. It also updates the recent
|
||||||
|
// hash associations and takes care of state cache invalidation if necessary.
|
||||||
func (c *Client) setHead(head *btypes.ExecutionHeader) bool {
|
func (c *Client) setHead(head *btypes.ExecutionHeader) bool {
|
||||||
c.chainLock.Lock()
|
c.chainLock.Lock()
|
||||||
defer c.chainLock.Unlock()
|
defer c.chainLock.Unlock()
|
||||||
|
|
@ -68,9 +72,15 @@ func (c *Client) setHead(head *btypes.ExecutionHeader) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if c.recent == nil || c.head == nil || c.head.BlockNumber()+1 != headNum || c.head.BlockHash() != head.ParentHash() {
|
if c.recent == nil || c.head == nil || c.head.BlockNumber()+1 != headNum || c.head.BlockHash() != head.ParentHash() {
|
||||||
// initialize recent canonical hash map when first head is added or when
|
// new head is not a descendant of the previous one; everything that was
|
||||||
// it is not a descendant of the previous head
|
// not finalized should be invalidated.
|
||||||
|
if c.finality == nil || c.recentTail > c.finality.BlockNumber()+1 {
|
||||||
|
// purge cache if the previous contents were not all finalized
|
||||||
|
c.cache.Purge()
|
||||||
|
}
|
||||||
|
// state proofs are cached by number
|
||||||
c.clearStateCache()
|
c.clearStateCache()
|
||||||
|
// initialize recent canonical hash map
|
||||||
c.recent = make(map[uint64]common.Hash)
|
c.recent = make(map[uint64]common.Hash)
|
||||||
if headNum > 0 {
|
if headNum > 0 {
|
||||||
c.recent[headNum-1] = head.ParentHash()
|
c.recent[headNum-1] = head.ParentHash()
|
||||||
|
|
@ -82,9 +92,7 @@ func (c *Client) setHead(head *btypes.ExecutionHeader) bool {
|
||||||
c.head = head
|
c.head = head
|
||||||
c.recent[headNum] = headHash
|
c.recent[headNum] = headHash
|
||||||
for headNum >= c.recentTail+recentCanonicalLength {
|
for headNum >= c.recentTail+recentCanonicalLength {
|
||||||
if c.finality != nil && c.recentTail <= c.finality.BlockNumber() {
|
c.cache.Add(c.recentTail, c.recent[c.recentTail])
|
||||||
c.finalized.Add(c.recentTail, c.recent[c.recentTail])
|
|
||||||
}
|
|
||||||
delete(c.recent, c.recentTail)
|
delete(c.recent, c.recentTail)
|
||||||
c.recentTail++
|
c.recentTail++
|
||||||
}
|
}
|
||||||
|
|
@ -93,6 +101,7 @@ func (c *Client) setHead(head *btypes.ExecutionHeader) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setFinality sets a new finality slot.
|
||||||
func (c *Client) setFinality(finality *btypes.ExecutionHeader) {
|
func (c *Client) setFinality(finality *btypes.ExecutionHeader) {
|
||||||
c.chainLock.Lock()
|
c.chainLock.Lock()
|
||||||
defer c.chainLock.Unlock()
|
defer c.chainLock.Unlock()
|
||||||
|
|
@ -100,11 +109,12 @@ func (c *Client) setFinality(finality *btypes.ExecutionHeader) {
|
||||||
c.finality = finality
|
c.finality = finality
|
||||||
finalNum := finality.BlockNumber()
|
finalNum := finality.BlockNumber()
|
||||||
if finalNum < c.recentTail {
|
if finalNum < c.recentTail {
|
||||||
c.finalized.Add(finalNum, finality.BlockHash())
|
c.cache.Add(finalNum, finality.BlockHash())
|
||||||
}
|
}
|
||||||
c.requests.tryDeliver(finalNum, finality.BlockHash())
|
c.requests.tryDeliver(finalNum, finality.BlockHash())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getHead returns the current local canonical chain head.
|
||||||
func (c *Client) getHead() *btypes.ExecutionHeader {
|
func (c *Client) getHead() *btypes.ExecutionHeader {
|
||||||
c.chainLock.Lock()
|
c.chainLock.Lock()
|
||||||
defer c.chainLock.Unlock()
|
defer c.chainLock.Unlock()
|
||||||
|
|
@ -112,6 +122,7 @@ func (c *Client) getHead() *btypes.ExecutionHeader {
|
||||||
return c.head
|
return c.head
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getFinality returns the current finality header
|
||||||
func (c *Client) getFinality() *btypes.ExecutionHeader {
|
func (c *Client) getFinality() *btypes.ExecutionHeader {
|
||||||
c.chainLock.Lock()
|
c.chainLock.Lock()
|
||||||
defer c.chainLock.Unlock()
|
defer c.chainLock.Unlock()
|
||||||
|
|
@ -119,6 +130,8 @@ func (c *Client) getFinality() *btypes.ExecutionHeader {
|
||||||
return c.finality
|
return c.finality
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addRecentTail tries to add the given header to the tail of the recent canonical
|
||||||
|
// section and returns true if successful.
|
||||||
func (c *Client) addRecentTail(tail *types.Header) bool {
|
func (c *Client) addRecentTail(tail *types.Header) bool {
|
||||||
c.chainLock.Lock()
|
c.chainLock.Lock()
|
||||||
defer c.chainLock.Unlock()
|
defer c.chainLock.Unlock()
|
||||||
|
|
@ -136,6 +149,7 @@ func (c *Client) addRecentTail(tail *types.Header) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tailFetcher reverse syncs canonical hashes until all requested items are present.
|
||||||
func (c *Client) tailFetcher() {
|
func (c *Client) tailFetcher() {
|
||||||
for {
|
for {
|
||||||
c.chainLock.Lock()
|
c.chainLock.Lock()
|
||||||
|
|
@ -173,6 +187,7 @@ func (c *Client) tailFetcher() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getHash returns the requested number -> hash association.
|
||||||
func (c *Client) getHash(ctx context.Context, number uint64) (common.Hash, error) {
|
func (c *Client) getHash(ctx context.Context, number uint64) (common.Hash, error) {
|
||||||
if hash, ok := c.getCachedHash(number); ok {
|
if hash, ok := c.getCachedHash(number); ok {
|
||||||
return hash, nil
|
return hash, nil
|
||||||
|
|
@ -186,6 +201,8 @@ func (c *Client) getHash(ctx context.Context, number uint64) (common.Hash, error
|
||||||
return req.waitForResult(ctx)
|
return req.waitForResult(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getCachedHash returns the requested number -> hash association if it is already
|
||||||
|
// in memory cache.
|
||||||
func (c *Client) getCachedHash(number uint64) (common.Hash, bool) {
|
func (c *Client) getCachedHash(number uint64) (common.Hash, bool) {
|
||||||
c.chainLock.Lock()
|
c.chainLock.Lock()
|
||||||
hash, ok := c.recent[number]
|
hash, ok := c.recent[number]
|
||||||
|
|
@ -193,9 +210,11 @@ func (c *Client) getCachedHash(number uint64) (common.Hash, bool) {
|
||||||
if ok {
|
if ok {
|
||||||
return hash, true
|
return hash, true
|
||||||
}
|
}
|
||||||
return c.finalized.Get(number)
|
return c.cache.Get(number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolveBlockNumber resolves an RPC block number into uint64 and also returns
|
||||||
|
// the payload header in case of special (negative) RPC numbers.
|
||||||
func (c *Client) resolveBlockNumber(number *big.Int) (uint64, *btypes.ExecutionHeader, error) {
|
func (c *Client) resolveBlockNumber(number *big.Int) (uint64, *btypes.ExecutionHeader, error) {
|
||||||
if !number.IsInt64() {
|
if !number.IsInt64() {
|
||||||
return 0, nil, errors.New("Invalid block number")
|
return 0, nil, errors.New("Invalid block number")
|
||||||
|
|
@ -220,6 +239,10 @@ func (c *Client) resolveBlockNumber(number *big.Int) (uint64, *btypes.ExecutionH
|
||||||
return uint64(num), nil, nil
|
return uint64(num), nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// blockNumberToHash returns the canonical hash belonging to the given RPC block
|
||||||
|
// number. Note that requesting older canonical hashes might trigger a reverse
|
||||||
|
// header sync process which might take a very long time depending on the age
|
||||||
|
// of the specified block.
|
||||||
func (c *Client) blockNumberToHash(ctx context.Context, number *big.Int) (common.Hash, error) {
|
func (c *Client) blockNumberToHash(ctx context.Context, number *big.Int) (common.Hash, error) {
|
||||||
num, pheader, err := c.resolveBlockNumber(number)
|
num, pheader, err := c.resolveBlockNumber(number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -231,6 +254,7 @@ func (c *Client) blockNumberToHash(ctx context.Context, number *big.Int) (common
|
||||||
return c.getHash(ctx, num)
|
return c.getHash(ctx, num)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// blockNumberOrHashToHash resolves rpc.BlockNumberOrHash into a block hash.
|
||||||
func (c *Client) blockNumberOrHashToHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (common.Hash, error) {
|
func (c *Client) blockNumberOrHashToHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (common.Hash, error) {
|
||||||
if blockNrOrHash.BlockNumber != nil {
|
if blockNrOrHash.BlockNumber != nil {
|
||||||
return c.blockNumberToHash(ctx, big.NewInt(int64(*blockNrOrHash.BlockNumber)))
|
return c.blockNumberToHash(ctx, big.NewInt(int64(*blockNrOrHash.BlockNumber)))
|
||||||
|
|
|
||||||
|
|
@ -370,6 +370,7 @@ func (c *Client) sendTransaction(ctx context.Context, tx *types.Transaction) err
|
||||||
return c.TrackTransaction(tx)
|
return c.TrackTransaction(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TrackTransaction adds a transaction to the set of tracked transactions.
|
||||||
func (c *Client) TrackTransaction(tx *types.Transaction) error {
|
func (c *Client) TrackTransaction(tx *types.Transaction) error {
|
||||||
sender, err := types.Sender(c.signer, tx)
|
sender, err := types.Sender(c.signer, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue