Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
c1310a6
proto: 🧶 add `tendermint-rpc` dependency
cratelyn May 22, 2024
8bbc455
proto: ⏰ add `chrono` dependency
cratelyn May 22, 2024
5805e38
proto: 🤯 add `thiserror` dependency
cratelyn May 22, 2024
b60798f
proto: ⏰ add `tendermint-proto` dependency
cratelyn May 23, 2024
34045a5
tendermint-proxy: 🧼 inherit workspace settings, tidy manifest
cratelyn May 22, 2024
bf68922
tendermint-proxy: 📕 add brief crate-level documentation
cratelyn May 22, 2024
36e6acb
tendermint-proxy: 🚰 add `tap` dependency
cratelyn May 22, 2024
3704858
tendermint-proxy: 🎈 hoist `TendermintProxy` to `lib.rs`
cratelyn May 22, 2024
b732e37
tendermint-proxy: 🔭 instrument `TendermintProxyService` methods
cratelyn May 22, 2024
0f74311
tendermint-proxy: 😬 fix comment typo
cratelyn May 22, 2024
86b9007
tendermint-proxy: ❔ decompose `TendermintProxyService::get_tx(..)` co…
cratelyn May 22, 2024
c211299
tendermint-proxy: ❔ decompose `TendermintProxyService::broadcast_tx_a…
cratelyn May 22, 2024
36f7c5a
tendermint-proxy: ❔ decompose `TendermintProxyService::broadcast_tx_s…
cratelyn May 22, 2024
c18ef1f
tendermint-proxy: ❔ decompose `TendermintProxyService::get_status(..)…
cratelyn May 22, 2024
81cc837
tendermint-proxy: ❔ decompose `TendermintProxyService::abci_query(..)…
cratelyn May 22, 2024
b0d7655
tendermint-proxy: ❔ decompose `TendermintProxyService::get_block_by_h…
cratelyn May 23, 2024
de9f6a9
tendermint-proxy: ❕ move conversions into submodule
cratelyn May 23, 2024
e0d0443
proto: 🚪 feature gate tendermint compatibility
cratelyn May 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
tendermint-proxy: ❔ decompose TendermintProxyService::get_tx(..) co…
…nversions

first, we break down the `get_tx(..)` endpoint, outlining the
conversions therein.

- GetTxResponse
- TxResult
- Tag

NB: there is a `TODO(kate)` added here noting what looks like an
errantly disabled boolean in `tendermint::abci::EventAttribute`.
  • Loading branch information
cratelyn committed May 23, 2024
commit 86b9007de08e8dc196a3d63b24de8917f7ec3482
75 changes: 75 additions & 0 deletions crates/proto/src/protobuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,78 @@ where
}
}
}

mod tendermint_rpc_compat {
use crate::util::tendermint_proxy::v1 as penumbra_pb;

// === get_tx ===

impl From<tendermint_rpc::endpoint::tx::Response> for penumbra_pb::GetTxResponse {
fn from(
tendermint_rpc::endpoint::tx::Response {
hash,
height,
index,
tx_result,
tx,
proof: _,
}: tendermint_rpc::endpoint::tx::Response,
) -> Self {
Self {
height: height.value(),
index: index as u64,
hash: hash.as_bytes().to_vec(),
tx_result: Some(tx_result.into()),
tx,
}
}
}

impl From<tendermint::abci::types::ExecTxResult> for penumbra_pb::TxResult {
fn from(
tendermint::abci::types::ExecTxResult {
log,
gas_wanted,
gas_used,
events,
code: _,
data: _,
info: _,
codespace: _,
}: tendermint::abci::types::ExecTxResult,
) -> Self {
use tendermint::abci::Event;
Self {
log: log.to_string(),
// TODO: validation here, fix mismatch between i64 <> u64
gas_wanted: gas_wanted as u64,
gas_used: gas_used as u64,
tags: events
.into_iter()
.flat_map(|Event { attributes, .. }: Event| {
attributes.into_iter().map(penumbra_pb::Tag::from)
})
.collect(),
}
}
}

impl From<tendermint::abci::EventAttribute> for penumbra_pb::Tag {
fn from(
tendermint::abci::EventAttribute {
key,
value,
index: _,
}: tendermint::abci::EventAttribute,
) -> Self {
Self {
key: key.into_bytes(),
value: value.into_bytes(),
// TODO(kate): this was set to false previously, but it should probably use the
// index field from the tendermint object. for now, carry out a refactor and avoid
// changing behavior while doing so.
index: false,
}
}
}
}
65 changes: 22 additions & 43 deletions crates/util/tendermint-proxy/src/tendermint_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use penumbra_proto::{
AbciQueryResponse, BroadcastTxAsyncRequest, BroadcastTxAsyncResponse,
BroadcastTxSyncRequest, BroadcastTxSyncResponse, GetBlockByHeightRequest,
GetBlockByHeightResponse, GetStatusRequest, GetStatusResponse, GetTxRequest, GetTxResponse,
SyncInfo, Tag, TxResult,
SyncInfo,
},
DomainType, Message,
};
Expand All @@ -26,59 +26,38 @@ impl TendermintProxyService for TendermintProxy {
// since none of the structs are defined in our crates :(
// TODO: move those to proto/src/protobuf.rs

/// Fetches a transaction by hash.
///
/// Returns a [`GetTxResponse`] information about the requested transaction.
#[instrument(level = "info", skip_all)]
async fn get_tx(
&self,
req: tonic::Request<GetTxRequest>,
) -> Result<tonic::Response<GetTxResponse>, Status> {
let client = HttpClient::new(self.tendermint_url.to_string().as_ref()).map_err(|e| {
tonic::Status::unavailable(format!("error creating tendermint http client: {e:#?}"))
// Create an HTTP client, connecting to tendermint.
let client = HttpClient::new(self.tendermint_url.as_ref()).map_err(|e| {
Status::unavailable(format!("error creating tendermint http client: {e:#?}"))
})?;

let req = req.into_inner();
let hash = req.hash;
let prove = req.prove;
// Parse the inbound transaction hash from the client request.
let GetTxRequest { hash, prove } = req.into_inner();
let hash = hash
.try_into()
.map_err(|e| Status::invalid_argument(format!("invalid transaction hash: {e:#?}")))?;

// Send the request to Tendermint.
let rsp = client
.tx(
hash.try_into().map_err(|e| {
tonic::Status::invalid_argument(format!("invalid transaction hash: {e:#?}"))
})?,
prove,
)
.tx(hash, prove)
.await
.map_err(|e| tonic::Status::unavailable(format!("error getting tx: {e}")))?;
.map(GetTxResponse::from)
.map_err(|e| Status::unavailable(format!("error getting tx: {e}")))?;

let tx = Transaction::decode(rsp.tx.as_ref())
.map_err(|e| tonic::Status::unavailable(format!("error decoding tx: {e}")))?;
// Before forwarding along the response, verify that the transaction can be
// successfully decoded into our domain type.
Transaction::decode(rsp.tx.as_ref())
.map_err(|e| Status::unavailable(format!("error decoding tx: {e}")))?;

Ok(tonic::Response::new(GetTxResponse {
tx: tx.into(),
tx_result: Some(TxResult {
log: rsp.tx_result.log.to_string(),
// TODO: validation here, fix mismatch between i64 <> u64
gas_wanted: rsp.tx_result.gas_wanted as u64,
gas_used: rsp.tx_result.gas_used as u64,
tags: rsp
.tx_result
.events
.iter()
.flat_map(|e| {
let a = &e.attributes;
a.iter().map(move |a| {
Tag {
key: a.key.to_string().as_bytes().to_vec(),
value: a.value.to_string().as_bytes().to_vec(),
// TODO: not sure where this index value comes from
index: false,
}
})
})
.collect(),
}),
height: rsp.height.value(),
index: rsp.index as u64,
hash: rsp.hash.as_bytes().to_vec(),
}))
Ok(tonic::Response::new(rsp))
}

#[instrument(level = "info", skip_all)]
Expand Down