github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/vntp2p/host.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 "encoding/hex" 22 "encoding/json" 23 "path/filepath" 24 "time" 25 // "crypto/rand" 26 // "flag" 27 "net" 28 "strings" 29 30 "crypto/ecdsa" 31 32 ds "github.com/ipfs/go-datastore" 33 libp2p "github.com/libp2p/go-libp2p" 34 pstore "github.com/libp2p/go-libp2p-peerstore" 35 "github.com/vntchain/go-vnt/crypto" 36 "github.com/whyrusleeping/base32" 37 // crypto "github.com/libp2p/go-libp2p-crypto" 38 p2phost "github.com/libp2p/go-libp2p-host" 39 dht "github.com/libp2p/go-libp2p-kad-dht" 40 dhtopts "github.com/libp2p/go-libp2p-kad-dht/opts" 41 // net "github.com/libp2p/go-libp2p-net" 42 peer "github.com/libp2p/go-libp2p-peer" 43 ma "github.com/multiformats/go-multiaddr" 44 manet "github.com/multiformats/go-multiaddr-net" 45 "github.com/vntchain/go-vnt/log" 46 47 // "github.com/vntchain/go-vnt/crypto" 48 49 "fmt" 50 // "strconv" 51 // "runtime/debug" 52 // "strings" 53 // "io" 54 // "io/ioutil" 55 ) 56 57 const ( 58 // PID vnt protocol basic id 59 PID = "/p2p/1.0.0" 60 persistDataInterval = 10 * time.Second 61 ) 62 63 const BootnodeCon = 1 64 65 type blankValidator struct{} 66 67 func (blankValidator) Validate(_ string, _ []byte) error { return nil } 68 func (blankValidator) Select(_ string, _ [][]byte) (int, error) { return 0, nil } 69 70 func recoverPersistentData(vdb *LevelDB) *dht.PersistentData { 71 pd := &dht.PersistentData{} 72 pdKey := ds.NewKey(base32.RawStdEncoding.EncodeToString([]byte("/PersistentData"))) 73 pdValue, err := vdb.Get(pdKey) 74 if err != nil { 75 // don't need to care about err != nil 76 return nil 77 } 78 //fmt.Printf("R- pdValue = %v\n", pdValue.([]byte)) 79 err = json.Unmarshal(pdValue.([]byte), pd) 80 if err != nil { 81 log.Error("recoverPersistentData", "unmarshal pd error", err) 82 return nil 83 } 84 return pd 85 } 86 87 // ConstructDHT create Kademlia DHT 88 func ConstructDHT(ctx context.Context, listenstring string, nodekey *ecdsa.PrivateKey, datadir string, restrictList []*net.IPNet, natm libp2p.Option) (*dht.IpfsDHT, p2phost.Host, error) { 89 90 var pd *dht.PersistentData 91 var vntp2pDB *LevelDB 92 var err error 93 // if datadir is empty, it means don't need persistentation 94 if datadir != "" { 95 dbpath := filepath.Join(datadir, "vntdb") 96 vntp2pDB, err = GetDatastore(dbpath) 97 if err != nil { 98 log.Error("ConstructDHT", "getDatastore error", err, "dbpath", dbpath) 99 return nil, nil, err 100 } 101 pd = recoverPersistentData(vntp2pDB) 102 } 103 if nodekey == nil && pd != nil { 104 // try to recover nodekey from database 105 k := string(pd.PrivKey) 106 bDump, err := hex.DecodeString(k) 107 if err != nil { 108 log.Error("ConstructDHT", "decode key error", err) 109 return nil, nil, err 110 } 111 privKey, err := crypto.ToECDSA(bDump) 112 if err != nil { 113 log.Error("ConstructDHT", "toECDSA error", err) 114 return nil, nil, err 115 } 116 nodekey = privKey 117 } // host private key recover finished 118 119 host, err := constructPeerHost(ctx, listenstring, nodekey, restrictList, natm) 120 if err != nil { 121 log.Error("ConstructDHT", "constructPeerHost error", err) 122 return nil, nil, err 123 } 124 125 var vdht *dht.IpfsDHT 126 127 if vntp2pDB != nil { 128 vdht, err = dht.New( 129 ctx, host, 130 dhtopts.NamespacedValidator("v", blankValidator{}), 131 dhtopts.Datastore(vntp2pDB), 132 ) 133 } else { 134 vdht, err = dht.New( 135 ctx, host, 136 dhtopts.NamespacedValidator("v", blankValidator{}), 137 ) 138 } 139 140 hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", host.ID().Pretty())) 141 142 addr := host.Addrs()[0] 143 fullAddr := addr.Encapsulate(hostAddr) 144 log.Info("ConstructDHT", "addr", fullAddr) 145 146 // fmt.Println("TEST: ", ip) 147 148 if pd != nil { 149 recoverPeerInfosAndBuckets(ctx, pd, host, vdht) 150 } 151 152 if vntp2pDB != nil { 153 go loop(vdht) 154 } 155 156 return vdht, host, err 157 } 158 159 // some loop handler for p2p itself can be put here 160 func loop(vdht *dht.IpfsDHT) { 161 var persistData = time.NewTicker(persistDataInterval) 162 for { 163 <-persistData.C 164 go persistDataPeriodly(vdht) 165 } 166 } 167 168 // persist data unified entrance, both for bootnode and membernode 169 func persistDataPeriodly(vdht *dht.IpfsDHT) { 170 pd := vdht.GetPersistentData() 171 /* fmt.Printf("host privKey is: %v \n", string(pd.PrivKey)) 172 fmt.Printf("peerInfos is: \n") 173 for i := range pd.PeerInfos { 174 fmt.Printf("-->peerID = %v, peerAddr = %v\n", pd.PeerInfos[i].ID, pd.PeerInfos[i].Addrs) 175 } 176 fmt.Printf("buckets is: \n") 177 for i := range pd.KBuckets { 178 fmt.Println("----> real e:", pd.KBuckets[i]) 179 } */ 180 pdByte, err := json.Marshal(pd) 181 if err != nil { 182 log.Error("persistDataPeriodly", "marshal error", err) 183 return 184 } 185 //log.Info("persistDataPeriodly TIME TO PERSIST DATA") 186 vdht.SaveData("/PersistentData", pdByte) 187 } 188 189 func recoverPeerInfosAndBuckets(ctx context.Context, pd *dht.PersistentData, host p2phost.Host, vdht *dht.IpfsDHT) { 190 191 /* fmt.Printf("R- host privKey is: %v \n", string(pd.PrivKey)) 192 fmt.Printf("R- peerInfos is: \n") 193 for i := range pd.PeerInfos { 194 fmt.Printf("R- -->peerID = %v, peerAddr = %v\n", pd.PeerInfos[i].ID, pd.PeerInfos[i].Addrs) 195 } 196 fmt.Printf("R- buckets is: \n") 197 for i := range pd.KBuckets { 198 fmt.Println("R- ----> real e:", pd.KBuckets[i]) 199 } */ 200 201 for i := range pd.PeerInfos { 202 host.Peerstore().AddAddrs(pd.PeerInfos[i].ID, pd.PeerInfos[i].Addrs, pstore.PermanentAddrTTL) 203 } 204 for i := range pd.KBuckets { 205 vdht.Update(ctx, pd.KBuckets[i]) 206 } 207 } 208 209 func constructPeerHost(ctx context.Context, listenstring string, nodekey *ecdsa.PrivateKey, restrictList []*net.IPNet, natm libp2p.Option) (p2phost.Host, error) { 210 var options []libp2p.Option 211 if nodekey != nil { 212 options = append(options, libp2p.ListenAddrStrings(listenstring), libp2p.Identity(nodekey)) 213 } else { 214 options = append(options, libp2p.ListenAddrStrings(listenstring)) 215 } 216 217 options = append(options, libp2p.FilterAddresses(restrictList)) 218 if natm != nil { 219 options = append(options, natm) 220 } 221 222 return libp2p.New(ctx, options...) 223 } 224 225 func MakePort(port string) string { 226 227 return "/ip4/0.0.0.0/tcp/" + port 228 } 229 230 func GetIPfromAddr(a ma.Multiaddr) string { 231 // TODO: 232 // 将ma地址转换为可读的IP 233 234 _, ip, _ := manet.DialArgs(a) 235 236 return strings.Split(ip, ":")[0] 237 } 238 239 func GetAddr(target string) (ma.Multiaddr, peer.ID, error) { 240 ipfsaddr, err := ma.NewMultiaddr(target) 241 if err != nil { 242 log.Error("GetAddr", "NewMultiaddr Err", err) 243 return nil, "", err 244 } 245 246 pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS) 247 if err != nil { 248 log.Error("GetAddr", "ValueForProtocol Err", err) 249 return nil, "", err 250 } 251 252 peerid, err := peer.IDB58Decode(pid) 253 if err != nil { 254 log.Error("GetAddr", "IDB58Decode Err", err) 255 return nil, "", err 256 } 257 258 // Decapsulate the /ipfs/<peerID> part from the target 259 // /ip4/<a.b.c.d>/ipfs/<peer> becomes /ip4/<a.b.c.d> 260 targetPeerAddr, _ := ma.NewMultiaddr( 261 fmt.Sprintf("/ipfs/%s", peer.IDB58Encode(peerid))) 262 targetAddr := ipfsaddr.Decapsulate(targetPeerAddr) 263 264 return targetAddr, peerid, nil 265 } 266 267 func ParseNetlist(s string) ([]*net.IPNet, error) { 268 ws := strings.NewReplacer(" ", "", "\n", "", "\t", "") 269 masks := strings.Split(ws.Replace(s), ",") 270 l := []*net.IPNet{} 271 for _, mask := range masks { 272 if mask == "" { 273 continue 274 } 275 // n := net.ParseIP(mask) 276 _, n, err := net.ParseCIDR(mask) 277 if err != nil { 278 return nil, err 279 } 280 l = append(l, n) 281 } 282 283 return l, nil 284 } 285 286 func NATParse(spec string) (libp2p.Option, error) { 287 switch spec { 288 case "", "none", "off": 289 return nil, nil 290 case "any": 291 return libp2p.NATPortMap(), nil 292 default: 293 return nil, fmt.Errorf("unknow mechanism") 294 } 295 }