Skip to content

Commit 12e83a7

Browse files
authored
ADR 012: Multi-Version Support (#1274)
* ADR 012: Multi-Version Support * ADR 012: Update CompactMode doc * ADR 012: Filled out text, bump changelog date * ADR 012: editorialize the Context section * ADR 012: write about RPC version discovery * ADR 012: decide on tendermint-abci * ADR 012: Fill out consequences, bump changelog * ADR 012: refer to CompatMode::latest() The LATEST associated const has been changed to the function. * ADR 012: Commit review suggestions from Thane * ADR 012: fix a typo * ADR 012: add examples of API use
1 parent 60e10ab commit 12e83a7

1 file changed

Lines changed: 175 additions & 0 deletions

File tree

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# ADR 012: Support for multiple versions of CometBFT Core
2+
3+
## Changelog
4+
5+
* 2023-03-02: First draft
6+
7+
## Context
8+
9+
As new releases of CometBFT come out, tendermint-rs should have a
10+
viable way to support the versions of the protocol in use by the Cosmos
11+
community. Hermes presents a particular challenge of needing to support
12+
multiple different versions of the protocol within a single software agent
13+
that performs IBC relaying across chains that are not necessarily using the
14+
same CometBFT version.
15+
16+
Previously, it was feasible for tendermint-rs to support a single version of
17+
the CometBFT protocols and expect all chain and relayer operators to
18+
upgrade their software in sync. But now there is a number of established chains
19+
using CometBFT 0.34 in production, and new chains using future versions of the
20+
protocol are expected to be deployed into the shared Cosmos ecosystem
21+
so that relaying is possible between the old and the new chains.
22+
23+
The approach to protocol evolution and versioning in CometBFT has not been
24+
very rigorous to date. As a result, the 0.37 release has a number of breaking
25+
changes in the RPC protocol format. Though the changes seem beneficial
26+
in the long term, there is only an ad-hoc way to discover which version is used
27+
by the node and select the appropriate encoding. It appears to be too
28+
late in the development process to introduce significant changes to mitigate
29+
this in the 0.37 release timeframe. A requirement to specify the
30+
protocol version in chain configuration would complicate the deployment
31+
experience for chain and relayer operators and should be avoided.
32+
33+
Another motivation for multi-version support is versioning of tendermint-rs
34+
itself: previously, the semver compatibility of tendermint-rs releases was
35+
tied with corresponding CometBFT version sequences in a none too obvious way.
36+
It's desirable to decouple tendermint-rs versioning from that of CometBFT,
37+
making it solely a matter of Rust crate API evolution. In the long term,
38+
a single version of the tendermint-rs libraries should be able to support all
39+
versions of CometBFT protocols that are relevant to the community.
40+
The developers of CometBFT protocols should take versioning practices into use
41+
for future revisions that support backward compatibility on the source code level.
42+
43+
## Decision
44+
45+
The tendermint-rs library API will be modified to provide support for
46+
multiple versions of CometBFT APIs, at this moment being 0.34 and 0.37.
47+
48+
### tendermint-proto
49+
50+
The generated Rust files providing bindings for Tendermint protobuf defitions
51+
will be emitted in two side-by-side modules, `tendermint::v0_34` and
52+
`tendermint::v0_37`. All names under the latter module are also reexported under
53+
the `tendermint` module, providing a low-change migration path for code bases
54+
that used previous versions of the crate, and the "default" import paths for
55+
those applications that only need to target the latest version.
56+
57+
### tendermint
58+
59+
The domain types are largely unchanged, except where additional fields are
60+
needed to support version 0.37. Some new types are added as required by the
61+
new version. Conversions to and from Protobuf types defined in
62+
`tendermint-proto` are provided for both `tendermint::v0_34` and
63+
`tendermint::v0_37` generated types, except where the types are new to 0.37.
64+
65+
### tendermint-rpc
66+
67+
A compatibility mode parameter is introduced for HTTP and WebSocket clients,
68+
with the following type:
69+
70+
```rust
71+
pub enum CompatMode {
72+
/// Use the v0.37 version of the protocol.
73+
V0_37,
74+
/// Use v0.34 version of the protocol.
75+
V0_34,
76+
}
77+
```
78+
79+
The mode parameter is used to dynamically select the encoding used by a client.
80+
By default, the clients use the latest protocol (designated by the associated
81+
const function `CompatMode::latest()`), but it's possible to specify
82+
the compatibility mode at construction using the newly introduced configuration
83+
API. In the HTTP client, it's also possible to switch the mode for a client
84+
that has been already connected; this is useful for dynamic version discovery
85+
using the `status` endpoint.
86+
87+
The `Client` trait is extended to support methods new to CometBFT 0.37,
88+
which are emulated using older protocol endpoints when `V0_34` compatibility
89+
mode is selected. There is no need to deprecate any methods. All data types
90+
in the public client API are the domain types of `tendermint`, so the
91+
difference in encoding is confined to the crate internals.
92+
93+
Protocol version discovery is not implemented in the library in a way that
94+
would be invisible to the API user. To discover the Tendermint version, a client
95+
needs to make a `status` request and process the version data from the response.
96+
The format of the response is not divergent between the supported protocol
97+
versions, which is why this should succeed regardless of the compatibility mode
98+
initially selected. As the RPC client API represents individual endpoint requests,
99+
it would be wrong to have the implementation perform a hidden RPC roundtrip to
100+
discover the version when needed, and have the client exhibit interior
101+
mutability that is otherwise not needed. In the future, a more formalized way
102+
to discover the protocol version in use should be provided, so this ad-hoc
103+
approach is expected to be eventually deprecated.
104+
105+
#### Examples
106+
107+
Connecting to the WebSocket endpoint with a specified compatibility mode:
108+
109+
```rust
110+
use tendermint_rpc::client::{CompatMode, WebSocketClient};
111+
112+
// ...
113+
114+
let client = WebSocketClient::builder(rpc_url)
115+
.compat_mode(CompatMode::V0_34)
116+
.build()
117+
.await?;
118+
```
119+
120+
Discovery of the RPC compatibility mode while preserving the HTTP connection:
121+
122+
```rust
123+
use tendermint_rpc::client::{Client, CompatMode, HttpClient, HttpClientUrl};
124+
use tendermint_rpc::error::Error;
125+
126+
async fn rpc_client_with_version_discovery<U>(url: U) -> Result<HttpClient, Error>
127+
where
128+
U: TryInto<HttpClientUrl, Error = Error>,
129+
{
130+
let mut rpc_client = HttpClient::new(url)?;
131+
let status = rpc_client.status().await?;
132+
let compat_mode = CompatMode::from_version(status.node_info.version)?;
133+
rpc_client.set_compat_mode(compat_mode);
134+
Ok(rpc_client)
135+
}
136+
```
137+
138+
### tendermint-abci
139+
140+
This crate is not actively supported and we should only make the minimal effort
141+
to update it to the 0.37 version of ABCI. No backward compatibility with 0.34
142+
or multi-version support is to be implemented; the consumers should be steered
143+
towards [tower-abci](https://github.com/penumbra-zone/tower-abci).
144+
145+
## Status
146+
147+
Proposed
148+
149+
## Consequences
150+
151+
### Positive
152+
153+
RPC interoperability with both 0.34 and 0.37 nodes is possible in a single built
154+
executable and a single runtime process without much extra coding effort.
155+
156+
Consumers of other tendermint-rs crates will get support for both 0.34 and 0.37
157+
versions of the protobuf messages and be able to use either or both.
158+
159+
### Negative
160+
161+
The consumers of `tendermint-rpc` wishing to remain interoperable with 0.34 nodes
162+
will have to configure the compatibility mode or add version discovery when
163+
migrating to the release of the crate that introduces these changes.
164+
165+
Conversions from and to Protobuf message types in `tendermint-proto`
166+
and the domain types in `tendermint` are no longer unambiguously resolved
167+
by type inference and the types sometimes have to be explicitly annotated.
168+
169+
The existing consumers of `tendermint-abci` who wish to remain on 0.34
170+
will be effectively stranded on the previous semver break release of the crate
171+
(0.29.x as of this writing).
172+
173+
## References
174+
175+
* Implementation: [#1193](https://github.com/informalsystems/tendermint-rs/pull/1193)

0 commit comments

Comments
 (0)