Skip to content

Commit

Permalink
DEBUG: Print response on JSON-RPC query errors (#881)
Browse files Browse the repository at this point in the history
  • Loading branch information
aakoshh authored Apr 17, 2024
1 parent fa564e1 commit 4b94a92
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 10 deletions.
1 change: 1 addition & 0 deletions fendermint/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ base64 = { workspace = true }
bytes = { workspace = true }
prost = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tendermint = { workspace = true }
tendermint-rpc = { workspace = true }
tendermint-proto = { workspace = true }
Expand Down
110 changes: 106 additions & 4 deletions fendermint/rpc/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,11 @@ where
F: FnOnce(&DeliverTx) -> anyhow::Result<T> + Sync + Send,
{
let data = SignedMessageFactory::serialize(&msg)?;
let response = self.inner.broadcast_tx_async(data).await?;
let response = self
.inner
.broadcast_tx_async(data)
.await
.context("broadcast_tx_async failed")?;
let response = AsyncResponse {
response,
return_data: PhantomData,
Expand All @@ -201,7 +205,11 @@ where
F: FnOnce(&DeliverTx) -> anyhow::Result<T> + Sync + Send,
{
let data = SignedMessageFactory::serialize(&msg)?;
let response = self.inner.broadcast_tx_sync(data).await?;
let response = self
.inner
.broadcast_tx_sync(data)
.await
.context("broadcast_tx_sync failed")?;
let response = SyncResponse {
response,
return_data: PhantomData,
Expand All @@ -224,7 +232,11 @@ where
F: FnOnce(&DeliverTx) -> anyhow::Result<T> + Sync + Send,
{
let data = SignedMessageFactory::serialize(&msg)?;
let response = self.inner.broadcast_tx_commit(data).await?;
let response = self
.inner
.broadcast_tx_commit(data)
.await
.context("broadcast_tx_commit failed")?;
// We have a fully `DeliverTx` with default fields even if `CheckTx` indicates failure.
let return_data = if response.check_tx.code.is_err() || response.deliver_tx.code.is_err() {
None
Expand Down Expand Up @@ -254,7 +266,97 @@ where
let height: u64 = height.into();
let height = Height::try_from(height).context("failed to conver to Height")?;

let res = client.abci_query(None, data, Some(height), false).await?;
// This is how we'd call it, but here we're trying to debug what's going on using
// the `perform` method below with a request that prints the response if it fails
// to deserialize for any reason.
// let res = client
// .abci_query(None, data, Some(height), false)
// .await
// .context("abci query failed")?;

let req = tendermint_rpc::endpoint::abci_query::Request::new(None, data, Some(height), false);

let res = client
.perform(debug::DebugRequest(req))
.await
.context("abci query failed")?
.0
.response;

Ok(res)
}

mod debug {
use serde::{Deserialize, Serialize};
use tendermint_rpc as trpc;

#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub struct DebugRequest<R>(pub R);

#[derive(Serialize, Deserialize)]
pub struct DebugResponse<R>(pub R);

impl<R> trpc::Request for DebugRequest<R>
where
R: trpc::Request,
{
type Response = DebugResponse<R::Response>;
}

impl<R> trpc::request::RequestMessage for DebugRequest<R>
where
R: trpc::request::RequestMessage,
{
fn method(&self) -> trpc::Method {
self.0.method()
}
}

impl<R> trpc::SimpleRequest for DebugRequest<R>
where
R: trpc::SimpleRequest,
{
type Output = Self::Response;
}

impl<R> trpc::Response for DebugResponse<R>
where
R: trpc::Response,
{
fn from_string(response: impl AsRef<[u8]>) -> Result<Self, trpc::Error> {
let wrapper: Result<trpc::response::Wrapper<Self>, trpc::Error> =
serde_json::from_slice(response.as_ref()).map_err(trpc::Error::serde);

let response_body = || String::from_utf8_lossy(response.as_ref()).to_string();

match wrapper {
Err(e) => {
tracing::error!(
error = e.to_string(),
response = response_body(),
"failed to parse JSON-RPC response"
);
Err(e)
}
Ok(wrapper) => match wrapper.into_result() {
Err(e) => {
tracing::error!(
error = e.to_string(),
response = response_body(),
"error from JSON-RPC"
);
Err(e)
}
Ok(response) => Ok(response),
},
}
}

fn from_reader(reader: impl std::io::prelude::Read) -> Result<Self, trpc::Error> {
let wrapper: trpc::response::Wrapper<Self> =
serde_json::from_reader(reader).map_err(trpc::Error::serde)?;
wrapper.into_result()
}
}
}
26 changes: 20 additions & 6 deletions fendermint/rpc/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ pub struct QueryResponse<T> {
pub trait QueryClient: Sync {
/// Query the contents of a CID from the IPLD store.
async fn ipld(&self, cid: &Cid, height: FvmQueryHeight) -> anyhow::Result<Option<Vec<u8>>> {
let res = self.perform(FvmQuery::Ipld(*cid), height).await?;
let res = self
.perform(FvmQuery::Ipld(*cid), height)
.await
.context("ipld query failed")?;
extract_opt(res, |res| Ok(res.value))
}

Expand All @@ -43,7 +46,10 @@ pub trait QueryClient: Sync {
address: &Address,
height: FvmQueryHeight,
) -> anyhow::Result<QueryResponse<Option<(ActorID, ActorState)>>> {
let res = self.perform(FvmQuery::ActorState(*address), height).await?;
let res = self
.perform(FvmQuery::ActorState(*address), height)
.await
.context("actor state query failed")?;
let height = res.height;
let value = extract_actor_state(res)?;
Ok(QueryResponse { height, value })
Expand All @@ -57,7 +63,8 @@ pub trait QueryClient: Sync {
) -> anyhow::Result<QueryResponse<response::DeliverTx>> {
let res = self
.perform(FvmQuery::Call(Box::new(message)), height)
.await?;
.await
.context("call query failed")?;
let height = res.height;
let value = extract(res, parse_deliver_tx)?;
Ok(QueryResponse { height, value })
Expand All @@ -74,7 +81,8 @@ pub trait QueryClient: Sync {

let res = self
.perform(FvmQuery::EstimateGas(Box::new(message)), height)
.await?;
.await
.context("estimate gas query failed")?;
let height = res.height;
let value = extract(res, |res| {
fvm_ipld_encoding::from_slice(&res.value)
Expand All @@ -88,7 +96,10 @@ pub trait QueryClient: Sync {
&self,
height: FvmQueryHeight,
) -> anyhow::Result<QueryResponse<StateParams>> {
let res = self.perform(FvmQuery::StateParams, height).await?;
let res = self
.perform(FvmQuery::StateParams, height)
.await
.context("state params query failed")?;
let height = res.height;
let value = extract(res, |res| {
fvm_ipld_encoding::from_slice(&res.value)
Expand All @@ -102,7 +113,10 @@ pub trait QueryClient: Sync {
&self,
height: FvmQueryHeight,
) -> anyhow::Result<QueryResponse<BuiltinActors>> {
let res = self.perform(FvmQuery::BuiltinActors, height).await?;
let res = self
.perform(FvmQuery::BuiltinActors, height)
.await
.context("builtin actors query failed")?;
let height = res.height;
let value = {
let registry: Vec<(String, Cid)> = extract(res, |res| {
Expand Down

0 comments on commit 4b94a92

Please sign in to comment.