github.com/holochain/holochain-proto@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/node.go (about) 1 // Copyright (C) 2013-2017, The MetaCurrency Project (Eric Harris-Braun, Arthur Brock, et. al.) 2 // Use of this source code is governed by GPLv3 found in the LICENSE file 3 //---------------------------------------------------------------------------------------- 4 5 // node implements ipfs network transport for communicating between holochain nodes 6 7 package holochain 8 9 import ( 10 "context" 11 // host "github.com/libp2p/go-libp2p-host" 12 "encoding/gob" 13 "errors" 14 "fmt" 15 16 . "github.com/holochain/holochain-proto/hash" 17 goprocess "github.com/jbenet/goprocess" 18 goprocessctx "github.com/jbenet/goprocess/context" 19 ic "github.com/libp2p/go-libp2p-crypto" 20 nat "github.com/libp2p/go-libp2p-nat" 21 net "github.com/libp2p/go-libp2p-net" 22 peer "github.com/libp2p/go-libp2p-peer" 23 pstore "github.com/libp2p/go-libp2p-peerstore" 24 protocol "github.com/libp2p/go-libp2p-protocol" 25 swarm "github.com/libp2p/go-libp2p-swarm" 26 discovery "github.com/libp2p/go-libp2p/p2p/discovery" 27 bhost "github.com/libp2p/go-libp2p/p2p/host/basic" 28 rhost "github.com/libp2p/go-libp2p/p2p/host/routed" 29 ma "github.com/multiformats/go-multiaddr" 30 mh "github.com/multiformats/go-multihash" 31 "gopkg.in/mgo.v2/bson" 32 "io" 33 "math/big" 34 "math/rand" 35 go_net "net" 36 "strconv" 37 "strings" 38 "sync" 39 "time" 40 ) 41 42 type ReceiverFn func(h *Holochain, m *Message) (response interface{}, err error) 43 44 type MsgType int8 45 46 // @TODO don't have order dependant constants 47 // https://github.com/holochain/holochain-proto/issues/713 48 const ( 49 // common messages 50 51 ERROR_RESPONSE MsgType = iota 52 OK_RESPONSE 53 54 // DHT messages 55 56 PUT_REQUEST 57 DEL_REQUEST 58 MOD_REQUEST 59 GET_REQUEST 60 LINK_REQUEST 61 GETLINK_REQUEST 62 DELETELINK_REQUEST 63 64 // Gossip messages 65 66 GOSSIP_REQUEST 67 68 // Validate Messages 69 70 VALIDATE_PUT_REQUEST 71 VALIDATE_LINK_REQUEST 72 VALIDATE_DEL_REQUEST 73 VALIDATE_MOD_REQUEST 74 75 // Application Messages 76 77 APP_MESSAGE 78 79 // Peer messages 80 81 LISTADD_REQUEST 82 83 // Kademlia messages 84 85 FIND_NODE_REQUEST 86 ) 87 88 func (msgType MsgType) String() string { 89 return []string{"ERROR_RESPONSE", 90 "OK_RESPONSE", 91 "PUT_REQUEST", 92 "DEL_REQUEST", 93 "MOD_REQUEST", 94 "GET_REQUEST", 95 "LINK_REQUEST", 96 "GETLINK_REQUEST", 97 "DELETELINK_REQUEST", 98 "GOSSIP_REQUEST", 99 "VALIDATE_PUT_REQUEST", 100 "VALIDATE_LINK_REQUEST", 101 "VALIDATE_DEL_REQUEST", 102 "VALIDATE_MOD_REQUEST", 103 "APP_MESSAGE", 104 "LISTADD_REQUEST", 105 "FIND_NODE_REQUEST"}[msgType] 106 } 107 108 var ErrBlockedListed = errors.New("node blockedlisted") 109 110 // Message represents data that can be sent to node in the network 111 type Message struct { 112 Type MsgType 113 Time time.Time 114 From peer.ID 115 Body interface{} 116 } 117 118 type BytesSent struct { 119 Bytes int64 120 MsgType MsgType 121 } 122 123 var BytesSentChan chan BytesSent 124 125 const ( 126 RetryingStopper = iota 127 GossipingStopper 128 BootstrappingStopper 129 RefreshingStopper 130 HoldingStopper 131 _StopperCount 132 ) 133 134 // Node represents a node in the network 135 type Node struct { 136 HashAddr peer.ID 137 NetAddr ma.Multiaddr 138 host *rhost.RoutedHost 139 mdnsSvc discovery.Service 140 blockedlist map[peer.ID]bool 141 protocols [_protocolCount]*Protocol 142 peerstore pstore.Peerstore 143 routingTable *RoutingTable 144 nat *nat.NAT 145 log *Logger 146 147 // ticker task stoppers 148 stoppers []chan bool 149 150 // items for the kademlia implementation 151 plk sync.Mutex 152 peers map[peer.ID]*peerTracker 153 ctx context.Context 154 proc goprocess.Process 155 } 156 157 // Protocol encapsulates data for our different protocols 158 type Protocol struct { 159 ID protocol.ID 160 Receiver ReceiverFn 161 } 162 163 const ( 164 ActionProtocol = iota 165 ValidateProtocol 166 GossipProtocol 167 KademliaProtocol 168 _protocolCount 169 ) 170 171 const ( 172 PeerTTL = time.Minute * 10 173 DefaultRoutingRefreshInterval = time.Minute 174 DefaultGossipInterval = time.Second * 2 175 DefaultHoldingCheckInterval = time.Second * 30 176 ) 177 178 // implement peer found function for mdns discovery 179 func (h *Holochain) HandlePeerFound(pi pstore.PeerInfo) { 180 if h.dht != nil { 181 h.dht.dlog.Logf("discovered peer via mdns: %v", pi) 182 err := h.AddPeer(pi) 183 if err != nil { 184 h.dht.dlog.Logf("error when adding peer: %v, %v", pi, err) 185 } 186 } 187 } 188 189 func (h *Holochain) getNodePubKey(ID peer.ID) (pubKey ic.PubKey, err error) { 190 req := GetReq{H: HashFromPeerID(ID), GetMask: GetMaskEntry} 191 var rsp interface{} 192 rsp, err = callGet(h, req, &GetOptions{GetMask: req.GetMask}) 193 if err != nil { 194 return 195 } 196 e := rsp.(GetResp).Entry 197 pubKey, err = DecodePubKey(e.Content().(string)) 198 if err != nil { 199 return 200 } 201 var pkID peer.ID 202 pkID, err = peer.IDFromPublicKey(pubKey) 203 if err != nil { 204 return 205 } 206 if pkID != ID { 207 err = errors.New("Public Key doesn't match Node ID!") 208 return 209 } 210 return 211 } 212 213 func (h *Holochain) addPeer(pi pstore.PeerInfo, confirm bool) (err error) { 214 // add the peer into the peerstore 215 h.node.peerstore.AddAddrs(pi.ID, pi.Addrs, PeerTTL) 216 217 // attempt a connection to see if this is actually valid 218 if confirm { 219 err = h.node.host.Connect(h.node.ctx, pi) 220 } 221 if err != nil { 222 h.dht.dlog.Logf("Clearing peer %v, connection failed (%v)\n", pi.ID, err) 223 h.node.peerstore.ClearAddrs(pi.ID) 224 err = nil 225 } else { 226 bootstrap := h.node.routingTable.IsEmpty() 227 h.dht.dlog.Logf("Adding Peer: %v\n", pi.ID) 228 h.node.routingTable.Update(pi.ID) 229 err = h.dht.AddGossiper(pi.ID) 230 if err != nil { 231 return 232 } 233 if bootstrap { 234 RoutingRefreshTask(h) 235 } 236 237 var pubKey ic.PubKey 238 if confirm { 239 pubKey, err = h.getNodePubKey(pi.ID) 240 if err != nil { 241 return 242 } 243 } 244 if h.Config.EnableWorldModel { 245 h.world.AddNode(pi, pubKey) 246 } 247 } 248 249 return 250 } 251 252 // RoutingRefreshTask fills the routing table by searching for a random node 253 func RoutingRefreshTask(h *Holochain) { 254 s := fmt.Sprintf("%d", rand.Intn(1000000)) 255 var hash Hash 256 hash, err := Sum(h.hashSpec, []byte(s)) 257 if err == nil { 258 h.node.FindPeer(h.node.ctx, PeerIDFromHash(hash)) 259 } 260 } 261 262 func (node *Node) isPeerActive(id peer.ID) bool { 263 // inactive currently defined by seeing if there are any addrs in the 264 // peerstore 265 // TODO: should be something different 266 addrs := node.peerstore.Addrs(id) 267 return len(addrs) > 0 268 } 269 270 // filterInactviePeers removes peers from a list who are currently inactive 271 // if max > 0 returns only max number of peers 272 func (node *Node) filterInactviePeers(peersIn []peer.ID, max int) (peersOut []peer.ID) { 273 if max <= 0 { 274 max = len(peersIn) 275 } 276 var i int 277 for _, p := range peersIn { 278 if node.isPeerActive(p) { 279 peersOut = append(peersOut, p) 280 i += 1 281 if i == max { 282 return 283 } 284 } 285 } 286 return 287 } 288 289 // AddPeer adds a peer to the peerstore if it passes various checks 290 func (h *Holochain) AddPeer(pi pstore.PeerInfo) (err error) { 291 // to protect against crashes from background routines after close 292 if h.node == nil || h.dht == nil { 293 return 294 } 295 h.dht.dlog.Logf("Adding Peer Req: %v my node %v\n", pi.ID, h.node.HashAddr) 296 if pi.ID == h.node.HashAddr { 297 return 298 } 299 if h.node.IsBlocked(pi.ID) { 300 err = ErrBlockedListed 301 } else { 302 err = h.addPeer(pi, true) 303 } 304 return 305 } 306 307 func (n *Node) EnableMDNSDiscovery(h *Holochain, interval time.Duration) (err error) { 308 ctx := context.Background() 309 tag := h.dnaHash.String() + "._udp" 310 n.mdnsSvc, err = discovery.NewMdnsService(ctx, n.host, interval, tag) 311 if err != nil { 312 return 313 } 314 n.mdnsSvc.RegisterNotifee(h) 315 return 316 } 317 318 func (n *Node) ExternalAddr() ma.Multiaddr { 319 if n.nat == nil { 320 return n.NetAddr 321 } else { 322 mappings := n.nat.Mappings() 323 for i := 0; i < len(mappings); i++ { 324 external_addr, err := mappings[i].ExternalAddr() 325 if err == nil { 326 return external_addr 327 } 328 } 329 return n.NetAddr 330 } 331 } 332 333 func (node *Node) discoverAndHandleNat(listenPort int) { 334 node.log.Logf("Looking for a NAT...") 335 node.nat = nat.DiscoverNAT() 336 if node.nat == nil { 337 node.log.Logf("No NAT found.") 338 } else { 339 node.log.Logf("Discovered NAT! Trying to aquire public port mapping via UPnP...") 340 ifaces, _ := go_net.Interfaces() 341 // handle err 342 for _, i := range ifaces { 343 addrs, _ := i.Addrs() 344 // handle err 345 for _, addr := range addrs { 346 var ip go_net.IP 347 switch v := addr.(type) { 348 case *go_net.IPNet: 349 ip = v.IP 350 case *go_net.IPAddr: 351 ip = v.IP 352 } 353 if ip.Equal(go_net.IPv4(127, 0, 0, 1)) { 354 continue 355 } 356 addr_string := fmt.Sprintf("/ip4/%s/tcp/%d", ip, listenPort) 357 localaddr, err := ma.NewMultiaddr(addr_string) 358 if err == nil { 359 node.log.Logf("NAT: trying to establish NAT mapping for %s...", addr_string) 360 node.nat.NewMapping(localaddr) 361 } 362 } 363 } 364 365 external_addr := node.ExternalAddr() 366 367 if external_addr != node.NetAddr { 368 node.log.Logf("NAT: successfully created port mapping! External address is: %s", external_addr.String()) 369 } else { 370 node.log.Logf("NAT: could not create port mappping. Keep trying...") 371 Infof("NAT:-------------------------------------------------------") 372 Infof("NAT:---------------------Warning---------------------------") 373 Infof("NAT:-------------------------------------------------------") 374 Infof("NAT: You seem to be behind a NAT that does not speak UPnP.") 375 Infof("NAT: You will have to setup a port forwarding manually.") 376 Infof("NAT: This instance is configured to listen on port: %d", listenPort) 377 Infof("NAT:-------------------------------------------------------") 378 } 379 380 } 381 } 382 383 // NewNode creates a new node with given multiAddress listener string and identity 384 func NewNode(listenAddr string, protoMux string, agent *LibP2PAgent, enableNATUPnP bool, log *Logger) (node *Node, err error) { 385 var n Node 386 n.log = log 387 n.log.Logf("Creating new node with protoMux: %s\n", protoMux) 388 nodeID, _, err := agent.NodeID() 389 if err != nil { 390 return 391 } 392 n.log.Logf("NodeID is: %v\n", nodeID) 393 394 listenPort, err := strconv.Atoi(strings.Split(listenAddr, "/")[4]) 395 if err != nil { 396 Infof("Can't parse port from Multiaddress string: %s", listenAddr) 397 return 398 } 399 400 n.NetAddr, err = ma.NewMultiaddr(listenAddr) 401 if err != nil { 402 return 403 } 404 405 if enableNATUPnP { 406 n.discoverAndHandleNat(listenPort) 407 } 408 409 ps := pstore.NewPeerstore() 410 n.peerstore = ps 411 ps.AddAddrs(nodeID, []ma.Multiaddr{n.NetAddr}, pstore.PermanentAddrTTL) 412 413 n.HashAddr = nodeID 414 priv := agent.PrivKey() 415 ps.AddPrivKey(nodeID, priv) 416 ps.AddPubKey(nodeID, priv.GetPublic()) 417 418 validateProtocolString := "/hc-validate-" + protoMux + "/0.0.0" 419 gossipProtocolString := "/hc-gossip-" + protoMux + "/0.0.0" 420 actionProtocolString := "/hc-action-" + protoMux + "/0.0.0" 421 kademliaProtocolString := "/hc-kademlia-" + protoMux + "/0.0.0" 422 423 n.log.Logf("Validate protocol identifier: " + validateProtocolString) 424 n.log.Logf("Gossip protocol identifier: " + gossipProtocolString) 425 n.log.Logf("Action protocol identifier: " + actionProtocolString) 426 n.log.Logf("Kademlia protocol identifier: " + kademliaProtocolString) 427 428 n.protocols[ValidateProtocol] = &Protocol{protocol.ID(validateProtocolString), ValidateReceiver} 429 n.protocols[GossipProtocol] = &Protocol{protocol.ID(gossipProtocolString), GossipReceiver} 430 n.protocols[ActionProtocol] = &Protocol{protocol.ID(actionProtocolString), ActionReceiver} 431 n.protocols[KademliaProtocol] = &Protocol{protocol.ID(kademliaProtocolString), KademliaReceiver} 432 433 n.stoppers = make([]chan bool, _StopperCount) 434 435 ctx := context.Background() 436 n.ctx = ctx 437 438 // create a new swarm to be used by the service host 439 netw, err := swarm.NewNetwork(ctx, []ma.Multiaddr{n.NetAddr}, nodeID, ps, nil) 440 if err != nil { 441 return nil, err 442 } 443 444 var bh *bhost.BasicHost 445 bh, err = bhost.New(netw), nil 446 if err != nil { 447 return 448 } 449 450 n.host = rhost.Wrap(bh, &n) 451 452 m := pstore.NewMetrics() 453 n.routingTable = NewRoutingTable(KValue, nodeID, time.Minute, m) 454 n.peers = make(map[peer.ID]*peerTracker) 455 456 node = &n 457 458 n.host.Network().Notify((*netNotifiee)(node)) 459 460 n.proc = goprocessctx.WithContextAndTeardown(ctx, func() error { 461 // remove ourselves from network notifs. 462 n.host.Network().StopNotify((*netNotifiee)(node)) 463 return n.host.Close() 464 }) 465 466 return 467 } 468 469 // Encode codes a message to gob format 470 // @TODO generalize for other message encoding formats 471 func (m *Message) Encode() (data []byte, err error) { 472 data, err = ByteEncoder(m) 473 if err != nil { 474 return 475 } 476 return 477 } 478 479 // Decode converts a message from gob format 480 // @TODO generalize for other message encoding formats 481 func (m *Message) Decode(r io.Reader) (err error) { 482 dec := gob.NewDecoder(r) 483 err = dec.Decode(m) 484 return 485 } 486 487 // Fingerprint creates a hash of a message 488 func (m *Message) Fingerprint() (f Hash, err error) { 489 var data []byte 490 if m != nil { 491 data, err = bson.Marshal(m) 492 493 if err != nil { 494 return 495 } 496 // TODO should just use hash.Sum Code and length not available? 497 var multiH mh.Multihash 498 multiH, err = mh.Sum(data, mh.SHA2_256, -1) 499 f = Hash(multiH) 500 } else { 501 f = NullHash() 502 } 503 504 return 505 } 506 507 // String converts a message to a nice string 508 func (m Message) String() string { 509 return fmt.Sprintf("%v @ %v From:%v Body:%v", m.Type, m.Time, m.From, m.Body) 510 } 511 512 // respondWith writes a message either error or otherwise, to the stream 513 func (node *Node) respondWith(s net.Stream, err error, body interface{}) { 514 var m *Message 515 if err != nil { 516 errResp := NewErrorResponse(err) 517 errResp.Payload = body 518 m = node.NewMessage(ERROR_RESPONSE, errResp) 519 } else { 520 m = node.NewMessage(OK_RESPONSE, body) 521 } 522 523 data, err := m.Encode() 524 if err != nil { 525 Infof("Response failed: unable to encode message: %v", m) 526 } 527 var n int 528 n, err = s.Write(data) 529 if err != nil { 530 Infof("Response failed: write returned error: %v", err) 531 } 532 if BytesSentChan != nil { 533 b := BytesSent{Bytes: int64(n), MsgType: m.Type} 534 BytesSentChan <- b 535 } 536 } 537 538 // StartProtocol initiates listening for a protocol on the node 539 func (node *Node) StartProtocol(h *Holochain, proto int) (err error) { 540 node.host.SetStreamHandler(node.protocols[proto].ID, func(s net.Stream) { 541 var m Message 542 err := m.Decode(s) 543 var response interface{} 544 if m.From == "" { 545 // @todo other sanity checks on From? 546 err = errors.New("message must have a source") 547 } else { 548 if node.IsBlocked(s.Conn().RemotePeer()) { 549 err = ErrBlockedListed 550 } 551 552 if err == nil { 553 response, err = node.protocols[proto].Receiver(h, &m) 554 } 555 } 556 node.respondWith(s, err, response) 557 }) 558 return 559 } 560 561 // Close shuts down the node 562 func (node *Node) Close() error { 563 for i, stopper := range node.stoppers { 564 if stopper != nil { 565 stop := node.stoppers[i] 566 node.stoppers[i] = nil 567 stop <- true 568 } 569 } 570 return node.proc.Close() 571 } 572 573 // Send delivers a message to a node via the given protocol 574 func (node *Node) Send(ctx context.Context, proto int, addr peer.ID, m *Message) (response Message, err error) { 575 576 if node.IsBlocked(addr) { 577 err = ErrBlockedListed 578 return 579 } 580 581 s, err := node.host.NewStream(ctx, addr, node.protocols[proto].ID) 582 if err != nil { 583 return 584 } 585 defer s.Close() 586 587 // encode the message and send it 588 data, err := m.Encode() 589 if err != nil { 590 return 591 } 592 593 n, err := s.Write(data) 594 if err != nil { 595 return 596 } 597 if n != len(data) { 598 err = errors.New("unable to send all data") 599 } 600 if BytesSentChan != nil { 601 b := BytesSent{Bytes: int64(n), MsgType: m.Type} 602 BytesSentChan <- b 603 } 604 605 // decode the response 606 err = response.Decode(s) 607 if err != nil { 608 node.log.Logf("failed to decode with err:%v ", err) 609 return 610 } 611 return 612 } 613 614 // NewMessage creates a message from the node with a new current timestamp 615 func (node *Node) NewMessage(t MsgType, body interface{}) (msg *Message) { 616 m := Message{Type: t, Time: time.Now().Round(0), Body: body, From: node.HashAddr} 617 msg = &m 618 return 619 } 620 621 // IsBlockedListed checks to see if a node is on the blockedlist 622 func (node *Node) IsBlocked(addr peer.ID) (ok bool) { 623 ok = node.blockedlist[addr] 624 return 625 } 626 627 // InitBlockedList sets up the blockedlist from a PeerList 628 func (node *Node) InitBlockedList(list PeerList) { 629 node.blockedlist = make(map[peer.ID]bool) 630 for _, r := range list.Records { 631 node.Block(r.ID) 632 } 633 } 634 635 // Block adds a peer to the blocklist 636 func (node *Node) Block(addr peer.ID) { 637 if node.blockedlist == nil { 638 node.blockedlist = make(map[peer.ID]bool) 639 } 640 node.blockedlist[addr] = true 641 } 642 643 // Unblock removes a peer from the blocklist 644 func (node *Node) Unblock(addr peer.ID) { 645 if node.blockedlist != nil { 646 delete(node.blockedlist, addr) 647 } 648 } 649 650 type ErrorResponse struct { 651 Code int 652 Message string 653 Payload interface{} 654 } 655 656 const ( 657 ErrUnknownCode = iota 658 ErrHashNotFoundCode 659 ErrHashDeletedCode 660 ErrHashModifiedCode 661 ErrHashRejectedCode 662 ErrLinkNotFoundCode 663 ErrEntryTypeMismatchCode 664 ErrBlockedListedCode 665 ) 666 667 // NewErrorResponse encodes standard errors for transmitting 668 func NewErrorResponse(err error) (errResp ErrorResponse) { 669 switch err { 670 case ErrHashNotFound: 671 errResp.Code = ErrHashNotFoundCode 672 case ErrHashDeleted: 673 errResp.Code = ErrHashDeletedCode 674 case ErrHashModified: 675 errResp.Code = ErrHashModifiedCode 676 case ErrHashRejected: 677 errResp.Code = ErrHashRejectedCode 678 case ErrLinkNotFound: 679 errResp.Code = ErrLinkNotFoundCode 680 case ErrEntryTypeMismatch: 681 errResp.Code = ErrEntryTypeMismatchCode 682 case ErrBlockedListed: 683 errResp.Code = ErrBlockedListedCode 684 default: 685 errResp.Message = err.Error() //Code will be set to ErrUnknown by default cus it's 0 686 } 687 return 688 } 689 690 // DecodeResponseError creates a go error object from the ErrorResponse data 691 func (errResp ErrorResponse) DecodeResponseError() (err error) { 692 switch errResp.Code { 693 case ErrHashNotFoundCode: 694 err = ErrHashNotFound 695 case ErrHashDeletedCode: 696 err = ErrHashDeleted 697 case ErrHashModifiedCode: 698 err = ErrHashModified 699 case ErrHashRejectedCode: 700 err = ErrHashRejected 701 case ErrLinkNotFoundCode: 702 err = ErrLinkNotFound 703 case ErrEntryTypeMismatchCode: 704 err = ErrEntryTypeMismatch 705 case ErrBlockedListedCode: 706 err = ErrBlockedListed 707 default: 708 err = errors.New(errResp.Message) 709 } 710 return 711 } 712 713 func distance(id peer.ID, hash Hash) *big.Int { 714 h := HashFromPeerID(id) 715 return HashXORDistance(h, hash) 716 } 717 718 // Distance returns the nodes peer distance to another node for purposes of gossip 719 func (node *Node) Distance(id peer.ID) *big.Int { 720 return distance(id, HashFromPeerID(node.HashAddr)) 721 } 722 723 // Context return node's context 724 func (node *Node) Context() context.Context { 725 return node.ctx 726 } 727 728 // Process return node's process 729 func (node *Node) Process() goprocess.Process { 730 return node.proc 731 }