github.com/luckypickle/go-ethereum-vet@v1.14.2/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 "fmt" 24 "sync" 25 "time" 26 27 "github.com/luckypickle/go-ethereum-vet/event" 28 "github.com/luckypickle/go-ethereum-vet/log" 29 "github.com/luckypickle/go-ethereum-vet/p2p" 30 "github.com/luckypickle/go-ethereum-vet/p2p/discover" 31 "github.com/luckypickle/go-ethereum-vet/p2p/simulations/adapters" 32 ) 33 34 var DialBanTimeout = 200 * time.Millisecond 35 36 // NetworkConfig defines configuration options for starting a Network 37 type NetworkConfig struct { 38 ID string `json:"id"` 39 DefaultService string `json:"default_service,omitempty"` 40 } 41 42 // Network models a p2p simulation network which consists of a collection of 43 // simulated nodes and the connections which exist between them. 44 // 45 // The Network has a single NodeAdapter which is responsible for actually 46 // starting nodes and connecting them together. 47 // 48 // The Network emits events when nodes are started and stopped, when they are 49 // connected and disconnected, and also when messages are sent between nodes. 50 type Network struct { 51 NetworkConfig 52 53 Nodes []*Node `json:"nodes"` 54 nodeMap map[discover.NodeID]int 55 56 Conns []*Conn `json:"conns"` 57 connMap map[string]int 58 59 nodeAdapter adapters.NodeAdapter 60 events event.Feed 61 lock sync.RWMutex 62 quitc chan struct{} 63 } 64 65 // NewNetwork returns a Network which uses the given NodeAdapter and NetworkConfig 66 func NewNetwork(nodeAdapter adapters.NodeAdapter, conf *NetworkConfig) *Network { 67 return &Network{ 68 NetworkConfig: *conf, 69 nodeAdapter: nodeAdapter, 70 nodeMap: make(map[discover.NodeID]int), 71 connMap: make(map[string]int), 72 quitc: make(chan struct{}), 73 } 74 } 75 76 // Events returns the output event feed of the Network. 77 func (net *Network) Events() *event.Feed { 78 return &net.events 79 } 80 81 // NewNodeWithConfig adds a new node to the network with the given config, 82 // returning an error if a node with the same ID or name already exists 83 func (net *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error) { 84 net.lock.Lock() 85 defer net.lock.Unlock() 86 87 if conf.Reachable == nil { 88 conf.Reachable = func(otherID discover.NodeID) bool { 89 _, err := net.InitConn(conf.ID, otherID) 90 if err != nil && bytes.Compare(conf.ID.Bytes(), otherID.Bytes()) < 0 { 91 return false 92 } 93 return true 94 } 95 } 96 97 // check the node doesn't already exist 98 if node := net.getNode(conf.ID); node != nil { 99 return nil, fmt.Errorf("node with ID %q already exists", conf.ID) 100 } 101 if node := net.getNodeByName(conf.Name); node != nil { 102 return nil, fmt.Errorf("node with name %q already exists", conf.Name) 103 } 104 105 // if no services are configured, use the default service 106 if len(conf.Services) == 0 { 107 conf.Services = []string{net.DefaultService} 108 } 109 110 // use the NodeAdapter to create the node 111 adapterNode, err := net.nodeAdapter.NewNode(conf) 112 if err != nil { 113 return nil, err 114 } 115 node := &Node{ 116 Node: adapterNode, 117 Config: conf, 118 } 119 log.Trace(fmt.Sprintf("node %v created", conf.ID)) 120 net.nodeMap[conf.ID] = len(net.Nodes) 121 net.Nodes = append(net.Nodes, node) 122 123 // emit a "control" event 124 net.events.Send(ControlEvent(node)) 125 126 return node, nil 127 } 128 129 // Config returns the network configuration 130 func (net *Network) Config() *NetworkConfig { 131 return &net.NetworkConfig 132 } 133 134 // StartAll starts all nodes in the network 135 func (net *Network) StartAll() error { 136 for _, node := range net.Nodes { 137 if node.Up { 138 continue 139 } 140 if err := net.Start(node.ID()); err != nil { 141 return err 142 } 143 } 144 return nil 145 } 146 147 // StopAll stops all nodes in the network 148 func (net *Network) StopAll() error { 149 for _, node := range net.Nodes { 150 if !node.Up { 151 continue 152 } 153 if err := net.Stop(node.ID()); err != nil { 154 return err 155 } 156 } 157 return nil 158 } 159 160 // Start starts the node with the given ID 161 func (net *Network) Start(id discover.NodeID) error { 162 return net.startWithSnapshots(id, nil) 163 } 164 165 // startWithSnapshots starts the node with the given ID using the give 166 // snapshots 167 func (net *Network) startWithSnapshots(id discover.NodeID, snapshots map[string][]byte) error { 168 net.lock.Lock() 169 defer net.lock.Unlock() 170 node := net.getNode(id) 171 if node == nil { 172 return fmt.Errorf("node %v does not exist", id) 173 } 174 if node.Up { 175 return fmt.Errorf("node %v already up", id) 176 } 177 log.Trace(fmt.Sprintf("starting node %v: %v using %v", id, node.Up, net.nodeAdapter.Name())) 178 if err := node.Start(snapshots); err != nil { 179 log.Warn(fmt.Sprintf("start up failed: %v", err)) 180 return err 181 } 182 node.Up = true 183 log.Info(fmt.Sprintf("started node %v: %v", id, node.Up)) 184 185 net.events.Send(NewEvent(node)) 186 187 // subscribe to peer events 188 client, err := node.Client() 189 if err != nil { 190 return fmt.Errorf("error getting rpc client for node %v: %s", id, err) 191 } 192 events := make(chan *p2p.PeerEvent) 193 sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents") 194 if err != nil { 195 return fmt.Errorf("error getting peer events for node %v: %s", id, err) 196 } 197 go net.watchPeerEvents(id, events, sub) 198 return nil 199 } 200 201 // watchPeerEvents reads peer events from the given channel and emits 202 // corresponding network events 203 func (net *Network) watchPeerEvents(id discover.NodeID, events chan *p2p.PeerEvent, sub event.Subscription) { 204 defer func() { 205 sub.Unsubscribe() 206 207 // assume the node is now down 208 net.lock.Lock() 209 defer net.lock.Unlock() 210 node := net.getNode(id) 211 if node == nil { 212 log.Error("Can not find node for id", "id", id) 213 return 214 } 215 node.Up = false 216 net.events.Send(NewEvent(node)) 217 }() 218 for { 219 select { 220 case event, ok := <-events: 221 if !ok { 222 return 223 } 224 peer := event.Peer 225 switch event.Type { 226 227 case p2p.PeerEventTypeAdd: 228 net.DidConnect(id, peer) 229 230 case p2p.PeerEventTypeDrop: 231 net.DidDisconnect(id, peer) 232 233 case p2p.PeerEventTypeMsgSend: 234 net.DidSend(id, peer, event.Protocol, *event.MsgCode) 235 236 case p2p.PeerEventTypeMsgRecv: 237 net.DidReceive(peer, id, event.Protocol, *event.MsgCode) 238 239 } 240 241 case err := <-sub.Err(): 242 if err != nil { 243 log.Error(fmt.Sprintf("error getting peer events for node %v", id), "err", err) 244 } 245 return 246 } 247 } 248 } 249 250 // Stop stops the node with the given ID 251 func (net *Network) Stop(id discover.NodeID) error { 252 net.lock.Lock() 253 defer net.lock.Unlock() 254 node := net.getNode(id) 255 if node == nil { 256 return fmt.Errorf("node %v does not exist", id) 257 } 258 if !node.Up { 259 return fmt.Errorf("node %v already down", id) 260 } 261 if err := node.Stop(); err != nil { 262 return err 263 } 264 node.Up = false 265 log.Info(fmt.Sprintf("stop node %v: %v", id, node.Up)) 266 267 net.events.Send(ControlEvent(node)) 268 return nil 269 } 270 271 // Connect connects two nodes together by calling the "admin_addPeer" RPC 272 // method on the "one" node so that it connects to the "other" node 273 func (net *Network) Connect(oneID, otherID discover.NodeID) error { 274 log.Debug(fmt.Sprintf("connecting %s to %s", oneID, otherID)) 275 conn, err := net.InitConn(oneID, otherID) 276 if err != nil { 277 return err 278 } 279 client, err := conn.one.Client() 280 if err != nil { 281 return err 282 } 283 net.events.Send(ControlEvent(conn)) 284 return client.Call(nil, "admin_addPeer", string(conn.other.Addr())) 285 } 286 287 // Disconnect disconnects two nodes by calling the "admin_removePeer" RPC 288 // method on the "one" node so that it disconnects from the "other" node 289 func (net *Network) Disconnect(oneID, otherID discover.NodeID) error { 290 conn := net.GetConn(oneID, otherID) 291 if conn == nil { 292 return fmt.Errorf("connection between %v and %v does not exist", oneID, otherID) 293 } 294 if !conn.Up { 295 return fmt.Errorf("%v and %v already disconnected", oneID, otherID) 296 } 297 client, err := conn.one.Client() 298 if err != nil { 299 return err 300 } 301 net.events.Send(ControlEvent(conn)) 302 return client.Call(nil, "admin_removePeer", string(conn.other.Addr())) 303 } 304 305 // DidConnect tracks the fact that the "one" node connected to the "other" node 306 func (net *Network) DidConnect(one, other discover.NodeID) error { 307 net.lock.Lock() 308 defer net.lock.Unlock() 309 conn, err := net.getOrCreateConn(one, other) 310 if err != nil { 311 return fmt.Errorf("connection between %v and %v does not exist", one, other) 312 } 313 if conn.Up { 314 return fmt.Errorf("%v and %v already connected", one, other) 315 } 316 conn.Up = true 317 net.events.Send(NewEvent(conn)) 318 return nil 319 } 320 321 // DidDisconnect tracks the fact that the "one" node disconnected from the 322 // "other" node 323 func (net *Network) DidDisconnect(one, other discover.NodeID) error { 324 net.lock.Lock() 325 defer net.lock.Unlock() 326 conn := net.getConn(one, other) 327 if conn == 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 disconnected", one, other) 332 } 333 conn.Up = false 334 conn.initiated = time.Now().Add(-DialBanTimeout) 335 net.events.Send(NewEvent(conn)) 336 return nil 337 } 338 339 // DidSend tracks the fact that "sender" sent a message to "receiver" 340 func (net *Network) DidSend(sender, receiver discover.NodeID, proto string, code uint64) error { 341 msg := &Msg{ 342 One: sender, 343 Other: receiver, 344 Protocol: proto, 345 Code: code, 346 Received: false, 347 } 348 net.events.Send(NewEvent(msg)) 349 return nil 350 } 351 352 // DidReceive tracks the fact that "receiver" received a message from "sender" 353 func (net *Network) DidReceive(sender, receiver discover.NodeID, proto string, code uint64) error { 354 msg := &Msg{ 355 One: sender, 356 Other: receiver, 357 Protocol: proto, 358 Code: code, 359 Received: true, 360 } 361 net.events.Send(NewEvent(msg)) 362 return nil 363 } 364 365 // GetNode gets the node with the given ID, returning nil if the node does not 366 // exist 367 func (net *Network) GetNode(id discover.NodeID) *Node { 368 net.lock.Lock() 369 defer net.lock.Unlock() 370 return net.getNode(id) 371 } 372 373 // GetNode gets the node with the given name, returning nil if the node does 374 // not exist 375 func (net *Network) GetNodeByName(name string) *Node { 376 net.lock.Lock() 377 defer net.lock.Unlock() 378 return net.getNodeByName(name) 379 } 380 381 // GetNodes returns the existing nodes 382 func (net *Network) GetNodes() (nodes []*Node) { 383 net.lock.Lock() 384 defer net.lock.Unlock() 385 386 nodes = append(nodes, net.Nodes...) 387 return nodes 388 } 389 390 func (net *Network) getNode(id discover.NodeID) *Node { 391 i, found := net.nodeMap[id] 392 if !found { 393 return nil 394 } 395 return net.Nodes[i] 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 // GetConn returns the connection which exists between "one" and "other" 408 // regardless of which node initiated the connection 409 func (net *Network) GetConn(oneID, otherID discover.NodeID) *Conn { 410 net.lock.Lock() 411 defer net.lock.Unlock() 412 return net.getConn(oneID, otherID) 413 } 414 415 // GetOrCreateConn is like GetConn but creates the connection if it doesn't 416 // already exist 417 func (net *Network) GetOrCreateConn(oneID, otherID discover.NodeID) (*Conn, error) { 418 net.lock.Lock() 419 defer net.lock.Unlock() 420 return net.getOrCreateConn(oneID, otherID) 421 } 422 423 func (net *Network) getOrCreateConn(oneID, otherID discover.NodeID) (*Conn, error) { 424 if conn := net.getConn(oneID, otherID); conn != nil { 425 return conn, nil 426 } 427 428 one := net.getNode(oneID) 429 if one == nil { 430 return nil, fmt.Errorf("node %v does not exist", oneID) 431 } 432 other := net.getNode(otherID) 433 if other == nil { 434 return nil, fmt.Errorf("node %v does not exist", otherID) 435 } 436 conn := &Conn{ 437 One: oneID, 438 Other: otherID, 439 one: one, 440 other: other, 441 } 442 label := ConnLabel(oneID, otherID) 443 net.connMap[label] = len(net.Conns) 444 net.Conns = append(net.Conns, conn) 445 return conn, nil 446 } 447 448 func (net *Network) getConn(oneID, otherID discover.NodeID) *Conn { 449 label := ConnLabel(oneID, otherID) 450 i, found := net.connMap[label] 451 if !found { 452 return nil 453 } 454 return net.Conns[i] 455 } 456 457 // InitConn(one, other) retrieves the connectiton model for the connection between 458 // peers one and other, or creates a new one if it does not exist 459 // the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i) 460 // it checks if the connection is already up, and if the nodes are running 461 // NOTE: 462 // it also checks whether there has been recent attempt to connect the peers 463 // this is cheating as the simulation is used as an oracle and know about 464 // remote peers attempt to connect to a node which will then not initiate the connection 465 func (net *Network) InitConn(oneID, otherID discover.NodeID) (*Conn, error) { 466 net.lock.Lock() 467 defer net.lock.Unlock() 468 if oneID == otherID { 469 return nil, fmt.Errorf("refusing to connect to self %v", oneID) 470 } 471 conn, err := net.getOrCreateConn(oneID, otherID) 472 if err != nil { 473 return nil, err 474 } 475 if conn.Up { 476 return nil, fmt.Errorf("%v and %v already connected", oneID, otherID) 477 } 478 if time.Since(conn.initiated) < DialBanTimeout { 479 return nil, fmt.Errorf("connection between %v and %v recently attempted", oneID, otherID) 480 } 481 482 err = conn.nodesUp() 483 if err != nil { 484 log.Trace(fmt.Sprintf("nodes not up: %v", err)) 485 return nil, fmt.Errorf("nodes not up: %v", err) 486 } 487 log.Debug("InitConn - connection initiated") 488 conn.initiated = time.Now() 489 return conn, nil 490 } 491 492 // Shutdown stops all nodes in the network and closes the quit channel 493 func (net *Network) Shutdown() { 494 for _, node := range net.Nodes { 495 log.Debug(fmt.Sprintf("stopping node %s", node.ID().TerminalString())) 496 if err := node.Stop(); err != nil { 497 log.Warn(fmt.Sprintf("error stopping node %s", node.ID().TerminalString()), "err", err) 498 } 499 } 500 close(net.quitc) 501 } 502 503 // Reset resets all network properties: 504 // emtpies the nodes and the connection list 505 func (net *Network) Reset() { 506 net.lock.Lock() 507 defer net.lock.Unlock() 508 509 //re-initialize the maps 510 net.connMap = make(map[string]int) 511 net.nodeMap = make(map[discover.NodeID]int) 512 513 net.Nodes = nil 514 net.Conns = nil 515 } 516 517 // Node is a wrapper around adapters.Node which is used to track the status 518 // of a node in the network 519 type Node struct { 520 adapters.Node `json:"-"` 521 522 // Config if the config used to created the node 523 Config *adapters.NodeConfig `json:"config"` 524 525 // Up tracks whether or not the node is running 526 Up bool `json:"up"` 527 } 528 529 // ID returns the ID of the node 530 func (n *Node) ID() discover.NodeID { 531 return n.Config.ID 532 } 533 534 // String returns a log-friendly string 535 func (n *Node) String() string { 536 return fmt.Sprintf("Node %v", n.ID().TerminalString()) 537 } 538 539 // NodeInfo returns information about the node 540 func (n *Node) NodeInfo() *p2p.NodeInfo { 541 // avoid a panic if the node is not started yet 542 if n.Node == nil { 543 return nil 544 } 545 info := n.Node.NodeInfo() 546 info.Name = n.Config.Name 547 return info 548 } 549 550 // MarshalJSON implements the json.Marshaler interface so that the encoded 551 // JSON includes the NodeInfo 552 func (n *Node) MarshalJSON() ([]byte, error) { 553 return json.Marshal(struct { 554 Info *p2p.NodeInfo `json:"info,omitempty"` 555 Config *adapters.NodeConfig `json:"config,omitempty"` 556 Up bool `json:"up"` 557 }{ 558 Info: n.NodeInfo(), 559 Config: n.Config, 560 Up: n.Up, 561 }) 562 } 563 564 // Conn represents a connection between two nodes in the network 565 type Conn struct { 566 // One is the node which initiated the connection 567 One discover.NodeID `json:"one"` 568 569 // Other is the node which the connection was made to 570 Other discover.NodeID `json:"other"` 571 572 // Up tracks whether or not the connection is active 573 Up bool `json:"up"` 574 // Registers when the connection was grabbed to dial 575 initiated time.Time 576 577 one *Node 578 other *Node 579 } 580 581 // nodesUp returns whether both nodes are currently up 582 func (c *Conn) nodesUp() error { 583 if !c.one.Up { 584 return fmt.Errorf("one %v is not up", c.One) 585 } 586 if !c.other.Up { 587 return fmt.Errorf("other %v is not up", c.Other) 588 } 589 return nil 590 } 591 592 // String returns a log-friendly string 593 func (c *Conn) String() string { 594 return fmt.Sprintf("Conn %v->%v", c.One.TerminalString(), c.Other.TerminalString()) 595 } 596 597 // Msg represents a p2p message sent between two nodes in the network 598 type Msg struct { 599 One discover.NodeID `json:"one"` 600 Other discover.NodeID `json:"other"` 601 Protocol string `json:"protocol"` 602 Code uint64 `json:"code"` 603 Received bool `json:"received"` 604 } 605 606 // String returns a log-friendly string 607 func (m *Msg) String() string { 608 return fmt.Sprintf("Msg(%d) %v->%v", m.Code, m.One.TerminalString(), m.Other.TerminalString()) 609 } 610 611 // ConnLabel generates a deterministic string which represents a connection 612 // between two nodes, used to compare if two connections are between the same 613 // nodes 614 func ConnLabel(source, target discover.NodeID) string { 615 var first, second discover.NodeID 616 if bytes.Compare(source.Bytes(), target.Bytes()) > 0 { 617 first = target 618 second = source 619 } else { 620 first = source 621 second = target 622 } 623 return fmt.Sprintf("%v-%v", first, second) 624 } 625 626 // Snapshot represents the state of a network at a single point in time and can 627 // be used to restore the state of a network 628 type Snapshot struct { 629 Nodes []NodeSnapshot `json:"nodes,omitempty"` 630 Conns []Conn `json:"conns,omitempty"` 631 } 632 633 // NodeSnapshot represents the state of a node in the network 634 type NodeSnapshot struct { 635 Node Node `json:"node,omitempty"` 636 637 // Snapshots is arbitrary data gathered from calling node.Snapshots() 638 Snapshots map[string][]byte `json:"snapshots,omitempty"` 639 } 640 641 // Snapshot creates a network snapshot 642 func (net *Network) Snapshot() (*Snapshot, error) { 643 net.lock.Lock() 644 defer net.lock.Unlock() 645 snap := &Snapshot{ 646 Nodes: make([]NodeSnapshot, len(net.Nodes)), 647 Conns: make([]Conn, len(net.Conns)), 648 } 649 for i, node := range net.Nodes { 650 snap.Nodes[i] = NodeSnapshot{Node: *node} 651 if !node.Up { 652 continue 653 } 654 snapshots, err := node.Snapshots() 655 if err != nil { 656 return nil, err 657 } 658 snap.Nodes[i].Snapshots = snapshots 659 } 660 for i, conn := range net.Conns { 661 snap.Conns[i] = *conn 662 } 663 return snap, nil 664 } 665 666 // Load loads a network snapshot 667 func (net *Network) Load(snap *Snapshot) error { 668 for _, n := range snap.Nodes { 669 if _, err := net.NewNodeWithConfig(n.Node.Config); err != nil { 670 return err 671 } 672 if !n.Node.Up { 673 continue 674 } 675 if err := net.startWithSnapshots(n.Node.Config.ID, n.Snapshots); err != nil { 676 return err 677 } 678 } 679 for _, conn := range snap.Conns { 680 681 if !net.GetNode(conn.One).Up || !net.GetNode(conn.Other).Up { 682 //in this case, at least one of the nodes of a connection is not up, 683 //so it would result in the snapshot `Load` to fail 684 continue 685 } 686 if err := net.Connect(conn.One, conn.Other); err != nil { 687 return err 688 } 689 } 690 return nil 691 } 692 693 // Subscribe reads control events from a channel and executes them 694 func (net *Network) Subscribe(events chan *Event) { 695 for { 696 select { 697 case event, ok := <-events: 698 if !ok { 699 return 700 } 701 if event.Control { 702 net.executeControlEvent(event) 703 } 704 case <-net.quitc: 705 return 706 } 707 } 708 } 709 710 func (net *Network) executeControlEvent(event *Event) { 711 log.Trace("execute control event", "type", event.Type, "event", event) 712 switch event.Type { 713 case EventTypeNode: 714 if err := net.executeNodeEvent(event); err != nil { 715 log.Error("error executing node event", "event", event, "err", err) 716 } 717 case EventTypeConn: 718 if err := net.executeConnEvent(event); err != nil { 719 log.Error("error executing conn event", "event", event, "err", err) 720 } 721 case EventTypeMsg: 722 log.Warn("ignoring control msg event") 723 } 724 } 725 726 func (net *Network) executeNodeEvent(e *Event) error { 727 if !e.Node.Up { 728 return net.Stop(e.Node.ID()) 729 } 730 731 if _, err := net.NewNodeWithConfig(e.Node.Config); err != nil { 732 return err 733 } 734 return net.Start(e.Node.ID()) 735 } 736 737 func (net *Network) executeConnEvent(e *Event) error { 738 if e.Conn.Up { 739 return net.Connect(e.Conn.One, e.Conn.Other) 740 } else { 741 return net.Disconnect(e.Conn.One, e.Conn.Other) 742 } 743 }