Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Add GetState request #98

Merged
merged 1 commit into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading