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.

201 lines
9.1 KiB

  1. # ADR 081: Protocol Buffers Management
  2. ## Changelog
  3. - 2022-02-28: First draft
  4. ## Status
  5. Accepted
  6. [Tracking issue](https://github.com/tendermint/tendermint/issues/8121)
  7. ## Context
  8. At present, we manage the [Protocol Buffers] schema files ("protos") that define
  9. our wire-level data formats within the Tendermint repository itself (see the
  10. [`proto`](../../proto/) directory). Recently, we have been making use of [Buf],
  11. both locally and in CI, in order to generate Go stubs, and lint and check
  12. `.proto` files for breaking changes.
  13. The version of Buf used at the time of this decision was `v1beta1`, and it was
  14. discussed in [\#7975] and in weekly calls as to whether we should upgrade to
  15. `v1` and harmonize our approach with that used by the Cosmos SDK. The team
  16. managing the Cosmos SDK was primarily interested in having our protos versioned
  17. and easily accessible from the [Buf] registry.
  18. The three main sets of stakeholders for the `.proto` files and their needs, as
  19. currently understood, are as follows.
  20. 1. Tendermint needs Go code generated from `.proto` files.
  21. 2. Consumers of Tendermint's `.proto` files, specifically projects that want to
  22. interoperate with Tendermint and need to generate code for their own
  23. programming language, want to be able to access these files in a reliable and
  24. efficient way.
  25. 3. The Tendermint Core team wants to provide stable interfaces that are as easy
  26. as possible to maintain, on which consumers can depend, and to be able to
  27. notify those consumers promptly when those interfaces change. To this end, we
  28. want to:
  29. 1. Prevent any breaking changes from being introduced in minor/patch releases
  30. of Tendermint. Only major version updates should be able to contain
  31. breaking interface changes.
  32. 2. Prevent generated code from diverging from the Protobuf schema files.
  33. There was also discussion surrounding the notion of automated documentation
  34. generation and hosting, but it is not clear at this time whether this would be
  35. that valuable to any of our stakeholders. What will, of course, be valuable at
  36. minimum would be better documentation (in comments) of the `.proto` files
  37. themselves.
  38. ## Alternative Approaches
  39. ### Meeting stakeholders' needs
  40. 1. Go stub generation from protos. We could use:
  41. 1. [Buf]. This approach has been rather cumbersome up to this point, and it
  42. is not clear what Buf really provides beyond that which `protoc` provides
  43. to justify the additional complexity in configuring Buf for stub
  44. generation.
  45. 2. [protoc] - the Protocol Buffers compiler.
  46. 2. Notification of breaking changes:
  47. 1. Buf in CI for all pull requests to *release* branches only (and not on
  48. `master`).
  49. 2. Buf in CI on every pull request to every branch (this was the case at the
  50. time of this decision, and the team decided that the signal-to-noise ratio
  51. for this approach was too low to be of value).
  52. 3. `.proto` linting:
  53. 1. Buf in CI on every pull request
  54. 4. `.proto` formatting:
  55. 1. [clang-format] locally and a [clang-format GitHub Action] in CI to check
  56. that files are formatted properly on every pull request.
  57. 5. Sharing of `.proto` files in a versioned, reliable manner:
  58. 1. Consumers could simply clone the Tendermint repository, check out a
  59. specific commit, tag or branch and manually copy out all of the `.proto`
  60. files they need. This requires no effort from the Tendermint Core team and
  61. will continue to be an option for consumers. The drawback of this approach
  62. is that it requires manual coding/scripting to implement and is brittle in
  63. the face of bigger changes.
  64. 2. Uploading our `.proto` files to Buf's registry on every release. This is
  65. by far the most seamless for consumers of our `.proto` files, but requires
  66. the dependency on Buf. This has the additional benefit that the Buf
  67. registry will automatically [generate and host
  68. documentation][buf-docs-gen] for these protos.
  69. 3. We could create a process that, upon release, creates a `.zip` file
  70. containing our `.proto` files.
  71. ### Popular alternatives to Buf
  72. [Prototool] was not considered as it appears deprecated, and the ecosystem seems
  73. to be converging on Buf at this time.
  74. ### Tooling complexity
  75. The more tools we have in our build/CI processes, the more complex and fragile
  76. repository/CI management becomes, and the longer it takes to onboard new team
  77. members. Maintainability is a core concern here.
  78. ### Buf sustainability and costs
  79. One of the primary considerations regarding the usage of Buf is whether, for
  80. example, access to its registry will eventually become a
  81. paid-for/subscription-based service and whether this is valuable enough for us
  82. and the ecosystem to pay for such a service. At this time, it appears as though
  83. Buf will never charge for hosting open source projects' protos.
  84. Another consideration was Buf's sustainability as a project - what happens when
  85. their resources run out? Will there be a strong and broad enough open source
  86. community to continue maintaining it?
  87. ### Local Buf usage options
  88. Local usage of Buf (i.e. not in CI) can be accomplished in two ways:
  89. 1. Installing the relevant tools individually.
  90. 2. By way of its [Docker image][buf-docker].
  91. Local installation of Buf requires developers to manually keep their toolchains
  92. up-to-date. The Docker option comes with a number of complexities, including
  93. how the file system permissions of code generated by a Docker container differ
  94. between platforms (e.g. on Linux, Buf-generated code ends up being owned by
  95. `root`).
  96. The trouble with the Docker-based approach is that we make use of the
  97. [gogoprotobuf] plugin for `protoc`. Continuing to use the Docker-based approach
  98. to using Buf will mean that we will have to continue building our own custom
  99. Docker image with embedded gogoprotobuf.
  100. Along these lines, we could eventually consider coming up with a [Nix]- or
  101. [redo]-based approach to developer tooling to ensure tooling consistency across
  102. the team and for anyone who wants to be able to contribute to Tendermint.
  103. ## Decision
  104. 1. We will adopt Buf for now for proto generation, linting, breakage checking
  105. and its registry (mainly in CI, with optional usage locally).
  106. 2. Failing CI when checking for breaking changes in `.proto` files will only
  107. happen when performing minor/patch releases.
  108. 3. Local tooling will be favored over Docker-based tooling.
  109. ## Detailed Design
  110. We currently aim to:
  111. 1. Update to Buf `v1` to facilitate linting, breakage checking and uploading to
  112. the Buf registry.
  113. 2. Configure CI appropriately for proto management:
  114. 1. Uploading protos to the Buf registry on every release (e.g. the
  115. [approach][cosmos-sdk-buf-registry-ci] used by the Cosmos SDK).
  116. 2. Linting on every pull request (e.g. the
  117. [approach][cosmos-sdk-buf-linting-ci] used by the Cosmos SDK). The linter
  118. passing should be considered a requirement for accepting PRs.
  119. 3. Checking for breaking changes in minor/patch version releases and failing
  120. CI accordingly - see [\#8003].
  121. 4. Add [clang-format GitHub Action] to check `.proto` file formatting. Format
  122. checking should be considered a requirement for accepting PRs.
  123. 3. Update the Tendermint [`Makefile`](../../Makefile) to primarily facilitate
  124. local Protobuf stub generation, linting, formatting and breaking change
  125. checking. More specifically:
  126. 1. This includes removing the dependency on Docker and introducing the
  127. dependency on local toolchain installation. CI-based equivalents, where
  128. relevant, will rely on specific GitHub Actions instead of the Makefile.
  129. 2. Go code generation will rely on `protoc` directly.
  130. ## Consequences
  131. ### Positive
  132. - We will still offer Go stub generation, proto linting and breakage checking.
  133. - Breakage checking will only happen on minor/patch releases to increase the
  134. signal-to-noise ratio in CI.
  135. - Versioned protos will be made available via Buf's registry upon every release.
  136. ### Negative
  137. - Developers/contributors will need to install the relevant Protocol
  138. Buffers-related tooling (Buf, gogoprotobuf, clang-format) locally in order to
  139. build, lint, format and check `.proto` files for breaking changes.
  140. ### Neutral
  141. ## References
  142. - [Protocol Buffers]
  143. - [Buf]
  144. - [\#7975]
  145. - [protoc] - The Protocol Buffers compiler
  146. [Protocol Buffers]: https://developers.google.com/protocol-buffers
  147. [Buf]: https://buf.build/
  148. [\#7975]: https://github.com/tendermint/tendermint/pull/7975
  149. [protoc]: https://github.com/protocolbuffers/protobuf
  150. [clang-format]: https://clang.llvm.org/docs/ClangFormat.html
  151. [clang-format GitHub Action]: https://github.com/marketplace/actions/clang-format-github-action
  152. [buf-docker]: https://hub.docker.com/r/bufbuild/buf
  153. [cosmos-sdk-buf-registry-ci]: https://github.com/cosmos/cosmos-sdk/blob/e6571906043b6751951a42b6546431b1c38b05bd/.github/workflows/proto-registry.yml
  154. [cosmos-sdk-buf-linting-ci]: https://github.com/cosmos/cosmos-sdk/blob/e6571906043b6751951a42b6546431b1c38b05bd/.github/workflows/proto.yml#L15
  155. [\#8003]: https://github.com/tendermint/tendermint/issues/8003
  156. [Nix]: https://nixos.org/
  157. [gogoprotobuf]: https://github.com/gogo/protobuf
  158. [Prototool]: https://github.com/uber/prototool
  159. [buf-docs-gen]: https://docs.buf.build/bsr/documentation
  160. [redo]: https://redo.readthedocs.io/en/latest/