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