@@ -36,30 +36,33 @@ import (
3636 "github.com/ethereum/go-ethereum/eth/gasprice"
3737 "github.com/ethereum/go-ethereum/event"
3838 "github.com/ethereum/go-ethereum/internal/ethapi"
39+ "github.com/ethereum/go-ethereum/les/vflux"
3940 vfc "github.com/ethereum/go-ethereum/les/vflux/client"
4041 "github.com/ethereum/go-ethereum/light"
4142 "github.com/ethereum/go-ethereum/log"
4243 "github.com/ethereum/go-ethereum/node"
4344 "github.com/ethereum/go-ethereum/p2p"
4445 "github.com/ethereum/go-ethereum/p2p/enode"
46+ "github.com/ethereum/go-ethereum/p2p/enr"
4547 "github.com/ethereum/go-ethereum/params"
48+ "github.com/ethereum/go-ethereum/rlp"
4649 "github.com/ethereum/go-ethereum/rpc"
4750)
4851
4952type LightEthereum struct {
5053 lesCommons
5154
52- peers * serverPeerSet
53- reqDist * requestDistributor
54- retriever * retrieveManager
55- odr * LesOdr
56- relay * lesTxRelay
57- handler * clientHandler
58- txPool * light.TxPool
59- blockchain * light.LightChain
60- serverPool * vfc.ServerPool
61- dialCandidates enode.Iterator
62- pruner * pruner
55+ peers * serverPeerSet
56+ reqDist * requestDistributor
57+ retriever * retrieveManager
58+ odr * LesOdr
59+ relay * lesTxRelay
60+ handler * clientHandler
61+ txPool * light.TxPool
62+ blockchain * light.LightChain
63+ serverPool * vfc.ServerPool
64+ serverPoolIterator enode.Iterator
65+ pruner * pruner
6366
6467 bloomRequests chan chan * bloombits.Retrieval // Channel receiving bloom data retrieval requests
6568 bloomIndexer * core.ChainIndexer // Bloom indexer operating during block imports
@@ -112,7 +115,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) {
112115 p2pConfig : & stack .Config ().P2P ,
113116 }
114117
115- leth .serverPool , leth .dialCandidates = vfc .NewServerPool (lesDb , []byte ("serverpool:" ), time .Second , nil , & mclock.System {}, config .UltraLightServers , requestList )
118+ leth .serverPool , leth .serverPoolIterator = vfc .NewServerPool (lesDb , []byte ("serverpool:" ), time .Second , leth . prenegQuery , & mclock.System {}, config .UltraLightServers , requestList )
116119 leth .serverPool .AddMetrics (suggestedTimeoutGauge , totalValueGauge , serverSelectableGauge , serverConnectedGauge , sessionValueMeter , serverDialedMeter )
117120
118121 leth .retriever = newRetrieveManager (peers , leth .reqDist , leth .serverPool .GetTimeout )
@@ -189,6 +192,62 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) {
189192 return leth , nil
190193}
191194
195+ // VfluxRequest sends a batch of requests to the given node through discv5 UDP TalkRequest and returns the responses
196+ func (s * LightEthereum ) VfluxRequest (n * enode.Node , reqs vflux.Requests ) vflux.Replies {
197+ reqsEnc , _ := rlp .EncodeToBytes (& reqs )
198+ repliesEnc , _ := s .p2pServer .DiscV5 .TalkRequest (s .serverPool .DialNode (n ), "vfx" , reqsEnc )
199+ var replies vflux.Replies
200+ if len (repliesEnc ) == 0 || rlp .DecodeBytes (repliesEnc , & replies ) != nil {
201+ return nil
202+ }
203+ return replies
204+ }
205+
206+ // vfxVersion returns the version number of the "les" service subdomain of the vflux UDP
207+ // service, as advertised in the ENR record
208+ func (s * LightEthereum ) vfxVersion (n * enode.Node ) uint {
209+ if n .Seq () == 0 {
210+ var err error
211+ if n , err = s .p2pServer .DiscV5 .RequestENR (n ); n != nil && err == nil && n .Seq () != 0 {
212+ s .serverPool .Persist (n )
213+ } else {
214+ return 0
215+ }
216+ }
217+
218+ var les []rlp.RawValue
219+ if err := n .Load (enr .WithEntry ("les" , & les )); err != nil || len (les ) < 1 {
220+ return 0
221+ }
222+ var version uint
223+ rlp .DecodeBytes (les [0 ], & version ) // Ignore additional fields (for forward compatibility).
224+ return version
225+ }
226+
227+ // prenegQuery sends a capacity query to the given server node to determine whether
228+ // a connection slot is immediately available
229+ func (s * LightEthereum ) prenegQuery (n * enode.Node ) int {
230+ if s .vfxVersion (n ) < 1 {
231+ // UDP query not supported, always try TCP connection
232+ return 1
233+ }
234+
235+ var requests vflux.Requests
236+ requests .Add ("les" , vflux .CapacityQueryName , vflux.CapacityQueryReq {
237+ Bias : 180 ,
238+ AddTokens : []vflux.IntOrInf {{}},
239+ })
240+ replies := s .VfluxRequest (n , requests )
241+ var cqr vflux.CapacityQueryReply
242+ if replies .Get (0 , & cqr ) != nil || len (cqr ) != 1 { // Note: Get returns an error if replies is nil
243+ return - 1
244+ }
245+ if cqr [0 ] > 0 {
246+ return 1
247+ }
248+ return 0
249+ }
250+
192251type LightDummyAPI struct {}
193252
194253// Etherbase is the address that mining rewards will be send to
@@ -269,7 +328,7 @@ func (s *LightEthereum) Protocols() []p2p.Protocol {
269328 return p .Info ()
270329 }
271330 return nil
272- }, s .dialCandidates )
331+ }, s .serverPoolIterator )
273332}
274333
275334// Start implements node.Lifecycle, starting all internal goroutines needed by the
0 commit comments