Skip to content

Commit

Permalink
rpc: Add temporary fix and tests for block_results serialization (#…
Browse files Browse the repository at this point in the history
…1061)

* Rename kvstore module to common, since it provides common RPC requests

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Use the unused config params

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Rename quick module to kvstore, since it caters exclusively for the kvstore

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add support for simple query plan for Gaia

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove outdated RPC request/response parsing tests

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove redundant interaction

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Enable rustls for wss support

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Use defaults if no version, app or app_version is supplied in ResponseInfo over ABCI and RPC

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Regenerate protos

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add convenience method to decode RPC requests from strings

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add deserialization workaround for validator updates

This introduces a (somewhat hacky, yet temporary) approach to being able
to deserialize public keys in validator updates until such time that
Tendermint addresses the problem.

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add test fixtures generated from local Gaia instance

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add test for outgoing requests

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add test case specifically for #1021

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Fix test case for #1021

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add changelog entry

Signed-off-by: Thane Thomson <connect@thanethomson.com>
  • Loading branch information
thanethomson authored Dec 20, 2021
1 parent 8354fec commit e562d4d
Show file tree
Hide file tree
Showing 81 changed files with 4,924 additions and 23,249 deletions.
4 changes: 4 additions & 0 deletions .changelog/unreleased/workarounds/1021-rpc-block_results.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- `[tendermint-rpc]` Allow deserialization of public keys from validator updates
from `block_results` endpoint in multiple JSON formats until this is fixed in
Tendermint
([#1021](https://github.com/informalsystems/tendermint-rs/issues/1021))
3 changes: 2 additions & 1 deletion proto/src/prost/tendermint.abci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,10 @@ pub struct ResponseInfo {
#[prost(string, tag="1")]
pub data: ::prost::alloc::string::String,
#[prost(string, tag="2")]
#[serde(default)]
pub version: ::prost::alloc::string::String,
#[prost(uint64, tag="3")]
#[serde(with = "crate::serializers::from_str")]
#[serde(with = "crate::serializers::from_str", default)]
pub app_version: u64,
#[prost(int64, tag="4")]
#[serde(with = "crate::serializers::from_str")]
Expand Down
21 changes: 11 additions & 10 deletions rpc/src/client/transport/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,11 @@ mod test {
use tokio::fs;

async fn read_json_fixture(name: &str) -> String {
fs::read_to_string(PathBuf::from("./tests/support/").join(name.to_owned() + ".json"))
.await
.unwrap()
fs::read_to_string(
PathBuf::from("./tests/kvstore_fixtures/incoming/").join(name.to_owned() + ".json"),
)
.await
.unwrap()
}

async fn read_event(name: &str) -> Event {
Expand All @@ -251,20 +253,19 @@ mod test {
#[tokio::test]
async fn mock_client() {
let abci_info_fixture = read_json_fixture("abci_info").await;
let block_fixture = read_json_fixture("block").await;
let block_fixture = read_json_fixture("block_at_height_10").await;
let matcher = MockRequestMethodMatcher::default()
.map(Method::AbciInfo, Ok(abci_info_fixture))
.map(Method::Block, Ok(block_fixture));
let (client, driver) = MockClient::new(matcher);
let driver_hdl = tokio::spawn(async move { driver.run().await });

let abci_info = client.abci_info().await.unwrap();
assert_eq!("GaiaApp".to_string(), abci_info.data);
assert_eq!(Height::from(488120_u32), abci_info.last_block_height);
assert_eq!("{\"size\":0}".to_string(), abci_info.data);

let block = client.block(Height::from(10_u32)).await.unwrap().block;
assert_eq!(Height::from(10_u32), block.header.height);
assert_eq!("cosmoshub-2".parse::<Id>().unwrap(), block.header.chain_id);
assert_eq!("dockerchain".parse::<Id>().unwrap(), block.header.chain_id);

client.close();
driver_hdl.await.unwrap().unwrap();
Expand All @@ -275,9 +276,9 @@ mod test {
let (client, driver) = MockClient::new(MockRequestMethodMatcher::default());
let driver_hdl = tokio::spawn(async move { driver.run().await });

let event1 = read_event("event_new_block_1").await;
let event2 = read_event("event_new_block_2").await;
let event3 = read_event("event_new_block_3").await;
let event1 = read_event("subscribe_newblock_0").await;
let event2 = read_event("subscribe_newblock_1").await;
let event3 = read_event("subscribe_newblock_2").await;
let events = vec![event1, event2, event3];

let subs1 = client.subscribe(EventType::NewBlock.into()).await.unwrap();
Expand Down
10 changes: 6 additions & 4 deletions rpc/src/client/transport/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,11 @@ mod test {
use tokio::time::{self, Duration};

async fn read_json_fixture(name: &str) -> String {
fs::read_to_string(PathBuf::from("./tests/support/").join(name.to_owned() + ".json"))
.await
.unwrap()
fs::read_to_string(
PathBuf::from("./tests/kvstore_fixtures/incoming/").join(name.to_owned() + ".json"),
)
.await
.unwrap()
}

async fn read_event(name: &str) -> Event {
Expand Down Expand Up @@ -193,7 +195,7 @@ mod test {
// Another subscription with a different query
router.add(subs3_id, "query2", subs3_event_tx);

let mut ev = read_event("event_new_block_1").await;
let mut ev = read_event("subscribe_newblock_0").await;
ev.query = "query1".into();
router.publish_event(ev.clone());

Expand Down
14 changes: 8 additions & 6 deletions rpc/src/client/transport/websocket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1094,9 +1094,11 @@ mod test {
}

async fn read_json_fixture(name: &str) -> String {
fs::read_to_string(PathBuf::from("./tests/support/").join(name.to_owned() + ".json"))
.await
.unwrap()
fs::read_to_string(
PathBuf::from("./tests/kvstore_fixtures/incoming/").join(name.to_owned() + ".json"),
)
.await
.unwrap()
}

async fn read_event(name: &str) -> Event {
Expand All @@ -1105,9 +1107,9 @@ mod test {

#[tokio::test]
async fn websocket_client_happy_path() {
let event1 = read_event("event_new_block_1").await;
let event2 = read_event("event_new_block_2").await;
let event3 = read_event("event_new_block_3").await;
let event1 = read_event("subscribe_newblock_0").await;
let event2 = read_event("subscribe_newblock_1").await;
let event3 = read_event("subscribe_newblock_2").await;
let test_events = vec![event1, event2, event3];

println!("Starting WebSocket server...");
Expand Down
8 changes: 7 additions & 1 deletion rpc/src/request.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! JSON-RPC requests

use super::{Id, Method, Version};
use crate::prelude::*;
use crate::{prelude::*, Error};
use core::fmt::Debug;
use serde::{de::DeserializeOwned, Deserialize, Serialize};

Expand All @@ -17,6 +17,12 @@ pub trait Request: Debug + DeserializeOwned + Serialize + Sized + Send {
fn into_json(self) -> String {
Wrapper::new(self).into_json()
}

/// Parse a JSON-RPC request from a JSON string.
fn from_string(s: impl AsRef<[u8]>) -> Result<Self, Error> {
let wrapper: Wrapper<Self> = serde_json::from_slice(s.as_ref()).map_err(Error::serde)?;
Ok(wrapper.params)
}
}

/// Simple JSON-RPC requests which correlate with a single response from the
Expand Down
163 changes: 163 additions & 0 deletions rpc/tests/gaia_fixtures.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
use std::fs;
use std::path::PathBuf;
use tendermint_rpc::event::Event;
use tendermint_rpc::{endpoint, Request, Response};
use walkdir::WalkDir;

fn find_fixtures(in_out_folder_name: &str) -> Vec<PathBuf> {
WalkDir::new(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("gaia_fixtures")
.join(in_out_folder_name),
)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| {
e.file_type().is_file()
&& e.path().extension().is_some()
&& e.path().extension().unwrap() == "json"
})
.map(|e| e.into_path())
.collect::<Vec<PathBuf>>()
}

#[test]
fn incoming_fixtures() {
for json_file in find_fixtures("incoming") {
let file_name = json_file
.file_name()
.unwrap()
.to_str()
.unwrap()
.strip_suffix(".json")
.unwrap();
let content = fs::read_to_string(&json_file).unwrap();
match file_name {
"abci_info" => {
let r = endpoint::abci_info::Response::from_string(content);
assert!(r.is_ok(), "{:?}", r)
}
"block_at_height_0" => {
assert!(endpoint::block::Response::from_string(content).is_err())
}
"block_at_height_1" => {
assert!(endpoint::block::Response::from_string(content).is_ok())
}
"block_at_height_10" => {
assert!(endpoint::block::Response::from_string(content).is_ok())
}
"block_at_height_4555980" => {
let r = endpoint::block::Response::from_string(content);
assert!(r.is_ok(), "{:?}", r);
}
"block_results_at_height_10" => {
let r = endpoint::block_results::Response::from_string(content);
assert!(r.is_ok(), "block_results_at_height_10: {:?}", r);
}
"block_results_at_height_4555980" => {
let r = endpoint::block_results::Response::from_string(content);
assert!(r.is_ok(), "block_results_at_height_4555980: {:?}", r);
}
"blockchain_from_1_to_10" => {
assert!(endpoint::blockchain::Response::from_string(content).is_ok())
}
"commit_at_height_10" => {
assert!(endpoint::commit::Response::from_string(content).is_ok())
}
"consensus_params" => {
assert!(endpoint::consensus_params::Response::from_string(content).is_ok())
}
"consensus_state" => {
assert!(endpoint::consensus_state::Response::from_string(content).is_ok())
}
"genesis" => {
assert!(endpoint::genesis::Response::from_string(content).is_ok())
}
"net_info" => {
assert!(endpoint::net_info::Response::from_string(content).is_ok())
}
"status" => {
assert!(endpoint::status::Response::from_string(content).is_ok())
}
"subscribe_newblock" => {
let r = endpoint::subscribe::Response::from_string(content);
assert!(r.is_err(), "{:?}", r);
}
_ => {
if file_name.starts_with("subscribe_newblock_") {
let r = Event::from_string(content);
assert!(r.is_ok(), "failed to parse event {}: {:?}", file_name, r);
} else {
panic!("unhandled incoming fixture: {}", file_name);
}
}
}
}
}

#[test]
fn outgoing_fixtures() {
for json_file in find_fixtures("outgoing") {
let file_name = json_file
.file_name()
.unwrap()
.to_str()
.unwrap()
.strip_suffix(".json")
.unwrap();
let content = fs::read_to_string(&json_file).unwrap();
match file_name {
"abci_info" => {
let r = endpoint::abci_info::Request::from_string(content);
assert!(r.is_ok(), "{:?}", r)
}
"block_at_height_0" => {
assert!(endpoint::block::Request::from_string(content).is_ok())
}
"block_at_height_1" => {
assert!(endpoint::block::Request::from_string(content).is_ok())
}
"block_at_height_10" => {
assert!(endpoint::block::Request::from_string(content).is_ok())
}
"block_at_height_4555980" => {
assert!(endpoint::block::Request::from_string(content).is_ok())
}
"block_results_at_height_10" => {
let r = endpoint::block_results::Request::from_string(content);
assert!(r.is_ok(), "block_results_at_height_10: {:?}", r);
}
"block_results_at_height_4555980" => {
let r = endpoint::block_results::Request::from_string(content);
assert!(r.is_ok(), "block_results_at_height_4555980: {:?}", r);
}
"blockchain_from_1_to_10" => {
assert!(endpoint::blockchain::Request::from_string(content).is_ok())
}
"commit_at_height_10" => {
assert!(endpoint::commit::Request::from_string(content).is_ok())
}
"consensus_params" => {
assert!(endpoint::consensus_params::Request::from_string(content).is_ok())
}
"consensus_state" => {
assert!(endpoint::consensus_state::Request::from_string(content).is_ok())
}
"genesis" => {
assert!(endpoint::genesis::Request::from_string(content).is_ok())
}
"net_info" => {
assert!(endpoint::net_info::Request::from_string(content).is_ok())
}
"status" => {
assert!(endpoint::status::Request::from_string(content).is_ok())
}
"subscribe_newblock" => {
let r = endpoint::subscribe::Request::from_string(content);
assert!(r.is_ok(), "{:?}", r);
}
_ => panic!("unhandled outgoing fixture: {}", file_name),
}
}
}
11 changes: 11 additions & 0 deletions rpc/tests/gaia_fixtures/incoming/abci_info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"id": "279cb095-9064-4620-bcaa-3c9383847575",
"jsonrpc": "2.0",
"result": {
"response": {
"data": "GaiaApp",
"last_block_app_hash": "vMfcSlXF/bB/xdsaQeFALAzVoY6AKqiFwchFz9ZUguc=",
"last_block_height": "154"
}
}
}
9 changes: 9 additions & 0 deletions rpc/tests/gaia_fixtures/incoming/block_at_height_0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"error": {
"code": -32603,
"data": "height must be greater than 0, but got 0",
"message": "Internal error"
},
"id": "29b5f462-d1cb-4b33-ab23-f0c96aa462b0",
"jsonrpc": "2.0"
}
57 changes: 57 additions & 0 deletions rpc/tests/gaia_fixtures/incoming/block_at_height_1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"id": "6b12587c-a02b-441b-9350-6a8a5ee6fb3b",
"jsonrpc": "2.0",
"result": {
"block": {
"data": {
"txs": []
},
"evidence": {
"evidence": []
},
"header": {
"app_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
"chain_id": "ibc-0",
"consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F",
"data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
"evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
"height": "1",
"last_block_id": {
"hash": "",
"parts": {
"hash": "",
"total": 0
}
},
"last_commit_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
"last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
"next_validators_hash": "0A6CA9001DB07E985DF9043045B392588DF7C1C720E30EBAEFDC8A848C551D6A",
"proposer_address": "BB22AD764B674CC08753B24175E2FC61B22B1419",
"time": "2021-12-17T20:27:28.966992937Z",
"validators_hash": "0A6CA9001DB07E985DF9043045B392588DF7C1C720E30EBAEFDC8A848C551D6A",
"version": {
"block": "11"
}
},
"last_commit": {
"block_id": {
"hash": "",
"parts": {
"hash": "",
"total": 0
}
},
"height": "0",
"round": 0,
"signatures": []
}
},
"block_id": {
"hash": "739127E7942BEF14DFF0C3C9C4A9BF0DF1A97BEFF085153817B8960273830439",
"parts": {
"hash": "AF225F2883AFC75DB7F481E5BDEE396CE9B5787399F8F9876CA980BD026C02D1",
"total": 1
}
}
}
}
Loading

0 comments on commit e562d4d

Please sign in to comment.