You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
5.9 KiB

  1. # Tendermint Architectural Overview
  2. > **November 2019**
  3. Over the next few weeks, @brapse, @marbar3778 and I (@tessr) are having a series of meetings to go over the architecture of Tendermint Core. These are my notes from these meetings, which will either serve as an artifact for onboarding future engineers; or will provide the basis for such a document.
  4. ## Communication
  5. There are three forms of communication (e.g., requests, responses, connections) that can happen in Tendermint Core: *internode communication*, *intranode communication*, and *client communication*.
  6. - Internode communication: Happens between a node and other peers. This kind of communication happens over TCP or HTTP. More on this below.
  7. - Intranode communication: Happens within the node itself (i.e., between reactors or other components). These are typically function or method calls, or occasionally happen through an event bus.
  8. - Client communiation: Happens between a client (like a wallet or a browser) and a node on the network.
  9. ### Internode Communication
  10. Internode communication can happen in two ways:
  11. 1. TCP connections through the p2p package
  12. - Most common form of internode communication
  13. - Connections between nodes are persisted and shared across reactors, facilitated by the switch. (More on the switch below.)
  14. 2. RPC over HTTP
  15. - Reserved for short-lived, one-off requests
  16. - Example: reactor-specific state, like height
  17. - Also possible: websocks connected to channels for notifications (like new transactions)
  18. ### P2P Business (the Switch, the PEX, and the Address Book)
  19. When writing a p2p service, there are two primary responsibilities:
  20. 1. Routing: Who gets which messages?
  21. 2. Peer management: Who can you talk to? What is their state? And how can you do peer discovery?
  22. The first responsibility is handled by the Switch:
  23. - Responsible for routing connections between peers
  24. - Notably _only handles TCP connections_; RPC/HTTP is separate
  25. - Is a dependency for every reactor; all reactors expose a function `setSwitch`
  26. - Holds onto channels (channels on the TCP connection--NOT Go channels) and uses them to route
  27. - Is a global object, with a global namespace for messages
  28. - Similar functionality to libp2p
  29. TODO: More information (maybe) on the implementation of the Switch.
  30. The second responsibility is handled by a combination of the PEX and the Address Book.
  31. TODO: What is the PEX and the Address Book?
  32. #### The Nature of TCP, and Introduction to the `mconnection`
  33. Here are some relevant facts about TCP:
  34. 1. All TCP connections have a "frame window size" which represents the packet size to the "confidence;" i.e., if you are sending packets along a new connection, you must start out with small packets. As the packets are received successfully, you can start to send larger and larger packets. (This curve is illustrated below.) This means that TCP connections are slow to spin up.
  35. 2. The syn/ack process also means that there's a high overhead for small, frequent messages
  36. 3. Sockets are represented by file descriptors.
  37. ![tcp](../imgs/tcp-window.png)
  38. In order to have performant TCP connections under the conditions created in Tendermint, we've created the `mconnection`, or the multiplexing connection. It is our own protocol built on top of TCP. It lets us reuse TCP connections to minimize overhead, and it keeps the window size high by sending auxiliary messages when necessary.
  39. The `mconnection` is represented by a struct, which contains a batch of messages, read and write buffers, and a map of channel IDs to reactors. It communicates with TCP via file descriptors, which it can write to. There is one `mconnection` per peer connection.
  40. The `mconnection` has two methods: `send`, which takes a raw handle to the socket and writes to it; and `trySend`, which writes to a different buffer. (TODO: which buffer?)
  41. The `mconnection` is owned by a peer, which is owned (potentially with many other peers) by a (global) transport, which is owned by the (global) switch:
  42. <!-- markdownlint-disable -->
  43. ```
  44. switch
  45. transport
  46. peer
  47. mconnection
  48. peer
  49. mconnection
  50. peer
  51. mconnection
  52. ```
  53. <!-- markdownlint-restore -->
  54. ## node.go
  55. node.go is the entrypoint for running a node. It sets up reactors, sets up the switch, and registers all the RPC endpoints for a node.
  56. ## Types of Nodes
  57. 1. Validator Node:
  58. 2. Full Node:
  59. 3. Seed Node:
  60. TODO: Flesh out the differences between the types of nodes and how they're configured.
  61. ## Reactors
  62. Here are some Reactor Facts:
  63. - Every reactor holds a pointer to the global switch (set through `SetSwitch()`)
  64. - The switch holds a pointer to every reactor (`addReactor()`)
  65. - Every reactor gets set up in node.go (and if you are using custom reactors, this is where you specify that)
  66. - `addReactor` is called by the switch; `addReactor` calls `setSwitch` for that reactor
  67. - There's an assumption that all the reactors are added before
  68. - Sometimes reactors talk to each other by fetching references to one another via the switch (which maintains a pointer to each reactor). **Question: Can reactors talk to each other in any other way?**
  69. Furthermore, all reactors expose:
  70. 1. A TCP channel
  71. 2. A `receive` method
  72. 3. An `addReactor` call
  73. The `receive` method can be called many times by the mconnection. It has the same signature across all reactors.
  74. The `addReactor` call does a for loop over all the channels on the reactor and creates a map of channel IDs->reactors. The switch holds onto this map, and passes it to the _transport_, a thin wrapper around TCP connections.
  75. The following is an exhaustive (?) list of reactors:
  76. - Blockchain Reactor
  77. - Consensus Reactor
  78. - Evidence Reactor
  79. - Mempool Reactor
  80. - PEX Reactor
  81. Each of these will be discussed in more detail later.
  82. ### Blockchain Reactor
  83. The blockchain reactor has two responsibilities:
  84. 1. Serve blocks at the request of peers
  85. 2. TODO: learn about the second responsibility of the blockchain reactor