-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathcosmos_to_eth.rs
153 lines (134 loc) · 4.66 KB
/
cosmos_to_eth.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
//! This module defines [`TxBuilder`] which is responsible for building transactions to be sent to
//! the Ethereum chain from events received from the Cosmos SDK chain.
use std::str::FromStr;
use alloy::{primitives::Address, providers::Provider, sol_types::SolCall};
use anyhow::Result;
use ibc_core_host_types::identifiers::ChainId;
use ibc_eureka_solidity_types::{
ics26::{
router::{multicallCall, routerCalls, routerInstance},
IICS02ClientMsgs::Height,
},
msgs::IICS07TendermintMsgs::ClientState,
sp1_ics07::sp1_ics07_tendermint,
};
use ibc_eureka_utils::rpc::TendermintRpcExt;
use sp1_ics07_tendermint_prover::prover::Sp1Prover;
use tendermint_rpc::HttpClient;
use sp1_prover::components::SP1ProverComponents;
use crate::{
chain::{CosmosSdk, EthEureka},
events::EurekaEventWithHeight,
utils::eth_eureka::{self, inject_sp1_proof},
};
use super::r#trait::TxBuilderService;
/// The `TxBuilder` produces txs to [`EthEureka`] based on events from [`CosmosSdk`].
#[allow(dead_code)]
pub struct TxBuilder<P, C>
where
P: Provider + Clone,
C: SP1ProverComponents,
{
/// The IBC Eureka router instance.
pub ics26_router: routerInstance<(), P>,
/// The HTTP client for the Cosmos SDK.
pub tm_client: HttpClient,
/// SP1 prover for generating proofs.
pub sp1_prover: Sp1Prover<C>,
}
impl<P, C> TxBuilder<P, C>
where
P: Provider + Clone,
C: SP1ProverComponents,
{
/// Create a new [`TxBuilder`] instance.
pub fn new(
ics26_address: Address,
provider: P,
tm_client: HttpClient,
sp1_prover: impl Into<Sp1Prover<C>>,
) -> Self {
Self {
ics26_router: routerInstance::new(ics26_address, provider),
tm_client,
sp1_prover: sp1_prover.into(),
}
}
/// Get the client state for a given client ID.
/// # Errors
/// Returns an error if the client state cannot be retrieved.
pub async fn client_state(&self, client_id: String) -> Result<ClientState> {
let ics07_address = self.ics26_router.getClient(client_id).call().await?._0;
Ok(
sp1_ics07_tendermint::new(ics07_address, self.ics26_router.provider().clone())
.clientState()
.call()
.await?
.into(),
)
}
}
#[async_trait::async_trait]
impl<P, C> TxBuilderService<EthEureka, CosmosSdk> for TxBuilder<P, C>
where
P: Provider + Clone,
C: SP1ProverComponents,
{
#[tracing::instrument(skip_all)]
async fn relay_events(
&self,
src_events: Vec<EurekaEventWithHeight>,
dest_events: Vec<EurekaEventWithHeight>,
target_client_id: String,
) -> Result<Vec<u8>> {
let now_since_unix = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)?;
let latest_light_block = self.tm_client.get_light_block(None).await?;
let revision_height = latest_light_block.height().value();
let chain_id =
ChainId::from_str(latest_light_block.signed_header.header.chain_id.as_str())?;
let latest_height = Height {
revisionNumber: chain_id.revision_number(),
revisionHeight: revision_height,
};
let timeout_msgs = eth_eureka::target_events_to_timeout_msgs(
dest_events,
&target_client_id,
&latest_height,
now_since_unix.as_secs(),
);
let recv_and_ack_msgs = eth_eureka::src_events_to_recv_and_ack_msgs(
src_events,
&target_client_id,
&latest_height,
now_since_unix.as_secs(),
);
let mut all_msgs = timeout_msgs
.into_iter()
.chain(recv_and_ack_msgs.into_iter())
.collect::<Vec<_>>();
if all_msgs.is_empty() {
anyhow::bail!("No messages to relay to Ethereum");
}
tracing::debug!("Messages to be relayed to Ethereum: {:?}", all_msgs);
let client_state = self.client_state(target_client_id).await?;
inject_sp1_proof(
&self.sp1_prover,
&mut all_msgs,
&self.tm_client,
latest_light_block,
client_state,
now_since_unix.as_nanos(),
)
.await?;
let calls = all_msgs.into_iter().map(|msg| match msg {
routerCalls::timeoutPacket(call) => call.abi_encode(),
routerCalls::recvPacket(call) => call.abi_encode(),
routerCalls::ackPacket(call) => call.abi_encode(),
_ => unreachable!(),
});
let multicall_tx = multicallCall {
data: calls.map(Into::into).collect(),
};
Ok(multicall_tx.abi_encode())
}
}