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 }