mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22: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()
|
||||
}
|
||||
|
||||
// getHeader returns the header with the given block hash.
|
||||
func (c *Client) getHeader(ctx context.Context, hash common.Hash) (*types.Header, error) {
|
||||
if header, ok := c.headerCache.Get(hash); ok {
|
||||
return header, nil
|
||||
|
|
@ -84,15 +85,25 @@ func (c *Client) getHeader(ctx context.Context, hash common.Hash) (*types.Header
|
|||
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 {
|
||||
pheader, _ := c.payloadHeaderCache.Get(hash)
|
||||
return pheader
|
||||
}
|
||||
|
||||
// addPayloadHeader caches the given payload header.
|
||||
func (c *Client) addPayloadHeader(header *btypes.ExecutionHeader) {
|
||||
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) {
|
||||
if block, ok := c.blockCache.Get(hash); ok {
|
||||
return block, nil
|
||||
|
|
@ -149,7 +160,8 @@ func (c *Client) requestBlock(ctx context.Context, hash common.Hash) (*types.Blo
|
|||
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) {
|
||||
// Decode header and transactions.
|
||||
var head *types.Header
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ import (
|
|||
"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
|
||||
|
||||
// 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
|
||||
recentTail uint64 // if recent != nil then recent hashes are available from recentTail to head
|
||||
tailFetchCh, closeCh chan struct{}
|
||||
finalized *lru.Cache[uint64, common.Hash] // finalized but not recent hashes
|
||||
requests *requestMap[uint64, common.Hash] // requested; neither recent nor cached finalized
|
||||
cache *lru.Cache[uint64, common.Hash] // older than recentTail
|
||||
requests *requestMap[uint64, common.Hash] // requested; neither recent nor cached
|
||||
}
|
||||
|
||||
// initCanonicalChain initializes the structures related to canonical chain tracking.
|
||||
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.tailFetchCh = make(chan struct{})
|
||||
c.closeCh = make(chan struct{})
|
||||
|
|
@ -59,6 +61,8 @@ func (c *Client) closeCanonicalChain() {
|
|||
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 {
|
||||
c.chainLock.Lock()
|
||||
defer c.chainLock.Unlock()
|
||||
|
|
@ -68,9 +72,15 @@ func (c *Client) setHead(head *btypes.ExecutionHeader) bool {
|
|||
return false
|
||||
}
|
||||
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
|
||||
// it is not a descendant of the previous head
|
||||
// new head is not a descendant of the previous one; everything that was
|
||||
// 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()
|
||||
// initialize recent canonical hash map
|
||||
c.recent = make(map[uint64]common.Hash)
|
||||
if headNum > 0 {
|
||||
c.recent[headNum-1] = head.ParentHash()
|
||||
|
|
@ -82,9 +92,7 @@ func (c *Client) setHead(head *btypes.ExecutionHeader) bool {
|
|||
c.head = head
|
||||
c.recent[headNum] = headHash
|
||||
for headNum >= c.recentTail+recentCanonicalLength {
|
||||
if c.finality != nil && c.recentTail <= c.finality.BlockNumber() {
|
||||
c.finalized.Add(c.recentTail, c.recent[c.recentTail])
|
||||
}
|
||||
c.cache.Add(c.recentTail, c.recent[c.recentTail])
|
||||
delete(c.recent, c.recentTail)
|
||||
c.recentTail++
|
||||
}
|
||||
|
|
@ -93,6 +101,7 @@ func (c *Client) setHead(head *btypes.ExecutionHeader) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// setFinality sets a new finality slot.
|
||||
func (c *Client) setFinality(finality *btypes.ExecutionHeader) {
|
||||
c.chainLock.Lock()
|
||||
defer c.chainLock.Unlock()
|
||||
|
|
@ -100,11 +109,12 @@ func (c *Client) setFinality(finality *btypes.ExecutionHeader) {
|
|||
c.finality = finality
|
||||
finalNum := finality.BlockNumber()
|
||||
if finalNum < c.recentTail {
|
||||
c.finalized.Add(finalNum, finality.BlockHash())
|
||||
c.cache.Add(finalNum, finality.BlockHash())
|
||||
}
|
||||
c.requests.tryDeliver(finalNum, finality.BlockHash())
|
||||
}
|
||||
|
||||
// getHead returns the current local canonical chain head.
|
||||
func (c *Client) getHead() *btypes.ExecutionHeader {
|
||||
c.chainLock.Lock()
|
||||
defer c.chainLock.Unlock()
|
||||
|
|
@ -112,6 +122,7 @@ func (c *Client) getHead() *btypes.ExecutionHeader {
|
|||
return c.head
|
||||
}
|
||||
|
||||
// getFinality returns the current finality header
|
||||
func (c *Client) getFinality() *btypes.ExecutionHeader {
|
||||
c.chainLock.Lock()
|
||||
defer c.chainLock.Unlock()
|
||||
|
|
@ -119,6 +130,8 @@ func (c *Client) getFinality() *btypes.ExecutionHeader {
|
|||
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 {
|
||||
c.chainLock.Lock()
|
||||
defer c.chainLock.Unlock()
|
||||
|
|
@ -136,6 +149,7 @@ func (c *Client) addRecentTail(tail *types.Header) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// tailFetcher reverse syncs canonical hashes until all requested items are present.
|
||||
func (c *Client) tailFetcher() {
|
||||
for {
|
||||
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) {
|
||||
if hash, ok := c.getCachedHash(number); ok {
|
||||
return hash, nil
|
||||
|
|
@ -186,6 +201,8 @@ func (c *Client) getHash(ctx context.Context, number uint64) (common.Hash, error
|
|||
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) {
|
||||
c.chainLock.Lock()
|
||||
hash, ok := c.recent[number]
|
||||
|
|
@ -193,9 +210,11 @@ func (c *Client) getCachedHash(number uint64) (common.Hash, bool) {
|
|||
if ok {
|
||||
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) {
|
||||
if !number.IsInt64() {
|
||||
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
|
||||
}
|
||||
|
||||
// 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) {
|
||||
num, pheader, err := c.resolveBlockNumber(number)
|
||||
if err != nil {
|
||||
|
|
@ -231,6 +254,7 @@ func (c *Client) blockNumberToHash(ctx context.Context, number *big.Int) (common
|
|||
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) {
|
||||
if blockNrOrHash.BlockNumber != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
// TrackTransaction adds a transaction to the set of tracked transactions.
|
||||
func (c *Client) TrackTransaction(tx *types.Transaction) error {
|
||||
sender, err := types.Sender(c.signer, tx)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue