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.

261 lines
14 KiB

  1. # RFC 015: ABCI++ TX Mutation
  2. ## Changelog
  3. - 23-Feb-2022: Initial draft (@williambanfield).
  4. - 28-Feb-2022: Revised draft (@williambanfield).
  5. ## Abstract
  6. A previous version of the ABCI++ specification detailed a mechanism for proposers to replace transactions
  7. in the proposed block. This scheme required the proposer to construct new transactions
  8. and mark these new transactions as replacing other removed transactions. The specification
  9. was ambiguous as to how the replacement may be communicated to peer nodes.
  10. This RFC discusses issues with this mechanism and possible solutions.
  11. ## Background
  12. ### What is the proposed change?
  13. A previous version of the ABCI++ specification proposed mechanisms for adding, removing, and replacing
  14. transactions in a proposed block. To replace a transaction, the application running
  15. `ProcessProposal` could mark a transaction as replaced by other application-supplied
  16. transactions by returning a new transaction marked with the `ADDED` flag setting
  17. the `new_hashes` field of the removed transaction to contain the list of transaction hashes
  18. that replace it. In that previous specification for ABCI++, the full use of the
  19. `new_hashes` field is left somewhat ambiguous. At present, these hashes are not
  20. gossiped and are not eventually included in the block to signal replacement to
  21. other nodes. The specification did indicate that the transactions specified in
  22. the `new_hashes` field will be removed from the mempool but it's not clear how
  23. peer nodes will learn about them.
  24. ### What systems would be affected by adding transaction replacement?
  25. The 'transaction' is a central building block of a Tendermint blockchain, so adding
  26. a mechanism for transaction replacement would require changes to many aspects of Tendermint.
  27. The following is a rough list of the functionality that this mechanism would affect:
  28. #### Transaction indexing
  29. Tendermint's indexer stores transactions and transaction results using the hash of the executed
  30. transaction [as the key][tx-result-index] and the ABCI results and transaction bytes as the value.
  31. To allow transaction replacement, the replaced transactions would need to stored as well in the
  32. indexer, likely as a mapping of original transaction to list of transaction hashes that replaced
  33. the original transaction.
  34. #### Transaction inclusion proofs
  35. The result of a transaction query includes a Merkle proof of the existence of the
  36. transaction in the block chain. This [proof is built][inclusion-proof] as a merkle tree
  37. of the hashes of all of the transactions in the block where the queried transaction was executed.
  38. To allow transaction replacement, these proofs would need to be updated to prove
  39. that a replaced transaction was included by replacement in the block.
  40. #### RPC-based transaction query parameters and results
  41. Tendermint's RPC allows clients to retrieve information about transactions via the
  42. `/tx_search` and `/tx` RPC endpoints.
  43. RPC query results containing replaced transactions would need to be updated to include
  44. information on replaced transactions, either by returning results for all of the replaced
  45. transactions, or by including a response with just the hashes of the replaced transactions
  46. which clients could proceed to query individually.
  47. #### Mempool transaction removal
  48. Additional logic would need to be added to the Tendermint mempool to clear out replaced
  49. transactions after each block is executed. Tendermint currently removes executed transactions
  50. from the mempool, so this would be a pretty straightforward change.
  51. ## Discussion
  52. ### What value may be added to Tendermint by introducing transaction replacement?
  53. Transaction replacement would would enable applications to aggregate or disaggregate transactions.
  54. For aggregation, a set of transactions that all related work, such as transferring
  55. tokens between the same two accounts, could be replaced with a single transaction,
  56. i.e. one that transfers a single sum from one account to the other.
  57. Applications that make frequent use of aggregation may be able to achieve a higher throughput.
  58. Aggregation would decrease the space occupied by a single client-submitted transaction in the block, allowing
  59. more client-submitted transactions to be executed per block.
  60. For disaggregation, a very complex transaction could be split into multiple smaller transactions.
  61. This may be useful if an application wishes to perform more fine-grained indexing on intermediate parts
  62. of a multi-part transaction.
  63. ### Drawbacks to transaction replacement
  64. Transaction replacement would require updating and shimming many of the places that
  65. Tendermint records and exposes information about executed transactions. While
  66. systems within Tendermint could be updated to account for transaction replacement,
  67. such a system would leave new issues and rough edges.
  68. #### No way of guaranteeing correct replacement
  69. If a user issues a transaction to the network and the transaction is replaced, the
  70. user has no guarantee that the replacement was correct. For example, suppose a set of users issue
  71. transactions A, B, and C and they are all aggregated into a new transaction, D.
  72. There is nothing guaranteeing that D was constructed correctly from the inputs.
  73. The only way for users to ensure D is correct would be if D contained all of the
  74. information of its constituent transactions, in which case, nothing is really gained by the replacement.
  75. #### Replacement transactions not signed by submitter
  76. Abstractly, Tendermint simply views transactions as a ball of bytes and therefore
  77. should be fine with replacing one for another. However, many applications require
  78. that transactions submitted to the chain be signed by some private key to authenticate
  79. and authorize the transaction. Replaced transactions could not be signed by the
  80. submitter, only by the application node. Therefore, any use of transaction replacement
  81. could not contain authorization from the submitter and would either need to grant
  82. application-submitted transactions power to perform application logic on behalf
  83. of a user without their consent.
  84. Granting this power to application-submitted transactions would be very dangerous
  85. and therefore might not be of much value to application developers.
  86. Transaction replacement might only be really safe in the case of application-submitted
  87. transactions or for transactions that require no authorization. For such transactions,
  88. it's quite not quite clear what the utility of replacement is: the application can already
  89. generate any transactions that it wants. The fact that such a transaction was a replacement
  90. is not particularly relevant to participants in the chain since the application is
  91. merely replacing its own transactions.
  92. #### New vector for censorship
  93. Depending on the implementation, transaction replacement may allow a node signal
  94. to the rest of the chain that some transaction should no longer be considered for execution.
  95. Honest nodes will use the replacement mechanism to signal that a transaction has been aggregated.
  96. Malicious nodes will be granted a new vector for censoring transactions.
  97. There is no guarantee that a replaced transactions is actually executed at all.
  98. A malicious node could censor a transaction by simply listing it as replaced.
  99. Honest nodes seeing the replacement would flush the transaction from their mempool
  100. and not execute or propose it it in later blocks.
  101. ### Transaction tracking implementations
  102. This section discusses possible ways to flesh out the implementation of transaction replacement.
  103. Specifically, this section proposes a few alternative ways that Tendermint blockchains could
  104. track and store transaction replacements.
  105. #### Include transaction replacements in the block
  106. One option to track transaction replacement is to include information on the
  107. transaction replacement within the block. An additional structure may be added
  108. the block of the following form:
  109. ```proto
  110. message Block {
  111. ...
  112. repeated Replacement replacements = 5;
  113. }
  114. message Replacement {
  115. bytes included_tx_key = 1;
  116. repeated bytes replaced_txs_keys = 2;
  117. }
  118. ```
  119. Applications executing `PrepareProposal` would return the list of replacements and
  120. Tendermint would include an encoding of these replacements in the block that is gossiped
  121. and committed.
  122. Tendermint's transaction indexing would include a new mapping for each replaced transaction
  123. key to the committed transaction.
  124. Transaction inclusion proofs would be updated to include these additional new transaction
  125. keys in the Merkle tree and queries for transaction hashes that were replaced would return
  126. information indicating that the transaction was replaced along with the hash of the
  127. transaction that replaced it.
  128. Block validation of gossiped blocks would be updated to check that each of the
  129. `included_txs_key` matches the hash of some transaction in the proposed block.
  130. Implementing the changes described in this section would allow Tendermint to gossip
  131. and index transaction replacements as part of block propagation. These changes would
  132. still require the application to certify that the replacements were valid. This
  133. validation may be performed in one of two ways:
  134. 1. **Applications optimistically trust that the proposer performed a legitimate replacement.**
  135. In this validation scheme, applications would not verify that the substitution
  136. is valid during consensus and instead simply trust that the proposer is correct.
  137. This would have the drawback of allowing a malicious proposer to remove transactions
  138. it did not want executed.
  139. 2. **Applications completely validate transaction replacement.**
  140. In this validation scheme, applications that allow replacement would check that
  141. each listed replaced transaction was correctly reflected in the replacement transaction.
  142. In order to perform such validation, the node would need to have the replaced transactions
  143. locally. This could be accomplished one of a few ways: by querying the mempool,
  144. by adding an additional p2p gossip channel for transaction replacements, or by including the replaced transactions
  145. in the block. Replacement validation via mempool querying would require the node
  146. to have received all of the replaced transactions in the mempool which is far from
  147. guaranteed. Adding an additional gossip channel would make gossiping replaced transactions
  148. a requirement for consensus to proceed, since all nodes would need to receive all replacement
  149. messages before considering a block valid. Finally, including replaced transactions in
  150. the block seems to obviate any benefit gained from performing a transaction replacement
  151. since the replaced transaction and the original transactions would now both appear in the block.
  152. #### Application defined transaction replacement
  153. An additional option for allowing transaction replacement is to leave it entirely as a responsibility
  154. of the application. The `PrepareProposal` ABCI++ call allows for applications to add
  155. new transactions to a proposed block. Applications that wished to implement a transaction
  156. replacement mechanism would be free to do so without the newly defined `new_hashes` field.
  157. Applications wishing to implement transaction replacement would add the aggregated
  158. transactions in the `PrepareProposal` response, and include one additional bookkeeping
  159. transaction that listed all of the replacements, with a similar scheme to the `new_hashes`
  160. field described in ABCI++. This new bookkeeping transaction could be used by the
  161. application to determine which transactions to clear from the mempool in future calls
  162. to `CheckTx`.
  163. The meaning of any transaction in the block is completely opaque to Tendermint,
  164. so applications performing this style of replacement would not be able to have the replacement
  165. reflected in any most of Tendermint's transaction tracking mechanisms, such as transaction indexing
  166. and the `/tx` endpoint.
  167. #### Application defined Tx Keys
  168. Tendermint currently uses cryptographic hashes, SHA256, as a key for each transaction.
  169. As noted in the section on systems that would require changing, this key is used
  170. to identify the transaction in the mempool, in the indexer, and within the RPC system.
  171. An alternative approach to allowing `ProcessProposal` to specify a set of transaction
  172. replacements would be instead to allow the application to specify an additional key or set
  173. of keys for each transaction during `ProcessProposal`. This new `secondary_keys` set
  174. would be included in the block and therefore gossiped during block propagation.
  175. Additional RPC endpoints could be exposed to query by the application-defined keys.
  176. Applications wishing to implement replacement would leverage this new field by providing the
  177. replaced transaction hashes as the `secondary_keys` and checking their validity during
  178. `ProcessProposal`. During `RecheckTx` the application would then be responsible for
  179. clearing out transactions that matched the `secondary_keys`.
  180. It is worth noting that something like this would be possible without `secondary_keys`.
  181. An application wishing to implement a system like this one could define a replacement
  182. transaction, as discussed in the section on application-defined transaction replacement,
  183. and use a custom [ABCI event type][abci-event-type] to communicate that the replacement should
  184. be indexed within Tendermint's ABCI event indexing.
  185. ### Complexity to value-add tradeoff
  186. It is worth remarking that adding a system like this may introduce a decent amount
  187. of new complexity into Tendermint. An approach that leaves much of the replacement
  188. logic to Tendermint would require altering the core transaction indexing and querying
  189. data. In many of the cases listed, a system for transaction replacement is possible
  190. without explicitly defining it as part of `PrepareProposal`. Since applications
  191. can now add transactions during `PrepareProposal` they can and should leverage this
  192. functionality to include additional bookkeeping transactions in the block. It may
  193. be worth encouraging applications to discover new and interesting ways to leverage this
  194. power instead of immediately solving the problem for them.
  195. ### References
  196. [inclusion-proof]: https://github.com/tendermint/tendermint/blob/0fcfaa4568cb700e27c954389c1fcd0b9e786332/types/tx.go#L67
  197. [tx-serach-result]: https://github.com/tendermint/tendermint/blob/0fcfaa4568cb700e27c954389c1fcd0b9e786332/rpc/coretypes/responses.go#L267
  198. [tx-rpc-func]: https://github.com/tendermint/tendermint/blob/0fcfaa4568cb700e27c954389c1fcd0b9e786332/internal/rpc/core/tx.go#L21
  199. [tx-result-index]: https://github.com/tendermint/tendermint/blob/0fcfaa4568cb700e27c954389c1fcd0b9e786332/internal/state/indexer/tx/kv/kv.go#L90
  200. [abci-event-type]: https://github.com/tendermint/tendermint/blob/0fcfaa4568cb700e27c954389c1fcd0b9e786332/abci/types/types.pb.go#L3168