github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/p2p/simulations/network.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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-ethereum 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-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package simulations 18 19 import ( 20 "bytes" 21 "context" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "math/rand" 26 "sync" 27 "time" 28 29 "github.com/ShyftNetwork/go-empyrean/event" 30 "github.com/ShyftNetwork/go-empyrean/log" 31 "github.com/ShyftNetwork/go-empyrean/p2p" 32 "github.com/ShyftNetwork/go-empyrean/p2p/enode" 33 "github.com/ShyftNetwork/go-empyrean/p2p/simulations/adapters" 34 ) 35 36 var DialBanTimeout = 200 * time.Millisecond 37 38 // NetworkConfig defines configuration options for starting a Network 39 type NetworkConfig struct { 40 ID string `json:"id"` 41 DefaultService string `json:"default_service,omitempty"` 42 } 43 44 // Network models a p2p simulation network which consists of a collection of 45 // simulated nodes and the connections which exist between them. 46 // 47 // The Network has a single NodeAdapter which is responsible for actually 48 // starting nodes and connecting them together. 49 // 50 // The Network emits events when nodes are started and stopped, when they are 51 // connected and disconnected, and also when messages are sent between nodes. 52 type Network struct { 53 NetworkConfig 54 55 Nodes []*Node `json:"nodes"` 56 nodeMap map[enode.ID]int 57 58 Conns []*Conn `json:"conns"` 59 connMap map[string]int 60 61 nodeAdapter adapters.NodeAdapter 62 events event.Feed 63 lock sync.RWMutex 64 quitc chan struct{} 65 } 66 67 // NewNetwork returns a Network which uses the given NodeAdapter and NetworkConfig 68 func NewNetwork(nodeAdapter adapters.NodeAdapter, conf *NetworkConfig) *Network { 69 return &Network{ 70 NetworkConfig: *conf, 71 nodeAdapter: nodeAdapter, 72 nodeMap: make(map[enode.ID]int), 73 connMap: make(map[string]int), 74 quitc: make(chan struct{}), 75 } 76 } 77 78 // Events returns the output event feed of the Network. 79 func (net *Network) Events() *event.Feed { 80 return &net.events 81 } 82 83 // NewNodeWithConfig adds a new node to the network with the given config, 84 // returning an error if a node with the same ID or name already exists 85 func (net *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error) { 86 net.lock.Lock() 87 defer net.lock.Unlock() 88 89 if conf.Reachable == nil { 90 conf.Reachable = func(otherID enode.ID) bool { 91 _, err := net.InitConn(conf.ID, otherID) 92 if err != nil && bytes.Compare(conf.ID.Bytes(), otherID.Bytes()) < 0 { 93 return false 94 } 95 return true 96 } 97 } 98 99 // check the node doesn't already exist 100 if node := net.getNode(conf.ID); node != nil { 101 return nil, fmt.Errorf("node with ID %q already exists", conf.ID) 102 } 103 if node := net.getNodeByName(conf.Name); node != nil { 104 return nil, fmt.Errorf("node with name %q already exists", conf.Name) 105 } 106 107 // if no services are configured, use the default service 108 if len(conf.Services) == 0 { 109 conf.Services = []string{net.DefaultService} 110 } 111 112 // use the NodeAdapter to create the node 113 adapterNode, err := net.nodeAdapter.NewNode(conf) 114 if err != nil { 115 return nil, err 116 } 117 node := &Node{ 118 Node: adapterNode, 119 Config: conf, 120 } 121 log.Trace("Node created", "id", conf.ID) 122 net.nodeMap[conf.ID] = len(net.Nodes) 123 net.Nodes = append(net.Nodes, node) 124 125 // emit a "control" event 126 net.events.Send(ControlEvent(node)) 127 128 return node, nil 129 } 130 131 // Config returns the network configuration 132 func (net *Network) Config() *NetworkConfig { 133 return &net.NetworkConfig 134 } 135 136 // StartAll starts all nodes in the network 137 func (net *Network) StartAll() error { 138 for _, node := range net.Nodes { 139 if node.Up { 140 continue 141 } 142 if err := net.Start(node.ID()); err != nil { 143 return err 144 } 145 } 146 return nil 147 } 148 149 // StopAll stops all nodes in the network 150 func (net *Network) StopAll() error { 151 for _, node := range net.Nodes { 152 if !node.Up { 153 continue 154 } 155 if err := net.Stop(node.ID()); err != nil { 156 return err 157 } 158 } 159 return nil 160 } 161 162 // Start starts the node with the given ID 163 func (net *Network) Start(id enode.ID) error { 164 return net.startWithSnapshots(id, nil) 165 } 166 167 // startWithSnapshots starts the node with the given ID using the give 168 // snapshots 169 func (net *Network) startWithSnapshots(id enode.ID, snapshots map[string][]byte) error { 170 net.lock.Lock() 171 defer net.lock.Unlock() 172 173 node := net.getNode(id) 174 if node == nil { 175 return fmt.Errorf("node %v does not exist", id) 176 } 177 if node.Up { 178 return fmt.Errorf("node %v already up", id) 179 } 180 log.Trace("Starting node", "id", id, "adapter", net.nodeAdapter.Name()) 181 if err := node.Start(snapshots); err != nil { 182 log.Warn("Node startup failed", "id", id, "err", err) 183 return err 184 } 185 node.Up = true 186 log.Info("Started node", "id", id) 187 188 net.events.Send(NewEvent(node)) 189 190 // subscribe to peer events 191 client, err := node.Client() 192 if err != nil { 193 return fmt.Errorf("error getting rpc client for node %v: %s", id, err) 194 } 195 events := make(chan *p2p.PeerEvent) 196 sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents") 197 if err != nil { 198 return fmt.Errorf("error getting peer events for node %v: %s", id, err) 199 } 200 go net.watchPeerEvents(id, events, sub) 201 return nil 202 } 203 204 // watchPeerEvents reads peer events from the given channel and emits 205 // corresponding network events 206 func (net *Network) watchPeerEvents(id enode.ID, events chan *p2p.PeerEvent, sub event.Subscription) { 207 defer func() { 208 sub.Unsubscribe() 209 210 // assume the node is now down 211 net.lock.Lock() 212 defer net.lock.Unlock() 213 node := net.getNode(id) 214 if node == nil { 215 return 216 } 217 node.Up = false 218 net.events.Send(NewEvent(node)) 219 }() 220 for { 221 select { 222 case event, ok := <-events: 223 if !ok { 224 return 225 } 226 peer := event.Peer 227 switch event.Type { 228 229 case p2p.PeerEventTypeAdd: 230 net.DidConnect(id, peer) 231 232 case p2p.PeerEventTypeDrop: 233 net.DidDisconnect(id, peer) 234 235 case p2p.PeerEventTypeMsgSend: 236 net.DidSend(id, peer, event.Protocol, *event.MsgCode) 237 238 case p2p.PeerEventTypeMsgRecv: 239 net.DidReceive(peer, id, event.Protocol, *event.MsgCode) 240 241 } 242 243 case err := <-sub.Err(): 244 if err != nil { 245 log.Error("Error in peer event subscription", "id", id, "err", err) 246 } 247 return 248 } 249 } 250 } 251 252 // Stop stops the node with the given ID 253 func (net *Network) Stop(id enode.ID) error { 254 net.lock.Lock() 255 node := net.getNode(id) 256 if node == nil { 257 return fmt.Errorf("node %v does not exist", id) 258 } 259 if !node.Up { 260 return fmt.Errorf("node %v already down", id) 261 } 262 node.Up = false 263 net.lock.Unlock() 264 265 err := node.Stop() 266 if err != nil { 267 net.lock.Lock() 268 node.Up = true 269 net.lock.Unlock() 270 return err 271 } 272 log.Info("Stopped node", "id", id, "err", err) 273 net.events.Send(ControlEvent(node)) 274 return nil 275 } 276 277 // Connect connects two nodes together by calling the "admin_addPeer" RPC 278 // method on the "one" node so that it connects to the "other" node 279 func (net *Network) Connect(oneID, otherID enode.ID) error { 280 log.Debug("Connecting nodes with addPeer", "id", oneID, "other", otherID) 281 conn, err := net.InitConn(oneID, otherID) 282 if err != nil { 283 return err 284 } 285 client, err := conn.one.Client() 286 if err != nil { 287 return err 288 } 289 net.events.Send(ControlEvent(conn)) 290 return client.Call(nil, "admin_addPeer", string(conn.other.Addr())) 291 } 292 293 // Disconnect disconnects two nodes by calling the "admin_removePeer" RPC 294 // method on the "one" node so that it disconnects from the "other" node 295 func (net *Network) Disconnect(oneID, otherID enode.ID) error { 296 conn := net.GetConn(oneID, otherID) 297 if conn == nil { 298 return fmt.Errorf("connection between %v and %v does not exist", oneID, otherID) 299 } 300 if !conn.Up { 301 return fmt.Errorf("%v and %v already disconnected", oneID, otherID) 302 } 303 client, err := conn.one.Client() 304 if err != nil { 305 return err 306 } 307 net.events.Send(ControlEvent(conn)) 308 return client.Call(nil, "admin_removePeer", string(conn.other.Addr())) 309 } 310 311 // DidConnect tracks the fact that the "one" node connected to the "other" node 312 func (net *Network) DidConnect(one, other enode.ID) error { 313 net.lock.Lock() 314 defer net.lock.Unlock() 315 conn, err := net.getOrCreateConn(one, other) 316 if err != nil { 317 return fmt.Errorf("connection between %v and %v does not exist", one, other) 318 } 319 if conn.Up { 320 return fmt.Errorf("%v and %v already connected", one, other) 321 } 322 conn.Up = true 323 net.events.Send(NewEvent(conn)) 324 return nil 325 } 326 327 // DidDisconnect tracks the fact that the "one" node disconnected from the 328 // "other" node 329 func (net *Network) DidDisconnect(one, other enode.ID) error { 330 net.lock.Lock() 331 defer net.lock.Unlock() 332 conn := net.getConn(one, other) 333 if conn == nil { 334 return fmt.Errorf("connection between %v and %v does not exist", one, other) 335 } 336 if !conn.Up { 337 return fmt.Errorf("%v and %v already disconnected", one, other) 338 } 339 conn.Up = false 340 conn.initiated = time.Now().Add(-DialBanTimeout) 341 net.events.Send(NewEvent(conn)) 342 return nil 343 } 344 345 // DidSend tracks the fact that "sender" sent a message to "receiver" 346 func (net *Network) DidSend(sender, receiver enode.ID, proto string, code uint64) error { 347 msg := &Msg{ 348 One: sender, 349 Other: receiver, 350 Protocol: proto, 351 Code: code, 352 Received: false, 353 } 354 net.events.Send(NewEvent(msg)) 355 return nil 356 } 357 358 // DidReceive tracks the fact that "receiver" received a message from "sender" 359 func (net *Network) DidReceive(sender, receiver enode.ID, proto string, code uint64) error { 360 msg := &Msg{ 361 One: sender, 362 Other: receiver, 363 Protocol: proto, 364 Code: code, 365 Received: true, 366 } 367 net.events.Send(NewEvent(msg)) 368 return nil 369 } 370 371 // GetNode gets the node with the given ID, returning nil if the node does not 372 // exist 373 func (net *Network) GetNode(id enode.ID) *Node { 374 net.lock.RLock() 375 defer net.lock.RUnlock() 376 return net.getNode(id) 377 } 378 379 // GetNode gets the node with the given name, returning nil if the node does 380 // not exist 381 func (net *Network) GetNodeByName(name string) *Node { 382 net.lock.RLock() 383 defer net.lock.RUnlock() 384 return net.getNodeByName(name) 385 } 386 387 func (net *Network) getNodeByName(name string) *Node { 388 for _, node := range net.Nodes { 389 if node.Config.Name == name { 390 return node 391 } 392 } 393 return nil 394 } 395 396 // GetNodes returns the existing nodes 397 func (net *Network) GetNodes() (nodes []*Node) { 398 net.lock.RLock() 399 defer net.lock.RUnlock() 400 401 nodes = append(nodes, net.Nodes...) 402 return nodes 403 } 404 405 func (net *Network) getNode(id enode.ID) *Node { 406 i, found := net.nodeMap[id] 407 if !found { 408 return nil 409 } 410 return net.Nodes[i] 411 } 412 413 // GetRandomUpNode returns a random node on the network, which is running. 414 func (net *Network) GetRandomUpNode(excludeIDs ...enode.ID) *Node { 415 net.lock.RLock() 416 defer net.lock.RUnlock() 417 return net.getRandomNode(net.getUpNodeIDs(), excludeIDs) 418 } 419 420 func (net *Network) getUpNodeIDs() (ids []enode.ID) { 421 for _, node := range net.Nodes { 422 if node.Up { 423 ids = append(ids, node.ID()) 424 } 425 } 426 return ids 427 } 428 429 // GetRandomDownNode returns a random node on the network, which is stopped. 430 func (net *Network) GetRandomDownNode(excludeIDs ...enode.ID) *Node { 431 net.lock.RLock() 432 defer net.lock.RUnlock() 433 return net.getRandomNode(net.getDownNodeIDs(), excludeIDs) 434 } 435 436 func (net *Network) getDownNodeIDs() (ids []enode.ID) { 437 for _, node := range net.GetNodes() { 438 if !node.Up { 439 ids = append(ids, node.ID()) 440 } 441 } 442 return ids 443 } 444 445 func (net *Network) getRandomNode(ids []enode.ID, excludeIDs []enode.ID) *Node { 446 filtered := filterIDs(ids, excludeIDs) 447 448 l := len(filtered) 449 if l == 0 { 450 return nil 451 } 452 return net.GetNode(filtered[rand.Intn(l)]) 453 } 454 455 func filterIDs(ids []enode.ID, excludeIDs []enode.ID) []enode.ID { 456 exclude := make(map[enode.ID]bool) 457 for _, id := range excludeIDs { 458 exclude[id] = true 459 } 460 var filtered []enode.ID 461 for _, id := range ids { 462 if _, found := exclude[id]; !found { 463 filtered = append(filtered, id) 464 } 465 } 466 return filtered 467 } 468 469 // GetConn returns the connection which exists between "one" and "other" 470 // regardless of which node initiated the connection 471 func (net *Network) GetConn(oneID, otherID enode.ID) *Conn { 472 net.lock.RLock() 473 defer net.lock.RUnlock() 474 return net.getConn(oneID, otherID) 475 } 476 477 // GetOrCreateConn is like GetConn but creates the connection if it doesn't 478 // already exist 479 func (net *Network) GetOrCreateConn(oneID, otherID enode.ID) (*Conn, error) { 480 net.lock.Lock() 481 defer net.lock.Unlock() 482 return net.getOrCreateConn(oneID, otherID) 483 } 484 485 func (net *Network) getOrCreateConn(oneID, otherID enode.ID) (*Conn, error) { 486 if conn := net.getConn(oneID, otherID); conn != nil { 487 return conn, nil 488 } 489 490 one := net.getNode(oneID) 491 if one == nil { 492 return nil, fmt.Errorf("node %v does not exist", oneID) 493 } 494 other := net.getNode(otherID) 495 if other == nil { 496 return nil, fmt.Errorf("node %v does not exist", otherID) 497 } 498 conn := &Conn{ 499 One: oneID, 500 Other: otherID, 501 one: one, 502 other: other, 503 } 504 label := ConnLabel(oneID, otherID) 505 net.connMap[label] = len(net.Conns) 506 net.Conns = append(net.Conns, conn) 507 return conn, nil 508 } 509 510 func (net *Network) getConn(oneID, otherID enode.ID) *Conn { 511 label := ConnLabel(oneID, otherID) 512 i, found := net.connMap[label] 513 if !found { 514 return nil 515 } 516 return net.Conns[i] 517 } 518 519 // InitConn(one, other) retrieves the connection model for the connection between 520 // peers one and other, or creates a new one if it does not exist 521 // the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i) 522 // it checks if the connection is already up, and if the nodes are running 523 // NOTE: 524 // it also checks whether there has been recent attempt to connect the peers 525 // this is cheating as the simulation is used as an oracle and know about 526 // remote peers attempt to connect to a node which will then not initiate the connection 527 func (net *Network) InitConn(oneID, otherID enode.ID) (*Conn, error) { 528 net.lock.Lock() 529 defer net.lock.Unlock() 530 if oneID == otherID { 531 return nil, fmt.Errorf("refusing to connect to self %v", oneID) 532 } 533 conn, err := net.getOrCreateConn(oneID, otherID) 534 if err != nil { 535 return nil, err 536 } 537 if conn.Up { 538 return nil, fmt.Errorf("%v and %v already connected", oneID, otherID) 539 } 540 if time.Since(conn.initiated) < DialBanTimeout { 541 return nil, fmt.Errorf("connection between %v and %v recently attempted", oneID, otherID) 542 } 543 544 err = conn.nodesUp() 545 if err != nil { 546 log.Trace("Nodes not up", "err", err) 547 return nil, fmt.Errorf("nodes not up: %v", err) 548 } 549 log.Debug("Connection initiated", "id", oneID, "other", otherID) 550 conn.initiated = time.Now() 551 return conn, nil 552 } 553 554 // Shutdown stops all nodes in the network and closes the quit channel 555 func (net *Network) Shutdown() { 556 for _, node := range net.Nodes { 557 log.Debug("Stopping node", "id", node.ID()) 558 if err := node.Stop(); err != nil { 559 log.Warn("Can't stop node", "id", node.ID(), "err", err) 560 } 561 } 562 close(net.quitc) 563 } 564 565 // Reset resets all network properties: 566 // empties the nodes and the connection list 567 func (net *Network) Reset() { 568 net.lock.Lock() 569 defer net.lock.Unlock() 570 571 //re-initialize the maps 572 net.connMap = make(map[string]int) 573 net.nodeMap = make(map[enode.ID]int) 574 575 net.Nodes = nil 576 net.Conns = nil 577 } 578 579 // Node is a wrapper around adapters.Node which is used to track the status 580 // of a node in the network 581 type Node struct { 582 adapters.Node `json:"-"` 583 584 // Config if the config used to created the node 585 Config *adapters.NodeConfig `json:"config"` 586 587 // Up tracks whether or not the node is running 588 Up bool `json:"up"` 589 } 590 591 // ID returns the ID of the node 592 func (n *Node) ID() enode.ID { 593 return n.Config.ID 594 } 595 596 // String returns a log-friendly string 597 func (n *Node) String() string { 598 return fmt.Sprintf("Node %v", n.ID().TerminalString()) 599 } 600 601 // NodeInfo returns information about the node 602 func (n *Node) NodeInfo() *p2p.NodeInfo { 603 // avoid a panic if the node is not started yet 604 if n.Node == nil { 605 return nil 606 } 607 info := n.Node.NodeInfo() 608 info.Name = n.Config.Name 609 return info 610 } 611 612 // MarshalJSON implements the json.Marshaler interface so that the encoded 613 // JSON includes the NodeInfo 614 func (n *Node) MarshalJSON() ([]byte, error) { 615 return json.Marshal(struct { 616 Info *p2p.NodeInfo `json:"info,omitempty"` 617 Config *adapters.NodeConfig `json:"config,omitempty"` 618 Up bool `json:"up"` 619 }{ 620 Info: n.NodeInfo(), 621 Config: n.Config, 622 Up: n.Up, 623 }) 624 } 625 626 // Conn represents a connection between two nodes in the network 627 type Conn struct { 628 // One is the node which initiated the connection 629 One enode.ID `json:"one"` 630 631 // Other is the node which the connection was made to 632 Other enode.ID `json:"other"` 633 634 // Up tracks whether or not the connection is active 635 Up bool `json:"up"` 636 // Registers when the connection was grabbed to dial 637 initiated time.Time 638 639 one *Node 640 other *Node 641 } 642 643 // nodesUp returns whether both nodes are currently up 644 func (c *Conn) nodesUp() error { 645 if !c.one.Up { 646 return fmt.Errorf("one %v is not up", c.One) 647 } 648 if !c.other.Up { 649 return fmt.Errorf("other %v is not up", c.Other) 650 } 651 return nil 652 } 653 654 // String returns a log-friendly string 655 func (c *Conn) String() string { 656 return fmt.Sprintf("Conn %v->%v", c.One.TerminalString(), c.Other.TerminalString()) 657 } 658 659 // Msg represents a p2p message sent between two nodes in the network 660 type Msg struct { 661 One enode.ID `json:"one"` 662 Other enode.ID `json:"other"` 663 Protocol string `json:"protocol"` 664 Code uint64 `json:"code"` 665 Received bool `json:"received"` 666 } 667 668 // String returns a log-friendly string 669 func (m *Msg) String() string { 670 return fmt.Sprintf("Msg(%d) %v->%v", m.Code, m.One.TerminalString(), m.Other.TerminalString()) 671 } 672 673 // ConnLabel generates a deterministic string which represents a connection 674 // between two nodes, used to compare if two connections are between the same 675 // nodes 676 func ConnLabel(source, target enode.ID) string { 677 var first, second enode.ID 678 if bytes.Compare(source.Bytes(), target.Bytes()) > 0 { 679 first = target 680 second = source 681 } else { 682 first = source 683 second = target 684 } 685 return fmt.Sprintf("%v-%v", first, second) 686 } 687 688 // Snapshot represents the state of a network at a single point in time and can 689 // be used to restore the state of a network 690 type Snapshot struct { 691 Nodes []NodeSnapshot `json:"nodes,omitempty"` 692 Conns []Conn `json:"conns,omitempty"` 693 } 694 695 // NodeSnapshot represents the state of a node in the network 696 type NodeSnapshot struct { 697 Node Node `json:"node,omitempty"` 698 699 // Snapshots is arbitrary data gathered from calling node.Snapshots() 700 Snapshots map[string][]byte `json:"snapshots,omitempty"` 701 } 702 703 // Snapshot creates a network snapshot 704 func (net *Network) Snapshot() (*Snapshot, error) { 705 return net.snapshot(nil, nil) 706 } 707 708 func (net *Network) SnapshotWithServices(addServices []string, removeServices []string) (*Snapshot, error) { 709 return net.snapshot(addServices, removeServices) 710 } 711 712 func (net *Network) snapshot(addServices []string, removeServices []string) (*Snapshot, error) { 713 net.lock.Lock() 714 defer net.lock.Unlock() 715 snap := &Snapshot{ 716 Nodes: make([]NodeSnapshot, len(net.Nodes)), 717 } 718 for i, node := range net.Nodes { 719 snap.Nodes[i] = NodeSnapshot{Node: *node} 720 if !node.Up { 721 continue 722 } 723 snapshots, err := node.Snapshots() 724 if err != nil { 725 return nil, err 726 } 727 snap.Nodes[i].Snapshots = snapshots 728 for _, addSvc := range addServices { 729 haveSvc := false 730 for _, svc := range snap.Nodes[i].Node.Config.Services { 731 if svc == addSvc { 732 haveSvc = true 733 break 734 } 735 } 736 if !haveSvc { 737 snap.Nodes[i].Node.Config.Services = append(snap.Nodes[i].Node.Config.Services, addSvc) 738 } 739 } 740 if len(removeServices) > 0 { 741 var cleanedServices []string 742 for _, svc := range snap.Nodes[i].Node.Config.Services { 743 haveSvc := false 744 for _, rmSvc := range removeServices { 745 if rmSvc == svc { 746 haveSvc = true 747 break 748 } 749 } 750 if !haveSvc { 751 cleanedServices = append(cleanedServices, svc) 752 } 753 754 } 755 snap.Nodes[i].Node.Config.Services = cleanedServices 756 } 757 } 758 for _, conn := range net.Conns { 759 if conn.Up { 760 snap.Conns = append(snap.Conns, *conn) 761 } 762 } 763 return snap, nil 764 } 765 766 var snapshotLoadTimeout = 120 * time.Second 767 768 // Load loads a network snapshot 769 func (net *Network) Load(snap *Snapshot) error { 770 // Start nodes. 771 for _, n := range snap.Nodes { 772 if _, err := net.NewNodeWithConfig(n.Node.Config); err != nil { 773 return err 774 } 775 if !n.Node.Up { 776 continue 777 } 778 if err := net.startWithSnapshots(n.Node.Config.ID, n.Snapshots); err != nil { 779 return err 780 } 781 } 782 783 // Prepare connection events counter. 784 allConnected := make(chan struct{}) // closed when all connections are established 785 done := make(chan struct{}) // ensures that the event loop goroutine is terminated 786 defer close(done) 787 788 // Subscribe to event channel. 789 // It needs to be done outside of the event loop goroutine (created below) 790 // to ensure that the event channel is blocking before connect calls are made. 791 events := make(chan *Event) 792 sub := net.Events().Subscribe(events) 793 defer sub.Unsubscribe() 794 795 go func() { 796 // Expected number of connections. 797 total := len(snap.Conns) 798 // Set of all established connections from the snapshot, not other connections. 799 // Key array element 0 is the connection One field value, and element 1 connection Other field. 800 connections := make(map[[2]enode.ID]struct{}, total) 801 802 for { 803 select { 804 case e := <-events: 805 // Ignore control events as they do not represent 806 // connect or disconnect (Up) state change. 807 if e.Control { 808 continue 809 } 810 // Detect only connection events. 811 if e.Type != EventTypeConn { 812 continue 813 } 814 connection := [2]enode.ID{e.Conn.One, e.Conn.Other} 815 // Nodes are still not connected or have been disconnected. 816 if !e.Conn.Up { 817 // Delete the connection from the set of established connections. 818 // This will prevent false positive in case disconnections happen. 819 delete(connections, connection) 820 log.Warn("load snapshot: unexpected disconnection", "one", e.Conn.One, "other", e.Conn.Other) 821 continue 822 } 823 // Check that the connection is from the snapshot. 824 for _, conn := range snap.Conns { 825 if conn.One == e.Conn.One && conn.Other == e.Conn.Other { 826 // Add the connection to the set of established connections. 827 connections[connection] = struct{}{} 828 if len(connections) == total { 829 // Signal that all nodes are connected. 830 close(allConnected) 831 return 832 } 833 834 break 835 } 836 } 837 case <-done: 838 // Load function returned, terminate this goroutine. 839 return 840 } 841 } 842 }() 843 844 // Start connecting. 845 for _, conn := range snap.Conns { 846 847 if !net.GetNode(conn.One).Up || !net.GetNode(conn.Other).Up { 848 //in this case, at least one of the nodes of a connection is not up, 849 //so it would result in the snapshot `Load` to fail 850 continue 851 } 852 if err := net.Connect(conn.One, conn.Other); err != nil { 853 return err 854 } 855 } 856 857 select { 858 // Wait until all connections from the snapshot are established. 859 case <-allConnected: 860 // Make sure that we do not wait forever. 861 case <-time.After(snapshotLoadTimeout): 862 return errors.New("snapshot connections not established") 863 } 864 return nil 865 } 866 867 // Subscribe reads control events from a channel and executes them 868 func (net *Network) Subscribe(events chan *Event) { 869 for { 870 select { 871 case event, ok := <-events: 872 if !ok { 873 return 874 } 875 if event.Control { 876 net.executeControlEvent(event) 877 } 878 case <-net.quitc: 879 return 880 } 881 } 882 } 883 884 func (net *Network) executeControlEvent(event *Event) { 885 log.Trace("Executing control event", "type", event.Type, "event", event) 886 switch event.Type { 887 case EventTypeNode: 888 if err := net.executeNodeEvent(event); err != nil { 889 log.Error("Error executing node event", "event", event, "err", err) 890 } 891 case EventTypeConn: 892 if err := net.executeConnEvent(event); err != nil { 893 log.Error("Error executing conn event", "event", event, "err", err) 894 } 895 case EventTypeMsg: 896 log.Warn("Ignoring control msg event") 897 } 898 } 899 900 func (net *Network) executeNodeEvent(e *Event) error { 901 if !e.Node.Up { 902 return net.Stop(e.Node.ID()) 903 } 904 905 if _, err := net.NewNodeWithConfig(e.Node.Config); err != nil { 906 return err 907 } 908 return net.Start(e.Node.ID()) 909 } 910 911 func (net *Network) executeConnEvent(e *Event) error { 912 if e.Conn.Up { 913 return net.Connect(e.Conn.One, e.Conn.Other) 914 } else { 915 return net.Disconnect(e.Conn.One, e.Conn.Other) 916 } 917 }