github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/p2p/simulations/README.md (about)

     1  # devp2p Simulations
     2  
     3  The `p2p/simulations` package implements a simulation framework which supports
     4  creating a collection of devp2p nodes, connecting them together to form a
     5  simulation network, performing simulation actions in that network and then
     6  extracting useful information.
     7  
     8  ## Nodes
     9  
    10  Each node in a simulation network runs multiple services by wrapping a collection
    11  of objects which implement the `node.Service` interface meaning they:
    12  
    13  * can be started and stopped
    14  * run p2p protocols
    15  * expose RPC APIs
    16  
    17  This means that any object which implements the `node.Service` interface can be
    18  used to run a node in the simulation.
    19  
    20  ## Services
    21  
    22  Before running a simulation, a set of service initializers must be registered
    23  which can then be used to run nodes in the network.
    24  
    25  A service initializer is a function with the following signature:
    26  
    27  ```go
    28  func(ctx *adapters.ServiceContext) (node.Service, error)
    29  ```
    30  
    31  These initializers should be registered by calling the `adapters.RegisterServices`
    32  function in an `init()` hook:
    33  
    34  ```go
    35  func init() {
    36  	adapters.RegisterServices(adapters.Services{
    37  		"service1": initService1,
    38  		"service2": initService2,
    39  	})
    40  }
    41  ```
    42  
    43  ## Node Adapters
    44  
    45  The simulation framework includes multiple "node adapters" which are
    46  responsible for creating an environment in which a node runs.
    47  
    48  ### SimAdapter
    49  
    50  The `SimAdapter` runs nodes in-memory, connecting them using an in-memory,
    51  synchronous `net.Pipe` and connecting to their RPC server using an in-memory
    52  `rpc.Client`.
    53  
    54  ### ExecAdapter
    55  
    56  The `ExecAdapter` runs nodes as child processes of the running simulation.
    57  
    58  It does this by executing the binary which is running the simulation but
    59  setting `argv[0]` (i.e. the program name) to `p2p-node` which is then
    60  detected by an init hook in the child process which runs the `node.Service`
    61  using the devp2p node stack rather than executing `main()`.
    62  
    63  The nodes listen for devp2p connections and WebSocket RPC clients on random
    64  localhost ports.
    65  
    66  ### DockerAdapter
    67  
    68  The `DockerAdapter` is similar to the `ExecAdapter` but executes `docker run`
    69  to run the node in a Docker container using a Docker image containing the
    70  simulation binary at `/bin/p2p-node`.
    71  
    72  The Docker image is built using `docker build` when the adapter is initialised,
    73  meaning no prior setup is necessary other than having a working Docker client.
    74  
    75  Each node listens on the external IP of the container and the default p2p and
    76  RPC ports (`30303` and `8546` respectively).
    77  
    78  ## Network
    79  
    80  A simulation network is created with an ID and default service (which is used
    81  if a node is created without an explicit service), exposes methods for
    82  creating, starting, stopping, connecting and disconnecting nodes, and emits
    83  events when certain actions occur.
    84  
    85  ### Events
    86  
    87  A simulation network emits the following events:
    88  
    89  * node event       - when nodes are created / started / stopped
    90  * connection event - when nodes are connected / disconnected
    91  * message event    - when a protocol message is sent between two nodes
    92  
    93  The events have a "control" flag which when set indicates that the event is the
    94  outcome of a controlled simulation action (e.g. creating a node or explicitly
    95  connecting two nodes together).
    96  
    97  This is in contrast to a non-control event, otherwise called a "live" event,
    98  which is the outcome of something happening in the network as a result of a
    99  control event (e.g. a node actually started up or a connection was actually
   100  established between two nodes).
   101  
   102  Live events are detected by the simulation network by subscribing to node peer
   103  events via RPC when the nodes start up.
   104  
   105  ## Testing Framework
   106  
   107  The `Simulation` type can be used in tests to perform actions in a simulation
   108  network and then wait for expectations to be met.
   109  
   110  With a running simulation network, the `Simulation.Run` method can be called
   111  with a `Step` which has the following fields:
   112  
   113  * `Action` - a function which performs some action in the network
   114  
   115  * `Expect` - an expectation function which returns whether or not a
   116      given node meets the expectation
   117  
   118  * `Trigger` - a channel which receives node IDs which then trigger a check
   119      of the expectation function to be performed against that node
   120  
   121  As a concrete example, consider a simulated network of Ethereum nodes. An
   122  `Action` could be the sending of a transaction, `Expect` it being included in
   123  a block, and `Trigger` a check for every block that is mined.
   124  
   125  On return, the `Simulation.Run` method returns a `StepResult` which can be used
   126  to determine if all nodes met the expectation, how long it took them to meet
   127  the expectation and what network events were emitted during the step run.
   128  
   129  ## HTTP API
   130  
   131  The simulation framework includes a HTTP API which can be used to control the
   132  simulation.
   133  
   134  The API is initialised with a particular node adapter and has the following
   135  endpoints:
   136  
   137  ```
   138  GET    /                            Get network information
   139  POST   /start                       Start all nodes in the network
   140  POST   /stop                        Stop all nodes in the network
   141  GET    /events                      Stream network events
   142  GET    /snapshot                    Take a network snapshot
   143  POST   /snapshot                    Load a network snapshot
   144  POST   /nodes                       Create a node
   145  GET    /nodes                       Get all nodes in the network
   146  GET    /nodes/:nodeid               Get node information
   147  POST   /nodes/:nodeid/start         Start a node
   148  POST   /nodes/:nodeid/stop          Stop a node
   149  POST   /nodes/:nodeid/conn/:peerid  Connect two nodes
   150  DELETE /nodes/:nodeid/conn/:peerid  Disconnect two nodes
   151  GET    /nodes/:nodeid/rpc           Make RPC requests to a node via WebSocket
   152  ```
   153  
   154  For convenience, `nodeid` in the URL can be the name of a node rather than its
   155  ID.
   156  
   157  ## Command line client
   158  
   159  `p2psim` is a command line client for the HTTP API, located in
   160  `cmd/p2psim`.
   161  
   162  It provides the following commands:
   163  
   164  ```
   165  p2psim show
   166  p2psim events [--current] [--filter=FILTER]
   167  p2psim snapshot
   168  p2psim load
   169  p2psim node create [--name=NAME] [--services=SERVICES] [--key=KEY]
   170  p2psim node list
   171  p2psim node show <node>
   172  p2psim node start <node>
   173  p2psim node stop <node>
   174  p2psim node connect <node> <peer>
   175  p2psim node disconnect <node> <peer>
   176  p2psim node rpc <node> <method> [<args>] [--subscribe]
   177  ```
   178  
   179  ## Example
   180  
   181  See [p2p/simulations/examples/README.md](examples/README.md).