-
Notifications
You must be signed in to change notification settings - Fork 42
tendermint-rs: /abci_query RPC endpoint (closes #287) #296
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
//! Paths to ABCI data | ||
|
||
use crate::error::Error; | ||
use serde::{Deserialize, Serialize}; | ||
use std::{ | ||
fmt::{self, Display}, | ||
str::FromStr, | ||
}; | ||
|
||
/// Path to ABCI data | ||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] | ||
pub struct Path(String); | ||
|
||
impl Display for Path { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "{}", &self.0) | ||
} | ||
} | ||
|
||
impl FromStr for Path { | ||
type Err = Error; | ||
|
||
fn from_str(s: &str) -> Result<Self, Error> { | ||
Ok(Path(s.to_owned())) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
//! ABCI Merkle proofs | ||
|
||
use crate::error::Error; | ||
use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}; | ||
use std::{ | ||
fmt::{self, Display}, | ||
str::FromStr, | ||
}; | ||
use subtle_encoding::{Encoding, Hex}; | ||
|
||
/// ABCI Merkle proofs | ||
#[derive(Clone, Debug, Eq, Hash, PartialEq)] | ||
pub struct Proof(Vec<u8>); | ||
|
||
impl AsRef<[u8]> for Proof { | ||
fn as_ref(&self) -> &[u8] { | ||
self.0.as_ref() | ||
} | ||
} | ||
|
||
impl Display for Proof { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!( | ||
f, | ||
"{}", | ||
&Hex::upper_case().encode_to_string(&self.0).unwrap() | ||
) | ||
} | ||
} | ||
|
||
impl FromStr for Proof { | ||
type Err = Error; | ||
|
||
fn from_str(s: &str) -> Result<Self, Error> { | ||
let bytes = Hex::upper_case().decode(s)?; | ||
Ok(Proof(bytes)) | ||
} | ||
} | ||
|
||
impl<'de> Deserialize<'de> for Proof { | ||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { | ||
let hex = String::deserialize(deserializer)?; | ||
Ok(Self::from_str(&hex).map_err(|e| D::Error::custom(format!("{}", e)))?) | ||
} | ||
} | ||
|
||
impl Serialize for Proof { | ||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { | ||
self.to_string().serialize(serializer) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ use std::{ | |
/// Block height for a particular chain (i.e. number of blocks created since | ||
/// the chain began) | ||
#[derive(Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)] | ||
pub struct Height(pub u64); | ||
pub struct Height(u64); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With |
||
|
||
impl Height { | ||
/// Convert `u64` to block height. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
//! `/abci_query` endpoint JSONRPC wrapper | ||
|
||
use crate::{ | ||
abci::{Code, Log, Path, Proof}, | ||
block, rpc, serializers, | ||
}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
/// Query the ABCI application for information | ||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] | ||
pub struct Request { | ||
/// Path to the data | ||
path: Option<Path>, | ||
|
||
/// Data to query | ||
data: Vec<u8>, | ||
|
||
/// Block height | ||
height: Option<block::Height>, | ||
|
||
/// Include proof in response | ||
prove: bool, | ||
} | ||
|
||
impl Request { | ||
/// Create a new ABCI query request | ||
pub fn new<D>(path: Option<Path>, data: D, height: Option<block::Height>, prove: bool) -> Self | ||
where | ||
D: Into<Vec<u8>>, | ||
{ | ||
Self { | ||
path, | ||
data: data.into(), | ||
height, | ||
prove, | ||
} | ||
} | ||
} | ||
|
||
impl rpc::Request for Request { | ||
type Response = Response; | ||
|
||
fn method(&self) -> rpc::Method { | ||
rpc::Method::AbciInfo | ||
} | ||
} | ||
|
||
/// ABCI query response wrapper | ||
#[derive(Clone, Debug, Deserialize, Serialize)] | ||
pub struct Response { | ||
/// ABCI query results | ||
pub response: AbciQuery, | ||
} | ||
|
||
impl rpc::Response for Response {} | ||
|
||
/// ABCI query results | ||
#[derive(Clone, Debug, Deserialize, Serialize)] | ||
pub struct AbciQuery { | ||
/// Response code | ||
pub code: Code, | ||
|
||
/// Log value | ||
pub log: Log, | ||
|
||
/// Info value | ||
pub info: Option<String>, | ||
|
||
/// Index | ||
#[cfg_attr( | ||
feature = "serde", | ||
serde( | ||
serialize_with = "serializers::serialize_i64", | ||
deserialize_with = "serializers::parse_i64" | ||
) | ||
)] | ||
pub index: i64, | ||
|
||
/// Key | ||
// TODO(tarcieri): parse to Vec<u8>? | ||
pub key: String, | ||
|
||
/// Value | ||
// TODO(tarcieri): parse to Vec<u8>? | ||
pub value: String, | ||
|
||
/// Proof (if requested) | ||
pub proof: Option<Proof>, | ||
|
||
/// Block height | ||
pub height: block::Height, | ||
|
||
/// Codespace | ||
pub codespace: Option<String>, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,12 @@ mod rpc { | |
assert_eq!(&abci_info.data, "GaiaApp"); | ||
} | ||
|
||
/// `/abci_query` endpoint | ||
#[test] | ||
fn abci_query() { | ||
// TODO(tarcieri): write integration test for this endpoint | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unlike the other endpoints it wasn't clear how to immediately test this in an integration test (with |
||
} | ||
|
||
/// `/block` endpoint | ||
#[test] | ||
fn block() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unlike the other JSON examples found in this directory, this one wasn't taken live from a |
||
"jsonrpc": "2.0", | ||
"id": "", | ||
"result": { | ||
"response": { | ||
"log": "exists", | ||
"height": "1", | ||
"proof": "010114FED0DAD959F36091AD761C922ABA3CBF1D8349990101020103011406AA2262E2F448242DF2C2607C3CDC705313EE3B0001149D16177BC71E445476174622EA559715C293740C", | ||
"value": "61626364", | ||
"key": "61626364", | ||
"index": "-1", | ||
"code": "0" | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ebuchman this seems like it might have some overlap with the stuff you're working on? That said, is this an OK start?