From 2d6ef2ee7f71fe11654439012b84a96db4e79e19 Mon Sep 17 00:00:00 2001 From: hu55a1n1 Date: Sun, 31 Dec 2023 15:59:59 -0800 Subject: [PATCH] Write serialized proof to file --- utils/cw-proof/Cargo.toml | 2 + utils/cw-proof/src/proof/cw.rs | 113 +++++++++++++++++++++----------- utils/cw-proof/src/proof/mod.rs | 2 +- utils/cw-prover/Cargo.lock | 80 ++++++++++++++++++++++ utils/cw-prover/query.proof | 1 + utils/cw-prover/src/main.rs | 17 +++-- 6 files changed, 166 insertions(+), 49 deletions(-) create mode 100644 utils/cw-prover/query.proof diff --git a/utils/cw-proof/Cargo.toml b/utils/cw-proof/Cargo.toml index 5b2f050..feebbb0 100644 --- a/utils/cw-proof/Cargo.toml +++ b/utils/cw-proof/Cargo.toml @@ -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"] } diff --git a/utils/cw-proof/src/proof/cw.rs b/utils/cw-proof/src/proof/cw.rs index 7ceea90..93db3bc 100644 --- a/utils/cw-proof/src/proof/cw.rs +++ b/utils/cw-proof/src/proof/cw.rs @@ -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>; - #[derive(Clone, Debug)] -pub struct CwProof { +pub struct CwProof, V = Vec> { proof: ProofOps, + // TODO(hu55a1n1): replace `K` with `CwAbciKey` key: PrefixedKey, value: V, } @@ -29,6 +30,75 @@ pub struct CwProof { #[derive(Clone, Debug, Display)] pub struct ErrorWithoutProof; +impl TryFrom for CwProof { + type Error = ErrorWithoutProof; + + fn try_from(query: AbciQuery) -> Result { + RawCwProof::try_from(query).map(Into::into) + } +} + +impl Proof for CwProof +where + K: Clone + Into>, + V: AsRef<[u8]>, +{ + type Key = K; + type Value = V; + type ProofOps = ProofOps; + + fn verify(&self, root: Vec) -> Result<(), ProofError> { + fn into_array_of_size_2(v: Vec) -> 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, + #[serde_as(as = "Hex")] + value: Vec, + proof: ProofOps, +} + +impl From for CwProof { + fn from(RawCwProof { key, value, proof }: RawCwProof) -> Self { + Self { + proof, + key: PrefixedKey::new(key), + value, + } + } +} + +impl From for RawCwProof { + fn from(CwProof { proof, key, value }: CwProof) -> Self { + Self { + key: key.into_keys().pop().expect("empty key"), + value, + proof, + } + } +} + impl TryFrom for RawCwProof { type Error = ErrorWithoutProof; @@ -40,41 +110,6 @@ impl TryFrom for RawCwProof { return Err(ErrorWithoutProof); }; - Ok(Self { - proof, - key: PrefixedKey::new(key), - value, - }) - } -} - -impl Proof for CwProof -where - K: Into>, - V: Into>, -{ - type Key = K; - type Value = V; - type ProofOps = ProofOps; - - fn verify(self, root: Vec) -> Result<(), ProofError> { - fn into_array_of_size_2(v: Vec) -> 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 }) } } diff --git a/utils/cw-proof/src/proof/mod.rs b/utils/cw-proof/src/proof/mod.rs index e9ac244..3fb970a 100644 --- a/utils/cw-proof/src/proof/mod.rs +++ b/utils/cw-proof/src/proof/mod.rs @@ -32,5 +32,5 @@ pub trait Proof { type Value; type ProofOps; - fn verify(self, root: Vec) -> Result<(), ProofError>; + fn verify(&self, root: Vec) -> Result<(), ProofError>; } diff --git a/utils/cw-prover/Cargo.lock b/utils/cw-prover/Cargo.lock index 0913ae9..0c7ed5a 100644 --- a/utils/cw-prover/Cargo.lock +++ b/utils/cw-prover/Cargo.lock @@ -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" diff --git a/utils/cw-prover/query.proof b/utils/cw-prover/query.proof new file mode 100644 index 0000000..9053ddd --- /dev/null +++ b/utils/cw-prover/query.proof @@ -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"}]}} \ No newline at end of file diff --git a/utils/cw-prover/src/main.rs b/utils/cw-prover/src/main.rs index 2aaef24..8c0b654 100644 --- a/utils/cw-prover/src/main.rs +++ b/utils/cw-prover/src/main.rs @@ -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> { .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> { 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> { +fn write_proof_to_file(proof_file: PathBuf, proof: RawCwProof) -> Result<(), Box> { 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() {