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