From c850327dcf60430f4c083fe194db274c68e78219 Mon Sep 17 00:00:00 2001 From: Dmitrii Novikov Date: Wed, 9 Oct 2024 18:03:17 +0400 Subject: [PATCH] feat(ethexe): use real block header in handling; impl Mailbox timeouts; remove scheduled tasks on actions (#4283) --- core-processor/src/ext.rs | 2 +- ethexe/cli/src/service.rs | 25 ++----- ethexe/cli/src/tests.rs | 75 +++++++++++++++---- ethexe/common/src/db.rs | 18 ++++- ethexe/ethereum/src/router/mod.rs | 2 +- ethexe/network/src/lib.rs | 8 +- ethexe/observer/src/event.rs | 37 +++++++-- ethexe/observer/src/lib.rs | 2 +- ethexe/observer/src/observer.rs | 21 ++++-- ethexe/processor/src/handling/events.rs | 63 +++++++++------- ethexe/processor/src/handling/mod.rs | 2 +- ethexe/processor/src/handling/run.rs | 1 - ethexe/processor/src/lib.rs | 36 ++++----- ethexe/processor/src/tests.rs | 18 +++-- ethexe/rpc/src/lib.rs | 31 +++++--- ethexe/runtime/common/src/journal.rs | 32 ++++++-- ethexe/runtime/common/src/schedule.rs | 8 +- ethexe/runtime/common/src/state.rs | 35 ++++----- ethexe/runtime/common/src/transitions.rs | 53 ++++++++----- ethexe/sequencer/src/lib.rs | 4 +- gcli/src/cmd/program.rs | 6 +- gprimitives/src/nonzero_u256.rs | 18 ++--- lazy-pages/src/common.rs | 6 +- lazy-pages/src/lib.rs | 4 +- lazy-pages/src/pages.rs | 12 +-- pallets/gear/src/benchmarking/mod.rs | 4 +- pallets/gear/src/internal.rs | 4 +- pallets/gear/src/lib.rs | 6 +- pallets/gear/src/tests.rs | 29 +++---- .../sandbox/wasmer_backend/store_refcell.rs | 19 ++--- utils/calc-stack-height/src/main.rs | 23 +++++- utils/gring/src/keyring.rs | 6 +- utils/gring/tests/command.rs | 2 +- utils/lazy-pages-fuzzer/src/config.rs | 9 +-- utils/node-loader/src/args.rs | 6 +- utils/wasm-builder/src/wasm_project.rs | 6 +- utils/wasm-gen/src/config.rs | 25 +++---- utils/wasm-gen/src/config/module.rs | 14 ++-- utils/wasm-gen/src/config/syscalls.rs | 15 ++-- utils/wasm-gen/src/generator.rs | 2 +- .../src/generator/syscalls/additional_data.rs | 6 +- .../src/generator/syscalls/imports.rs | 17 +++-- .../src/generator/syscalls/invocator.rs | 4 +- utils/wasm-gen/src/tests.rs | 10 +-- utils/wasm-optimizer/src/optimize.rs | 6 +- 45 files changed, 451 insertions(+), 281 deletions(-) diff --git a/core-processor/src/ext.rs b/core-processor/src/ext.rs index f1ecaddfe58..67a4985525c 100644 --- a/core-processor/src/ext.rs +++ b/core-processor/src/ext.rs @@ -1227,7 +1227,7 @@ impl Externalities for Ext { } fn system_reserve_gas(&mut self, amount: u64) -> Result<(), Self::FallibleError> { - // TODO: use `NonZeroU64` after issue #1838 is fixed + // TODO: use `NonZero` after issue #1838 is fixed if amount == 0 { return Err(ReservationError::ZeroReservationAmount.into()); } diff --git a/ethexe/cli/src/service.rs b/ethexe/cli/src/service.rs index da679a13138..a418816637b 100644 --- a/ethexe/cli/src/service.rs +++ b/ethexe/cli/src/service.rs @@ -29,7 +29,7 @@ use ethexe_common::{ }, BlockRequestEvent, }; -use ethexe_db::{BlockHeader, BlockMetaStorage, CodesStorage, Database}; +use ethexe_db::{BlockMetaStorage, CodesStorage, Database}; use ethexe_ethereum::router::RouterQuery; use ethexe_network::NetworkReceiverEvent; use ethexe_observer::{RequestBlockData, RequestEvent}; @@ -333,20 +333,11 @@ impl Service { processor: &mut ethexe_processor::Processor, block_data: RequestBlockData, ) -> Result> { - db.set_block_events(block_data.block_hash, block_data.events); - db.set_block_header( - block_data.block_hash, - BlockHeader { - height: block_data.block_number.try_into()?, - timestamp: block_data.block_timestamp, - parent_hash: block_data.parent_hash, - }, - ); + db.set_block_events(block_data.hash, block_data.events); + db.set_block_header(block_data.hash, block_data.header); let mut commitments = vec![]; - let last_committed_chain = query - .get_last_committed_chain(block_data.block_hash) - .await?; + let last_committed_chain = query.get_last_committed_chain(block_data.hash).await?; for block_hash in last_committed_chain.into_iter().rev() { let transitions = Self::process_one_block(db, query, processor, block_hash).await?; @@ -357,7 +348,7 @@ impl Service { commitments.push(BlockCommitment { block_hash, - pred_block_hash: block_data.block_hash, + pred_block_hash: block_data.hash, prev_commitment_hash: db .block_prev_commitment(block_hash) .ok_or_else(|| anyhow!("Prev commitment not found"))?, @@ -383,9 +374,9 @@ impl Service { RequestEvent::Block(block_data) => { log::info!( "📦 receive a new block {}, hash {}, parent hash {}", - block_data.block_number, - block_data.block_hash, - block_data.parent_hash + block_data.header.height, + block_data.hash, + block_data.header.parent_hash ); let commitments = diff --git a/ethexe/cli/src/tests.rs b/ethexe/cli/src/tests.rs index 8787ffb1830..757b5d39646 100644 --- a/ethexe/cli/src/tests.rs +++ b/ethexe/cli/src/tests.rs @@ -28,7 +28,7 @@ use anyhow::Result; use ethexe_common::{ db::CodesStorage, mirror::Event as MirrorEvent, router::Event as RouterEvent, BlockEvent, }; -use ethexe_db::{Database, MemDb}; +use ethexe_db::{BlockMetaStorage, Database, MemDb, ScheduledTask}; use ethexe_ethereum::{router::RouterQuery, Ethereum}; use ethexe_observer::{Event, MockBlobReader, Observer, Query}; use ethexe_processor::Processor; @@ -42,7 +42,11 @@ use gear_core::{ }; use gprimitives::{ActorId, CodeId, MessageId, H160, H256}; use parity_scale_codec::Encode; -use std::{collections::BTreeMap, sync::Arc, time::Duration}; +use std::{ + collections::{BTreeMap, BTreeSet}, + sync::Arc, + time::Duration, +}; use tokio::{ sync::oneshot, task::{self, JoinHandle}, @@ -183,12 +187,13 @@ async fn mailbox() { .await .unwrap(); - let mid_expected_message = MessageId::generate_outgoing(res.message_id, 0); - let ping_expected_message = MessageId::generate_outgoing(res.message_id, 1); + let original_mid = res.message_id; + let mid_expected_message = MessageId::generate_outgoing(original_mid, 0); + let ping_expected_message = MessageId::generate_outgoing(original_mid, 1); let mut listener = env.events_publisher().subscribe().await; - listener - .apply_until_block_event(|event| match event { + let block_data = listener + .apply_until_block_event_with_header(|event, block_data| match event { BlockEvent::Mirror { address, event } if address == pid => { if let MirrorEvent::Message { id, @@ -204,7 +209,7 @@ async fn mailbox() { Ok(None) } else if id == ping_expected_message { assert_eq!(payload, b"PING"); - Ok(Some(())) + Ok(Some(block_data.clone())) } else { unreachable!() } @@ -217,9 +222,37 @@ async fn mailbox() { .await .unwrap(); + // -1 bcs execution took place in previous block, not the one that emits events. + let wake_expiry = block_data.header.height - 1 + 100; // 100 is default wait for. + let expiry = block_data.header.height - 1 + ethexe_runtime_common::state::MAILBOX_VALIDITY; + + let expected_schedule = BTreeMap::from_iter([ + ( + wake_expiry, + BTreeSet::from_iter([ScheduledTask::WakeMessage(pid, original_mid)]), + ), + ( + expiry, + BTreeSet::from_iter([ + ScheduledTask::RemoveFromMailbox((pid, env.sender_id), mid_expected_message), + ScheduledTask::RemoveFromMailbox((pid, env.sender_id), ping_expected_message), + ]), + ), + ]); + + let schedule = node + .db + .block_end_schedule(block_data.header.parent_hash) + .expect("must exist"); + + assert_eq!(schedule, expected_schedule); + let expected_mailbox = BTreeMap::from_iter([( env.sender_id, - BTreeMap::from_iter([(mid_expected_message, 0), (ping_expected_message, 0)]), + BTreeMap::from_iter([ + (mid_expected_message, (0, expiry)), + (ping_expected_message, (0, expiry)), + ]), )]); let mirror = env.ethereum.mirror(pid.try_into().unwrap()); let state_hash = mirror.query().state_hash().await.unwrap(); @@ -255,20 +288,20 @@ async fn mailbox() { let expected_mailbox = BTreeMap::from_iter([( env.sender_id, - BTreeMap::from_iter([(mid_expected_message, 0)]), + BTreeMap::from_iter([(mid_expected_message, (0, expiry))]), )]); assert_eq!(mailbox, expected_mailbox); mirror.claim_value(mid_expected_message).await.unwrap(); - listener - .apply_until_block_event(|event| match event { + let block_data = listener + .apply_until_block_event_with_header(|event, block_data| match event { BlockEvent::Mirror { address, event } if address == pid => match event { MirrorEvent::ValueClaimed { claimed_id, .. } if claimed_id == mid_expected_message => { - Ok(Some(())) + Ok(Some(block_data.clone())) } _ => Ok(None), }, @@ -281,6 +314,12 @@ async fn mailbox() { let state = node.db.read_state(state_hash).unwrap(); assert!(state.mailbox_hash.is_empty()); + + let schedule = node + .db + .block_end_schedule(block_data.header.parent_hash) + .expect("must exist"); + assert!(schedule.is_empty(), "{:?}", schedule); } #[tokio::test(flavor = "multi_thread")] @@ -646,6 +685,7 @@ async fn multiple_validators() { mod utils { use super::*; + use ethexe_observer::SimpleBlockData; use futures::StreamExt; use gear_core::message::ReplyCode; use tokio::sync::{broadcast::Sender, Mutex}; @@ -1020,6 +1060,13 @@ mod utils { pub async fn apply_until_block_event( &mut self, mut f: impl FnMut(BlockEvent) -> Result>, + ) -> Result { + self.apply_until_block_event_with_header(|e, _h| f(e)).await + } + + pub async fn apply_until_block_event_with_header( + &mut self, + mut f: impl FnMut(BlockEvent, &SimpleBlockData) -> Result>, ) -> Result { loop { let event = self.next_event().await?; @@ -1028,8 +1075,10 @@ mod utils { continue; }; + let block_data = block.as_simple(); + for event in block.events { - if let Some(res) = f(event)? { + if let Some(res) = f(event, &block_data)? { return Ok(res); } } diff --git a/ethexe/common/src/db.rs b/ethexe/common/src/db.rs index 4975fa4cd40..3e660b6e425 100644 --- a/ethexe/common/src/db.rs +++ b/ethexe/common/src/db.rs @@ -30,7 +30,8 @@ use gear_core::{ use gprimitives::H256; use parity_scale_codec::{Decode, Encode}; -pub type ScheduledTask = gear_core::tasks::ScheduledTask; +/// NOTE: key for actor id is (program_id, user_id). only used for mailbox. +pub type ScheduledTask = gear_core::tasks::ScheduledTask<(ProgramId, ActorId)>; #[derive(Debug, Clone, Default, Encode, Decode, serde::Serialize)] pub struct BlockHeader { @@ -39,13 +40,26 @@ pub struct BlockHeader { pub parent_hash: H256, } +impl BlockHeader { + pub fn dummy(height: u32) -> Self { + let mut parent_hash = [0; 32]; + parent_hash[..4].copy_from_slice(&height.to_le_bytes()); + + Self { + height, + timestamp: height as u64 * 12, + parent_hash: parent_hash.into(), + } + } +} + #[derive(Debug, Clone, Default, Encode, Decode)] pub struct CodeUploadInfo { pub origin: ActorId, pub tx_hash: H256, } -pub type Schedule = BTreeMap>; +pub type Schedule = BTreeMap>; pub trait BlockMetaStorage: Send + Sync { fn block_header(&self, block_hash: H256) -> Option; diff --git a/ethexe/ethereum/src/router/mod.rs b/ethexe/ethereum/src/router/mod.rs index 36247d1fb4c..e096b1b4d32 100644 --- a/ethexe/ethereum/src/router/mod.rs +++ b/ethexe/ethereum/src/router/mod.rs @@ -136,7 +136,7 @@ impl Router { } } - Err(anyhow::anyhow!("Failed to define if code is validated")) + Err(anyhow!("Failed to define if code is validated")) } pub async fn create_program( diff --git a/ethexe/network/src/lib.rs b/ethexe/network/src/lib.rs index 70f15e8e632..53fbb3950f9 100644 --- a/ethexe/network/src/lib.rs +++ b/ethexe/network/src/lib.rs @@ -25,7 +25,7 @@ pub mod export { pub use libp2p::{multiaddr::Protocol, Multiaddr, PeerId}; } -use anyhow::Context; +use anyhow::{anyhow, Context}; use ethexe_db::Database; use ethexe_signer::{PublicKey, Signer}; use futures::future::Either; @@ -544,18 +544,18 @@ impl Behaviour { gossipsub::MessageId::from(hasher.finish().to_be_bytes()) }) .build() - .map_err(|e| anyhow::anyhow!("`gossipsub::ConfigBuilder::build()` error: {e}"))?; + .map_err(|e| anyhow!("`gossipsub::ConfigBuilder::build()` error: {e}"))?; let mut gossipsub = gossipsub::Behaviour::new( gossipsub::MessageAuthenticity::Signed(keypair.clone()), gossip_config, ) - .map_err(|e| anyhow::anyhow!("`gossipsub::Behaviour` error: {e}"))?; + .map_err(|e| anyhow!("`gossipsub::Behaviour` error: {e}"))?; gossipsub .with_peer_score( gossipsub::PeerScoreParams::default(), gossipsub::PeerScoreThresholds::default(), ) - .map_err(|e| anyhow::anyhow!("`gossipsub` scoring parameters error: {e}"))?; + .map_err(|e| anyhow!("`gossipsub` scoring parameters error: {e}"))?; gossipsub.subscribe(&gpu_commitments_topic())?; diff --git a/ethexe/observer/src/event.rs b/ethexe/observer/src/event.rs index 3ee5a855c38..9080d11e4a0 100644 --- a/ethexe/observer/src/event.rs +++ b/ethexe/observer/src/event.rs @@ -1,4 +1,5 @@ use ethexe_common::{BlockEvent, BlockRequestEvent}; +use ethexe_db::BlockHeader; use gprimitives::{CodeId, H256}; use parity_scale_codec::{Decode, Encode}; @@ -16,18 +17,38 @@ pub enum Event { #[derive(Debug, Clone, Encode, Decode)] pub struct RequestBlockData { - pub parent_hash: H256, - pub block_hash: H256, - pub block_number: u64, - pub block_timestamp: u64, + pub hash: H256, + pub header: BlockHeader, pub events: Vec, } +impl RequestBlockData { + pub fn as_simple(&self) -> SimpleBlockData { + SimpleBlockData { + hash: self.hash, + header: self.header.clone(), + } + } +} + #[derive(Debug, Clone, Encode, Decode)] pub struct BlockData { - pub parent_hash: H256, - pub block_hash: H256, - pub block_number: u64, - pub block_timestamp: u64, + pub hash: H256, + pub header: BlockHeader, pub events: Vec, } + +impl BlockData { + pub fn as_simple(&self) -> SimpleBlockData { + SimpleBlockData { + hash: self.hash, + header: self.header.clone(), + } + } +} + +#[derive(Debug, Clone, Encode, Decode)] +pub struct SimpleBlockData { + pub hash: H256, + pub header: BlockHeader, +} diff --git a/ethexe/observer/src/lib.rs b/ethexe/observer/src/lib.rs index 65a116e825e..3a9e1a23e92 100644 --- a/ethexe/observer/src/lib.rs +++ b/ethexe/observer/src/lib.rs @@ -24,6 +24,6 @@ mod observer; mod query; pub use blobs::{BlobReader, ConsensusLayerBlobReader, MockBlobReader}; -pub use event::{BlockData, Event, RequestBlockData, RequestEvent}; +pub use event::{BlockData, Event, RequestBlockData, RequestEvent, SimpleBlockData}; pub use observer::{Observer, ObserverStatus}; pub use query::Query; diff --git a/ethexe/observer/src/observer.rs b/ethexe/observer/src/observer.rs index 26318ba15e3..f4070aef6fb 100644 --- a/ethexe/observer/src/observer.rs +++ b/ethexe/observer/src/observer.rs @@ -13,6 +13,7 @@ use ethexe_common::{ router::{Event as RouterEvent, RequestEvent as RouterRequestEvent}, BlockEvent, BlockRequestEvent, }; +use ethexe_db::BlockHeader; use ethexe_ethereum::{ mirror, router::{self, RouterQuery}, @@ -144,10 +145,12 @@ impl Observer { }); let block_data = BlockData { - block_hash, - parent_hash, - block_number, - block_timestamp, + hash: block_hash, + header: BlockHeader { + height: block_number as u32, + timestamp: block_timestamp, + parent_hash, + }, events, }; @@ -233,10 +236,12 @@ impl Observer { }); let block_data = RequestBlockData { - block_hash, - parent_hash, - block_number, - block_timestamp, + hash: block_hash, + header: BlockHeader { + height: block_number as u32, + timestamp: block_timestamp, + parent_hash, + }, events, }; diff --git a/ethexe/processor/src/handling/events.rs b/ethexe/processor/src/handling/events.rs index ceffd2afbf0..dfa93ad2be1 100644 --- a/ethexe/processor/src/handling/events.rs +++ b/ethexe/processor/src/handling/events.rs @@ -17,13 +17,13 @@ // along with this program. If not, see . use crate::Processor; -use anyhow::Result; +use anyhow::{anyhow, Result}; use ethexe_common::{ mirror::RequestEvent as MirrorEvent, router::{RequestEvent as RouterEvent, ValueClaim}, wvara::RequestEvent as WVaraEvent, }; -use ethexe_db::CodesStorage; +use ethexe_db::{CodesStorage, ScheduledTask}; use ethexe_runtime_common::{ state::{ComplexStorage as _, Dispatch, Storage}, InBlockTransitions, @@ -75,9 +75,7 @@ impl Processor { let new_state_hash = self.handle_executable_balance_top_up(state_hash, value)?; in_block_transitions .modify_state(actor_id, new_state_hash) - .ok_or_else(|| { - anyhow::anyhow!("failed to modify state of recognized program") - })?; + .ok_or_else(|| anyhow!("failed to modify state of recognized program"))?; } MirrorEvent::MessageQueueingRequested { id, @@ -90,7 +88,7 @@ impl Processor { let state = self .db .read_state(state_hash) - .ok_or_else(|| anyhow::anyhow!("program should exist"))?; + .ok_or_else(|| anyhow!("program should exist"))?; let kind = if state.requires_init_message() { DispatchKind::Init @@ -111,9 +109,7 @@ impl Processor { let new_state_hash = self.handle_message_queueing(state_hash, dispatch)?; in_block_transitions .modify_state(actor_id, new_state_hash) - .ok_or_else(|| { - anyhow::anyhow!("failed to modify state of recognized program") - })?; + .ok_or_else(|| anyhow!("failed to modify state of recognized program"))?; } MirrorEvent::ReplyQueueingRequested { replied_to, @@ -121,25 +117,31 @@ impl Processor { payload, value, } => { - if let Some((value_claim, new_state_hash)) = + if let Some((value_claim, expiry, new_state_hash)) = self.handle_reply_queueing(state_hash, replied_to, source, payload, value)? { in_block_transitions .modify_state_with(actor_id, new_state_hash, 0, vec![value_claim], vec![]) - .ok_or_else(|| { - anyhow::anyhow!("failed to modify state of recognized program") - })?; + .ok_or_else(|| anyhow!("failed to modify state of recognized program"))?; + + in_block_transitions.remove_task( + expiry, + &ScheduledTask::RemoveFromMailbox((actor_id, source), replied_to), + )?; } } MirrorEvent::ValueClaimingRequested { claimed_id, source } => { - if let Some((value_claim, new_state_hash)) = + if let Some((value_claim, expiry, new_state_hash)) = self.handle_value_claiming(state_hash, claimed_id, source)? { in_block_transitions .modify_state_with(actor_id, new_state_hash, 0, vec![value_claim], vec![]) - .ok_or_else(|| { - anyhow::anyhow!("failed to modify state of recognized program") - })?; + .ok_or_else(|| anyhow!("failed to modify state of recognized program"))?; + + in_block_transitions.remove_task( + expiry, + &ScheduledTask::RemoveFromMailbox((actor_id, source), claimed_id), + )?; } } }; @@ -178,7 +180,7 @@ impl Processor { user_id: ActorId, payload: Vec, value: u128, - ) -> Result> { + ) -> Result> { self.handle_mailboxed_message_impl( state_hash, mailboxed_id, @@ -194,7 +196,7 @@ impl Processor { state_hash: H256, mailboxed_id: MessageId, user_id: ActorId, - ) -> Result> { + ) -> Result> { self.handle_mailboxed_message_impl( state_hash, mailboxed_id, @@ -213,10 +215,10 @@ impl Processor { payload: Vec, value: u128, reply_reason: SuccessReplyReason, - ) -> Result> { + ) -> Result> { self.db .mutate_state_returning(state_hash, |db, state| { - let Some((claimed_value, mailbox_hash)) = + let Some(((claimed_value, expiry), mailbox_hash)) = db.modify_mailbox_if_changed(state.mailbox_hash.clone(), |mailbox| { let local_mailbox = mailbox.get_mut(&user_id)?; let claimed_value = local_mailbox.remove(&mailboxed_id)?; @@ -240,17 +242,20 @@ impl Processor { state.queue_hash = db.modify_queue(state.queue_hash.clone(), |queue| queue.push_back(reply))?; - Ok(Some(ValueClaim { - message_id: mailboxed_id, - destination: user_id, - value: claimed_value, - })) + Ok(Some(( + ValueClaim { + message_id: mailboxed_id, + destination: user_id, + value: claimed_value, + }, + expiry, + ))) }) - .map(|(claim, hash)| { - if claim.is_none() { + .map(|(claim_with_expiry, hash)| { + if claim_with_expiry.is_none() { debug_assert_eq!(hash, state_hash); } - claim.map(|v| (v, hash)) + claim_with_expiry.map(|(claim, expiry)| (claim, expiry, hash)) }) } diff --git a/ethexe/processor/src/handling/mod.rs b/ethexe/processor/src/handling/mod.rs index 9baff8a640d..ded4b37d209 100644 --- a/ethexe/processor/src/handling/mod.rs +++ b/ethexe/processor/src/handling/mod.rs @@ -34,7 +34,7 @@ impl Processor { log::debug!( "Running schedule for #{}: tasks are {tasks:?}", - in_block_transitions.block_number() + in_block_transitions.header().height ); let mut handler = ScheduleHandler { diff --git a/ethexe/processor/src/handling/run.rs b/ethexe/processor/src/handling/run.rs index 75d0006d118..774e30b30c9 100644 --- a/ethexe/processor/src/handling/run.rs +++ b/ethexe/processor/src/handling/run.rs @@ -96,7 +96,6 @@ async fn run_in_async( program_id, in_block_transitions, storage: &db, - block_info: Default::default(), }; core_processor::handle_journal(journal, &mut handler); } diff --git a/ethexe/processor/src/lib.rs b/ethexe/processor/src/lib.rs index baa471dc702..abe16b462ab 100644 --- a/ethexe/processor/src/lib.rs +++ b/ethexe/processor/src/lib.rs @@ -18,7 +18,7 @@ //! Program's execution service for eGPU. -use anyhow::Result; +use anyhow::{anyhow, Result}; use ethexe_common::{mirror::RequestEvent as MirrorEvent, BlockRequestEvent}; use ethexe_db::{BlockMetaStorage, CodesStorage, Database}; use ethexe_runtime_common::{state::Storage, InBlockTransitions}; @@ -77,9 +77,10 @@ impl Processor { ) -> Result> { log::debug!("Processing events for {block_hash:?}: {events:#?}"); - let header = self.db.block_header(block_hash).ok_or_else(|| { - anyhow::anyhow!("failed to get block header for under-processing block") - })?; + let header = self + .db + .block_header(block_hash) + .ok_or_else(|| anyhow!("failed to get block header for under-processing block"))?; let states = self .db @@ -88,7 +89,7 @@ impl Processor { let schedule = self.db.block_start_schedule(block_hash).unwrap_or_default(); // TODO (breathx): shouldn't it be a panic? - let mut in_block_transitions = InBlockTransitions::new(header.height, states, schedule); + let mut in_block_transitions = InBlockTransitions::new(header, states, schedule); // TODO (breathx): handle resulting addresses that were changed (e.g. top up balance wont be dumped as outcome). for event in events { @@ -148,10 +149,11 @@ impl OverlaidProcessor { ) -> Result { self.0.creator.set_chain_head(block_hash); - let header = - self.0.db.block_header(block_hash).ok_or_else(|| { - anyhow::anyhow!("failed to find block header for given block hash") - })?; + let header = self + .0 + .db + .block_header(block_hash) + .ok_or_else(|| anyhow!("failed to find block header for given block hash"))?; let states = self .0 @@ -159,17 +161,17 @@ impl OverlaidProcessor { .block_start_program_states(block_hash) .unwrap_or_default(); - let mut in_block_transitions = - InBlockTransitions::new(header.height, states, Default::default()); + let mut in_block_transitions = InBlockTransitions::new(header, states, Default::default()); let state_hash = in_block_transitions .state_of(&program_id) - .ok_or_else(|| anyhow::anyhow!("unknown program at specified block hash"))?; + .ok_or_else(|| anyhow!("unknown program at specified block hash"))?; - let state = - self.0.db.read_state(state_hash).ok_or_else(|| { - anyhow::anyhow!("unreachable: state partially presents in storage") - })?; + let state = self + .0 + .db + .read_state(state_hash) + .ok_or_else(|| anyhow!("unreachable: state partially presents in storage"))?; anyhow::ensure!( !state.requires_init_message(), @@ -206,7 +208,7 @@ impl OverlaidProcessor { }) }) }) - .ok_or_else(|| anyhow::anyhow!("reply wasn't found"))?; + .ok_or_else(|| anyhow!("reply wasn't found"))?; Ok(res) } diff --git a/ethexe/processor/src/tests.rs b/ethexe/processor/src/tests.rs index 7a5a4f55d63..b2afb513d00 100644 --- a/ethexe/processor/src/tests.rs +++ b/ethexe/processor/src/tests.rs @@ -28,7 +28,7 @@ use gear_core::{ }; use gprimitives::{ActorId, MessageId}; use parity_scale_codec::Encode; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use utils::*; use wabt::wat2wasm; @@ -284,7 +284,8 @@ fn ping_pong() { .expect("failed to populate message queue"); let states = BTreeMap::from_iter([(program_id, state_hash)]); - let mut in_block_transitions = InBlockTransitions::new(0, states, Default::default()); + let mut in_block_transitions = + InBlockTransitions::new(BlockHeader::dummy(0), states, Default::default()); run::run( 8, @@ -418,7 +419,8 @@ fn async_and_ping() { .expect("failed to populate message queue"); let states = BTreeMap::from_iter([(ping_id, ping_state_hash), (async_id, async_state_hash)]); - let mut in_block_transitions = InBlockTransitions::new(0, states, Default::default()); + let mut in_block_transitions = + InBlockTransitions::new(BlockHeader::dummy(0), states, Default::default()); run::run( 8, @@ -512,7 +514,8 @@ fn many_waits() { states.insert(program_id, state_hash); } - let mut in_block_transitions = InBlockTransitions::new(1, states, Default::default()); + let mut in_block_transitions = + InBlockTransitions::new(BlockHeader::dummy(1), states, Default::default()); processor.run_schedule(&mut in_block_transitions); run::run( @@ -573,7 +576,7 @@ fn many_waits() { // Reproducibility test. { - let mut expected_schedule = BTreeMap::<_, Vec<_>>::new(); + let mut expected_schedule = BTreeMap::<_, BTreeSet<_>>::new(); for (pid, state_hash) in &states { let state = processor.db.read_state(*state_hash).unwrap(); @@ -585,7 +588,7 @@ fn many_waits() { expected_schedule .entry(expiry) .or_default() - .push(ScheduledTask::WakeMessage(*pid, mid)); + .insert(ScheduledTask::WakeMessage(*pid, mid)); } } @@ -593,7 +596,8 @@ fn many_waits() { assert_eq!(schedule, expected_schedule); } - let mut in_block_transitions = InBlockTransitions::new(11, states, schedule); + let mut in_block_transitions = + InBlockTransitions::new(BlockHeader::dummy(11), states, schedule); processor.run_schedule(&mut in_block_transitions); run::run( diff --git a/ethexe/rpc/src/lib.rs b/ethexe/rpc/src/lib.rs index ea91cdd8955..adf20feee6d 100644 --- a/ethexe/rpc/src/lib.rs +++ b/ethexe/rpc/src/lib.rs @@ -1,3 +1,22 @@ +// This file is part of Gear. +// +// Copyright (C) 2024 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use anyhow::anyhow; use ethexe_db::{BlockHeader, BlockMetaStorage, Database}; use ethexe_processor::Processor; use futures::FutureExt; @@ -186,18 +205,12 @@ impl RpcService { async move { log::info!("WebSocket connection accepted"); - svc.call(req) - .await - .map_err(|e| anyhow::anyhow!("Error: {:?}", e)) + svc.call(req).await.map_err(|e| anyhow!("Error: {:?}", e)) } .boxed() } else { - async move { - svc.call(req) - .await - .map_err(|e| anyhow::anyhow!("Error: {:?}", e)) - } - .boxed() + async move { svc.call(req).await.map_err(|e| anyhow!("Error: {:?}", e)) } + .boxed() } }); diff --git a/ethexe/runtime/common/src/journal.rs b/ethexe/runtime/common/src/journal.rs index 22d6be199cb..253ba7604e9 100644 --- a/ethexe/runtime/common/src/journal.rs +++ b/ethexe/runtime/common/src/journal.rs @@ -1,5 +1,3 @@ -use core::num::NonZeroU32; - use crate::{ state::{ self, ActiveProgram, ComplexStorage, Dispatch, HashAndLen, MaybeHash, Program, @@ -9,6 +7,7 @@ use crate::{ }; use alloc::{collections::BTreeMap, vec, vec::Vec}; use anyhow::Result; +use core::num::NonZero; use core_processor::{ common::{DispatchOutcome, JournalHandler}, configs::BlockInfo, @@ -32,7 +31,6 @@ pub struct Handler<'a, S: Storage> { pub program_id: ProgramId, pub in_block_transitions: &'a mut InBlockTransitions, pub storage: &'a S, - pub block_info: BlockInfo, } impl Handler<'_, S> { @@ -175,13 +173,21 @@ impl JournalHandler for Handler<'_, S> { .is_none() { if !dispatch.is_reply() { + let expiry = self.in_block_transitions.schedule_task( + state::MAILBOX_VALIDITY.try_into().expect("infallible"), + ScheduledTask::RemoveFromMailbox( + (dispatch.source(), dispatch.destination()), + dispatch.id(), + ), + ); + self.update_state_with_storage(dispatch.source(), |storage, state| { state.mailbox_hash = storage.modify_mailbox(state.mailbox_hash.clone(), |mailbox| { mailbox .entry(dispatch.destination()) .or_default() - .insert(dispatch.id(), dispatch.value()); + .insert(dispatch.id(), (dispatch.value(), expiry)); })?; Ok(()) @@ -241,7 +247,8 @@ impl JournalHandler for Handler<'_, S> { todo!("Wait dispatch without specified duration"); }; - let in_blocks = NonZeroU32::try_from(duration).expect("must be checked on backend side"); + let in_blocks = + NonZero::::try_from(duration).expect("must be checked on backend side"); let expiry = self.in_block_transitions.schedule_task( in_blocks, @@ -286,8 +293,10 @@ impl JournalHandler for Handler<'_, S> { log::trace!("Dispatch {message_id} tries to wake {awakening_id}"); + let mut expiry_if_found = None; + self.update_state_with_storage(program_id, |storage, state| { - let Some(((dispatch, _expiry), new_waitlist_hash)) = storage + let Some(((dispatch, expiry), new_waitlist_hash)) = storage .modify_waitlist_if_changed(state.waitlist_hash.clone(), |waitlist| { waitlist.remove(&awakening_id) })? @@ -295,6 +304,8 @@ impl JournalHandler for Handler<'_, S> { return Ok(()); }; + expiry_if_found = Some(expiry); + state.waitlist_hash = new_waitlist_hash; state.queue_hash = storage.modify_queue(state.queue_hash.clone(), |queue| { queue.push_back(dispatch); @@ -302,6 +313,15 @@ impl JournalHandler for Handler<'_, S> { Ok(()) }); + + if let Some(expiry) = expiry_if_found { + self.in_block_transitions + .remove_task( + expiry, + &ScheduledTask::WakeMessage(program_id, awakening_id), + ) + .expect("failed to remove scheduled task"); + } } fn update_pages_data( diff --git a/ethexe/runtime/common/src/schedule.rs b/ethexe/runtime/common/src/schedule.rs index c6d5da525c8..1928ef12048 100644 --- a/ethexe/runtime/common/src/schedule.rs +++ b/ethexe/runtime/common/src/schedule.rs @@ -29,8 +29,12 @@ impl Handler<'_, S> { } } -impl<'a, S: Storage> TaskHandler for Handler<'a, S> { - fn remove_from_mailbox(&mut self, _user_id: ActorId, _message_id: MessageId) -> u64 { +impl<'a, S: Storage> TaskHandler<(ProgramId, ActorId)> for Handler<'a, S> { + fn remove_from_mailbox( + &mut self, + (_program_id, _user_id): (ProgramId, ActorId), + _message_id: MessageId, + ) -> u64 { unimplemented!("TODO (breathx)") } fn send_dispatch(&mut self, _stashed_message_id: MessageId) -> u64 { diff --git a/ethexe/runtime/common/src/state.rs b/ethexe/runtime/common/src/state.rs index fb27f7a2241..a48b0db6fc1 100644 --- a/ethexe/runtime/common/src/state.rs +++ b/ethexe/runtime/common/src/state.rs @@ -22,8 +22,8 @@ use alloc::{ collections::{BTreeMap, VecDeque}, vec::Vec, }; -use anyhow::Result; -use core::num::NonZeroU32; +use anyhow::{anyhow, Result}; +use core::num::NonZero; use gear_core::{ code::InstrumentedCode, ids::{prelude::MessageIdExt as _, ProgramId}, @@ -43,10 +43,13 @@ use parity_scale_codec::{Decode, Encode}; pub use gear_core::program::ProgramState as InitStatus; +/// 3h validity in mailbox for 12s blocks. +pub const MAILBOX_VALIDITY: u32 = 54_000; + #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)] pub struct HashAndLen { pub hash: H256, - pub len: NonZeroU32, + pub len: NonZero, } // TODO: temporary solution to avoid lengths taking in account @@ -54,7 +57,7 @@ impl From for HashAndLen { fn from(value: H256) -> Self { Self { hash: value, - len: NonZeroU32::new(1).expect("impossible"), + len: NonZero::::new(1).expect("impossible"), } } } @@ -249,7 +252,7 @@ pub type MessageQueue = VecDeque; pub type Waitlist = BTreeMap>; // TODO (breathx): consider here LocalMailbox for each user. -pub type Mailbox = BTreeMap>; +pub type Mailbox = BTreeMap>>; pub type MemoryPages = BTreeMap; @@ -307,8 +310,8 @@ pub trait Storage { pub trait ComplexStorage: Storage { fn store_payload(&self, payload: Vec) -> Result { - let payload = Payload::try_from(payload) - .map_err(|_| anyhow::anyhow!("failed to save payload: too large"))?; + let payload = + Payload::try_from(payload).map_err(|_| anyhow!("failed to save payload: too large"))?; Ok(payload .inner() @@ -331,7 +334,7 @@ pub trait ComplexStorage: Storage { ) -> Result { let mut pages = pages_hash.with_hash_or_default_result(|pages_hash| { self.read_pages(pages_hash) - .ok_or_else(|| anyhow::anyhow!("failed to read pages by their hash ({pages_hash})")) + .ok_or_else(|| anyhow!("failed to read pages by their hash ({pages_hash})")) })?; f(&mut pages); @@ -351,7 +354,7 @@ pub trait ComplexStorage: Storage { ) -> Result { let mut allocations = allocations_hash.with_hash_or_default_result(|allocations_hash| { self.read_allocations(allocations_hash).ok_or_else(|| { - anyhow::anyhow!("failed to read allocations by their hash ({allocations_hash})") + anyhow!("failed to read allocations by their hash ({allocations_hash})") }) })?; @@ -388,9 +391,8 @@ pub trait ComplexStorage: Storage { f: impl FnOnce(&mut Waitlist) -> Option, ) -> Result> { let mut waitlist = waitlist_hash.with_hash_or_default_result(|waitlist_hash| { - self.read_waitlist(waitlist_hash).ok_or_else(|| { - anyhow::anyhow!("failed to read waitlist by its hash ({waitlist_hash})") - }) + self.read_waitlist(waitlist_hash) + .ok_or_else(|| anyhow!("failed to read waitlist by its hash ({waitlist_hash})")) })?; let res = if let Some(v) = f(&mut waitlist) { @@ -423,7 +425,7 @@ pub trait ComplexStorage: Storage { ) -> Result<(T, MaybeHash)> { let mut queue = queue_hash.with_hash_or_default_result(|queue_hash| { self.read_queue(queue_hash) - .ok_or_else(|| anyhow::anyhow!("failed to read queue by its hash ({queue_hash})")) + .ok_or_else(|| anyhow!("failed to read queue by its hash ({queue_hash})")) })?; let res = f(&mut queue); @@ -458,9 +460,8 @@ pub trait ComplexStorage: Storage { f: impl FnOnce(&mut Mailbox) -> Option, ) -> Result> { let mut mailbox = mailbox_hash.with_hash_or_default_result(|mailbox_hash| { - self.read_mailbox(mailbox_hash).ok_or_else(|| { - anyhow::anyhow!("failed to read mailbox by its hash ({mailbox_hash})") - }) + self.read_mailbox(mailbox_hash) + .ok_or_else(|| anyhow!("failed to read mailbox by its hash ({mailbox_hash})")) })?; let res = if let Some(v) = f(&mut mailbox) { @@ -494,7 +495,7 @@ pub trait ComplexStorage: Storage { ) -> Result<(T, H256)> { let mut state = self .read_state(state_hash) - .ok_or_else(|| anyhow::anyhow!("failed to read state by its hash ({state_hash})"))?; + .ok_or_else(|| anyhow!("failed to read state by its hash ({state_hash})"))?; let res = f(self, &mut state)?; diff --git a/ethexe/runtime/common/src/transitions.rs b/ethexe/runtime/common/src/transitions.rs index eae51f1261a..d3d880d72ef 100644 --- a/ethexe/runtime/common/src/transitions.rs +++ b/ethexe/runtime/common/src/transitions.rs @@ -16,14 +16,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use core::num::NonZeroU32; - use alloc::{ - collections::{btree_map::Iter, BTreeMap}, + collections::{btree_map::Iter, BTreeMap, BTreeSet}, vec::Vec, }; +use anyhow::{anyhow, Result}; +use core::num::NonZero; use ethexe_common::{ - db::{Schedule, ScheduledTask}, + db::{BlockHeader, Schedule, ScheduledTask}, router::{OutgoingMessage, StateTransition, ValueClaim}, }; use gprimitives::{ActorId, CodeId, H256}; @@ -31,24 +31,24 @@ use parity_scale_codec::{Decode, Encode}; #[derive(Default)] pub struct InBlockTransitions { - current_bn: u32, + header: BlockHeader, states: BTreeMap, schedule: Schedule, modifications: BTreeMap, } impl InBlockTransitions { - pub fn new(current_bn: u32, states: BTreeMap, schedule: Schedule) -> Self { + pub fn new(header: BlockHeader, states: BTreeMap, schedule: Schedule) -> Self { Self { - current_bn, + header, states, schedule, ..Default::default() } } - pub fn block_number(&self) -> u32 { - self.current_bn + pub fn header(&self) -> &BlockHeader { + &self.header } pub fn state_of(&self, actor_id: &ActorId) -> Option { @@ -70,20 +70,39 @@ impl InBlockTransitions { .collect() } - pub fn take_actual_tasks(&mut self) -> Vec { - self.schedule.remove(&self.current_bn).unwrap_or_default() + pub fn take_actual_tasks(&mut self) -> BTreeSet { + self.schedule + .remove(&self.header.height) + .unwrap_or_default() } - pub fn schedule_task(&mut self, in_blocks: NonZeroU32, task: ScheduledTask) -> u32 { - let scheduled_block = self.current_bn + u32::from(in_blocks); + pub fn schedule_task(&mut self, in_blocks: NonZero, task: ScheduledTask) -> u32 { + let scheduled_block = self.header.height + u32::from(in_blocks); + + self.schedule + .entry(scheduled_block) + .or_default() + .insert(task); - let entry = self.schedule.entry(scheduled_block).or_default(); + scheduled_block + } - if !entry.contains(&task) { - entry.push(task); + pub fn remove_task(&mut self, expiry: u32, task: &ScheduledTask) -> Result<()> { + let block_tasks = self + .schedule + .get_mut(&expiry) + .ok_or_else(|| anyhow!("No tasks found scheduled for a given block"))?; + + block_tasks + .remove(task) + .then_some(()) + .ok_or_else(|| anyhow!("Requested task wasn't found scheduled for a given block"))?; + + if block_tasks.is_empty() { + self.schedule.remove(&expiry); } - scheduled_block + Ok(()) } pub fn register_new(&mut self, actor_id: ActorId) { diff --git a/ethexe/sequencer/src/lib.rs b/ethexe/sequencer/src/lib.rs index 56b388a9749..bc48fdb32e4 100644 --- a/ethexe/sequencer/src/lib.rs +++ b/ethexe/sequencer/src/lib.rs @@ -106,7 +106,7 @@ impl Sequencer { // This function should never block. pub fn process_observer_event(&mut self, event: &RequestEvent) -> Result<()> { - if let RequestEvent::Block(RequestBlockData { block_hash, .. }) = event { + if let RequestEvent::Block(RequestBlockData { hash, .. }) = event { // Reset status, candidates and chain-head each block event self.update_status(|status| { @@ -115,7 +115,7 @@ impl Sequencer { self.codes_candidate = None; self.blocks_candidate = None; - self.chain_head = Some(*block_hash); + self.chain_head = Some(*hash); } Ok(()) diff --git a/gcli/src/cmd/program.rs b/gcli/src/cmd/program.rs index 10f20b343ef..d51e97019e1 100644 --- a/gcli/src/cmd/program.rs +++ b/gcli/src/cmd/program.rs @@ -17,7 +17,9 @@ // along with this program. If not, see . //! Command `program`. +//! use crate::{meta::Meta, result::Result, App}; +use anyhow::anyhow; use clap::Parser; use gclient::{ext::sp_core::H256, GearApi}; use std::{fs, path::PathBuf}; @@ -143,7 +145,7 @@ impl Program { fn resolve_meta(path: &PathBuf) -> Result { let ext = path .extension() - .ok_or_else(|| anyhow::anyhow!("Invalid file extension"))?; + .ok_or_else(|| anyhow!("Invalid file extension"))?; let data = fs::read(path)?; // parse from hex if end with `txt`. @@ -153,7 +155,7 @@ impl Program { // parse from wasm if end with `wasm`. Meta::decode_wasm(&data)? } else { - return Err(anyhow::anyhow!(format!("Unsupported file extension {:?}", ext)).into()); + return Err(anyhow!(format!("Unsupported file extension {:?}", ext)).into()); }; Ok(meta) diff --git a/gprimitives/src/nonzero_u256.rs b/gprimitives/src/nonzero_u256.rs index 81627009570..3c19d9f6bbe 100644 --- a/gprimitives/src/nonzero_u256.rs +++ b/gprimitives/src/nonzero_u256.rs @@ -24,7 +24,7 @@ use core::{ fmt, hash::{Hash, Hasher}, mem::transmute, - num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8}, + num::NonZero, }; #[cfg(feature = "codec")] use scale_info::{ @@ -364,11 +364,11 @@ macro_rules! impl_map_from { }; } -impl_map_from!(NonZeroU8); -impl_map_from!(NonZeroU16); -impl_map_from!(NonZeroU32); -impl_map_from!(NonZeroU64); -impl_map_from!(NonZeroU128); +impl_map_from!(NonZero); +impl_map_from!(NonZero); +impl_map_from!(NonZero); +impl_map_from!(NonZero); +impl_map_from!(NonZero); macro_rules! impl_try_from { ($from:ty) => { @@ -571,7 +571,7 @@ mod tests { #[test] fn nonzero_u256_from_nz64() { - let nzu64 = NonZeroU64::new(42u64).unwrap(); + let nzu64 = NonZero::::new(42u64).unwrap(); let nz: NonZeroU256 = nzu64.into(); assert_eq!(U256::from(nzu64.get()), nz.get()); } @@ -601,7 +601,7 @@ mod tests { #[test] fn nonzero_u256_overflowing_mul() { - let mut nzu256 = NonZeroU256::from(NonZeroU128::MAX); + let mut nzu256 = NonZeroU256::from(NonZero::::MAX); nzu256 += 1; let result = nzu256.overflowing_mul(nzu256); assert_eq!((NonZeroU256::MAX, true), result); @@ -609,7 +609,7 @@ mod tests { #[test] fn nonzero_u256_overflowing_pow() { - let mut nzu256 = NonZeroU256::from(NonZeroU128::MAX); + let mut nzu256 = NonZeroU256::from(NonZero::::MAX); nzu256 += 1; let result: (NonZeroU256, bool) = nzu256.overflowing_pow(2.into()); assert_eq!((NonZeroU256::MAX, true), result); diff --git a/lazy-pages/src/common.rs b/lazy-pages/src/common.rs index bc31cd557cc..71778ebb0fd 100644 --- a/lazy-pages/src/common.rs +++ b/lazy-pages/src/common.rs @@ -26,7 +26,7 @@ use crate::{ use gear_core::str::LimitedStr; use gear_lazy_pages_common::{GlobalsAccessError, Status}; use numerated::tree::IntervalsTree; -use std::{fmt, num::NonZeroU32}; +use std::{fmt, num::NonZero}; // TODO: investigate error allocations #2441 #[derive(Debug, derive_more::Display, derive_more::From)] @@ -127,7 +127,7 @@ impl LazyPagesContext { pub(crate) type Costs = [u64; CostNo::Amount as usize]; pub(crate) type GlobalNames = Vec>; -pub(crate) type PageSizes = [NonZeroU32; SIZES_AMOUNT]; +pub(crate) type PageSizes = [NonZero; SIZES_AMOUNT]; #[derive(Debug)] pub(crate) struct LazyPagesRuntimeContext { @@ -214,7 +214,7 @@ pub enum LazyPagesVersion { } impl SizeManager for LazyPagesRuntimeContext { - fn size_non_zero(&self) -> NonZeroU32 { + fn size_non_zero(&self) -> NonZero { self.page_sizes[S::SIZE_NO] } } diff --git a/lazy-pages/src/lib.rs b/lazy-pages/src/lib.rs index 2731a7eabc2..1bef69b7db9 100644 --- a/lazy-pages/src/lib.rs +++ b/lazy-pages/src/lib.rs @@ -62,7 +62,7 @@ use numerated::iterators::IntervalIterator; use pages::GearPage; use signal::DefaultUserSignalHandler; pub use signal::{ExceptionInfo, UserSignalHandler}; -use std::{cell::RefCell, convert::TryInto, num::NonZeroU32}; +use std::{cell::RefCell, convert::TryInto, num::NonZero}; /// Initialize lazy-pages once for process. static LAZY_PAGES_INITIALIZED: InitializationFlag = InitializationFlag::new(); @@ -400,7 +400,7 @@ pub fn init_with_handler( // Check that sizes are not zero let page_sizes = page_sizes .into_iter() - .map(TryInto::::try_into) + .map(TryInto::>::try_into) .collect::, _>>() .map_err(|_| ZeroPageSize)?; diff --git a/lazy-pages/src/pages.rs b/lazy-pages/src/pages.rs index 9d374ccbf9c..bd365156277 100644 --- a/lazy-pages/src/pages.rs +++ b/lazy-pages/src/pages.rs @@ -19,7 +19,7 @@ //! Module for pages which size can be different for different runtime versions. use numerated::{interval::Interval, iterators::IntervalIterator, Bound, Numerated, OptionBound}; -use std::{cmp::Ordering, marker::PhantomData, num::NonZeroU32}; +use std::{cmp::Ordering, marker::PhantomData, num::NonZero}; /// Size number for dyn-size pages. pub trait SizeNumber: Copy + Ord + Eq { @@ -56,13 +56,13 @@ impl SizeNumber for GearSizeNo { /// Context where dynamic size pages store their sizes pub trait SizeManager { /// Returns non-zero size of page. - fn size_non_zero(&self) -> NonZeroU32; + fn size_non_zero(&self) -> NonZero; } #[cfg(test)] impl SizeManager for u32 { - fn size_non_zero(&self) -> NonZeroU32 { - NonZeroU32::new(*self).expect("Size cannot be zero") + fn size_non_zero(&self) -> NonZero { + NonZero::::new(*self).expect("Size cannot be zero") } } @@ -250,8 +250,8 @@ pub(crate) mod tests { pub struct PageSizeManager(pub [u32; 2]); impl SizeManager for PageSizeManager { - fn size_non_zero(&self) -> NonZeroU32 { - NonZeroU32::new(self.0[S::SIZE_NO]).expect("Size cannot be zero") + fn size_non_zero(&self) -> NonZero { + NonZero::::new(self.0[S::SIZE_NO]).expect("Size cannot be zero") } } diff --git a/pallets/gear/src/benchmarking/mod.rs b/pallets/gear/src/benchmarking/mod.rs index 9767b778af9..f565967b93b 100644 --- a/pallets/gear/src/benchmarking/mod.rs +++ b/pallets/gear/src/benchmarking/mod.rs @@ -108,7 +108,7 @@ use sp_runtime::{ traits::{Bounded, CheckedAdd, One, UniqueSaturatedInto, Zero}, Digest, DigestItem, Perbill, Saturating, }; -use sp_std::{num::NonZeroU32, prelude::*}; +use sp_std::{num::NonZero, prelude::*}; const MAX_PAYLOAD_LEN: u32 = 32 * 64 * 1024; const MAX_PAYLOAD_LEN_KB: u32 = MAX_PAYLOAD_LEN / 1024; @@ -626,7 +626,7 @@ benchmarks! { let program_id = inheritor; init_block::(None); - }: _(RawOrigin::Signed(caller.clone()), program_id, NonZeroU32::MAX) + }: _(RawOrigin::Signed(caller.clone()), program_id, NonZero::::MAX) verify { assert_eq!( CurrencyOf::::free_balance(&caller), diff --git a/pallets/gear/src/internal.rs b/pallets/gear/src/internal.rs index 5307a2d3d24..ffbce2eb9c9 100644 --- a/pallets/gear/src/internal.rs +++ b/pallets/gear/src/internal.rs @@ -36,7 +36,7 @@ use common::{ }; use core::{ cmp::{Ord, Ordering}, - num::NonZeroUsize, + num::NonZero, }; use frame_system::pallet_prelude::BlockNumberFor; use gear_core::{ @@ -1283,7 +1283,7 @@ where pub(crate) fn inheritor_for( program_id: ProgramId, - max_depth: NonZeroUsize, + max_depth: NonZero, ) -> Result<(ProgramId, BTreeSet), InheritorForError> { let max_depth = max_depth.get(); diff --git a/pallets/gear/src/lib.rs b/pallets/gear/src/lib.rs index 5568a95a5df..c573ce5623e 100644 --- a/pallets/gear/src/lib.rs +++ b/pallets/gear/src/lib.rs @@ -63,7 +63,7 @@ use common::{ self, event::*, gas_provider::GasNodeId, scheduler::*, storage::*, BlockLimiter, CodeMetadata, CodeStorage, GasProvider, GasTree, Origin, Program, ProgramStorage, QueueRunner, }; -use core::{marker::PhantomData, num::NonZeroU32}; +use core::{marker::PhantomData, num::NonZero}; use core_processor::{ common::{DispatchOutcome as CoreDispatchOutcome, ExecutableActorData, JournalNote}, configs::{BlockConfig, BlockInfo}, @@ -1710,12 +1710,12 @@ pub mod pallet { pub fn claim_value_to_inheritor( origin: OriginFor, program_id: ProgramId, - depth: NonZeroU32, + depth: NonZero, ) -> DispatchResultWithPostInfo { ensure_signed(origin)?; let depth = depth.try_into().unwrap_or_else(|e| { - unreachable!("NonZeroU32 to NonZeroUsize conversion must be infallible: {e}") + unreachable!("NonZero to NonZero conversion must be infallible: {e}") }); let (destination, holders) = match Self::inheritor_for(program_id, depth) { Ok(res) => res, diff --git a/pallets/gear/src/tests.rs b/pallets/gear/src/tests.rs index 2c3248c8d4c..9d0f129d77b 100644 --- a/pallets/gear/src/tests.rs +++ b/pallets/gear/src/tests.rs @@ -78,10 +78,7 @@ use sp_runtime::{ SaturatedConversion, }; use sp_std::convert::TryFrom; -use std::{ - collections::BTreeSet, - num::{NonZeroU32, NonZeroUsize}, -}; +use std::{collections::BTreeSet, num::NonZero}; pub use utils::init_logger; use utils::*; @@ -6339,7 +6336,7 @@ fn exit_locking_funds() { assert_ok!(Gear::claim_value_to_inheritor( RuntimeOrigin::signed(USER_1), program_id, - NonZeroU32::MAX, + NonZero::::MAX, )); run_to_next_block(None); @@ -6653,7 +6650,7 @@ fn terminated_locking_funds() { assert_ok!(Gear::claim_value_to_inheritor( RuntimeOrigin::signed(USER_1), program_id, - NonZeroU32::MAX, + NonZero::::MAX, )); run_to_next_block(None); @@ -6685,7 +6682,11 @@ fn claim_value_to_inheritor() { // also, noop cases are in `*_locking_funds` tests assert_noop!( - Gear::claim_value_to_inheritor(RuntimeOrigin::signed(USER_1), pid1, NonZeroU32::MAX), + Gear::claim_value_to_inheritor( + RuntimeOrigin::signed(USER_1), + pid1, + NonZero::::MAX + ), Error::::ActiveProgram ); @@ -6786,7 +6787,7 @@ fn claim_value_to_inheritor() { assert_ok!(Gear::claim_value_to_inheritor( RuntimeOrigin::signed(USER_1), pid1, - NonZeroU32::MAX, + NonZero::::MAX, )); run_to_next_block(None); @@ -6849,13 +6850,13 @@ fn test_sequence_inheritor_of() { holders }; let inheritor_for = |id, max_depth| { - let max_depth = NonZeroUsize::new(max_depth).unwrap(); + let max_depth = NonZero::::new(max_depth).unwrap(); let (inheritor, holders) = Gear::inheritor_for(id, max_depth).unwrap(); let holders = convert_holders(holders); (inheritor, holders) }; - let res = Gear::inheritor_for(USER_1.into(), NonZeroUsize::MAX); + let res = Gear::inheritor_for(USER_1.into(), NonZero::::MAX); assert_eq!(res, Err(InheritorForError::NotFound)); let (inheritor, holders) = inheritor_for(programs[99], usize::MAX); @@ -6938,7 +6939,7 @@ fn test_cyclic_inheritor_of() { let cyclic_programs: BTreeSet = cyclic_programs.into_iter().collect(); - let res = Gear::inheritor_for(2000.into(), NonZeroUsize::MAX); + let res = Gear::inheritor_for(2000.into(), NonZero::::MAX); assert_eq!( res, Err(InheritorForError::Cyclic { @@ -6946,7 +6947,7 @@ fn test_cyclic_inheritor_of() { }) ); - let res = Gear::inheritor_for(2000.into(), NonZeroUsize::new(101).unwrap()); + let res = Gear::inheritor_for(2000.into(), NonZero::::new(101).unwrap()); assert_eq!( res, Err(InheritorForError::Cyclic { @@ -6955,11 +6956,11 @@ fn test_cyclic_inheritor_of() { ); let (inheritor, _holders) = - Gear::inheritor_for(2000.into(), NonZeroUsize::new(100).unwrap()).unwrap(); + Gear::inheritor_for(2000.into(), NonZero::::new(100).unwrap()).unwrap(); assert_eq!(inheritor, 2000.into()); let (inheritor, _holders) = - Gear::inheritor_for(2000.into(), NonZeroUsize::new(99).unwrap()).unwrap(); + Gear::inheritor_for(2000.into(), NonZero::::new(99).unwrap()).unwrap(); assert_eq!(inheritor, 2001.into()); }); } diff --git a/sandbox/host/src/sandbox/wasmer_backend/store_refcell.rs b/sandbox/host/src/sandbox/wasmer_backend/store_refcell.rs index 58f73a14552..548ec2de725 100644 --- a/sandbox/host/src/sandbox/wasmer_backend/store_refcell.rs +++ b/sandbox/host/src/sandbox/wasmer_backend/store_refcell.rs @@ -35,13 +35,13 @@ //! //! Now we need to borrow store mutably again inside `func`, //! but we can't do it because `mut_borrow` still exists. -//! +//! //! ```ignore //! fn func(ref_cell: &RefCell, mut_borrow: &mut Store) { //! ref_cell.borrow_mut(); // This will panic //! } //! ``` -//! +//! //! With `StoreRefCell` we can do it safely: //! //! ```ignore @@ -52,7 +52,7 @@ //! }); //! } //! ``` -//! +//! //! # Why is this necessary? Can't we do without repeated mutable borrowing? //! //! The issue arises because when handling syscalls within an instance of a program running in Wasmer, @@ -86,7 +86,7 @@ use std::{ cell::{Cell, UnsafeCell}, - num::NonZeroUsize, + num::NonZero, ops::{Deref, DerefMut}, ptr::NonNull, }; @@ -96,7 +96,7 @@ use wasmer::{AsStoreMut, AsStoreRef, Store, StoreRef}; #[derive(Debug, Clone, Copy)] enum BorrowState { - Shared(NonZeroUsize), + Shared(NonZero), Mutable, NonShared, } @@ -127,12 +127,13 @@ impl StoreRefCell { match self.state.get() { BorrowState::Shared(n) => { self.state.set(BorrowState::Shared( - NonZeroUsize::new(n.get() + 1).expect("non zero"), + NonZero::::new(n.get() + 1).expect("non zero"), )); } BorrowState::NonShared => { - self.state - .set(BorrowState::Shared(NonZeroUsize::new(1).expect("non zero"))); + self.state.set(BorrowState::Shared( + NonZero::::new(1).expect("non zero"), + )); } BorrowState::Mutable => { panic!("store already borrowed mutably"); @@ -235,7 +236,7 @@ impl Drop for Ref<'_> { } BorrowState::Shared(n) => { self.state.set(BorrowState::Shared( - NonZeroUsize::new(n.get() - 1).expect("non zero"), + NonZero::::new(n.get() - 1).expect("non zero"), )); } _ => unreachable!(), diff --git a/utils/calc-stack-height/src/main.rs b/utils/calc-stack-height/src/main.rs index ae626187f52..e8e00678703 100644 --- a/utils/calc-stack-height/src/main.rs +++ b/utils/calc-stack-height/src/main.rs @@ -1,3 +1,22 @@ +// This file is part of Gear. +// +// Copyright (C) 2024 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use anyhow::anyhow; use gear_core::code::{Code, TryNewCodeConfig}; use gear_wasm_instrument::{SystemBreakCode, STACK_HEIGHT_EXPORT_NAME}; use std::{env, fs}; @@ -24,7 +43,7 @@ fn main() -> anyhow::Result<()> { ..Default::default() }, ) - .map_err(|e| anyhow::anyhow!("{e}"))?; + .map_err(|e| anyhow!("{e}"))?; let compiler = Singlepass::default(); let mut store = Store::new(compiler); @@ -91,7 +110,7 @@ fn main() -> anyhow::Result<()> { schedule.limits.data_segments_amount.into(), schedule.limits.table_number.into(), ) - .map_err(|e| anyhow::anyhow!("{e}"))?; + .map_err(|e| anyhow!("{e}"))?; let module = Module::new(&store, code.code())?; let instance = Instance::new(&mut store, &module, &imports)?; diff --git a/utils/gring/src/keyring.rs b/utils/gring/src/keyring.rs index 7374fb11939..ab1caaa0fd9 100644 --- a/utils/gring/src/keyring.rs +++ b/utils/gring/src/keyring.rs @@ -19,7 +19,7 @@ //! Keyring implementation based on the polkadot-js keystore. use crate::{ss58, Keystore}; -use anyhow::Result; +use anyhow::{anyhow, Result}; use colored::Colorize; use schnorrkel::Keypair; use serde::{Deserialize, Serialize}; @@ -79,7 +79,7 @@ impl Keyring { #[allow(clippy::assigning_clones)] pub fn primary(&mut self) -> Result { if self.ring.is_empty() { - return Err(anyhow::anyhow!( + return Err(anyhow!( "No keys in keyring, run {} to create a new one.", "`gring generate -p `" .underline() @@ -110,7 +110,7 @@ impl Keyring { .find(|k| k.meta.name == name) .cloned() .ok_or_else(|| { - anyhow::anyhow!( + anyhow!( "Key with name {} not found, run {} to see all keys in keyring.", name.underline().bold(), "`gring list`".underline().cyan().bold() diff --git a/utils/gring/tests/command.rs b/utils/gring/tests/command.rs index 0ca422c56ea..12f2a85d518 100644 --- a/utils/gring/tests/command.rs +++ b/utils/gring/tests/command.rs @@ -35,7 +35,7 @@ fn bin() -> PathBuf { fn gring(bin: &PathBuf, args: &[&str]) -> Result { let output = process::Command::new(bin).args(args).output()?; if output.stdout.is_empty() { - return Err(anyhow::anyhow!( + return Err(anyhow!( "stderr: {}", String::from_utf8_lossy(&output.stderr) )); diff --git a/utils/lazy-pages-fuzzer/src/config.rs b/utils/lazy-pages-fuzzer/src/config.rs index 2eaf40fd02d..13a51d279e6 100644 --- a/utils/lazy-pages-fuzzer/src/config.rs +++ b/utils/lazy-pages-fuzzer/src/config.rs @@ -16,8 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::num::{NonZeroU32, NonZeroUsize}; - use gear_wasm_gen::{ ConfigsBundle, GearWasmGeneratorConfig, InstructionKind, MemoryPagesConfig, SelectableParams, SyscallsConfigBuilder, SyscallsInjectionTypes, @@ -25,6 +23,7 @@ use gear_wasm_gen::{ use gear_wasm_instrument::{ gas_metering::MemoryGrowCost, parity_wasm::elements::Instruction, Rules, }; +use std::num::NonZero; use crate::{ generate::{InjectGlobalsConfig, InjectMemoryAccessesConfig}, @@ -57,8 +56,8 @@ impl ConfigsBundle for FuzzerConfigBundle { Numeric, Reference, Parametric, Variable, Table, Memory, Control, ], max_instructions: 500, - min_funcs: NonZeroUsize::new(3).expect("non zero value"), - max_funcs: NonZeroUsize::new(5).expect("non zero value"), + min_funcs: NonZero::::new(3).expect("non zero value"), + max_funcs: NonZero::::new(5).expect("non zero value"), }, ) } @@ -76,7 +75,7 @@ impl Rules for DummyCostRules { fn memory_grow_cost(&self) -> MemoryGrowCost { const DUMMY_MEMORY_GROW_COST: u32 = 1242; - MemoryGrowCost::Linear(NonZeroU32::new(DUMMY_MEMORY_GROW_COST).unwrap()) + MemoryGrowCost::Linear(NonZero::::new(DUMMY_MEMORY_GROW_COST).unwrap()) } fn call_per_local_cost(&self) -> u32 { diff --git a/utils/node-loader/src/args.rs b/utils/node-loader/src/args.rs index 8da757448fe..13233a51079 100644 --- a/utils/node-loader/src/args.rs +++ b/utils/node-loader/src/args.rs @@ -1,6 +1,6 @@ //! CLI args for the `gear-node-loader` -use anyhow::Error; +use anyhow::{anyhow, Error}; use clap::Parser; use std::str::FromStr; @@ -74,7 +74,7 @@ impl FromStr for SeedVariant { let s = s.to_lowercase(); let input = s.split('=').collect::>(); if input.len() != 2 { - return Err(anyhow::anyhow!( + return Err(anyhow!( "Invalid seed argument format {s:?}. Must be 'seed_variant=num'" )); } @@ -84,7 +84,7 @@ impl FromStr for SeedVariant { match variant { "start" => Ok(SeedVariant::Dynamic(num)), "constant" => Ok(SeedVariant::Constant(num)), - v => Err(anyhow::anyhow!("Invalid variant {v}")), + v => Err(anyhow!("Invalid variant {v}")), } } } diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index ebec6755f0e..aecd3c7e0b4 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use crate::{code_validator::CodeValidator, crate_info::CrateInfo, smart_fs}; -use anyhow::{Context, Ok, Result}; +use anyhow::{anyhow, Context, Ok, Result}; use chrono::offset::Local as ChronoLocal; use gear_wasm_optimizer::{self as optimize, OptType, Optimizer}; use gmeta::MetadataRepr; @@ -459,7 +459,7 @@ extern "C" fn metahash() {{ .filter(|(target, _)| *target == PreProcessorTarget::Default) .count(); if default_targets > 1 { - return Err(anyhow::anyhow!("Pre-processor \"{pre_processor_name}\" cannot have more than one default target.")); + return Err(anyhow!("Pre-processor \"{pre_processor_name}\" cannot have more than one default target.")); } for (pre_processor_target, content) in pre_processor_output { @@ -533,7 +533,7 @@ extern "C" fn metahash() {{ let exports = module .export_section() - .ok_or_else(|| anyhow::anyhow!("Export section not found"))? + .ok_or_else(|| anyhow!("Export section not found"))? .entries() .iter() .flat_map(|entry| { diff --git a/utils/wasm-gen/src/config.rs b/utils/wasm-gen/src/config.rs index 88dddabdb17..33e3700e724 100644 --- a/utils/wasm-gen/src/config.rs +++ b/utils/wasm-gen/src/config.rs @@ -22,7 +22,7 @@ //! 1. From scratch by settings fields to corresponding values sometimes using //! related to these fields builders. For example, wasm module configs: //! ```rust -//! # use std::num::NonZeroUsize; +//! # use std::num::NonZero; //! use gear_wasm_gen::*; //! use arbitrary::{Arbitrary, Result, Unstructured}; //! @@ -38,8 +38,8 @@ //! InstructionKind::Control, //! ], //! max_instructions: 100_000, -//! min_funcs: NonZeroUsize::new(15).unwrap(), -//! max_funcs: NonZeroUsize::new(30).unwrap(), +//! min_funcs: NonZero::::new(15).unwrap(), +//! max_funcs: NonZero::::new(30).unwrap(), //! }; //! let arbitrary = ArbitraryParams::arbitrary(u)?; //! Ok((selectable_params, arbitrary).into()) @@ -93,20 +93,19 @@ //! There's a pre-defined one - [`StandardGearWasmConfigsBundle`], usage of which will result //! in generation of valid (always) gear-wasm module. -use std::num::{NonZeroU32, NonZeroUsize}; +use crate::InvocableSyscall; +use arbitrary::Unstructured; +use gear_wasm_instrument::SyscallName; +use std::num::NonZero; mod generator; mod module; mod syscalls; -use arbitrary::Unstructured; -use gear_wasm_instrument::SyscallName; pub use generator::*; pub use module::*; pub use syscalls::*; -use crate::InvocableSyscall; - /// Trait which describes a type that stores and manages data for generating /// [`GearWasmGeneratorConfig`] and [`SelectableParams`], which are both used /// by [`crate::generate_gear_program_code`] and [`crate::generate_gear_program_module`] @@ -141,7 +140,7 @@ pub struct StandardGearWasmConfigsBundle { /// /// For example, if this parameter is 4, wait syscalls will be invoked /// with probability 1/4. - pub waiting_probability: Option, + pub waiting_probability: Option>, /// Flag which signals whether recursions must be removed. pub remove_recursion: bool, /// If the limit is set to `Some(_)`, programs will try to stop execution @@ -167,7 +166,7 @@ impl Default for StandardGearWasmConfigsBundle { fn default() -> Self { Self { log_info: Some("StandardGearWasmConfigsBundle".into()), - waiting_probability: NonZeroU32::new(4), + waiting_probability: NonZero::::new(4), remove_recursion: false, critical_gas_limit: Some(1_000_000), injection_types: SyscallsInjectionTypes::all_once(), @@ -304,7 +303,7 @@ impl RandomizedGearWasmConfigBundle { log_info, params_config, initial_pages: initial_pages as u32, - waiting_probability: NonZeroU32::new(unstructured.int_in_range(1..=4).unwrap()), + waiting_probability: NonZero::::new(unstructured.int_in_range(1..=4).unwrap()), ..Default::default() }, max_funcs, @@ -338,8 +337,8 @@ impl ConfigsBundle for RandomizedGearWasmConfigBundle { let mut selectable_params = SelectableParams { max_instructions, - max_funcs: NonZeroUsize::new(max_funcs).unwrap(), - min_funcs: NonZeroUsize::new(min_funcs).unwrap(), + max_funcs: NonZero::::new(max_funcs).unwrap(), + min_funcs: NonZero::::new(min_funcs).unwrap(), ..Default::default() }; diff --git a/utils/wasm-gen/src/config/module.rs b/utils/wasm-gen/src/config/module.rs index 4c2856ed7d4..b0a523941b0 100644 --- a/utils/wasm-gen/src/config/module.rs +++ b/utils/wasm-gen/src/config/module.rs @@ -23,13 +23,13 @@ //! can be arbitrary, but some must be constantly set. That's implemented with [`ArbitraryParams`] //! and [`ConstantParams`]. -use std::num::NonZeroUsize; - use crate::MemoryLayout; use arbitrary::{Arbitrary, Result, Unstructured}; -pub use wasm_smith::InstructionKind; +use std::num::NonZero; use wasm_smith::{InstructionKind::*, InstructionKinds, SwarmConfig}; +pub use wasm_smith::InstructionKind; + /// Wasm module generation config. /// /// This config wraps the [`wasm_smith::SwarmConfig`]. That's to make it @@ -362,10 +362,10 @@ pub struct SelectableParams { pub max_instructions: usize, /// Minimum amount of functions `wasm-gen` will insert /// into generated wasm. - pub min_funcs: NonZeroUsize, + pub min_funcs: NonZero, /// Maximum amount of functions `wasm-gen` will insert /// into generated wasm. - pub max_funcs: NonZeroUsize, + pub max_funcs: NonZero, } impl Default for SelectableParams { @@ -375,8 +375,8 @@ impl Default for SelectableParams { Numeric, Reference, Parametric, Variable, Table, Memory, Control, ], max_instructions: 500, - min_funcs: NonZeroUsize::new(3).expect("from non zero value; qed."), - max_funcs: NonZeroUsize::new(5).expect("from non zero value; qed."), + min_funcs: NonZero::::new(3).expect("from non zero value; qed."), + max_funcs: NonZero::::new(5).expect("from non zero value; qed."), } } } diff --git a/utils/wasm-gen/src/config/syscalls.rs b/utils/wasm-gen/src/config/syscalls.rs index 40400242b7d..448f5d3fab1 100644 --- a/utils/wasm-gen/src/config/syscalls.rs +++ b/utils/wasm-gen/src/config/syscalls.rs @@ -19,21 +19,20 @@ //! Configuration for the syscalls imports generator, additional data injector //! and syscalls invocations generator. +use crate::InvocableSyscall; +use gear_wasm_instrument::syscalls::SyscallName; +use std::num::NonZero; + mod injection; mod param; mod precise; mod process_errors; -use gear_wasm_instrument::syscalls::SyscallName; -use std::num::NonZeroU32; - pub use injection::*; pub use param::*; pub use precise::*; pub use process_errors::*; -use crate::InvocableSyscall; - /// Builder for [`SyscallsConfig`]. #[derive(Debug, Clone)] pub struct SyscallsConfigBuilder(SyscallsConfig); @@ -97,7 +96,7 @@ impl SyscallsConfigBuilder { } /// Set probability of wait syscalls. - pub fn with_waiting_probability(mut self, waiting_probability: NonZeroU32) -> Self { + pub fn with_waiting_probability(mut self, waiting_probability: NonZero) -> Self { self.0.waiting_probability = Some(waiting_probability); self @@ -132,7 +131,7 @@ pub struct SyscallsConfig { precise_syscalls_config: PreciseSyscallsConfig, error_processing_config: ErrorProcessingConfig, log_info: Option, - waiting_probability: Option, + waiting_probability: Option>, keeping_insertion_order: bool, } @@ -170,7 +169,7 @@ impl SyscallsConfig { } /// Get probability of wait syscalls. - pub fn waiting_probability(&self) -> Option { + pub fn waiting_probability(&self) -> Option> { self.waiting_probability } diff --git a/utils/wasm-gen/src/generator.rs b/utils/wasm-gen/src/generator.rs index fa44ffbb14c..7a99945690f 100644 --- a/utils/wasm-gen/src/generator.rs +++ b/utils/wasm-gen/src/generator.rs @@ -267,7 +267,7 @@ impl CallIndexes { .iter() .filter_map(FunctionIndex::internal_func_idx) .max() - // Config min/max function params are `NonZeroUsize`. + // Config min/max function params are `NonZero`. .expect("at least 1 func is generated by config definition") as usize }; diff --git a/utils/wasm-gen/src/generator/syscalls/additional_data.rs b/utils/wasm-gen/src/generator/syscalls/additional_data.rs index c8e953e7827..3c34fbba9e4 100644 --- a/utils/wasm-gen/src/generator/syscalls/additional_data.rs +++ b/utils/wasm-gen/src/generator/syscalls/additional_data.rs @@ -41,7 +41,7 @@ use gear_wasm_instrument::{ parity_wasm::{builder, elements::Instruction}, syscalls::SyscallName, }; -use std::{collections::BTreeMap, num::NonZeroU32}; +use std::{collections::BTreeMap, num::NonZero}; /// Additional data injector. /// @@ -56,7 +56,7 @@ pub struct AdditionalDataInjector<'a, 'b> { config: SyscallsConfig, last_offset: u32, module: WasmModule, - syscalls_imports: BTreeMap, CallIndexesHandle)>, + syscalls_imports: BTreeMap>, CallIndexesHandle)>, } impl<'a, 'b> @@ -191,7 +191,7 @@ pub struct DisabledAdditionalDataInjector<'a, 'b> { pub(super) module: WasmModule, pub(super) call_indexes: CallIndexes, pub(super) syscalls_imports: - BTreeMap, CallIndexesHandle)>, + BTreeMap>, CallIndexesHandle)>, pub(super) config: SyscallsConfig, } diff --git a/utils/wasm-gen/src/generator/syscalls/imports.rs b/utils/wasm-gen/src/generator/syscalls/imports.rs index de993d975ff..66480cff8d2 100644 --- a/utils/wasm-gen/src/generator/syscalls/imports.rs +++ b/utils/wasm-gen/src/generator/syscalls/imports.rs @@ -35,7 +35,7 @@ use gear_wasm_instrument::{ syscalls::SyscallName, }; use gsys::{Handle, Hash, Length}; -use std::{collections::BTreeMap, num::NonZeroU32}; +use std::{collections::BTreeMap, num::NonZero}; /// Gear syscalls imports generator. pub struct SyscallsImportsGenerator<'a, 'b> { @@ -43,7 +43,7 @@ pub struct SyscallsImportsGenerator<'a, 'b> { call_indexes: CallIndexes, module: WasmModule, config: SyscallsConfig, - syscalls_imports: BTreeMap, CallIndexesHandle)>, + syscalls_imports: BTreeMap>, CallIndexesHandle)>, } /// Syscalls imports generator instantiator. @@ -199,7 +199,7 @@ impl<'a, 'b> SyscallsImportsGenerator<'a, 'b> { .injection_type(InvocableSyscall::Precise(precise_syscall)); if let SyscallInjectionType::Function(syscall_amount_range) = syscall_injection_type { let precise_syscall_amount = - NonZeroU32::new(self.unstructured.int_in_range(syscall_amount_range)?); + NonZero::::new(self.unstructured.int_in_range(syscall_amount_range)?); log::trace!( "Constructing `{name}` syscall...", name = InvocableSyscall::Precise(precise_syscall).to_str() @@ -237,14 +237,14 @@ impl<'a, 'b> SyscallsImportsGenerator<'a, 'b> { /// Generate import of the gear syscall defined by `syscall` param. /// /// Returns [`Option`] which wraps the tuple of maybe non-zero amount of syscall further injections - /// and handle in the call indexes collection. The amount type is `NonZeroU32` in order to distinguish + /// and handle in the call indexes collection. The amount type is `NonZero` in order to distinguish /// between syscalls imports that must be generated without further invocation and ones, /// that must be invoked along with the import generation. /// If no import is required, `None` is returned. fn generate_syscall_import( &mut self, syscall: SyscallName, - ) -> Result, CallIndexesHandle)>> { + ) -> Result>, CallIndexesHandle)>> { let syscall_injection_type = self.config.injection_type(InvocableSyscall::Loose(syscall)); let syscall_amount = match syscall_injection_type { @@ -264,7 +264,10 @@ impl<'a, 'b> SyscallsImportsGenerator<'a, 'b> { syscall_amount, ); - Ok(Some((NonZeroU32::new(syscall_amount), call_indexes_handle))) + Ok(Some(( + NonZero::::new(syscall_amount), + call_indexes_handle, + ))) } /// Inserts gear syscall defined by the `syscall` param. @@ -848,7 +851,7 @@ pub struct DisabledSyscallsImportsGenerator<'a, 'b> { pub(super) module: WasmModule, pub(super) config: SyscallsConfig, pub(super) syscalls_imports: - BTreeMap, CallIndexesHandle)>, + BTreeMap>, CallIndexesHandle)>, } impl<'a, 'b> From> for ModuleWithCallIndexes { diff --git a/utils/wasm-gen/src/generator/syscalls/invocator.rs b/utils/wasm-gen/src/generator/syscalls/invocator.rs index ffa781e23bd..29e77364a23 100644 --- a/utils/wasm-gen/src/generator/syscalls/invocator.rs +++ b/utils/wasm-gen/src/generator/syscalls/invocator.rs @@ -43,7 +43,7 @@ use std::{ collections::{btree_map::Entry, BTreeMap, BinaryHeap, HashSet}, fmt::{self, Debug, Display}, iter, - num::NonZeroU32, + num::NonZero, }; #[derive(Debug)] @@ -138,7 +138,7 @@ pub struct SyscallsInvocator<'a, 'b> { call_indexes: CallIndexes, module: WasmModule, config: SyscallsConfig, - syscalls_imports: BTreeMap, CallIndexesHandle)>, + syscalls_imports: BTreeMap>, CallIndexesHandle)>, } impl<'a, 'b> From> for SyscallsInvocator<'a, 'b> { diff --git a/utils/wasm-gen/src/tests.rs b/utils/wasm-gen/src/tests.rs index 46ad82d3af7..28c38c5083f 100644 --- a/utils/wasm-gen/src/tests.rs +++ b/utils/wasm-gen/src/tests.rs @@ -42,7 +42,7 @@ use gear_wasm_instrument::parity_wasm::{self, elements::Module}; use nonempty::nonempty; use proptest::prelude::*; use rand::{rngs::SmallRng, RngCore, SeedableRng}; -use std::num::{NonZeroU32, NonZeroUsize}; +use std::num::NonZero; const UNSTRUCTURED_SIZE: usize = 1_000_000; const WASM_PAGE_SIZE: u32 = 64 * 1024; @@ -229,7 +229,7 @@ fn test_avoid_waits_works() { let mut injection_types = SyscallsInjectionTypes::all_never(); injection_types.set(InvocableSyscall::Loose(SyscallName::Wait), 1, 1); let syscalls_config = SyscallsConfigBuilder::new(injection_types) - .with_waiting_probability(NonZeroU32::new(4).unwrap()) + .with_waiting_probability(NonZero::::new(4).unwrap()) .build(); let backend_report = execute_wasm_with_custom_configs( @@ -273,7 +273,7 @@ fn test_wait_stores_message_id() { let syscalls_config_with_waiting_probability = SyscallsConfigBuilder::new(injection_types.clone()) .with_params_config(params_config.clone()) - .with_waiting_probability(NonZeroU32::new(4).unwrap()) + .with_waiting_probability(NonZero::::new(4).unwrap()) .build(); let syscalls_config_wo_waiting_probability = SyscallsConfigBuilder::new(injection_types) @@ -1015,8 +1015,8 @@ fn execute_wasm_with_custom_configs( SelectableParams { allowed_instructions: vec![], max_instructions: 0, - min_funcs: NonZeroUsize::new(1).unwrap(), - max_funcs: NonZeroUsize::new(1).unwrap(), + min_funcs: NonZero::::new(1).unwrap(), + max_funcs: NonZero::::new(1).unwrap(), }, ); diff --git a/utils/wasm-optimizer/src/optimize.rs b/utils/wasm-optimizer/src/optimize.rs index aeef74992c3..942662c2535 100644 --- a/utils/wasm-optimizer/src/optimize.rs +++ b/utils/wasm-optimizer/src/optimize.rs @@ -109,7 +109,7 @@ impl Optimizer { } else { self.module .export_section() - .ok_or_else(|| anyhow::anyhow!("Export section not found"))? + .ok_or_else(|| anyhow!("Export section not found"))? .entries() .iter() .flat_map(|entry| { @@ -165,7 +165,7 @@ pub fn optimize_wasm>( let destination = destination.as_ref(); if !destination.exists() { - return Err(anyhow::anyhow!( + return Err(anyhow!( "Optimization failed, optimized wasm output file `{}` not found.", destination.display() )); @@ -196,7 +196,7 @@ pub fn do_optimization>( // check `wasm-opt` is installed let which = which::which("wasm-opt"); if which.is_err() { - return Err(anyhow::anyhow!( + return Err(anyhow!( "wasm-opt not found! Make sure the binary is in your PATH environment.\n\n\ We use this tool to optimize the size of your program's Wasm binary.\n\n\ wasm-opt is part of the binaryen package. You can find detailed\n\