Skip to content

Commit

Permalink
add GetState request
Browse files Browse the repository at this point in the history
  • Loading branch information
gshep committed Aug 7, 2024
1 parent fd79113 commit 3254f7f
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 35 deletions.
2 changes: 2 additions & 0 deletions gear-programs/checkpoint-light-client/io/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ pub enum Handle {
headers: Vec<BeaconBlockHeader>,
},
ReplayBack(Vec<BeaconBlockHeader>),
GetState(meta::StateRequest),
}

#[derive(Debug, Clone, Encode, Decode, TypeInfo)]
Expand All @@ -88,4 +89,5 @@ pub enum HandleResult {
SyncUpdate(Result<(), sync_update::Error>),
ReplayBackStart(Result<replay_back::StatusStart, replay_back::Error>),
ReplayBack(Option<replay_back::Status>),
State(meta::State),
}
30 changes: 26 additions & 4 deletions gear-programs/checkpoint-light-client/io/src/meta.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;

use gmeta::{In, InOut, Out};
use gmeta::{In, InOut};
use gstd::prelude::*;

pub struct Metadata;
Expand All @@ -11,13 +11,35 @@ impl gmeta::Metadata for Metadata {
type Others = ();
type Reply = ();
type Signal = ();
type State = Out<State>;
type State = InOut<StateRequest, State>;
}

#[derive(Debug, Clone, Default, Encode, Decode, TypeInfo)]
pub struct State {
pub checkpoints: Vec<(Slot, Hash256)>,
/// The field contains the last processed header if the program is
/// The field contains the data if the program is
/// replaying checkpoints back.
pub replay_back: Option<BeaconBlockHeader>,
pub replay_back: Option<ReplayBack>,
}

/// The struct contains slots of the finalized and the last checked headers.
#[derive(Debug, Clone, Encode, Decode, TypeInfo)]
pub struct ReplayBack {
pub finalized_header: Slot,
pub last_header: Slot,
}

#[derive(Debug, Clone, Encode, Decode, TypeInfo)]
pub enum Order {
Direct,
Reverse,
}

#[derive(Debug, Clone, Encode, Decode, TypeInfo)]
pub struct StateRequest {
// The flag specifies the subslice position
pub order: Order,
// Parameters determine checkpoints count in the response
pub index_start: u32,
pub count: u32,
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub enum Error {
InvalidNextSyncCommitteeProof,
InvalidPublicKeys,
ReplayBackRequired {
replayed_slot: Option<Slot>,
replay_back: Option<meta::ReplayBack>,
checkpoint: (Slot, Hash256),
},
}
33 changes: 14 additions & 19 deletions gear-programs/checkpoint-light-client/src/wasm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::*;
use ark_serialize::CanonicalSerialize;
use core::{cmp, num::Saturating};
use gstd::{msg, vec};
use io::{
ethereum_common::{
Expand All @@ -9,6 +10,7 @@ use io::{
tree_hash::TreeHash,
utils as eth_utils, Hash256, SYNC_COMMITTEE_SIZE,
},
meta,
sync_update::Error as SyncCommitteeUpdateError,
BeaconBlockHeader, Handle, HandleResult, Init, SyncCommitteeKeys, SyncCommitteeUpdate, G1, G2,
};
Expand Down Expand Up @@ -107,28 +109,21 @@ async fn main() {
} => replay_back::handle_start(state, sync_update, headers).await,

Handle::ReplayBack(headers) => replay_back::handle(state, headers),

Handle::GetState(request) => {
let reply = utils::construct_state_reply(request, state);
msg::reply(HandleResult::State(reply), 0)
.expect("Unable to reply with `HandleResult::State`");
}
}
}

#[no_mangle]
extern "C" fn state() {
let state = unsafe { STATE.as_ref() };
let checkpoints = state
.map(|state| state.checkpoints.checkpoints())
.unwrap_or(vec![]);
let replay_back = state.and_then(|state| {
state
.replay_back
.as_ref()
.map(|replay_back| replay_back.last_header.clone())
});

msg::reply(
io::meta::State {
checkpoints,
replay_back,
},
0,
)
.expect("Failed to encode or reply with `<AppMetadata as Metadata>::State` from `state()`");
let request = msg::load().expect("Unable to decode `StateRequest` message");
let state = unsafe { STATE.as_ref() }.expect("The program should be initialized");
let reply = utils::construct_state_reply(request, state);

msg::reply(reply, 0)
.expect("Failed to encode or reply with `<AppMetadata as Metadata>::State` from `state()`");
}
7 changes: 5 additions & 2 deletions gear-programs/checkpoint-light-client/src/wasm/sync_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ pub async fn handle(state: &mut State<STORED_CHECKPOINTS_COUNT>, sync_update: Sy
{
let result =
HandleResult::SyncUpdate(Err(io::sync_update::Error::ReplayBackRequired {
replayed_slot: state
replay_back: state
.replay_back
.as_ref()
.map(|replay_back| replay_back.last_header.slot),
.map(|replay_back| meta::ReplayBack {
finalized_header: replay_back.finalized_header.slot,
last_header: replay_back.last_header.slot,
}),
checkpoint: state
.checkpoints
.last()
Expand Down
55 changes: 48 additions & 7 deletions gear-programs/checkpoint-light-client/src/wasm/utils.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
use super::*;
use io::{
ethereum_common::{
base_types::{BytesFixed, FixedArray},
beacon::{BLSPubKey, SyncCommittee},
SYNC_COMMITTEE_SIZE,
},
SyncCommitteeKeys,
use io::ethereum_common::{
base_types::BytesFixed,
beacon::{BLSPubKey, SyncCommittee},
};

pub fn construct_sync_committee(
Expand Down Expand Up @@ -41,3 +37,48 @@ pub fn get_participating_keys(
.filter_map(|(bit, pub_key)| bit.then_some(pub_key.clone().0 .0))
.collect::<Vec<_>>()
}

pub fn construct_state_reply(
request: meta::StateRequest,
state: &State<STORED_CHECKPOINTS_COUNT>,
) -> meta::State {
use meta::Order;

let count = Saturating(request.count as usize);
let checkpoints_all = state.checkpoints.checkpoints();
let (start, end) = match request.order {
Order::Direct => {
let start = Saturating(request.index_start as usize);
let Saturating(end) = start + count;

(start.0, cmp::min(end, checkpoints_all.len()))
}

Order::Reverse => {
let len = Saturating(checkpoints_all.len());
let index_last = Saturating(request.index_start as usize);
let end = len - index_last;
let Saturating(start) = end - count;

(start, end.0)
}
};

let checkpoints = checkpoints_all
.get(start..end)
.map(|slice| slice.to_vec())
.unwrap_or(vec![]);

let replay_back = state
.replay_back
.as_ref()
.map(|replay_back| meta::ReplayBack {
finalized_header: replay_back.finalized_header.slot,
last_header: replay_back.last_header.slot,
});

meta::State {
checkpoints,
replay_back,
}
}
4 changes: 2 additions & 2 deletions relayer/src/ethereum_checkpoints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub async fn relay(args: RelayCheckpointsArgs) {
return;
}
Ok(Err(sync_update::Error::ReplayBackRequired {
replayed_slot,
replay_back,
checkpoint,
})) => {
if let Err(e) = replay_back::execute(
Expand All @@ -111,7 +111,7 @@ pub async fn relay(args: RelayCheckpointsArgs) {
&mut listener,
program_id,
gas_limit,
replayed_slot,
replay_back.map(|r| r.last_header),
checkpoint,
sync_update,
)
Expand Down

0 comments on commit 3254f7f

Please sign in to comment.