-
Notifications
You must be signed in to change notification settings - Fork 636
ADR-103: Protobuf definition versioning #772
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
thanethomson
merged 5 commits into
feature/proto-upgrade
from
thane/adr-protobuf-versioning
May 8, 2023
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
94f9211
Add first draft of ADR-103
thanethomson 8256780
Add rollout strategy
thanethomson 7e18082
Expand on problem with manual diffs
thanethomson db9db89
Clarify that code generators generate breaking code from non-breaking…
thanethomson 3f24891
Clarify that consolidation only applies to currently maintained versions
thanethomson File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,142 @@ | ||||||
# ADR 103: Protobuf definition versioning | ||||||
|
||||||
## Changelog | ||||||
|
||||||
- 2023-04-27: First draft (@thanethomson) | ||||||
|
||||||
## Status | ||||||
|
||||||
Accepted | ||||||
|
||||||
## Context | ||||||
|
||||||
In CometBFT v0.34 through v0.38, the Protocol Buffers definitions in the `proto` | ||||||
folder are organized in a relatively flat structure and evolve over time in | ||||||
major releases of CometBFT. | ||||||
|
||||||
For integrators who may want to interact with nodes running different versions | ||||||
of CometBFT, this means that, when consuming those Protobuf definitions, they | ||||||
need to clone the CometBFT repository and check out the definitions for each and | ||||||
every major version they want to support. It also means that they need to | ||||||
manually diff the types to get a precise sense of what changed between CometBFT | ||||||
releases. Moreover, the differences obtained with the manual diff are often | ||||||
undocumented. | ||||||
|
||||||
We hypothesize that, if we had to version our Protobuf definitions according to | ||||||
[Buf's style guide][buf-style], we could simplify integration efforts with | ||||||
CometBFT in the long run. Adopting such a practice would also introduce a new | ||||||
level of rigour into the way CometBFT Protobuf definitions are managed, allowing | ||||||
for better expectation management with integrators. It would also allow the core | ||||||
team to make better use of Protobuf-related tooling (such as Buf) in enforcing | ||||||
standards, conventions and versioning practices in an automated way. | ||||||
|
||||||
Some context is captured in [\#95] and the issues/PRs to which it links. | ||||||
|
||||||
## Alternative Approaches | ||||||
|
||||||
1. The main alternative here is to do nothing and keep our existing Protobuf | ||||||
definition approach, which suffers from the issues captured in the | ||||||
[Context](#context) section. | ||||||
2. Version our Protobuf definitions, as per this ADR. The primary drawback of | ||||||
introducing versioning is that it represents a substantial breaking change. | ||||||
Within this approach, there are two alternative policies that @mzabaluev has | ||||||
proposed: | ||||||
1. **Conservative**, recommended by Buf: Do not create new versions when | ||||||
making non-breaking changes to Protobuf message definitions, such as | ||||||
adding a new field. The upside to this approach is that non-breaking | ||||||
changes can be made in non-breaking releases of CometBFT, but the downside | ||||||
is that some code generators, such as [prost] for Rust, cannot generate | ||||||
non-breaking code from these non-breaking changes. | ||||||
2. **Sensitive**: Create a new version of a Protobuf message definition any | ||||||
time anything changes, including adding a new field. The upside to this | ||||||
approach is that generated code in languages like Rust is additive and | ||||||
non-breaking, but the downside is that non-breaking Protobuf changes can | ||||||
only be released in new, breaking versions of CometBFT. | ||||||
|
||||||
## Decision | ||||||
|
||||||
From team discussion, it was decided to adopt versioning, using the **sensitive | ||||||
versioning** policy. | ||||||
|
||||||
## Detailed Design | ||||||
|
||||||
### Implementation | ||||||
|
||||||
In order to implement Protobuf definition versioning, it is recommended to bring | ||||||
all of the Protobuf definitions for all currently maintained major CometBFT | ||||||
releases thus far (v0.34, v0.37 and v0.38 as of the time of writing this ADR) | ||||||
into `main`, implementing versioning for each major version's definitions. | ||||||
|
||||||
For example, the v0.34 Protobuf definitions would be brought to `main` as `v1` | ||||||
(i.e. `proto/tendermint/types/types.proto` would become | ||||||
`proto/tendermint/types/v1/types.proto`, and the package would change from | ||||||
`tendermint.types` to `tendermint.types.v1`). | ||||||
|
||||||
Then, the v0.37 Protobuf definitions would be brought to `main`, and only where | ||||||
changes were made according to our **sensitive** versioning policy would we | ||||||
create new types (e.g. `proto/tendermint/types/params.proto` from v0.37 would | ||||||
become `proto/tendermint/types/v2/params.proto` and the package would change | ||||||
from `tendermint.types` to `tendermint.types.v2`). | ||||||
|
||||||
### Minimizing breaking impact | ||||||
|
||||||
Changing the type URLs of Protobuf message types (e.g. `tendermint.types.Block` | ||||||
becoming `tendermint.types.v1.Block`), is considered a breaking change because, | ||||||
in some cases, integrators may be serializing structures into Protobuf | ||||||
`Any`-typed fields. When doing so, the URL of the type being serialized is also | ||||||
embedded in the encoded message. | ||||||
|
||||||
In order to minimize the impact of this breaking change, it is proposed to keep | ||||||
type definitions in the `proto` folder that are _wire-compatible_ with the | ||||||
_latest_ versioned types, but that are unversioned (e.g. exposing | ||||||
`tendermint.types.Block`, which would be wire-compatible with | ||||||
`tendermint.types.v1.Block`). | ||||||
|
||||||
Internally, however, CometBFT would make use of types generated from the | ||||||
versioned Protobuf types only. | ||||||
|
||||||
This would facilitate a transition period for integrators who depend on the old | ||||||
type URL structure, and would allow for a grace period to upgrade to use the | ||||||
versioned type definitions. | ||||||
|
||||||
### Ergonomics of generated code | ||||||
|
||||||
One of the challenges associated with this change is that usage of the generated | ||||||
Go code becomes more difficult for the core team. This is because all generated | ||||||
code will also have version suffixes in package paths, meaning that the core | ||||||
team needs to know exactly which versions of which messages are relevant to the | ||||||
current release when wiring them up. | ||||||
|
||||||
A simple way of mitigating the impact here is to introduce type aliases for the | ||||||
latest versions of generated types, and make use of these aliases internally. | ||||||
|
||||||
### Rollout strategy | ||||||
|
||||||
The current recommended strategy to roll out this change is to accumulate all | ||||||
incremental changes on a **feature branch**, which can then be targeted to a | ||||||
specific release. At present, it is envisaged that CometBFT v0.39 or v0.40 will | ||||||
introduce these changes, but this could change based on negotiation with | ||||||
stakeholders. | ||||||
|
||||||
## Consequences | ||||||
|
||||||
### Positive | ||||||
|
||||||
- Protobuf definitions that are wire-compatible with all versions of CometBFT | ||||||
will be able to be packaged together | ||||||
- The combined Protobuf definitions could be uploaded to the Buf registry for | ||||||
easy consumption by integrators | ||||||
- Changes to Protobuf definitions will be more obvious and explicit to | ||||||
integrators | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This, I think, should also go into the README in the |
||||||
|
||||||
### Negative | ||||||
|
||||||
- While some of the short-term impact of this change can be mitigated, | ||||||
ultimately this is a substantial breaking change for some integrators who | ||||||
depend on the type URLs of the Protobuf definitions | ||||||
- Requires slightly more maintenance than not versioning the types if type | ||||||
aliases need to be maintained for generated code | ||||||
|
||||||
[\#95]: https://github.com/cometbft/cometbft/issues/95 | ||||||
[buf-style]: https://buf.build/docs/best-practices/style-guide/ | ||||||
[prost]: https://github.com/tokio-rs/prost/ |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a paragraph explaining that, when a new version of a protobuf package is introduced, all changes w.r.t. the previous version MUST be documented:
(let me know if you'd rather have me add that paragraph)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This information should rather exist in the README in the
proto
folder. Otherwise people may miss it, given that it'd be buried in an ADR.