Skip to content

Commit

Permalink
[pallet_contracts] Increase the weight of the deposit_event host func…
Browse files Browse the repository at this point in the history
…tion to limit the memory used by events. (#4973)

This PR updates the weight of the `deposit_event` host function by
adding
a fixed ref_time of 60,000 picoseconds per byte. Given a block time of 2
seconds
and this specified ref_time, the total allocation size is 32MB.

---------

Co-authored-by: Alexander Theißen <alex.theissen@me.com>
  • Loading branch information
smiasojed and athei authored Aug 6, 2024
1 parent 2b5ccba commit 11fdff1
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 3 deletions.
15 changes: 15 additions & 0 deletions prdoc/pr_4973.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json

title: "[pallet_contracts] Increase the weight of the deposit_event host function to limit the memory used by events."

doc:
- audience: Runtime User
description: |
This PR updates the weight of the deposit_event host function by adding
a fixed ref_time of 60,000 picoseconds per byte. Given a block time of 2 seconds
and this specified ref_time, the total allocation size is 32MB.

crates:
- name: pallet-contracts
bump: major
63 changes: 61 additions & 2 deletions substrate/frame/contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ use crate::{
},
gas::GasMeter,
storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager},
wasm::{CodeInfo, WasmBlob},
wasm::{CodeInfo, RuntimeCosts, WasmBlob},
};
use codec::{Codec, Decode, Encode, HasCompact, MaxEncodedLen};
use core::fmt::Debug;
Expand Down Expand Up @@ -670,7 +670,66 @@ pub mod pallet {
"Debug buffer should have minimum size of {} (current setting is {})",
MIN_DEBUG_BUF_SIZE,
T::MaxDebugBufferLen::get(),
)
);

// Validators are configured to be able to use more memory than block builders. This is
// because in addition to `max_runtime_mem` they need to hold additional data in
// memory: PoV in multiple copies (1x encoded + 2x decoded) and all storage which
// includes emitted events. The assumption is that storage/events size
// can be a maximum of half of the validator runtime memory - max_runtime_mem.
let max_block_ref_time = T::BlockWeights::get()
.get(DispatchClass::Normal)
.max_total
.unwrap_or_else(|| T::BlockWeights::get().max_block)
.ref_time();
let max_payload_size = T::Schedule::get().limits.payload_len;
let max_key_size =
Key::<T>::try_from_var(alloc::vec![0u8; T::MaxStorageKeyLen::get() as usize])
.expect("Key of maximal size shall be created")
.hash()
.len() as u32;

// We can use storage to store items using the available block ref_time with the
// `set_storage` host function.
let max_storage_size: u32 = ((max_block_ref_time /
(<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::SetStorage {
new_bytes: max_payload_size,
old_bytes: 0,
})
.ref_time()))
.saturating_mul(max_payload_size.saturating_add(max_key_size) as u64))
.try_into()
.expect("Storage size too big");

let max_validator_runtime_mem: u32 = T::Schedule::get().limits.validator_runtime_memory;
let storage_size_limit = max_validator_runtime_mem.saturating_sub(max_runtime_mem) / 2;

assert!(
max_storage_size < storage_size_limit,
"Maximal storage size {} exceeds the storage limit {}",
max_storage_size,
storage_size_limit
);

// We can use storage to store events using the available block ref_time with the
// `deposit_event` host function. The overhead of stored events, which is around 100B,
// is not taken into account to simplify calculations, as it does not change much.
let max_events_size: u32 = ((max_block_ref_time /
(<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::DepositEvent {
num_topic: 0,
len: max_payload_size,
})
.ref_time()))
.saturating_mul(max_payload_size as u64))
.try_into()
.expect("Events size too big");

assert!(
max_events_size < storage_size_limit,
"Maximal events size {} exceeds the events limit {}",
max_events_size,
storage_size_limit
);
}
}

Expand Down
10 changes: 10 additions & 0 deletions substrate/frame/contracts/src/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ pub struct Limits {
/// The maximum node runtime memory. This is for integrity checks only and does not affect the
/// real setting.
pub runtime_memory: u32,

/// The maximum validator node runtime memory. This is for integrity checks only and does not
/// affect the real setting.
pub validator_runtime_memory: u32,

/// The additional ref_time added to the `deposit_event` host function call per event data
/// byte.
pub event_ref_time: u64,
}

impl Limits {
Expand Down Expand Up @@ -121,6 +129,8 @@ impl Default for Limits {
subject_len: 32,
payload_len: 16 * 1024,
runtime_memory: 1024 * 1024 * 128,
validator_runtime_memory: 1024 * 1024 * 512,
event_ref_time: 60_000,
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion substrate/frame/contracts/src/wasm/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,13 @@ impl<T: Config> Token<T> for RuntimeCosts {
WeightToFee => T::WeightInfo::seal_weight_to_fee(),
Terminate(locked_dependencies) => T::WeightInfo::seal_terminate(locked_dependencies),
Random => T::WeightInfo::seal_random(),
DepositEvent { num_topic, len } => T::WeightInfo::seal_deposit_event(num_topic, len),
// Given a 2-second block time and hardcoding a `ref_time` of 60,000 picoseconds per
// byte (event_ref_time), the max allocation size is 32MB per block.
DepositEvent { num_topic, len } => T::WeightInfo::seal_deposit_event(num_topic, len)
.saturating_add(Weight::from_parts(
T::Schedule::get().limits.event_ref_time.saturating_mul(len.into()),
0,
)),
DebugMessage(len) => T::WeightInfo::seal_debug_message(len),
SetStorage { new_bytes, old_bytes } =>
cost_storage!(write, seal_set_storage, new_bytes, old_bytes),
Expand Down

0 comments on commit 11fdff1

Please sign in to comment.