github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/protocols/snap/snapstream/snapleecher/leecher.go (about)

     1  package snapleecher
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sync"
     7  
     8  	u2u "github.com/unicornultrafoundation/go-u2u"
     9  	"github.com/unicornultrafoundation/go-u2u/core/rawdb"
    10  	"github.com/unicornultrafoundation/go-u2u/eth/protocols/snap"
    11  	"github.com/unicornultrafoundation/go-u2u/ethdb"
    12  	"github.com/unicornultrafoundation/go-u2u/trie"
    13  )
    14  
    15  var (
    16  	MaxStateFetch = 384 // Amount of node state values to allow fetching per request
    17  )
    18  
    19  var (
    20  	errTimeout          = errors.New("timeout")
    21  	errCancelStateFetch = errors.New("state data download canceled (requested)")
    22  	errCanceled         = errors.New("syncing canceled (requested)")
    23  )
    24  
    25  type Leecher struct {
    26  	peers *peerSet // Set of active peers from which download can proceed
    27  	// Callbacks
    28  	dropPeer peerDropFn // Drops a peer for misbehaving
    29  
    30  	stateDB    ethdb.Database  // Database to state sync into (and deduplicate via)
    31  	stateBloom *trie.SyncBloom // Bloom filter for fast trie node and contract code existence checks
    32  	SnapSyncer *snap.Syncer    // TODO(karalabe): make private! hack for now
    33  
    34  	stateSyncStart chan *stateSync
    35  	trackStateReq  chan *stateReq
    36  	stateCh        chan dataPack // Channel receiving inbound node state data
    37  
    38  	// Statistics
    39  	syncStatsState stateSyncStats
    40  	syncStatsLock  sync.RWMutex // Lock protecting the sync stats fields
    41  
    42  	// Cancellation and termination
    43  	cancelPeer string         // Identifier of the peer currently being used as the master (cancel on drop)
    44  	cancelCh   chan struct{}  // Channel to cancel mid-flight syncs
    45  	cancelLock sync.RWMutex   // Lock to protect the cancel channel and peer in delivers
    46  	cancelWg   sync.WaitGroup // Make sure all fetcher goroutines have exited.
    47  
    48  	quitCh chan struct{} // Quit channel to signal termination
    49  }
    50  
    51  // New creates a new downloader to fetch hashes and blocks from remote peers.
    52  func New(stateDb ethdb.Database, stateBloom *trie.SyncBloom, dropPeer peerDropFn) *Leecher {
    53  	d := &Leecher{
    54  		stateDB:        stateDb,
    55  		stateBloom:     stateBloom,
    56  		dropPeer:       dropPeer,
    57  		peers:          newPeerSet(),
    58  		quitCh:         make(chan struct{}),
    59  		stateCh:        make(chan dataPack),
    60  		SnapSyncer:     snap.NewSyncer(stateDb),
    61  		stateSyncStart: make(chan *stateSync),
    62  		syncStatsState: stateSyncStats{
    63  			processed: rawdb.ReadFastTrieProgress(stateDb),
    64  		},
    65  		trackStateReq: make(chan *stateReq),
    66  	}
    67  	go d.stateFetcher()
    68  	return d
    69  }
    70  
    71  // cancel aborts all of the operations and resets the queue. However, cancel does
    72  // not wait for the running download goroutines to finish. This method should be
    73  // used when cancelling the downloads from inside the downloader.
    74  func (d *Leecher) cancel() {
    75  	// Close the current cancel channel
    76  	d.cancelLock.Lock()
    77  	defer d.cancelLock.Unlock()
    78  
    79  	if d.cancelCh != nil {
    80  		select {
    81  		case <-d.cancelCh:
    82  			// Channel was already closed
    83  		default:
    84  			close(d.cancelCh)
    85  		}
    86  	}
    87  }
    88  
    89  // DeliverSnapPacket is invoked from a peer's message handler when it transmits a
    90  // data packet for the local node to consume.
    91  func (d *Leecher) DeliverSnapPacket(peer *snap.Peer, packet snap.Packet) error {
    92  	switch packet := packet.(type) {
    93  	case *snap.AccountRangePacket:
    94  		hashes, accounts, err := packet.Unpack()
    95  		if err != nil {
    96  			return err
    97  		}
    98  		return d.SnapSyncer.OnAccounts(peer, packet.ID, hashes, accounts, packet.Proof)
    99  
   100  	case *snap.StorageRangesPacket:
   101  		hashset, slotset := packet.Unpack()
   102  		return d.SnapSyncer.OnStorage(peer, packet.ID, hashset, slotset, packet.Proof)
   103  
   104  	case *snap.ByteCodesPacket:
   105  		return d.SnapSyncer.OnByteCodes(peer, packet.ID, packet.Codes)
   106  
   107  	case *snap.TrieNodesPacket:
   108  		return d.SnapSyncer.OnTrieNodes(peer, packet.ID, packet.Nodes)
   109  
   110  	default:
   111  		return fmt.Errorf("unexpected snap packet type: %T", packet)
   112  	}
   113  }
   114  
   115  // Progress retrieves the synchronisation boundaries, specifically the origin
   116  // block where synchronisation started at (may have failed/suspended); the block
   117  // or header sync is currently at; and the latest known block which the sync targets.
   118  //
   119  // In addition, during the state download phase of fast synchronisation the number
   120  // of processed and the total number of known states are also returned. Otherwise
   121  // these are zero.
   122  func (d *Leecher) Progress() u2u.SyncProgress {
   123  	// Lock the current stats and return the progress
   124  	d.syncStatsLock.RLock()
   125  	defer d.syncStatsLock.RUnlock()
   126  
   127  	return u2u.SyncProgress{
   128  		PulledStates: d.syncStatsState.processed,
   129  		KnownStates:  d.syncStatsState.processed + d.syncStatsState.pending,
   130  	}
   131  }