Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement proof verification functions for Tendermint client #1583

Merged
merged 30 commits into from
Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
468b4fd
proof verification functions
yito88 Nov 22, 2021
6d54a5a
fix counterparty in ConnectionOpenAck
yito88 Nov 22, 2021
5272eae
verify delay
yito88 Dec 7, 2021
df667bb
Merge branch 'master' into yuji/tm_proof_verification
yito88 Dec 7, 2021
4735aa7
verify height
yito88 Dec 7, 2021
aa2336b
Revert "verify height"
hu55a1n1 Dec 9, 2021
33e493c
Impl verify_height()
hu55a1n1 Dec 9, 2021
be733a3
Revert changes to ics23 types
hu55a1n1 Dec 10, 2021
50aa14a
Update mock impl to use new ClientDef API with height
hu55a1n1 Dec 10, 2021
3ec08f8
Clippy happy
hu55a1n1 Dec 10, 2021
16189f2
Modify ClientDef API
hu55a1n1 Dec 11, 2021
a5483ea
Implement max_expected_time_per_block()
hu55a1n1 Dec 12, 2021
41b80dd
Fix mock build
hu55a1n1 Dec 12, 2021
34c029e
Refactor verify_delay_passed()
hu55a1n1 Dec 13, 2021
3075c61
Move get_block_delay() into ChannelReader trait as provided method
hu55a1n1 Dec 13, 2021
424088d
Remove usages of std::
hu55a1n1 Dec 13, 2021
4933269
Fix clippy errors
hu55a1n1 Dec 13, 2021
2cf3d2b
Merge branch 'master' into yuji/tm_proof_verification
hu55a1n1 Dec 13, 2021
f9b16e6
Add keeper methods for processed time and height
hu55a1n1 Dec 13, 2021
db66a34
Set processed time using host_timestamp()
hu55a1n1 Dec 13, 2021
11c641d
Add new ICS02 error variant InvalidCommitmentProof
hu55a1n1 Dec 17, 2021
5c1ee1d
Augment packet delay errors
hu55a1n1 Dec 17, 2021
ec08b33
Revert to old naming of errors for client upgrade proofs
hu55a1n1 Dec 17, 2021
8dcb33d
Rename processed_{time,height}()
hu55a1n1 Dec 17, 2021
6b010bf
Apply suggestions from code review
hu55a1n1 Dec 17, 2021
43a8468
Fix conflicts
hu55a1n1 Dec 17, 2021
7381e02
Record height in processed height/time errors
hu55a1n1 Dec 17, 2021
71403c2
Merge branch 'master' into yuji/tm_proof_verification
hu55a1n1 Dec 21, 2021
bb66a5f
Fix clippy errors
hu55a1n1 Dec 21, 2021
630a84b
Add changelog entry
hu55a1n1 Dec 21, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ impl From<MsgTransfer> for RawMsgTransfer {

#[cfg(test)]
pub mod test_util {
use std::ops::Add;
use std::time::Duration;
use core::ops::Add;
use core::time::Duration;

use crate::{
core::ics24_host::identifier::{ChannelId, PortId},
Expand Down
297 changes: 232 additions & 65 deletions modules/src/clients/ics07_tendermint/client_def.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::convert::TryInto;
use core::convert::TryInto;

use ibc_proto::ibc::core::commitment::v1::MerkleProof;
use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof;
use prost::Message;
use tendermint::Time;
use tendermint_light_client::components::verifier::{ProdVerifier, Verdict, Verifier};
use tendermint_light_client::types::{TrustedBlockState, UntrustedBlockState};
use tendermint_proto::Protobuf;

use crate::clients::ics07_tendermint::client_state::ClientState;
use crate::clients::ics07_tendermint::consensus_state::ConsensusState;
Expand All @@ -17,13 +19,16 @@ use crate::core::ics02_client::context::ClientReader;
use crate::core::ics02_client::error::Error as Ics02Error;
use crate::core::ics03_connection::connection::ConnectionEnd;
use crate::core::ics04_channel::channel::ChannelEnd;
use crate::core::ics04_channel::context::ChannelReader;
use crate::core::ics04_channel::packet::Sequence;

use crate::core::ics23_commitment::commitment::{
CommitmentPrefix, CommitmentProofBytes, CommitmentRoot,
};
use crate::core::ics23_commitment::merkle::{apply_prefix, MerkleProof};
use crate::core::ics24_host::identifier::ConnectionId;
use crate::core::ics24_host::identifier::{ChannelId, ClientId, PortId};
use crate::core::ics24_host::Path;
use crate::prelude::*;
use crate::Height;

Expand Down Expand Up @@ -185,116 +190,278 @@ impl ClientDef for TendermintClient {

fn verify_client_consensus_state(
&self,
_client_state: &Self::ClientState,
_height: Height,
_prefix: &CommitmentPrefix,
_proof: &CommitmentProofBytes,
_client_id: &ClientId,
_consensus_height: Height,
_expected_consensus_state: &AnyConsensusState,
client_state: &Self::ClientState,
height: Height,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
client_id: &ClientId,
consensus_height: Height,
expected_consensus_state: &AnyConsensusState,
) -> Result<(), Ics02Error> {
todo!()
client_state.verify_height(height)?;

let path = Path::ClientConsensusState {
hu55a1n1 marked this conversation as resolved.
Show resolved Hide resolved
client_id: client_id.clone(),
epoch: consensus_height.revision_number,
height: consensus_height.revision_height,
}
.to_string();
let value = expected_consensus_state.encode_vec().unwrap();
hu55a1n1 marked this conversation as resolved.
Show resolved Hide resolved
verify_membership(client_state, prefix, proof, root, path, value)
}

fn verify_connection_state(
&self,
_client_state: &Self::ClientState,
_height: Height,
_prefix: &CommitmentPrefix,
_proof: &CommitmentProofBytes,
_connection_id: Option<&ConnectionId>,
_expected_connection_end: &ConnectionEnd,
client_state: &Self::ClientState,
height: Height,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
connection_id: &ConnectionId,
expected_connection_end: &ConnectionEnd,
) -> Result<(), Ics02Error> {
todo!()
client_state.verify_height(height)?;

let path = Path::Connections(connection_id.clone()).to_string();
let value = expected_connection_end.encode_vec().unwrap();
verify_membership(client_state, prefix, proof, root, path, value)
}

fn verify_channel_state(
&self,
_client_state: &Self::ClientState,
_height: Height,
_prefix: &CommitmentPrefix,
_proof: &CommitmentProofBytes,
_port_id: &PortId,
_channel_id: &ChannelId,
_expected_channel_end: &ChannelEnd,
client_state: &Self::ClientState,
height: Height,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
port_id: &PortId,
channel_id: &ChannelId,
expected_channel_end: &ChannelEnd,
) -> Result<(), Ics02Error> {
todo!()
client_state.verify_height(height)?;

let path = Path::ChannelEnds(port_id.clone(), channel_id.clone()).to_string();
let value = expected_channel_end.encode_vec().unwrap();
verify_membership(client_state, prefix, proof, root, path, value)
}

fn verify_client_full_state(
&self,
_client_state: &Self::ClientState,
_height: Height,
_root: &CommitmentRoot,
_prefix: &CommitmentPrefix,
_client_id: &ClientId,
_proof: &CommitmentProofBytes,
_expected_client_state: &AnyClientState,
client_state: &Self::ClientState,
height: Height,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
client_id: &ClientId,
expected_client_state: &AnyClientState,
) -> Result<(), Ics02Error> {
unimplemented!()
client_state.verify_height(height)?;

let path = Path::ClientState(client_id.clone()).to_string();
let value = expected_client_state.encode_vec().unwrap();
verify_membership(client_state, prefix, proof, root, path, value)
}

fn verify_packet_data(
&self,
_client_state: &Self::ClientState,
_height: Height,
_proof: &CommitmentProofBytes,
_port_id: &PortId,
_channel_id: &ChannelId,
_seq: &Sequence,
_data: String,
ctx: &dyn ChannelReader,
client_state: &Self::ClientState,
height: Height,
connection_end: &ConnectionEnd,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
port_id: &PortId,
channel_id: &ChannelId,
sequence: Sequence,
commitment: String,
) -> Result<(), Ics02Error> {
todo!()
client_state.verify_height(height)?;
verify_delay_passed(ctx, height, connection_end)?;

let commitment_path = Path::Commitments {
port_id: port_id.clone(),
channel_id: channel_id.clone(),
sequence,
};
verify_membership(
client_state,
connection_end.counterparty().prefix(),
proof,
root,
commitment_path.to_string(),
commitment.encode_to_vec(),
)
}

fn verify_packet_acknowledgement(
&self,
_client_state: &Self::ClientState,
_height: Height,
_proof: &CommitmentProofBytes,
_port_id: &PortId,
_channel_id: &ChannelId,
_seq: &Sequence,
_data: Vec<u8>,
ctx: &dyn ChannelReader,
client_state: &Self::ClientState,
height: Height,
connection_end: &ConnectionEnd,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
port_id: &PortId,
channel_id: &ChannelId,
sequence: Sequence,
ack: Vec<u8>,
) -> Result<(), Ics02Error> {
todo!()
client_state.verify_height(height)?;
verify_delay_passed(ctx, height, connection_end)?;

let ack_path = Path::Acks {
port_id: port_id.clone(),
channel_id: channel_id.clone(),
sequence,
};
verify_membership(
client_state,
connection_end.counterparty().prefix(),
proof,
root,
ack_path.to_string(),
ack,
)
}

fn verify_next_sequence_recv(
&self,
_client_state: &Self::ClientState,
_height: Height,
_proof: &CommitmentProofBytes,
_port_id: &PortId,
_channel_id: &ChannelId,
_seq: &Sequence,
ctx: &dyn ChannelReader,
client_state: &Self::ClientState,
height: Height,
connection_end: &ConnectionEnd,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
port_id: &PortId,
channel_id: &ChannelId,
sequence: Sequence,
) -> Result<(), Ics02Error> {
todo!()
client_state.verify_height(height)?;
verify_delay_passed(ctx, height, connection_end)?;

let seq_path = Path::SeqRecvs(port_id.clone(), channel_id.clone());
verify_membership(
client_state,
connection_end.counterparty().prefix(),
proof,
root,
seq_path.to_string(),
u64::from(sequence).encode_to_vec(),
)
}

fn verify_packet_receipt_absence(
&self,
_client_state: &Self::ClientState,
_height: Height,
_proof: &CommitmentProofBytes,
_port_id: &PortId,
_channel_id: &ChannelId,
_seq: &Sequence,
ctx: &dyn ChannelReader,
client_state: &Self::ClientState,
height: Height,
connection_end: &ConnectionEnd,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
port_id: &PortId,
channel_id: &ChannelId,
sequence: Sequence,
) -> Result<(), Ics02Error> {
todo!()
client_state.verify_height(height)?;
verify_delay_passed(ctx, height, connection_end)?;

let receipt_path = Path::Receipts {
port_id: port_id.clone(),
channel_id: channel_id.clone(),
sequence,
};
verify_non_membership(
client_state,
connection_end.counterparty().prefix(),
proof,
root,
receipt_path.to_string(),
)
}

fn verify_upgrade_and_update_state(
&self,
_client_state: &Self::ClientState,
_consensus_state: &Self::ConsensusState,
_proof_upgrade_client: MerkleProof,
_proof_upgrade_consensus_state: MerkleProof,
_proof_upgrade_client: RawMerkleProof,
_proof_upgrade_consensus_state: RawMerkleProof,
) -> Result<(Self::ClientState, Self::ConsensusState), Ics02Error> {
todo!()
}
}

fn verify_membership(
client_state: &ClientState,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
path: String,
value: Vec<u8>,
) -> Result<(), Ics02Error> {
let merkle_path = apply_prefix(prefix, vec![path]).map_err(Error::ics23_error)?;
let merkle_proof: MerkleProof = RawMerkleProof::try_from(proof.clone())
.map_err(Ics02Error::invalid_consensus_state_proof)?
hu55a1n1 marked this conversation as resolved.
Show resolved Hide resolved
.into();

merkle_proof
.verify_membership(
&client_state.proof_specs,
root.clone().into(),
merkle_path,
value,
0,
)
.map_err(|e| Ics02Error::tendermint(Error::ics23_error(e)))
}

fn verify_non_membership(
client_state: &ClientState,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
path: String,
) -> Result<(), Ics02Error> {
let merkle_path = apply_prefix(prefix, vec![path]).map_err(Error::ics23_error)?;
let merkle_proof: MerkleProof = RawMerkleProof::try_from(proof.clone())
.map_err(Ics02Error::invalid_consensus_state_proof)?
hu55a1n1 marked this conversation as resolved.
Show resolved Hide resolved
.into();

merkle_proof
.verify_non_membership(&client_state.proof_specs, root.clone().into(), merkle_path)
.map_err(|e| Ics02Error::tendermint(Error::ics23_error(e)))
}

fn verify_delay_passed(
ctx: &dyn ChannelReader,
height: Height,
connection_end: &ConnectionEnd,
) -> Result<(), Ics02Error> {
let current_timestamp = ctx.host_timestamp();
let current_height = ctx.host_height();

let client_id = connection_end.client_id();
let processed_time = ctx
.processed_time(client_id, height)
.map_err(|_| Error::processed_time_not_found(client_id.clone()))?;
let processed_height = ctx
.processed_height(client_id, height)
.map_err(|_| Error::processed_height_not_found(client_id.clone()))?;

let delay_period_time = connection_end.delay_period();
let delay_period_height = ctx.block_delay(delay_period_time);

ClientState::verify_delay_passed(
current_timestamp,
current_height,
processed_time,
processed_height,
delay_period_time,
delay_period_height,
)
.map_err(|e| e.into())
}

fn downcast_consensus_state(cs: AnyConsensusState) -> Result<ConsensusState, Ics02Error> {
downcast!(
cs => AnyConsensusState::Tendermint
Expand Down
Loading