-
Notifications
You must be signed in to change notification settings - Fork 82
/
mod.rs
157 lines (126 loc) · 5.29 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
pub mod mock;
pub mod tendermint;
use core::fmt::Debug;
use core::ops::Add;
use core::time::Duration;
use ibc::core::client::context::consensus_state::ConsensusState;
use ibc::core::client::types::Height;
use ibc::core::primitives::prelude::*;
use ibc::core::primitives::Timestamp;
use ibc::primitives::proto::Any;
pub use self::mock::MockHost;
pub use self::tendermint::TendermintHost;
use crate::testapp::ibc::clients::{AnyClientState, AnyConsensusState};
pub type HostClientState<H> = <H as TestHost>::ClientState;
pub type HostBlock<H> = <H as TestHost>::Block;
pub type HostBlockParams<H> = <H as TestHost>::BlockParams;
pub type HostLightClientParams<H> = <H as TestHost>::LightClientParams;
pub type HostHeader<H> = <HostBlock<H> as TestBlock>::Header;
pub type HostConsensusState<H> = <HostHeader<H> as TestHeader>::ConsensusState;
/// TestHost is a trait that defines the interface for a host blockchain.
pub trait TestHost: Default + Debug + Sized {
/// The type of block produced by the host.
type Block: TestBlock;
/// The type of client state produced by the host.
type ClientState: Into<AnyClientState> + Debug;
/// The type of block parameter to produce a block.
type BlockParams: Debug + Default;
/// The type of light client parameters to produce a light client state.
type LightClientParams: Debug + Default;
/// The history of blocks produced by the host chain.
fn history(&self) -> &Vec<Self::Block>;
/// Returns true if the host chain has no blocks.
fn is_empty(&self) -> bool {
self.history().is_empty()
}
/// The latest height of the host chain.
fn latest_height(&self) -> Height {
self.latest_block().height()
}
/// The latest block of the host chain.
fn latest_block(&self) -> Self::Block {
self.history().last().cloned().expect("no error")
}
/// Get the block at the given height.
fn get_block(&self, target_height: &Height) -> Option<Self::Block> {
self.history()
.get(target_height.revision_height() as usize - 1)
.cloned() // indexed from 1
}
/// Add a block to the host chain.
fn push_block(&mut self, block: Self::Block);
/// Commit a block with commitment root to the blockchain, by extending the history of blocks.
fn commit_block(
&mut self,
commitment_root: Vec<u8>,
block_time: Duration,
params: &Self::BlockParams,
) {
let latest_block = self.latest_block();
let height = TestBlock::height(&latest_block)
.increment()
.revision_height();
let timestamp = TestBlock::timestamp(&latest_block)
.add(block_time)
.expect("Never fails");
let new_block = self.generate_block(commitment_root, height, timestamp, params);
// History is not full yet.
self.push_block(new_block);
}
/// Generate a block at the given height and timestamp, using the provided parameters.
fn generate_block(
&self,
commitment_root: Vec<u8>,
height: u64,
timestamp: Timestamp,
params: &Self::BlockParams,
) -> Self::Block;
/// Generate a client state using the block at the given height and the provided parameters.
fn generate_client_state(
&self,
latest_height: &Height,
params: &Self::LightClientParams,
) -> Self::ClientState;
fn validate(&self) -> Result<(), String> {
// Check that headers in the history are in sequential order.
let latest_height = self.latest_height();
let mut current_height = Height::min(latest_height.revision_number());
while current_height <= latest_height {
if current_height != self.get_block(¤t_height).expect("no error").height() {
return Err("block height does not match".to_owned());
}
current_height = current_height.increment();
}
Ok(())
}
}
/// TestBlock is a trait that defines the interface for a block produced by a host blockchain.
pub trait TestBlock: Clone + Debug {
/// The type of header can be extracted from the block.
type Header: TestHeader;
/// The height of the block.
fn height(&self) -> Height;
/// The timestamp of the block.
fn timestamp(&self) -> Timestamp;
/// Extract the IBC header using the target and trusted blocks.
fn into_header_with_trusted(self, trusted_block: &Self) -> Self::Header;
/// Extract the IBC header only using the target block (sets the trusted
/// block to itself).
fn into_header(self) -> Self::Header {
self.clone().into_header_with_trusted(&self)
}
}
/// TestHeader is a trait that defines the interface for a header
/// submitted by relayer from the host blockchain.
pub trait TestHeader: Clone + Debug + Into<Any> {
/// The type of consensus state can be extracted from the header.
type ConsensusState: ConsensusState + Into<AnyConsensusState> + From<Self> + Clone + Debug;
/// The height of the block, as recorded in the header.
fn height(&self) -> Height;
/// The timestamp of the block, as recorded in the header.
fn timestamp(&self) -> Timestamp;
/// Extract the consensus state from the header.
fn into_consensus_state(self) -> Self::ConsensusState {
Self::ConsensusState::from(self)
}
}