Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add core_processor::prepare method #1211

Merged
merged 26 commits into from
Aug 2, 2022
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
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: 36 additions & 8 deletions core-processor/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use alloc::{
use codec::{Decode, Encode};
use gear_backend_common::TrapExplanation;
use gear_core::{
gas::GasAmount,
gas::{GasAllowanceCounter, GasAmount, GasCounter},
ids::{CodeId, MessageId, ProgramId},
memory::{PageBuf, PageNumber, WasmPageNumber},
message::{ContextStore, Dispatch, IncomingDispatch, StoredDispatch},
Expand Down Expand Up @@ -90,10 +90,31 @@ impl DispatchResult {
self.dispatch.source()
}

/// Return dispatch message value
/// Return dispatch message value.
pub fn message_value(&self) -> u128 {
self.dispatch.value()
}

/// Create partially initialized instance with the kind
/// representing Success.
pub fn success(
dispatch: IncomingDispatch,
program_id: ProgramId,
gas_amount: GasAmount,
) -> Self {
Self {
kind: DispatchResultKind::Success,
dispatch,
program_id,
context_store: Default::default(),
generated_dispatches: Default::default(),
awakening: Default::default(),
program_candidates: Default::default(),
gas_amount,
page_update: Default::default(),
allocations: Default::default(),
}
}
}

/// Dispatch outcome of the specific message.
Expand Down Expand Up @@ -355,17 +376,24 @@ pub struct Actor {
/// Executable actor data.
#[derive(Clone, Debug, Decode, Encode)]
pub struct ExecutableActorData {
/// Program.
/// Program aggregated data.
pub program: Program,
/// Data which some program allocated pages may have.
pub pages_data: BTreeMap<PageNumber, PageBuf>,
/// Numbers of allocated memory pages that have non-default data.
pub pages_with_data: BTreeSet<PageNumber>,
}

/// Execution context.
#[derive(Clone, Debug, Decode, Encode)]
pub struct WasmExecutionContext {
/// Original user.
pub origin: ProgramId,
/// Gas allowance of the block.
pub gas_allowance: u64,
/// A counter for gas.
pub gas_counter: GasCounter,
/// A counter for gas allowance.
pub gas_allowance_counter: GasAllowanceCounter,
/// Program to be executed.
pub program: Program,
/// Memory pages with initial data.
pub pages_initial_data: BTreeMap<PageNumber, PageBuf>,
/// Size of the memory block.
pub memory_size: WasmPageNumber,
}
22 changes: 2 additions & 20 deletions core-processor/src/configs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,26 +107,6 @@ impl ExecutionSettings {
pub fn max_pages(&self) -> WasmPageNumber {
self.allocations_config.max_pages
}

/// Cost of initial memory.
pub fn init_cost(&self) -> u64 {
self.allocations_config.init_cost
}

/// Cost of allocating memory.
pub fn alloc_cost(&self) -> u64 {
self.allocations_config.alloc_cost
}

/// Memory grow cost.
pub fn mem_grow_cost(&self) -> u64 {
self.allocations_config.mem_grow_cost
}

/// Load gear page cost.
pub fn load_page_cost(&self) -> u64 {
self.allocations_config.load_page_cost
}
}

/// Stable parameters for the whole block across processing runs.
Expand Down Expand Up @@ -159,4 +139,6 @@ pub struct MessageExecutionContext {
pub origin: ProgramId,
/// Gas allowance.
pub gas_allowance: u64,
/// The program is being executed the second or next time in the block.
pub subsequent_execution: bool,
}
139 changes: 69 additions & 70 deletions core-processor/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@

use crate::{
common::{
DispatchResult, DispatchResultKind, ExecutableActorData, ExecutionError,
ExecutionErrorReason, WasmExecutionContext,
DispatchResult, DispatchResultKind, ExecutionError, ExecutionErrorReason,
WasmExecutionContext,
},
configs::ExecutionSettings,
configs::{AllocationsConfig, ExecutionSettings},
ext::{ProcessorContext, ProcessorExt},
};
use alloc::{
Expand All @@ -34,21 +34,16 @@ use gear_core::{
gas::{ChargeResult, GasAllowanceCounter, GasCounter, ValueCounter},
ids::ProgramId,
memory::{AllocationsContext, Memory, PageBuf, PageNumber, WasmPageNumber},
message::{ContextSettings, DispatchKind, IncomingDispatch, MessageContext},
message::{ContextSettings, IncomingDispatch, MessageContext},
};

/// Make checks that everything with memory pages go well.
/// Charge gas for pages init/load/grow and checks that there is enough gas for that.
/// Returns size of wasm memory buffer which must be created in execution environment.
fn make_checks_and_charge_gas_for_pages<'a>(
settings: &ExecutionSettings,
gas_counter: &mut GasCounter,
gas_allowance_counter: &mut GasAllowanceCounter,
/// Make checks that everything with memory goes well.
fn check_memory<'a>(
allocations: &BTreeSet<WasmPageNumber>,
pages_with_data: impl Iterator<Item = &'a PageNumber>,
static_pages: WasmPageNumber,
initial_execution: bool,
) -> Result<WasmPageNumber, ExecutionErrorReason> {
memory_size: WasmPageNumber,
) -> Result<(), ExecutionErrorReason> {
// Checks that all pages with data are in allocations set.
for page in pages_with_data {
let wasm_page = page.to_wasm_page();
Expand All @@ -57,7 +52,30 @@ fn make_checks_and_charge_gas_for_pages<'a>(
}
}

let mem_size = if !initial_execution {
if memory_size < static_pages {
log::error!(
"Mem size less then static pages num: mem_size = {:?}, static_pages = {:?}",
memory_size,
static_pages
);
return Err(ExecutionErrorReason::InsufficientMemorySize);
}

Ok(())
}

/// Charge gas for pages init/load/grow and checks that there is enough gas for that.
/// Returns size of wasm memory buffer which must be created in execution environment.
pub(crate) fn charge_gas_for_pages(
settings: &AllocationsConfig,
gas_counter: &mut GasCounter,
gas_allowance_counter: &mut GasAllowanceCounter,
allocations: &BTreeSet<WasmPageNumber>,
static_pages: WasmPageNumber,
initial_execution: bool,
subsequent_execution: bool,
) -> Result<WasmPageNumber, ExecutionErrorReason> {
if !initial_execution {
let max_wasm_page = if let Some(page) = allocations.iter().next_back() {
*page
} else if static_pages != WasmPageNumber(0) {
Expand All @@ -66,20 +84,21 @@ fn make_checks_and_charge_gas_for_pages<'a>(
return Ok(0.into());
};

// Charging gas for loaded pages
let amount = settings.load_page_cost() * (allocations.len() as u64 + static_pages.0 as u64);

if gas_allowance_counter.charge(amount) != ChargeResult::Enough {
return Err(ExecutionErrorReason::LoadMemoryBlockGasExceeded);
}
if !subsequent_execution {
// Charging gas for loaded pages
let amount =
settings.load_page_cost * (allocations.len() as u64 + static_pages.0 as u64);
if gas_allowance_counter.charge(amount) != ChargeResult::Enough {
return Err(ExecutionErrorReason::LoadMemoryBlockGasExceeded);
}

if gas_counter.charge(amount) != ChargeResult::Enough {
return Err(ExecutionErrorReason::LoadMemoryGasExceeded);
if gas_counter.charge(amount) != ChargeResult::Enough {
return Err(ExecutionErrorReason::LoadMemoryGasExceeded);
}
}

// Charging gas for mem size
let amount =
settings.mem_grow_cost() * (max_wasm_page.0 as u64 + 1 - static_pages.0 as u64);
let amount = settings.mem_grow_cost * (max_wasm_page.0 as u64 + 1 - static_pages.0 as u64);

if gas_allowance_counter.charge(amount) != ChargeResult::Enough {
return Err(ExecutionErrorReason::GrowMemoryBlockGasExceeded);
Expand All @@ -90,32 +109,21 @@ fn make_checks_and_charge_gas_for_pages<'a>(
}

// +1 because pages numeration begins from 0
max_wasm_page + 1.into()
Ok(max_wasm_page + 1.into())
} else {
// Charging gas for initial pages
let amount = settings.init_cost() * static_pages.0 as u64;
let amount = settings.init_cost * static_pages.0 as u64;

if gas_allowance_counter.charge(amount) != ChargeResult::Enough {
return Err(ExecutionErrorReason::GrowMemoryBlockGasExceeded);
return Err(ExecutionErrorReason::InitialMemoryBlockGasExceeded);
}

if gas_counter.charge(amount) != ChargeResult::Enough {
return Err(ExecutionErrorReason::InitialMemoryGasExceeded);
}

static_pages
};

if mem_size < static_pages {
log::error!(
"Mem size less then static pages num: mem_size = {:?}, static_pages = {:?}",
mem_size,
static_pages
);
return Err(ExecutionErrorReason::InsufficientMemorySize);
Ok(static_pages)
}

Ok(mem_size)
}

/// Writes initial pages data to memory and prepare memory for execution.
Expand Down Expand Up @@ -201,7 +209,6 @@ fn get_pages_to_be_updated<A: ProcessorExt>(
/// Execute wasm with dispatch and return dispatch result.
pub fn execute_wasm<A: ProcessorExt + EnvExt + IntoExtInfo + 'static, E: Environment<A>>(
balance: u128,
data: ExecutableActorData,
dispatch: IncomingDispatch,
context: WasmExecutionContext,
settings: ExecutionSettings,
Expand All @@ -215,48 +222,40 @@ pub fn execute_wasm<A: ProcessorExt + EnvExt + IntoExtInfo + 'static, E: Environ
panic!("Cannot use ext with lazy pages without lazy pages env enabled");
}

let ExecutableActorData {
let WasmExecutionContext {
gas_counter,
gas_allowance_counter,
origin,
program,
pages_data: mut pages_initial_data,
} = data;
mut pages_initial_data,
memory_size,
} = context;

let program_id = program.id();
let kind = dispatch.kind();

log::debug!("Executing program {}", program_id);
log::debug!("Executing dispatch {:?}", dispatch);

// Creating gas counters.
let mut gas_counter = GasCounter::new(dispatch.gas_limit());
let mut gas_allowance_counter = GasAllowanceCounter::new(context.gas_allowance);

let static_pages = program.static_pages();
let allocations = program.get_allocations();

let mem_size = match make_checks_and_charge_gas_for_pages(
&settings,
&mut gas_counter,
&mut gas_allowance_counter,
program.get_allocations(),
if let Err(reason) = check_memory(
allocations,
pages_initial_data.keys(),
static_pages,
dispatch.context().is_none() && matches!(kind, DispatchKind::Init),
memory_size,
) {
Ok(mem_size) => mem_size,
Err(reason) => {
return Err(ExecutionError {
program_id,
gas_amount: gas_counter.into(),
reason,
})
}
};
return Err(ExecutionError {
program_id,
gas_amount: gas_counter.into(),
reason,
});
}

// Creating allocations context.
let allocations_context = AllocationsContext::new(
program.get_allocations().clone(),
static_pages,
settings.max_pages(),
);
let allocations_context =
AllocationsContext::new(allocations.clone(), static_pages, settings.max_pages());

// Creating message context.
let message_context = MessageContext::new_with_settings(
Expand All @@ -278,7 +277,7 @@ pub fn execute_wasm<A: ProcessorExt + EnvExt + IntoExtInfo + 'static, E: Environ
block_info: settings.block_info,
config: settings.allocations_config,
existential_deposit: settings.existential_deposit,
origin: context.origin,
origin,
program_id,
program_candidates_data: Default::default(),
host_fn_weights: settings.host_fn_weights,
Expand All @@ -294,7 +293,7 @@ pub fn execute_wasm<A: ProcessorExt + EnvExt + IntoExtInfo + 'static, E: Environ
&mut ext,
program.raw_code(),
program.code().exports().clone(),
mem_size,
memory_size,
&kind,
|memory| {
prepare_memory::<A, E::Memory>(
Expand Down Expand Up @@ -335,7 +334,7 @@ pub fn execute_wasm<A: ProcessorExt + EnvExt + IntoExtInfo + 'static, E: Environ
};

// Page which is right after stack last page
log::trace!("Stack end page = {:?}", stack_end_page);
log::trace!("Stack end page = {stack_end_page:?}");
gshep marked this conversation as resolved.
Show resolved Hide resolved

log::debug!("Termination reason: {:?}", termination);

Expand Down
2 changes: 1 addition & 1 deletion core-processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ pub const RE_INIT_EXIT_CODE: ExitCode = 3;
pub use executor::execute_wasm;
pub use ext::{Ext, ProcessorContext, ProcessorError, ProcessorExt};
pub use handler::handle_journal;
pub use processor::process;
pub use processor::{prepare, process, PrepareResult, PreparedMessageExecutionContext};
Loading