github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/vntp2p/discovery.go (about) 1 // Copyright 2019 The go-vnt Authors 2 // This file is part of the go-vnt library. 3 // 4 // The go-vnt library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-vnt library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-vnt library. If not, see <http://www.gnu.org/licenses/>. 16 17 package vntp2p 18 19 import ( 20 "context" 21 "crypto/rand" 22 "sync" 23 "time" 24 25 util "github.com/ipfs/go-ipfs-util" 26 dht "github.com/libp2p/go-libp2p-kad-dht" 27 peer "github.com/libp2p/go-libp2p-peer" 28 routing "github.com/libp2p/go-libp2p-routing" 29 "github.com/vntchain/go-vnt/log" 30 ) 31 32 const ( 33 refreshInterval = 30 * time.Second 34 searchTimeOut = 1 * time.Minute 35 ) 36 37 type DhtTable interface { 38 Start(ctx context.Context) error 39 Lookup(ctx context.Context, targetID NodeID) []*NodeID 40 Update(ctx context.Context, id peer.ID) error 41 RandomPeer() []peer.ID 42 GetDhtTable() *dht.IpfsDHT 43 } 44 45 type VNTDht struct { 46 mutex sync.Mutex 47 table *dht.IpfsDHT 48 self peer.ID 49 } 50 51 func NewDHTTable(dht *dht.IpfsDHT, id peer.ID) *VNTDht { 52 return &VNTDht{ 53 table: dht, 54 self: id, 55 } 56 } 57 58 func (vdht *VNTDht) Start(ctx context.Context) error { 59 var bootStrapConfig = dht.DefaultBootstrapConfig 60 bootStrapConfig.Period = time.Duration(refreshInterval) 61 bootStrapConfig.Timeout = time.Duration(searchTimeOut) 62 proc, err := vdht.table.BootstrapWithConfig(bootStrapConfig) 63 if err != nil { 64 log.Debug("Start refresh k-bucket error", "error", err) 65 return err 66 } 67 68 // wait till ctx or dht.Context exits. 69 // we have to do it this way to satisfy the Routing interface (contexts) 70 go func() { 71 defer proc.Close() 72 select { 73 case <-ctx.Done(): 74 case <-vdht.table.Context().Done(): 75 } 76 }() 77 78 return nil 79 } 80 81 func (vdht *VNTDht) Update(ctx context.Context, id peer.ID) error { 82 vdht.table.Update(ctx, id) 83 return nil 84 } 85 86 func randomID() peer.ID { 87 id := make([]byte, 16) 88 rand.Read(id) 89 id = util.Hash(id) 90 91 // var aid NodeID 92 // copy(aid, id) 93 return peer.ID(id) 94 } 95 96 func (vdht *VNTDht) Lookup(ctx context.Context, targetID NodeID) []*NodeID { 97 // vdht.table.GetClosestPeers(vdht.Context, ) 98 99 results := vdht.lookup(ctx, targetID.PeerID()) 100 101 nodeids := []*NodeID{} 102 103 for _, result := range results { 104 nodeid := PeerIDtoNodeID(result) 105 nodeids = append(nodeids, &nodeid) 106 } 107 108 return nodeids 109 } 110 111 func (vdht *VNTDht) lookup(ctx context.Context, targetid peer.ID) []peer.ID { 112 // 开始搜寻 113 114 // fmt.Println("Begin Lookup") 115 cctx, cancel := context.WithTimeout(ctx, searchTimeOut) 116 defer cancel() 117 118 runQuery := func(ctxs context.Context, id peer.ID) { 119 p, err := vdht.table.FindPeer(ctxs, id) 120 if err == routing.ErrNotFound { 121 } else if err != nil { 122 log.Debug("lookup peer occurs error", "error", err) 123 } else { 124 log.Debug("lookup peer find peer", "id", id.ToString(), "peer", p.ID.ToString()) 125 } 126 } 127 128 runQuery(cctx, targetid) 129 130 return nil 131 } 132 133 func (vdht *VNTDht) doRefresh(ctx context.Context, done chan struct{}) { 134 // defer close(done) 135 136 // Load nodes from the database and insert 137 // them. This should yield a few previously seen nodes that are 138 // (hopefully) still alive. 139 // tab.loadSeedNodes(true) 140 141 // Run self lookup to discover new neighbor nodes. 142 // fmt.Println("@@@CCCC find my self", vdht.self) 143 vdht.lookup(ctx, vdht.self) 144 145 // The Kademlia paper specifies that the bucket refresh should 146 // perform a lookup in the least recently used bucket. We cannot 147 // adhere to this because the findnode target is a 512bit value 148 // (not hash-sized) and it is not easily possible to generate a 149 // sha3 preimage that falls into a chosen bucket. 150 // We perform a few lookups with a random target instead. 151 for i := 0; i < 3; i++ { 152 target := randomID() 153 // fmt.Println("random id: ", target) 154 vdht.lookup(ctx, target) 155 } 156 } 157 158 func (vdht *VNTDht) RandomPeer() []peer.ID { 159 return vdht.table.GetRandomPeers() 160 } 161 162 func (vdht *VNTDht) GetDhtTable() *dht.IpfsDHT { 163 return vdht.table 164 }