diff --git a/prdoc/pr_10047.prdoc b/prdoc/pr_10047.prdoc new file mode 100644 index 0000000000000..a014fd3d7addb --- /dev/null +++ b/prdoc/pr_10047.prdoc @@ -0,0 +1,12 @@ +title: 'pallet_revive: Increase event sizes' +doc: +- audience: Runtime User + description: |- + Fixes https://github.com/paritytech/contract-issues/issues/140 + + This increases the maximum event payload size from 416 bytes to 64k. Since https://github.com/paritytech/polkadot-sdk/pull/9418 we charge some additional weight per byte of event payload. This makes it possible to raise the limit while staying within our memory envelope. This artificial weight will add 18us of weight to a maximum sized event. +crates: +- name: pallet-revive-fixtures + bump: patch +- name: pallet-revive + bump: patch diff --git a/substrate/frame/revive/fixtures/contracts/event_size.rs b/substrate/frame/revive/fixtures/contracts/event_size.rs index 92f5caf115f61..b1b88ceb7d4b6 100644 --- a/substrate/frame/revive/fixtures/contracts/event_size.rs +++ b/substrate/frame/revive/fixtures/contracts/event_size.rs @@ -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] diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 76c43b1a38360..2bc903630613a 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -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::::with_storage(VmBinaryModule::dummy(), k, limits::PAYLOAD_BYTES)?; + Contract::::with_storage(VmBinaryModule::dummy(), k, limits::STORAGE_BYTES)?; instance.info()?.queue_trie_for_deletion(); #[block] @@ -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::>(); @@ -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::::new(VmBinaryModule::dummy(), vec![])?; @@ -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::::with_unbalanced_storage_trie(VmBinaryModule::dummy(), &key)?; @@ -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::::new(VmBinaryModule::dummy(), vec![])?; @@ -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::::with_unbalanced_storage_trie(VmBinaryModule::dummy(), &key)?; @@ -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]) @@ -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")?; @@ -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")?; @@ -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")?; @@ -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")?; @@ -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")?; @@ -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")?; @@ -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")?; @@ -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")?; @@ -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")?; @@ -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]) @@ -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]) @@ -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]) @@ -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]) @@ -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]) diff --git a/substrate/frame/revive/src/call_builder.rs b/substrate/frame/revive/src/call_builder.rs index 9f5ba521d205c..a4a781e52bbf4 100644 --- a/substrate/frame/revive/src/call_builder.rs +++ b/substrate/frame/revive/src/call_builder.rs @@ -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::::new(code, vec![])?; let info = contract.info()?; let child_trie_info = info.child_trie_info(); diff --git a/substrate/frame/revive/src/evm/block_storage.rs b/substrate/frame/revive/src/evm/block_storage.rs index 480bdbb7db6e0..61aff1352cc17 100644 --- a/substrate/frame/revive/src/evm/block_storage.rs +++ b/substrate/frame/revive/src/evm/block_storage.rs @@ -178,7 +178,7 @@ pub fn process_transaction( // `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. diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index f0b6ef0682cd0..e7849c7d995d8 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -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; @@ -2130,10 +2127,6 @@ where ::ChainId::get() } - fn max_value_size(&self) -> u32 { - limits::PAYLOAD_BYTES - } - fn gas_meter(&self) -> &GasMeter { &self.top_frame().nested_gas } diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index 57c1df0093391..77473681c60ed 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -152,10 +152,6 @@ impl PrecompileExt for MockExt { panic!("MockExt::chain_id") } - fn max_value_size(&self) -> u32 { - panic!("MockExt::max_value_size") - } - fn gas_meter(&self) -> &GasMeter { &self.gas_meter } diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index b83cd2962acec..536c94b7c48ff 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -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`. @@ -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 / - (>::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(&>::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 / - (>::weight(&RuntimeCosts::DepositEvent { - num_topic: 0, - len: max_payload_size, - }) - .saturating_add(>::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( + &(>::weight(&RuntimeCosts::DepositEvent { + num_topic: 0, + len: limits::EVENT_BYTES, + }) + .saturating_add(>::weight( + &RuntimeCosts::HostFn, + ))), + ) + .unwrap() + .saturating_mul(limits::EVENT_BYTES.into()); assert!( max_events_size < storage_size_limit, @@ -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, @@ -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()); @@ -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 / - (>::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( + &>::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, diff --git a/substrate/frame/revive/src/limits.rs b/substrate/frame/revive/src/limits.rs index 1265c2e3cb03d..68108846b5856 100644 --- a/substrate/frame/revive/src/limits.rs +++ b/substrate/frame/revive/src/limits.rs @@ -48,19 +48,22 @@ pub const CALL_STACK_DEPTH: u32 = 25; /// We set it to the same limit that ethereum has. It is unlikely to change. pub const NUM_EVENT_TOPICS: u32 = 4; -/// Maximum size of events (including topics) and storage values. -pub const PAYLOAD_BYTES: u32 = 416; - /// Maximum size of of the transaction payload /// /// Maximum code size during instantiation taken into account plus some overhead. pub const MAX_TRANSACTION_PAYLOAD_SIZE: u32 = code::BLOB_BYTES + CALLDATA_BYTES; -/// The extra charge of deposit event per byte. +/// Maximum size of storage items. +pub const STORAGE_BYTES: u32 = 416; + +/// Maximum payload size of events. +pub const EVENT_BYTES: u32 = 64 * 1024; + +/// The extra ref time charge of deposit event per byte. /// /// This ensure the block builder has enough memory and pallet storage /// to operate under worst case scenarios. -pub const EXTRA_EVENT_CHARGE_PER_BYTE: u32 = 1024 * 256; +pub const EXTRA_EVENT_CHARGE_PER_BYTE: u64 = 256 * 1024; /// The maximum size for calldata and return data. /// diff --git a/substrate/frame/revive/src/precompiles/builtin/storage.rs b/substrate/frame/revive/src/precompiles/builtin/storage.rs index 69242cd483d63..de387df5d28ba 100644 --- a/substrate/frame/revive/src/precompiles/builtin/storage.rs +++ b/substrate/frame/revive/src/precompiles/builtin/storage.rs @@ -16,6 +16,7 @@ // limitations under the License. use crate::{ + limits, precompiles::{BuiltinAddressMatcher, BuiltinPrecompile, Error, Ext}, storage::WriteOutcome, vm::RuntimeCosts, @@ -51,7 +52,7 @@ impl BuiltinPrecompile for Storage { } use IStorage::IStorageCalls; - let max_size = env.max_value_size(); + let max_size = limits::STORAGE_BYTES; match input { IStorageCalls::clearStorage(IStorage::clearStorageCall { flags, key, isFixedKey }) => { let transient = is_transient(*flags) diff --git a/substrate/frame/revive/src/tests/pvm.rs b/substrate/frame/revive/src/tests/pvm.rs index 8ec14531fb75d..d32ee0033299a 100644 --- a/substrate/frame/revive/src/tests/pvm.rs +++ b/substrate/frame/revive/src/tests/pvm.rs @@ -436,17 +436,17 @@ fn deposit_event_max_value_limit() { .native_value(30_000) .build_and_unwrap_contract(); - // Call contract with allowed storage value. + // Call contract with allowed event size. assert_ok!(builder::call(addr) .gas_limit(Weight::from_parts(u64::MAX, u64::MAX)) - .data(limits::PAYLOAD_BYTES.encode()) + .data(limits::EVENT_BYTES.encode()) .build()); - // Call contract with too large a storage value. + // Call contract with too large a evene size assert_err_ignore_postinfo!( builder::call(addr) .gas_limit(Weight::from_parts(u64::MAX, u64::MAX)) - .data((limits::PAYLOAD_BYTES + 1).encode()) + .data((limits::EVENT_BYTES + 1).encode()) .build(), Error::::ValueTooLarge, ); @@ -607,12 +607,12 @@ fn storage_max_value_limit() { // Call contract with allowed storage value. assert_ok!(builder::call(addr) .gas_limit(GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2)) // we are copying a huge buffer - .data(limits::PAYLOAD_BYTES.encode()) + .data(limits::STORAGE_BYTES.encode()) .build()); // Call contract with too large a storage value. assert_err_ignore_postinfo!( - builder::call(addr).data((limits::PAYLOAD_BYTES + 1).encode()).build(), + builder::call(addr).data((limits::STORAGE_BYTES + 1).encode()).build(), Error::::ValueTooLarge, ); }); diff --git a/substrate/frame/revive/src/vm/evm/instructions/host.rs b/substrate/frame/revive/src/vm/evm/instructions/host.rs index b14dc9ff8f4c0..43111a7ebf3e7 100644 --- a/substrate/frame/revive/src/vm/evm/instructions/host.rs +++ b/substrate/frame/revive/src/vm/evm/instructions/host.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. use crate::{ + limits, storage::WriteOutcome, vec::Vec, vm::{ @@ -162,7 +163,7 @@ fn store_helper<'ext, E: Ext>( /// /// Stores a word to storage. pub fn sstore(interpreter: &mut Interpreter) -> ControlFlow { - let old_bytes = interpreter.ext.max_value_size(); + let old_bytes = limits::STORAGE_BYTES; store_helper( interpreter, RuntimeCosts::SetStorage { new_bytes: 32, old_bytes }, @@ -174,7 +175,7 @@ pub fn sstore(interpreter: &mut Interpreter) -> ControlFlow { /// EIP-1153: Transient storage opcodes /// Store value to transient storage pub fn tstore(interpreter: &mut Interpreter) -> ControlFlow { - let old_bytes = interpreter.ext.max_value_size(); + let old_bytes = limits::STORAGE_BYTES; store_helper( interpreter, RuntimeCosts::SetTransientStorage { new_bytes: 32, old_bytes }, @@ -222,7 +223,7 @@ pub fn log<'ext, const N: usize, E: Ext>( let [offset, len] = interpreter.stack.popn()?; let len = as_usize_or_halt::(len)?; - if len as u32 > interpreter.ext.max_value_size() { + if len as u32 > limits::EVENT_BYTES { return ControlFlow::Break(Error::::OutOfGas.into()); } diff --git a/substrate/frame/revive/src/vm/pvm.rs b/substrate/frame/revive/src/vm/pvm.rs index 089479bfda88d..aeeafb95cfecd 100644 --- a/substrate/frame/revive/src/vm/pvm.rs +++ b/substrate/frame/revive/src/vm/pvm.rs @@ -502,8 +502,8 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { StorageValue::Value(data) => data.len() as u32, }; - let max_size = self.ext.max_value_size(); - let charged = self.charge_gas(costs(value_len, self.ext.max_value_size()))?; + let max_size = limits::STORAGE_BYTES; + let charged = self.charge_gas(costs(value_len, max_size))?; if value_len > max_size { return Err(Error::::ValueTooLarge.into()); } @@ -540,7 +540,7 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { RuntimeCosts::ClearStorage(len) } }; - let charged = self.charge_gas(costs(self.ext.max_value_size()))?; + let charged = self.charge_gas(costs(limits::STORAGE_BYTES))?; let key = self.decode_key(memory, key_ptr, key_len)?; let outcome = if transient { self.ext.set_transient_storage(&key, None, false)? @@ -568,7 +568,7 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { RuntimeCosts::GetStorage(len) } }; - let charged = self.charge_gas(costs(self.ext.max_value_size()))?; + let charged = self.charge_gas(costs(limits::STORAGE_BYTES))?; let key = self.decode_key(memory, key_ptr, key_len)?; let outcome = if transient { self.ext.get_transient_storage(&key) diff --git a/substrate/frame/revive/src/vm/pvm/env.rs b/substrate/frame/revive/src/vm/pvm/env.rs index 420831eab822d..876f96f57d610 100644 --- a/substrate/frame/revive/src/vm/pvm/env.rs +++ b/substrate/frame/revive/src/vm/pvm/env.rs @@ -698,7 +698,7 @@ pub mod env { return Err(Error::::TooManyTopics.into()); } - if data_len > self.ext.max_value_size() { + if data_len > limits::EVENT_BYTES { return Err(Error::::ValueTooLarge.into()); } diff --git a/substrate/frame/revive/src/vm/runtime_costs.rs b/substrate/frame/revive/src/vm/runtime_costs.rs index 314dd531fbf4d..d0b2676cae4f6 100644 --- a/substrate/frame/revive/src/vm/runtime_costs.rs +++ b/substrate/frame/revive/src/vm/runtime_costs.rs @@ -262,8 +262,9 @@ impl Token for RuntimeCosts { Terminate { code_removed } => T::WeightInfo::seal_terminate(code_removed.into()), DepositEvent { num_topic, len } => T::WeightInfo::seal_deposit_event(num_topic, len) .saturating_add(T::WeightInfo::on_finalize_block_per_event(len)) - .saturating_add(Weight::from_all( + .saturating_add(Weight::from_parts( limits::EXTRA_EVENT_CHARGE_PER_BYTE.saturating_mul(len.into()).into(), + 0, )), SetStorage { new_bytes, old_bytes } => { cost_storage!(write, seal_set_storage, new_bytes, old_bytes)