diff --git a/pallets/rolldown/src/benchmarking.rs b/pallets/rolldown/src/benchmarking.rs index 57ff32682..672cd5d95 100644 --- a/pallets/rolldown/src/benchmarking.rs +++ b/pallets/rolldown/src/benchmarking.rs @@ -355,9 +355,17 @@ mod benchmarks { .build(); let update_hash = update.abi_encode_hash(); + let metadata = UpdateMetadata { + min_id: 0u128, + max_id: 0u128, + update_size: 0u128, + sequencer: SEQUENCER_ACCOUNT, + update_hash, + }; + >::set_block_number(1u32.into()); let dispute_period_end = >::block_number().saturated_into::() + - Rolldown::::get_dispute_period(); + Rolldown::::get_dispute_period(l1_chain).unwrap(); assert!( PendingSequencerUpdates::::get(dispute_period_end, l1_chain).is_none(), "BEFORE PendingSequencerUpdates {:?} dispute_period_end {:?} l1_chain should be uninit", @@ -408,7 +416,7 @@ mod benchmarks { >::set_block_number(1u32.into()); let dispute_period_end = >::block_number().saturated_into::() + - Rolldown::::get_dispute_period(); + Rolldown::::get_dispute_period(l1_chain).unwrap(); assert!( PendingSequencerUpdates::::get(dispute_period_end, l1_chain).is_none(), "BEFORE PendingSequencerUpdates {:?} dispute_period_end {:?} l1_chain should be uninit", @@ -468,6 +476,7 @@ mod benchmarks { Ok(()) } + //FIX: check and possibly allign this benchmark #[benchmark] fn cancel_requests_from_l1() -> Result<(), BenchmarkError> { setup_sequencer::(SEQUENCER_ACCOUNT.into(), None, true, false)?; @@ -476,16 +485,24 @@ mod benchmarks { get_chain_and_address_for_asset_id::(TOKEN_ID.into())?; let l1_chain: ::ChainId = l1_aset_chain.into(); + let requests = vec![L1UpdateRequest::Deposit(Default::default())]; let update = L1UpdateBuilder::default() .with_requests(vec![L1UpdateRequest::Deposit(Default::default())]) .build(); + let update_hash = H256::default(); let sequencer_account: T::AccountId = SEQUENCER_ACCOUNT.into(); - PendingSequencerUpdates::::insert( - DUMMY_REQUEST_ID, - l1_chain, - (sequencer_account, update, H256::default()), - ); + let metadata = UpdateMetadata { + min_id: 1u128, + max_id: 1u128, + update_size: 1u128, + sequencer: sequencer_account.clone(), + update_hash: H256::zero(), + }; + + PendingSequencerUpdates::::insert(DUMMY_REQUEST_ID, l1_chain, metadata); + + PendingSequencerUpdateContent::::insert(update_hash, update); assert!( L2Requests::::get(l1_chain, RequestId::from((Origin::L2, FIRST_REQUEST_ID))) @@ -510,6 +527,7 @@ mod benchmarks { Ok(()) } + //FIX: check and possibly allign this benchmark #[benchmark] fn force_cancel_requests_from_l1() -> Result<(), BenchmarkError> { setup_sequencer::(SEQUENCER_ACCOUNT.into(), None, true, true)?; @@ -517,12 +535,16 @@ mod benchmarks { get_chain_and_address_for_asset_id::(TOKEN_ID.into())?; let l1_chain: ::ChainId = l1_aset_chain.into(); + let metadata = UpdateMetadata:: { + min_id: 1u128, + max_id: 1u128, + update_size: 1u128, + sequencer: T::AddressConverter::convert(SEQUENCER_ACCOUNT), + update_hash: H256::zero(), + }; + let sequencer_account: T::AccountId = SEQUENCER_ACCOUNT.into(); - PendingSequencerUpdates::::insert( - DUMMY_REQUEST_ID, - l1_chain, - (sequencer_account, messages::L1Update::default(), H256::default()), - ); + PendingSequencerUpdates::::insert(DUMMY_REQUEST_ID, l1_chain, metadata); assert!( T::SequencerStakingProvider::is_selected_sequencer(l1_chain, &SEQUENCER_ACCOUNT.into()), @@ -885,51 +907,154 @@ mod benchmarks { } #[benchmark] - fn schedule_requests(x: Linear<2, 200>) -> Result<(), BenchmarkError> { + fn load_next_update_from_execution_queue() -> Result<(), BenchmarkError> { + let current_execution_id = 1u128; + let next_execution_id = 2u128; + let scheduled_at: BlockNumberFor = 19u32.into(); + let (l1_aset_chain, _) = get_chain_and_address_for_asset_id::(TOKEN_ID.into())?; + let l1_chain: ::ChainId = l1_aset_chain.into(); + + UpdatesExecutionQueue::::remove(current_execution_id); + UpdatesExecutionQueue::::insert( + next_execution_id, + (scheduled_at, l1_chain, H256::zero(), 10u128), + ); + UpdatesExecutionQueueNextId::::put(current_execution_id); + + #[block] + { + Rolldown::::load_next_update_from_execution_queue(); + } + + assert_eq!(UpdatesExecutionQueueNextId::::get(), next_execution_id); + + Ok(()) + } + + #[benchmark] + fn schedule_request_for_execution_if_dispute_period_has_passsed() -> Result<(), BenchmarkError> + { + setup_account::(USER_ACCOUNT.into())?; + setup_and_do_withdrawal::(USER_ACCOUNT.into())?; + + let block_for_automatic_batch = + (::MerkleRootAutomaticBatchSize::get() + 1u128).saturated_into::(); + let chain: ::ChainId = crate::messages::Chain::Ethereum.into(); + let update_hash = + H256::from(hex!("1111111111111111111111111111111111111111111111111111111111111111")); + + let sequencer_account: T::AccountId = SEQUENCER_ACCOUNT.into(); + let metadata = UpdateMetadata { + min_id: 1u128, + max_id: 1u128, + update_size: 1u128, + sequencer: sequencer_account.clone(), + update_hash, + }; + + PendingSequencerUpdates::::insert(1u128, chain, metadata); + assert_eq!(LastScheduledUpdateIdInExecutionQueue::::get(), 0u128); + assert_eq!(UpdatesExecutionQueue::::get(FIRST_SCHEDULED_UPDATE_ID), None); + + #[block] + { + Rolldown::::schedule_request_for_execution_if_dispute_period_has_passsed( + block_for_automatic_batch.into(), + ); + } + + assert_eq!(LastScheduledUpdateIdInExecutionQueue::::get(), 1u128); + assert_eq!( + UpdatesExecutionQueue::::get(FIRST_SCHEDULED_UPDATE_ID), + Some((block_for_automatic_batch.into(), chain, update_hash, 1u128)) + ); + + Ok(()) + } + + #[benchmark] + fn maybe_create_batch() -> Result<(), BenchmarkError> { + // trigger batch creating because of automatic batch size + setup_sequencer::(SEQUENCER_ACCOUNT.into(), None, true, true)?; + let (l1_aset_chain, l1_asset_address) = get_chain_and_address_for_asset_id::(TOKEN_ID.into())?; let l1_chain: ::ChainId = l1_aset_chain.into(); + let automatic_batch_size = Pallet::::automatic_batch_size(); - let x_deposits: usize = (x as usize) / 2; - let x_cancel_resolution: usize = (x as usize) - x_deposits; - let mut update = L1UpdateBuilder::default() - .with_requests( - [ - vec![L1UpdateRequest::Deposit(Default::default()); x_deposits], - vec![ - L1UpdateRequest::CancelResolution(Default::default()); - x_cancel_resolution - ], - ] - .concat(), - ) - .build(); + let last_batch_id = 1u128; + let latest_element_in_previous_batch = 123u128; + let last_batch_range = (1u128, latest_element_in_previous_batch); + let latest_element_now = latest_element_in_previous_batch + automatic_batch_size; - assert!( - MaxAcceptedRequestIdOnl2::::get(l1_chain).is_zero(), - "BEFORE MaxAcceptedRequestIdOnl2 {:?} chain should be zero", - l1_chain + assert!(T::SequencerStakingProvider::is_selected_sequencer( + l1_chain, + &SEQUENCER_ACCOUNT.into() + )); + + L2OriginRequestId::::mutate(|map| { + map.insert(l1_chain, latest_element_now.saturating_add(1u128)); + }); + + L2RequestsBatchLast::::mutate(|map| { + map.insert(l1_chain, (20u32.into(), 1u128, (1u128, latest_element_in_previous_batch))); + }); + + assert_eq!(L2RequestsBatch::::get((l1_chain, 2u128)), None); + + >::set_block_number(20u32.into()); + + #[block] + { + Rolldown::::maybe_create_batch(21u32.into()); + } + + assert_eq!( + L2RequestsBatch::::get((l1_chain, 2u128)), + Some(( + 21u32.into(), + (latest_element_in_previous_batch + 1, latest_element_now), + SEQUENCER_ACCOUNT.into() + )) ); - assert!( - UpdatesExecutionQueue::::get(FIRST_SCHEDULED_UPDATE_ID).is_none(), - "BEFORE UpdatesExecutionQueue {:?} scheduled update id should be none", - FIRST_SCHEDULED_UPDATE_ID + + Ok(()) + } + + #[benchmark] + fn execute_requests_from_execute_queue() -> Result<(), BenchmarkError> { + let (l1_aset_chain, l1_asset_address) = + get_chain_and_address_for_asset_id::(TOKEN_ID.into())?; + let l1_chain: ::ChainId = l1_aset_chain.into(); + + >::set_block_number(20u32.into()); + let execution_id = 123u128; + let scheduled_at: BlockNumberFor = 19u32.into(); + let l1_chain: ::ChainId = l1_aset_chain.into(); + let update_hash = + H256::from(hex!("1111111111111111111111111111111111111111111111111111111111111111")); + + UpdatesExecutionQueueNextId::::put(execution_id); + UpdatesExecutionQueue::::insert( + execution_id, + (scheduled_at, l1_chain, update_hash, 10u128), ); + LastProcessedRequestOnL2::::insert(l1_chain, 0u128); + + let update = L1UpdateBuilder::default() + .with_requests(vec![L1UpdateRequest::Deposit(Default::default()); 10_000]) + .build(); + PendingSequencerUpdateContent::::insert(update_hash, update); #[block] { - Rolldown::::schedule_requests(BlockNumberFor::::default(), l1_chain, update); + Rolldown::::execute_requests_from_execute_queue(); } - assert!( - !MaxAcceptedRequestIdOnl2::::get(l1_chain).is_zero(), - "AFTER MaxAcceptedRequestIdOnl2 {:?} chain should NOT be zero", - l1_chain - ); - assert!( - UpdatesExecutionQueue::::get(FIRST_SCHEDULED_UPDATE_ID).is_some(), - "AFTER UpdatesExecutionQueue {:?} scheduled update id should be some", - FIRST_SCHEDULED_UPDATE_ID + UpdatesExecutionQueue::::get(execution_id).expect("update partially executed"); + assert_eq!( + LastProcessedRequestOnL2::::get(l1_chain), + ::RequestsPerBlock::get() ); Ok(()) } diff --git a/pallets/rolldown/src/lib.rs b/pallets/rolldown/src/lib.rs index eeb8c51ef..176fa53d2 100644 --- a/pallets/rolldown/src/lib.rs +++ b/pallets/rolldown/src/lib.rs @@ -1,11 +1,12 @@ #![cfg_attr(not(feature = "std"), no_std)] -use messages::{EthAbi, EthAbiHash}; +use messages::{EthAbi, EthAbiHash, L1UpdateRequest}; pub mod messages; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +mod weight_utils; pub mod weights; pub use weights::WeightInfo; @@ -154,25 +155,73 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(now: BlockNumberFor) -> Weight { - let mut total_weight: Weight = Weight::default(); + let mut total_weight: Weight = T::DbWeight::get().reads(1); + if T::MaintenanceStatusProvider::is_maintenance() { LastMaintananceMode::::put(now.saturated_into::()); + total_weight += T::DbWeight::get().writes(1); + } else { + Self::maybe_create_batch(now); + total_weight += ::WeightInfo::maybe_create_batch(); } - // weight for is_maintenance - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); - let weight = Self::maybe_create_batch(now); - total_weight = total_weight.saturating_add(weight); - let weight = Self::schedule_request_for_execution_if_dispute_period_has_passsed(now); - total_weight = total_weight.saturating_add(weight); - let weight = Self::execute_requests_from_execute_queue(now); - total_weight = total_weight.saturating_add(weight); - // We multiply by two so that we can have our large storage access (update requests) - // go upto 500 requests per update - // 500 also is really pushing it - it should probably be something like 100... - // https://substrate.stackexchange.com/questions/525/how-expensive-is-it-to-access-storage-items + + Self::schedule_request_for_execution_if_dispute_period_has_passsed(now); + total_weight += ::WeightInfo::schedule_request_for_execution_if_dispute_period_has_passsed(); + + Self::load_next_update_from_execution_queue(); + total_weight += ::WeightInfo::load_next_update_from_execution_queue(); total_weight - .saturating_mul(2) - .saturating_add(Weight::from_parts(200__000_000, 0)) + } + + fn on_idle(_now: BlockNumberFor, mut remaining_weight: Weight) -> Weight { + let mut used_weight = Weight::default(); + + // already cached by using in on_initialize hook + if !T::MaintenanceStatusProvider::is_maintenance() { + let get_update_size_cost = T::DbWeight::get().reads(2); + + if remaining_weight.ref_time() < get_update_size_cost.ref_time() { + return used_weight; + } + + remaining_weight -= get_update_size_cost; + used_weight += get_update_size_cost; + + let update_size = + Self::get_current_update_size_from_execution_queue().unwrap_or(1u128); + + // NOTE: execute_requests_from_execute_queue accounts for overal cost of processing + // biggest expected update (with 10k requests) assuming that all of them are deposits + // to accounts for most expensive case now need to substract cost of processing deposits + // and add cost of processing cancels instead + let mut cost_of_processing_requests = + ::WeightInfo::execute_requests_from_execute_queue(); + + cost_of_processing_requests += + ::WeightInfo::process_cancel_resolution() + .saturating_mul(Self::get_max_requests_per_block().saturated_into()); + cost_of_processing_requests -= ::WeightInfo::process_deposit() + .saturating_mul(Self::get_max_requests_per_block().saturated_into()); + + // account for huge read cost when reading huge update + cost_of_processing_requests += T::DbWeight::get().reads(1).saturating_mul( + weight_utils::get_read_scalling_factor(update_size.saturated_into()) + .saturated_into(), + ); + + if remaining_weight.ref_time() < cost_of_processing_requests.ref_time() { + return used_weight; + } + + // NOTE: here we could adjust the used weight based on the actual executed requests + // as the benchmarks accounts for the worst case scenario which is cancel_resultion + // processing + let _executed: Vec = Self::execute_requests_from_execute_queue(); + + used_weight += cost_of_processing_requests; + remaining_weight -= cost_of_processing_requests; + } + used_weight } } @@ -184,6 +233,15 @@ pub mod pallet { pub cancel_rights: u128, } + #[derive(Eq, PartialEq, RuntimeDebug, Clone, Encode, Decode, MaxEncodedLen, TypeInfo)] + pub struct UpdateMetadata { + pub max_id: u128, + pub min_id: u128, + pub update_size: u128, + pub sequencer: AccountId, + pub update_hash: H256, + } + #[derive(Eq, PartialEq, RuntimeDebug, Clone, Copy, Encode, Decode, TypeInfo)] pub enum L2Request { FailedDepositResolution(FailedDepositResolution), @@ -245,10 +303,16 @@ pub mod pallet { u128, Blake2_128Concat, ::ChainId, - (T::AccountId, messages::L1Update, H256), + UpdateMetadata, OptionQuery, >; + #[pallet::storage] + #[pallet::unbounded] + // Stores requests brought by sequencer that are under dispute period. + pub type PendingSequencerUpdateContent = + StorageMap<_, Blake2_128Concat, H256, messages::L1Update, OptionQuery>; + #[pallet::storage] #[pallet::unbounded] // queue of all updates that went through dispute period and are ready to be processed @@ -256,7 +320,8 @@ pub mod pallet { _, Blake2_128Concat, u128, - (BlockNumberFor, ::ChainId, messages::L1Update), + // scheduled_at, chain, update_hash, update_size + (BlockNumberFor, ::ChainId, H256, u128), OptionQuery, >; @@ -344,6 +409,10 @@ pub mod pallet { ValueQuery, >; + #[pallet::storage] + pub type DisputePeriod = + StorageMap<_, Blake2_128Concat, ChainIdOf, u128, OptionQuery>; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -394,11 +463,23 @@ pub mod pallet { chain: ::ChainId, hash: H256, }, + L1ReadIgnoredBecauseOfUnknownDisputePeriod { + chain: ::ChainId, + hash: H256, + }, DepositFerried { chain: ::ChainId, deposit: messages::Deposit, deposit_hash: H256, }, + L1ReadExecuted { + chain: ::ChainId, + hash: H256, + }, + DisputePeriodSet { + chain: ::ChainId, + dispute_period_length: u128, + }, } #[pallet::error] @@ -437,6 +518,7 @@ pub mod pallet { AssetRegistrationProblem, UpdateHashMishmatch, AlreadyExecuted, + UninitializedChainId, } #[cfg(feature = "runtime-benchmarks")] @@ -461,8 +543,6 @@ pub mod pallet { + MultiTokenCurrencyExtended; type AssetRegistryProvider: AssetRegistryProviderTrait>; #[pallet::constant] - type DisputePeriodLength: Get; - #[pallet::constant] type RightsMultiplier: Get; #[pallet::constant] type RequestsPerBlock: Get; @@ -499,17 +579,22 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig { pub _phantom: PhantomData, + pub dispute_periods: BTreeMap, u128>, } impl Default for GenesisConfig { fn default() -> Self { - GenesisConfig { _phantom: Default::default() } + GenesisConfig { _phantom: Default::default(), dispute_periods: Default::default() } } } #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { - fn build(&self) {} + fn build(&self) { + for (chain, period) in &self.dispute_periods { + DisputePeriod::::insert(chain, *period); + } + } } // Many calls that deal with large storage items have their weight mutiplied by 2 @@ -520,7 +605,9 @@ pub mod pallet { #[pallet::call] impl Pallet { #[pallet::call_index(0)] - #[pallet::weight(::WeightInfo::update_l2_from_l1(requests.pendingDeposits.len().saturating_add(requests.pendingCancelResolutions.len()).saturating_mul(2) as u32))] + #[pallet::weight(::WeightInfo::update_l2_from_l1( + requests.get_requests_count().saturated_into() + ).saturating_add(T::DbWeight::get().reads(weight_utils::get_read_scalling_factor(requests.get_requests_count().saturated_into()).saturated_into())))] pub fn update_l2_from_l1( origin: OriginFor, requests: messages::L1Update, @@ -540,7 +627,7 @@ pub mod pallet { origin: OriginFor, update: messages::L1Update, ) -> DispatchResultWithPostInfo { - let _ = ensure_root(origin)?; + let root = ensure_root(origin)?; let chain: ::ChainId = update.chain.into(); ensure!( @@ -548,15 +635,21 @@ pub mod pallet { Error::::BlockedByMaintenanceMode ); - Self::validate_l1_update(chain, &update)?; + let metadata = + Self::validate_l1_update(chain, &update, T::AddressConverter::convert([0u8; 20]))?; + let now = >::block_number(); - Self::schedule_requests(now, chain, update.into()); + let update_size = update.get_requests_count(); + PendingSequencerUpdateContent::::insert(metadata.update_hash, update); + + Self::schedule_requests(now, chain, metadata); Ok(().into()) } #[pallet::call_index(3)] - #[pallet::weight(::WeightInfo::cancel_requests_from_l1().saturating_mul(2))] - //EXTRINSIC2 (who canceled, dispute_period_end(u32-blocknum))) + // NOTE: account for worst case scenario, in the future we should introduce the mandatory + // parameter 'update_size' so we can parametrize weight with it + #[pallet::weight(::WeightInfo::cancel_requests_from_l1().saturating_mul(weight_utils::get_read_scalling_factor(10_000).saturated_into()))] pub fn cancel_requests_from_l1( origin: OriginFor, chain: ::ChainId, @@ -577,11 +670,14 @@ pub mod pallet { Ok::<_, Error>(()) })?; - let (submitter, request, _) = - PendingSequencerUpdates::::take(requests_to_cancel, chain) - .ok_or(Error::::RequestDoesNotExist)?; + let metadata = PendingSequencerUpdates::::take(requests_to_cancel, chain) + .ok_or(Error::::RequestDoesNotExist)?; - let hash_of_pending_request = Self::calculate_hash_of_sequencer_update(request.clone()); + let submitter = metadata.sequencer; + let request_hash = metadata.update_hash; + + let request = PendingSequencerUpdateContent::::take(request_hash) + .ok_or(Error::::RequestDoesNotExist)?; let l2_request_id = Self::acquire_l2_request_id(chain); @@ -590,7 +686,7 @@ pub mod pallet { updater: submitter.clone(), canceler: canceler.clone(), range: request.range().ok_or(Error::::InvalidUpdate)?, - hash: hash_of_pending_request, + hash: request_hash, }; AwaitingCancelResolution::::mutate(chain, |v| { @@ -723,9 +819,11 @@ pub mod pallet { Error::::BlockedByMaintenanceMode ); - let (submitter, _request, _hash) = - PendingSequencerUpdates::::take(requests_to_cancel, chain) - .ok_or(Error::::RequestDoesNotExist)?; + let metadata = PendingSequencerUpdates::::take(requests_to_cancel, chain) + .ok_or(Error::::RequestDoesNotExist)?; + + let submitter = metadata.sequencer; + let hash = metadata.update_hash; if T::SequencerStakingProvider::is_active_sequencer(chain, &submitter) { SequencersRights::::mutate(chain, |sequencers| { @@ -923,12 +1021,25 @@ pub mod pallet { let sequencer = ensure_signed(origin)?; Self::update_impl(sequencer, requests) } + + #[pallet::call_index(13)] + #[pallet::weight(T::DbWeight::get().reads_writes(0, 2))] + pub fn set_dispute_period( + origin: OriginFor, + chain: ::ChainId, + dispute_period_length: u128, + ) -> DispatchResult { + let _ = ensure_root(origin)?; + DisputePeriod::::insert(chain, dispute_period_length); + Self::deposit_event(Event::DisputePeriodSet { chain, dispute_period_length }); + Ok(()) + } } } impl Pallet { - fn get_dispute_period() -> u128 { - T::DisputePeriodLength::get() + fn get_dispute_period(chain: ChainIdOf) -> Option { + DisputePeriod::::get(chain) } fn get_max_requests_per_block() -> u128 { @@ -941,31 +1052,28 @@ impl Pallet { request_id: u128, ) -> Option { let pending_requests_to_process = PendingSequencerUpdates::::get(request_id, chain); - if let Some((_, l1_update, _hash)) = pending_requests_to_process { - let calculated_hash = Self::calculate_hash_of_sequencer_update(l1_update); - Some(hash == calculated_hash) + if let Some(metadata) = pending_requests_to_process { + if let Some(l1_update) = PendingSequencerUpdateContent::::get(metadata.update_hash) { + let calculated_hash = l1_update.abi_encode_hash(); + Some(hash == calculated_hash) + } else { + None + } } else { None } } - fn maybe_create_batch(now: BlockNumberFor) -> Weight { - let mut total_weight: Weight = Weight::default(); + fn maybe_create_batch(now: BlockNumberFor) { let batch_size = Self::automatic_batch_size(); let batch_period: BlockNumberFor = Self::automatic_batch_period().saturated_into(); // weight for is_maintenance - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); if T::MaintenanceStatusProvider::is_maintenance() { - return total_weight + return; } - // weight for L2OriginRequestId iter extra read incase empty - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); for (chain, next_id) in L2OriginRequestId::::get().iter() { - // weight for L2OriginRequestId iter - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); - let last_id = next_id.saturating_sub(1); let (last_batch_block_number, last_batch_id, last_id_in_batch) = @@ -976,8 +1084,6 @@ impl Pallet { (block_number, batch_id, last_reqeust_id) }) .unwrap_or_default(); - // weight for L2RequestsBatchLast - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); let trigger = if last_id >= last_id_in_batch + batch_size { Some(BatchSource::AutomaticSizeReached) @@ -988,8 +1094,6 @@ impl Pallet { }; if let Some(trigger) = trigger { - // weight for selected_sequencer - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); let updater = T::SequencerStakingProvider::selected_sequencer(*chain) .unwrap_or(T::AddressConverter::convert([0u8; 20])); let batch_id = last_batch_id.saturating_add(1); @@ -1003,13 +1107,9 @@ impl Pallet { (chain, batch_id), (now, (range_start, range_end), updater.clone()), ); - // weight for L2RequestsBatch - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); L2RequestsBatchLast::::mutate(|batches| { batches.insert(chain.clone(), (now, batch_id, (range_start, range_end))); }); - // weight for L2RequestsBatchLast - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); Pallet::::deposit_event(Event::TxBatchCreated { chain: *chain, source: trigger, @@ -1017,249 +1117,177 @@ impl Pallet { batch_id, range: (range_start, range_end), }); - // Not sure about this - not sure exactly what is cached and how across extrinsics (/hooks) - // weight for deposit_event - total_weight = - total_weight.saturating_add(T::DbWeight::get().reads_writes(2, 3)); break } } } - total_weight + Default::default() } - fn schedule_request_for_execution_if_dispute_period_has_passsed( - now: BlockNumberFor, - ) -> Weight { - // weight = 0 -> pretty sure reading blocknumber is free + fn schedule_request_for_execution_if_dispute_period_has_passsed(now: BlockNumberFor) { let block_number = >::block_number().saturated_into::(); - let mut total_weight: Weight = Weight::default(); - let mut number_of_updates: u32 = u32::zero(); - // weight for PendingSequencerUpdates iter extra read incase empty - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); - for (l1, (sequencer, requests, l1_read_hash)) in - PendingSequencerUpdates::::iter_prefix(block_number) - { - number_of_updates = number_of_updates.saturating_add(1u32); - // weight for PendingSequencerUpdates iter - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); - - if T::SequencerStakingProvider::is_active_sequencer(l1, &sequencer) { - SequencersRights::::mutate(l1, |sequencers| { - if let Some(rights) = sequencers.get_mut(&sequencer) { - rights.read_rights.saturating_accrue(T::RightsMultiplier::get()); - } - }); - } - // weight for above block - total_weight = total_weight.saturating_add(T::DbWeight::get().reads_writes(2, 1)); - - let update_creation_block = block_number.saturating_sub(Self::get_dispute_period()); - // weight for LastMaintananceMode - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); - match LastMaintananceMode::::get() { - Some(last_maintanance_mode) if update_creation_block < last_maintanance_mode => { - Self::deposit_event(Event::L1ReadIgnoredBecauseOfMaintenanceMode { - chain: l1, - hash: l1_read_hash, + for (l1, metadata) in PendingSequencerUpdates::::iter_prefix(block_number) { + let sequencer = metadata.sequencer.clone(); + let l1_read_hash = metadata.update_hash.clone(); + let update_size = metadata.update_size.clone(); + if let Some(dispute_period) = Self::get_dispute_period(l1) { + if T::SequencerStakingProvider::is_active_sequencer(l1, &sequencer) { + SequencersRights::::mutate(l1, |sequencers| { + if let Some(rights) = sequencers.get_mut(&sequencer) { + rights.read_rights.saturating_accrue(T::RightsMultiplier::get()); + } }); + } - // Not sure about this - not sure exactly what is cached and how across extrinsics (/hooks) - // weight for deposit_event - total_weight = - total_weight.saturating_add(T::DbWeight::get().reads_writes(2, 3)); - }, - _ => { - Self::schedule_requests(now, l1, requests.clone()); - // weight for schedule_requests - total_weight = - total_weight.saturating_add(::WeightInfo::schedule_requests( - requests - .pendingDeposits - .len() - .saturating_add(requests.pendingCancelResolutions.len()) as u32, - )); - Self::deposit_event(Event::L1ReadScheduledForExecution { - chain: l1, - hash: l1_read_hash, - }); - // Not sure about this - not sure exactly what is cached and how across extrinsics (/hooks) - // weight for deposit_event - total_weight = - total_weight.saturating_add(T::DbWeight::get().reads_writes(2, 3)); - }, + let update_creation_block = block_number.saturating_sub(dispute_period); + + match LastMaintananceMode::::get() { + Some(last_maintanance_mode) + if update_creation_block <= last_maintanance_mode => + { + Self::deposit_event(Event::L1ReadIgnoredBecauseOfMaintenanceMode { + chain: l1, + hash: l1_read_hash, + }); + }, + _ => { + Self::schedule_requests(now, l1, metadata); + Self::deposit_event(Event::L1ReadScheduledForExecution { + chain: l1, + hash: l1_read_hash, + }); + }, + } + } else { + Self::deposit_event(Event::L1ReadIgnoredBecauseOfUnknownDisputePeriod { + chain: l1, + hash: l1_read_hash, + }); } } - // weight for PendingSequencerUpdates iter - total_weight = - total_weight.saturating_add(T::DbWeight::get().writes(number_of_updates.into())); - let _ = PendingSequencerUpdates::::clear_prefix( - >::block_number().saturated_into::(), - u32::MAX, - None, - ); - - total_weight + let _ = PendingSequencerUpdates::::clear_prefix(block_number, u32::MAX, None); } fn process_single_request( l1: ::ChainId, - request: messages::L1UpdateRequest, - ) -> Weight { - let mut total_weight: Weight = Weight::default(); - - // weight for LastProcessedRequestOnL2 - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); - if request.id() <= LastProcessedRequestOnL2::::get(l1) { - return total_weight + request: &messages::L1UpdateRequest, + ) -> bool { + let request_id = request.id(); + if request_id <= LastProcessedRequestOnL2::::get(l1) { + return true; } let status = match request.clone() { messages::L1UpdateRequest::Deposit(deposit) => { let deposit_status = Self::process_deposit(l1, &deposit); - total_weight = - total_weight.saturating_add(::WeightInfo::process_deposit()); TotalNumberOfDeposits::::mutate(|v| *v = v.saturating_add(One::one())); - // weight for TotalNumberOfDeposits - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); deposit_status.or_else(|err| { let who: T::AccountId = T::AddressConverter::convert(deposit.depositRecipient); FailedL1Deposits::::insert( (l1, deposit.requestId.id), (who, deposit.abi_encode_hash()), ); - // weight for FailedL1Deposits - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); Err(err.into()) }) }, - messages::L1UpdateRequest::CancelResolution(cancel) => { - total_weight = total_weight - .saturating_add(::WeightInfo::process_cancel_resolution()); + messages::L1UpdateRequest::CancelResolution(cancel) => Self::process_cancel_resolution(l1, &cancel).or_else(|err| { T::MaintenanceStatusProvider::trigger_maintanance_mode(); Err(err) - }) - }, + }), }; Pallet::::deposit_event(Event::RequestProcessedOnL2 { chain: l1, - request_id: request.id(), - status, + request_id, + status: status.clone(), }); - // Not sure about this - not sure exactly what is cached and how across extrinsics (/hooks) - // weight for deposit_event - total_weight = total_weight.saturating_add(T::DbWeight::get().reads_writes(2, 3)); - LastProcessedRequestOnL2::::insert(l1, request.id()); - // weight for LastProcessedRequestOnL2 - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); - total_weight + status.is_ok() } - fn execute_requests_from_execute_queue(now: BlockNumberFor) -> Weight { - let mut total_weight: Weight = Weight::default(); - - // weight for the if in the below block - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(3)); - if T::MaintenanceStatusProvider::is_maintenance() && - UpdatesExecutionQueue::::get(UpdatesExecutionQueueNextId::::get()).is_some() - { - let new_id: u128 = LastScheduledUpdateIdInExecutionQueue::::mutate(|v| { - v.saturating_inc(); - *v - }); - UpdatesExecutionQueueNextId::::put(new_id); + fn get_current_update_size_from_execution_queue() -> Option { + UpdatesExecutionQueue::::get(UpdatesExecutionQueueNextId::::get()) + .map(|(_, _, _, size)| size) + } - // weight for this block - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(2)); - return total_weight + fn load_next_update_from_execution_queue() -> bool { + let current_execution_id = UpdatesExecutionQueueNextId::::get(); + let next_execution_id = current_execution_id.saturating_add(1u128); + match ( + UpdatesExecutionQueue::::get(current_execution_id), + UpdatesExecutionQueue::::get(next_execution_id), + ) { + (None, Some(_)) => { + UpdatesExecutionQueueNextId::::mutate(Saturating::saturating_inc); + true + }, + _ => false, } + } - let mut limit = Self::get_max_requests_per_block(); - loop { - if limit == 0 { - return total_weight - } - - // weight for the if in the below block - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(2)); - if let Some((scheduled_at, l1, r)) = - UpdatesExecutionQueue::::get(UpdatesExecutionQueueNextId::::get()) + fn execute_requests_from_execute_queue() -> Vec { + let limit = Self::get_max_requests_per_block(); + match ( + UpdatesExecutionQueue::::get(UpdatesExecutionQueueNextId::::get()), + LastMaintananceMode::::get(), + ) { + (Some((scheduled_at, _, _, _)), Some(last_maintanance_mode)) + if scheduled_at.saturated_into::() <= last_maintanance_mode => { - if scheduled_at == now { - return total_weight - } - - // Repeated reads of the same value should be cached - // weight for LastProcessedRequestOnL2 - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); - for req in r - .into_requests() - .into_iter() - .filter(|request| request.id() > LastProcessedRequestOnL2::::get(l1)) - .map(|val| Some(val)) - .chain(sp_std::iter::repeat(None)) - .take(limit.try_into().unwrap()) - { - if let Some(request) = req { - let weight = Self::process_single_request(l1, request); - // weight for process_single_request - total_weight = total_weight.saturating_add(weight); - limit -= 1; - } else { + UpdatesExecutionQueue::::remove(UpdatesExecutionQueueNextId::::get()); + UpdatesExecutionQueueNextId::::mutate(Saturating::saturating_inc); + Default::default() + }, + (Some((_, l1, hash, _)), _) => { + if let Some(update) = PendingSequencerUpdateContent::::get(hash) { + let requests = update + .into_requests() + .into_iter() + .filter(|request| request.id() > LastProcessedRequestOnL2::::get(l1)) + .take(limit.saturated_into()) + .collect::>(); + + if requests.is_empty() { UpdatesExecutionQueue::::remove(UpdatesExecutionQueueNextId::::get()); - UpdatesExecutionQueueNextId::::mutate(|v| *v += 1); - // weight for this block - total_weight = - total_weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)); - break + PendingSequencerUpdateContent::::remove(hash); + Self::deposit_event(Event::L1ReadExecuted { chain: l1, hash }); + Default::default() + } else { + for r in requests.iter() { + if !Self::process_single_request(l1, &r) { + // maintanance mode triggered + break; + } + } + requests } - } - } else { - // weight for the if in the below block - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(2)); - if UpdatesExecutionQueue::::contains_key( - UpdatesExecutionQueueNextId::::get() + 1, - ) { - UpdatesExecutionQueueNextId::::mutate(|v| *v += 1); - // weight for UpdatesExecutionQueueNextId - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); } else { - break + PendingSequencerUpdateContent::::remove(hash); + Default::default() } - } + }, + _ => Default::default(), } - total_weight } fn schedule_requests( now: BlockNumberFor, chain: ::ChainId, - update: messages::L1Update, + metadata: UpdateMetadata, ) { - let max_id = [ - update.pendingDeposits.iter().map(|r| r.requestId.id).max(), - update.pendingCancelResolutions.iter().map(|r| r.requestId.id).max(), - ] - .iter() - .filter_map(|elem| elem.clone()) - .max(); - - if let Some(max_id) = max_id { - MaxAcceptedRequestIdOnl2::::mutate(chain, |cnt| { - *cnt = sp_std::cmp::max(*cnt, max_id) - }); - } + MaxAcceptedRequestIdOnl2::::mutate(chain, |cnt| { + *cnt = sp_std::cmp::max(*cnt, metadata.max_id) + }); let id = LastScheduledUpdateIdInExecutionQueue::::mutate(|id| { id.saturating_inc(); *id }); - UpdatesExecutionQueue::::insert(id, (now, chain, update)); + let size = metadata.max_id.saturating_sub(metadata.min_id).saturating_add(1); + UpdatesExecutionQueue::::insert(id, (now, chain, metadata.update_hash, size)); } /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -1347,12 +1375,6 @@ impl Pallet { Ok(()) } - fn calculate_hash_of_sequencer_update(update: messages::L1Update) -> H256 { - let update: messages::eth_abi::L1Update = update.into(); - let hash: [u8; 32] = keccak_256(&update.abi_encode()[..]).into(); - H256::from(hash) - } - fn handle_sequencer_deactivation( chain: ::ChainId, deactivated_sequencers: BTreeSet, @@ -1386,7 +1408,8 @@ impl Pallet { pub fn validate_l1_update( l1: ::ChainId, update: &messages::L1Update, - ) -> DispatchResult { + sequencer: T::AccountId, + ) -> Result, Error> { ensure!( !update.pendingDeposits.is_empty() || !update.pendingCancelResolutions.is_empty(), Error::::EmptyUpdate @@ -1473,7 +1496,14 @@ impl Pallet { } } - Ok(().into()) + Ok(UpdateMetadata { + sequencer, + update_hash: update.abi_encode_hash(), + update_size: update.pendingDeposits.len() as u128 + + update.pendingCancelResolutions.len() as u128, + max_id: lowest_id, + min_id: last_id, + }) } pub fn update_impl(sequencer: T::AccountId, read: messages::L1Update) -> DispatchResult { @@ -1488,12 +1518,14 @@ impl Pallet { T::SequencerStakingProvider::is_selected_sequencer(l1, &sequencer), Error::::OnlySelectedSequencerisAllowedToUpdate ); - Self::validate_l1_update(l1, &read)?; + let metadata = Self::validate_l1_update(l1, &read, sequencer.clone())?; // check json length to prevent big data spam, maybe not necessary as it will be checked later and slashed let current_block_number = >::block_number().saturated_into::(); - let dispute_period_length = Self::get_dispute_period(); + let dispute_period_length = + Self::get_dispute_period(l1).ok_or(Error::::UninitializedChainId)?; + let dispute_period_end: u128 = current_block_number + dispute_period_length; // ensure sequencer has rights to update @@ -1519,15 +1551,9 @@ impl Pallet { Error::::MultipleUpdatesInSingleBlock ); - let update: messages::eth_abi::L1Update = read.clone().into(); - let request_hash = keccak_256(&update.abi_encode()); - let l1_read_hash = H256::from_slice(request_hash.as_slice()); + PendingSequencerUpdates::::insert(dispute_period_end, l1, metadata.clone()); - PendingSequencerUpdates::::insert( - dispute_period_end, - l1, - (sequencer.clone(), read.clone(), l1_read_hash), - ); + PendingSequencerUpdateContent::::insert(metadata.update_hash, read.clone()); LastUpdateBySequencer::::insert((l1, &sequencer), current_block_number); @@ -1538,7 +1564,7 @@ impl Pallet { sequencer: sequencer.clone(), dispute_period_end, range: requests_range, - hash: l1_read_hash, + hash: metadata.update_hash, }); // 2 storage reads & writes in seqs pallet @@ -1550,9 +1576,10 @@ impl Pallet { fn count_of_read_rights_under_dispute(chain: ChainIdOf, sequencer: &AccountIdOf) -> u128 { let mut read_rights = 0u128; let last_update = LastUpdateBySequencer::::get((chain, sequencer)); + let dispute_period = Self::get_dispute_period(chain).unwrap_or(u128::MAX); if last_update != 0 && - last_update.saturating_add(T::DisputePeriodLength::get()) >= + last_update.saturating_add(dispute_period) >= >::block_number().saturated_into::() { read_rights += 1; diff --git a/pallets/rolldown/src/messages/mod.rs b/pallets/rolldown/src/messages/mod.rs index 6f06277f9..59d83d63f 100644 --- a/pallets/rolldown/src/messages/mod.rs +++ b/pallets/rolldown/src/messages/mod.rs @@ -234,6 +234,12 @@ pub struct L1Update { pub pendingCancelResolutions: Vec, } +impl L1Update { + pub fn get_requests_count(&self) -> u128 { + self.pendingDeposits.len() as u128 + self.pendingCancelResolutions.len() as u128 + } +} + impl NativeToEthMapping for L1Update where Self: Clone, diff --git a/pallets/rolldown/src/mock.rs b/pallets/rolldown/src/mock.rs index 7e0755808..2fb48f684 100644 --- a/pallets/rolldown/src/mock.rs +++ b/pallets/rolldown/src/mock.rs @@ -143,7 +143,6 @@ impl rolldown::Config for Test { type Tokens = orml_tokens::MultiTokenCurrencyAdapter; type AssetRegistryProvider = MockAssetRegistryProviderApi; type AddressConverter = DummyAddressConverter; - type DisputePeriodLength = ConstU128<5>; type RequestsPerBlock = ConstU128<10>; type MaintenanceStatusProvider = MockMaintenanceStatusProviderApi; type ChainId = messages::Chain; @@ -168,9 +167,12 @@ impl ExtBuilder { .build_storage() .expect("Frame system builds valid default genesis config"); - rolldown::GenesisConfig:: { _phantom: Default::default() } - .assimilate_storage(&mut t) - .expect("Tokens storage can be assimilated"); + rolldown::GenesisConfig:: { + _phantom: Default::default(), + dispute_periods: [(crate::messages::Chain::Ethereum, 5u128)].iter().cloned().collect(), + } + .assimilate_storage(&mut t) + .expect("Tokens storage can be assimilated"); let mut ext = sp_io::TestExternalities::new(t); @@ -188,24 +190,18 @@ impl ExtBuilder { .build_storage() .expect("Frame system builds valid default genesis config"); - rolldown::GenesisConfig:: { _phantom: Default::default() } - .assimilate_storage(&mut t) - .expect("Tokens storage can be assimilated"); + rolldown::GenesisConfig:: { + _phantom: Default::default(), + dispute_periods: [(crate::messages::Chain::Ethereum, 5u128)].iter().cloned().collect(), + } + .assimilate_storage(&mut t) + .expect("Tokens storage can be assimilated"); let ext = sp_io::TestExternalities::new(t); Self { ext } } - pub fn single_sequencer(_seq: AccountId) -> Self { - let t = frame_system::GenesisConfig::::default() - .build_storage() - .expect("Frame system builds valid default genesis config"); - - let ext = sp_io::TestExternalities::new(t); - Self { ext } - } - fn create_if_does_not_exists(&mut self, token_id: TokenId) { self.ext.execute_with(|| { while token_id >= Tokens::next_asset_id() { @@ -319,6 +315,7 @@ where frame_system::Pallet::::on_initialize(new_block_number); rolldown::Pallet::::on_initialize(new_block_number); + rolldown::Pallet::::on_idle(new_block_number, Weight::from_parts(u64::MAX, 0u64)); } } diff --git a/pallets/rolldown/src/tests.rs b/pallets/rolldown/src/tests.rs index d71f6c002..124e73ba1 100644 --- a/pallets/rolldown/src/tests.rs +++ b/pallets/rolldown/src/tests.rs @@ -38,7 +38,12 @@ impl L1UpdateBuilder { } pub fn build(self) -> messages::L1Update { + Self::build_for_chain(self, Chain::Ethereum) + } + + pub fn build_for_chain(self, chain: Chain) -> messages::L1Update { let mut update = messages::L1Update::default(); + update.chain = chain; for (id, r) in self.1.into_iter().enumerate() { let rid = if let Some(offset) = self.0 { (id as u128) + offset } else { r.id() }; @@ -94,7 +99,7 @@ fn process_single_deposit() { forward_to_block::(36); let current_block_number = >::block_number().saturated_into::(); - let dispute_period: u128 = Rolldown::get_dispute_period(); + let dispute_period: u128 = Rolldown::get_dispute_period(consts::CHAIN).unwrap(); let update = L1UpdateBuilder::default() .with_requests(vec![L1UpdateRequest::Deposit(Default::default())]) .build(); @@ -149,9 +154,9 @@ fn l2_counter_updates_when_requests_are_processed() { Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(BOB), update2).unwrap(); forward_to_block::(15); - forward_to_next_block::(); assert_eq!(Rolldown::get_last_processed_request_on_l2(Chain::Ethereum), 1u128.into()); + forward_to_next_block::(); forward_to_next_block::(); assert_eq!(Rolldown::get_last_processed_request_on_l2(Chain::Ethereum), 2u128.into()); }); @@ -333,7 +338,7 @@ fn test_withdrawal_can_be_refunded_only_by_account_deposit_recipient() { #[test] #[serial] -fn l1_upate_executed_immaidately_if_force_submitted() { +fn l1_upate_executed_immediately_if_force_submitted() { ExtBuilder::new() .issue(ALICE, ETH_TOKEN_ADDRESS_MGX, 0u128) .execute_with_default_mocks(|| { @@ -358,7 +363,8 @@ fn l1_upate_executed_immaidately_if_force_submitted() { Rolldown::force_update_l2_from_l1(RuntimeOrigin::root(), update).unwrap(); assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); - forward_to_block::(11); + forward_to_next_block::(); + forward_to_next_block::(); assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 1u128.into()); assert_eq!(TokensOf::::free_balance(ETH_TOKEN_ADDRESS_MGX, &CHARLIE), MILLION); }); @@ -825,95 +831,136 @@ fn cancel_request_as_council_executed_immadiately() { #[test] #[serial] fn execute_a_lot_of_requests_in_following_blocks() { - ExtBuilder::new().execute_with_default_mocks(|| { - forward_to_block::(10); + ExtBuilder::new() + .issue(ALICE, ETH_TOKEN_ADDRESS_MGX, 0u128) + .execute_with_default_mocks(|| { + forward_to_block::(10); - let requests_count = 25; - let requests = vec![L1UpdateRequest::Deposit(messages::Deposit::default()); requests_count]; + let requests_count = 25; - let deposit_update = L1UpdateBuilder::default().with_requests(requests).build(); - Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), deposit_update).unwrap(); + let dummy_update = L1UpdateRequest::Deposit(messages::Deposit { + requestId: Default::default(), + depositRecipient: DummyAddressConverter::convert_back(CHARLIE), + tokenAddress: ETH_TOKEN_ADDRESS, + amount: sp_core::U256::from(MILLION), + timeStamp: sp_core::U256::from(1), + ferryTip: sp_core::U256::from(0), + }); - forward_to_block::(14); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); - assert_eq!(UpdatesExecutionQueueNextId::::get(), 0u128); + let requests = vec![dummy_update; requests_count]; - forward_to_block::(15); - forward_to_next_block::(); - assert_eq!( - LastProcessedRequestOnL2::::get(Chain::Ethereum), - Rolldown::get_max_requests_per_block().into() - ); + let deposit_update = L1UpdateBuilder::default().with_requests(requests).build(); + Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), deposit_update) + .unwrap(); - forward_to_next_block::(); - assert_eq!( - LastProcessedRequestOnL2::::get(Chain::Ethereum), - (2u128 * Rolldown::get_max_requests_per_block()).into() - ); + forward_to_block::(14); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); + assert_eq!(UpdatesExecutionQueueNextId::::get(), 0u128); - forward_to_next_block::(); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), requests_count as u128); + forward_to_next_block::(); + assert_eq!( + LastProcessedRequestOnL2::::get(Chain::Ethereum), + Rolldown::get_max_requests_per_block().into() + ); - forward_to_next_block::(); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), requests_count as u128); - }); + forward_to_next_block::(); + assert_eq!( + LastProcessedRequestOnL2::::get(Chain::Ethereum), + (2u128 * Rolldown::get_max_requests_per_block()).into() + ); + + forward_to_next_block::(); + assert_eq!( + LastProcessedRequestOnL2::::get(Chain::Ethereum), + requests_count as u128 + ); + + forward_to_next_block::(); + assert_eq!( + LastProcessedRequestOnL2::::get(Chain::Ethereum), + requests_count as u128 + ); + }); } #[test] #[serial] fn ignore_duplicated_requests_when_already_executed() { - ExtBuilder::new().execute_with_default_mocks(|| { - let dummy_request = L1UpdateRequest::Deposit(Default::default()); - let first_update = - L1UpdateBuilder::default().with_requests(vec![dummy_request.clone(); 5]).build(); - let second_update = - L1UpdateBuilder::default().with_requests(vec![dummy_request; 6]).build(); + ExtBuilder::new() + .issue(ALICE, ETH_TOKEN_ADDRESS_MGX, 0u128) + .execute_with_default_mocks(|| { + let dummy_request = L1UpdateRequest::Deposit(messages::Deposit { + requestId: Default::default(), + depositRecipient: DummyAddressConverter::convert_back(CHARLIE), + tokenAddress: ETH_TOKEN_ADDRESS, + amount: sp_core::U256::from(MILLION), + timeStamp: sp_core::U256::from(1), + ferryTip: sp_core::U256::from(0), + }); - forward_to_block::(10); - Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), first_update).unwrap(); + let first_update = + L1UpdateBuilder::default().with_requests(vec![dummy_request.clone(); 5]).build(); + let second_update = + L1UpdateBuilder::default().with_requests(vec![dummy_request; 6]).build(); - forward_to_block::(11); - Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(BOB), second_update).unwrap(); + forward_to_block::(10); + Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), first_update).unwrap(); - forward_to_block::(14); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); + forward_to_block::(11); + Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(BOB), second_update).unwrap(); - forward_to_block::(15); - forward_to_next_block::(); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 5u128.into()); + forward_to_block::(14); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); - forward_to_next_block::(); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 6u128.into()); - }); + forward_to_block::(15); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 5u128.into()); + + forward_to_next_block::(); + forward_to_next_block::(); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 6u128.into()); + }); } #[test] #[serial] fn process_l1_reads_in_order() { - ExtBuilder::new().execute_with_default_mocks(|| { - let dummy_request = L1UpdateRequest::Deposit(Default::default()); - let first_update = L1UpdateBuilder::default() - .with_requests(vec![dummy_request.clone(); 11]) - .build(); - let second_update = - L1UpdateBuilder::default().with_requests(vec![dummy_request; 20]).build(); + ExtBuilder::new() + .issue(ALICE, ETH_TOKEN_ADDRESS_MGX, 0u128) + .execute_with_default_mocks(|| { + let dummy_request = L1UpdateRequest::Deposit(messages::Deposit { + requestId: Default::default(), + depositRecipient: DummyAddressConverter::convert_back(CHARLIE), + tokenAddress: ETH_TOKEN_ADDRESS, + amount: sp_core::U256::from(MILLION), + timeStamp: sp_core::U256::from(1), + ferryTip: sp_core::U256::from(0), + }); - forward_to_block::(10); - Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), first_update).unwrap(); + let first_update = L1UpdateBuilder::default() + .with_requests(vec![dummy_request.clone(); 11]) + .build(); + let second_update = + L1UpdateBuilder::default().with_requests(vec![dummy_request; 20]).build(); - forward_to_block::(11); - Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(BOB), second_update).unwrap(); + forward_to_block::(10); + Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), first_update).unwrap(); - forward_to_block::(14); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); + forward_to_block::(11); + Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(BOB), second_update).unwrap(); - forward_to_block::(15); - forward_to_next_block::(); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 10u128.into()); + forward_to_block::(14); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); - forward_to_next_block::(); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 20u128.into()); - }); + forward_to_block::(15); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 10u128.into()); + + forward_to_next_block::(); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 11u128.into()); + + forward_to_next_block::(); + forward_to_next_block::(); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 20u128.into()); + }); } #[test] @@ -1000,45 +1047,47 @@ fn reject_second_update_in_the_same_block() { #[test] #[serial] fn accept_consecutive_update_split_into_two() { - ExtBuilder::new().execute_with_default_mocks(|| { - forward_to_block::(10); - - // imagine that there are 20 request on L1 waiting to be processed - // they need to be split into 2 update_l2_from_l1_unsafe calls + ExtBuilder::new() + .issue(ALICE, ETH_TOKEN_ADDRESS_MGX, 0u128) + .execute_with_default_mocks(|| { + forward_to_block::(10); - let dummy_update = L1UpdateRequest::Deposit(Default::default()); + // imagine that there are 20 request on L1 waiting to be processed + // they need to be split into 2 update_l2_from_l1_unsafe calls - let first_update = L1UpdateBuilder::default() - .with_requests(vec![ - dummy_update.clone(); - (2 * Rolldown::get_max_requests_per_block()) as usize - ]) - .with_offset(1u128) - .build(); + let dummy_update = L1UpdateRequest::Deposit(messages::Deposit { + requestId: Default::default(), + depositRecipient: DummyAddressConverter::convert_back(CHARLIE), + tokenAddress: ETH_TOKEN_ADDRESS, + amount: sp_core::U256::from(MILLION), + timeStamp: sp_core::U256::from(1), + ferryTip: sp_core::U256::from(0), + }); - Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), first_update).unwrap(); + let first_update = L1UpdateBuilder::default() + .with_requests(vec![ + dummy_update.clone(); + (2 * Rolldown::get_max_requests_per_block()) as usize + ]) + .with_offset(1u128) + .build(); - forward_to_next_block::(); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0); + Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), first_update).unwrap(); - forward_to_block::(15); - let mut expected_updates = L2Requests::::iter_prefix(Chain::Ethereum) - .map(|(k, _)| k.id) - .collect::>(); - expected_updates.sort(); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0); + forward_to_next_block::(); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0); - forward_to_next_block::(); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 10); + forward_to_block::(15); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 10); - forward_to_next_block::(); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 20); - }); + forward_to_next_block::(); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 20); + }); } #[test] #[serial] -fn execute_two_consecutive_incremental_reqeusts() { +fn execute_two_consecutive_incremental_requests() { ExtBuilder::new() .issue(ALICE, ETH_TOKEN_ADDRESS_MGX, 0u128) .execute_with_default_mocks(|| { @@ -1071,9 +1120,9 @@ fn execute_two_consecutive_incremental_reqeusts() { assert_eq!(TokensOf::::free_balance(ETH_TOKEN_ADDRESS_MGX, &CHARLIE), 0_u128); forward_to_block::(15); - forward_to_next_block::(); assert_eq!(TokensOf::::free_balance(ETH_TOKEN_ADDRESS_MGX, &CHARLIE), MILLION); + forward_to_next_block::(); forward_to_next_block::(); assert_eq!( TokensOf::::free_balance(ETH_TOKEN_ADDRESS_MGX, &CHARLIE), @@ -1293,7 +1342,7 @@ fn test_sequencer_unstaking() { let is_maintenance_mock = MockMaintenanceStatusProviderApi::is_maintenance_context(); is_maintenance_mock.expect().return_const(false); forward_to_block::(1); - let dispute_period_length = Rolldown::get_dispute_period(); + let dispute_period_length = Rolldown::get_dispute_period(consts::CHAIN).unwrap(); let now = frame_system::Pallet::::block_number().saturated_into::(); LastUpdateBySequencer::::insert((consts::CHAIN, ALICE), now); @@ -1537,7 +1586,7 @@ fn test_maintenance_mode_blocks_extrinsics() { #[test] #[serial] fn test_single_sequencer_cannot_cancel_request_without_cancel_rights_in_same_block() { - ExtBuilder::single_sequencer(BOB) + ExtBuilder::new_without_default_sequencers() .issue(ETH_RECIPIENT_ACCOUNT_MGX, ETH_TOKEN_ADDRESS_MGX, MILLION) .execute_with_default_mocks(|| { forward_to_block::(10); @@ -1581,7 +1630,7 @@ fn test_single_sequencer_cannot_cancel_request_without_cancel_rights_in_same_blo #[test] #[serial] fn test_single_sequencer_cannot_cancel_request_without_cancel_rights_in_next_block() { - ExtBuilder::single_sequencer(BOB) + ExtBuilder::new_without_default_sequencers() .issue(ETH_RECIPIENT_ACCOUNT_MGX, ETH_TOKEN_ADDRESS_MGX, MILLION) .execute_with_default_mocks(|| { forward_to_block::(10); @@ -1687,7 +1736,8 @@ fn consider_awaiting_cancel_resolutions_and_cancel_disputes_when_assigning_initi ) .unwrap(); - forward_to_block::(12); + forward_to_next_block::(); + forward_to_next_block::(); assert_eq!( *SequencersRights::::get(consts::CHAIN).get(&ALICE).unwrap(), SequencerRights { read_rights: 1u128, cancel_rights: 2u128 } @@ -2622,6 +2672,12 @@ fn test_sequencer_updates_are_ignored_and_removed_in_maintanance_mode() { assert!(PendingSequencerUpdates::::contains_key(15u128, Chain::Ethereum)); forward_to_block::(15); + + is_maintenance_mock.checkpoint(); + let is_maintenance_mock = MockMaintenanceStatusProviderApi::is_maintenance_context(); + is_maintenance_mock.expect().return_const(true); + forward_to_next_block::(); + forward_to_next_block::(); assert!(!PendingSequencerUpdates::::contains_key(15u128, Chain::Ethereum)); assert_event_emitted!(Event::L1ReadIgnoredBecauseOfMaintenanceMode { chain: consts::CHAIN, @@ -2649,7 +2705,6 @@ fn test_reqeust_scheduled_for_execution_are_not_execute_in_the_same_block() { assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); forward_to_block::(15); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); assert_event_emitted!(Event::L1ReadScheduledForExecution { chain: consts::CHAIN, hash: H256::from(hex!( @@ -2657,7 +2712,7 @@ fn test_reqeust_scheduled_for_execution_are_not_execute_in_the_same_block() { )), }); - forward_to_block::(16); + forward_to_next_block::(); assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 1u128.into()); assert_event_emitted!(Event::RequestProcessedOnL2 { chain: consts::CHAIN, @@ -2679,32 +2734,31 @@ fn test_sequencer_updates_that_went_though_dispute_period_are_not_executed_in_ma forward_to_block::(10); let deposit_update = L1UpdateBuilder::default() - .with_requests(vec![L1UpdateRequest::Deposit(messages::Deposit::default())]) + .with_requests(vec![L1UpdateRequest::Deposit(messages::Deposit::default()); 11]) .build(); + let update_hash = deposit_update.abi_encode_hash(); Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), deposit_update) .unwrap(); assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); forward_to_block::(15); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 10u128.into()); assert_event_emitted!(Event::L1ReadScheduledForExecution { chain: consts::CHAIN, - hash: H256::from(hex!( - "75207958ce929568193284a176e012a8cf5058dc19d73dafee61a419eb667398" - )), + hash: update_hash, }); - is_maintenance_mock.checkpoint(); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 10u128.into()); + is_maintenance_mock.checkpoint(); let is_maintenance_mock = MockMaintenanceStatusProviderApi::is_maintenance_context(); is_maintenance_mock.expect().return_const(true); + forward_to_block::(20); - forward_to_block::(50); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); is_maintenance_mock.checkpoint(); - let is_maintenance_mock = MockMaintenanceStatusProviderApi::is_maintenance_context(); is_maintenance_mock.expect().return_const(false); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); + forward_to_block::(100); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 10u128.into()); }) } @@ -2747,7 +2801,7 @@ fn test_sequencer_updates_that_went_though_dispute_period_are_not_scheduled_for_ #[test] #[serial] -fn test_sequencer_can_submit_same_update_again_after_maintenance_mode() { +fn test_sequencer_can_submit_update_with_remaining_elements() { ExtBuilder::new() .issue(ALICE, ETH_TOKEN_ADDRESS_MGX, MILLION) .issue(BOB, ETH_TOKEN_ADDRESS_MGX, MILLION) @@ -2756,22 +2810,23 @@ fn test_sequencer_can_submit_same_update_again_after_maintenance_mode() { is_maintenance_mock.expect().return_const(false); forward_to_block::(10); - let deposit_update = L1UpdateBuilder::default() - .with_requests(vec![L1UpdateRequest::Deposit(messages::Deposit::default())]) - .build(); - Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), deposit_update) - .unwrap(); + let requests = vec![L1UpdateRequest::Deposit(messages::Deposit::default()); 11]; + let deposit_update = L1UpdateBuilder::default().with_requests(requests.clone()).build(); + Rolldown::update_l2_from_l1_unsafe( + RuntimeOrigin::signed(ALICE), + deposit_update.clone(), + ) + .unwrap(); assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); forward_to_block::(15); assert_event_emitted!(Event::L1ReadScheduledForExecution { chain: consts::CHAIN, - hash: H256::from(hex!( - "75207958ce929568193284a176e012a8cf5058dc19d73dafee61a419eb667398" - )), + hash: deposit_update.abi_encode_hash() }); - is_maintenance_mock.checkpoint(); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 10u128.into()); + is_maintenance_mock.checkpoint(); let is_maintenance_mock = MockMaintenanceStatusProviderApi::is_maintenance_context(); is_maintenance_mock.expect().return_const(true); @@ -2783,13 +2838,14 @@ fn test_sequencer_can_submit_same_update_again_after_maintenance_mode() { forward_to_block::(20); let deposit_update = L1UpdateBuilder::default() - .with_requests(vec![L1UpdateRequest::Deposit(messages::Deposit::default())]) + .with_requests(requests.into_iter().skip(10).collect()) + .with_offset(11) .build(); Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), deposit_update) .unwrap(); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 0u128.into()); - forward_to_block::(26); - assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 1u128.into()); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 10u128.into()); + forward_to_block::(25); + assert_eq!(LastProcessedRequestOnL2::::get(Chain::Ethereum), 11u128.into()); }) } @@ -3317,3 +3373,56 @@ fn ferry_already_executed_deposit_fails() { ); }); } + +#[test] +#[serial] +fn reject_update_for_unknown_chain_id() { + ExtBuilder::new() + .issue(ALICE, ETH_TOKEN_ADDRESS_MGX, 0u128) + .execute_with_default_mocks(|| { + forward_to_block::(10); + let update = L1UpdateBuilder::default() + .with_requests(vec![L1UpdateRequest::Deposit(messages::Deposit { + requestId: Default::default(), + depositRecipient: DummyAddressConverter::convert_back(CHARLIE), + tokenAddress: ETH_TOKEN_ADDRESS, + amount: sp_core::U256::from(MILLION), + timeStamp: sp_core::U256::from(1), + ferryTip: sp_core::U256::from(0), + })]) + .build_for_chain(Chain::Arbitrum); + assert_err!( + Rolldown::update_l2_from_l1_unsafe(RuntimeOrigin::signed(ALICE), update.clone()), + Error::::UninitializedChainId + ); + }); +} + +#[test] +#[serial] +fn set_dispute_period() { + ExtBuilder::new() + .issue(ALICE, ETH_TOKEN_ADDRESS_MGX, 0u128) + .execute_with_default_mocks(|| { + forward_to_block::(10); + + let dispute_period = Rolldown::get_dispute_period(Chain::Ethereum).unwrap(); + Rolldown::set_dispute_period( + RuntimeOrigin::root(), + Chain::Ethereum, + dispute_period + 1u128, + ) + .unwrap(); + + assert_event_emitted!(Event::DisputePeriodSet { + chain: messages::Chain::Ethereum, + dispute_period_length: dispute_period + 1u128 + }); + + Rolldown::set_dispute_period(RuntimeOrigin::root(), Chain::Arbitrum, 1234).unwrap(); + assert_event_emitted!(Event::DisputePeriodSet { + chain: messages::Chain::Arbitrum, + dispute_period_length: 1234 + }); + }); +} diff --git a/pallets/rolldown/src/weight_utils.rs b/pallets/rolldown/src/weight_utils.rs new file mode 100644 index 000000000..44ca7d71f --- /dev/null +++ b/pallets/rolldown/src/weight_utils.rs @@ -0,0 +1,30 @@ +use sp_runtime::traits::Saturating; + +/// accounts for cost of reading huge L1Update from runtime storage (rocksdb) +pub const fn get_read_scalling_factor(size: usize) -> u128 { + const BASE_READ_COST: u128 = 25; + let approximated_cost = match size { + 0..=50 => 25u128, + 51..=100 => 45u128, + 101..=500 => 210u128, + 501..=1000 => 400u128, + 1001..=5000 => 1800u128, + _ => 2800u128, + }; + approximated_cost.saturating_div(BASE_READ_COST).saturating_add(1u128) +} + +/// accounts for cost of writing huge L1Update from runtime storage (rocksdb) +pub const fn get_write_scalling_factor(size: usize) -> u128 { + const BASE_WRITE_COST: u128 = 100; + + let approximated_cost = match size { + 0..=50 => 25u128, + 51..=100 => 150u128, + 101..=500 => 700u128, + 501..=1000 => 1050u128, + 1001..=5000 => 5000u128, + _ => 9000u128, + }; + approximated_cost.saturating_div(BASE_WRITE_COST).saturating_add(1u128) +} diff --git a/pallets/rolldown/src/weights.rs b/pallets/rolldown/src/weights.rs index 098114150..6bbf88b7b 100644 --- a/pallets/rolldown/src/weights.rs +++ b/pallets/rolldown/src/weights.rs @@ -69,7 +69,22 @@ pub trait WeightInfo { fn ferry_deposit_unsafe() -> Weight; fn process_deposit() -> Weight; fn process_cancel_resolution() -> Weight; - fn schedule_requests(x: u32, ) -> Weight; + fn load_next_update_from_execution_queue() -> Weight{ + (Weight::from_parts(22_558_000, 0)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + fn schedule_request_for_execution_if_dispute_period_has_passsed() -> Weight{ + (Weight::from_parts(22_558_000, 0)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + fn maybe_create_batch() -> Weight{ + (Weight::from_parts(22_558_000, 0)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + fn execute_requests_from_execute_queue() -> Weight{ + (Weight::from_parts(22_558_000, 0)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } } // For backwards compatibility and tests @@ -319,17 +334,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(12 as u64)) .saturating_add(RocksDbWeight::get().writes(9 as u64)) } - // Storage: `Rolldown::MaxAcceptedRequestIdOnl2` (r:1 w:1) - // Proof: `Rolldown::MaxAcceptedRequestIdOnl2` (`max_values`: None, `max_size`: Some(33), added: 2508, mode: `MaxEncodedLen`) - // Storage: `Rolldown::LastScheduledUpdateIdInExecutionQueue` (r:1 w:1) - // Proof: `Rolldown::LastScheduledUpdateIdInExecutionQueue` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - // Storage: `Rolldown::UpdatesExecutionQueue` (r:0 w:1) - // Proof: `Rolldown::UpdatesExecutionQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn schedule_requests(x: u32, ) -> Weight { - (Weight::from_parts(8_898_848, 0)) - // Standard Error: 8_479 - .saturating_add((Weight::from_parts(299_825, 0)).saturating_mul(x as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - } } diff --git a/rollup/node/Cargo.toml b/rollup/node/Cargo.toml index dc92ab5e5..64e52d242 100644 --- a/rollup/node/Cargo.toml +++ b/rollup/node/Cargo.toml @@ -99,6 +99,7 @@ substrate-build-script-utils = { workspace = true } [features] default = ["std"] +fast-runtime = [] std = [ "rollup-runtime/std", "xyk-rpc/std", diff --git a/rollup/node/src/chain_spec.rs b/rollup/node/src/chain_spec.rs index 8499efd8d..4b6d36760 100644 --- a/rollup/node/src/chain_spec.rs +++ b/rollup/node/src/chain_spec.rs @@ -404,7 +404,30 @@ fn rollup_genesis( .cloned() .collect(), }, - rolldown: rollup_runtime::RolldownConfig { _phantom: Default::default() }, + #[cfg(not(feature = "fast-runtime"))] + rolldown: rollup_runtime::RolldownConfig { + _phantom: Default::default(), + dispute_periods: [ + (pallet_rolldown::messages::Chain::Ethereum, 300u128), + (pallet_rolldown::messages::Chain::Arbitrum, 600u128), + (pallet_rolldown::messages::Chain::Base, 600u128), + ] + .iter() + .cloned() + .collect(), + }, + #[cfg(feature = "fast-runtime")] + rolldown: rollup_runtime::RolldownConfig { + _phantom: Default::default(), + dispute_periods: [ + (pallet_rolldown::messages::Chain::Ethereum, 10u128), + (pallet_rolldown::messages::Chain::Arbitrum, 15u128), + (pallet_rolldown::messages::Chain::Base, 15u128), + ] + .iter() + .cloned() + .collect(), + }, metamask: rollup_runtime::MetamaskConfig { name: "Gasp".to_string(), version: "0.0.1".to_string(), diff --git a/rollup/runtime/src/lib.rs b/rollup/runtime/src/lib.rs index 69e4918a4..80a8671e6 100644 --- a/rollup/runtime/src/lib.rs +++ b/rollup/runtime/src/lib.rs @@ -780,7 +780,6 @@ impl pallet_rolldown::Config for Runtime { type SequencerStakingProvider = SequencerStaking; type Tokens = orml_tokens::MultiTokenCurrencyAdapter; type AssetRegistryProvider = cfg::orml_asset_registry::AssetRegistryProvider; - type DisputePeriodLength = cfg::pallet_rolldown::DisputePeriodLength; type RequestsPerBlock = cfg::pallet_rolldown::RequestsPerBlock; // We havent spent any time considering rights multiplier being > 1. There might be some corner // cases that should be investigated. diff --git a/rollup/runtime/src/runtime_config.rs b/rollup/runtime/src/runtime_config.rs index 5ca4611b5..9412ed467 100644 --- a/rollup/runtime/src/runtime_config.rs +++ b/rollup/runtime/src/runtime_config.rs @@ -1324,14 +1324,12 @@ pub mod config { #[cfg(feature = "fast-runtime")] parameter_types! { - pub const DisputePeriodLength: u32 = 10; pub const MerkleRootAutomaticBatchPeriod: u128 = 25; pub const MerkleRootAutomaticBatchSize: u128 = 32; } #[cfg(not(feature = "fast-runtime"))] parameter_types! { - pub const DisputePeriodLength: u32 = 300; pub const MerkleRootAutomaticBatchPeriod: u128 = 1200; pub const MerkleRootAutomaticBatchSize: u128 = 1024; } diff --git a/rollup/runtime/src/weights/pallet_rolldown.rs b/rollup/runtime/src/weights/pallet_rolldown.rs index 8846e77f7..010d7f301 100644 --- a/rollup/runtime/src/weights/pallet_rolldown.rs +++ b/rollup/runtime/src/weights/pallet_rolldown.rs @@ -69,7 +69,22 @@ pub trait WeightInfo { fn ferry_deposit_unsafe() -> Weight; fn process_deposit() -> Weight; fn process_cancel_resolution() -> Weight; - fn schedule_requests(x: u32, ) -> Weight; + fn load_next_update_from_execution_queue() -> Weight{ + (Weight::from_parts(22_558_000, 0)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + fn schedule_request_for_execution_if_dispute_period_has_passsed() -> Weight{ + (Weight::from_parts(22_558_000, 0)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + fn maybe_create_batch() -> Weight{ + (Weight::from_parts(22_558_000, 0)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + fn execute_requests_from_execute_queue() -> Weight{ + (Weight::from_parts(22_558_000, 0)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } } /// Weights for pallet_rolldown using the Mangata node and recommended hardware. @@ -320,19 +335,6 @@ impl pallet_rolldown::WeightInfo for ModuleWeight { .saturating_add(T::DbWeight::get().reads(12 as u64)) .saturating_add(T::DbWeight::get().writes(9 as u64)) } - // Storage: `Rolldown::MaxAcceptedRequestIdOnl2` (r:1 w:1) - // Proof: `Rolldown::MaxAcceptedRequestIdOnl2` (`max_values`: None, `max_size`: Some(33), added: 2508, mode: `MaxEncodedLen`) - // Storage: `Rolldown::LastScheduledUpdateIdInExecutionQueue` (r:1 w:1) - // Proof: `Rolldown::LastScheduledUpdateIdInExecutionQueue` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - // Storage: `Rolldown::UpdatesExecutionQueue` (r:0 w:1) - // Proof: `Rolldown::UpdatesExecutionQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn schedule_requests(x: u32, ) -> Weight { - (Weight::from_parts(8_898_848, 0)) - // Standard Error: 8_479 - .saturating_add((Weight::from_parts(299_825, 0)).saturating_mul(x as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } } // For backwards compatibility and tests @@ -582,17 +584,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(12 as u64)) .saturating_add(RocksDbWeight::get().writes(9 as u64)) } - // Storage: `Rolldown::MaxAcceptedRequestIdOnl2` (r:1 w:1) - // Proof: `Rolldown::MaxAcceptedRequestIdOnl2` (`max_values`: None, `max_size`: Some(33), added: 2508, mode: `MaxEncodedLen`) - // Storage: `Rolldown::LastScheduledUpdateIdInExecutionQueue` (r:1 w:1) - // Proof: `Rolldown::LastScheduledUpdateIdInExecutionQueue` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - // Storage: `Rolldown::UpdatesExecutionQueue` (r:0 w:1) - // Proof: `Rolldown::UpdatesExecutionQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn schedule_requests(x: u32, ) -> Weight { - (Weight::from_parts(8_898_848, 0)) - // Standard Error: 8_479 - .saturating_add((Weight::from_parts(299_825, 0)).saturating_mul(x as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - } }