Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
1fef6b2
fix(gno): switch tx plugin datagram templates to realm-aware msg cons…
aronpark1007 Jul 6, 2026
d3a9327
fix(gno): handle typed return format in parse_gno_string_object
aronpark1007 Jul 6, 2026
9f109db
fix(gno): parse chunked packet_data and acknowledgement event attrs
aronpark1007 Jul 6, 2026
aa20456
fix(gno): switch tx plugin msg constructors to types package and wire…
aronpark1007 Jul 6, 2026
e929522
fix(gno): parse chunked maker_msg event attrs
aronpark1007 Jul 8, 2026
c4141ef
fix(voyager/state-gno): find PacketSend event by type in query_packet…
aronpark1007 Jul 8, 2026
b9f9286
fix(gno): parse and construct batch_send and packet_ack events
aronpark1007 Jul 14, 2026
86d2ba9
chore(gno): remove unnecessary comments
aronpark1007 Jul 20, 2026
bddd6cc
refactor(gno): drop unused fields from IbcEvent parsing
aronpark1007 Jul 20, 2026
3e5e151
fix(gno): implement end-to-end batch_send support
aronpark1007 Jul 20, 2026
7f0e705
fix(gno): implement packet ack lookup and fix state query correctness
aronpark1007 Jul 20, 2026
49b29c9
fix(gno): verify ics23 proofs against gno.land's new bptree store
aronpark1007 Jul 21, 2026
69ead9e
fix(voyager): coerce numeric client_id before has() in transaction-ba…
aronpark1007 Jul 22, 2026
4362033
fix(gno): stop retrying permanently-failed tx submissions
aronpark1007 Jul 23, 2026
fd1bd97
fix(gno): fix ci
aronpark1007 Jul 24, 2026
14bdd36
fix(voyager): commit non-membership proofs on L1 for proof-lens packe…
aronpark1007 Jul 25, 2026
05688e2
fix(gno): use first present precommit for Commit height/round instead…
aronpark1007 Jul 25, 2026
0d846e5
test(voyager): cover numeric client_id in transaction-batch-proof-len…
aronpark1007 Jul 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions cosmwasm/lightclient/gno/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,9 +516,8 @@ mod tests {
testing::{mock_dependencies, mock_env},
};
use gno_light_client_types::Fraction;
use hex_literal::hex;
use ibc_union_spec::ClientId;
use ics23::ibc_api::SDK_SPECS;
use ics23::ibc_api::{self as ics23_api, GNO_SPECS, SDK_SPECS};
use unionlabs::{
encoding::{EncodeAs, EthAbi},
google::protobuf,
Expand Down Expand Up @@ -624,24 +623,33 @@ mod tests {
assert_status!(Frozen);
}

/// Real proof captured from the `topaz-1` testnet
/// (`https://rpc.topaz.testnets.gno.land/`) after its main store
/// migrated from IAVL to bptree (`gnolang/gno` PR #5937). [`GNO_SPECS`]
/// must verify it; the old [`SDK_SPECS`] (IAVL) must reject it.
#[test]
fn verify_proof() {
// TODO: This is from a dev deployment, update this test with values from an actual testnet or mainnet deployment once there's one live
fn verify_proof_bptree_topaz() {
use unionlabs::cosmos::ics23::commitment_proof::CommitmentProof;

let proof = r#"{"proofs":[{"@type":"exist","@value":{"key":"0x2f70762f766d3a676e6f2e6c616e642f722f636f72652f6962632f76312f636f72653a61366565663765333561626537303236373239363431313437663739313535373363376539376234376566613534366635663665333233303236336263623439","value":"0xfef470406bf3ca4daf4865ed047f1a4b9a49307e5724c21e508a8782f415889d","leaf":{"hash":"sha256","prehash_key":"no_hash","prehash_value":"sha256","length":"var_proto","prefix":"0x000206"},"path":[{"hash":"sha256","prefix":"0x020406206d81723c787f48cdb0fe48017bfeb8c7777c18d2ce768ff3bef8be989d732af920","suffix":"0x0"},{"hash":"sha256","prefix":"0x04060620424eb03f08942ba873f0ad61a3e532dd49f9ebe341c15820b91b2d6f59adb16520","suffix":"0x0"},{"hash":"sha256","prefix":"0x060a06207a6060551a75bb698b17d3eb5b11ef4b6c583d4dd65f074109c5d8ff352d874820","suffix":"0x0"},{"hash":"sha256","prefix":"0x08120620","suffix":"0x20aafb8c883b219159457c342081a41717e117622362092df6aecd69b2e823049b"},{"hash":"sha256","prefix":"0x0a2206207e05a6db10f558103a216d64fb77b010c74e9134995a502d303d1205cbe5ec2220","suffix":"0x0"},{"hash":"sha256","prefix":"0x0c420620f318b74164e6e7317df2eb259a7d3e6d0a81e9b7fc2b2b83d5407b37427a702e20","suffix":"0x0"},{"hash":"sha256","prefix":"0x0e86010620","suffix":"0x20508c3a794d8e22e86e7fa9ea4b1cf59fb581e726c4bec1a7bda9a238c830bb10"},{"hash":"sha256","prefix":"0x1086020620","suffix":"0x2028da987f98245d9cf15ae22917f42e5a2100d86cd7de7243a6a3a02519f2788a"},{"hash":"sha256","prefix":"0x1286040620","suffix":"0x2072afbfb3032a69b75dd4630d95f5916f34d5dd8ed017121f6f96a1e81d680011"},{"hash":"sha256","prefix":"0x14ca090620","suffix":"0x2042fe18a32b874de8f5c4cb122d9539e6b81b1453d991bf6013053975fe0bb975"}]}},{"@type":"exist","@value":{"key":"0x6d61696e","value":"0xf7e8b054c2e090fe8fb5ea96e815e62eb7b6ab710d211b9c9c1769f56d83a888","leaf":{"hash":"sha256","prehash_key":"no_hash","prehash_value":"sha256","length":"var_proto","prefix":"0x00"},"path":[{"hash":"sha256","prefix":"0x01ccb581a002a493db462c72bc97aac085192a8ffb6a45fa5ee3cf22ee89eb1574","suffix":"0x0"}]}}]}"#;
let proof: MerkleProof =
serde_json::from_str(include_str!("../testdata/topaz_bptree_proof.json")).unwrap();
let CommitmentProof::Exist(existence_proof) = &proof.proofs[0] else {
panic!("expected the first proof to be an existence proof");
};
let value = existence_proof.value.to_vec();
let root = MerkleRoot {
hash: "NACWxFYEYbJdstiUpo11iVtSm2ej46I+Jq1AvBVAHhM="
.parse()
.unwrap(),
};
let path = [b"main".to_vec(), b"pkg:gno.land/r/aib/ibc/core".to_vec()];

verify_membership(
"gno.land/r/core/ibc/v1/core",
&SDK_SPECS,
&MerkleRoot {
hash: "UwihADwTPJO2lMK0aRr41qXcRJO6itbLR/zAKEN4bBo="
.parse()
.unwrap(),
},
hex!("a6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49").to_vec(),
serde_json::from_str(proof).unwrap(),
hex!("fef470406bf3ca4daf4865ed047f1a4b9a49307e5724c21e508a8782f415889d").into(),
)
.unwrap();
ics23_api::verify_membership(&proof, &GNO_SPECS, &root, &path, value.clone())
.expect("real bptree proof must verify under GNO_SPECS");

assert!(
ics23_api::verify_membership(&proof, &SDK_SPECS, &root, &path, value).is_err(),
"a bptree proof must NOT verify under the legacy IAVL-only SDK_SPECS"
);
}
}
1 change: 1 addition & 0 deletions cosmwasm/lightclient/gno/testdata/topaz_bptree_proof.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/ics23/src/existence_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub fn check_against_spec(
}

if let Some(max_depth) = spec.max_depth
&& existence_proof.path.len() < max_depth.inner()
&& existence_proof.path.len() > max_depth.inner()
{
return Err(SpecMismatchError::InnerDepthTooLong {
path_len: existence_proof.path.len(),
Expand Down
3 changes: 2 additions & 1 deletion lib/ics23/src/ibc_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ use unionlabs::{
primitives::Bytes,
};

pub use crate::proof_specs::{IAVL_PROOF_SPEC, TENDERMINT_PROOF_SPEC};
pub use crate::proof_specs::{BPTREE_PROOF_SPEC, IAVL_PROOF_SPEC, TENDERMINT_PROOF_SPEC};
use crate::{
existence_proof,
verify::{self},
};

pub const SDK_SPECS: [ProofSpec; 2] = [IAVL_PROOF_SPEC, TENDERMINT_PROOF_SPEC];
pub const GNO_SPECS: [ProofSpec; 2] = [BPTREE_PROOF_SPEC, TENDERMINT_PROOF_SPEC];

#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum VerifyMembershipError {
Expand Down
37 changes: 37 additions & 0 deletions lib/ics23/src/proof_specs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::borrow::Cow;

use unionlabs::{
bounded::BoundedUsize,
cosmos::ics23::{
hash_op::HashOp,
inner_spec::{InnerSpec, PositiveI32AsUsize},
Expand Down Expand Up @@ -68,6 +69,42 @@ pub const TENDERMINT_PROOF_SPEC: ProofSpec = ProofSpec {
prehash_key_before_comparison: false,
};

pub const BPTREE_PROOF_SPEC: ProofSpec = ProofSpec {
leaf_spec: LeafOp {
hash: HashOp::Sha256,
prehash_key: HashOp::NoHash,
prehash_value: HashOp::Sha256,
length: LengthOp::VarProto,
prefix: Bytes::new_static(&[0]),
},
inner_spec: InnerSpec {
child_order: Cow::Borrowed(
const {
&[
result_unwrap!(PositiveI32AsUsize::new_const(0)),
result_unwrap!(PositiveI32AsUsize::new_const(1)),
]
},
),
child_size: result_unwrap!(PositiveI32AsUsize::new_const(32)),
min_prefix_length: result_unwrap!(PositiveI32AsUsize::new_const(1)),
max_prefix_length: result_unwrap!(PositiveI32AsUsize::new_const(1)),
empty_child: Bytes::new_static(&[
0xdb, 0xc1, 0xb4, 0xc9, 0x00, 0xff, 0xe4, 0x8d, 0x57, 0x5b, 0x5d, 0xa5, 0xc6, 0x38,
0x04, 0x01, 0x25, 0xf6, 0x5d, 0xb0, 0xfe, 0x3e, 0x24, 0x49, 0x4b, 0x76, 0xea, 0x98,
0x64, 0x57, 0xd9, 0x86,
]),
hash: HashOp::Sha256,
},
max_depth: Some(result_unwrap!(
BoundedUsize::<1, { i32::MAX as usize }>::new_const(60)
Comment thread
aronpark1007 marked this conversation as resolved.
)),
min_depth: Some(result_unwrap!(
BoundedUsize::<1, { i32::MAX as usize }>::new_const(5)
)),
prehash_key_before_comparison: false,
};

#[must_use]
pub fn compatible(lhs: &ProofSpec, rhs: &ProofSpec) -> bool {
lhs.leaf_spec.hash == rhs.leaf_spec.hash
Expand Down
4 changes: 2 additions & 2 deletions voyager/modules/client-bootstrap/gno/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{fmt::Debug, num::NonZeroU64, time::Duration};

use gno_light_client_types::{ClientState, ConsensusState, Fraction};
use ics23::ibc_api::SDK_SPECS;
use ics23::ibc_api::GNO_SPECS;
use jsonrpsee::{Extensions, core::async_trait};
use serde::{Deserialize, Serialize};
use serde_json::Value;
Expand Down Expand Up @@ -133,7 +133,7 @@ impl ClientBootstrapModuleServer for Module {
0,
height.inner().try_into().expect("is within bounds; qed;"),
),
proof_specs: SDK_SPECS.into(),
proof_specs: GNO_SPECS.into(),
upgrade_path: vec!["upgrade".into(), "upgradedIBCState".into()],
realm: self.ibc_core_realm.clone(),
})
Expand Down
Loading