diff --git a/core/src/reservation.rs b/core/src/reservation.rs index 23fe6dd6d21..e5b1731624c 100644 --- a/core/src/reservation.rs +++ b/core/src/reservation.rs @@ -22,7 +22,7 @@ use crate::{ ids::{prelude::*, MessageId, ReservationId}, message::IncomingDispatch, }; -use alloc::collections::BTreeMap; +use alloc::{collections::BTreeMap, format}; use gear_core_errors::ReservationError; use scale_info::{ scale::{Decode, Encode}, @@ -184,10 +184,15 @@ impl GasReserver { ); if maybe_reservation.is_some() { - unreachable!( - "Duplicate reservation was created with message id {} and nonce {}", - self.message_id, self.nonce.0, + let err_msg = format!( + "GasReserver::reserve: created a duplicate reservation. \ + Message id - {message_id}, nonce - {nonce}", + message_id = self.message_id, + nonce = self.nonce.0 ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } Ok(id) diff --git a/pallets/gear/src/internal.rs b/pallets/gear/src/internal.rs index 5b2d1a8a66c..8c3f60caa98 100644 --- a/pallets/gear/src/internal.rs +++ b/pallets/gear/src/internal.rs @@ -23,7 +23,7 @@ use crate::{ GasBalanceOf, GasHandlerOf, GasNodeIdOf, GearBank, MailboxOf, Pallet, QueueOf, SchedulingCostOf, TaskPoolOf, WaitlistOf, }; -use alloc::collections::BTreeSet; +use alloc::{collections::BTreeSet, format}; use common::{ event::{ MessageWaitedReason, MessageWaitedRuntimeReason::*, MessageWokenReason, Reason::*, @@ -52,6 +52,10 @@ use sp_runtime::{ DispatchError, TokenError, }; +type MailboxError = <<::Messenger as Messenger>::Mailbox as Mailbox>::OutputError; +type WaitlistError = + <<::Messenger as Messenger>::Waitlist as Waitlist>::OutputError; + /// [`HoldBound`] builder #[derive(Clone, Debug)] pub(crate) struct HoldBoundBuilder { @@ -107,8 +111,15 @@ impl HoldBoundBuilder { /// by querying it's gas limit. pub fn maximum_for_message(self, message_id: MessageId) -> HoldBound { // Querying gas limit. Fails in cases of `GasTree` invalidations. - let gas_limit = GasHandlerOf::::get_limit(message_id) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + let gas_limit = GasHandlerOf::::get_limit(message_id).unwrap_or_else(|e| { + let err_msg = format!( + "HoldBoundBuilder::maximum_for_message: failed getting message gas limit. \ + Message id - {message_id}. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); self.maximum_for(gas_limit) } @@ -236,21 +247,40 @@ where } // Spending gas amount from `GasNode`. - GasHandlerOf::::spend(id, amount) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + GasHandlerOf::::spend(id, amount).unwrap_or_else(|e| { + let err_msg = format!( + "spend_gas: failed spending gas. Message id - {id}, amount - {amount}. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Querying external id. Fails in cases of `GasTree` invalidations. - let (external, multiplier, _) = GasHandlerOf::::get_origin_node(id) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + let (external, multiplier, _) = GasHandlerOf::::get_origin_node(id).unwrap_or_else(|e| { + let err_msg = format!( + "spend_gas: failed getting origin node for the current one. Message id - {id}, Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Transferring reserved funds from external user to destination. - let result = if let Some(account_id) = to { - GearBank::::spend_gas_to(&account_id, &external, amount, multiplier) + if let Some(account_id) = &to { + GearBank::::spend_gas_to(account_id, &external, amount, multiplier) } else { GearBank::::spend_gas(&external, amount, multiplier) - }; - - result.unwrap_or_else(|e| unreachable!("Gear bank error: {e:?}")); + }.unwrap_or_else(|e| { + let err_msg = format!( + "spend_gas: failed spending value for gas in gear bank. \ + Spender - {external:?}, spending to - {to:?}, amount - {amount}, multiplier - {multiplier:?}. \ + Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }) } /// Consumes message by given `MessageId` or gas reservation by `ReservationId`. @@ -260,8 +290,14 @@ where let id = id.into(); // Consuming `GasNode`, returning optional outcome with imbalance. - let outcome = GasHandlerOf::::consume(id) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + let outcome = GasHandlerOf::::consume(id).unwrap_or_else(|e| { + let err_msg = format!( + "consume_and_retrieve: failed consuming the rest of gas. Message id - {id:?}. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); // Unreserving funds, if imbalance returned. if let Some((imbalance, multiplier, external)) = outcome { @@ -275,7 +311,16 @@ where ); GearBank::::withdraw_gas(&external, gas_left, multiplier) - .unwrap_or_else(|e| unreachable!("Gear bank error: {e:?}")); + .unwrap_or_else(|e| { + let err_msg = format!( + "consume_and_retrieve: failed withdrawing value for gas from bank. \ + Message id - {id:?}, withdraw to - {external:?}, amount - {gas_left}, multiplier - {multiplier:?}. \ + Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); } } } @@ -329,8 +374,15 @@ where let amount = storage_type.try_into().map_or_else( |_| duration.saturating_mul(cost), |lock_id| { - let prepaid = GasHandlerOf::::unlock_all(id, lock_id) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + let prepaid = GasHandlerOf::::unlock_all(id, lock_id).unwrap_or_else(|e| { + let err_msg = format!( + "charge_for_hold: failed unlocking locked gas. Message id - {id:?}, lock id - {lock_id:?}, \ + Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); prepaid.min(duration.saturating_mul(cost)) }, ); @@ -362,6 +414,10 @@ where maximal_hold }; + // Taking data for tasks and error logs. + let message_id = dispatch.id(); + let destination = dispatch.destination(); + // Validating duration. if hold.expected_duration().is_zero() { // TODO: Replace with unreachable call after: @@ -372,23 +428,50 @@ where // Locking funds for holding. let lock_id = hold.lock_id().unwrap_or_else(|| { - unreachable!("Waitlist storage is guaranteed to have an associated lock id") + // Waitlist storage is guaranteed to have an associated lock id + let err_msg = "wait_dispatch: No associated lock id for the waitlist storage"; + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); + GasHandlerOf::::lock(message_id, lock_id, hold.lock_amount()).unwrap_or_else(|e| { + let err_msg = format!( + "wait_dispatch: failed locking gas for the waitlist hold. \ + Message id - {message_id}, lock amount - {lock}. Got error - {e:?}", + lock = hold.lock_amount() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); }); - GasHandlerOf::::lock(dispatch.id(), lock_id, hold.lock_amount()) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); // Querying origin message id. Fails in cases of `GasTree` invalidations. - let origin_msg = GasHandlerOf::::get_origin_key(GasNodeId::Node(dispatch.id())) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + let origin_msg = GasHandlerOf::::get_origin_key(GasNodeId::Node(message_id)) + .unwrap_or_else(|e| { + let err_msg = format!( + "wait_dispatch: failed getting origin node for the current one. \ + Message id - {message_id}, Got error - {e:?}", + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); match reason { Runtime(WaitForCalled | WaitUpToCalledFull) => { let expected = hold.expected(); - let task = ScheduledTask::WakeMessage(dispatch.destination(), dispatch.id()); + let task = ScheduledTask::WakeMessage(destination, message_id); if !TaskPoolOf::::contains(&expected, &task) { - TaskPoolOf::::add(expected, task) - .unwrap_or_else(|e| unreachable!("Scheduling logic invalidated! {:?}", e)); + TaskPoolOf::::add(expected, task).unwrap_or_else(|e| { + let err_msg = format!( + "wait_dispatch: failed adding task for waking message. \ + Expected bn - {expected:?}, program id - {destination}, message id - {message_id}. Got error - {e:?}", + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } } Runtime(WaitCalled | WaitUpToCalled) => { @@ -396,7 +479,16 @@ where hold.expected(), ScheduledTask::RemoveFromWaitlist(dispatch.destination(), dispatch.id()), ) - .unwrap_or_else(|e| unreachable!("Scheduling logic invalidated! {:?}", e)); + .unwrap_or_else(|e| { + let err_msg = format!( + "wait_dispatch: failed adding task for removing message from waitlist. \ + Expected bn - {bn:?}, program id - {destination}, message id - {message_id}. Got error - {e:?}", + bn = hold.expected(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } System(reason) => match reason {}, } @@ -411,7 +503,16 @@ where // Adding message in waitlist. WaitlistOf::::insert(dispatch, hold.expected()) - .unwrap_or_else(|e| unreachable!("Waitlist corrupted! {:?}", e)); + .unwrap_or_else(|e| { + let err_msg = format!( + "wait_dispatch: failed inserting message to the wailist. \ + Expected bn - {bn:?}, program id - {destination}, message id - {message_id}. Got error - {e:?}", + bn = hold.expected(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }) } /// Wakes dispatch from waitlist, permanently charged for hold with @@ -420,11 +521,10 @@ where program_id: ProgramId, message_id: MessageId, reason: MessageWokenReason, - ) -> Option { + ) -> Result> { // Removing dispatch from waitlist, doing wake requirements if found. WaitlistOf::::remove(program_id, message_id) .map(|v| Self::wake_dispatch_requirements(v, reason)) - .ok() } /// Charges and deposits event for already taken from waitlist dispatch. @@ -461,11 +561,10 @@ where user_id: T::AccountId, message_id: MessageId, reason: UserMessageReadReason, - ) -> Option { + ) -> Result> { // Removing message from mailbox, doing read requirements if found. MailboxOf::::remove(user_id, message_id) .map(|v| Self::read_message_requirements(v, reason)) - .ok() } /// Charges and deposits event for already taken from mailbox message. @@ -490,7 +589,16 @@ where // Transferring reserved funds, associated with the message. GearBank::::transfer_value(&from, &user_id, mailboxed.value().unique_saturated_into()) - .unwrap_or_else(|e| unreachable!("Gear bank error: {e:?}")); + .unwrap_or_else(|e| { + let err_msg = format!( + "read_message_requirements: failed transferring value on gear bank. \ + Sender - {from:?}, destination - {user_id:?}, value - {value}. Got error - {e:?}", + value = mailboxed.value(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Depositing appropriate event. Pallet::::deposit_event(Event::UserMessageRead { @@ -525,17 +633,32 @@ where ) { // Validating delay. if delay.is_zero() { - unreachable!("Delayed sending with zero delay appeared"); + let err_msg = "send_delayed_dispatch: delayed sending with zero delay appeared"; + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } // Validating stash from duplicates. if DispatchStashOf::::contains_key(&dispatch.id()) { - unreachable!("Stash logic invalidated!") + let err_msg = format!( + "send_delayed_dispatch: stash already has the message id - {id}", + id = dispatch.id() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } // Validating dispatch wasn't sent from system with delay. if dispatch.is_error_reply() || matches!(dispatch.kind(), DispatchKind::Signal) { - unreachable!("Scheduling logic invalidated"); + let err_msg = format!( + "send_delayed_dispatch: message of an invalid kind is sent: {kind:?}", + kind = dispatch.kind() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } // Indicates that message goes to mailbox and gas should be charged for holding @@ -570,8 +693,15 @@ where .gas_limit() .or_else(|| { // Querying gas limit. Fails in cases of `GasTree` invalidations. - let gas_limit = GasHandlerOf::::get_limit(sender_node) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + let gas_limit = GasHandlerOf::::get_limit(sender_node).unwrap_or_else(|e| { + let err_msg = format!( + "send_delayed_dispatch: failed getting message gas limit. \ + Lock sponsor id - {sender_node}. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // If available gas is greater then threshold, // than threshold can be used. @@ -594,8 +724,17 @@ where gas_for_delay }; - GasHandlerOf::::cut(sender_node, dispatch.id(), gas_amount) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + GasHandlerOf::::cut(sender_node, dispatch.id(), gas_amount).unwrap_or_else(|e| { + let err_msg = format!( + "send_delayed_dispatch: failed creating cut node. \ + Origin node - {sender_node}, cut node id - {id}, amount - {gas_amount}. \ + Got error - {e:?}", + id = dispatch.id() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Generating gas node for future auto reply. // TODO: use `sender_node` (e.g. reservation case) as first argument after #1828. @@ -615,13 +754,35 @@ where // Locking funds for holding. let lock_id = delay_hold.lock_id().unwrap_or_else(|| { - unreachable!("DispatchStash storage is guaranteed to have an associated lock id") + // Dispatch stash storage is guaranteed to have an associated lock id + let err_msg = + "send_delayed_dispatch: No associated lock id for the dispatch stash storage"; + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); }); GasHandlerOf::::lock(dispatch.id(), lock_id, delay_hold.lock_amount()) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + .unwrap_or_else(|e| { + let err_msg = format!( + "send_delayed_dispatch: failed locking gas for the user message stash hold. \ + Message id - {message_id}, lock amount - {lock}. Got error - {e:?}", + message_id = dispatch.id(), + lock = delay_hold.lock_amount() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); if delay_hold.expected_duration().is_zero() { - unreachable!("Hold duration cannot be zero"); + let err_msg = format!( + "send_delayed_dispatch: user message got zero duration hold bound for dispatch stash. \ + Requested duration - {delay}, block cost - {cost}, source - {from:?}", + cost = CostsPerBlockOf::::by_storage_type(StorageType::DispatchStash) + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } delay_hold.expected() @@ -634,12 +795,17 @@ where dispatch.is_reply(), ), (None, None) => Self::split(sender_node, dispatch.id(), dispatch.is_reply()), - (Some(_gas_limit), Some(_reservation_id)) => { + (Some(gas_limit), Some(reservation_id)) => { // TODO: #1828 - unreachable!( - "Sending dispatch with gas limit from reservation \ - is currently unimplemented and there is no way to send such dispatch" + let err_msg = format!( + "send_delayed_dispatch: sending dispatch with gas from reservation isn't implemented. \ + Message - {message_id}, sender - {sender}, gas limit - {gas_limit}, reservation - {reservation_id}", + message_id = dispatch.id(), + sender = dispatch.source(), ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } (None, Some(reservation_id)) => { Self::split(reservation_id, dispatch.id(), dispatch.is_reply()); @@ -649,13 +815,35 @@ where // Locking funds for holding. let lock_id = delay_hold.lock_id().unwrap_or_else(|| { - unreachable!("DispatchStash storage is guaranteed to have an associated lock id") + // Dispatch stash storage is guaranteed to have an associated lock id + let err_msg = + "send_delayed_dispatch: No associated lock id for the dispatch stash storage"; + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); }); GasHandlerOf::::lock(dispatch.id(), lock_id, delay_hold.lock_amount()) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + .unwrap_or_else(|e| { + let err_msg = format!( + "send_delayed_dispatch: failed locking gas for the program message stash hold. \ + Message id - {message_id}, lock amount - {lock}. Got error - {e:?}", + message_id = dispatch.id(), + lock = delay_hold.lock_amount() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); if delay_hold.expected_duration().is_zero() { - unreachable!("Hold duration cannot be zero"); + let err_msg = format!( + "send_delayed_dispatch: program message got zero duration hold bound for dispatch stash. \ + Requested duration - {delay}, block cost - {cost}, source - {from:?}", + cost = CostsPerBlockOf::::by_storage_type(StorageType::DispatchStash) + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } delay_hold.expected() @@ -663,8 +851,15 @@ where if !dispatch.value().is_zero() { // Reserving value from source for future transfer or unreserve. - GearBank::::deposit_value(&from, value, false) - .unwrap_or_else(|e| unreachable!("Gear bank error: {e:?}")); + GearBank::::deposit_value(&from, value, false).unwrap_or_else(|e| { + let err_msg = format!( + "send_delayed_dispatch: failed depositting value on gear bank. \ + From - {from:?}, value - {value:?}. Got error - {e:?}", + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } // Saving id to allow moving dispatch further. @@ -691,8 +886,15 @@ where // Adding removal request in task pool. let task_bn = Self::block_number().saturating_add(delay.unique_saturated_into()); - TaskPoolOf::::add(task_bn, task) - .unwrap_or_else(|e| unreachable!("Scheduling logic invalidated! {:?}", e)); + TaskPoolOf::::add(task_bn, task).unwrap_or_else(|e| { + let err_msg = format!( + "send_delayed_dispatch: failed adding task for delayed message sending. \ + Message to user - {to_user}, message id - {message_id}. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } /// Sends message to user. @@ -719,8 +921,15 @@ where .gas_limit() .or_else(|| { // Querying gas limit. Fails in cases of `GasTree` invalidations. - let gas_limit = GasHandlerOf::::get_limit(msg_id) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + let gas_limit = GasHandlerOf::::get_limit(msg_id).unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message: failed getting message gas limit. \ + Lock sponsor id - {msg_id}. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // If available gas is greater then threshold, // than threshold can be used. @@ -728,15 +937,27 @@ where }) .unwrap_or_default(); + // Taking data for error log + let message_id = message.id(); + let from = message.source(); + let to = message.destination(); + // Converting message into stored one and user one. let message = message.into_stored(); - let message: UserMessage = message - .try_into() - .unwrap_or_else(|_| unreachable!("Signal message sent to user")); + let message: UserMessage = message.try_into().unwrap_or_else(|_| { + // Signal message sent to user + let err_msg = format!( + "send_user_message: failed convertion from stored into user message. \ + Message id - {message_id}, program id - {from}, destination - {to}", + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); // Taking data for funds manipulations. let from = message.source().cast(); - let to = message.destination().cast(); + let to = message.destination().cast::(); let value = message.value().unique_saturated_into(); // If gas limit can cover threshold, message will be added to mailbox, @@ -747,36 +968,92 @@ where // Validating holding duration. if hold.expected_duration().is_zero() { - unreachable!("Threshold for mailbox invalidated") + let err_msg = format!( + "send_user_message: mailbox message got zero duration hold bound for storing. \ + Gas limit - {gas_limit}, block cost - {cost}, source - {from:?}", + cost = CostsPerBlockOf::::by_storage_type(StorageType::Mailbox) + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } // Cutting gas for storing in mailbox. - GasHandlerOf::::cut(msg_id, message.id(), gas_limit) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + GasHandlerOf::::cut(msg_id, message.id(), gas_limit).unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message: failed creating cut node. \ + Origin node - {msg_id}, cut node id - {id}, amount - {gas_limit}. \ + Got error - {e:?}", + id = message.id() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Reserving value from source for future transfer or unreserve. - GearBank::::deposit_value(&from, value, false) - .unwrap_or_else(|e| unreachable!("Gear bank error: {e:?}")); + GearBank::::deposit_value(&from, value, false).unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message: failed depositting value on gear bank. \ + From - {from:?}, value - {value:?}. Got error - {e:?}", + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Lock the entire `gas_limit` since the only purpose of it is payment for storage. - GasHandlerOf::::lock(message.id(), LockId::Mailbox, gas_limit) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + GasHandlerOf::::lock(message.id(), LockId::Mailbox, gas_limit).unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message: failed locking gas for the user message mailbox. \ + Message id - {message_id}, lock amount - {gas_limit}. Got error - {e:?}", + message_id = message.id(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Inserting message in mailbox. let message_id = message.id(); - let message: UserStoredMessage = message - .clone() - .try_into() - .unwrap_or_else(|_| unreachable!("Replies are never added into mailbox")); - MailboxOf::::insert(message, hold.expected()) - .unwrap_or_else(|e| unreachable!("Mailbox corrupted! {:?}", e)); + let message: UserStoredMessage = message.clone().try_into().unwrap_or_else(|_| { + // Replies never sent to mailbox + let err_msg = format!( + "send_user_message: failed convertion from user into user stored message. \ + Message id - {message_id}, program id - {from:?}, destination - {to:?}", + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); + MailboxOf::::insert(message, hold.expected()).unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message: failed inserting message into mailbox. \ + Message id - {message_id}, source - {from:?}, destination - {to:?}, \ + expected bn - {bn:?}. Got error - {e:?}", + bn = hold.expected(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Adding removal request in task pool. TaskPoolOf::::add( hold.expected(), - ScheduledTask::RemoveFromMailbox(to, message_id), + ScheduledTask::RemoveFromMailbox(to.clone(), message_id), ) - .unwrap_or_else(|e| unreachable!("Scheduling logic invalidated! {:?}", e)); + .unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message: failed adding task for removing from mailbox. \ + Bn - {bn:?}, sent to - {to:?}, message id - {message_id}. \ + Got error - {e:?}", + bn = hold.expected() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Real expiration block. Some(hold.expected()) @@ -796,9 +1073,14 @@ where value, )); } - _ => { + e => { // Other errors are ruled out by the protocol guarantees. - unreachable!("Failed to transfer value: {:?}", e) + let err_msg = format!( + "send_user_message: failed to transfer value. Got error: {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } }); @@ -818,8 +1100,13 @@ where ); // Queueing dispatch. - QueueOf::::queue(reply_dispatch) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::queue(reply_dispatch).unwrap_or_else(|e| { + let err_msg = + format!("send_user_message: failed queuing message. Got error - {e:?}"); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } // No expiration block due to absence of insertion in storage. @@ -842,7 +1129,7 @@ where pub(crate) fn send_user_message_after_delay(message: UserMessage, to_mailbox: bool) { // Taking data for funds manipulations. let from = message.source().cast(); - let to = message.destination().cast(); + let to = message.destination().cast::(); let value = message.value().unique_saturated_into(); // If gas limit can cover threshold, message will be added to mailbox, @@ -850,43 +1137,102 @@ where let expiration = if to_mailbox { // Querying gas limit. Fails in cases of `GasTree` invalidations. - let gas_limit = GasHandlerOf::::get_limit(message.id()) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + let gas_limit = GasHandlerOf::::get_limit(message.id()).unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message_after_delay: failed getting message gas limit. \ + Message id - {message_id}. Got error - {e:?}", + message_id = message.id() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Figuring out hold bound for given gas limit. let hold = HoldBoundBuilder::::new(StorageType::Mailbox).maximum_for(gas_limit); // Validating holding duration. if hold.expected_duration().is_zero() { - unreachable!("Threshold for mailbox invalidated") + let err_msg = format!( + "send_user_message_after_delay: mailbox message (after delay) got zero duration hold bound for storing. \ + Gas limit - {gas_limit}, block cost - {cost}, source - {from:?}", + cost = CostsPerBlockOf::::by_storage_type(StorageType::Mailbox) + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } // Lock the entire `gas_limit` since the only purpose of it is payment for storage. GasHandlerOf::::lock(message.id(), LockId::Mailbox, gas_limit) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + .unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message_after_delay: failed locking gas for the user message mailbox. \ + Message id - {message_id}, lock amount - {gas_limit}. Got error - {e:?}", + message_id = message.id(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Inserting message in mailbox. let message_id = message.id(); let message: UserStoredMessage = message .clone() .try_into() - .unwrap_or_else(|_| unreachable!("Replies are never added into mailbox")); - MailboxOf::::insert(message, hold.expected()) - .unwrap_or_else(|e| unreachable!("Mailbox corrupted! {:?}", e)); + .unwrap_or_else(|_| { + // Replies never sent to mailbox + let err_msg = format!( + "send_user_message_after_delay: failed convertion from user into user stored message. \ + Message id - {message_id}, program id - {from:?}, destination - {to:?}", + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); + MailboxOf::::insert(message, hold.expected()).unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message_after_delay: failed inserting message into mailbox. \ + Message id - {message_id}, source - {from:?}, destination - {to:?}, \ + expected bn - {bn:?}. Got error - {e:?}", + bn = hold.expected(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Adding removal request in task pool. TaskPoolOf::::add( hold.expected(), - ScheduledTask::RemoveFromMailbox(to, message_id), + ScheduledTask::RemoveFromMailbox(to.clone(), message_id), ) - .unwrap_or_else(|e| unreachable!("Scheduling logic invalidated! {:?}", e)); + .unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message_after_delay: failed adding task for removing from mailbox. \ + Bn - {bn:?}, sent to - {to:?}, message id - {message_id}. \ + Got error - {e:?}", + bn = hold.expected() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Real expiration block. Some(hold.expected()) } else { // Transferring reserved funds. - GearBank::::transfer_value(&from, &to, value) - .unwrap_or_else(|e| unreachable!("Gear bank error: {e:?}")); + GearBank::::transfer_value(&from, &to, value).unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message_after_delay: failed transferring value on gear bank. \ + Sender - {from:?}, destination - {to:?}, value - {value:?}. Got error - {e:?}", + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Message is never reply here, because delayed reply sending forbidden. if message.details().is_none() { @@ -903,8 +1249,14 @@ where ); // Queueing dispatch. - QueueOf::::queue(reply_dispatch) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::queue(reply_dispatch).unwrap_or_else(|e| { + let err_msg = format!( + "send_user_message_after_delay: failed queuing message. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } Self::consume_and_retrieve(message.id()); @@ -968,26 +1320,46 @@ where /// handler to split (optionally with value) for all cases except reply /// sent and contains deposit in storage. pub(crate) fn split( - key: impl Into>, + key: impl Into> + Clone, new_key: impl Into> + Clone, is_reply: bool, ) { if !is_reply || !GasHandlerOf::::exists_and_deposit(new_key.clone()) { - GasHandlerOf::::split(key, new_key) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + GasHandlerOf::::split(key.clone(), new_key.clone()).unwrap_or_else(|e| { + let err_msg = format!( + "splt: failed to split gas node. Original message id - {key}, \ + new message id - {new_key}, is_reply - {is_reply}. Got error - {e:?}", + key = key.into(), + new_key = new_key.into(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } } /// See ['split']. pub(crate) fn split_with_value( - key: impl Into>, + key: impl Into> + Clone, new_key: impl Into> + Clone, amount: GasBalanceOf, is_reply: bool, ) { if !is_reply || !GasHandlerOf::::exists_and_deposit(new_key.clone()) { - GasHandlerOf::::split_with_value(key, new_key, amount) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + GasHandlerOf::::split_with_value(key.clone(), new_key.clone(), amount) + .unwrap_or_else(|e| { + let err_msg = format!( + "split_with_value: failed to split with value gas node. Original message id - {key}, \ + new message id - {new_key}. amount - {amount}, is_reply - {is_reply}. \ + Got error - {e:?}", + key = key.into(), + new_key = new_key.into(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } } @@ -1000,8 +1372,17 @@ where ) { let multiplier = ::GasMultiplier::get(); if !is_reply || !GasHandlerOf::::exists_and_deposit(key.clone()) { - GasHandlerOf::::create(origin, multiplier, key, amount) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + GasHandlerOf::::create(origin.clone(), multiplier, key.clone(), amount) + .unwrap_or_else(|e| { + let err_msg = format!( + "create: failed to creat gas node. Origin - {origin:?}, message id - {key}, \ + amount - {amount}, is_reply - {is_reply}. Got error - {e:?}", + key = key.into(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } } } diff --git a/pallets/gear/src/lib.rs b/pallets/gear/src/lib.rs index 1f2b49393d6..e641bb3578e 100644 --- a/pallets/gear/src/lib.rs +++ b/pallets/gear/src/lib.rs @@ -1017,8 +1017,15 @@ pub mod pallet { GasAllowanceOf::::get() .saturating_add(DbWeightOf::::get().writes(1).ref_time()), ); - TaskPoolOf::::add(bn, task) - .unwrap_or_else(|e| unreachable!("Scheduling logic invalidated! {:?}", e)); + TaskPoolOf::::add(bn, task.clone()).unwrap_or_else(|e| { + let err_msg = format!( + "process_tasks: failed adding not processed last task to task pool. \ + Bn - {bn:?}, task - {task:?}. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } // Stopping iteration over blocks if no resources left. @@ -1043,7 +1050,11 @@ pub mod pallet { pub(crate) fn enable_lazy_pages() { let prefix = ProgramStorageOf::::pages_final_prefix(); if !LazyPagesRuntimeInterface::try_to_enable_lazy_pages(prefix) { - unreachable!("By some reasons we cannot run lazy-pages on this machine"); + let err_msg = + "enable_lazy_pages: By some reasons we cannot run lazy-pages on this machine"; + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } } @@ -1112,12 +1123,15 @@ pub mod pallet { // By the invariant set in CodeStorage trait, original code can't exist in storage // without the instrumented code - let original_code = T::CodeStorage::get_original_code(code_id).unwrap_or_else(|| - unreachable!( - "Code storage is corrupted: instrumented code with id {:?} exists while original not", - code_id - ) - ); + let original_code = T::CodeStorage::get_original_code(code_id).unwrap_or_else(|| { + let err_msg = format!( + "reinstrument_code: failed to get original code, while instrumented exists. \ + Code id - {code_id}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); let code = Code::try_new( original_code, @@ -1273,8 +1287,13 @@ pub mod pallet { entry: MessageEntry::Init, }; - QueueOf::::queue(dispatch) - .unwrap_or_else(|e| unreachable!("Messages storage corrupted: {e:?}")); + QueueOf::::queue(dispatch).unwrap_or_else(|e| { + let err_msg = + format!("do_create_program: failed queuing message. Got error - {e:?}"); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); Self::deposit_event(program_event); Self::deposit_event(event); @@ -1562,7 +1581,7 @@ pub mod pallet { // Reading message, if found, or failing extrinsic. let mailboxed = Self::read_message(origin.clone(), message_id, reason) - .ok_or(Error::::MessageNotFound)?; + .map_err(|_| Error::::MessageNotFound)?; let (builtins, _) = T::BuiltinDispatcherFactory::create(); if Self::is_active(&builtins, mailboxed.source()) { @@ -1576,8 +1595,12 @@ pub mod pallet { message.into_stored_dispatch(origin.cast(), mailboxed.source(), mailboxed.id()); // Queueing dispatch. - QueueOf::::queue(dispatch) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::queue(dispatch).unwrap_or_else(|e| { + let err_msg = format!("claim_value: failed queuing message. Got error - {e:?}"); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } Ok(().into()) @@ -1800,13 +1823,32 @@ pub mod pallet { entry: MessageEntry::Handle, }); - QueueOf::::queue(message) - .unwrap_or_else(|e| unreachable!("Messages storage corrupted: {e:?}")); + QueueOf::::queue(message).unwrap_or_else(|e| { + let err_msg = + format!("send_message_impl: failed queuing message. Got error - {e:?}"); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } else { - let message = message.into_stored(origin.cast()); + // Take data for the error log + let message_id = message.id(); + let source = origin.cast::(); + let destination = message.destination(); + + let message = message.into_stored(source); let message: UserMessage = message .try_into() - .unwrap_or_else(|_| unreachable!("Signal message sent to user")); + .unwrap_or_else(|_| { + // Signal message sent to user + let err_msg = format!( + "send_message_impl: failed convertion from stored into user message. \ + Message id - {message_id}, program id - {source}, destination - {destination}", + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); let existence_requirement = if keep_alive { ExistenceRequirement::KeepAlive @@ -1849,7 +1891,7 @@ pub mod pallet { // Reading message, if found, or failing extrinsic. let mailboxed = Self::read_message(origin.clone(), reply_to_id, reason) - .ok_or(Error::::MessageNotFound)?; + .map_err(|_| Error::::MessageNotFound)?; Self::check_gas_limit(gas_limit)?; @@ -1898,8 +1940,12 @@ pub mod pallet { }; // Queueing dispatch. - QueueOf::::queue(dispatch) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::queue(dispatch).unwrap_or_else(|e| { + let err_msg = format!("send_reply_impl: failed queuing message. Got error - {e:?}"); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Depositing pre-generated event. Self::deposit_event(event); diff --git a/pallets/gear/src/manager/journal.rs b/pallets/gear/src/manager/journal.rs index 41d0df4cfb6..1154266b220 100644 --- a/pallets/gear/src/manager/journal.rs +++ b/pallets/gear/src/manager/journal.rs @@ -19,12 +19,13 @@ use crate::{ internal::HoldBoundBuilder, manager::{CodeInfo, ExtManager}, - Config, CurrencyOf, Event, GasAllowanceOf, GasHandlerOf, GasTree, GearBank, Pallet, - ProgramStorageOf, QueueOf, TaskPoolOf, WaitlistOf, EXISTENTIAL_DEPOSIT_LOCK_ID, + Config, CostsPerBlockOf, CurrencyOf, Event, GasAllowanceOf, GasHandlerOf, GasTree, GearBank, + Pallet, ProgramStorageOf, QueueOf, TaskPoolOf, WaitlistOf, EXISTENTIAL_DEPOSIT_LOCK_ID, }; +use alloc::format; use common::{ event::*, - scheduler::{ScheduledTask, StorageType, TaskHandler, TaskPool}, + scheduler::{ScheduledTask, SchedulingCostsPerBlock, StorageType, TaskHandler, TaskPool}, storage::*, CodeStorage, LockableTree, Origin, ProgramStorage, ReservableTree, }; @@ -96,16 +97,26 @@ where ProgramStorageOf::::update_program_if_active(program_id, |p, bn| { match p { Program::Active(active) => active.state = ProgramState::Initialized, - _ => unreachable!("Only active programs are able to initialize"), + actual_program => { + // Guaranteed to be called on existing program, because only existing programs + // are able to be initialized. + let err_msg = format!("JournalHandler::message_dispatched: failed to update active program state. \ + Program - {program_id}, actual program - {actual_program:?}"); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + } } bn }) .unwrap_or_else(|e| { - unreachable!( - "Program initialized status may only be set to active program {:?}", - e - ); + // Guaranteed to be called on existing program + let err_msg = format!("JournalHandler::message_dispatched: failed to update program. \ + Program - {program_id}. Got error: {e:?}"); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") }); Pallet::::deposit_event(Event::ProgramChanged { @@ -162,13 +173,29 @@ where Program::Active(program) => { Self::clean_inactive_program(id_exited, program, value_destination) } - _ => unreachable!("Action executed only for active program"), + actual_program => { + // Guaranteed to be called only on active program + let err_msg = format!( + "JournalHandler::exit_dispatch: failed to exit active program. \ + Program - {id_exited}, actual program - {actual_program:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + } } *p = Program::Exited(value_destination); }) .unwrap_or_else(|e| { - unreachable!("`exit` can be called only from active program: {:?}", e); + // Guaranteed to be called only on active program + let err_msg = format!( + "ExtManager::exit_dispatch: failed to update program. \ + Program - {id_exited}. Got error: {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); }); } @@ -208,7 +235,17 @@ where dispatch.value().unique_saturated_into(), false, ) - .unwrap_or_else(|e| unreachable!("Gear bank error: {e:?}")); + .unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::send_dispatch: failed depositing value on gear bank. \ + Sender - {sender}, value - {value}. Got error - {e:?}", + sender = dispatch.source(), + value = dispatch.value(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } match (gas_limit, reservation) { @@ -219,12 +256,16 @@ where dispatch.is_reply(), ), (None, None) => Pallet::::split(message_id, dispatch.id(), dispatch.is_reply()), - (Some(_gas_limit), Some(_reservation_id)) => { + (Some(gas_limit), Some(reservation_id)) => { // TODO: #1828 - unreachable!( - "Sending dispatch with gas limit from reservation \ - is currently unimplemented and there is no way to send such dispatch" + let err_msg = format!( + "JournalHandler::send_dispatch: sending dispatch with gas from reservation isn't implemented. \ + Message - {message_id}, sender - {sender}, gas limit - {gas_limit}, reservation - {reservation_id}", + sender = dispatch.source(), ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } (None, Some(reservation_id)) => { Pallet::::split(reservation_id, dispatch.id(), dispatch.is_reply()); @@ -235,8 +276,14 @@ where } } - QueueOf::::queue(dispatch) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::queue(dispatch).unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::send_dispatch: failed queuing message. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } else { log::debug!( "Sending user message {:?} from {:?} with gas limit {:?}", @@ -274,13 +321,19 @@ where // because message already charged for it within the env. if delay.is_zero() { - if let Some(dispatch) = Pallet::::wake_dispatch( + if let Ok(dispatch) = Pallet::::wake_dispatch( program_id, awakening_id, MessageWokenRuntimeReason::WakeCalled.into_reason(), ) { - QueueOf::::queue(dispatch) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::queue(dispatch).unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::wake_message: failed queuing message. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); return; } @@ -291,8 +344,16 @@ where // This validation helps us to avoid returning error on insertion into `TaskPool` in case of duplicate wake. if !TaskPoolOf::::contains(&expected_bn, &task) { - TaskPoolOf::::add(expected_bn, task) - .unwrap_or_else(|e| unreachable!("Scheduling logic invalidated! {:?}", e)); + TaskPoolOf::::add(expected_bn, task).unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::wake_message: failed adding task for waking message. \ + Expected bn - {expected_bn:?}, program id - {program_id}, message_id - {awakening_id}. + Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } return; @@ -326,26 +387,47 @@ where } }) .unwrap_or_else(|e| { - unreachable!( - "Page update guaranteed to be called only for existing and active program: {:?}", - e - ) + // Guaranteed to be called on existing active program + let err_msg = format!( + "JournalHandler::update_pages_data: failed to update program. \ + Program - {program_id}. Got error: {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); }); } fn update_allocations(&mut self, program_id: ProgramId, allocations: IntervalsTree) { ProgramStorageOf::::update_active_program(program_id, |p| { - for page in p.allocations.difference(&allocations).flat_map(|i| i.iter()).flat_map(|p| p.to_iter()) { + for page in p + .allocations + .difference(&allocations) + .flat_map(|i| i.iter()) + .flat_map(|p| p.to_iter()) + { // TODO: do not use `contains` #3879 if p.pages_with_data.contains(page) { p.pages_with_data.remove(page); - ProgramStorageOf::::remove_program_page_data(program_id, p.memory_infix, page); + ProgramStorageOf::::remove_program_page_data( + program_id, + p.memory_infix, + page, + ); } } p.allocations = allocations; - }).unwrap_or_else(|e| { - unreachable!("Allocations update guaranteed to be called only for existing and active program: {:?}", e) + }) + .unwrap_or_else(|e| { + // Guaranteed to be called on existing active program + let err_msg = format!( + "JournalHandler::update_allocations: failed to update program. \ + Program - {program_id}. Got error: {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); }); } @@ -354,8 +436,15 @@ where let from = from.cast(); let value = value.unique_saturated_into(); - GearBank::::transfer_value(&from, &to, value) - .unwrap_or_else(|e| unreachable!("Gear bank error: {e:?}")); + GearBank::::transfer_value(&from, &to, value).unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::send_value: failed transferring bank value. \ + From - {from:?}, to - {to:?}, value - {value:?}. Got error: {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } fn store_new_programs( @@ -381,7 +470,15 @@ where ed, ExistenceRequirement::KeepAlive, ) - .unwrap_or_else(|e| unreachable!("Existential deposit transfer error: {e:?}")); + .unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::store_new_programs: failed transferring ED to a new program. \ + Sender - {program_id}, dest - {candidate_id}, value - {ed:?}. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Set lock to avoid accidental account removal by the runtime. CurrencyOf::::set_lock( EXISTENTIAL_DEPOSIT_LOCK_ID, @@ -423,8 +520,14 @@ where GasAllowanceOf::::decrease(gas_burned); // TODO: #3112. Rework requeueing logic to avoid blocked queue. - QueueOf::::requeue(dispatch) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::requeue(dispatch).unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::stop_processing: failed requeuing message. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } fn reserve_gas( @@ -448,25 +551,63 @@ where // Validating holding duration. if hold.expected_duration().is_zero() { - unreachable!("Threshold for reservation invalidated") + let err_msg = format!( + "JournalHandler::reserve_gas: reservation got zero duration hold bound for storing. \ + Duration - {duration}, block cost - {cost}, program - {program_id}.", + cost = CostsPerBlockOf::::by_storage_type(StorageType::Reservation) + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } let total_amount = amount.saturating_add(hold.lock_amount()); - GasHandlerOf::::reserve(message_id, reservation_id, total_amount) - .unwrap_or_else(|e| unreachable!("GasTree corrupted: {:?}", e)); + GasHandlerOf::::reserve(message_id, reservation_id, total_amount).unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::reserve_gas: failed reserving gas. Origin message id - {message_id}, \ + reservation id - {reservation_id}, reservation amount - {amount}, hold lock - {lock}. \ + Got error - {e:?}", + lock = hold.lock_amount(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); let lock_id = hold.lock_id().unwrap_or_else(|| { - unreachable!("Reservation storage is guaranteed to have an associated lock id") + // Reservation storage is guaranteed to have an associated lock id + let err_msg = + "JournalHandler::reserve_gas: No associated lock id for the reservation storage"; + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); + GasHandlerOf::::lock(reservation_id, lock_id, hold.lock_amount()).unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::reserve_gas: failed locking gas for the reservation hold. \ + Reseravation - {reservation_id}, lock amount - {lock}. Got error - {e:?}", + lock = hold.lock_amount() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); }); - GasHandlerOf::::lock(reservation_id, lock_id, hold.lock_amount()) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); TaskPoolOf::::add( hold.expected(), ScheduledTask::RemoveGasReservation(program_id, reservation_id), ) - .unwrap_or_else(|e| unreachable!("Scheduling logic invalidated! {:?}", e)); + .unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::reserve_gas: failed adding task for gas reservation removal. \ + Expected bn - {bn:?}, program id - {program_id}, reservation id - {reservation_id}. Got error - {e:?}", + bn = hold.expected() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } fn unreserve_gas( @@ -500,23 +641,41 @@ where ); }) .unwrap_or_else(|e| { - unreachable!( - "Gas reservation update guaranteed to be called only on an existing program: {:?}", - e - ) + // Guaranteed to be called on existing active program + let err_msg = format!( + "JournalHandler::update_gas_reservation: failed to update program. \ + Program - {program_id}. Got error: {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); }); } fn system_reserve_gas(&mut self, message_id: MessageId, amount: u64) { log::debug!("Reserve {} of gas for system from {}", amount, message_id); - GasHandlerOf::::system_reserve(message_id, amount) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + GasHandlerOf::::system_reserve(message_id, amount).unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::system_reserve_gas: failed system reserve gas. \ + Message id - {message_id}, amount - {amount}. Got error: {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } fn system_unreserve_gas(&mut self, message_id: MessageId) { - let amount = GasHandlerOf::::system_unreserve(message_id) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + let amount = GasHandlerOf::::system_unreserve(message_id).unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::system_unreserve_gas: failed system unreserve. \ + Message id - {message_id}. Got error: {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); if amount != 0 { log::debug!("Unreserved {} gas for system from {}", amount, message_id); @@ -535,7 +694,14 @@ where fn reply_deposit(&mut self, message_id: MessageId, future_reply_id: MessageId, amount: u64) { log::debug!("Creating reply deposit {amount} gas for message id {future_reply_id}"); - GasHandlerOf::::create_deposit(message_id, future_reply_id, amount) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + GasHandlerOf::::create_deposit(message_id, future_reply_id, amount).unwrap_or_else(|e| { + let err_msg = format!( + "JournalHandler::reply_deposit: failed creating reply deposit. Message id - {message_id}, \ + future reply id - {future_reply_id}, amount - {amount}. Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } } diff --git a/pallets/gear/src/manager/mod.rs b/pallets/gear/src/manager/mod.rs index 414016e9cba..9444ea2344c 100644 --- a/pallets/gear/src/manager/mod.rs +++ b/pallets/gear/src/manager/mod.rs @@ -55,6 +55,7 @@ use crate::{ fungible, BuiltinDispatcherFactory, Config, CurrencyOf, Event, Fortitude, GasHandlerOf, Pallet, Preservation, ProgramStorageOf, QueueOf, TaskPoolOf, WaitlistOf, EXISTENTIAL_DEPOSIT_LOCK_ID, }; +use alloc::format; use common::{ event::*, scheduler::{ScheduledTask, StorageType, TaskPool}, @@ -290,17 +291,20 @@ where p.gas_reservation_map .remove(&reservation_id) .unwrap_or_else(|| { - unreachable!( - "Gas reservation removing called on non-existing reservation ID: {}", - reservation_id - ) + let err_msg = format!("ExtManager::remove_gas_reservation_impl: failed removing gas reservation. \ + Reservation {reservation_id} doesn't exist."); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); }) }) .unwrap_or_else(|e| { - unreachable!( - "Gas reservation removing guaranteed to be called only on existing program: {:?}", - e - ) + // Guaranteed to be called on existing program + let err_msg = format!("ExtManager::remove_gas_reservation_impl: failed to update program. \ + Program - {program_id}. Got error: {e:?}"); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") }); Self::remove_gas_reservation_slot(reservation_id, slot) @@ -325,8 +329,15 @@ where } fn send_signal(&mut self, message_id: MessageId, destination: ProgramId, code: SignalCode) { - let reserved = GasHandlerOf::::system_unreserve(message_id) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {:?}", e)); + let reserved = GasHandlerOf::::system_unreserve(message_id).unwrap_or_else(|e| { + let err_msg = format!( + "ExtManager::send_signal: failed system unreserve. \ + Message id - {message_id}. Got error: {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); if reserved != 0 { log::debug!( "Send signal issued by {} to {} with {} supply", @@ -349,8 +360,13 @@ where ); // Enqueueing dispatch into message queue. - QueueOf::::queue(trap_signal) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::queue(trap_signal).unwrap_or_else(|e| { + let err_msg = + format!("ExtManager::send_signal: failed queuing message. Got error - {e:?}"); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } else { log::trace!("Signal wasn't sent due to inappropriate supply"); } @@ -389,7 +405,14 @@ where balance, ExistenceRequirement::AllowDeath, ) - .unwrap_or_else(|e| unreachable!("Failed to transfer value: {e:?}")); + .unwrap_or_else(|e| { + let err_msg = format!("ExtManager::clean_inactive_program: failed transferring the rest balance. \ + Sender - {program_account:?}, sender balance - {balance:?}, dest - {value_destination:?}. \ + Got error: {e:?}"); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } } diff --git a/pallets/gear/src/manager/task.rs b/pallets/gear/src/manager/task.rs index ab8bc557e6b..c7dec0a541c 100644 --- a/pallets/gear/src/manager/task.rs +++ b/pallets/gear/src/manager/task.rs @@ -19,7 +19,7 @@ use crate::{ manager::ExtManager, weights::WeightInfo, Config, DispatchStashOf, Event, Pallet, QueueOf, }; -use alloc::string::ToString; +use alloc::{format, string::ToString}; use common::{ event::{ MessageWokenRuntimeReason, MessageWokenSystemReason, RuntimeReason, SystemReason, @@ -32,7 +32,7 @@ use common::{ use core::cmp; use gear_core::{ ids::{CodeId, MessageId, ProgramId, ReservationId}, - message::{DispatchKind, ReplyMessage}, + message::{DispatchKind, Payload, ReplyMessage}, }; use gear_core_errors::{ErrorReplyReason, SignalCode}; @@ -89,8 +89,16 @@ where Pallet::::create(user_id.clone(), message.id(), 0, true); // Reading message from mailbox. - let mailboxed = Pallet::::read_message(user_id, message_id, reason) - .unwrap_or_else(|| unreachable!("Scheduling logic invalidated!")); + let mailboxed = Pallet::::read_message(user_id.clone(), message_id, reason.clone()) + .unwrap_or_else(|e| { + let err_msg = format!( + "TaskHandler::remove_from_mailbox: failed reading message from mailbox. \ + User - {user_id:?}, message - {message_id}, reason - {reason:?}. Got error: {e:?}." + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Converting reply message into appropriate type for queueing. let dispatch = message.into_stored_dispatch( @@ -100,8 +108,15 @@ where ); // Queueing dispatch. - QueueOf::::queue(dispatch) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::queue(dispatch).unwrap_or_else(|e| { + let err_msg = format!( + "TaskHandler::remove_from_mailbox: failed queuing message. \ + Got error: {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); let gas = ::WeightInfo::tasks_remove_from_mailbox().ref_time(); log::trace!("Task gas: tasks_remove_from_mailbox = {gas}"); @@ -114,8 +129,17 @@ where let reason = MessageWokenSystemReason::OutOfRent.into_reason(); // Waking dispatch. - let waitlisted = Pallet::::wake_dispatch(program_id, message_id, reason) - .unwrap_or_else(|| unreachable!("Scheduling logic invalidated!")); + let waitlisted = Pallet::::wake_dispatch(program_id, message_id, reason.clone()) + .unwrap_or_else(|e| { + let err_msg = format!( + "TaskHandler::remove_from_waitlist: failed waking dispatch. \ + Program id - {program_id}, waking message - {message_id}, reason - {reason:?} \ + Got error - {e:?}." + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); self.send_signal( message_id, @@ -132,7 +156,18 @@ where .to_string() .into_bytes() .try_into() - .unwrap_or_else(|_| unreachable!("Error message is too large")); + .unwrap_or_else(|_| { + let error_reply = err.to_string().into_bytes(); + let err_msg = format!( + "TaskHandler::remove_from_waitlist: failed convertion of error reply into `Payload`. \ + Error reply bytes len - {len}, max payload len - {max_len}", + len = error_reply.len(), + max_len = Payload::max_len(), + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); let trap_reply = ReplyMessage::system(message_id, err_payload, err); @@ -149,8 +184,15 @@ where ); // Queueing dispatch. - QueueOf::::queue(trap_dispatch) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::queue(trap_dispatch).unwrap_or_else(|e| { + let err_msg = format!( + "TaskHandler::remove_from_waitlist: failed queuing message. \ + Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); } else { // Sending trap reply to user, by depositing event. // @@ -161,7 +203,17 @@ where trap_reply.into_stored(program_id, waitlisted.source(), message_id); let trap_reply = trap_reply .try_into() - .unwrap_or_else(|_| unreachable!("Signal message sent to user")); + .unwrap_or_else(|_| { + // Signal message sent to user + let err_msg = format!( + "TaskHandler::remove_from_waitlist: failed convertion from stored into user message. \ + Message id - {message_id}, program id - {program_id}, destination - {dest}", + dest = waitlisted.source() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); // Depositing appropriate event. Pallet::::deposit_event(Event::UserMessageSent { @@ -194,10 +246,19 @@ where program_id, message_id, MessageWokenRuntimeReason::WakeCalled.into_reason(), - ) { + ) + .ok() + { Some(dispatch) => { - QueueOf::::queue(dispatch) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::queue(dispatch).unwrap_or_else(|e| { + let err_msg = format!( + "TaskHandler::wake_message: failed queuing message. \ + Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); let gas = ::WeightInfo::tasks_wake_message().ref_time(); log::trace!("Task gas: tasks_wake_message = {gas}"); @@ -217,13 +278,27 @@ where // No validation required. If program doesn't exist, then NotExecuted appears. let (dispatch, hold_interval) = DispatchStashOf::::take(stashed_message_id) - .unwrap_or_else(|| unreachable!("Scheduler & Stash logic invalidated!")); + .unwrap_or_else(|| { + let err_msg = format!( + "TaskHandler::send_dispatch: failed taking message from stash. Message id - {stashed_message_id}." + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Charging locked gas for holding in dispatch stash. Pallet::::charge_for_hold(dispatch.id(), hold_interval, StorageType::DispatchStash); - QueueOf::::queue(dispatch.into()) - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {:?}", e)); + QueueOf::::queue(dispatch.into()).unwrap_or_else(|e| { + let err_msg = format!( + "TaskHandler::send_dispatch: failed queuing message. \ + Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); let gas = ::WeightInfo::tasks_send_dispatch().ref_time(); log::trace!("Task gas: tasks_send_dispatch = {gas}"); @@ -236,15 +311,33 @@ where // Atm despite the fact that program may exist, message goes into mailbox / event. let (message, hold_interval) = DispatchStashOf::::take(stashed_message_id) .map(|(dispatch, interval)| (dispatch.into_parts().1, interval)) - .unwrap_or_else(|| unreachable!("Scheduler & Stash logic invalidated!")); + .unwrap_or_else(|| { + let err_msg = format!( + "TaskHandler::send_user_message: failed taking message from stash. Message id - {stashed_message_id}." + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); // Charge gas for message save. Pallet::::charge_for_hold(message.id(), hold_interval, StorageType::DispatchStash); + // Taking data for error log + let message_id = message.id(); + let program_id = message.source(); + // Cast message type. - let message = message - .try_into() - .unwrap_or_else(|_| unreachable!("Signal message sent to user")); + let message = message.try_into().unwrap_or_else(|_| { + // Signal message sent to user + let err_msg = format!( + "TaskHandler::send_user_message: failed convertion from stored into user message. \ + Message id - {message_id}, program id - {program_id}.", + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }); Pallet::::send_user_message_after_delay(message, to_mailbox); if to_mailbox { diff --git a/pallets/gear/src/queue.rs b/pallets/gear/src/queue.rs index c24bcdab140..b2aa4333b1a 100644 --- a/pallets/gear/src/queue.rs +++ b/pallets/gear/src/queue.rs @@ -65,9 +65,13 @@ where if program.state == ProgramState::Initialized && dispatch_kind == DispatchKind::Init { // Panic is impossible, because gear protocol does not provide functionality // to send second init message to any already existing program. - unreachable!( - "Init message {dispatch_id:?} is sent to already initialized program {destination_id:?}" + let err_msg = format!( + "run_queue_step: got init message for already initialized program. \ + Current init message id - {dispatch_id:?}, already initialized program id - {destination_id:?}." ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } // If the destination program is uninitialized, then we allow @@ -79,9 +83,13 @@ where if dispatch_kind == DispatchKind::Init { // Panic is impossible, because gear protocol does not provide functionality // to send second init message to any existing program. - unreachable!( - "Init message {dispatch_id:?} is not the first init message to the program {destination_id:?}" + let err_msg = format!( + "run_queue_step: got init message which is not the first init message to the program. \ + Current init message id - {dispatch_id:?}, original init message id - {dispatch_id}, program - {destination_id:?}.", ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); } return core_processor::process_non_executable(precharged_dispatch, destination_id); @@ -111,7 +119,14 @@ where // Load correct code length value. let code_id = context.actor_data().code_id; let code_len_bytes = T::CodeStorage::get_code_len(code_id).unwrap_or_else(|| { - unreachable!("Program '{destination_id:?}' exists so do code len '{code_id:?}'") + // `Program` exists, so do code and code len. + let err_msg = format!( + "run_queue_step: failed to get code len for the existing program. \ + Program id -'{destination_id:?}', Code id - '{code_id:?}'." + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); }); // Adjust gas counters for fetching instrumented binary code. @@ -123,7 +138,14 @@ where // Load instrumented binary code from storage. let code = T::CodeStorage::get_code(code_id).unwrap_or_else(|| { - unreachable!("Program '{destination_id:?}' exists so do code '{code_id:?}'") + // `Program` exists, so do code and code len. + let err_msg = format!( + "run_queue_step: failed to get code for the existing program. \ + Program id -'{destination_id:?}', Code id - '{code_id:?}'." + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); }); // Reinstrument the code if necessary. @@ -171,7 +193,15 @@ where (context, code, balance).into(), (random.encode(), bn.unique_saturated_into()), ) - .unwrap_or_else(|e| unreachable!("{e}")) + .unwrap_or_else(|e| { + let err_msg = format!( + "run_queue_step: failed processing message. Message id - {dispatch_id}, program id - {destination_id}. \ + Got error - {e:?}" + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}"); + }) } /// Message Queue processing. @@ -185,16 +215,29 @@ where } while QueueProcessingOf::::allowed() { - let dispatch = match QueueOf::::dequeue() - .unwrap_or_else(|e| unreachable!("Message queue corrupted! {e:?}")) - { - Some(d) => d, - None => break, + let dispatch = match QueueOf::::dequeue() { + Ok(Some(d)) => d, + Ok(None) => break, + Err(e) => { + let err_msg = + format!("process_queue: failed dequeuing message. Got error - {e:?}"); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + } }; // Querying gas limit. Fails in cases of `GasTree` invalidations. let gas_limit = GasHandlerOf::::get_limit(dispatch.id()) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {e:?}")); + .unwrap_or_else(|e| { + let err_msg = format!( + "process_queue: failed getting message gas limit. Message id - {}. Got error - {e:?}.", + dispatch.id() + ); + + log::error!("{err_msg}"); + unreachable!("{err_msg}") + }); log::debug!( "QueueProcessing message ({:?}): {:?} to {:?} / gas_limit: {}, gas_allowance: {}", diff --git a/scripts/check-fuzzer.sh b/scripts/check-fuzzer.sh index 1350209b465..1dcddad4f43 100755 --- a/scripts/check-fuzzer.sh +++ b/scripts/check-fuzzer.sh @@ -17,7 +17,7 @@ main() { RUST_BACKTRACE=1 FAILPOINTS=fail_fuzzer=return ./scripts/gear.sh test fuzz "" wlogs > fuzz_run 2>&1 echo " >> Checking fuzzer output" - if cat fuzz_run | grep -qzP '(?s)(?=.*GasTree corrupted)(?=.*NodeAlreadyExists)(?=.*\Qpallet_gear::pallet::Pallet>::consume_and_retrieve\E)' ; then + if cat fuzz_run | grep -qzP '(?s)(?=.*consume_and_retrieve: failed consuming the rest of gas)(?=.*NodeAlreadyExists)(?=.*\Qpallet_gear::pallet::Pallet>::consume_and_retrieve\E)' ; then echo "Success" exit 0 else