Write serialized proof to file

This commit is contained in:
hu55a1n1 2023-12-31 15:59:59 -08:00
parent 57d71ed391
commit 2d6ef2ee7f
6 changed files with 166 additions and 49 deletions

View file

@ -9,6 +9,8 @@ cosmrs = { version = "0.15.0", default-features = false }
displaydoc = { version = "0.2.4", default-features = false }
ics23 = { version = "0.11.0", default-features = false, features = ["host-functions"] }
prost = { version = "0.12.3", default-features = false }
serde = { version = "1.0.189", features = ["derive"] }
serde_with = { version = "3.4.0", default-features = false, features = ["hex", "macros"] }
tendermint = { version = "0.34.0", default-features = false }
tendermint-rpc = { version = "0.34.0", default-features = false, features = ["http-client"] }

View file

@ -2,6 +2,8 @@ use alloc::{boxed::Box, vec::Vec};
use core::fmt::Debug;
use displaydoc::Display;
use serde::{Deserialize, Serialize};
use serde_with::{hex::Hex, serde_as};
use tendermint::merkle::proof::ProofOps;
use tendermint_rpc::endpoint::abci_query::AbciQuery;
@ -16,11 +18,10 @@ use crate::{
verifier::cw::CwVerifier,
};
pub type RawCwProof = CwProof<Vec<u8>, Vec<u8>>;
#[derive(Clone, Debug)]
pub struct CwProof<K, V> {
pub struct CwProof<K = Vec<u8>, V = Vec<u8>> {
proof: ProofOps,
// TODO(hu55a1n1): replace `K` with `CwAbciKey`
key: PrefixedKey<PrefixWasm, K>,
value: V,
}
@ -29,6 +30,75 @@ pub struct CwProof<K, V> {
#[derive(Clone, Debug, Display)]
pub struct ErrorWithoutProof;
impl TryFrom<AbciQuery> for CwProof {
type Error = ErrorWithoutProof;
fn try_from(query: AbciQuery) -> Result<Self, Self::Error> {
RawCwProof::try_from(query).map(Into::into)
}
}
impl<K, V> Proof for CwProof<K, V>
where
K: Clone + Into<Vec<u8>>,
V: AsRef<[u8]>,
{
type Key = K;
type Value = V;
type ProofOps = ProofOps;
fn verify(&self, root: Vec<u8>) -> Result<(), ProofError> {
fn into_array_of_size_2<T: Debug>(v: Vec<T>) -> Result<[T; 2], ProofError> {
let boxed_slice = v.into_boxed_slice();
let boxed_array: Box<[T; 2]> = boxed_slice.try_into().expect("todo");
Ok(*boxed_array)
}
let Self { proof, key, value } = self;
let proofs = convert_tm_to_ics_merkle_proof(proof)?;
let cw_verifier = CwVerifier::default();
cw_verifier.verify(
&into_array_of_size_2(proofs)?,
&root,
&into_array_of_size_2(key.clone().into_keys())?,
value.as_ref(),
)?;
Ok(())
}
}
#[serde_as]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RawCwProof {
#[serde_as(as = "Hex")]
key: Vec<u8>,
#[serde_as(as = "Hex")]
value: Vec<u8>,
proof: ProofOps,
}
impl From<RawCwProof> for CwProof {
fn from(RawCwProof { key, value, proof }: RawCwProof) -> Self {
Self {
proof,
key: PrefixedKey::new(key),
value,
}
}
}
impl From<CwProof> for RawCwProof {
fn from(CwProof { proof, key, value }: CwProof) -> Self {
Self {
key: key.into_keys().pop().expect("empty key"),
value,
proof,
}
}
}
impl TryFrom<AbciQuery> for RawCwProof {
type Error = ErrorWithoutProof;
@ -40,41 +110,6 @@ impl TryFrom<AbciQuery> for RawCwProof {
return Err(ErrorWithoutProof);
};
Ok(Self {
proof,
key: PrefixedKey::new(key),
value,
})
}
}
impl<K, V> Proof for CwProof<K, V>
where
K: Into<Vec<u8>>,
V: Into<Vec<u8>>,
{
type Key = K;
type Value = V;
type ProofOps = ProofOps;
fn verify(self, root: Vec<u8>) -> Result<(), ProofError> {
fn into_array_of_size_2<T: Debug>(v: Vec<T>) -> Result<[T; 2], ProofError> {
let boxed_slice = v.into_boxed_slice();
let boxed_array: Box<[T; 2]> = boxed_slice.try_into().expect("todo");
Ok(*boxed_array)
}
let Self { proof, key, value } = self;
let proofs = convert_tm_to_ics_merkle_proof(&proof)?;
let cw_verifier = CwVerifier::default();
cw_verifier.verify(
&into_array_of_size_2(proofs)?,
&root,
&into_array_of_size_2(key.into_keys())?,
&value.into(),
)?;
Ok(())
Ok(Self { proof, key, value })
}
}

View file

@ -32,5 +32,5 @@ pub trait Proof {
type Value;
type ProofOps;
fn verify(self, root: Vec<u8>) -> Result<(), ProofError>;
fn verify(&self, root: Vec<u8>) -> Result<(), ProofError>;
}

View file

@ -206,6 +206,16 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"num-traits",
"serde",
]
[[package]]
name = "clap"
version = "4.4.11"
@ -358,6 +368,8 @@ dependencies = [
"displaydoc",
"ics23",
"prost",
"serde",
"serde_with",
"tendermint",
"tendermint-rpc",
]
@ -376,6 +388,41 @@ dependencies = [
"tokio",
]
[[package]]
name = "darling"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.41",
]
[[package]]
name = "darling_macro"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [
"darling_core",
"quote",
"syn 2.0.41",
]
[[package]]
name = "der"
version = "0.7.8"
@ -790,6 +837,12 @@ dependencies = [
"sha3",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.5.0"
@ -1424,6 +1477,33 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_with"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
dependencies = [
"base64",
"chrono",
"hex",
"serde",
"serde_json",
"serde_with_macros",
"time",
]
[[package]]
name = "serde_with_macros"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.41",
]
[[package]]
name = "sha2"
version = "0.9.9"

View file

@ -0,0 +1 @@
{"key":"03ade4a5f5803a439835c636395a8d648dee57b2fc90d98dc17fa887159b69638b7367787374617465","value":"7b22636f6d707574655f6d72656e636c617665223a2264633433663863343264386535663532633862626436386634323632343231353366306265313036333066663863636132353531323961336361303364323733222c226b65795f6d616e616765725f6d72656e636c617665223a2231636632653532393131343130666266336631393930353661393864353837393561353539613265383030393333663766636431336430343834363232373163222c227463625f696e666f223a2233313233383736227d","proof":{"ops":[{"field_type":"ics23:iavl","key":"A63kpfWAOkOYNcY2OVqNZI3uV7L8kNmNwX+ohxWbaWOLc2d4c3RhdGU=","data":"CrgDCikDreSl9YA6Q5g1xjY5Wo1kje5XsvyQ2Y3Bf6iHFZtpY4tzZ3hzdGF0ZRLIAXsiY29tcHV0ZV9tcmVuY2xhdmUiOiJkYzQzZjhjNDJkOGU1ZjUyYzhiYmQ2OGY0MjYyNDIxNTNmMGJlMTA2MzBmZjhjY2EyNTUxMjlhM2NhMDNkMjczIiwia2V5X21hbmFnZXJfbXJlbmNsYXZlIjoiMWNmMmU1MjkxMTQxMGZiZjNmMTk5MDU2YTk4ZDU4Nzk1YTU1OWEyZTgwMDkzM2Y3ZmNkMTNkMDQ4NDYyMjcxYyIsInRjYl9pbmZvIjoiMzEyMzg3NiJ9GgwIARgBIAEqBAACmAEiKggBEiYCBJgBIFclzyzP2y2LTcBhP0IxBhvnlMJiEFCsDEMUQ9dM5dvYICIsCAESBQQGmAEgGiEgfUSWe0VMFTsxkzDuMQNE05aSzdRTTvkWzZXkfplWUbEiKggBEiYGDJBnIEkK+nmGmXpOfREXvfonLrK4mEZx1XF4DgJp86QIVF1EICIsCAESBQgakGcgGiEgBl/NSR16eG1vDenJA6GEEJ9xcQv9Bwxv8wyhAL5JLwE="},{"field_type":"ics23:simple","key":"d2FzbQ==","data":"CqgBCgR3YXNtEiDYWxn2B9M/eGP18Gwl3zgWZkT7Yn/iFlcS0THfmfcfDBoJCAEYASABKgEAIiUIARIhAWLU8PgnJ/EMp4BYvtTN9MX/rS70dNQ3ZAzrJLssrLjRIiUIARIhAeZ4u8MKaaJoanRG1ZtncskBGpLgN5tPEXihifKcMflrIiUIARIhASJkYRU83gOvlkSLVW5EV87q/xnJXY2+Iipku/9Sjq/x"}]}}

View file

@ -26,12 +26,11 @@ use clap::{Parser, Subcommand};
use cosmrs::AccountId;
use tendermint::{block::Height, AppHash};
use tendermint_rpc::{
client::HttpClient as TmRpcClient,
endpoint::{abci_query::AbciQuery, status::Response},
Client, HttpClientUrl,
client::HttpClient as TmRpcClient, endpoint::status::Response, Client, HttpClientUrl,
};
use cw_proof::proof::{cw::RawCwProof, key::CwAbciKey, Proof};
use cw_proof::proof::cw::RawCwProof;
use cw_proof::proof::{cw::CwProof, key::CwAbciKey, Proof};
#[derive(Debug, Parser)]
#[command(author, version, about, long_about = None)]
@ -91,7 +90,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
.abci_query(Some(path), data, Some(proof_height), true)
.await?;
let proof: RawCwProof = result.clone().try_into().map_err(into_string)?;
let proof: CwProof = result.clone().try_into().map_err(into_string)?;
proof
.verify(latest_app_hash.clone().into())
.map_err(into_string)?;
@ -99,7 +98,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
println!("{}", String::from_utf8(result.value.clone())?);
if let Some(proof_file) = proof_file {
write_proof_to_file(proof_file, result)?;
write_proof_to_file(proof_file, proof.into())?;
}
}
};
@ -123,18 +122,18 @@ fn latest_proof_height_hash(status: Response) -> (Height, AppHash) {
(proof_height, latest_app_hash)
}
fn write_proof_to_file(proof_file: PathBuf, output: AbciQuery) -> Result<(), Box<dyn Error>> {
fn write_proof_to_file(proof_file: PathBuf, proof: RawCwProof) -> Result<(), Box<dyn Error>> {
let file = File::create(proof_file)?;
let mut writer = BufWriter::new(file);
serde_json::to_writer(&mut writer, &output)?;
serde_json::to_writer(&mut writer, &proof)?;
writer.flush()?;
Ok(())
}
#[cfg(test)]
mod tests {
use tendermint_rpc::endpoint::abci_query::AbciQuery;
use cw_proof::{proof::cw::RawCwProof, proof::Proof};
use tendermint_rpc::endpoint::abci_query::AbciQuery;
#[test]
fn test_query_item() {