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.

308 lines
12 KiB

  1. # ADR 016: Protocol Versions
  2. ## TODO
  3. - How to / should we version the authenticated encryption handshake itself (ie.
  4. upfront protocol negotiation for the P2PVersion)
  5. - How to / should we version ABCI itself? Should it just be absorbed by the
  6. BlockVersion?
  7. ## Changelog
  8. - 18-09-2018: Updates after working a bit on implementation
  9. - ABCI Handshake needs to happen independently of starting the app
  10. conns so we can see the result
  11. - Add question about ABCI protocol version
  12. - 16-08-2018: Updates after discussion with SDK team
  13. - Remove signalling for next version from Header/ABCI
  14. - 03-08-2018: Updates from discussion with Jae:
  15. - ProtocolVersion contains Block/AppVersion, not Current/Next
  16. - signal upgrades to Tendermint using EndBlock fields
  17. - dont restrict peer compatibilty by version to simplify syncing old nodes
  18. - 28-07-2018: Updates from review
  19. - split into two ADRs - one for protocol, one for chains
  20. - include signalling for upgrades in header
  21. - 16-07-2018: Initial draft - was originally joint ADR for protocol and chain
  22. versions
  23. ## Context
  24. Here we focus on software-agnostic protocol versions.
  25. The Software Version is covered by SemVer and described elsewhere.
  26. It is not relevant to the protocol description, suffice to say that if any protocol version
  27. changes, the software version changes, but not necessarily vice versa.
  28. Software version should be included in NodeInfo for convenience/diagnostics.
  29. We are also interested in versioning across different blockchains in a
  30. meaningful way, for instance to differentiate branches of a contentious
  31. hard-fork. We leave that for a later ADR.
  32. ## Requirements
  33. We need to version components of the blockchain that may be independently upgraded.
  34. We need to do it in a way that is scalable and maintainable - we can't just litter
  35. the code with conditionals.
  36. We can consider the complete version of the protocol to contain the following sub-versions:
  37. BlockVersion, P2PVersion, AppVersion. These versions reflect the major sub-components
  38. of the software that are likely to evolve together, at different rates, and in different ways,
  39. as described below.
  40. The BlockVersion defines the core of the blockchain data structures and
  41. should change infrequently.
  42. The P2PVersion defines how peers connect and communicate with eachother - it's
  43. not part of the blockchain data structures, but defines the protocols used to build the
  44. blockchain. It may change gradually.
  45. The AppVersion determines how we compute app specific information, like the
  46. AppHash and the Results.
  47. All of these versions may change over the life of a blockchain, and we need to
  48. be able to help new nodes sync up across version changes. This means we must be willing
  49. to connect to peers with older version.
  50. ### BlockVersion
  51. - All tendermint hashed data-structures (headers, votes, txs, responses, etc.).
  52. - Note the semantic meaning of a transaction may change according to the AppVersion, but the way txs are merklized into the header is part of the BlockVersion
  53. - It should be the least frequent/likely to change.
  54. - Tendermint should be stabilizing - it's just Atomic Broadcast.
  55. - We can start considering for Tendermint v2.0 in a year
  56. - It's easy to determine the version of a block from its serialized form
  57. ### P2PVersion
  58. - All p2p and reactor messaging (messages, detectable behaviour)
  59. - Will change gradually as reactors evolve to improve performance and support new features - eg proposed new message types BatchTx in the mempool and HasBlockPart in the consensus
  60. - It's easy to determine the version of a peer from its first serialized message/s
  61. - New versions must be compatible with at least one old version to allow gradual upgrades
  62. ### AppVersion
  63. - The ABCI state machine (txs, begin/endblock behaviour, commit hashing)
  64. - Behaviour and message types will change abruptly in the course of the life of a chain
  65. - Need to minimize complexity of the code for supporting different AppVersions at different heights
  66. - Ideally, each version of the software supports only a _single_ AppVersion at one time
  67. - this means we checkout different versions of the software at different heights instead of littering the code
  68. with conditionals
  69. - minimize the number of data migrations required across AppVersion (ie. most AppVersion should be able to read the same state from disk as previous AppVersion).
  70. ## Ideal
  71. Each component of the software is independently versioned in a modular way and its easy to mix and match and upgrade.
  72. ## Proposal
  73. Each of BlockVersion, AppVersion, P2PVersion, is a monotonically increasing uint64.
  74. To use these versions, we need to update the block Header, the p2p NodeInfo, and the ABCI.
  75. ### Header
  76. Block Header should include a `Version` struct as its first field like:
  77. ```
  78. type Version struct {
  79. Block uint64
  80. App uint64
  81. }
  82. ```
  83. Here, `Version.Block` defines the rules for the current block, while
  84. `Version.App` defines the app version that processed the last block and computed
  85. the `AppHash` in the current block. Together they provide a complete description
  86. of the consensus-critical protocol.
  87. Since we have settled on a proto3 header, the ability to read the BlockVersion out of the serialized header is unanimous.
  88. Using a Version struct gives us more flexibility to add fields without breaking
  89. the header.
  90. The ProtocolVersion struct includes both the Block and App versions - it should
  91. serve as a complete description of the consensus-critical protocol.
  92. ### NodeInfo
  93. NodeInfo should include a Version struct as its first field like:
  94. ```
  95. type Version struct {
  96. P2P uint64
  97. Block uint64
  98. App uint64
  99. Other []string
  100. }
  101. ```
  102. Note this effectively makes `Version.P2P` the first field in the NodeInfo, so it
  103. should be easy to read this out of the serialized header if need be to facilitate an upgrade.
  104. The `Version.Other` here should include additional information like the name of the software client and
  105. it's SemVer version - this is for convenience only. Eg.
  106. `tendermint-core/v0.22.8`. It's a `[]string` so it can include information about
  107. the version of Tendermint, of the app, of Tendermint libraries, etc.
  108. ### ABCI
  109. Since the ABCI is responsible for keeping Tendermint and the App in sync, we
  110. need to communicate version information through it.
  111. On startup, we use Info to perform a basic handshake. It should include all the
  112. version information.
  113. We also need to be able to update versions in the life of a blockchain. The
  114. natural place to do this is EndBlock.
  115. Note that currently the result of the Handshake isn't exposed anywhere, as the
  116. handshaking happens inside the `proxy.AppConns` abstraction. We will need to
  117. remove the handshaking from the `proxy` package so we can call it independently
  118. and get the result, which should contain the application version.
  119. #### Info
  120. RequestInfo should add support for protocol versions like:
  121. ```
  122. message RequestInfo {
  123. string version
  124. uint64 block_version
  125. uint64 p2p_version
  126. }
  127. ```
  128. Similarly, ResponseInfo should return the versions:
  129. ```
  130. message ResponseInfo {
  131. string data
  132. string version
  133. uint64 app_version
  134. int64 last_block_height
  135. bytes last_block_app_hash
  136. }
  137. ```
  138. The existing `version` fields should be called `software_version` but we leave
  139. them for now to reduce the number of breaking changes.
  140. #### EndBlock
  141. Updating the version could be done either with new fields or by using the
  142. existing `tags`. Since we're trying to communicate information that will be
  143. included in Tendermint block Headers, it should be native to the ABCI, and not
  144. something embedded through some scheme in the tags. Thus, version updates should
  145. be communicated through EndBlock.
  146. EndBlock already contains `ConsensusParams`. We can add version information to
  147. the ConsensusParams as well:
  148. ```
  149. message ConsensusParams {
  150. BlockSize block_size
  151. EvidenceParams evidence_params
  152. VersionParams version
  153. }
  154. message VersionParams {
  155. uint64 block_version
  156. uint64 app_version
  157. }
  158. ```
  159. For now, the `block_version` will be ignored, as we do not allow block version
  160. to be updated live. If the `app_version` is set, it signals that the app's
  161. protocol version has changed, and the new `app_version` will be included in the
  162. `Block.Header.Version.App` for the next block.
  163. ### BlockVersion
  164. BlockVersion is included in both the Header and the NodeInfo.
  165. Changing BlockVersion should happen quite infrequently and ideally only for
  166. critical upgrades. For now, it is not encoded in ABCI, though it's always
  167. possible to use tags to signal an external process to co-ordinate an upgrade.
  168. Note Ethereum has not had to make an upgrade like this (everything has been at state machine level, AFAIK).
  169. ### P2PVersion
  170. P2PVersion is not included in the block Header, just the NodeInfo.
  171. P2PVersion is the first field in the NodeInfo. NodeInfo is also proto3 so this is easy to read out.
  172. Note we need the peer/reactor protocols to take the versions of peers into account when sending messages:
  173. - don't send messages they don't understand
  174. - don't send messages they don't expect
  175. Doing this will be specific to the upgrades being made.
  176. Note we also include the list of reactor channels in the NodeInfo and already don't send messages for channels the peer doesn't understand.
  177. If upgrades always use new channels, this simplifies the development cost of backwards compatibility.
  178. Note NodeInfo is only exchanged after the authenticated encryption handshake to ensure that it's private.
  179. Doing any version exchange before encrypting could be considered information leakage, though I'm not sure
  180. how much that matters compared to being able to upgrade the protocol.
  181. XXX: if needed, can we change the meaning of the first byte of the first message to encode a handshake version?
  182. this is the first byte of a 32-byte ed25519 pubkey.
  183. ### AppVersion
  184. AppVersion is also included in the block Header and the NodeInfo.
  185. AppVersion essentially defines how the AppHash and LastResults are computed.
  186. ### Peer Compatibility
  187. Restricting peer compatibility based on version is complicated by the need to
  188. help old peers, possibly on older versions, sync the blockchain.
  189. We might be tempted to say that we only connect to peers with the same
  190. AppVersion and BlockVersion (since these define the consensus critical
  191. computations), and a select list of P2PVersions (ie. those compatible with
  192. ours), but then we'd need to make accomodations for connecting to peers with the
  193. right Block/AppVersion for the height they're on.
  194. For now, we will connect to peers with any version and restrict compatibility
  195. solely based on the ChainID. We leave more restrictive rules on peer
  196. compatibiltiy to a future proposal.
  197. ### Future Changes
  198. It may be valuable to support an `/unsafe_stop?height=_` endpoint to tell Tendermint to shutdown at a given height.
  199. This could be use by an external manager process that oversees upgrades by
  200. checking out and installing new software versions and restarting the process. It
  201. would subscribe to the relevant upgrade event (needs to be implemented) and call `/unsafe_stop` at
  202. the correct height (of course only after getting approval from its user!)
  203. ## Consequences
  204. ### Positive
  205. - Make tendermint and application versions native to the ABCI to more clearly
  206. communicate about them
  207. - Distinguish clearly between protocol versions and software version to
  208. facilitate implementations in other languages
  209. - Versions included in key data structures in easy to discern way
  210. - Allows proposers to signal for upgrades and apps to decide when to actually change the
  211. version (and start signalling for a new version)
  212. ### Neutral
  213. - Unclear how to version the initial P2P handshake itself
  214. - Versions aren't being used (yet) to restrict peer compatibility
  215. - Signalling for a new version happens through the proposer and must be
  216. tallied/tracked in the app.
  217. ### Negative
  218. - Adds more fields to the ABCI
  219. - Implies that a single codebase must be able to handle multiple versions