Skip to content

Commit

Permalink
feat(pallet-gear): move allocations to separate storage; remove `pa…
Browse files Browse the repository at this point in the history
…ges_with_data`; expand max memory size to 2 GB (#3954)
  • Loading branch information
grishasobol authored Jul 31, 2024
1 parent 3945a2f commit 00c535f
Show file tree
Hide file tree
Showing 42 changed files with 1,039 additions and 261 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,6 @@ jobs:
- name: "Test: Try runtime migrations"
run: |
export RUST_LOG=remote-ext=debug,runtime=debug
echo "---------- Downloading try-runtime CLI ----------"
curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.5.4/try-runtime-x86_64-unknown-linux-musl -o try-runtime
chmod +x ./try-runtime
Expand All @@ -159,7 +157,7 @@ jobs:
time ./try-runtime --runtime ./target/${{ matrix.profiles.name }}/wbuild/vara-runtime/vara_runtime.wasm on-runtime-upgrade --checks=all --no-weight-warnings --disable-spec-version-check live --uri ws://rpc-private.vara-network.io:9944
sleep 5
env:
RUST_LOG: info,remote-ext=debug,runtime=debug
RUST_LOG: info,pallet=debug

- name: "Build: Production binaries"
if: ${{ inputs.production && matrix.profiles.name == 'release' }}
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions common/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,7 @@ pub fn set_program<ProgramStorage, BlockNumber>(
ProgramStorage::add_program(
program_id,
ActiveProgram {
allocations: Default::default(),
pages_with_data: Default::default(),
allocations_tree_len: 0,
code_hash: CodeId::generate(&code).into_origin(),
code_exports: Default::default(),
static_pages,
Expand Down
60 changes: 48 additions & 12 deletions common/src/program_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use gear_core::pages::{numerated::tree::IntervalsTree, WasmPage};

use super::*;
use crate::storage::{MapStorage, TripleMapStorage};
use core::fmt::Debug;
Expand Down Expand Up @@ -56,11 +58,13 @@ pub trait ProgramStorage {
Key3 = GearPage,
Value = PageBuf,
>;
type AllocationsMap: MapStorage<Key = ProgramId, Value = IntervalsTree<WasmPage>>;

/// Attempt to remove all items from all the associated maps.
fn reset() {
Self::ProgramMap::clear();
Self::MemoryPageMap::clear();
Self::AllocationsMap::clear();
}

/// Store a program to be associated with the given key `program_id` from the map.
Expand Down Expand Up @@ -102,6 +106,46 @@ pub trait ProgramStorage {
})
}

fn remove_data_for_pages(
program_id: ProgramId,
memory_infix: MemoryInfix,
pages: impl Iterator<Item = GearPage>,
) {
for page in pages {
Self::remove_program_page_data(program_id, memory_infix, page);
}
}

fn allocations(program_id: ProgramId) -> Option<IntervalsTree<WasmPage>> {
Self::AllocationsMap::get(&program_id)
}

fn set_allocations(program_id: ProgramId, allocations: IntervalsTree<WasmPage>) {
Self::update_active_program(program_id, |program| {
program.allocations_tree_len = u32::try_from(allocations.intervals_amount())
.unwrap_or_else(|err| {
// This panic is impossible because page numbers are u32.
unreachable!("allocations tree length is too big to fit into u32: {err}")
});
})
.unwrap_or_else(|err| {
// set_allocations must be called only for active programs.
unreachable!("Failed to update program allocations: {err:?}")
});
Self::AllocationsMap::insert(program_id, allocations);
}

fn clear_allocations(program_id: ProgramId) {
Self::AllocationsMap::remove(program_id);
}

fn memory_infix(program_id: ProgramId) -> Option<MemoryInfix> {
match Self::ProgramMap::get(&program_id) {
Some(Program::Active(program)) => Some(program.memory_infix),
_ => None,
}
}

/// Update the program under the given key `program_id` only if the
/// stored program is an active one.
fn update_program_if_active<F, ReturnType>(
Expand All @@ -124,20 +168,12 @@ pub trait ProgramStorage {
Ok(result)
}

/// Return program data for each page from `pages`.
fn get_program_data_for_pages(
/// Return data buffer for each memory page, which has data.
fn get_program_pages_data(
program_id: ProgramId,
memory_infix: MemoryInfix,
pages: impl Iterator<Item = GearPage>,
) -> Result<MemoryMap, Self::Error> {
let mut pages_data = BTreeMap::new();
for page in pages {
let data = Self::MemoryPageMap::get(&program_id, &memory_infix, &page)
.ok_or(Self::InternalError::cannot_find_page_data())?;
pages_data.insert(page, data);
}

Ok(pages_data)
Ok(Self::MemoryPageMap::iter_prefix(&program_id, &memory_infix).collect())
}

/// Store a memory page buffer to be associated with the given keys `program_id`, `memory_infix` and `page` from the map.
Expand All @@ -160,7 +196,7 @@ pub trait ProgramStorage {
}

/// Remove all memory page buffers under the given keys `program_id` and `memory_infix`.
fn remove_program_pages(program_id: ProgramId, memory_infix: MemoryInfix) {
fn clear_program_memory(program_id: ProgramId, memory_infix: MemoryInfix) {
Self::MemoryPageMap::clear_prefix(program_id, memory_infix);
}

Expand Down
1 change: 0 additions & 1 deletion common/src/scheduler/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ impl<AccountId> ScheduledTask<AccountId> {
RemoveGasReservation(program_id, reservation_id) => {
handler.remove_gas_reservation(program_id, reservation_id)
}

#[allow(deprecated)]
RemoveResumeSession(session_id) => handler.remove_resume_session(session_id),
}
Expand Down
12 changes: 12 additions & 0 deletions common/src/storage/primitives/triple_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ pub trait TripleMapStorage {

/// Remove items from the map matching a `key1`/`key2` prefix.
fn clear_prefix(key1: Self::Key1, key2: Self::Key2);

fn iter_prefix(
key1: &Self::Key1,
key2: &Self::Key2,
) -> impl Iterator<Item = (Self::Key3, Self::Value)>;
}

/// Creates new type with specified name and key1-key2-key3-value types and
Expand Down Expand Up @@ -150,6 +155,13 @@ macro_rules! wrap_storage_triple_map {
fn clear_prefix(key1: Self::Key1, key2: Self::Key2) {
let _ = $storage::<T>::clear_prefix((key1, key2), u32::MAX, None);
}

fn iter_prefix(
key1: &Self::Key1,
key2: &Self::Key2,
) -> impl Iterator<Item = (Self::Key3, Self::Value)> {
$storage::<T>::iter_prefix((key1, key2))
}
}
};
}
28 changes: 0 additions & 28 deletions core-processor/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,31 +561,3 @@ pub(crate) struct WasmExecutionContext {
/// Size of the memory block.
pub memory_size: WasmPagesAmount,
}

/// Struct with dispatch and counters charged for program data.
#[derive(Debug)]
pub struct PrechargedDispatch {
dispatch: IncomingDispatch,
gas: GasCounter,
allowance: GasAllowanceCounter,
}

impl PrechargedDispatch {
/// Create new instance from parts.
pub(crate) fn from_parts(
dispatch: IncomingDispatch,
gas: GasCounter,
allowance: GasAllowanceCounter,
) -> Self {
Self {
dispatch,
gas,
allowance,
}
}

/// Decompose the instance into parts.
pub fn into_parts(self) -> (IncomingDispatch, GasCounter, GasAllowanceCounter) {
(self.dispatch, self.gas, self.allowance)
}
}
2 changes: 2 additions & 0 deletions core-processor/src/configs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ pub struct ProcessCosts {
pub instrumentation_per_byte: CostOf<BytesAmount>,
/// Module instantiation costs.
pub instantiation_costs: InstantiationCosts,
/// Load program allocations cost per interval.
pub load_allocations_per_interval: CostOf<u32>,
}

/// Execution settings for handling messages.
Expand Down
11 changes: 11 additions & 0 deletions core-processor/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ use gear_core::{
reservation::GasReserver,
};

/// Struct with dispatch and counters charged for program data.
#[derive(Debug)]
pub struct ContextChargedForProgram {
pub(crate) dispatch: IncomingDispatch,
pub(crate) destination_id: ProgramId,
pub(crate) gas_counter: GasCounter,
pub(crate) gas_allowance_counter: GasAllowanceCounter,
}

pub struct ContextChargedForAllocations(pub(crate) ContextChargedForProgram);

pub(crate) struct ContextData {
pub(crate) gas_counter: GasCounter,
pub(crate) gas_allowance_counter: GasAllowanceCounter,
Expand Down
5 changes: 3 additions & 2 deletions core-processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ pub use ext::{
};
pub use handler::handle_journal;
pub use precharge::{
precharge_for_code, precharge_for_code_length, precharge_for_instrumentation,
precharge_for_module_instantiation, precharge_for_program, SuccessfulDispatchResultKind,
precharge_for_allocations, precharge_for_code, precharge_for_code_length,
precharge_for_instrumentation, precharge_for_module_instantiation, precharge_for_program,
SuccessfulDispatchResultKind,
};
pub use processing::{
process, process_execution_error, process_non_executable, process_reinstrumentation_error,
Expand Down
76 changes: 64 additions & 12 deletions core-processor/src/precharge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use crate::{
common::{
ActorExecutionErrorReplyReason, DispatchResult, ExecutableActorData, JournalNote,
PrechargedDispatch,
},
common::{ActorExecutionErrorReplyReason, DispatchResult, ExecutableActorData, JournalNote},
configs::{BlockConfig, ProcessCosts},
context::{
ContextChargedForCodeLength, ContextChargedForMemory, ContextData, SystemReservationContext,
ContextChargedForAllocations, ContextChargedForCodeLength, ContextChargedForMemory,
ContextChargedForProgram, ContextData, SystemReservationContext,
},
processing::{process_allowance_exceed, process_execution_error, process_success},
ContextChargedForCode, ContextChargedForInstrumentation,
Expand Down Expand Up @@ -56,6 +54,9 @@ pub enum PreChargeGasOperation {
/// Instrument Wasm module.
#[display(fmt = "instrument Wasm module")]
ModuleInstrumentation,
/// Obtain program allocations.
#[display(fmt = "obtain program allocations")]
Allocations,
}

#[derive(Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -163,7 +164,7 @@ impl<'a> GasPrecharger<'a> {
}
}

/// Possible variants of the `DispatchResult` if the latter contains value.
/// Possible variants of the [`DispatchResult`] if the latter contains value.
#[allow(missing_docs)]
#[derive(Debug)]
pub enum SuccessfulDispatchResultKind {
Expand All @@ -181,7 +182,7 @@ pub fn precharge_for_program(
gas_allowance: u64,
dispatch: IncomingDispatch,
destination_id: ProgramId,
) -> PrechargeResult<PrechargedDispatch> {
) -> PrechargeResult<ContextChargedForProgram> {
let mut gas_counter = GasCounter::new(dispatch.gas_limit());
let mut gas_allowance_counter = GasAllowanceCounter::new(gas_allowance);
let mut charger = GasPrecharger::new(
Expand All @@ -191,11 +192,12 @@ pub fn precharge_for_program(
);

match charger.charge_gas_for_program_data() {
Ok(()) => Ok(PrechargedDispatch::from_parts(
Ok(()) => Ok(ContextChargedForProgram {
dispatch,
destination_id,
gas_counter,
gas_allowance_counter,
)),
}),
Err(PrechargeError::BlockGasExceeded) => {
let gas_burned = gas_counter.burned();
Err(process_allowance_exceed(
Expand All @@ -218,6 +220,52 @@ pub fn precharge_for_program(
}
}

/// Precharge for allocations obtaining from storage.
pub fn precharge_for_allocations(
block_config: &BlockConfig,
mut context: ContextChargedForProgram,
allocations_tree_len: u32,
) -> PrechargeResult<ContextChargedForAllocations> {
let mut charger = GasPrecharger::new(
&mut context.gas_counter,
&mut context.gas_allowance_counter,
&block_config.costs,
);

if allocations_tree_len == 0 {
return Ok(ContextChargedForAllocations(context));
}

let amount = block_config
.costs
.load_allocations_per_interval
.cost_for(allocations_tree_len)
.saturating_add(block_config.costs.read.cost_for_one());

match charger.charge_gas(PreChargeGasOperation::Allocations, amount) {
Ok(()) => Ok(ContextChargedForAllocations(context)),
Err(PrechargeError::BlockGasExceeded) => {
let gas_burned = context.gas_counter.burned();
Err(process_allowance_exceed(
context.dispatch,
context.destination_id,
gas_burned,
))
}
Err(PrechargeError::GasExceeded(op)) => {
let gas_burned = context.gas_counter.burned();
let system_reservation_ctx = SystemReservationContext::from_dispatch(&context.dispatch);
Err(process_execution_error(
context.dispatch,
context.destination_id,
gas_burned,
system_reservation_ctx,
ActorExecutionErrorReplyReason::PreChargeGasLimitExceeded(op),
))
}
}
}

/// Charge a message for fetching the actual length of the binary code
/// from a storage. The updated value of binary code length
/// should be kept in standalone storage. The caller has to call this
Expand All @@ -228,11 +276,15 @@ pub fn precharge_for_program(
/// - if a required dispatch method is exported.
pub fn precharge_for_code_length(
block_config: &BlockConfig,
dispatch: PrechargedDispatch,
destination_id: ProgramId,
context: ContextChargedForAllocations,
actor_data: ExecutableActorData,
) -> PrechargeResult<ContextChargedForCodeLength> {
let (dispatch, mut gas_counter, mut gas_allowance_counter) = dispatch.into_parts();
let ContextChargedForProgram {
dispatch,
destination_id,
mut gas_counter,
mut gas_allowance_counter,
} = context.0;

if !actor_data.code_exports.contains(&dispatch.kind()) {
return Err(process_success(
Expand Down
Loading

0 comments on commit 00c535f

Please sign in to comment.