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.

104 lines
4.0 KiB

6 years ago
6 years ago
6 years ago
  1. # ADR 020: Limiting txs size inside a block
  2. ## Changelog
  3. 13-08-2018: Initial Draft
  4. 15-08-2018: Second version after Dev's comments
  5. 28-08-2018: Third version after Ethan's comments
  6. 30-08-2018: AminoOverheadForBlock => MaxAminoOverheadForBlock
  7. 31-08-2018: Bounding evidence and chain ID
  8. 13-01-2019: Add section on MaxBytes vs MaxDataBytes
  9. ## Context
  10. We currently use MaxTxs to reap txs from the mempool when proposing a block,
  11. but enforce MaxBytes when unmarshaling a block, so we could easily propose a
  12. block thats too large to be valid.
  13. We should just remove MaxTxs all together and stick with MaxBytes, and have a
  14. `mempool.ReapMaxBytes`.
  15. But we can't just reap BlockSize.MaxBytes, since MaxBytes is for the entire block,
  16. not for the txs inside the block. There's extra amino overhead + the actual
  17. headers on top of the actual transactions + evidence + last commit.
  18. We could also consider using a MaxDataBytes instead of or in addition to MaxBytes.
  19. ## MaxBytes vs MaxDataBytes
  20. The [PR #3045](https://github.com/tendermint/tendermint/pull/3045) suggested
  21. additional clarity/justification was necessary here, wither respect to the use
  22. of MaxDataBytes in addition to, or instead of, MaxBytes.
  23. MaxBytes provides a clear limit on the total size of a block that requires no
  24. additional calculation if you want to use it to bound resource usage, and there
  25. has been considerable discussions about optimizing tendermint around 1MB blocks.
  26. Regardless, we need some maximum on the size of a block so we can avoid
  27. unmarshaling blocks that are too big during the consensus, and it seems more
  28. straightforward to provide a single fixed number for this rather than a
  29. computation of "MaxDataBytes + everything else you need to make room for
  30. (signatures, evidence, header)". MaxBytes provides a simple bound so we can
  31. always say "blocks are less than X MB".
  32. Having both MaxBytes and MaxDataBytes feels like unnecessary complexity. It's
  33. not particularly surprising for MaxBytes to imply the maximum size of the
  34. entire block (not just txs), one just has to know that a block includes header,
  35. txs, evidence, votes. For more fine grained control over the txs included in the
  36. block, there is the MaxGas. In practice, the MaxGas may be expected to do most of
  37. the tx throttling, and the MaxBytes to just serve as an upper bound on the total
  38. size. Applications can use MaxGas as a MaxDataBytes by just taking the gas for
  39. every tx to be its size in bytes.
  40. ## Proposed solution
  41. Therefore, we should
  42. 1) Get rid of MaxTxs.
  43. 2) Rename MaxTxsBytes to MaxBytes.
  44. When we need to ReapMaxBytes from the mempool, we calculate the upper bound as follows:
  45. ```
  46. ExactLastCommitBytes = {number of validators currently enabled} * {MaxVoteBytes}
  47. MaxEvidenceBytesPerBlock = MaxBytes / 10
  48. ExactEvidenceBytes = cs.evpool.PendingEvidence(MaxEvidenceBytesPerBlock) * MaxEvidenceBytes
  49. mempool.ReapMaxBytes(MaxBytes - MaxAminoOverheadForBlock - ExactLastCommitBytes - ExactEvidenceBytes - MaxHeaderBytes)
  50. ```
  51. where MaxVoteBytes, MaxEvidenceBytes, MaxHeaderBytes and MaxAminoOverheadForBlock
  52. are constants defined inside the `types` package:
  53. - MaxVoteBytes - 170 bytes
  54. - MaxEvidenceBytes - 364 bytes
  55. - MaxHeaderBytes - 476 bytes (~276 bytes hashes + 200 bytes - 50 UTF-8 encoded
  56. symbols of chain ID 4 bytes each in the worst case + amino overhead)
  57. - MaxAminoOverheadForBlock - 8 bytes (assuming MaxHeaderBytes includes amino
  58. overhead for encoding header, MaxVoteBytes - for encoding vote, etc.)
  59. ChainID needs to bound to 50 symbols max.
  60. When reaping evidence, we use MaxBytes to calculate the upper bound (e.g. 1/10)
  61. to save some space for transactions.
  62. NOTE while reaping the `max int` bytes in mempool, we should account that every
  63. transaction will take `len(tx)+aminoOverhead`, where aminoOverhead=1-4 bytes.
  64. We should write a test that fails if the underlying structs got changed, but
  65. MaxXXX stayed the same.
  66. ## Status
  67. Implemented
  68. ## Consequences
  69. ### Positive
  70. * one way to limit the size of a block
  71. * less variables to configure
  72. ### Negative
  73. * constants that need to be adjusted if the underlying structs got changed
  74. ### Neutral