diff --git a/ethexe/runtime/common/src/journal.rs b/ethexe/runtime/common/src/journal.rs index f3c217965cb..3a0b9db52d7 100644 --- a/ethexe/runtime/common/src/journal.rs +++ b/ethexe/runtime/common/src/journal.rs @@ -41,7 +41,7 @@ impl Handler<'_, S> { program_id: ProgramId, f: impl FnOnce(&mut ProgramState) -> Result<()>, ) -> H256 { - self.update_state_with_storage(program_id, |_s, state| f(state)) + crate::update_state(self.in_block_transitions, self.storage, program_id, f) } pub fn update_state_with_storage( @@ -49,20 +49,7 @@ impl Handler<'_, S> { program_id: ProgramId, f: impl FnOnce(&S, &mut ProgramState) -> Result<()>, ) -> H256 { - let state_hash = self - .in_block_transitions - .state_of(&program_id) - .expect("failed to find program in known states"); - - let new_state_hash = self - .storage - .mutate_state(state_hash, f) - .expect("failed to mutate state"); - - self.in_block_transitions - .modify_state(program_id, new_state_hash); - - new_state_hash + crate::update_state_with_storage(self.in_block_transitions, self.storage, program_id, f) } fn pop_queue_message(state: &ProgramState, storage: &S) -> (H256, MessageId) { diff --git a/ethexe/runtime/common/src/lib.rs b/ethexe/runtime/common/src/lib.rs index 65bfa20e50d..933eb4f6b7a 100644 --- a/ethexe/runtime/common/src/lib.rs +++ b/ethexe/runtime/common/src/lib.rs @@ -27,6 +27,7 @@ use alloc::{ collections::{BTreeMap, VecDeque}, vec::Vec, }; +use anyhow::Result; use core::{marker::PhantomData, mem::swap}; use core_processor::{ common::{ExecutableActorData, JournalNote}, @@ -46,8 +47,8 @@ use gprimitives::{CodeId, H256}; use gsys::{GasMultiplier, Percent}; use parity_scale_codec::{Decode, Encode}; use state::{ - ActiveProgram, Dispatch, HashAndLen, InitStatus, MaybeHash, MessageQueue, ProgramState, - Storage, Waitlist, + ActiveProgram, ComplexStorage, Dispatch, HashAndLen, InitStatus, MaybeHash, MessageQueue, + ProgramState, Storage, Waitlist, }; pub use core_processor::configs::BlockInfo; @@ -74,6 +75,36 @@ pub trait RuntimeInterface { fn storage(&self) -> &S; } +pub(crate) fn update_state( + in_block_transitions: &mut InBlockTransitions, + storage: &S, + program_id: ProgramId, + f: impl FnOnce(&mut ProgramState) -> Result<()>, +) -> H256 { + update_state_with_storage(in_block_transitions, storage, program_id, |_s, state| { + f(state) + }) +} + +pub(crate) fn update_state_with_storage( + in_block_transitions: &mut InBlockTransitions, + storage: &S, + program_id: ProgramId, + f: impl FnOnce(&S, &mut ProgramState) -> Result<()>, +) -> H256 { + let state_hash = in_block_transitions + .state_of(&program_id) + .expect("failed to find program in known states"); + + let new_state_hash = storage + .mutate_state(state_hash, f) + .expect("failed to mutate state"); + + in_block_transitions.modify_state(program_id, new_state_hash); + + new_state_hash +} + pub fn process_next_message>( program_id: ProgramId, program_state: ProgramState, diff --git a/ethexe/runtime/common/src/schedule.rs b/ethexe/runtime/common/src/schedule.rs index 5ab8e0e8d31..ed17821bc7e 100644 --- a/ethexe/runtime/common/src/schedule.rs +++ b/ethexe/runtime/common/src/schedule.rs @@ -1,32 +1,71 @@ +use crate::{ + state::{ComplexStorage, ProgramState, Storage}, + InBlockTransitions, +}; +use anyhow::Result; use gear_core::{ids::ProgramId, tasks::TaskHandler}; -use gprimitives::{ActorId, CodeId, MessageId, ReservationId}; - -use crate::{state::Storage, InBlockTransitions}; +use gprimitives::{ActorId, CodeId, MessageId, ReservationId, H256}; pub struct Handler<'a, S: Storage> { pub in_block_transitions: &'a mut InBlockTransitions, pub storage: &'a S, } +impl Handler<'_, S> { + pub fn update_state( + &mut self, + program_id: ProgramId, + f: impl FnOnce(&mut ProgramState) -> Result<()>, + ) -> H256 { + crate::update_state(self.in_block_transitions, self.storage, program_id, f) + } + + pub fn update_state_with_storage( + &mut self, + program_id: ProgramId, + f: impl FnOnce(&S, &mut ProgramState) -> Result<()>, + ) -> H256 { + crate::update_state_with_storage(self.in_block_transitions, self.storage, program_id, f) + } +} + impl<'a, S: Storage> TaskHandler for Handler<'a, S> { fn remove_from_mailbox(&mut self, _user_id: ActorId, _message_id: MessageId) -> u64 { unimplemented!("TODO (breathx)") } - fn remove_from_waitlist(&mut self, _program_id: ProgramId, _message_id: MessageId) -> u64 { - unimplemented!("TODO (breathx)") - } fn send_dispatch(&mut self, _stashed_message_id: MessageId) -> u64 { unimplemented!("TODO (breathx)") } fn send_user_message(&mut self, _stashed_message_id: MessageId, _to_mailbox: bool) -> u64 { unimplemented!("TODO (breathx)") } - fn wake_message(&mut self, _program_id: ProgramId, _message_id: MessageId) -> u64 { - // TODO (breathx): consider deprecation of delayed wakes + non-concrete waits. - unimplemented!("TODO (breathx)") + // TODO (breathx): consider deprecation of delayed wakes + non-concrete waits. + fn wake_message(&mut self, program_id: ProgramId, message_id: MessageId) -> u64 { + // TODO (breathx): don't update state if not changed? + self.update_state_with_storage(program_id, |storage, state| { + let Some((dispatch, new_waitlist_hash)) = storage + .modify_waitlist_if_changed(state.waitlist_hash.clone(), |waitlist| { + waitlist.remove(&message_id) + })? + else { + return Ok(()); + }; + + state.waitlist_hash = new_waitlist_hash; + state.queue_hash = storage.modify_queue(state.queue_hash.clone(), |queue| { + queue.push_back(dispatch); + })?; + + Ok(()) + }); + + 0 } /* Deprecated APIs */ + fn remove_from_waitlist(&mut self, _program_id: ProgramId, _message_id: MessageId) -> u64 { + unreachable!("considering deprecation of it; use `wake_message` instead") + } fn pause_program(&mut self, _: ProgramId) -> u64 { unreachable!("deprecated") }