Skip to content

Commit

Permalink
First stab at ICS3 connection handshake protocol (message processing …
Browse files Browse the repository at this point in the history
…logic) (#188)

* First processing logic for ICS 03 (#160).

* Fix for temporary pick_version().

* First attempt at the process_try_msg function.

* Sketch for proof verification in process_try_msg. Removed Connection* traits.

* Added logic for the Try message.

* Logic for processing ICS3 confirm msg. Cosmetic improvements

* Adapting code to new architecture based on contexts.

* Refactored, new terminology, added events.

* WIP: Adding tests

* Higher-level interface for the context.

* One chunk of proof verification is done

* Implementation of ics3 verify_proofs done.

* Addressing Romain's concerns.

* Tests for conn open init message processing.

* Fixes for integration tests: PartialEq for identifiers.

* More changes cf adr003 and code reorg

* Move info to new  context and context_mock modules

* migrate conn-open-init to new infra

* Refine client and connection mock context

* Fix conn_open_try handler

* Create new mock_client

* remove mocks.rs

* Add global chain context

* Uncomment tests

* Cleanup

* Started to fill client verification functions.

Started TryFromRaw for connection messages.

Some work on commitment prefix, path, root.

* Add try_from for connection messages and remove new()

* Add test for try dispatch

* Some changes to mock context setup

* Some cleanup

* Review comments

* Mark mocks as `#[cfg(test)]

* Fix clippy warnings

* Remove use of clone in a Debug impl

Co-authored-by: Anca Zamfir <zamfiranca@gmail.com>
Co-authored-by: Romain Ruetschi <romain@informal.systems>
  • Loading branch information
3 people committed Sep 3, 2020
1 parent 66274aa commit cf6c815
Show file tree
Hide file tree
Showing 47 changed files with 2,169 additions and 749 deletions.
1 change: 1 addition & 0 deletions modules/src/address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub struct AccAddress(Vec<u8>;
36 changes: 36 additions & 0 deletions modules/src/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use serde_derive::{Deserialize, Serialize};
use tendermint::block::Height;

#[cfg(test)]
use crate::ics02_client::client_def::AnyConsensusState;
#[cfg(test)]
use crate::mock_client::header::MockHeader;
#[cfg(test)]
use crate::mock_client::state::MockConsensusState;

#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum SelfHeader {
// Tendermint(tendermint::header::Header),
#[cfg(test)]
Mock(MockHeader),
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct HistoricalInfo {
pub header: SelfHeader,
}

#[cfg(test)]
impl From<MockHeader> for AnyConsensusState {
fn from(h: MockHeader) -> Self {
AnyConsensusState::Mock(MockConsensusState(h))
}
}

pub trait ChainReader {
fn self_historical_info(&self, height: Height) -> Option<&HistoricalInfo>;
}

pub trait ChainKeeper {
fn store_historical_info(&mut self, height: Height, info: HistoricalInfo);
}
142 changes: 142 additions & 0 deletions modules/src/context_mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
use crate::context::{ChainKeeper, ChainReader, HistoricalInfo, SelfHeader};
use crate::mock_client::header::MockHeader;
use serde_derive::{Deserialize, Serialize};
use std::error::Error;
use tendermint::block::Height;

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct MockChainContext {
pub max_size: usize,
pub latest: Height,
pub history: Vec<HistoricalInfo>,
}

impl MockChainContext {
pub fn new(max_size: usize, n: Height) -> Self {
Self {
max_size,
latest: n,
history: (0..n.value())
.map(|i| HistoricalInfo {
header: SelfHeader::Mock(MockHeader(Height(i).increment())),
})
.collect(),
}
}

pub fn max_size(&self) -> usize {
self.max_size
}

/// Used for testing
pub fn populate(&mut self, hs: Vec<u64>) {
for h in hs {
self.store_historical_info(
Height(h),
HistoricalInfo {
header: SelfHeader::Mock(MockHeader(Height(h))),
},
);
}
}

/// Used for testing
pub fn validate(&self) -> Result<(), Box<dyn Error>> {
// check that the number of entries is not higher than max_size
if self.history.len() > self.max_size {
return Err("too many entries".to_string().into());
}

// check latest is properly updated with highest header height
let SelfHeader::Mock(lh) = self.history[self.history.len() - 1].header;
if lh.height() != self.latest {
return Err("latest height is not updated".to_string().into());
}

// check that all headers are in sequential order
for i in 1..self.history.len() {
let SelfHeader::Mock(ph) = self.history[i - 1].header;
let SelfHeader::Mock(h) = self.history[i].header;
if ph.height().increment() != h.height() {
return Err("headers in history not sequential".to_string().into());
}
}
Ok(())
}
}

impl ChainReader for MockChainContext {
fn self_historical_info(&self, height: Height) -> Option<&HistoricalInfo> {
let l = height.value() as usize;
let h = self.latest.value() as usize;

if l <= h - self.max_size {
// header with height not in the history
None
} else {
Some(&self.history[h - l])
}
}
}

impl ChainKeeper for MockChainContext {
fn store_historical_info(&mut self, height: Height, info: HistoricalInfo) {
if height != self.latest.increment() {
return;
}
let mut history = self.history.clone();
if history.len() >= self.max_size {
history.rotate_left(1);
history[self.max_size - 1] = info;
} else {
history.push(info);
}
//history.insert(height, info);
self.history = history;
self.latest = height;
}
}

#[cfg(test)]
mod tests {
use crate::context_mock::MockChainContext;
use tendermint::block::Height;

#[test]
fn test_store_historical_info() {
pub struct Test {
name: String,
ctx: MockChainContext,
args: Vec<u64>,
}

impl Test {
pub fn apply(&mut self, hs: Vec<u64>) {
self.ctx.populate(hs);
}
}

let tests: Vec<Test> = vec![
Test {
name: "Add no prune".to_string(),
ctx: MockChainContext::new(3, Height(0)),
args: [1].to_vec(),
},
Test {
name: "Add with prune".to_string(),
ctx: MockChainContext::new(3, Height(2)),
args: [3, 4].to_vec(),
},
Test {
name: "Attempt to add non sequential headers".to_string(),
ctx: MockChainContext::new(3, Height(2)),
args: [3, 5, 7].to_vec(),
},
];

for mut test in tests {
test.apply(test.args.clone());
assert!(test.ctx.validate().is_ok());
}
}
}
1 change: 1 addition & 0 deletions modules/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use tendermint::block;

use tendermint_rpc::event_listener::{ResultEvent, TMEventData};

/// Events created by the IBC component of a chain, destined for a relayer.
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum IBCEvent {
NewBlock(NewBlock),
Expand Down
4 changes: 2 additions & 2 deletions modules/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ pub enum EventType {

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Event {
tpe: EventType,
attributes: Vec<Attribute>,
pub tpe: EventType,
pub attributes: Vec<Attribute>,
}

impl Event {
Expand Down
Loading

0 comments on commit cf6c815

Please sign in to comment.