diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index f0200fbd15fd4..a3c2c914cb87c 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -378,6 +378,14 @@ decl_error! { /// on the call stack. Those actions are contract self destruction and restoration /// of a tombstone. ReentranceDenied, + /// `seal_input` was called twice from the same contract execution context. + InputAlreadyRead, + /// The subject passed to `seal_random` exceeds the limit. + RandomSubjectTooLong, + /// The amount of topics passed to `seal_deposit_events` exceeds the limit. + TooManyTopics, + /// The topics passed to `seal_deposit_events` contains at least one duplicate. + DuplicateTopics, } } diff --git a/frame/contracts/src/wasm/env_def/macros.rs b/frame/contracts/src/wasm/env_def/macros.rs index cc61deb074b75..e49014ed950da 100644 --- a/frame/contracts/src/wasm/env_def/macros.rs +++ b/frame/contracts/src/wasm/env_def/macros.rs @@ -96,7 +96,7 @@ macro_rules! unmarshall_then_body { #[inline(always)] pub fn constrain_closure(f: F) -> F where - F: FnOnce() -> Result, + F: FnOnce() -> Result, { f } @@ -109,14 +109,20 @@ macro_rules! unmarshall_then_body_then_marshall { >(|| { unmarshall_then_body!($body, $ctx, $args_iter, $( $names : $params ),*) }); - let r = body()?; + let r = body().map_err(|reason| { + $ctx.set_trap_reason(reason); + sp_sandbox::HostError + })?; return Ok(sp_sandbox::ReturnValue::Value({ use $crate::wasm::env_def::ConvertibleToWasm; r.to_typed_value() })) }); ( $args_iter:ident, $ctx:ident, ( $( $names:ident : $params:ty ),* ) => $body:tt ) => ({ let body = $crate::wasm::env_def::macros::constrain_closure::<(), _>(|| { unmarshall_then_body!($body, $ctx, $args_iter, $( $names : $params ),*) }); - body()?; + body().map_err(|reason| { + $ctx.set_trap_reason(reason); + sp_sandbox::HostError + })?; return Ok(sp_sandbox::ReturnValue::Unit) }) } @@ -207,15 +213,24 @@ mod tests { use parity_wasm::elements::ValueType; use sp_runtime::traits::Zero; use sp_sandbox::{ReturnValue, Value}; - use crate::wasm::tests::MockExt; - use crate::wasm::Runtime; - use crate::exec::Ext; - use crate::gas::Gas; + use crate::{ + wasm::{Runtime, runtime::TrapReason, tests::MockExt}, + exec::Ext, + gas::Gas, + }; + + struct TestRuntime { + value: u32, + } + + impl TestRuntime { + fn set_trap_reason(&mut self, _reason: TrapReason) {} + } #[test] fn macro_unmarshall_then_body_then_marshall_value_or_trap() { fn test_value( - _ctx: &mut u32, + _ctx: &mut TestRuntime, args: &[sp_sandbox::Value], ) -> Result { let mut args = args.iter(); @@ -224,7 +239,7 @@ mod tests { _ctx, (a: u32, b: u32) -> u32 => { if b == 0 { - Err(sp_sandbox::HostError) + Err(crate::wasm::runtime::TrapReason::Termination) } else { Ok(a / b) } @@ -232,7 +247,7 @@ mod tests { ) } - let ctx = &mut 0; + let ctx = &mut TestRuntime { value: 0 }; assert_eq!( test_value(ctx, &[Value::I32(15), Value::I32(3)]).unwrap(), ReturnValue::Value(Value::I32(5)), @@ -243,7 +258,7 @@ mod tests { #[test] fn macro_unmarshall_then_body_then_marshall_unit() { fn test_unit( - ctx: &mut u32, + ctx: &mut TestRuntime, args: &[sp_sandbox::Value], ) -> Result { let mut args = args.iter(); @@ -251,16 +266,16 @@ mod tests { args, ctx, (a: u32, b: u32) => { - *ctx = a + b; + ctx.value = a + b; Ok(()) } ) } - let ctx = &mut 0; + let ctx = &mut TestRuntime { value: 0 }; let result = test_unit(ctx, &[Value::I32(2), Value::I32(3)]).unwrap(); assert_eq!(result, ReturnValue::Unit); - assert_eq!(*ctx, 5); + assert_eq!(ctx.value, 5); } #[test] @@ -270,7 +285,7 @@ mod tests { if !amount.is_zero() { Ok(()) } else { - Err(sp_sandbox::HostError) + Err(TrapReason::Termination) } }); let _f: fn(&mut Runtime, &[sp_sandbox::Value]) @@ -322,7 +337,7 @@ mod tests { if !amount.is_zero() { Ok(()) } else { - Err(sp_sandbox::HostError) + Err(crate::wasm::runtime::TrapReason::Termination) } }, ); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 7d7668d5ec6d2..a10e087cde83f 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -1537,7 +1537,7 @@ mod tests { &mut gas_meter ), Err(ExecError { - error: Error::::ContractTrapped.into(), + error: Error::::TooManyTopics.into(), origin: ErrorOrigin::Caller, }) ); @@ -1582,7 +1582,7 @@ mod tests { &mut gas_meter ), Err(ExecError { - error: Error::::ContractTrapped.into(), + error: Error::::DuplicateTopics.into(), origin: ErrorOrigin::Caller, }) ); diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 56e21d2ee664c..070e68bc4758b 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -491,18 +491,24 @@ mod tests { } } - // Define test environment for tests. We need ImportSatisfyCheck - // implementation from it. So actual implementations doesn't matter. - define_env!(TestEnv, , - panic(_ctx) => { unreachable!(); }, + /// Using unreachable statements triggers unreachable warnings in the generated code + #[allow(unreachable_code)] + mod env { + use super::*; - // gas is an implementation defined function and a contract can't import it. - gas(_ctx, _amount: u32) => { unreachable!(); }, + // Define test environment for tests. We need ImportSatisfyCheck + // implementation from it. So actual implementations doesn't matter. + define_env!(Test, , + panic(_ctx) => { unreachable!(); }, - nop(_ctx, _unused: u64) => { unreachable!(); }, + // gas is an implementation defined function and a contract can't import it. + gas(_ctx, _amount: u32) => { unreachable!(); }, - seal_println(_ctx, _ptr: u32, _len: u32) => { unreachable!(); }, - ); + nop(_ctx, _unused: u64) => { unreachable!(); }, + + seal_println(_ctx, _ptr: u32, _len: u32) => { unreachable!(); }, + ); + } macro_rules! prepare_test { ($name:ident, $wat:expr, $($expected:tt)*) => { @@ -520,7 +526,7 @@ mod tests { }, .. Default::default() }; - let r = prepare_contract::(wasm.as_ref(), &schedule); + let r = prepare_contract::(wasm.as_ref(), &schedule); assert_matches!(r, $($expected)*); } }; @@ -931,7 +937,7 @@ mod tests { ).unwrap(); let mut schedule = Schedule::default(); schedule.enable_println = true; - let r = prepare_contract::(wasm.as_ref(), &schedule); + let r = prepare_contract::(wasm.as_ref(), &schedule); assert_matches!(r, Ok(_)); } } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index ac1cb1f54d56f..c4365e2cb0f57 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -90,7 +90,7 @@ impl From for ReturnCode { } /// The data passed through when a contract uses `seal_return`. -struct ReturnData { +pub struct ReturnData { /// The flags as passed through by the contract. They are still unchecked and /// will later be parsed into a `ReturnFlags` bitflags struct. flags: u32, @@ -104,7 +104,7 @@ struct ReturnData { /// occurred (the SupervisorError variant). /// The other case is where the trap does not constitute an error but rather was invoked /// as a quick way to terminate the application (all other variants). -enum TrapReason { +pub enum TrapReason { /// The supervisor trapped the contract because of an error condition occurred during /// execution in privileged code. SupervisorError(DispatchError), @@ -117,9 +117,15 @@ enum TrapReason { Restoration, } +impl> From for TrapReason { + fn from(from: T) -> Self { + Self::SupervisorError(from.into()) + } +} + #[cfg_attr(test, derive(Debug, PartialEq, Eq))] #[derive(Copy, Clone)] -pub enum RuntimeToken { +enum RuntimeToken { /// Charge the gas meter with the cost of a metering block. The charged costs are /// the supplied cost of the block plus the overhead of the metering itself. MeteringBlock(u32), @@ -369,21 +375,25 @@ where } } + /// Store the reason for a host function triggered trap. + /// + /// This is called by the `define_env` macro in order to store any error returned by + /// the host functions defined through the said macro. It should **not** be called + /// manually. + pub fn set_trap_reason(&mut self, reason: TrapReason) { + self.trap_reason = Some(reason); + } + /// Charge the gas meter with the specified token. /// /// Returns `Err(HostError)` if there is not enough gas. - fn charge_gas(&mut self, token: Tok) -> Result<(), sp_sandbox::HostError> + fn charge_gas(&mut self, token: Tok) -> Result<(), DispatchError> where Tok: Token>, { match self.gas_meter.charge(&self.schedule.host_fn_weights, token) { GasMeterResult::Proceed => Ok(()), - GasMeterResult::OutOfGas => { - self.trap_reason = Some( - TrapReason::SupervisorError(Error::::OutOfGas.into()) - ); - Err(sp_sandbox::HostError) - }, + GasMeterResult::OutOfGas => Err(Error::::OutOfGas.into()) } } @@ -392,12 +402,12 @@ where /// Returns `Err` if one of the following conditions occurs: /// /// - requested buffer is not within the bounds of the sandbox memory. - fn read_sandbox_memory(&mut self, ptr: u32, len: u32) - -> Result, sp_sandbox::HostError> + fn read_sandbox_memory(&self, ptr: u32, len: u32) + -> Result, DispatchError> { let mut buf = vec![0u8; len as usize]; self.memory.get(ptr, buf.as_mut_slice()) - .map_err(|_| self.store_err(Error::::OutOfBounds))?; + .map_err(|_| Error::::OutOfBounds)?; Ok(buf) } @@ -406,10 +416,10 @@ where /// Returns `Err` if one of the following conditions occurs: /// /// - requested buffer is not within the bounds of the sandbox memory. - fn read_sandbox_memory_into_buf(&mut self, ptr: u32, buf: &mut [u8]) - -> Result<(), sp_sandbox::HostError> + fn read_sandbox_memory_into_buf(&self, ptr: u32, buf: &mut [u8]) + -> Result<(), DispatchError> { - self.memory.get(ptr, buf).map_err(|_| self.store_err(Error::::OutOfBounds)) + self.memory.get(ptr, buf).map_err(|_| Error::::OutOfBounds.into()) } /// Read designated chunk from the sandbox memory and attempt to decode into the specified type. @@ -418,11 +428,11 @@ where /// /// - requested buffer is not within the bounds of the sandbox memory. /// - the buffer contents cannot be decoded as the required type. - fn read_sandbox_memory_as(&mut self, ptr: u32, len: u32) - -> Result + fn read_sandbox_memory_as(&self, ptr: u32, len: u32) + -> Result { let buf = self.read_sandbox_memory(ptr, len)?; - D::decode(&mut &buf[..]).map_err(|_| self.store_err(Error::::DecodingFailed)) + D::decode(&mut &buf[..]).map_err(|_| Error::::DecodingFailed.into()) } /// Write the given buffer to the designated location in the sandbox memory. @@ -430,8 +440,8 @@ where /// Returns `Err` if one of the following conditions occurs: /// /// - designated area is not within the bounds of the sandbox memory. - fn write_sandbox_memory(&mut self, ptr: u32, buf: &[u8]) -> Result<(), sp_sandbox::HostError> { - self.memory.set(ptr, buf).map_err(|_| self.store_err(Error::::OutOfBounds)) + fn write_sandbox_memory(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError> { + self.memory.set(ptr, buf).map_err(|_| Error::::OutOfBounds.into()) } /// Write the given buffer and its length to the designated locations in sandbox memory and @@ -460,7 +470,7 @@ where buf: &[u8], allow_skip: bool, create_token: impl FnOnce(u32) -> Option, - ) -> Result<(), sp_sandbox::HostError> + ) -> Result<(), DispatchError> { if allow_skip && out_ptr == u32::max_value() { return Ok(()); @@ -470,7 +480,7 @@ where let len: u32 = self.read_sandbox_memory_as(out_len_ptr, 4)?; if len < buf_len { - Err(self.store_err(Error::::OutputBufferTooSmall))? + Err(Error::::OutputBufferTooSmall)? } if let Some(token) = create_token(buf_len) { @@ -480,7 +490,7 @@ where self.memory.set(out_ptr, buf).and_then(|_| { self.memory.set(out_len_ptr, &buf_len.encode()) }) - .map_err(|_| self.store_err(Error::::OutOfBounds))?; + .map_err(|_| Error::::OutOfBounds)?; Ok(()) } @@ -503,7 +513,7 @@ where input_ptr: u32, input_len: u32, output_ptr: u32, - ) -> Result<(), sp_sandbox::HostError> + ) -> Result<(), DispatchError> where F: FnOnce(&[u8]) -> R, R: AsRef<[u8]>, @@ -517,48 +527,6 @@ where Ok(()) } - /// Stores a DispatchError returned from an Ext function into the trap_reason. - /// - /// This allows through supervisor generated errors to the caller. - fn store_err(&mut self, err: Error) -> sp_sandbox::HostError - where - Error: Into, - { - self.trap_reason = Some(TrapReason::SupervisorError(err.into())); - sp_sandbox::HostError - } - - /// Used by Runtime API that calls into other contracts. - /// - /// Those need to transform the the `ExecResult` returned from the execution into - /// a `ReturnCode`. If this conversion fails because the `ExecResult` constitutes a - /// a fatal error then this error is stored in the `ExecutionContext` so it can be - /// extracted for display in the UI. - fn map_exec_result(&mut self, result: ExecResult) -> Result { - match Self::exec_into_return_code(result) { - Ok(code) => Ok(code), - Err(err) => Err(self.store_err(err)), - } - } - - /// Try to convert an error into a `ReturnCode`. - /// - /// Used to decide between fatal and non-fatal errors. - fn map_dispatch_result(&mut self, result: Result) - -> Result - { - let err = if let Err(err) = result { - err - } else { - return Ok(ReturnCode::Success) - }; - - match Self::err_into_return_code(err) { - Ok(code) => Ok(code), - Err(err) => Err(self.store_err(err)), - } - } - /// Fallible conversion of `DispatchError` to `ReturnCode`. fn err_into_return_code(from: DispatchError) -> Result { use ReturnCode::*; @@ -638,7 +606,7 @@ define_env!(Env, , seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) => { ctx.charge_gas(RuntimeToken::SetStorage(value_len))?; if value_len > ctx.ext.max_value_size() { - Err(ctx.store_err(Error::::ValueTooLarge))?; + Err(Error::::ValueTooLarge)?; } let mut key: StorageKey = [0; 32]; ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; @@ -715,7 +683,13 @@ define_env!(Env, , ctx.read_sandbox_memory_as(value_ptr, value_len)?; let result = ctx.ext.transfer(&callee, value); - ctx.map_dispatch_result(result) + match result { + Ok(()) => Ok(ReturnCode::Success), + Err(err) => { + let code = Runtime::::err_into_return_code(err)?; + Ok(code) + } + } }, // Make a call to another contract. @@ -797,7 +771,7 @@ define_env!(Env, , Some(RuntimeToken::CallCopyOut(len)) })?; } - ctx.map_exec_result(call_outcome) + Ok(Runtime::::exec_into_return_code(call_outcome)?) }, // Instantiate a contract with the specified code hash. @@ -899,7 +873,7 @@ define_env!(Env, , Some(RuntimeToken::InstantiateCopyOut(len)) })?; } - ctx.map_exec_result(instantiate_outcome.map(|(_id, retval)| retval)) + Ok(Runtime::::exec_into_return_code(instantiate_outcome.map(|(_id, retval)| retval))?) }, // Remove the calling account and transfer remaining balance. @@ -925,10 +899,8 @@ define_env!(Env, , let beneficiary: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(beneficiary_ptr, beneficiary_len)?; - if let Ok(_) = ctx.ext.terminate(&beneficiary).map_err(|e| ctx.store_err(e)) { - ctx.trap_reason = Some(TrapReason::Termination); - } - Err(sp_sandbox::HostError) + ctx.ext.terminate(&beneficiary)?; + Err(TrapReason::Termination) }, seal_input(ctx, buf_ptr: u32, buf_len_ptr: u32) => { @@ -936,9 +908,10 @@ define_env!(Env, , if let Some(input) = ctx.input_data.take() { ctx.write_sandbox_output(buf_ptr, buf_len_ptr, &input, false, |len| { Some(RuntimeToken::InputCopyOut(len)) - }) + })?; + Ok(()) } else { - Err(sp_sandbox::HostError) + Err(Error::::InputAlreadyRead.into()) } }, @@ -961,15 +934,10 @@ define_env!(Env, , // Using a reserved bit triggers a trap. seal_return(ctx, flags: u32, data_ptr: u32, data_len: u32) => { ctx.charge_gas(RuntimeToken::Return(data_len))?; - ctx.trap_reason = Some(TrapReason::Return(ReturnData { + Err(TrapReason::Return(ReturnData { flags, data: ctx.read_sandbox_memory(data_ptr, data_len)?, - })); - - // The trap mechanism is used to immediately terminate the execution. - // This trap should be handled appropriately before returning the result - // to the user of this crate. - Err(sp_sandbox::HostError) + })) }, // Stores the address of the caller into the supplied buffer. @@ -984,9 +952,9 @@ define_env!(Env, , // address of the contract will be returned. The value is encoded as T::AccountId. seal_caller(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::Caller)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.caller().encode(), false, already_charged - ) + )?) }, // Stores the address of the current contract into the supplied buffer. @@ -997,9 +965,9 @@ define_env!(Env, , // space at `out_ptr` is less than the size of the value a trap is triggered. seal_address(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::Address)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.address().encode(), false, already_charged - ) + )?) }, // Stores the price for the specified amount of gas into the supplied buffer. @@ -1017,9 +985,9 @@ define_env!(Env, , // gas can be smaller than one. seal_weight_to_fee(ctx, gas: u64, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::WeightToFee)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.get_weight_price(gas).encode(), false, already_charged - ) + )?) }, // Stores the amount of gas left into the supplied buffer. @@ -1032,9 +1000,9 @@ define_env!(Env, , // The data is encoded as Gas. seal_gas_left(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::GasLeft)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.gas_meter.gas_left().encode(), false, already_charged - ) + )?) }, // Stores the balance of the current account into the supplied buffer. @@ -1047,9 +1015,9 @@ define_env!(Env, , // The data is encoded as T::Balance. seal_balance(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::Balance)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.balance().encode(), false, already_charged - ) + )?) }, // Stores the value transferred along with this call or as endowment into the supplied buffer. @@ -1062,9 +1030,9 @@ define_env!(Env, , // The data is encoded as T::Balance. seal_value_transferred(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::ValueTransferred)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.value_transferred().encode(), false, already_charged - ) + )?) }, // Stores a random number for the current block and the given subject into the supplied buffer. @@ -1078,12 +1046,12 @@ define_env!(Env, , seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::Random)?; if subject_len > ctx.schedule.limits.subject_len { - return Err(sp_sandbox::HostError); + Err(Error::::RandomSubjectTooLong)?; } let subject_buf = ctx.read_sandbox_memory(subject_ptr, subject_len)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.random(&subject_buf).encode(), false, already_charged - ) + )?) }, // Load the latest block timestamp into the supplied buffer @@ -1094,9 +1062,9 @@ define_env!(Env, , // space at `out_ptr` is less than the size of the value a trap is triggered. seal_now(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::Now)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.now().encode(), false, already_charged - ) + )?) }, // Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. @@ -1104,9 +1072,9 @@ define_env!(Env, , // The data is encoded as T::Balance. seal_minimum_balance(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::MinimumBalance)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.minimum_balance().encode(), false, already_charged - ) + )?) }, // Stores the tombstone deposit into the supplied buffer. @@ -1126,9 +1094,9 @@ define_env!(Env, , // is commonly referred as subsistence threshold in code. seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::TombstoneDeposit)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.tombstone_deposit().encode(), false, already_charged - ) + )?) }, // Try to restore the given destination contract sacrificing the caller. @@ -1189,21 +1157,14 @@ define_env!(Env, , delta.push(delta_key); // Offset key_ptr to the next element. - key_ptr = key_ptr.checked_add(KEY_SIZE as u32).ok_or_else(|| sp_sandbox::HostError)?; + key_ptr = key_ptr.checked_add(KEY_SIZE as u32).ok_or(Error::::OutOfBounds)?; } delta }; - if let Ok(()) = ctx.ext.restore_to( - dest, - code_hash, - rent_allowance, - delta, - ).map_err(|e| ctx.store_err(e)) { - ctx.trap_reason = Some(TrapReason::Restoration); - } - Err(sp_sandbox::HostError) + ctx.ext.restore_to(dest, code_hash, rent_allowance, delta)?; + Err(TrapReason::Restoration) }, // Deposit a contract event with the data buffer and optional list of topics. There is a limit @@ -1217,13 +1178,13 @@ define_env!(Env, , seal_deposit_event(ctx, topics_ptr: u32, topics_len: u32, data_ptr: u32, data_len: u32) => { let num_topic = topics_len .checked_div(sp_std::mem::size_of::>() as u32) - .ok_or_else(|| ctx.store_err("Zero sized topics are not allowed"))?; + .ok_or_else(|| "Zero sized topics are not allowed")?; ctx.charge_gas(RuntimeToken::DepositEvent { num_topic, len: data_len, })?; if data_len > ctx.ext.max_value_size() { - Err(ctx.store_err(Error::::ValueTooLarge))?; + Err(Error::::ValueTooLarge)?; } let mut topics: Vec::::T>> = match topics_len { @@ -1233,12 +1194,12 @@ define_env!(Env, , // If there are more than `event_topics`, then trap. if topics.len() > ctx.schedule.limits.event_topics as usize { - return Err(sp_sandbox::HostError); + Err(Error::::TooManyTopics)?; } // Check for duplicate topics. If there are any, then trap. if has_duplicates(&mut topics) { - return Err(sp_sandbox::HostError); + Err(Error::::DuplicateTopics)?; } let event_data = ctx.read_sandbox_memory(data_ptr, data_len)?; @@ -1272,9 +1233,9 @@ define_env!(Env, , // The data is encoded as T::Balance. seal_rent_allowance(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::RentAllowance)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.rent_allowance().encode(), false, already_charged - ) + )?) }, // Prints utf8 encoded string from the data buffer. @@ -1296,9 +1257,9 @@ define_env!(Env, , // space at `out_ptr` is less than the size of the value a trap is triggered. seal_block_number(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeToken::BlockNumber)?; - ctx.write_sandbox_output( + Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.block_number().encode(), false, already_charged - ) + )?) }, // Computes the SHA2 256-bit hash on the given input buffer. @@ -1323,7 +1284,7 @@ define_env!(Env, , // directly into this buffer. seal_hash_sha2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { ctx.charge_gas(RuntimeToken::HashSha256(input_len))?; - ctx.compute_hash_on_intermediate_buffer(sha2_256, input_ptr, input_len, output_ptr) + Ok(ctx.compute_hash_on_intermediate_buffer(sha2_256, input_ptr, input_len, output_ptr)?) }, // Computes the KECCAK 256-bit hash on the given input buffer. @@ -1348,7 +1309,7 @@ define_env!(Env, , // directly into this buffer. seal_hash_keccak_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { ctx.charge_gas(RuntimeToken::HashKeccak256(input_len))?; - ctx.compute_hash_on_intermediate_buffer(keccak_256, input_ptr, input_len, output_ptr) + Ok(ctx.compute_hash_on_intermediate_buffer(keccak_256, input_ptr, input_len, output_ptr)?) }, // Computes the BLAKE2 256-bit hash on the given input buffer. @@ -1373,7 +1334,7 @@ define_env!(Env, , // directly into this buffer. seal_hash_blake2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { ctx.charge_gas(RuntimeToken::HashBlake256(input_len))?; - ctx.compute_hash_on_intermediate_buffer(blake2_256, input_ptr, input_len, output_ptr) + Ok(ctx.compute_hash_on_intermediate_buffer(blake2_256, input_ptr, input_len, output_ptr)?) }, // Computes the BLAKE2 128-bit hash on the given input buffer. @@ -1398,6 +1359,6 @@ define_env!(Env, , // directly into this buffer. seal_hash_blake2_128(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { ctx.charge_gas(RuntimeToken::HashBlake128(input_len))?; - ctx.compute_hash_on_intermediate_buffer(blake2_128, input_ptr, input_len, output_ptr) + Ok(ctx.compute_hash_on_intermediate_buffer(blake2_128, input_ptr, input_len, output_ptr)?) }, );