Skip to content

Commit dc46d5d

Browse files
benlueloaeryz
authored andcommitted
feat(voyager): idk probably fixes it
1 parent 6a75bf8 commit dc46d5d

File tree

1 file changed

+132
-101
lines changed
  • voyager/plugins/transaction-batch/src

1 file changed

+132
-101
lines changed

voyager/plugins/transaction-batch/src/call.rs

Lines changed: 132 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::cmp::Ordering;
44
use enumorph::Enumorph;
55
use ibc_classic_spec::IbcClassic;
66
use ibc_union_spec::{IbcUnion, query::PacketsByBatchHash};
7+
use itertools::Itertools;
78
use macros::model;
89
use serde_json::json;
910
use tracing::{debug, info, instrument, warn};
@@ -18,7 +19,7 @@ use voyager_sdk::{
1819
primitives::{ChainId, QueryHeight},
1920
rpc::{RpcError, RpcResult},
2021
types::RawClientId,
21-
vm::{Op, data, now, promise},
22+
vm::{Op, conc, data, now, promise},
2223
};
2324

2425
use crate::{
@@ -55,6 +56,13 @@ where
5556
module: &Module,
5657
voyager_client: &VoyagerClient,
5758
) -> RpcResult<Op<VoyagerMessage>> {
59+
#[derive(Debug)]
60+
enum TargetHeights {
61+
None,
62+
Min(Height),
63+
Exact(Vec<Height>),
64+
}
65+
5866
let client_state_meta = voyager_client
5967
.client_state_meta::<V>(
6068
module.chain_id.clone(),
@@ -71,55 +79,57 @@ where
7179
.query_latest_height(client_state_meta.counterparty_chain_id.clone(), true)
7280
.await?;
7381

74-
let target_height = self
82+
let target_heights = self
7583
.batches
7684
.iter()
7785
.flatten()
7886
.map(|e| e.provable_height)
79-
.reduce(|acc, elem| match (elem, acc) {
80-
(EventProvableHeight::Min(elem), EventProvableHeight::Min(acc)) => {
81-
// the min target height of a batch of `Min` events is the highest min height
82-
// given the batch [10, 11, 12]
83-
// the min height that all events are provable at is 12
84-
EventProvableHeight::Min(elem.max(acc))
87+
.try_fold(TargetHeights::None, |acc, elem| match (elem, acc) {
88+
(EventProvableHeight::Min(elem), TargetHeights::None) => {
89+
Ok(TargetHeights::Min(elem))
8590
}
86-
(EventProvableHeight::Exactly(elem), EventProvableHeight::Exactly(acc)) => {
87-
assert_eq!(elem, acc, "multiple exact heights in the batch");
88-
EventProvableHeight::Exactly(elem)
91+
(EventProvableHeight::Exactly(elem), TargetHeights::None) => {
92+
Ok(TargetHeights::Exact(vec![elem]))
8993
}
90-
tuple => {
91-
panic!("cannot mix exact and min provable heights currently (found {tuple:?})");
94+
95+
(EventProvableHeight::Min(elem), TargetHeights::Min(acc)) => {
96+
Ok(TargetHeights::Min(elem.max(acc)))
9297
}
93-
})
94-
.expect("batch has at least one event; qed;");
95-
96-
// at this point we assume that a valid update exists - we only ever enqueue this message behind the relevant WaitForHeight on the counterparty chain. to prevent explosions, we do a sanity check here.
97-
{
98-
let (EventProvableHeight::Min(target_height)
99-
| EventProvableHeight::Exactly(target_height)) = target_height;
100-
101-
if latest_height < target_height {
102-
// we treat this as a missing state error, since this message assumes the state exists.
103-
return Err(RpcError::missing_state(format!(
104-
"the latest height of the counterparty chain ({counterparty_chain_id}) \
105-
is {latest_height} and the latest trusted height on the client tracking \
106-
it ({client_id}) on this chain ({self_chain_id}) is {trusted_height}. \
107-
in order to create an update for this client, we need to wait for the \
108-
counterparty chain to progress to the next consensus checkpoint greater \
109-
than the required target height {target_height}",
110-
counterparty_chain_id = client_state_meta.counterparty_chain_id,
111-
trusted_height = client_state_meta.counterparty_height,
112-
client_id = self.client_id,
113-
self_chain_id = module.chain_id,
114-
))
115-
.with_data(json!({
116-
"current_timestamp": now(),
117-
})));
118-
}
119-
}
12098

121-
match target_height {
122-
EventProvableHeight::Min(target_height) => {
99+
(EventProvableHeight::Exactly(elem), TargetHeights::Exact(acc)) => Ok(
100+
TargetHeights::Exact(acc.into_iter().chain([elem]).collect()),
101+
),
102+
103+
(elem, acc) => Err(RpcError::fatal_from_message(format!(
104+
"cannot mix exact and min update heights in a \
105+
single instance of this plugin: {elem:?}, {acc:?}"
106+
))),
107+
})?;
108+
109+
let mut ops = vec![];
110+
111+
// TODO: Check the same for exact heights?
112+
match target_heights {
113+
TargetHeights::Min(target_height) => {
114+
// at this point we assume that a valid update exists - we only ever enqueue this message behind the relevant WaitForHeight on the counterparty chain. to prevent explosions, we do a sanity check here.
115+
if latest_height < target_height {
116+
// we treat this as a missing state error, since this message assumes the state exists.
117+
return Err(RpcError::missing_state(format!(
118+
"the latest height of the counterparty chain ({counterparty_chain_id}) \
119+
is {latest_height} and the latest trusted height on the client tracking \
120+
it ({client_id}) on this chain ({self_chain_id}) is {trusted_height}. \
121+
in order to create an update for this client, we need to wait for the \
122+
counterparty chain to progress to the next consensus checkpoint greater \
123+
than the required target height {target_height}",
124+
counterparty_chain_id = client_state_meta.counterparty_chain_id,
125+
trusted_height = client_state_meta.counterparty_height,
126+
client_id = self.client_id,
127+
self_chain_id = module.chain_id,
128+
))
129+
.with_data(json!({
130+
"current_timestamp": now(),
131+
})));
132+
}
123133
if client_state_meta.counterparty_height >= target_height {
124134
info!(
125135
"client {client_id} has already been updated to a height \
@@ -128,28 +138,28 @@ where
128138
client_id = self.client_id,
129139
);
130140

131-
make_msgs(
141+
ops.push(make_msgs(
132142
module,
133143
self.client_id,
134144
self.batches,
135145
None,
136146
client_state_meta.clone(),
137147
client_state_meta.counterparty_height,
138-
)
148+
)?);
139149
} else {
140-
Ok(promise(
150+
ops.push(promise(
141151
[call(FetchUpdateHeaders {
142-
client_type: client_info.client_type,
152+
client_type: client_info.client_type.clone(),
143153
counterparty_chain_id: module.chain_id.clone(),
144-
chain_id: client_state_meta.counterparty_chain_id,
154+
chain_id: client_state_meta.counterparty_chain_id.clone(),
145155
client_id: RawClientId::new(self.client_id.clone()),
146156
update_from: client_state_meta.counterparty_height,
147157
update_to: if latest_height.height() < target_height.height() {
148158
warn!(
149159
"latest height {latest_height} is less than the target \
150-
height {target_height}, there may be something wrong \
151-
with the rpc for {} - client {} will be updated to the \
152-
target height instead of the latest height",
160+
height {target_height}, there may be something wrong \
161+
with the rpc for {} - client {} will be updated to the \
162+
target height instead of the latest height",
153163
module.chain_id, self.client_id
154164
);
155165
target_height
@@ -162,61 +172,53 @@ where
162172
module.plugin_name(),
163173
ModuleCallback::from(MakeIbcMessagesFromUpdate::<V> {
164174
client_id: self.client_id.clone(),
165-
batches: self.batches,
175+
batches: self.batches.clone(),
166176
}),
167177
),
168-
))
178+
));
169179
}
170180
}
171-
EventProvableHeight::Exactly(target_height) => {
172-
match client_state_meta.counterparty_height.cmp(&target_height) {
173-
Ordering::Equal => {
174-
info!(
175-
"client {client_id} has already been updated to \
176-
the desired target height ({} == {target_height})",
177-
client_state_meta.counterparty_height,
178-
client_id = self.client_id,
179-
);
180-
make_msgs(
181-
module,
182-
self.client_id,
183-
self.batches,
184-
None,
185-
client_state_meta.clone(),
186-
client_state_meta.counterparty_height,
187-
)
188-
}
189-
Ordering::Less => Ok(promise(
190-
[call(FetchUpdateHeaders {
191-
client_type: client_info.client_type,
192-
counterparty_chain_id: module.chain_id.clone(),
193-
chain_id: client_state_meta.counterparty_chain_id,
194-
client_id: RawClientId::new(self.client_id.clone()),
195-
update_from: client_state_meta.counterparty_height,
196-
update_to: target_height,
197-
})],
198-
[],
199-
PluginMessage::new(
200-
module.plugin_name(),
201-
ModuleCallback::from(MakeIbcMessagesFromUpdate::<V> {
202-
client_id: self.client_id.clone(),
203-
batches: self.batches,
204-
}),
205-
),
206-
)),
207-
// update backwards
208-
// currently this is only supported in sui, and as such has some baked-in assumptions about the semantics of when this branch is hit
209-
Ordering::Greater => {
210-
info!(
211-
"updating client to an earlier height ({} -> {target_height})",
212-
client_state_meta.counterparty_height
213-
);
214-
215-
Ok(promise(
181+
TargetHeights::None => todo!(),
182+
#[allow(unstable_name_collisions)]
183+
TargetHeights::Exact(target_heights) => {
184+
info!(
185+
"found exact heights: [{}]",
186+
target_heights
187+
.iter()
188+
.map(|h| h.to_string())
189+
.intersperse(",".to_string())
190+
.collect::<String>(),
191+
);
192+
193+
for events in self.batches {
194+
let EventProvableHeight::Exactly(target_height) = events[0].provable_height
195+
else {
196+
panic!("???")
197+
};
198+
199+
match client_state_meta.counterparty_height.cmp(&target_height) {
200+
Ordering::Equal => {
201+
info!(
202+
"client {client_id} has already been updated to \
203+
the desired target height ({} == {target_height})",
204+
client_state_meta.counterparty_height,
205+
client_id = self.client_id,
206+
);
207+
208+
ops.push(make_msgs(
209+
module,
210+
self.client_id.clone(),
211+
vec![events],
212+
None,
213+
client_state_meta.clone(),
214+
client_state_meta.counterparty_height,
215+
)?);
216+
}
217+
Ordering::Less => ops.push(promise(
216218
[call(FetchUpdateHeaders {
217-
client_type: client_info.client_type,
219+
client_type: client_info.client_type.clone(),
218220
counterparty_chain_id: module.chain_id.clone(),
219-
chain_id: client_state_meta.counterparty_chain_id,
221+
chain_id: client_state_meta.counterparty_chain_id.clone(),
220222
client_id: RawClientId::new(self.client_id.clone()),
221223
update_from: client_state_meta.counterparty_height,
222224
update_to: target_height,
@@ -226,14 +228,43 @@ where
226228
module.plugin_name(),
227229
ModuleCallback::from(MakeIbcMessagesFromUpdate::<V> {
228230
client_id: self.client_id.clone(),
229-
batches: self.batches,
231+
batches: vec![events],
230232
}),
231233
),
232-
))
234+
)),
235+
// update backwards
236+
// currently this is only supported in sui, and as such has some baked-in assumptions about the semantics of when this branch is hit
237+
Ordering::Greater => {
238+
info!(
239+
"updating client to an earlier height ({} -> {target_height})",
240+
client_state_meta.counterparty_height
241+
);
242+
243+
ops.push(promise(
244+
[call(FetchUpdateHeaders {
245+
client_type: client_info.client_type.clone(),
246+
counterparty_chain_id: module.chain_id.clone(),
247+
chain_id: client_state_meta.counterparty_chain_id.clone(),
248+
client_id: RawClientId::new(self.client_id.clone()),
249+
update_from: client_state_meta.counterparty_height,
250+
update_to: target_height,
251+
})],
252+
[],
253+
PluginMessage::new(
254+
module.plugin_name(),
255+
ModuleCallback::from(MakeIbcMessagesFromUpdate::<V> {
256+
client_id: self.client_id.clone(),
257+
batches: vec![events],
258+
}),
259+
),
260+
));
261+
}
233262
}
234263
}
235264
}
236265
}
266+
267+
Ok(conc(ops))
237268
}
238269
}
239270

0 commit comments

Comments
 (0)