Skip to content
Merged
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
2 changes: 1 addition & 1 deletion substrate/frame/revive/fixtures/contracts/event_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ include!("../panic_handler.rs");

use uapi::{input, HostFn, HostFnImpl as api};

static BUFFER: [u8; 16 * 1024 + 1] = [0u8; 16 * 1024 + 1];
static BUFFER: [u8; 64 * 1024 + 1] = [0u8; 64 * 1024 + 1];

#[no_mangle]
#[polkavm_derive::polkavm_export]
Expand Down
48 changes: 24 additions & 24 deletions substrate/frame/revive/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ mod benchmarks {
#[benchmark(skip_meta, pov_mode = Measured)]
fn on_initialize_per_trie_key(k: Linear<0, 1024>) -> Result<(), BenchmarkError> {
let instance =
Contract::<T>::with_storage(VmBinaryModule::dummy(), k, limits::PAYLOAD_BYTES)?;
Contract::<T>::with_storage(VmBinaryModule::dummy(), k, limits::STORAGE_BYTES)?;
instance.info()?.queue_trie_for_deletion();

#[block]
Expand Down Expand Up @@ -1233,7 +1233,7 @@ mod benchmarks {
#[benchmark(pov_mode = Measured)]
fn seal_deposit_event(
t: Linear<0, { limits::NUM_EVENT_TOPICS as u32 }>,
n: Linear<0, { limits::PAYLOAD_BYTES }>,
n: Linear<0, { limits::EVENT_BYTES }>,
) {
let num_topic = t as u32;
let topics = (0..t).map(|i| H256::repeat_byte(i as u8)).collect::<Vec<_>>();
Expand Down Expand Up @@ -1268,7 +1268,7 @@ mod benchmarks {
fn get_storage_empty() -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = vec![0u8; max_key_len as usize];
let max_value_len = limits::PAYLOAD_BYTES as usize;
let max_value_len = limits::STORAGE_BYTES as usize;
let value = vec![1u8; max_value_len];

let instance = Contract::<T>::new(VmBinaryModule::dummy(), vec![])?;
Expand All @@ -1291,7 +1291,7 @@ mod benchmarks {
fn get_storage_full() -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = vec![0u8; max_key_len as usize];
let max_value_len = limits::PAYLOAD_BYTES;
let max_value_len = limits::STORAGE_BYTES;
let value = vec![1u8; max_value_len as usize];

let instance = Contract::<T>::with_unbalanced_storage_trie(VmBinaryModule::dummy(), &key)?;
Expand All @@ -1314,7 +1314,7 @@ mod benchmarks {
fn set_storage_empty() -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = vec![0u8; max_key_len as usize];
let max_value_len = limits::PAYLOAD_BYTES as usize;
let max_value_len = limits::STORAGE_BYTES as usize;
let value = vec![1u8; max_value_len];

let instance = Contract::<T>::new(VmBinaryModule::dummy(), vec![])?;
Expand All @@ -1339,7 +1339,7 @@ mod benchmarks {
fn set_storage_full() -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = vec![0u8; max_key_len as usize];
let max_value_len = limits::PAYLOAD_BYTES;
let max_value_len = limits::STORAGE_BYTES;
let value = vec![1u8; max_value_len as usize];

let instance = Contract::<T>::with_unbalanced_storage_trie(VmBinaryModule::dummy(), &key)?;
Expand All @@ -1364,8 +1364,8 @@ mod benchmarks {
// o: old byte size
#[benchmark(skip_meta, pov_mode = Measured)]
fn seal_set_storage(
n: Linear<0, { limits::PAYLOAD_BYTES }>,
o: Linear<0, { limits::PAYLOAD_BYTES }>,
n: Linear<0, { limits::STORAGE_BYTES }>,
o: Linear<0, { limits::STORAGE_BYTES }>,
) -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
Expand Down Expand Up @@ -1397,7 +1397,7 @@ mod benchmarks {
}

#[benchmark(skip_meta, pov_mode = Measured)]
fn clear_storage(n: Linear<0, { limits::PAYLOAD_BYTES }>) -> Result<(), BenchmarkError> {
fn clear_storage(n: Linear<0, { limits::STORAGE_BYTES }>) -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
.map_err(|_| "Key has wrong length")?;
Expand Down Expand Up @@ -1430,7 +1430,7 @@ mod benchmarks {
}

#[benchmark(skip_meta, pov_mode = Measured)]
fn seal_get_storage(n: Linear<0, { limits::PAYLOAD_BYTES }>) -> Result<(), BenchmarkError> {
fn seal_get_storage(n: Linear<0, { limits::STORAGE_BYTES }>) -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
.map_err(|_| "Key has wrong length")?;
Expand Down Expand Up @@ -1460,7 +1460,7 @@ mod benchmarks {
}

#[benchmark(skip_meta, pov_mode = Measured)]
fn contains_storage(n: Linear<0, { limits::PAYLOAD_BYTES }>) -> Result<(), BenchmarkError> {
fn contains_storage(n: Linear<0, { limits::STORAGE_BYTES }>) -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
.map_err(|_| "Key has wrong length")?;
Expand Down Expand Up @@ -1492,7 +1492,7 @@ mod benchmarks {
}

#[benchmark(skip_meta, pov_mode = Measured)]
fn take_storage(n: Linear<0, { limits::PAYLOAD_BYTES }>) -> Result<(), BenchmarkError> {
fn take_storage(n: Linear<0, { limits::STORAGE_BYTES }>) -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![3u8; max_key_len as usize])
.map_err(|_| "Key has wrong length")?;
Expand Down Expand Up @@ -1530,7 +1530,7 @@ mod benchmarks {
// complexity can introduce approximation errors.
#[benchmark(pov_mode = Ignored)]
fn set_transient_storage_empty() -> Result<(), BenchmarkError> {
let max_value_len = limits::PAYLOAD_BYTES;
let max_value_len = limits::STORAGE_BYTES;
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
.map_err(|_| "Key has wrong length")?;
Expand All @@ -1552,7 +1552,7 @@ mod benchmarks {

#[benchmark(pov_mode = Ignored)]
fn set_transient_storage_full() -> Result<(), BenchmarkError> {
let max_value_len = limits::PAYLOAD_BYTES;
let max_value_len = limits::STORAGE_BYTES;
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
.map_err(|_| "Key has wrong length")?;
Expand All @@ -1575,7 +1575,7 @@ mod benchmarks {

#[benchmark(pov_mode = Ignored)]
fn get_transient_storage_empty() -> Result<(), BenchmarkError> {
let max_value_len = limits::PAYLOAD_BYTES;
let max_value_len = limits::STORAGE_BYTES;
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
.map_err(|_| "Key has wrong length")?;
Expand All @@ -1600,7 +1600,7 @@ mod benchmarks {

#[benchmark(pov_mode = Ignored)]
fn get_transient_storage_full() -> Result<(), BenchmarkError> {
let max_value_len = limits::PAYLOAD_BYTES;
let max_value_len = limits::STORAGE_BYTES;
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
.map_err(|_| "Key has wrong length")?;
Expand All @@ -1627,7 +1627,7 @@ mod benchmarks {
// The weight of journal rollbacks should be taken into account when setting storage.
#[benchmark(pov_mode = Ignored)]
fn rollback_transient_storage() -> Result<(), BenchmarkError> {
let max_value_len = limits::PAYLOAD_BYTES;
let max_value_len = limits::STORAGE_BYTES;
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
.map_err(|_| "Key has wrong length")?;
Expand Down Expand Up @@ -1655,8 +1655,8 @@ mod benchmarks {
// o: old byte size
#[benchmark(pov_mode = Measured)]
fn seal_set_transient_storage(
n: Linear<0, { limits::PAYLOAD_BYTES }>,
o: Linear<0, { limits::PAYLOAD_BYTES }>,
n: Linear<0, { limits::STORAGE_BYTES }>,
o: Linear<0, { limits::STORAGE_BYTES }>,
) -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
Expand Down Expand Up @@ -1689,7 +1689,7 @@ mod benchmarks {

#[benchmark(pov_mode = Measured)]
fn seal_clear_transient_storage(
n: Linear<0, { limits::PAYLOAD_BYTES }>,
n: Linear<0, { limits::STORAGE_BYTES }>,
) -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
Expand Down Expand Up @@ -1723,7 +1723,7 @@ mod benchmarks {

#[benchmark(pov_mode = Measured)]
fn seal_get_transient_storage(
n: Linear<0, { limits::PAYLOAD_BYTES }>,
n: Linear<0, { limits::STORAGE_BYTES }>,
) -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
Expand Down Expand Up @@ -1759,7 +1759,7 @@ mod benchmarks {

#[benchmark(pov_mode = Measured)]
fn seal_contains_transient_storage(
n: Linear<0, { limits::PAYLOAD_BYTES }>,
n: Linear<0, { limits::STORAGE_BYTES }>,
) -> Result<(), BenchmarkError> {
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
Expand Down Expand Up @@ -1794,9 +1794,9 @@ mod benchmarks {

#[benchmark(pov_mode = Measured)]
fn seal_take_transient_storage(
n: Linear<0, { limits::PAYLOAD_BYTES }>,
n: Linear<0, { limits::STORAGE_BYTES }>,
) -> Result<(), BenchmarkError> {
let n = limits::PAYLOAD_BYTES;
let n = limits::STORAGE_BYTES;
let value = vec![42u8; n as usize];
let max_key_len = limits::STORAGE_KEY_BYTES;
let key = Key::try_from_var(vec![0u8; max_key_len as usize])
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/revive/src/call_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ where
return Err("Key size too small to create the specified trie");
}

let value = vec![16u8; limits::PAYLOAD_BYTES as usize];
let value = vec![16u8; limits::STORAGE_BYTES as usize];
let contract = Contract::<T>::new(code, vec![])?;
let info = contract.info()?;
let child_trie_info = info.child_trie_info();
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/revive/src/evm/block_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ pub fn process_transaction<T: Config>(
// `EthereumBlockBuilder = 3 * (max size of transactions + max size of receipts)`
// The maximum size of a transaction is limited by
// `limits::MAX_TRANSACTION_PAYLOAD_SIZE`, while the maximum size of a receipt is
// limited by `limits::PAYLOAD_BYTES`.
// limited by `limits::EVENT_BYTES`.
//
// Similarly, this is the amount of pallet storage consumed by the
// `EthereumBlockBuilderIR` object, plus a marginal book-keeping overhead.
Expand Down
7 changes: 0 additions & 7 deletions substrate/frame/revive/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,9 +384,6 @@ pub trait PrecompileExt: sealing::Sealed {
/// Returns the chain id.
fn chain_id(&self) -> u64;

/// Returns the maximum allowed size of a storage item.
fn max_value_size(&self) -> u32;

/// Get an immutable reference to the nested gas meter.
fn gas_meter(&self) -> &GasMeter<Self::T>;

Expand Down Expand Up @@ -2130,10 +2127,6 @@ where
<T as Config>::ChainId::get()
}

fn max_value_size(&self) -> u32 {
limits::PAYLOAD_BYTES
}

fn gas_meter(&self) -> &GasMeter<Self::T> {
&self.top_frame().nested_gas
}
Expand Down
4 changes: 0 additions & 4 deletions substrate/frame/revive/src/exec/mock_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,6 @@ impl<T: Config> PrecompileExt for MockExt<T> {
panic!("MockExt::chain_id")
}

fn max_value_size(&self) -> u32 {
panic!("MockExt::max_value_size")
}

fn gas_meter(&self) -> &GasMeter<Self::T> {
&self.gas_meter
}
Expand Down
88 changes: 46 additions & 42 deletions substrate/frame/revive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ pub mod pallet {
DecodingFailed = 0x0A,
/// Contract trapped during execution.
ContractTrapped = 0x0B,
/// Event body or storage item exceeds [`limits::PAYLOAD_BYTES`].
/// Event body or storage item exceeds [`limits::STORAGE_BYTES`].
ValueTooLarge = 0x0C,
/// Termination of a contract is not allowed while the contract is already
/// on the call stack. Can be triggered by `seal_terminate`.
Expand Down Expand Up @@ -840,55 +840,59 @@ pub mod pallet {
T::FeeInfo::integrity_test();

// The memory available in the block building runtime
let max_runtime_mem: u32 = T::RuntimeMemory::get();
let max_runtime_mem: u64 = T::RuntimeMemory::get().into();

// We only allow 50% of the runtime memory to be utilized by the contracts call
// stack, keeping the rest for other facilities, such as PoV, etc.
const TOTAL_MEMORY_DEVIDER: u32 = 2;
const TOTAL_MEMORY_DEVIDER: u64 = 2;

// 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()
let max_block_weight = T::BlockWeights::get()
.get(DispatchClass::Normal)
.max_total
.unwrap_or_else(|| T::BlockWeights::get().max_block)
.ref_time();
let max_payload_size = limits::PAYLOAD_BYTES;
let max_key_size =
.unwrap_or_else(|| T::BlockWeights::get().max_block);
let max_key_size: u64 =
Key::try_from_var(alloc::vec![0u8; limits::STORAGE_KEY_BYTES as usize])
.expect("Key of maximal size shall be created")
.hash()
.len() as u32;

let max_immutable_key_size = T::AccountId::max_encoded_len() as u32;
let max_immutable_size: u32 = ((max_block_ref_time /
(<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::SetImmutableData(
limits::IMMUTABLE_BYTES,
.len()
.try_into()
.unwrap();

let max_immutable_key_size: u64 = T::AccountId::max_encoded_len().try_into().unwrap();
let max_immutable_size: u64 = max_block_weight
.checked_div_per_component(&<RuntimeCosts as gas::Token<T>>::weight(
&RuntimeCosts::SetImmutableData(limits::IMMUTABLE_BYTES),
))
.ref_time()))
.saturating_mul(limits::IMMUTABLE_BYTES.saturating_add(max_immutable_key_size) as u64))
.try_into()
.expect("Immutable data size too big");
.unwrap()
.saturating_mul(
u64::from(limits::IMMUTABLE_BYTES)
.saturating_add(max_immutable_key_size)
.into(),
);

let max_pvf_mem: u32 = T::PVFMemory::get();
let max_pvf_mem: u64 = T::PVFMemory::get().into();
let storage_size_limit = max_pvf_mem.saturating_sub(max_runtime_mem) / 2;

// 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,
})
.saturating_add(<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::HostFn))
.ref_time()))
.saturating_mul(max_payload_size as u64))
.try_into()
.expect("Events size too big");
let max_events_size = max_block_weight
.checked_div_per_component(
&(<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::DepositEvent {
num_topic: 0,
len: limits::EVENT_BYTES,
})
.saturating_add(<RuntimeCosts as gas::Token<T>>::weight(
&RuntimeCosts::HostFn,
))),
)
.unwrap()
.saturating_mul(limits::EVENT_BYTES.into());

assert!(
max_events_size < storage_size_limit,
Expand Down Expand Up @@ -932,7 +936,7 @@ pub mod pallet {
// In practice, the builder will consume even lower amounts considering
// it is unlikely for a transaction to utilize all the weight of the block for events.
let max_eth_block_builder_bytes =
block_storage::block_builder_bytes_usage(max_events_size);
block_storage::block_builder_bytes_usage(max_events_size.try_into().unwrap());

log::debug!(
target: LOG_TARGET,
Expand All @@ -945,7 +949,7 @@ pub mod pallet {
//
// Dynamic allocations are not available, yet. Hence they are not taken into
// consideration here.
let memory_left = i64::from(max_runtime_mem)
let memory_left = i128::from(max_runtime_mem)
.saturating_div(TOTAL_MEMORY_DEVIDER.into())
.saturating_sub(limits::MEMORY_REQUIRED.into())
.saturating_sub(max_eth_block_builder_bytes.into());
Expand All @@ -960,17 +964,17 @@ pub mod pallet {

// 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))
.saturating_add(max_immutable_size.into())
.saturating_add(max_eth_block_builder_bytes.into())
.try_into()
.expect("Storage size too big");
let max_storage_size = max_block_weight
.checked_div_per_component(
&<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::SetStorage {
new_bytes: limits::STORAGE_BYTES,
old_bytes: 0,
})
.saturating_mul(u64::from(limits::STORAGE_BYTES).saturating_add(max_key_size)),
)
.unwrap()
.saturating_add(max_immutable_size.into())
.saturating_add(max_eth_block_builder_bytes.into());

assert!(
max_storage_size < storage_size_limit,
Expand Down
Loading
Loading