1use super::*;
19
20use crate::{
21 address::AddressMapper,
22 exec::Ext,
23 limits,
24 primitives::ExecReturnValue,
25 vm::{calculate_code_deposit, BytecodeType, ExportedFunction, RuntimeCosts},
26 AccountIdOf, BalanceOf, CodeInfo, Config, ContractBlob, Error, Weight, SENTINEL,
27};
28use alloc::vec::Vec;
29use codec::Encode;
30use core::mem;
31use frame_support::traits::Get;
32use pallet_revive_proc_macro::define_env;
33use pallet_revive_uapi::{CallFlags, ReturnErrorCode, ReturnFlags};
34use sp_core::{H160, H256, U256};
35use sp_io::hashing::keccak_256;
36use sp_runtime::DispatchError;
37
38impl<T: Config> ContractBlob<T> {
39 pub fn prepare_call<E: Ext<T = T>>(
45 self,
46 mut runtime: Runtime<E, polkavm::RawInstance>,
47 entry_point: ExportedFunction,
48 aux_data_size: u32,
49 ) -> Result<PreparedCall<E>, ExecError> {
50 let mut config = polkavm::Config::default();
51 config.set_backend(Some(polkavm::BackendKind::Interpreter));
52 config.set_cache_enabled(false);
53 #[cfg(feature = "std")]
54 if std::env::var_os("REVIVE_USE_COMPILER").is_some() {
55 log::warn!(target: LOG_TARGET, "Using PolkaVM compiler backend because env var REVIVE_USE_COMPILER is set");
56 config.set_backend(Some(polkavm::BackendKind::Compiler));
57 }
58 let engine = polkavm::Engine::new(&config).expect(
59 "on-chain (no_std) use of interpreter is hard coded.
60 interpreter is available on all platforms; qed",
61 );
62
63 let mut module_config = polkavm::ModuleConfig::new();
64 module_config.set_page_size(limits::PAGE_SIZE);
65 module_config.set_gas_metering(Some(polkavm::GasMeteringKind::Sync));
66 module_config.set_allow_sbrk(false);
67 module_config.set_aux_data_size(aux_data_size);
68 let module =
69 polkavm::Module::new(&engine, &module_config, self.code.into()).map_err(|err| {
70 log::debug!(target: LOG_TARGET, "failed to create polkavm module: {err:?}");
71 Error::<T>::CodeRejected
72 })?;
73
74 let entry_program_counter = module
75 .exports()
76 .find(|export| export.symbol().as_bytes() == entry_point.identifier().as_bytes())
77 .ok_or_else(|| <Error<T>>::CodeRejected)?
78 .program_counter();
79
80 let gas_limit_polkavm: polkavm::Gas = runtime.ext().gas_meter_mut().engine_fuel_left()?;
81
82 let mut instance = module.instantiate().map_err(|err| {
83 log::debug!(target: LOG_TARGET, "failed to instantiate polkavm module: {err:?}");
84 Error::<T>::CodeRejected
85 })?;
86
87 instance.set_gas(gas_limit_polkavm);
88 instance
89 .set_interpreter_cache_size_limit(Some(polkavm::SetCacheSizeLimitArgs {
90 max_block_size: limits::code::BASIC_BLOCK_SIZE,
91 max_cache_size_bytes: limits::code::INTERPRETER_CACHE_BYTES
92 .try_into()
93 .map_err(|_| Error::<T>::CodeRejected)?,
94 }))
95 .map_err(|_| Error::<T>::CodeRejected)?;
96 instance.prepare_call_untyped(entry_program_counter, &[]);
97
98 Ok(PreparedCall { module, instance, runtime })
99 }
100}
101
102impl<T: Config> ContractBlob<T>
103where
104 BalanceOf<T>: Into<U256> + TryFrom<U256>,
105{
106 pub fn from_pvm_code(code: Vec<u8>, owner: AccountIdOf<T>) -> Result<Self, DispatchError> {
108 let available_syscalls = list_syscalls(T::UnsafeUnstableInterface::get());
111 let code = limits::code::enforce::<T>(code, available_syscalls)?;
112
113 let code_len = code.len() as u32;
114 let deposit = calculate_code_deposit::<T>(code_len);
115
116 let code_info = CodeInfo {
117 owner,
118 deposit,
119 refcount: 0,
120 code_len,
121 code_type: BytecodeType::Pvm,
122 behaviour_version: Default::default(),
123 };
124 let code_hash = H256(sp_io::hashing::keccak_256(&code));
125 Ok(ContractBlob { code, code_info, code_hash })
126 }
127}
128
129impl<'a, E: Ext, M: PolkaVmInstance<E::T>> Runtime<'a, E, M> {
130 pub fn handle_interrupt(
131 &mut self,
132 interrupt: Result<polkavm::InterruptKind, polkavm::Error>,
133 module: &polkavm::Module,
134 instance: &mut M,
135 ) -> Option<ExecResult> {
136 use polkavm::InterruptKind::*;
137
138 match interrupt {
139 Err(error) => {
140 log::error!(target: LOG_TARGET, "polkavm execution error: {error}");
142 Some(Err(Error::<E::T>::ExecutionFailed.into()))
143 },
144 Ok(Finished) =>
145 Some(Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })),
146 Ok(Trap) => Some(Err(Error::<E::T>::ContractTrapped.into())),
147 Ok(Segfault(_)) => Some(Err(Error::<E::T>::ExecutionFailed.into())),
148 Ok(NotEnoughGas) => Some(Err(Error::<E::T>::OutOfGas.into())),
149 Ok(Step) => None,
150 Ok(Ecalli(idx)) => {
151 if cfg!(feature = "runtime-benchmarks") && idx == SENTINEL {
156 return Some(Ok(ExecReturnValue {
157 flags: ReturnFlags::empty(),
158 data: Vec::new(),
159 }))
160 }
161 let Some(syscall_symbol) = module.imports().get(idx) else {
162 return Some(Err(<Error<E::T>>::InvalidSyscall.into()));
163 };
164 match self.handle_ecall(instance, syscall_symbol.as_bytes()) {
165 Ok(None) => None,
166 Ok(Some(return_value)) => {
167 instance.write_output(return_value);
168 None
169 },
170 Err(TrapReason::Return(ReturnData { flags, data })) =>
171 match ReturnFlags::from_bits(flags) {
172 None => Some(Err(Error::<E::T>::InvalidCallFlags.into())),
173 Some(flags) => Some(Ok(ExecReturnValue { flags, data })),
174 },
175 Err(TrapReason::Termination) => Some(Ok(Default::default())),
176 Err(TrapReason::SupervisorError(error)) => Some(Err(error.into())),
177 }
178 },
179 }
180 }
181}
182
183#[define_env]
191pub mod env {
192 #[cfg(feature = "runtime-benchmarks")]
197 #[stable]
198 fn noop(&mut self, memory: &mut M) -> Result<(), TrapReason> {
199 Ok(())
200 }
201
202 #[stable]
205 #[mutating]
206 fn set_storage(
207 &mut self,
208 memory: &mut M,
209 flags: u32,
210 key_ptr: u32,
211 key_len: u32,
212 value_ptr: u32,
213 value_len: u32,
214 ) -> Result<u32, TrapReason> {
215 self.set_storage(
216 memory,
217 flags,
218 key_ptr,
219 key_len,
220 StorageValue::Memory { ptr: value_ptr, len: value_len },
221 )
222 }
223
224 #[stable]
227 #[mutating]
228 fn set_storage_or_clear(
229 &mut self,
230 memory: &mut M,
231 flags: u32,
232 key_ptr: u32,
233 value_ptr: u32,
234 ) -> Result<u32, TrapReason> {
235 let value = memory.read(value_ptr, 32)?;
236
237 if value.iter().all(|&b| b == 0) {
238 self.clear_storage(memory, flags, key_ptr, SENTINEL)
239 } else {
240 self.set_storage(memory, flags, key_ptr, SENTINEL, StorageValue::Value(value))
241 }
242 }
243
244 #[stable]
247 fn get_storage(
248 &mut self,
249 memory: &mut M,
250 flags: u32,
251 key_ptr: u32,
252 key_len: u32,
253 out_ptr: u32,
254 out_len_ptr: u32,
255 ) -> Result<ReturnErrorCode, TrapReason> {
256 self.get_storage(
257 memory,
258 flags,
259 key_ptr,
260 key_len,
261 out_ptr,
262 StorageReadMode::VariableOutput { output_len_ptr: out_len_ptr },
263 )
264 }
265
266 #[stable]
269 fn get_storage_or_zero(
270 &mut self,
271 memory: &mut M,
272 flags: u32,
273 key_ptr: u32,
274 out_ptr: u32,
275 ) -> Result<(), TrapReason> {
276 let _ = self.get_storage(
277 memory,
278 flags,
279 key_ptr,
280 SENTINEL,
281 out_ptr,
282 StorageReadMode::FixedOutput32,
283 )?;
284
285 Ok(())
286 }
287
288 #[stable]
291 fn call(
292 &mut self,
293 memory: &mut M,
294 flags_and_callee: u64,
295 ref_time_limit: u64,
296 proof_size_limit: u64,
297 deposit_and_value: u64,
298 input_data: u64,
299 output_data: u64,
300 ) -> Result<ReturnErrorCode, TrapReason> {
301 let (flags, callee_ptr) = extract_hi_lo(flags_and_callee);
302 let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value);
303 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
304 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
305
306 self.call(
307 memory,
308 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
309 CallType::Call { value_ptr },
310 callee_ptr,
311 deposit_ptr,
312 Weight::from_parts(ref_time_limit, proof_size_limit),
313 input_data_ptr,
314 input_data_len,
315 output_ptr,
316 output_len_ptr,
317 )
318 }
319
320 #[stable]
323 fn delegate_call(
324 &mut self,
325 memory: &mut M,
326 flags_and_callee: u64,
327 ref_time_limit: u64,
328 proof_size_limit: u64,
329 deposit_ptr: u32,
330 input_data: u64,
331 output_data: u64,
332 ) -> Result<ReturnErrorCode, TrapReason> {
333 let (flags, address_ptr) = extract_hi_lo(flags_and_callee);
334 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
335 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
336
337 self.call(
338 memory,
339 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
340 CallType::DelegateCall,
341 address_ptr,
342 deposit_ptr,
343 Weight::from_parts(ref_time_limit, proof_size_limit),
344 input_data_ptr,
345 input_data_len,
346 output_ptr,
347 output_len_ptr,
348 )
349 }
350
351 #[stable]
354 #[mutating]
355 fn instantiate(
356 &mut self,
357 memory: &mut M,
358 ref_time_limit: u64,
359 proof_size_limit: u64,
360 deposit_and_value: u64,
361 input_data: u64,
362 output_data: u64,
363 address_and_salt: u64,
364 ) -> Result<ReturnErrorCode, TrapReason> {
365 let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value);
366 let (input_data_len, code_hash_ptr) = extract_hi_lo(input_data);
367 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
368 let (address_ptr, salt_ptr) = extract_hi_lo(address_and_salt);
369 let Some(input_data_ptr) = code_hash_ptr.checked_add(32) else {
370 return Err(Error::<E::T>::OutOfBounds.into());
371 };
372 let Some(input_data_len) = input_data_len.checked_sub(32) else {
373 return Err(Error::<E::T>::OutOfBounds.into());
374 };
375
376 self.instantiate(
377 memory,
378 code_hash_ptr,
379 Weight::from_parts(ref_time_limit, proof_size_limit),
380 deposit_ptr,
381 value_ptr,
382 input_data_ptr,
383 input_data_len,
384 address_ptr,
385 output_ptr,
386 output_len_ptr,
387 salt_ptr,
388 )
389 }
390
391 #[stable]
394 fn call_data_size(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
395 self.charge_gas(RuntimeCosts::CallDataSize)?;
396 Ok(self
397 .input_data
398 .as_ref()
399 .map(|input| input.len().try_into().expect("usize fits into u64; qed"))
400 .unwrap_or_default())
401 }
402
403 #[stable]
406 fn call_data_copy(
407 &mut self,
408 memory: &mut M,
409 out_ptr: u32,
410 out_len: u32,
411 offset: u32,
412 ) -> Result<(), TrapReason> {
413 self.charge_gas(RuntimeCosts::CallDataCopy(out_len))?;
414
415 let Some(input) = self.input_data.as_ref() else {
416 return Err(Error::<E::T>::InputForwarded.into());
417 };
418
419 let start = offset as usize;
420 if start >= input.len() {
421 memory.zero(out_ptr, out_len)?;
422 return Ok(());
423 }
424
425 let end = start.saturating_add(out_len as usize).min(input.len());
426 memory.write(out_ptr, &input[start..end])?;
427
428 let bytes_written = (end - start) as u32;
429 memory.zero(out_ptr.saturating_add(bytes_written), out_len - bytes_written)?;
430
431 Ok(())
432 }
433
434 #[stable]
437 fn call_data_load(
438 &mut self,
439 memory: &mut M,
440 out_ptr: u32,
441 offset: u32,
442 ) -> Result<(), TrapReason> {
443 self.charge_gas(RuntimeCosts::CallDataLoad)?;
444
445 let Some(input) = self.input_data.as_ref() else {
446 return Err(Error::<E::T>::InputForwarded.into());
447 };
448
449 let mut data = [0; 32];
450 let start = offset as usize;
451 let data = if start >= input.len() {
452 data } else {
454 let end = start.saturating_add(32).min(input.len());
455 data[..end - start].copy_from_slice(&input[start..end]);
456 data.reverse();
457 data };
459
460 self.write_fixed_sandbox_output(memory, out_ptr, &data, false, already_charged)?;
461
462 Ok(())
463 }
464
465 #[stable]
468 fn seal_return(
469 &mut self,
470 memory: &mut M,
471 flags: u32,
472 data_ptr: u32,
473 data_len: u32,
474 ) -> Result<(), TrapReason> {
475 self.charge_gas(RuntimeCosts::CopyFromContract(data_len))?;
476 if data_len > limits::CALLDATA_BYTES {
477 Err(<Error<E::T>>::ReturnDataTooLarge)?;
478 }
479 Err(TrapReason::Return(ReturnData { flags, data: memory.read(data_ptr, data_len)? }))
480 }
481
482 #[stable]
485 fn caller(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
486 self.charge_gas(RuntimeCosts::Caller)?;
487 let caller = <E::T as Config>::AddressMapper::to_address(self.ext.caller().account_id()?);
488 Ok(self.write_fixed_sandbox_output(
489 memory,
490 out_ptr,
491 caller.as_bytes(),
492 false,
493 already_charged,
494 )?)
495 }
496
497 #[stable]
500 fn origin(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
501 self.charge_gas(RuntimeCosts::Origin)?;
502 let origin = <E::T as Config>::AddressMapper::to_address(self.ext.origin().account_id()?);
503 Ok(self.write_fixed_sandbox_output(
504 memory,
505 out_ptr,
506 origin.as_bytes(),
507 false,
508 already_charged,
509 )?)
510 }
511
512 #[stable]
515 fn code_hash(&mut self, memory: &mut M, addr_ptr: u32, out_ptr: u32) -> Result<(), TrapReason> {
516 self.charge_gas(RuntimeCosts::CodeHash)?;
517 let address = memory.read_h160(addr_ptr)?;
518 Ok(self.write_fixed_sandbox_output(
519 memory,
520 out_ptr,
521 &self.ext.code_hash(&address).as_bytes(),
522 false,
523 already_charged,
524 )?)
525 }
526
527 #[stable]
530 fn code_size(&mut self, memory: &mut M, addr_ptr: u32) -> Result<u64, TrapReason> {
531 self.charge_gas(RuntimeCosts::CodeSize)?;
532 let address = memory.read_h160(addr_ptr)?;
533 Ok(self.ext.code_size(&address))
534 }
535
536 #[stable]
539 fn address(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
540 self.charge_gas(RuntimeCosts::Address)?;
541 let address = self.ext.address();
542 Ok(self.write_fixed_sandbox_output(
543 memory,
544 out_ptr,
545 address.as_bytes(),
546 false,
547 already_charged,
548 )?)
549 }
550
551 #[stable]
554 fn weight_to_fee(
555 &mut self,
556 memory: &mut M,
557 ref_time_limit: u64,
558 proof_size_limit: u64,
559 out_ptr: u32,
560 ) -> Result<(), TrapReason> {
561 let weight = Weight::from_parts(ref_time_limit, proof_size_limit);
562 self.charge_gas(RuntimeCosts::WeightToFee)?;
563 Ok(self.write_fixed_sandbox_output(
564 memory,
565 out_ptr,
566 &self.ext.get_weight_price(weight).encode(),
567 false,
568 already_charged,
569 )?)
570 }
571
572 #[stable]
575 fn get_immutable_data(
576 &mut self,
577 memory: &mut M,
578 out_ptr: u32,
579 out_len_ptr: u32,
580 ) -> Result<(), TrapReason> {
581 let len = self.ext.immutable_data_len();
583 self.charge_gas(RuntimeCosts::GetImmutableData(len))?;
584 let data = self.ext.get_immutable_data()?;
585 self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged)?;
586 Ok(())
587 }
588
589 #[stable]
592 fn set_immutable_data(&mut self, memory: &mut M, ptr: u32, len: u32) -> Result<(), TrapReason> {
593 if len > limits::IMMUTABLE_BYTES {
594 return Err(Error::<E::T>::OutOfBounds.into());
595 }
596 self.charge_gas(RuntimeCosts::SetImmutableData(len))?;
597 let buf = memory.read(ptr, len)?;
598 let data = buf.try_into().expect("bailed out earlier; qed");
599 self.ext.set_immutable_data(data)?;
600 Ok(())
601 }
602
603 #[stable]
606 fn balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
607 self.charge_gas(RuntimeCosts::Balance)?;
608 Ok(self.write_fixed_sandbox_output(
609 memory,
610 out_ptr,
611 &self.ext.balance().to_little_endian(),
612 false,
613 already_charged,
614 )?)
615 }
616
617 #[stable]
620 fn balance_of(
621 &mut self,
622 memory: &mut M,
623 addr_ptr: u32,
624 out_ptr: u32,
625 ) -> Result<(), TrapReason> {
626 self.charge_gas(RuntimeCosts::BalanceOf)?;
627 let address = memory.read_h160(addr_ptr)?;
628 Ok(self.write_fixed_sandbox_output(
629 memory,
630 out_ptr,
631 &self.ext.balance_of(&address).to_little_endian(),
632 false,
633 already_charged,
634 )?)
635 }
636
637 #[stable]
640 fn chain_id(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
641 Ok(self.write_fixed_sandbox_output(
642 memory,
643 out_ptr,
644 &U256::from(<E::T as Config>::ChainId::get()).to_little_endian(),
645 false,
646 |_| Some(RuntimeCosts::CopyToContract(32)),
647 )?)
648 }
649
650 #[stable]
653 fn gas_limit(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
654 self.charge_gas(RuntimeCosts::GasLimit)?;
655 Ok(<E::T as frame_system::Config>::BlockWeights::get().max_block.ref_time())
656 }
657
658 #[stable]
661 fn value_transferred(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
662 self.charge_gas(RuntimeCosts::ValueTransferred)?;
663 Ok(self.write_fixed_sandbox_output(
664 memory,
665 out_ptr,
666 &self.ext.value_transferred().to_little_endian(),
667 false,
668 already_charged,
669 )?)
670 }
671
672 #[stable]
675 fn gas_price(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
676 self.charge_gas(RuntimeCosts::GasPrice)?;
677 Ok(GAS_PRICE.into())
678 }
679
680 #[stable]
683 fn base_fee(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
684 self.charge_gas(RuntimeCosts::BaseFee)?;
685 Ok(self.write_fixed_sandbox_output(
686 memory,
687 out_ptr,
688 &U256::zero().to_little_endian(),
689 false,
690 already_charged,
691 )?)
692 }
693
694 #[stable]
697 fn now(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
698 self.charge_gas(RuntimeCosts::Now)?;
699 Ok(self.write_fixed_sandbox_output(
700 memory,
701 out_ptr,
702 &self.ext.now().to_little_endian(),
703 false,
704 already_charged,
705 )?)
706 }
707
708 #[stable]
711 #[mutating]
712 fn deposit_event(
713 &mut self,
714 memory: &mut M,
715 topics_ptr: u32,
716 num_topic: u32,
717 data_ptr: u32,
718 data_len: u32,
719 ) -> Result<(), TrapReason> {
720 self.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len })?;
721
722 if num_topic > limits::NUM_EVENT_TOPICS {
723 return Err(Error::<E::T>::TooManyTopics.into());
724 }
725
726 if data_len > self.ext.max_value_size() {
727 return Err(Error::<E::T>::ValueTooLarge.into());
728 }
729
730 let topics: Vec<H256> = match num_topic {
731 0 => Vec::new(),
732 _ => {
733 let mut v = Vec::with_capacity(num_topic as usize);
734 let topics_len = num_topic * H256::len_bytes() as u32;
735 let buf = memory.read(topics_ptr, topics_len)?;
736 for chunk in buf.chunks_exact(H256::len_bytes()) {
737 v.push(H256::from_slice(chunk));
738 }
739 v
740 },
741 };
742
743 let event_data = memory.read(data_ptr, data_len)?;
744 self.ext.deposit_event(topics, event_data);
745 Ok(())
746 }
747
748 #[stable]
751 fn block_number(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
752 self.charge_gas(RuntimeCosts::BlockNumber)?;
753 Ok(self.write_fixed_sandbox_output(
754 memory,
755 out_ptr,
756 &self.ext.block_number().to_little_endian(),
757 false,
758 already_charged,
759 )?)
760 }
761
762 #[stable]
765 fn block_hash(
766 &mut self,
767 memory: &mut M,
768 block_number_ptr: u32,
769 out_ptr: u32,
770 ) -> Result<(), TrapReason> {
771 self.charge_gas(RuntimeCosts::BlockHash)?;
772 let block_number = memory.read_u256(block_number_ptr)?;
773 let block_hash = self.ext.block_hash(block_number).unwrap_or(H256::zero());
774 Ok(self.write_fixed_sandbox_output(
775 memory,
776 out_ptr,
777 &block_hash.as_bytes(),
778 false,
779 already_charged,
780 )?)
781 }
782
783 #[stable]
786 fn block_author(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
787 self.charge_gas(RuntimeCosts::BlockAuthor)?;
788 let block_author = self.ext.block_author().unwrap_or(H160::zero());
789
790 Ok(self.write_fixed_sandbox_output(
791 memory,
792 out_ptr,
793 &block_author.as_bytes(),
794 false,
795 already_charged,
796 )?)
797 }
798
799 #[stable]
802 fn hash_keccak_256(
803 &mut self,
804 memory: &mut M,
805 input_ptr: u32,
806 input_len: u32,
807 output_ptr: u32,
808 ) -> Result<(), TrapReason> {
809 self.charge_gas(RuntimeCosts::HashKeccak256(input_len))?;
810 Ok(self.compute_hash_on_intermediate_buffer(
811 memory, keccak_256, input_ptr, input_len, output_ptr,
812 )?)
813 }
814
815 #[stable]
818 fn return_data_size(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
819 self.charge_gas(RuntimeCosts::ReturnDataSize)?;
820 Ok(self
821 .ext
822 .last_frame_output()
823 .data
824 .len()
825 .try_into()
826 .expect("usize fits into u64; qed"))
827 }
828
829 #[stable]
832 fn return_data_copy(
833 &mut self,
834 memory: &mut M,
835 out_ptr: u32,
836 out_len_ptr: u32,
837 offset: u32,
838 ) -> Result<(), TrapReason> {
839 let output = mem::take(self.ext.last_frame_output_mut());
840 let result = if offset as usize > output.data.len() {
841 Err(Error::<E::T>::OutOfBounds.into())
842 } else {
843 self.write_sandbox_output(
844 memory,
845 out_ptr,
846 out_len_ptr,
847 &output.data[offset as usize..],
848 false,
849 |len| Some(RuntimeCosts::CopyToContract(len)),
850 )
851 };
852 *self.ext.last_frame_output_mut() = output;
853 Ok(result?)
854 }
855
856 #[stable]
859 fn ref_time_left(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
860 self.charge_gas(RuntimeCosts::RefTimeLeft)?;
861 Ok(self.ext.gas_meter().gas_left().ref_time())
862 }
863
864 #[mutating]
867 fn clear_storage(
868 &mut self,
869 memory: &mut M,
870 flags: u32,
871 key_ptr: u32,
872 key_len: u32,
873 ) -> Result<u32, TrapReason> {
874 self.clear_storage(memory, flags, key_ptr, key_len)
875 }
876
877 fn contains_storage(
880 &mut self,
881 memory: &mut M,
882 flags: u32,
883 key_ptr: u32,
884 key_len: u32,
885 ) -> Result<u32, TrapReason> {
886 self.contains_storage(memory, flags, key_ptr, key_len)
887 }
888
889 fn ecdsa_to_eth_address(
892 &mut self,
893 memory: &mut M,
894 key_ptr: u32,
895 out_ptr: u32,
896 ) -> Result<ReturnErrorCode, TrapReason> {
897 self.charge_gas(RuntimeCosts::EcdsaToEthAddress)?;
898 let mut compressed_key: [u8; 33] = [0; 33];
899 memory.read_into_buf(key_ptr, &mut compressed_key)?;
900 let result = self.ext.ecdsa_to_eth_address(&compressed_key);
901 match result {
902 Ok(eth_address) => {
903 memory.write(out_ptr, eth_address.as_ref())?;
904 Ok(ReturnErrorCode::Success)
905 },
906 Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed),
907 }
908 }
909
910 #[mutating]
916 fn set_code_hash(&mut self, memory: &mut M, code_hash_ptr: u32) -> Result<(), TrapReason> {
917 let charged = self.charge_gas(RuntimeCosts::SetCodeHash { old_code_removed: true })?;
918 let code_hash: H256 = memory.read_h256(code_hash_ptr)?;
919 if matches!(self.ext.set_code_hash(code_hash)?, crate::CodeRemoved::No) {
920 self.adjust_gas(charged, RuntimeCosts::SetCodeHash { old_code_removed: false });
921 }
922 Ok(())
923 }
924
925 fn sr25519_verify(
928 &mut self,
929 memory: &mut M,
930 signature_ptr: u32,
931 pub_key_ptr: u32,
932 message_len: u32,
933 message_ptr: u32,
934 ) -> Result<ReturnErrorCode, TrapReason> {
935 self.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?;
936
937 let mut signature: [u8; 64] = [0; 64];
938 memory.read_into_buf(signature_ptr, &mut signature)?;
939
940 let mut pub_key: [u8; 32] = [0; 32];
941 memory.read_into_buf(pub_key_ptr, &mut pub_key)?;
942
943 let message: Vec<u8> = memory.read(message_ptr, message_len)?;
944
945 if self.ext.sr25519_verify(&signature, &message, &pub_key) {
946 Ok(ReturnErrorCode::Success)
947 } else {
948 Ok(ReturnErrorCode::Sr25519VerifyFailed)
949 }
950 }
951
952 #[mutating]
955 fn take_storage(
956 &mut self,
957 memory: &mut M,
958 flags: u32,
959 key_ptr: u32,
960 key_len: u32,
961 out_ptr: u32,
962 out_len_ptr: u32,
963 ) -> Result<ReturnErrorCode, TrapReason> {
964 self.take_storage(memory, flags, key_ptr, key_len, out_ptr, out_len_ptr)
965 }
966
967 #[mutating]
970 fn terminate(&mut self, memory: &mut M, beneficiary_ptr: u32) -> Result<(), TrapReason> {
971 let charged = self.charge_gas(RuntimeCosts::Terminate { code_removed: true })?;
972 let beneficiary = memory.read_h160(beneficiary_ptr)?;
973 if matches!(self.ext.terminate(&beneficiary)?, crate::CodeRemoved::No) {
974 self.adjust_gas(charged, RuntimeCosts::Terminate { code_removed: false });
975 }
976 Err(TrapReason::Termination)
977 }
978}