From 4b94a92d1928dc418c0b31c7a091c7868f55156c Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Wed, 17 Apr 2024 10:28:49 +0100 Subject: [PATCH] DEBUG: Print response on JSON-RPC query errors (#881) --- fendermint/rpc/Cargo.toml | 1 + fendermint/rpc/src/client.rs | 110 +++++++++++++++++++++++++++++++++-- fendermint/rpc/src/query.rs | 26 +++++++-- 3 files changed, 127 insertions(+), 10 deletions(-) diff --git a/fendermint/rpc/Cargo.toml b/fendermint/rpc/Cargo.toml index 165c5b854..0d944470d 100644 --- a/fendermint/rpc/Cargo.toml +++ b/fendermint/rpc/Cargo.toml @@ -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 } diff --git a/fendermint/rpc/src/client.rs b/fendermint/rpc/src/client.rs index ef520c7bd..8741187b3 100644 --- a/fendermint/rpc/src/client.rs +++ b/fendermint/rpc/src/client.rs @@ -178,7 +178,11 @@ where F: FnOnce(&DeliverTx) -> anyhow::Result + 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, @@ -201,7 +205,11 @@ where F: FnOnce(&DeliverTx) -> anyhow::Result + 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, @@ -224,7 +232,11 @@ where F: FnOnce(&DeliverTx) -> anyhow::Result + 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 @@ -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(pub R); + + #[derive(Serialize, Deserialize)] + pub struct DebugResponse(pub R); + + impl trpc::Request for DebugRequest + where + R: trpc::Request, + { + type Response = DebugResponse; + } + + impl trpc::request::RequestMessage for DebugRequest + where + R: trpc::request::RequestMessage, + { + fn method(&self) -> trpc::Method { + self.0.method() + } + } + + impl trpc::SimpleRequest for DebugRequest + where + R: trpc::SimpleRequest, + { + type Output = Self::Response; + } + + impl trpc::Response for DebugResponse + where + R: trpc::Response, + { + fn from_string(response: impl AsRef<[u8]>) -> Result { + let wrapper: Result, 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 { + let wrapper: trpc::response::Wrapper = + serde_json::from_reader(reader).map_err(trpc::Error::serde)?; + wrapper.into_result() + } + } +} diff --git a/fendermint/rpc/src/query.rs b/fendermint/rpc/src/query.rs index cfef1edc1..930606229 100644 --- a/fendermint/rpc/src/query.rs +++ b/fendermint/rpc/src/query.rs @@ -33,7 +33,10 @@ pub struct QueryResponse { pub trait QueryClient: Sync { /// Query the contents of a CID from the IPLD store. async fn ipld(&self, cid: &Cid, height: FvmQueryHeight) -> anyhow::Result>> { - 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)) } @@ -43,7 +46,10 @@ pub trait QueryClient: Sync { address: &Address, height: FvmQueryHeight, ) -> anyhow::Result>> { - 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 }) @@ -57,7 +63,8 @@ pub trait QueryClient: Sync { ) -> anyhow::Result> { 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 }) @@ -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) @@ -88,7 +96,10 @@ pub trait QueryClient: Sync { &self, height: FvmQueryHeight, ) -> anyhow::Result> { - 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) @@ -102,7 +113,10 @@ pub trait QueryClient: Sync { &self, height: FvmQueryHeight, ) -> anyhow::Result> { - 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| {