-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathcosmos_to_cosmos.rs
145 lines (129 loc) · 4.46 KB
/
cosmos_to_cosmos.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
//! This module defines [`TxBuilder`] which is responsible for building transactions to be sent to
//! the Cosmos SDK chain from events received from another Cosmos SDK chain.
use anyhow::Result;
use ibc_eureka_utils::{light_block::LightBlockExt, rpc::TendermintRpcExt};
use ibc_proto_eureka::{
cosmos::tx::v1beta1::TxBody,
google::protobuf::Any,
ibc::{
core::client::v1::{Height, MsgUpdateClient},
lightclients::tendermint::v1::ClientState,
},
};
use prost::Message;
use tendermint_rpc::HttpClient;
use crate::{
chain::CosmosSdk,
events::EurekaEventWithHeight,
utils::cosmos::{self},
};
use super::r#trait::TxBuilderService;
/// The `TxBuilder` produces txs to [`CosmosSdk`] based on events from [`CosmosSdk`].
#[allow(dead_code)]
pub struct TxBuilder {
/// The HTTP client for the source chain.
pub source_tm_client: HttpClient,
/// The HTTP client for the target chain.
pub target_tm_client: HttpClient,
/// The signer address for the Cosmos messages.
pub signer_address: String,
}
impl TxBuilder {
/// Creates a new `TxBuilder`.
#[must_use]
pub const fn new(
source_tm_client: HttpClient,
target_tm_client: HttpClient,
signer_address: String,
) -> Self {
Self {
source_tm_client,
target_tm_client,
signer_address,
}
}
}
#[async_trait::async_trait]
impl TxBuilderService<CosmosSdk, CosmosSdk> for TxBuilder {
#[tracing::instrument(skip_all)]
async fn relay_events(
&self,
src_events: Vec<EurekaEventWithHeight>,
target_events: Vec<EurekaEventWithHeight>,
target_client_id: String,
) -> Result<Vec<u8>> {
let client_state = ClientState::decode(
self.target_tm_client
.client_state(target_client_id.clone())
.await?
.value
.as_slice(),
)?;
let target_light_block = self.source_tm_client.get_light_block(None).await?;
let revision_height = target_light_block.height().value();
let revision_number = client_state
.latest_height
.ok_or_else(|| anyhow::anyhow!("No latest height found"))?
.revision_number;
let target_height = Height {
revision_number,
revision_height,
};
let now_since_unix = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)?;
let mut timeout_msgs = cosmos::target_events_to_timeout_msgs(
target_events,
&target_client_id,
&target_height,
&self.signer_address,
now_since_unix.as_secs(),
);
let (mut recv_msgs, mut ack_msgs) = cosmos::src_events_to_recv_and_ack_msgs(
src_events,
&target_client_id,
&target_height,
&self.signer_address,
now_since_unix.as_secs(),
);
cosmos::inject_tendermint_proofs(
&mut recv_msgs,
&mut ack_msgs,
&mut timeout_msgs,
&self.source_tm_client,
&target_height,
)
.await?;
let trusted_light_block = self
.source_tm_client
.get_light_block(Some(
client_state
.latest_height
.ok_or_else(|| anyhow::anyhow!("No latest height found"))?
.revision_height,
))
.await?;
let proposed_header = target_light_block.into_header(&trusted_light_block);
let update_msg = MsgUpdateClient {
client_id: target_client_id,
client_message: Some(Any::from_msg(&proposed_header)?),
signer: self.signer_address.clone(),
};
let all_msgs = std::iter::once(Any::from_msg(&update_msg))
.chain(timeout_msgs.into_iter().map(|m| Any::from_msg(&m)))
.chain(recv_msgs.into_iter().map(|m| Any::from_msg(&m)))
.chain(ack_msgs.into_iter().map(|m| Any::from_msg(&m)))
.collect::<Result<Vec<_>, _>>()?;
if all_msgs.len() == 1 {
// The update message is the only message.
anyhow::bail!("No messages to relay to Cosmos");
}
tracing::debug!(
"Messages to be relayed to Cosmos: {:?}",
all_msgs[1..].to_vec()
);
let tx_body = TxBody {
messages: all_msgs,
..Default::default()
};
Ok(tx_body.encode_to_vec())
}
}