1use super::*;
19
20use crate::{
21 address::AddressMapper,
22 debug::DebugSettings,
23 exec::Ext,
24 limits,
25 primitives::ExecReturnValue,
26 vm::{calculate_code_deposit, BytecodeType, ExportedFunction, RuntimeCosts},
27 AccountIdOf, CodeInfo, Config, ContractBlob, Error, Weight, SENTINEL,
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(T::UnsafeUnstableInterface::get());
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 Ok(Trap) => Some(Err(Error::<E::T>::ContractTrapped.into())),
149 Ok(Segfault(_)) => Some(Err(Error::<E::T>::ExecutionFailed.into())),
150 Ok(NotEnoughGas) => Some(Err(Error::<E::T>::OutOfGas.into())),
151 Ok(Step) => None,
152 Ok(Ecalli(idx)) => {
153 if cfg!(feature = "runtime-benchmarks") && idx == SENTINEL {
158 return Some(Ok(ExecReturnValue {
159 flags: ReturnFlags::empty(),
160 data: Vec::new(),
161 }))
162 }
163 let Some(syscall_symbol) = module.imports().get(idx) else {
164 return Some(Err(<Error<E::T>>::InvalidSyscall.into()));
165 };
166 match self.handle_ecall(instance, syscall_symbol.as_bytes()) {
167 Ok(None) => None,
168 Ok(Some(return_value)) => {
169 instance.write_output(return_value);
170 None
171 },
172 Err(TrapReason::Return(ReturnData { flags, data })) =>
173 match ReturnFlags::from_bits(flags) {
174 None => Some(Err(Error::<E::T>::InvalidCallFlags.into())),
175 Some(flags) => Some(Ok(ExecReturnValue { flags, data })),
176 },
177 Err(TrapReason::Termination) => Some(Ok(Default::default())),
178 Err(TrapReason::SupervisorError(error)) => Some(Err(error.into())),
179 }
180 },
181 }
182 }
183}
184
185#[define_env]
193pub mod env {
194 #[cfg(feature = "runtime-benchmarks")]
199 #[stable]
200 fn noop(&mut self, memory: &mut M) -> Result<(), TrapReason> {
201 Ok(())
202 }
203
204 #[stable]
207 #[mutating]
208 fn set_storage(
209 &mut self,
210 memory: &mut M,
211 flags: u32,
212 key_ptr: u32,
213 key_len: u32,
214 value_ptr: u32,
215 value_len: u32,
216 ) -> Result<u32, TrapReason> {
217 self.set_storage(
218 memory,
219 flags,
220 key_ptr,
221 key_len,
222 StorageValue::Memory { ptr: value_ptr, len: value_len },
223 )
224 }
225
226 #[stable]
229 #[mutating]
230 fn set_storage_or_clear(
231 &mut self,
232 memory: &mut M,
233 flags: u32,
234 key_ptr: u32,
235 value_ptr: u32,
236 ) -> Result<u32, TrapReason> {
237 let value = memory.read(value_ptr, 32)?;
238
239 if value.iter().all(|&b| b == 0) {
240 self.clear_storage(memory, flags, key_ptr, SENTINEL)
241 } else {
242 self.set_storage(memory, flags, key_ptr, SENTINEL, StorageValue::Value(value))
243 }
244 }
245
246 #[stable]
249 fn get_storage(
250 &mut self,
251 memory: &mut M,
252 flags: u32,
253 key_ptr: u32,
254 key_len: u32,
255 out_ptr: u32,
256 out_len_ptr: u32,
257 ) -> Result<ReturnErrorCode, TrapReason> {
258 self.get_storage(
259 memory,
260 flags,
261 key_ptr,
262 key_len,
263 out_ptr,
264 StorageReadMode::VariableOutput { output_len_ptr: out_len_ptr },
265 )
266 }
267
268 #[stable]
271 fn get_storage_or_zero(
272 &mut self,
273 memory: &mut M,
274 flags: u32,
275 key_ptr: u32,
276 out_ptr: u32,
277 ) -> Result<(), TrapReason> {
278 let _ = self.get_storage(
279 memory,
280 flags,
281 key_ptr,
282 SENTINEL,
283 out_ptr,
284 StorageReadMode::FixedOutput32,
285 )?;
286
287 Ok(())
288 }
289
290 #[stable]
293 fn call(
294 &mut self,
295 memory: &mut M,
296 flags_and_callee: u64,
297 ref_time_limit: u64,
298 proof_size_limit: u64,
299 deposit_and_value: u64,
300 input_data: u64,
301 output_data: u64,
302 ) -> Result<ReturnErrorCode, TrapReason> {
303 let (flags, callee_ptr) = extract_hi_lo(flags_and_callee);
304 let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value);
305 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
306 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
307 let weight = Weight::from_parts(ref_time_limit, proof_size_limit);
308
309 self.charge_gas(RuntimeCosts::CopyFromContract(32))?;
310 let deposit_limit = memory.read_u256(deposit_ptr)?;
311
312 self.call(
313 memory,
314 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
315 CallType::Call { value_ptr },
316 callee_ptr,
317 &CallResources::from_weight_and_deposit(weight, deposit_limit),
318 input_data_ptr,
319 input_data_len,
320 output_ptr,
321 output_len_ptr,
322 )
323 }
324
325 #[stable]
328 fn call_evm(
329 &mut self,
330 memory: &mut M,
331 flags: u32,
332 callee: u32,
333 value_ptr: u32,
334 gas: u64,
335 input_data: u64,
336 output_data: u64,
337 ) -> Result<ReturnErrorCode, TrapReason> {
338 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
339 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
340 let resources = if gas == u64::MAX {
341 CallResources::NoLimits
342 } else {
343 self.charge_gas(RuntimeCosts::CopyFromContract(32))?;
344 let value = memory.read_u256(value_ptr)?;
345 let add_stipend = !value.is_zero() || gas == revm::interpreter::gas::CALL_STIPEND;
347 CallResources::from_ethereum_gas(gas.into(), add_stipend)
348 };
349
350 self.call(
351 memory,
352 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
353 CallType::Call { value_ptr },
354 callee,
355 &resources,
356 input_data_ptr,
357 input_data_len,
358 output_ptr,
359 output_len_ptr,
360 )
361 }
362
363 #[stable]
366 fn delegate_call(
367 &mut self,
368 memory: &mut M,
369 flags_and_callee: u64,
370 ref_time_limit: u64,
371 proof_size_limit: u64,
372 deposit_ptr: u32,
373 input_data: u64,
374 output_data: u64,
375 ) -> Result<ReturnErrorCode, TrapReason> {
376 let (flags, address_ptr) = extract_hi_lo(flags_and_callee);
377 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
378 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
379 let weight = Weight::from_parts(ref_time_limit, proof_size_limit);
380
381 self.charge_gas(RuntimeCosts::CopyFromContract(32))?;
382 let deposit_limit = memory.read_u256(deposit_ptr)?;
383
384 self.call(
385 memory,
386 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
387 CallType::DelegateCall,
388 address_ptr,
389 &CallResources::from_weight_and_deposit(weight, deposit_limit),
390 input_data_ptr,
391 input_data_len,
392 output_ptr,
393 output_len_ptr,
394 )
395 }
396
397 #[stable]
400 fn delegate_call_evm(
401 &mut self,
402 memory: &mut M,
403 flags: u32,
404 callee: u32,
405 gas: u64,
406 input_data: u64,
407 output_data: u64,
408 ) -> Result<ReturnErrorCode, TrapReason> {
409 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
410 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
411 let resources = if gas == u64::MAX {
412 CallResources::NoLimits
413 } else {
414 CallResources::from_ethereum_gas(gas.into(), false)
415 };
416
417 self.call(
418 memory,
419 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
420 CallType::DelegateCall,
421 callee,
422 &resources,
423 input_data_ptr,
424 input_data_len,
425 output_ptr,
426 output_len_ptr,
427 )
428 }
429
430 #[stable]
433 #[mutating]
434 fn instantiate(
435 &mut self,
436 memory: &mut M,
437 ref_time_limit: u64,
438 proof_size_limit: u64,
439 deposit_and_value: u64,
440 input_data: u64,
441 output_data: u64,
442 address_and_salt: u64,
443 ) -> Result<ReturnErrorCode, TrapReason> {
444 let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value);
445 let (input_data_len, code_hash_ptr) = extract_hi_lo(input_data);
446 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
447 let (address_ptr, salt_ptr) = extract_hi_lo(address_and_salt);
448 let Some(input_data_ptr) = code_hash_ptr.checked_add(32) else {
449 return Err(Error::<E::T>::OutOfBounds.into());
450 };
451 let Some(input_data_len) = input_data_len.checked_sub(32) else {
452 return Err(Error::<E::T>::OutOfBounds.into());
453 };
454
455 self.instantiate(
456 memory,
457 code_hash_ptr,
458 Weight::from_parts(ref_time_limit, proof_size_limit),
459 deposit_ptr,
460 value_ptr,
461 input_data_ptr,
462 input_data_len,
463 address_ptr,
464 output_ptr,
465 output_len_ptr,
466 salt_ptr,
467 )
468 }
469
470 #[stable]
473 fn call_data_size(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
474 self.charge_gas(RuntimeCosts::CallDataSize)?;
475 Ok(self
476 .input_data
477 .as_ref()
478 .map(|input| input.len().try_into().expect("usize fits into u64; qed"))
479 .unwrap_or_default())
480 }
481
482 #[stable]
485 fn call_data_copy(
486 &mut self,
487 memory: &mut M,
488 out_ptr: u32,
489 out_len: u32,
490 offset: u32,
491 ) -> Result<(), TrapReason> {
492 self.charge_gas(RuntimeCosts::CallDataCopy(out_len))?;
493
494 let Some(input) = self.input_data.as_ref() else {
495 return Err(Error::<E::T>::InputForwarded.into());
496 };
497
498 let start = offset as usize;
499 if start >= input.len() {
500 memory.zero(out_ptr, out_len)?;
501 return Ok(());
502 }
503
504 let end = start.saturating_add(out_len as usize).min(input.len());
505 memory.write(out_ptr, &input[start..end])?;
506
507 let bytes_written = (end - start) as u32;
508 memory.zero(out_ptr.saturating_add(bytes_written), out_len - bytes_written)?;
509
510 Ok(())
511 }
512
513 #[stable]
516 fn call_data_load(
517 &mut self,
518 memory: &mut M,
519 out_ptr: u32,
520 offset: u32,
521 ) -> Result<(), TrapReason> {
522 self.charge_gas(RuntimeCosts::CallDataLoad)?;
523
524 let Some(input) = self.input_data.as_ref() else {
525 return Err(Error::<E::T>::InputForwarded.into());
526 };
527
528 let mut data = [0; 32];
529 let start = offset as usize;
530 let data = if start >= input.len() {
531 data } else {
533 let end = start.saturating_add(32).min(input.len());
534 data[..end - start].copy_from_slice(&input[start..end]);
535 data.reverse();
536 data };
538
539 self.write_fixed_sandbox_output(memory, out_ptr, &data, false, already_charged)?;
540
541 Ok(())
542 }
543
544 #[stable]
547 fn seal_return(
548 &mut self,
549 memory: &mut M,
550 flags: u32,
551 data_ptr: u32,
552 data_len: u32,
553 ) -> Result<(), TrapReason> {
554 self.charge_gas(RuntimeCosts::CopyFromContract(data_len))?;
555 if data_len > limits::CALLDATA_BYTES {
556 Err(<Error<E::T>>::ReturnDataTooLarge)?;
557 }
558 Err(TrapReason::Return(ReturnData { flags, data: memory.read(data_ptr, data_len)? }))
559 }
560
561 #[stable]
564 fn caller(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
565 self.charge_gas(RuntimeCosts::Caller)?;
566 let caller = <E::T as Config>::AddressMapper::to_address(self.ext.caller().account_id()?);
567 Ok(self.write_fixed_sandbox_output(
568 memory,
569 out_ptr,
570 caller.as_bytes(),
571 false,
572 already_charged,
573 )?)
574 }
575
576 #[stable]
579 fn origin(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
580 self.charge_gas(RuntimeCosts::Origin)?;
581 let origin = <E::T as Config>::AddressMapper::to_address(self.ext.origin().account_id()?);
582 Ok(self.write_fixed_sandbox_output(
583 memory,
584 out_ptr,
585 origin.as_bytes(),
586 false,
587 already_charged,
588 )?)
589 }
590
591 #[stable]
594 fn code_hash(&mut self, memory: &mut M, addr_ptr: u32, out_ptr: u32) -> Result<(), TrapReason> {
595 self.charge_gas(RuntimeCosts::CodeHash)?;
596 let address = memory.read_h160(addr_ptr)?;
597 Ok(self.write_fixed_sandbox_output(
598 memory,
599 out_ptr,
600 &self.ext.code_hash(&address).as_bytes(),
601 false,
602 already_charged,
603 )?)
604 }
605
606 #[stable]
609 fn code_size(&mut self, memory: &mut M, addr_ptr: u32) -> Result<u64, TrapReason> {
610 self.charge_gas(RuntimeCosts::CodeSize)?;
611 let address = memory.read_h160(addr_ptr)?;
612 Ok(self.ext.code_size(&address))
613 }
614
615 #[stable]
618 fn address(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
619 self.charge_gas(RuntimeCosts::Address)?;
620 let address = self.ext.address();
621 Ok(self.write_fixed_sandbox_output(
622 memory,
623 out_ptr,
624 address.as_bytes(),
625 false,
626 already_charged,
627 )?)
628 }
629
630 #[stable]
633 fn get_immutable_data(
634 &mut self,
635 memory: &mut M,
636 out_ptr: u32,
637 out_len_ptr: u32,
638 ) -> Result<(), TrapReason> {
639 let len = self.ext.immutable_data_len();
641 self.charge_gas(RuntimeCosts::GetImmutableData(len))?;
642 let data = self.ext.get_immutable_data()?;
643 self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged)?;
644 Ok(())
645 }
646
647 #[stable]
650 fn set_immutable_data(&mut self, memory: &mut M, ptr: u32, len: u32) -> Result<(), TrapReason> {
651 if len > limits::IMMUTABLE_BYTES {
652 return Err(Error::<E::T>::OutOfBounds.into());
653 }
654 self.charge_gas(RuntimeCosts::SetImmutableData(len))?;
655 let buf = memory.read(ptr, len)?;
656 let data = buf.try_into().expect("bailed out earlier; qed");
657 self.ext.set_immutable_data(data)?;
658 Ok(())
659 }
660
661 #[stable]
664 fn balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
665 self.charge_gas(RuntimeCosts::Balance)?;
666 Ok(self.write_fixed_sandbox_output(
667 memory,
668 out_ptr,
669 &self.ext.balance().to_little_endian(),
670 false,
671 already_charged,
672 )?)
673 }
674
675 #[stable]
678 fn balance_of(
679 &mut self,
680 memory: &mut M,
681 addr_ptr: u32,
682 out_ptr: u32,
683 ) -> Result<(), TrapReason> {
684 self.charge_gas(RuntimeCosts::BalanceOf)?;
685 let address = memory.read_h160(addr_ptr)?;
686 Ok(self.write_fixed_sandbox_output(
687 memory,
688 out_ptr,
689 &self.ext.balance_of(&address).to_little_endian(),
690 false,
691 already_charged,
692 )?)
693 }
694
695 #[stable]
698 fn chain_id(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
699 Ok(self.write_fixed_sandbox_output(
700 memory,
701 out_ptr,
702 &U256::from(<E::T as Config>::ChainId::get()).to_little_endian(),
703 false,
704 |_| Some(RuntimeCosts::CopyToContract(32)),
705 )?)
706 }
707
708 #[stable]
711 fn gas_limit(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
712 self.charge_gas(RuntimeCosts::GasLimit)?;
713 Ok(self.ext.gas_limit())
714 }
715
716 #[stable]
719 fn value_transferred(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
720 self.charge_gas(RuntimeCosts::ValueTransferred)?;
721 Ok(self.write_fixed_sandbox_output(
722 memory,
723 out_ptr,
724 &self.ext.value_transferred().to_little_endian(),
725 false,
726 already_charged,
727 )?)
728 }
729
730 #[stable]
733 fn gas_price(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
734 self.charge_gas(RuntimeCosts::GasPrice)?;
735 Ok(self.ext.effective_gas_price().saturated_into())
736 }
737
738 #[stable]
741 fn base_fee(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
742 self.charge_gas(RuntimeCosts::BaseFee)?;
743 Ok(self.write_fixed_sandbox_output(
744 memory,
745 out_ptr,
746 &Pallet::<E::T>::evm_base_fee().to_little_endian(),
747 false,
748 already_charged,
749 )?)
750 }
751
752 #[stable]
755 fn now(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
756 self.charge_gas(RuntimeCosts::Now)?;
757 Ok(self.write_fixed_sandbox_output(
758 memory,
759 out_ptr,
760 &self.ext.now().to_little_endian(),
761 false,
762 already_charged,
763 )?)
764 }
765
766 #[stable]
769 #[mutating]
770 fn deposit_event(
771 &mut self,
772 memory: &mut M,
773 topics_ptr: u32,
774 num_topic: u32,
775 data_ptr: u32,
776 data_len: u32,
777 ) -> Result<(), TrapReason> {
778 self.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len })?;
779
780 if num_topic > limits::NUM_EVENT_TOPICS {
781 return Err(Error::<E::T>::TooManyTopics.into());
782 }
783
784 if data_len > limits::EVENT_BYTES {
785 return Err(Error::<E::T>::ValueTooLarge.into());
786 }
787
788 let topics: Vec<H256> = match num_topic {
789 0 => Vec::new(),
790 _ => {
791 let mut v = Vec::with_capacity(num_topic as usize);
792 let topics_len = num_topic * H256::len_bytes() as u32;
793 let buf = memory.read(topics_ptr, topics_len)?;
794 for chunk in buf.chunks_exact(H256::len_bytes()) {
795 v.push(H256::from_slice(chunk));
796 }
797 v
798 },
799 };
800
801 let event_data = memory.read(data_ptr, data_len)?;
802 self.ext.deposit_event(topics, event_data);
803 Ok(())
804 }
805
806 #[stable]
809 fn block_number(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
810 self.charge_gas(RuntimeCosts::BlockNumber)?;
811 Ok(self.write_fixed_sandbox_output(
812 memory,
813 out_ptr,
814 &self.ext.block_number().to_little_endian(),
815 false,
816 already_charged,
817 )?)
818 }
819
820 #[stable]
823 fn block_hash(
824 &mut self,
825 memory: &mut M,
826 block_number_ptr: u32,
827 out_ptr: u32,
828 ) -> Result<(), TrapReason> {
829 self.charge_gas(RuntimeCosts::BlockHash)?;
830 let block_number = memory.read_u256(block_number_ptr)?;
831 let block_hash = self.ext.block_hash(block_number).unwrap_or(H256::zero());
832 Ok(self.write_fixed_sandbox_output(
833 memory,
834 out_ptr,
835 &block_hash.as_bytes(),
836 false,
837 already_charged,
838 )?)
839 }
840
841 #[stable]
844 fn block_author(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
845 self.charge_gas(RuntimeCosts::BlockAuthor)?;
846 let block_author = self.ext.block_author();
847
848 Ok(self.write_fixed_sandbox_output(
849 memory,
850 out_ptr,
851 &block_author.as_bytes(),
852 false,
853 already_charged,
854 )?)
855 }
856
857 #[stable]
860 fn hash_keccak_256(
861 &mut self,
862 memory: &mut M,
863 input_ptr: u32,
864 input_len: u32,
865 output_ptr: u32,
866 ) -> Result<(), TrapReason> {
867 self.charge_gas(RuntimeCosts::HashKeccak256(input_len))?;
868 Ok(self.compute_hash_on_intermediate_buffer(
869 memory, keccak_256, input_ptr, input_len, output_ptr,
870 )?)
871 }
872
873 #[stable]
876 fn return_data_size(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
877 self.charge_gas(RuntimeCosts::ReturnDataSize)?;
878 Ok(self
879 .ext
880 .last_frame_output()
881 .data
882 .len()
883 .try_into()
884 .expect("usize fits into u64; qed"))
885 }
886
887 #[stable]
890 fn return_data_copy(
891 &mut self,
892 memory: &mut M,
893 out_ptr: u32,
894 out_len_ptr: u32,
895 offset: u32,
896 ) -> Result<(), TrapReason> {
897 let output = mem::take(self.ext.last_frame_output_mut());
898 let result = if offset as usize > output.data.len() {
899 Err(Error::<E::T>::OutOfBounds.into())
900 } else {
901 self.write_sandbox_output(
902 memory,
903 out_ptr,
904 out_len_ptr,
905 &output.data[offset as usize..],
906 false,
907 |len| Some(RuntimeCosts::CopyToContract(len)),
908 )
909 };
910 *self.ext.last_frame_output_mut() = output;
911 Ok(result?)
912 }
913
914 #[stable]
921 fn ref_time_left(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
922 self.charge_gas(RuntimeCosts::RefTimeLeft)?;
923 Ok(self.ext.gas_left())
924 }
925
926 #[stable]
930 fn consume_all_gas(&mut self, memory: &mut M) -> Result<(), TrapReason> {
931 self.ext.frame_meter_mut().consume_all_weight();
932 Err(TrapReason::Return(ReturnData {
933 flags: ReturnFlags::REVERT.bits(),
934 data: Default::default(),
935 }))
936 }
937
938 fn ecdsa_to_eth_address(
941 &mut self,
942 memory: &mut M,
943 key_ptr: u32,
944 out_ptr: u32,
945 ) -> Result<ReturnErrorCode, TrapReason> {
946 self.charge_gas(RuntimeCosts::EcdsaToEthAddress)?;
947 let mut compressed_key: [u8; 33] = [0; 33];
948 memory.read_into_buf(key_ptr, &mut compressed_key)?;
949 let result = self.ext.ecdsa_to_eth_address(&compressed_key);
950 match result {
951 Ok(eth_address) => {
952 memory.write(out_ptr, eth_address.as_ref())?;
953 Ok(ReturnErrorCode::Success)
954 },
955 Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed),
956 }
957 }
958
959 fn sr25519_verify(
962 &mut self,
963 memory: &mut M,
964 signature_ptr: u32,
965 pub_key_ptr: u32,
966 message_len: u32,
967 message_ptr: u32,
968 ) -> Result<ReturnErrorCode, TrapReason> {
969 self.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?;
970
971 let mut signature: [u8; 64] = [0; 64];
972 memory.read_into_buf(signature_ptr, &mut signature)?;
973
974 let mut pub_key: [u8; 32] = [0; 32];
975 memory.read_into_buf(pub_key_ptr, &mut pub_key)?;
976
977 let message: Vec<u8> = memory.read(message_ptr, message_len)?;
978
979 if self.ext.sr25519_verify(&signature, &message, &pub_key) {
980 Ok(ReturnErrorCode::Success)
981 } else {
982 Ok(ReturnErrorCode::Sr25519VerifyFailed)
983 }
984 }
985
986 #[mutating]
990 #[stable]
991 fn terminate(&mut self, memory: &mut M, beneficiary_ptr: u32) -> Result<(), TrapReason> {
992 let charged = self.charge_gas(RuntimeCosts::Terminate { code_removed: true })?;
993 let beneficiary = memory.read_h160(beneficiary_ptr)?;
994 if matches!(self.ext.terminate_if_same_tx(&beneficiary)?, crate::CodeRemoved::No) {
995 self.adjust_gas(charged, RuntimeCosts::Terminate { code_removed: false });
996 }
997 Err(TrapReason::Termination)
998 }
999}