1use super::*;
19
20use crate::{
21 AccountIdOf, CodeInfo, Config, ContractBlob, Error, SENTINEL, Weight,
22 address::AddressMapper,
23 debug::DebugSettings,
24 exec::Ext,
25 limits,
26 primitives::ExecReturnValue,
27 vm::{BytecodeType, ExportedFunction, RuntimeCosts, calculate_code_deposit},
28};
29use alloc::vec::Vec;
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::U256;
35use sp_io::hashing::keccak_256;
36use sp_runtime::{DispatchError, SaturatedConversion};
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 let pvm_logs_enabled = DebugSettings::is_pvm_logs_enabled::<T>();
56 config.set_imperfect_logger_filtering_workaround(!pvm_logs_enabled);
57 config.set_backend(Some(polkavm::BackendKind::Interpreter));
58 config.set_cache_enabled(false);
59 #[cfg(feature = "std")]
60 if std::env::var_os("REVIVE_USE_COMPILER").is_some() {
61 log::warn!(target: LOG_TARGET, "Using PolkaVM compiler backend because env var REVIVE_USE_COMPILER is set");
62 config.set_backend(Some(polkavm::BackendKind::Compiler));
63 }
64 let engine = polkavm::Engine::new(&config).expect(
65 "on-chain (no_std) use of interpreter is hard coded.
66 interpreter is available on all platforms; qed",
67 );
68
69 let mut module_config = polkavm::ModuleConfig::new();
70 module_config.set_page_size(limits::PAGE_SIZE);
71 module_config.set_gas_metering(Some(polkavm::GasMeteringKind::Sync));
72 module_config.set_aux_data_size(aux_data_size);
73 let module =
74 polkavm::Module::new(&engine, &module_config, self.code.into()).map_err(|err| {
75 log::debug!(target: LOG_TARGET, "failed to create polkavm module: {err:?}");
76 Error::<T>::CodeRejected
77 })?;
78
79 let entry_program_counter = module
80 .exports()
81 .find(|export| export.symbol().as_bytes() == entry_point.identifier().as_bytes())
82 .ok_or_else(|| <Error<T>>::CodeRejected)?
83 .program_counter();
84
85 let gas_limit_polkavm: polkavm::Gas = runtime.ext().frame_meter_mut().sync_to_executor();
86
87 let mut instance = module.instantiate().map_err(|err| {
88 log::debug!(target: LOG_TARGET, "failed to instantiate polkavm module: {err:?}");
89 Error::<T>::CodeRejected
90 })?;
91
92 instance.set_gas(gas_limit_polkavm);
93 instance
94 .set_interpreter_cache_size_limit(Some(polkavm::SetCacheSizeLimitArgs {
95 max_block_size: limits::code::BASIC_BLOCK_SIZE,
96 max_cache_size_bytes: limits::code::INTERPRETER_CACHE_BYTES
97 .try_into()
98 .map_err(|_| Error::<T>::CodeRejected)?,
99 }))
100 .map_err(|_| Error::<T>::CodeRejected)?;
101 instance.prepare_call_untyped(entry_program_counter, &[]);
102
103 Ok(PreparedCall { module, instance, runtime })
104 }
105}
106
107impl<T: Config> ContractBlob<T> {
108 pub fn from_pvm_code(code: Vec<u8>, owner: AccountIdOf<T>) -> Result<Self, DispatchError> {
110 let available_syscalls = list_syscalls();
113 let code = limits::code::enforce::<T>(code, available_syscalls)?;
114
115 let code_len = code.len() as u32;
116 let deposit = calculate_code_deposit::<T>(code_len);
117
118 let code_info = CodeInfo {
119 owner,
120 deposit,
121 refcount: 0,
122 code_len,
123 code_type: BytecodeType::Pvm,
124 behaviour_version: Default::default(),
125 };
126 let code_hash = H256(sp_io::hashing::keccak_256(&code));
127 Ok(ContractBlob { code, code_info, code_hash })
128 }
129}
130
131impl<'a, E: Ext, M: PolkaVmInstance<E::T>> Runtime<'a, E, M> {
132 pub fn handle_interrupt(
133 &mut self,
134 interrupt: Result<polkavm::InterruptKind, polkavm::Error>,
135 module: &polkavm::Module,
136 instance: &mut M,
137 ) -> Option<ExecResult> {
138 use polkavm::InterruptKind::*;
139
140 match interrupt {
141 Err(error) => {
142 log::error!(target: LOG_TARGET, "polkavm execution error: {error}");
144 Some(Err(Error::<E::T>::ExecutionFailed.into()))
145 },
146 Ok(Finished) => {
147 Some(Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }))
148 },
149 Ok(Trap) => Some(Err(Error::<E::T>::ContractTrapped.into())),
150 Ok(Segfault(_)) => Some(Err(Error::<E::T>::ExecutionFailed.into())),
151 Ok(NotEnoughGas) => Some(Err(Error::<E::T>::OutOfGas.into())),
152 Ok(Step) => None,
153 Ok(Ecalli(idx)) => {
154 if cfg!(feature = "runtime-benchmarks") && idx == SENTINEL {
159 return Some(Ok(ExecReturnValue {
160 flags: ReturnFlags::empty(),
161 data: Vec::new(),
162 }));
163 }
164 let Some(syscall_symbol) = module.imports().get(idx) else {
165 return Some(Err(<Error<E::T>>::InvalidSyscall.into()));
166 };
167 match self.handle_ecall(instance, syscall_symbol.as_bytes()) {
168 Ok(None) => None,
169 Ok(Some(return_value)) => {
170 instance.write_output(return_value);
171 None
172 },
173 Err(TrapReason::Return(ReturnData { flags, data })) => {
174 match ReturnFlags::from_bits(flags) {
175 None => Some(Err(Error::<E::T>::InvalidCallFlags.into())),
176 Some(flags) => Some(Ok(ExecReturnValue { flags, data })),
177 }
178 },
179 Err(TrapReason::Termination) => Some(Ok(Default::default())),
180 Err(TrapReason::SupervisorError(error)) => Some(Err(error.into())),
181 }
182 },
183 }
184 }
185}
186
187#[define_env]
195pub mod env {
196 #[cfg(feature = "runtime-benchmarks")]
198 fn noop(&mut self, memory: &mut M) -> Result<(), TrapReason> {
199 Ok(())
200 }
201
202 #[mutating]
205 fn set_storage(
206 &mut self,
207 memory: &mut M,
208 flags: u32,
209 key_ptr: u32,
210 key_len: u32,
211 value_ptr: u32,
212 value_len: u32,
213 ) -> Result<u32, TrapReason> {
214 self.set_storage(
215 memory,
216 flags,
217 key_ptr,
218 key_len,
219 StorageValue::Memory { ptr: value_ptr, len: value_len },
220 )
221 }
222
223 #[mutating]
226 fn set_storage_or_clear(
227 &mut self,
228 memory: &mut M,
229 flags: u32,
230 key_ptr: u32,
231 value_ptr: u32,
232 ) -> Result<u32, TrapReason> {
233 let value = memory.read(value_ptr, 32)?;
234
235 if value.iter().all(|&b| b == 0) {
236 self.clear_storage(memory, flags, key_ptr, SENTINEL)
237 } else {
238 self.set_storage(memory, flags, key_ptr, SENTINEL, StorageValue::Value(value))
239 }
240 }
241
242 fn get_storage(
245 &mut self,
246 memory: &mut M,
247 flags: u32,
248 key_ptr: u32,
249 key_len: u32,
250 out_ptr: u32,
251 out_len_ptr: u32,
252 ) -> Result<ReturnErrorCode, TrapReason> {
253 self.get_storage(
254 memory,
255 flags,
256 key_ptr,
257 key_len,
258 out_ptr,
259 StorageReadMode::VariableOutput { output_len_ptr: out_len_ptr },
260 )
261 }
262
263 fn get_storage_or_zero(
266 &mut self,
267 memory: &mut M,
268 flags: u32,
269 key_ptr: u32,
270 out_ptr: u32,
271 ) -> Result<(), TrapReason> {
272 let _ = self.get_storage(
273 memory,
274 flags,
275 key_ptr,
276 SENTINEL,
277 out_ptr,
278 StorageReadMode::FixedOutput32,
279 )?;
280
281 Ok(())
282 }
283
284 fn call(
287 &mut self,
288 memory: &mut M,
289 flags_and_callee: u64,
290 ref_time_limit: u64,
291 proof_size_limit: u64,
292 deposit_and_value: u64,
293 input_data: u64,
294 output_data: u64,
295 ) -> Result<ReturnErrorCode, TrapReason> {
296 let (flags, callee_ptr) = extract_hi_lo(flags_and_callee);
297 let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value);
298 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
299 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
300 let weight = Weight::from_parts(ref_time_limit, proof_size_limit);
301
302 self.charge_gas(RuntimeCosts::CopyFromContract(32))?;
303 let deposit_limit = memory.read_u256(deposit_ptr)?;
304
305 self.call(
306 memory,
307 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
308 CallType::Call { value_ptr },
309 callee_ptr,
310 &CallResources::from_weight_and_deposit(weight, deposit_limit),
311 input_data_ptr,
312 input_data_len,
313 output_ptr,
314 output_len_ptr,
315 )
316 }
317
318 fn call_evm(
321 &mut self,
322 memory: &mut M,
323 flags: u32,
324 callee: u32,
325 value_ptr: u32,
326 gas: u64,
327 input_data: u64,
328 output_data: u64,
329 ) -> Result<ReturnErrorCode, TrapReason> {
330 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
331 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
332 let resources = if gas == u64::MAX {
333 CallResources::NoLimits
334 } else {
335 self.charge_gas(RuntimeCosts::CopyFromContract(32))?;
336 let value = memory.read_u256(value_ptr)?;
337 let add_stipend = !value.is_zero() || gas == revm::interpreter::gas::CALL_STIPEND;
339 CallResources::from_ethereum_gas(gas.into(), add_stipend)
340 };
341
342 self.call(
343 memory,
344 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
345 CallType::Call { value_ptr },
346 callee,
347 &resources,
348 input_data_ptr,
349 input_data_len,
350 output_ptr,
351 output_len_ptr,
352 )
353 }
354
355 fn delegate_call(
358 &mut self,
359 memory: &mut M,
360 flags_and_callee: u64,
361 ref_time_limit: u64,
362 proof_size_limit: u64,
363 deposit_ptr: u32,
364 input_data: u64,
365 output_data: u64,
366 ) -> Result<ReturnErrorCode, TrapReason> {
367 let (flags, address_ptr) = extract_hi_lo(flags_and_callee);
368 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
369 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
370 let weight = Weight::from_parts(ref_time_limit, proof_size_limit);
371
372 self.charge_gas(RuntimeCosts::CopyFromContract(32))?;
373 let deposit_limit = memory.read_u256(deposit_ptr)?;
374
375 self.call(
376 memory,
377 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
378 CallType::DelegateCall,
379 address_ptr,
380 &CallResources::from_weight_and_deposit(weight, deposit_limit),
381 input_data_ptr,
382 input_data_len,
383 output_ptr,
384 output_len_ptr,
385 )
386 }
387
388 fn delegate_call_evm(
391 &mut self,
392 memory: &mut M,
393 flags: u32,
394 callee: u32,
395 gas: u64,
396 input_data: u64,
397 output_data: u64,
398 ) -> Result<ReturnErrorCode, TrapReason> {
399 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
400 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
401 let resources = if gas == u64::MAX {
402 CallResources::NoLimits
403 } else {
404 CallResources::from_ethereum_gas(gas.into(), false)
405 };
406
407 self.call(
408 memory,
409 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
410 CallType::DelegateCall,
411 callee,
412 &resources,
413 input_data_ptr,
414 input_data_len,
415 output_ptr,
416 output_len_ptr,
417 )
418 }
419
420 #[mutating]
423 fn instantiate(
424 &mut self,
425 memory: &mut M,
426 ref_time_limit: u64,
427 proof_size_limit: u64,
428 deposit_and_value: u64,
429 input_data: u64,
430 output_data: u64,
431 address_and_salt: u64,
432 ) -> Result<ReturnErrorCode, TrapReason> {
433 let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value);
434 let (input_data_len, code_hash_ptr) = extract_hi_lo(input_data);
435 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
436 let (address_ptr, salt_ptr) = extract_hi_lo(address_and_salt);
437 let Some(input_data_ptr) = code_hash_ptr.checked_add(32) else {
438 return Err(Error::<E::T>::OutOfBounds.into());
439 };
440 let Some(input_data_len) = input_data_len.checked_sub(32) else {
441 return Err(Error::<E::T>::OutOfBounds.into());
442 };
443
444 self.instantiate(
445 memory,
446 code_hash_ptr,
447 Weight::from_parts(ref_time_limit, proof_size_limit),
448 deposit_ptr,
449 value_ptr,
450 input_data_ptr,
451 input_data_len,
452 address_ptr,
453 output_ptr,
454 output_len_ptr,
455 salt_ptr,
456 )
457 }
458
459 fn call_data_size(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
462 self.charge_gas(RuntimeCosts::CallDataSize)?;
463 Ok(self
464 .input_data
465 .as_ref()
466 .map(|input| input.len().try_into().expect("usize fits into u64; qed"))
467 .unwrap_or_default())
468 }
469
470 fn call_data_copy(
473 &mut self,
474 memory: &mut M,
475 out_ptr: u32,
476 out_len: u32,
477 offset: u32,
478 ) -> Result<(), TrapReason> {
479 self.charge_gas(RuntimeCosts::CallDataCopy(out_len))?;
480
481 let Some(input) = self.input_data.as_ref() else {
482 return Err(Error::<E::T>::InputForwarded.into());
483 };
484
485 let start = offset as usize;
486 if start >= input.len() {
487 memory.zero(out_ptr, out_len)?;
488 return Ok(());
489 }
490
491 let end = start.saturating_add(out_len as usize).min(input.len());
492 memory.write(out_ptr, &input[start..end])?;
493
494 let bytes_written = (end - start) as u32;
495 memory.zero(out_ptr.saturating_add(bytes_written), out_len - bytes_written)?;
496
497 Ok(())
498 }
499
500 fn call_data_load(
503 &mut self,
504 memory: &mut M,
505 out_ptr: u32,
506 offset: u32,
507 ) -> Result<(), TrapReason> {
508 self.charge_gas(RuntimeCosts::CallDataLoad)?;
509
510 let Some(input) = self.input_data.as_ref() else {
511 return Err(Error::<E::T>::InputForwarded.into());
512 };
513
514 let mut data = [0; 32];
515 let start = offset as usize;
516 let data = if start >= input.len() {
517 data } else {
519 let end = start.saturating_add(32).min(input.len());
520 data[..end - start].copy_from_slice(&input[start..end]);
521 data.reverse();
522 data };
524
525 self.write_fixed_sandbox_output(memory, out_ptr, &data, false, already_charged)?;
526
527 Ok(())
528 }
529
530 fn seal_return(
533 &mut self,
534 memory: &mut M,
535 flags: u32,
536 data_ptr: u32,
537 data_len: u32,
538 ) -> Result<(), TrapReason> {
539 self.charge_gas(RuntimeCosts::CopyFromContract(data_len))?;
540 if data_len > limits::CALLDATA_BYTES {
541 Err(<Error<E::T>>::ReturnDataTooLarge)?;
542 }
543 Err(TrapReason::Return(ReturnData { flags, data: memory.read(data_ptr, data_len)? }))
544 }
545
546 fn caller(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
549 self.charge_gas(RuntimeCosts::Caller)?;
550 let caller = <E::T as Config>::AddressMapper::to_address(self.ext.caller().account_id()?);
551 Ok(self.write_fixed_sandbox_output(
552 memory,
553 out_ptr,
554 caller.as_bytes(),
555 false,
556 already_charged,
557 )?)
558 }
559
560 fn origin(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
563 self.charge_gas(RuntimeCosts::Origin)?;
564 let origin = <E::T as Config>::AddressMapper::to_address(self.ext.origin().account_id()?);
565 Ok(self.write_fixed_sandbox_output(
566 memory,
567 out_ptr,
568 origin.as_bytes(),
569 false,
570 already_charged,
571 )?)
572 }
573
574 fn code_hash(&mut self, memory: &mut M, addr_ptr: u32, out_ptr: u32) -> Result<(), TrapReason> {
577 self.charge_gas(RuntimeCosts::CodeHash)?;
578 let address = memory.read_h160(addr_ptr)?;
579 Ok(self.write_fixed_sandbox_output(
580 memory,
581 out_ptr,
582 &self.ext.code_hash(&address).as_bytes(),
583 false,
584 already_charged,
585 )?)
586 }
587
588 fn code_size(&mut self, memory: &mut M, addr_ptr: u32) -> Result<u64, TrapReason> {
591 self.charge_gas(RuntimeCosts::CodeSize)?;
592 let address = memory.read_h160(addr_ptr)?;
593 Ok(self.ext.code_size(&address))
594 }
595
596 fn address(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
599 self.charge_gas(RuntimeCosts::Address)?;
600 let address = self.ext.address();
601 Ok(self.write_fixed_sandbox_output(
602 memory,
603 out_ptr,
604 address.as_bytes(),
605 false,
606 already_charged,
607 )?)
608 }
609
610 fn get_immutable_data(
613 &mut self,
614 memory: &mut M,
615 out_ptr: u32,
616 out_len_ptr: u32,
617 ) -> Result<(), TrapReason> {
618 let len = self.ext.immutable_data_len();
620 self.charge_gas(RuntimeCosts::GetImmutableData(len))?;
621 let data = self.ext.get_immutable_data()?;
622 self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged)?;
623 Ok(())
624 }
625
626 fn set_immutable_data(&mut self, memory: &mut M, ptr: u32, len: u32) -> Result<(), TrapReason> {
629 if len > limits::IMMUTABLE_BYTES {
630 return Err(Error::<E::T>::OutOfBounds.into());
631 }
632 self.charge_gas(RuntimeCosts::SetImmutableData(len))?;
633 let buf = memory.read(ptr, len)?;
634 let data = buf.try_into().expect("bailed out earlier; qed");
635 self.ext.set_immutable_data(data)?;
636 Ok(())
637 }
638
639 fn balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
642 self.charge_gas(RuntimeCosts::Balance)?;
643 Ok(self.write_fixed_sandbox_output(
644 memory,
645 out_ptr,
646 &self.ext.balance().to_little_endian(),
647 false,
648 already_charged,
649 )?)
650 }
651
652 fn balance_of(
655 &mut self,
656 memory: &mut M,
657 addr_ptr: u32,
658 out_ptr: u32,
659 ) -> Result<(), TrapReason> {
660 self.charge_gas(RuntimeCosts::BalanceOf)?;
661 let address = memory.read_h160(addr_ptr)?;
662 Ok(self.write_fixed_sandbox_output(
663 memory,
664 out_ptr,
665 &self.ext.balance_of(&address).to_little_endian(),
666 false,
667 already_charged,
668 )?)
669 }
670
671 fn chain_id(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
674 Ok(self.write_fixed_sandbox_output(
675 memory,
676 out_ptr,
677 &U256::from(<E::T as Config>::ChainId::get()).to_little_endian(),
678 false,
679 |_| Some(RuntimeCosts::CopyToContract(32)),
680 )?)
681 }
682
683 fn gas_limit(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
686 self.charge_gas(RuntimeCosts::GasLimit)?;
687 Ok(self.ext.gas_limit())
688 }
689
690 fn value_transferred(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
693 self.charge_gas(RuntimeCosts::ValueTransferred)?;
694 Ok(self.write_fixed_sandbox_output(
695 memory,
696 out_ptr,
697 &self.ext.value_transferred().to_little_endian(),
698 false,
699 already_charged,
700 )?)
701 }
702
703 fn gas_price(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
706 self.charge_gas(RuntimeCosts::GasPrice)?;
707 Ok(self.ext.effective_gas_price().saturated_into())
708 }
709
710 fn base_fee(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
713 self.charge_gas(RuntimeCosts::BaseFee)?;
714 Ok(self.write_fixed_sandbox_output(
715 memory,
716 out_ptr,
717 &Pallet::<E::T>::evm_base_fee().to_little_endian(),
718 false,
719 already_charged,
720 )?)
721 }
722
723 fn now(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
726 self.charge_gas(RuntimeCosts::Now)?;
727 Ok(self.write_fixed_sandbox_output(
728 memory,
729 out_ptr,
730 &self.ext.now().to_little_endian(),
731 false,
732 already_charged,
733 )?)
734 }
735
736 #[mutating]
739 fn deposit_event(
740 &mut self,
741 memory: &mut M,
742 topics_ptr: u32,
743 num_topic: u32,
744 data_ptr: u32,
745 data_len: u32,
746 ) -> Result<(), TrapReason> {
747 self.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len })?;
748
749 if num_topic > limits::NUM_EVENT_TOPICS {
750 return Err(Error::<E::T>::TooManyTopics.into());
751 }
752
753 if data_len > limits::EVENT_BYTES {
754 return Err(Error::<E::T>::ValueTooLarge.into());
755 }
756
757 let topics: Vec<H256> = match num_topic {
758 0 => Vec::new(),
759 _ => {
760 let mut v = Vec::with_capacity(num_topic as usize);
761 let topics_len = num_topic * H256::len_bytes() as u32;
762 let buf = memory.read(topics_ptr, topics_len)?;
763 for chunk in buf.chunks_exact(H256::len_bytes()) {
764 v.push(H256::from_slice(chunk));
765 }
766 v
767 },
768 };
769
770 let event_data = memory.read(data_ptr, data_len)?;
771 self.ext.deposit_event(topics, event_data);
772 Ok(())
773 }
774
775 fn block_number(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
778 self.charge_gas(RuntimeCosts::BlockNumber)?;
779 Ok(self.write_fixed_sandbox_output(
780 memory,
781 out_ptr,
782 &self.ext.block_number().to_little_endian(),
783 false,
784 already_charged,
785 )?)
786 }
787
788 fn block_hash(
791 &mut self,
792 memory: &mut M,
793 block_number_ptr: u32,
794 out_ptr: u32,
795 ) -> Result<(), TrapReason> {
796 self.charge_gas(RuntimeCosts::BlockHash)?;
797 let block_number = memory.read_u256(block_number_ptr)?;
798 let block_hash = self.ext.block_hash(block_number).unwrap_or(H256::zero());
799 Ok(self.write_fixed_sandbox_output(
800 memory,
801 out_ptr,
802 &block_hash.as_bytes(),
803 false,
804 already_charged,
805 )?)
806 }
807
808 fn block_author(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
811 self.charge_gas(RuntimeCosts::BlockAuthor)?;
812 let block_author = self.ext.block_author();
813
814 Ok(self.write_fixed_sandbox_output(
815 memory,
816 out_ptr,
817 &block_author.as_bytes(),
818 false,
819 already_charged,
820 )?)
821 }
822
823 fn hash_keccak_256(
826 &mut self,
827 memory: &mut M,
828 input_ptr: u32,
829 input_len: u32,
830 output_ptr: u32,
831 ) -> Result<(), TrapReason> {
832 self.charge_gas(RuntimeCosts::HashKeccak256(input_len))?;
833 Ok(self.compute_hash_on_intermediate_buffer(
834 memory, keccak_256, input_ptr, input_len, output_ptr,
835 )?)
836 }
837
838 fn return_data_size(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
841 self.charge_gas(RuntimeCosts::ReturnDataSize)?;
842 Ok(self
843 .ext
844 .last_frame_output()
845 .data
846 .len()
847 .try_into()
848 .expect("usize fits into u64; qed"))
849 }
850
851 fn return_data_copy(
854 &mut self,
855 memory: &mut M,
856 out_ptr: u32,
857 out_len_ptr: u32,
858 offset: u32,
859 ) -> Result<(), TrapReason> {
860 let output = mem::take(self.ext.last_frame_output_mut());
861 let result = if offset as usize > output.data.len() {
862 Err(Error::<E::T>::OutOfBounds.into())
863 } else {
864 self.write_sandbox_output(
865 memory,
866 out_ptr,
867 out_len_ptr,
868 &output.data[offset as usize..],
869 false,
870 |len| Some(RuntimeCosts::CopyToContract(len)),
871 )
872 };
873 *self.ext.last_frame_output_mut() = output;
874 Ok(result?)
875 }
876
877 fn ref_time_left(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
884 self.charge_gas(RuntimeCosts::RefTimeLeft)?;
885 Ok(self.ext.gas_left())
886 }
887
888 fn consume_all_gas(&mut self, memory: &mut M) -> Result<(), TrapReason> {
892 self.ext.frame_meter_mut().consume_all_weight();
893 Err(TrapReason::Return(ReturnData {
894 flags: ReturnFlags::REVERT.bits(),
895 data: Default::default(),
896 }))
897 }
898
899 fn ecdsa_to_eth_address(
902 &mut self,
903 memory: &mut M,
904 key_ptr: u32,
905 out_ptr: u32,
906 ) -> Result<ReturnErrorCode, TrapReason> {
907 self.charge_gas(RuntimeCosts::EcdsaToEthAddress)?;
908 let mut compressed_key: [u8; 33] = [0; 33];
909 memory.read_into_buf(key_ptr, &mut compressed_key)?;
910 let result = self.ext.ecdsa_to_eth_address(&compressed_key);
911 match result {
912 Ok(eth_address) => {
913 memory.write(out_ptr, eth_address.as_ref())?;
914 Ok(ReturnErrorCode::Success)
915 },
916 Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed),
917 }
918 }
919
920 fn sr25519_verify(
923 &mut self,
924 memory: &mut M,
925 signature_ptr: u32,
926 pub_key_ptr: u32,
927 message_len: u32,
928 message_ptr: u32,
929 ) -> Result<ReturnErrorCode, TrapReason> {
930 self.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?;
931
932 let mut signature: [u8; 64] = [0; 64];
933 memory.read_into_buf(signature_ptr, &mut signature)?;
934
935 let mut pub_key: [u8; 32] = [0; 32];
936 memory.read_into_buf(pub_key_ptr, &mut pub_key)?;
937
938 let message: Vec<u8> = memory.read(message_ptr, message_len)?;
939
940 if self.ext.sr25519_verify(&signature, &message, &pub_key) {
941 Ok(ReturnErrorCode::Success)
942 } else {
943 Ok(ReturnErrorCode::Sr25519VerifyFailed)
944 }
945 }
946
947 #[mutating]
951 fn terminate(&mut self, memory: &mut M, beneficiary_ptr: u32) -> Result<(), TrapReason> {
952 let charged = self.charge_gas(RuntimeCosts::Terminate { code_removed: true })?;
953 let beneficiary = memory.read_h160(beneficiary_ptr)?;
954 if matches!(self.ext.terminate_if_same_tx(&beneficiary)?, crate::CodeRemoved::No) {
955 self.adjust_gas(charged, RuntimeCosts::Terminate { code_removed: false });
956 }
957 Err(TrapReason::Termination)
958 }
959}