Skip to content
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

upate tendermint to 0.40.0 #4963

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

SuperFluffy
Copy link
Contributor

@SuperFluffy SuperFluffy commented Dec 16, 2024

Describe your changes

This patch started out as an attempt to penumbra to use crates.io cnidarium, but quickly snowballed from there to include several connected changs (primarily due to a hard coupling with prost and/or tonic):

  1. [email protected]
  2. [email protected]
  3. [email protected] (and related crates such as tonic_build)
  4. [email protected] (and related crates such as prost_build)
  5. [email protected] (and related crates such as pbjson_build)
  6. [email protected] (induced by the update to tonic)
  7. [email protected]
  8. [email protected] (induced by axum and tonic)
  9. [email protected]
  10. [email protected]
  11. [email protected]
  12. [email protected]
  13. [email protected]
  14. [email protected]
  15. [email protected] (and related utilities such as metrics-exporter-prometheus and metrics-tracing-context)

Checklist before requesting a review

  • I have added guiding text to explain how a reviewer should test these changes.

  • If this code contains consensus-breaking changes, I have added the "consensus-breaking" label. Otherwise, I declare my belief that there are not consensus-breaking changes, for the following reason:

    REPLACE THIS TEXT WITH RATIONALE (CAN BE BRIEF)

tonic = { git = "https://github.com/penumbra-zone/tonic.git", tag = "v0.10.3-penumbra" }
tonic-reflection = { git = "https://github.com/penumbra-zone/tonic.git", tag = "v0.10.3-penumbra" }
tonic-web = { git = "https://github.com/penumbra-zone/tonic.git", tag = "v0.10.3-penumbra" }
tendermint = { git = "https://github.com/informalsystems/tendermint-rs/", rev = "refs/pull/1480/head" }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merged, I shall point them to their main repo. We should create an issue to followup with their patch release.

@@ -344,7 +344,7 @@ impl Opt {
.register_encoded_file_descriptor_set(
penumbra_proto::FILE_DESCRIPTOR_SET,
)
.build()
.build_v1()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build() was deprecated

use tower::ServiceExt;

fn proxy(
channel: Channel,
req: http::Request<Body>,
req: http::Request<BoxBody>,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Body is now a trait - BoxBody seems to have taken its place entirely.

) -> Pin<Box<dyn Future<Output = Result<http::Response<BoxBody>, Infallible>> + Send + 'static>> {
tracing::debug!(headers = ?req.headers(), "proxying request");
// Convert request types
let req = req.map(|b| {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conversion seems no longer necessary because BoxBody is an aliaes for UnsyncBoxBody<Bytes, Status>


let rsp = channel.oneshot(req);

async move {
// Once we get the response, we need to convert any transport errors into
// an Ok(HTTP response reporting an internal error), so we can have Error = Infallible
let rsp = match rsp.await {
Ok(rsp) => rsp.map(|b| {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to above, this conversion is no longer necessary due to the use of BoxBody

}),
Err(e) => tonic::Status::internal(format!("grpc proxy error: {e}")).to_http(),
Ok(rsp) => rsp,
Err(e) => tonic::Status::internal(format!("grpc proxy error: {e}")).into_http(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to_http is now into_http

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All changes in this file are primarily due to Body now being a traid, with tonic::body::BoxBody seemingly having taken over its place.

@@ -28,7 +28,7 @@ anyhow = { workspace = true }
ark-ff = { workspace = true, default-features = true }
async-stream = { workspace = true }
async-trait = { workspace = true }
axum = "0.6"
axum = { workspace = true, features = ["http2"] }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not completely sure about axum, axum::serve, and when/how to activate http2. I have left a lengthy comment in penumbra-core::rpc to that effect.

let grpc_server = penumbra_app::rpc::router(&storage, tm_proxy, enable_expensive_rpc)?;

let grpc_routes = penumbra_app::rpc::routes(&storage, tm_proxy, enable_expensive_rpc)?;
// let grpc_server = penumbra_app::rpc::router(&storage, tm_proxy, enable_expensive_rpc)?;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented out code

// typically uses HTTP/2, which requires HTTPS. Accepting HTTP/2
// allows local applications such as web browsers to talk to pd.
.accept_http1(true)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still needs to be addressed.

The http2-bit might just magically work at all callsites due to our use of axum::serve. But a new trace layer might need be established, for example using tower-http.

@erwanor erwanor self-requested a review December 16, 2024 14:13
@@ -125,8 +143,7 @@ pub fn router(
))))
.add_service(we(tonic_reflection::server::Builder::configure()
.register_encoded_file_descriptor_set(penumbra_proto::FILE_DESCRIPTOR_SET)
.build()
.build_v1()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deprecated

@erwanor erwanor added the consensus-breaking breaking change to execution of on-chain data label Dec 16, 2024
@@ -25,7 +25,10 @@ fn trace_events(events: &[Event]) {
let span = tracing::debug_span!("event", kind = ?event.kind);
span.in_scope(|| {
for attr in &event.attributes {
tracing::debug!(k = ?attr.key, v=?attr.value);
tracing::debug!(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These seemed to be reasonable. Tendermint no longer guarantees that keys and values are utf8: https://docs.rs/tendermint/0.40.0/tendermint/abci/enum.EventAttribute.html

// plain bytes and need not be utf8. This messes with the
// regex and is likely not desirable to have in downstream
// consumers of the indexed events.
match attr.key_str() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to tendermint-rs no longer guaranteeing that keys are utf8: https://docs.rs/tendermint/0.40.0/tendermint/abci/enum.EventAttribute.html

It seemed to make sense that, in the case of keys not being utf8, we do not want to index them. But should this case just be dropped quietly?

@@ -259,6 +259,7 @@ impl Info {
channel_id: chan_id,
port_id: PortId::transfer(),
channel_end: channel,
upgrade_sequence: 0,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New field; I did not know what to do with it, so opted for the default value (as per protobuf convention).

@@ -308,6 +309,7 @@ impl Info {
channel_id: chan_id,
port_id: PortId::transfer(),
channel_end: channel,
upgrade_sequence: 0,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New field; I did not know what to do with it, so opted for the default value (as per protobuf convention).

@@ -70,6 +70,7 @@ impl MsgHandler for MsgChannelCloseConfirm {
remote: expected_counterparty,
connection_hops: expected_connection_hops,
version: channel.version.clone(),
..ChannelEnd::default()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChannelEnd now has a default impl - so I used it for all new fields. Could set them explicitly?

@@ -58,6 +58,7 @@ impl MsgHandler for MsgChannelOpenAck {
remote: expected_counterparty,
connection_hops: expected_connection_hops,
version: self.version_on_b.clone(),
..ChannelEnd::default()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChannelEnd now has a default impl - so I used it for all new fields. Could set them explicitly?

@@ -65,6 +65,7 @@ impl MsgHandler for MsgChannelOpenConfirm {
remote: expected_counterparty,
connection_hops: expected_connection_hops,
version: channel.version.clone(),
..ChannelEnd::default()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChannelEnd now has a default impl - so I used it for all new fields. Could set them explicitly?

@@ -57,6 +57,7 @@ impl MsgHandler for MsgChannelOpenInit {
remote: Counterparty::new(self.port_id_on_b.clone(), None),
connection_hops: self.connection_hops_on_a.clone(),
version: self.version_proposal.clone(),
..ChannelEnd::default()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChannelEnd now has a default impl - so I used it for all new fields. Could set them explicitly?

@@ -49,6 +49,7 @@ impl MsgHandler for MsgChannelOpenTry {
.clone()
.ok_or_else(|| anyhow::anyhow!("no counterparty connection id provided"))?],
version: self.version_supported_on_a.clone(),
..ChannelEnd::default()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChannelEnd now has a default impl - so I used it for all new fields. Could set them explicitly?

@@ -81,6 +82,7 @@ impl MsgHandler for MsgChannelOpenTry {
remote: Counterparty::new(self.port_id_on_a.clone(), Some(self.chan_id_on_a.clone())),
connection_hops: self.connection_hops_on_b.clone(),
version: self.version_supported_on_a.clone(),
..ChannelEnd::default()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChannelEnd now has a default impl - so I used it for all new fields. Could set them explicitly?

@@ -130,6 +132,7 @@ impl<HI: HostInterface + Send + Sync + 'static> ConsensusQuery for IbcQuery<HI>
channel_id: chan_id,
port_id: PortId::transfer(),
channel_end: channel,
upgrade_sequence: 0,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New field; I did not know what to do with it, so opted for the default value (as per protobuf convention).

@@ -187,6 +190,7 @@ impl<HI: HostInterface + Send + Sync + 'static> ConsensusQuery for IbcQuery<HI>
channel_id: chan_id,
port_id: PortId::transfer(),
channel_end: channel,
upgrade_sequence: 0,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New field; I did not know what to do with it, so opted for the default value (as per protobuf convention).

@@ -856,4 +860,28 @@ impl<HI: HostInterface + Send + Sync + 'static> ConsensusQuery for IbcQuery<HI>
}),
}))
}

#[tracing::instrument(skip(self), err, level = "debug")]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are other examples in the penumbra codebase for services that are not yet implemented - so I just opted to go with the same flow here.

@@ -50,7 +50,7 @@ decaf377-ka = {workspace = true}
decaf377-rdsa = {workspace = true}
futures = {workspace = true}
hex = {workspace = true}
ibc-proto = {workspace = true, default-features = false}
ibc-proto = {workspace = true, features = ["transport"], default-features = false}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to expose the generated grpc services of cosmos-sdk; the transport feature now sets cosmos-sdk-proto/grpc-transport, which was previously always exported.

@@ -207,4 +209,18 @@ impl BankQuery for Server {
) -> std::result::Result<tonic::Response<QuerySendEnabledResponse>, tonic::Status> {
Err(tonic::Status::unimplemented("not implemented"))
}

async fn denom_metadata_by_query_string(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, these are new and I chose to do the same thing as other penumbra handlers that have these unimplemented.

@@ -21,7 +21,9 @@ tokio-util = {workspace = true, features = ["full"]}
tonic = {workspace = true}
prost = {workspace = true}
tokio-stream = {workspace = true}
axum = {workspace = true, features = ["headers", "query"]}
axum = {workspace = true }
# TODO: consider using the Query extractor provided by axum-extra
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The query extractor is now provided by both axum and axum-extra, although they have minute differences. Just flagging this here.

axum = {workspace = true, features = ["headers", "query"]}
axum = {workspace = true }
# TODO: consider using the Query extractor provided by axum-extra
axum-extra = {workspace = true, features = ["typed-header"] }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of extractors have been moved out of axum into axum-extra.

@@ -79,8 +80,8 @@ async fn main() -> anyhow::Result<()> {
.unwrap()
}
(None, None) => {
axum::Server::bind(&address)
.serve(app.into_make_service())
let listener = tokio::net::TcpListener::bind(&address).await.unwrap();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be seen also in other parts of the penumbra stack: axum has removed its Server type, instead replacing it with a axum::serve utiilty function.

@@ -262,15 +262,14 @@ fn render_dot(mut tree: watch::Receiver<Tree>) -> MethodRouter {
if !query.graph {
return Ok::<_, (StatusCode, String)>((
TypedHeader(ContentType::json()),
StreamBody::new(
stream::iter(vec![json!({
Body::from_stream(stream::once(future::ok::<_, Infallible>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Axum replaced StreamBody in favor of Body::from_stream

@@ -334,7 +333,7 @@ fn render_dot(mut tree: watch::Receiver<Tree>) -> MethodRouter {
// Manually construct a streaming response to avoid allocating a copy of the large
// rendered bytes: the graph is already rendered as a JSON-escaped string, so we include
// it literally in this output
StreamBody::new(
Body::from_stream(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, StreamBody was replaced in favor of Body::from_stream

@@ -8,7 +8,7 @@ anyhow = "1"

[features]
rpc = ["dep:tonic", "ibc-proto/client"]
box-grpc = ["dep:http-body", "dep:tonic", "dep:tower"]
box-grpc = ["dep:http-body", "dep:http-body-util", "dep:tonic", "dep:tower"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adaptors on the http::Body trait have been moved to http-body-util

http-body = { version = "0.4.5" }
http = { version = "1.2.0" }
http-body = { version = "1.0.1" }
http-body-util = { version = "0.1.2" }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adaptors on the http::Body trait have been moved to http-body-util

@@ -20,7 +17,7 @@ pub type RspBody = UnsyncBoxBody<Bytes, BoxError>;
pub async fn connect(ep: Endpoint) -> anyhow::Result<BoxGrpcService> {
let conn = ep.connect().await?;
let svc = ServiceBuilder::new()
.map_response(|rsp: grpc::Response<transport::Body>| rsp.map(box_rsp_body))
.map_response(|rsp: grpc::Response<tonic::body::BoxBody>| rsp.map(box_rsp_body))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As elsewhere: tonic::body::BoxBody took the place of transport::Body

.with_context(|| format!("could not parse JSON for attribute {:?}", attr))?;
attributes.insert(attr.key.clone(), value);
attributes.insert(String::from_utf8_lossy(attr.key_bytes()).into(), value);
Copy link
Contributor Author

@SuperFluffy SuperFluffy Dec 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seemed to be the least invasive way to deal with tendermints new flexibility around utf8. In the worst case there will be some weird symbols in the attributes. But that's probably fine?

@@ -78,6 +72,25 @@ impl From<tendermint::abci::EventAttribute> for penumbra_pb::Tag {
}
}

// impl From<tendermint::abci::event::v0_37::EventAttribute> for penumbra_pb::Tag {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to remove this: this turned out to not be used.

@@ -89,6 +102,7 @@ impl From<tendermint_rpc::endpoint::broadcast::tx_async::Response>
data,
log,
hash,
..
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New unused fields

@@ -111,6 +125,7 @@ impl From<tendermint_rpc::endpoint::broadcast::tx_sync::Response>
data,
log,
hash,
..
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New unused fields

@@ -288,7 +288,7 @@ where
"made block"
);
// pass the current value of last_commit with this header
let block = Block::new(header.clone(), data, evidence, last_commit)?;
let block = Block::new(header.clone(), data, evidence, last_commit);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has become infallible

@@ -12,7 +12,7 @@ publish = false
[dependencies]
anyhow = {workspace = true}
futures = {workspace = true}
rustls = "0.21"
rustls = "0.23.20"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bump to rustls was induced to due rustls-acme needing http 1.0.0

@@ -45,7 +45,6 @@ pub fn axum_acceptor(

// Define our server configuration, using the ACME certificate resolver.
let mut rustls_config = ServerConfig::builder()
.with_safe_defaults()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently the ServerConfig is now safe by default. I need to dig it up, this was mentioned either in the hyper issue tracker or in their changelog.

@@ -70,7 +70,7 @@ fn main() -> anyhow::Result<()> {
.emit_rerun_if_changed(false)
.server_mod_attribute(".", rpc_doc_attr)
.client_mod_attribute(".", rpc_doc_attr)
.compile_with_config(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deprecated, replaced by compile_protos_with_config

@@ -84,7 +84,7 @@ fn main() -> anyhow::Result<()> {
// We need to feature-gate the RPCs.
.server_mod_attribute(".", rpc_doc_attr)
.client_mod_attribute(".", rpc_doc_attr)
.compile_with_config(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deprecated, replaced by compile_protos_with_config

@@ -206,11 +207,13 @@ impl Opt {
};
let service =
CoordinatorService::new(knower, storage.clone(), queue.clone(), marker);
let grpc_server = Server::builder().add_service(

let routes = Routes::new(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trusty tonic Server can no longer be turned into an (axum) router - instead, tonic routes need to be constructed.

@@ -30,7 +30,7 @@ async fn serve_summoning_jpg() -> impl IntoResponse {
.status(StatusCode::OK)
.header("Content-Type", "image/jpeg")
.header("Cache-Control", "public, max-age=3600") // Cache for 1 hour
.body(axum::body::Full::from(jpg))
.body(axum::body::Body::from(jpg))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

axum::body::Full was removed, and one is to use Body instead (according to their changelog)

@@ -40,7 +40,7 @@ async fn serve_css() -> impl IntoResponse {
.status(StatusCode::OK)
.header("Content-Type", "text/css")
.header("Cache-Control", "public, max-age=3600") // Cache for 1 hour
.body(axum::body::Full::from(css))
.body(axum::body::Body::from(css))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

axum::body::Full was removed, and one is to use Body instead (according to their changelog)

@@ -62,7 +62,7 @@ async fn serve_woff2(filename: &str) -> impl IntoResponse {
.status(StatusCode::OK)
.header("Content-Type", "font/woff2")
.header("Cache-Control", "public, max-age=3600") // Cache for 1 hour
.body(axum::body::Full::from(data))
.body(axum::body::Body::from(data))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

axum::body::Full was removed, and one is to use Body instead (according to their changelog)

let grpc_routes = penumbra_app::rpc::routes(&storage, tm_proxy, enable_expensive_rpc)?
.into_axum_router()
.layer(
ServiceBuilder::new().layer(TraceLayer::new_for_grpc().make_span_with(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This addresses the fact that we can no longer make use of tonic::transport::Server and it's trace_fn setter (since we can no longer turn the "battries included server" back into an axum router).

erwanor added a commit that referenced this pull request Dec 25, 2024
Continuation of #4963, into a release branch `v0.82.x` before tagging a
release candidate at that version and publishing the workspace using an
`alpha` version.

This handles the domain type change for upgradeable channels
(penumbra-zone/ibc-types#84) smoothly. It makes
sure to write default values to the new fields, which avoids wire
protocol changes, and makes this PR non consensus/state breaking.

---------

Co-authored-by: Richard Janis Goldschmidt <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
consensus-breaking breaking change to execution of on-chain data
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants