Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 30 additions & 14 deletions core-processor/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,27 +399,31 @@ impl<'a, LP: LazyPagesInterface> ExtMutator<'a, LP> {
.alloc::<Context, LazyGrowHandler<LP>>(ctx, mem, pages, |pages| {
let cost = gas_for_call.saturating_add(gas_for_pages.cost_for(pages));
// Inline charge_gas_if_enough because otherwise we have borrow error due to access to `allocations_context` mutable
if self.gas_counter.charge_if_enough(cost) == ChargeResult::NotEnough {
if self.gas_counter.charge_if_enough(cost).is_not_enough() {
return Err(ChargeError::GasLimitExceeded);
}

if self.gas_allowance_counter.charge_if_enough(cost) == ChargeResult::NotEnough {
if self
.gas_allowance_counter
.charge_if_enough(cost)
.is_not_enough()
{
return Err(ChargeError::GasAllowanceExceeded);
}
Ok(())
})
}

fn reduce_gas(&mut self, limit: GasLimit) -> Result<(), FallibleExtError> {
if self.gas_counter.reduce(limit) == ChargeResult::NotEnough {
if self.gas_counter.reduce(limit).is_not_enough() {
return Err(FallibleExecutionError::NotEnoughGas.into());
}

Ok(())
}

fn charge_message_value(&mut self, value: u128) -> Result<(), FallibleExtError> {
if self.value_counter.reduce(value) == ChargeResult::NotEnough {
if self.value_counter.reduce(value).is_not_enough() {
return Err(FallibleExecutionError::NotEnoughValue.into());
}

Expand All @@ -440,11 +444,15 @@ impl<'a, LP: LazyPagesInterface> ExtMutator<'a, LP> {
}

fn charge_gas_if_enough(&mut self, gas: u64) -> Result<(), ChargeError> {
if self.gas_counter.charge_if_enough(gas) == ChargeResult::NotEnough {
if self.gas_counter.charge_if_enough(gas).is_not_enough() {
return Err(ChargeError::GasLimitExceeded);
}

if self.gas_allowance_counter.charge_if_enough(gas) == ChargeResult::NotEnough {
if self
.gas_allowance_counter
.charge_if_enough(gas)
.is_not_enough()
{
return Err(ChargeError::GasAllowanceExceeded);
}
Ok(())
Expand Down Expand Up @@ -737,10 +745,13 @@ impl<LP: LazyPagesInterface> Ext<LP> {
gas_allowance_counter: &mut GasAllowanceCounter,
amount: u64,
) -> Result<(), ChargeError> {
if gas_counter.charge_if_enough(amount) != ChargeResult::Enough {
if gas_counter.charge_if_enough(amount).is_not_enough() {
return Err(ChargeError::GasLimitExceeded);
}
if gas_allowance_counter.charge_if_enough(amount) != ChargeResult::Enough {
if gas_allowance_counter
.charge_if_enough(amount)
.is_not_enough()
{
// Here might be refunds for gas counter, but it's meaningless since
// on gas allowance exceed we totally roll up the message and give
// it another try in next block with the same initial resources.
Expand Down Expand Up @@ -825,7 +836,7 @@ impl<LP: LazyPagesInterface> CountersOwner for Ext<LP> {
unreachable!("{err_msg}")
});

if self.context.gas_counter.charge(diff) == ChargeResult::NotEnough {
if self.context.gas_counter.charge(diff).is_not_enough() {
let err_msg = format!(
"CounterOwner::decrease_current_counter_to: Tried to set gas limit left bigger than before. \
Message id - {message_id}, program id - {program_id}, gas counter - {gas_counter:?}, diff - {diff}",
Expand All @@ -838,7 +849,12 @@ impl<LP: LazyPagesInterface> CountersOwner for Ext<LP> {
unreachable!("{err_msg}")
}

if self.context.gas_allowance_counter.charge(diff) == ChargeResult::NotEnough {
if self
.context
.gas_allowance_counter
.charge(diff)
.is_not_enough()
{
let err_msg = format!(
"CounterOwner::decrease_current_counter_to: Tried to set gas allowance left bigger than before. \
Message id - {message_id}, program id - {program_id}, gas allowance counter - {gas_allowance_counter:?}, diff - {diff}",
Expand Down Expand Up @@ -1237,7 +1253,7 @@ impl<LP: LazyPagesInterface> Externalities for Ext<LP> {
return Err(ReservationError::ZeroReservationAmount.into());
}

if self.context.gas_counter.reduce(amount) == ChargeResult::NotEnough {
if self.context.gas_counter.reduce(amount).is_not_enough() {
return Err(FallibleExecutionError::NotEnoughGas.into());
}

Expand Down Expand Up @@ -1303,7 +1319,7 @@ impl<LP: LazyPagesInterface> Externalities for Ext<LP> {
.waitlist
.cost_for(mutator.context.reserve_for.saturating_add(duration).into());

if mutator.gas_counter.reduce(reserve) != ChargeResult::Enough {
if mutator.gas_counter.reduce(reserve).is_not_enough() {
return Err(UnrecoverableExecutionError::NotEnoughGas.into());
}

Expand All @@ -1330,7 +1346,7 @@ impl<LP: LazyPagesInterface> Externalities for Ext<LP> {
.waitlist
.cost_for(mutator.context.reserve_for.saturating_add(1).into());

if mutator.gas_counter.reduce(reserve) != ChargeResult::Enough {
if mutator.gas_counter.reduce(reserve).is_not_enough() {
return Err(UnrecoverableExecutionError::NotEnoughGas.into());
}

Expand All @@ -1343,7 +1359,7 @@ impl<LP: LazyPagesInterface> Externalities for Ext<LP> {

let reserve_diff = reserve_full - reserve;

Ok(mutator.gas_counter.reduce(reserve_diff) == ChargeResult::Enough)
Ok(mutator.gas_counter.reduce(reserve_diff).is_enough())
})
}

Expand Down
48 changes: 45 additions & 3 deletions core-processor/src/precharge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use core::marker::PhantomData;
use gear_core::{
code::{CodeMetadata, InstantiatedSectionSizes, SectionName},
costs::{BytesAmount, ProcessCosts},
gas::{ChargeResult, GasAllowanceCounter, GasCounter},
gas::{GasAllowanceCounter, GasCounter},
ids::ActorId,
message::IncomingDispatch,
};
Expand Down Expand Up @@ -61,6 +61,27 @@ pub enum PreChargeGasOperation {
/// Obtain program allocations.
#[display("obtain program allocations")]
Allocations,
/// Other operations.
#[display("{description}")]
Other {
/// Operation description.
description: &'static str,

/// Whether the operation affects block gas allowance.
affects_allowance: bool,
},
}

impl PreChargeGasOperation {
/// Checks whether the operation affects block gas allowance.
pub const fn affects_allowance(&self) -> bool {
Comment thread
liferooter marked this conversation as resolved.
match self {
&Self::Other {
affects_allowance, ..
} => affects_allowance,
_ => true,
}
}
}

/// Defines result variants of the precharge functions.
Expand Down Expand Up @@ -142,13 +163,34 @@ impl<T> ContextCharged<T> {
self.gas_counter.left()
}

/// Charges gas for a non-standard operation.
pub fn charge_extra_fee(
self,
description: &'static str,
affects_allowance: bool,
amount: u64,
) -> PrechargeResult<Self> {
self.charge_gas(
PreChargeGasOperation::Other {
description,
affects_allowance,
},
amount,
)
}

/// Charges gas for the operation.
fn charge_gas<For>(
mut self,
operation: PreChargeGasOperation,
amount: u64,
) -> PrechargeResult<ContextCharged<For>> {
if self.gas_allowance_counter.charge_if_enough(amount) != ChargeResult::Enough {
if operation.affects_allowance()
&& self
.gas_allowance_counter
.charge_if_enough(amount)
.is_not_enough()
{
let gas_burned = self.gas_counter.burned();

return Err(process_allowance_exceed(
Expand All @@ -158,7 +200,7 @@ impl<T> ContextCharged<T> {
));
}

if self.gas_counter.charge_if_enough(amount) != ChargeResult::Enough {
if self.gas_counter.charge_if_enough(amount).is_not_enough() {
let gas_burned = self.gas_counter.burned();
let system_reservation_ctx = SystemReservationContext::from_dispatch(&self.dispatch);

Expand Down
26 changes: 19 additions & 7 deletions core/src/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,22 @@ pub enum LockId {
pub enum ChargeResult {
/// There was enough gas and it has been charged.
Enough,
/// There was not enough gas and it hasn't been charged.
/// There was not enough gas.
NotEnough,
}

impl ChargeResult {
/// Checks whether there was enough gas to charge.
pub const fn is_enough(&self) -> bool {
matches!(self, Self::Enough)
}

/// Checks whether there was not enough gas to charge.
pub const fn is_not_enough(self) -> bool {
matches!(self, Self::NotEnough)
}
}

/// Gas counter with some predefined maximum gas.
///
/// `Copy` and `Clone` traits aren't implemented for the type (however could be)
Expand Down Expand Up @@ -343,7 +355,7 @@ impl From<(i64, i64)> for GasLeft {

#[cfg(test)]
mod tests {
use super::{ChargeResult, GasCounter};
use super::GasCounter;
use crate::gas::GasAllowanceCounter;

#[test]
Expand All @@ -355,30 +367,30 @@ mod tests {

let result = counter.charge_if_enough(100u64);

assert_eq!(result, ChargeResult::Enough);
assert!(result.is_enough());
assert_eq!(counter.left(), 100);

let result = counter.charge_if_enough(101u64);

assert_eq!(result, ChargeResult::NotEnough);
assert!(result.is_not_enough());
assert_eq!(counter.left(), 100);
}

#[test]
fn charge_fails() {
let mut counter = GasCounter::new(100);
assert_eq!(counter.charge_if_enough(200u64), ChargeResult::NotEnough);
assert!(counter.charge_if_enough(200u64).is_not_enough());
}

#[test]
fn charge_token_fails() {
let mut counter = GasCounter::new(10);
assert_eq!(counter.charge(1000u64), ChargeResult::NotEnough);
assert!(counter.charge(1000u64).is_not_enough());
}

#[test]
fn charge_allowance_token_fails() {
let mut counter = GasAllowanceCounter::new(10);
assert_eq!(counter.charge(1000u64), ChargeResult::NotEnough);
assert!(counter.charge(1000u64).is_not_enough());
}
}
27 changes: 26 additions & 1 deletion ethexe/processor/src/handling/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ use ethexe_runtime_common::{
use gear_core::gas::GasAllowanceCounter;
use gprimitives::{ActorId, H256};
use itertools::Itertools;
use std::collections::HashSet;

#[derive(Debug, Clone)]
pub struct RunnerConfig {
Expand Down Expand Up @@ -163,11 +164,16 @@ pub async fn run(
let mut allowance_counter = GasAllowanceCounter::new(config.block_gas_limit);
let chunk_size = config.chunk_processing_threads;

// Set of programs which has already processed
// their queue. Used to charge first message fee.
let mut processed_first_queue = HashSet::new();

// Start with injected queues processing.
let (is_out_of_gas_for_block, run_ctx) = run_inner(
run_ctx,
db.clone(),
instance_creator.clone(),
&mut processed_first_queue,
&mut allowance_counter,
chunk_size,
MessageType::Injected,
Expand All @@ -180,6 +186,7 @@ pub async fn run(
run_ctx,
db,
instance_creator,
&mut processed_first_queue,
&mut allowance_counter,
chunk_size,
MessageType::Canonical,
Expand All @@ -203,6 +210,7 @@ pub async fn run_overlaid(
run_ctx,
db,
instance_creator,
&mut HashSet::new(),
&mut allowance_counter,
chunk_size,
MessageType::Canonical,
Expand All @@ -215,6 +223,7 @@ async fn run_inner<C: RunContext>(
mut run_ctx: C,
db: Database,
instance_creator: InstanceCreator,
processed_first_queue: &mut HashSet<ActorId>,
allowance_counter: &mut GasAllowanceCounter,
chunk_size: usize,
processing_queue_type: MessageType,
Expand Down Expand Up @@ -244,6 +253,7 @@ async fn run_inner<C: RunContext>(
chunk,
db.clone(),
instance_creator.clone(),
processed_first_queue,
allowance_counter.left().min(CHUNK_PROCESSING_GAS_LIMIT),
processing_queue_type,
)
Expand Down Expand Up @@ -590,13 +600,25 @@ mod chunk_execution_spawn {
chunk: Vec<(ActorId, H256)>,
db: Database,
instance_creator: InstanceCreator,
processed_first_queue: &mut HashSet<ActorId>,
gas_allowance_for_chunk: u64,
processing_queue_type: MessageType,
) -> Vec<ChunkItemOutput> {
let chunk = chunk
.into_iter()
.map(|(program_id, state_hash)| {
(
program_id,
state_hash,
processed_first_queue.insert(program_id),
)
})
.collect::<Vec<_>>();
Comment thread
liferooter marked this conversation as resolved.
Outdated

tokio::task::spawn_blocking(move || {
chunk
.into_par_iter()
.map(|(program_id, state_hash)| {
.map(|(program_id, state_hash, is_first_queue)| {
let db = db.clone();
let mut executor = instance_creator
.instantiate()
Expand All @@ -608,6 +630,7 @@ mod chunk_execution_spawn {
program_id,
state_hash,
processing_queue_type,
is_first_queue,
gas_allowance_for_chunk,
);
(program_id, new_state_hash, jn, gas_spent)
Expand All @@ -624,6 +647,7 @@ mod chunk_execution_spawn {
program_id: ActorId,
state_hash: H256,
queue_type: MessageType,
is_first_queue: bool,
gas_allowance: u64,
) -> (ProgramJournals, H256, u64) {
let code_id = db.program_code_id(program_id).expect("Code ID must be set");
Expand All @@ -639,6 +663,7 @@ mod chunk_execution_spawn {
queue_type,
instrumented_code,
code_metadata,
is_first_queue,
gas_allowance,
)
.expect("Some error occurs while running program in instance")
Expand Down
Loading