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  }