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 code = limits::code::enforce::<T>(code)?;
113
114 let code_len = code.len() as u32;
115 let deposit = calculate_code_deposit::<T>(code_len);
116
117 let code_info = CodeInfo {
118 owner,
119 deposit,
120 refcount: 0,
121 code_len,
122 code_type: BytecodeType::Pvm,
123 behaviour_version: Default::default(),
124 };
125 let code_hash = H256(sp_io::hashing::keccak_256(&code));
126 Ok(ContractBlob { code, code_info, code_hash })
127 }
128}
129
130impl<'a, E: Ext, M: PolkaVmInstance<E::T>> Runtime<'a, E, M> {
131 pub fn handle_interrupt(
132 &mut self,
133 interrupt: Result<polkavm::InterruptKind, polkavm::Error>,
134 module: &polkavm::Module,
135 instance: &mut M,
136 ) -> Option<ExecResult> {
137 use polkavm::InterruptKind::*;
138
139 match interrupt {
140 Err(error) => {
141 log::error!(target: LOG_TARGET, "polkavm execution error: {error}");
143 Some(Err(Error::<E::T>::ExecutionFailed.into()))
144 },
145 Ok(Finished) => {
146 Some(Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }))
147 },
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 },
178 Err(TrapReason::Termination) => Some(Ok(Default::default())),
179 Err(TrapReason::SupervisorError(error)) => Some(Err(error.into())),
180 }
181 },
182 }
183 }
184}
185
186#[define_env]
194pub mod env {
195 #[cfg(feature = "runtime-benchmarks")]
197 fn noop(&mut self, memory: &mut M) -> Result<(), TrapReason> {
198 Ok(())
199 }
200
201 #[mutating]
204 fn set_storage(
205 &mut self,
206 memory: &mut M,
207 flags: u32,
208 key_ptr: u32,
209 key_len: u32,
210 value_ptr: u32,
211 value_len: u32,
212 ) -> Result<u32, TrapReason> {
213 self.set_storage(
214 memory,
215 flags,
216 key_ptr,
217 key_len,
218 StorageValue::Memory { ptr: value_ptr, len: value_len },
219 )
220 }
221
222 #[mutating]
225 fn set_storage_or_clear(
226 &mut self,
227 memory: &mut M,
228 flags: u32,
229 key_ptr: u32,
230 value_ptr: u32,
231 ) -> Result<u32, TrapReason> {
232 let value = memory.read(value_ptr, 32)?;
233
234 if value.iter().all(|&b| b == 0) {
235 self.clear_storage(memory, flags, key_ptr, SENTINEL)
236 } else {
237 self.set_storage(memory, flags, key_ptr, SENTINEL, StorageValue::Value(value))
238 }
239 }
240
241 fn get_storage(
244 &mut self,
245 memory: &mut M,
246 flags: u32,
247 key_ptr: u32,
248 key_len: u32,
249 out_ptr: u32,
250 out_len_ptr: u32,
251 ) -> Result<ReturnErrorCode, TrapReason> {
252 self.get_storage(
253 memory,
254 flags,
255 key_ptr,
256 key_len,
257 out_ptr,
258 StorageReadMode::VariableOutput { output_len_ptr: out_len_ptr },
259 )
260 }
261
262 fn get_storage_or_zero(
265 &mut self,
266 memory: &mut M,
267 flags: u32,
268 key_ptr: u32,
269 out_ptr: u32,
270 ) -> Result<(), TrapReason> {
271 let _ = self.get_storage(
272 memory,
273 flags,
274 key_ptr,
275 SENTINEL,
276 out_ptr,
277 StorageReadMode::FixedOutput32,
278 )?;
279
280 Ok(())
281 }
282
283 fn call(
286 &mut self,
287 memory: &mut M,
288 flags_and_callee: u64,
289 ref_time_limit: u64,
290 proof_size_limit: u64,
291 deposit_and_value: u64,
292 input_data: u64,
293 output_data: u64,
294 ) -> Result<ReturnErrorCode, TrapReason> {
295 let (flags, callee_ptr) = extract_hi_lo(flags_and_callee);
296 let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value);
297 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
298 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
299 let weight = Weight::from_parts(ref_time_limit, proof_size_limit);
300
301 self.charge_gas(RuntimeCosts::CopyFromContract(32))?;
302 let deposit_limit = memory.read_u256(deposit_ptr)?;
303
304 self.call(
305 memory,
306 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
307 CallType::Call { value_ptr },
308 callee_ptr,
309 &CallResources::from_weight_and_deposit(weight, deposit_limit),
310 input_data_ptr,
311 input_data_len,
312 output_ptr,
313 output_len_ptr,
314 )
315 }
316
317 fn call_evm(
320 &mut self,
321 memory: &mut M,
322 flags: u32,
323 callee: u32,
324 value_ptr: u32,
325 gas: u64,
326 input_data: u64,
327 output_data: u64,
328 ) -> Result<ReturnErrorCode, TrapReason> {
329 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
330 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
331 let resources = if gas == u64::MAX {
332 CallResources::NoLimits
333 } else {
334 self.charge_gas(RuntimeCosts::CopyFromContract(32))?;
335 let value = memory.read_u256(value_ptr)?;
336 let add_stipend = !value.is_zero() || gas == revm::interpreter::gas::CALL_STIPEND;
338 CallResources::from_ethereum_gas(gas.into(), add_stipend)
339 };
340
341 self.call(
342 memory,
343 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
344 CallType::Call { value_ptr },
345 callee,
346 &resources,
347 input_data_ptr,
348 input_data_len,
349 output_ptr,
350 output_len_ptr,
351 )
352 }
353
354 fn delegate_call(
357 &mut self,
358 memory: &mut M,
359 flags_and_callee: u64,
360 ref_time_limit: u64,
361 proof_size_limit: u64,
362 deposit_ptr: u32,
363 input_data: u64,
364 output_data: u64,
365 ) -> Result<ReturnErrorCode, TrapReason> {
366 let (flags, address_ptr) = extract_hi_lo(flags_and_callee);
367 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
368 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
369 let weight = Weight::from_parts(ref_time_limit, proof_size_limit);
370
371 self.charge_gas(RuntimeCosts::CopyFromContract(32))?;
372 let deposit_limit = memory.read_u256(deposit_ptr)?;
373
374 self.call(
375 memory,
376 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
377 CallType::DelegateCall,
378 address_ptr,
379 &CallResources::from_weight_and_deposit(weight, deposit_limit),
380 input_data_ptr,
381 input_data_len,
382 output_ptr,
383 output_len_ptr,
384 )
385 }
386
387 fn delegate_call_evm(
390 &mut self,
391 memory: &mut M,
392 flags: u32,
393 callee: u32,
394 gas: u64,
395 input_data: u64,
396 output_data: u64,
397 ) -> Result<ReturnErrorCode, TrapReason> {
398 let (input_data_len, input_data_ptr) = extract_hi_lo(input_data);
399 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
400 let resources = if gas == u64::MAX {
401 CallResources::NoLimits
402 } else {
403 CallResources::from_ethereum_gas(gas.into(), false)
404 };
405
406 self.call(
407 memory,
408 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
409 CallType::DelegateCall,
410 callee,
411 &resources,
412 input_data_ptr,
413 input_data_len,
414 output_ptr,
415 output_len_ptr,
416 )
417 }
418
419 #[mutating]
422 fn instantiate(
423 &mut self,
424 memory: &mut M,
425 ref_time_limit: u64,
426 proof_size_limit: u64,
427 deposit_and_value: u64,
428 input_data: u64,
429 output_data: u64,
430 address_and_salt: u64,
431 ) -> Result<ReturnErrorCode, TrapReason> {
432 let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value);
433 let (input_data_len, code_hash_ptr) = extract_hi_lo(input_data);
434 let (output_len_ptr, output_ptr) = extract_hi_lo(output_data);
435 let (address_ptr, salt_ptr) = extract_hi_lo(address_and_salt);
436 let Some(input_data_ptr) = code_hash_ptr.checked_add(32) else {
437 return Err(Error::<E::T>::OutOfBounds.into());
438 };
439 let Some(input_data_len) = input_data_len.checked_sub(32) else {
440 return Err(Error::<E::T>::OutOfBounds.into());
441 };
442
443 self.instantiate(
444 memory,
445 code_hash_ptr,
446 Weight::from_parts(ref_time_limit, proof_size_limit),
447 deposit_ptr,
448 value_ptr,
449 input_data_ptr,
450 input_data_len,
451 address_ptr,
452 output_ptr,
453 output_len_ptr,
454 salt_ptr,
455 )
456 }
457
458 fn call_data_size(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
461 self.charge_gas(RuntimeCosts::CallDataSize)?;
462 Ok(self
463 .input_data
464 .as_ref()
465 .map(|input| input.len().try_into().expect("usize fits into u64; qed"))
466 .unwrap_or_default())
467 }
468
469 fn call_data_copy(
472 &mut self,
473 memory: &mut M,
474 out_ptr: u32,
475 out_len: u32,
476 offset: u32,
477 ) -> Result<(), TrapReason> {
478 self.charge_gas(RuntimeCosts::CallDataCopy(out_len))?;
479
480 let Some(input) = self.input_data.as_ref() else {
481 return Err(Error::<E::T>::InputForwarded.into());
482 };
483
484 let start = offset as usize;
485 if start >= input.len() {
486 memory.zero(out_ptr, out_len)?;
487 return Ok(());
488 }
489
490 let end = start.saturating_add(out_len as usize).min(input.len());
491 memory.write(out_ptr, &input[start..end])?;
492
493 let bytes_written = (end - start) as u32;
494 memory.zero(out_ptr.saturating_add(bytes_written), out_len - bytes_written)?;
495
496 Ok(())
497 }
498
499 fn call_data_load(
502 &mut self,
503 memory: &mut M,
504 out_ptr: u32,
505 offset: u32,
506 ) -> Result<(), TrapReason> {
507 self.charge_gas(RuntimeCosts::CallDataLoad)?;
508
509 let Some(input) = self.input_data.as_ref() else {
510 return Err(Error::<E::T>::InputForwarded.into());
511 };
512
513 let mut data = [0; 32];
514 let start = offset as usize;
515 let data = if start >= input.len() {
516 data } else {
518 let end = start.saturating_add(32).min(input.len());
519 data[..end - start].copy_from_slice(&input[start..end]);
520 data.reverse();
521 data };
523
524 self.write_fixed_sandbox_output(memory, out_ptr, &data, false, already_charged)?;
525
526 Ok(())
527 }
528
529 fn seal_return(
532 &mut self,
533 memory: &mut M,
534 flags: u32,
535 data_ptr: u32,
536 data_len: u32,
537 ) -> Result<(), TrapReason> {
538 self.charge_gas(RuntimeCosts::CopyFromContract(data_len))?;
539 if data_len > limits::CALLDATA_BYTES {
540 Err(<Error<E::T>>::ReturnDataTooLarge)?;
541 }
542 Err(TrapReason::Return(ReturnData { flags, data: memory.read(data_ptr, data_len)? }))
543 }
544
545 fn caller(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
548 self.charge_gas(RuntimeCosts::Caller)?;
549 let caller = <E::T as Config>::AddressMapper::to_address(self.ext.caller().account_id()?);
550 Ok(self.write_fixed_sandbox_output(
551 memory,
552 out_ptr,
553 caller.as_bytes(),
554 false,
555 already_charged,
556 )?)
557 }
558
559 fn origin(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
562 self.charge_gas(RuntimeCosts::Origin)?;
563 let origin = <E::T as Config>::AddressMapper::to_address(self.ext.origin().account_id()?);
564 Ok(self.write_fixed_sandbox_output(
565 memory,
566 out_ptr,
567 origin.as_bytes(),
568 false,
569 already_charged,
570 )?)
571 }
572
573 fn code_hash(&mut self, memory: &mut M, addr_ptr: u32, out_ptr: u32) -> Result<(), TrapReason> {
576 self.charge_gas(RuntimeCosts::CodeHash)?;
577 let address = memory.read_h160(addr_ptr)?;
578 Ok(self.write_fixed_sandbox_output(
579 memory,
580 out_ptr,
581 &self.ext.code_hash(&address).as_bytes(),
582 false,
583 already_charged,
584 )?)
585 }
586
587 fn code_size(&mut self, memory: &mut M, addr_ptr: u32) -> Result<u64, TrapReason> {
590 self.charge_gas(RuntimeCosts::CodeSize)?;
591 let address = memory.read_h160(addr_ptr)?;
592 Ok(self.ext.code_size(&address))
593 }
594
595 fn address(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
598 self.charge_gas(RuntimeCosts::Address)?;
599 let address = self.ext.address();
600 Ok(self.write_fixed_sandbox_output(
601 memory,
602 out_ptr,
603 address.as_bytes(),
604 false,
605 already_charged,
606 )?)
607 }
608
609 fn get_immutable_data(
612 &mut self,
613 memory: &mut M,
614 out_ptr: u32,
615 out_len_ptr: u32,
616 ) -> Result<(), TrapReason> {
617 let charge_len = self.ext.immutable_data_len();
622 let charged = self.charge_gas(RuntimeCosts::GetImmutableData(charge_len))?;
623 let data = self.ext.get_immutable_data()?;
624 self.adjust_gas(charged, RuntimeCosts::GetImmutableData(data.len() as u32));
625 self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged)?;
626 Ok(())
627 }
628
629 fn set_immutable_data(&mut self, memory: &mut M, ptr: u32, len: u32) -> Result<(), TrapReason> {
632 if len > limits::IMMUTABLE_BYTES {
633 return Err(Error::<E::T>::OutOfBounds.into());
634 }
635 self.charge_gas(RuntimeCosts::SetImmutableData(len))?;
636 let buf = memory.read(ptr, len)?;
637 let data = buf.try_into().expect("bailed out earlier; qed");
638 self.ext.set_immutable_data(data)?;
639 Ok(())
640 }
641
642 fn balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
645 self.charge_gas(RuntimeCosts::Balance)?;
646 Ok(self.write_fixed_sandbox_output(
647 memory,
648 out_ptr,
649 &self.ext.balance().to_little_endian(),
650 false,
651 already_charged,
652 )?)
653 }
654
655 fn balance_of(
658 &mut self,
659 memory: &mut M,
660 addr_ptr: u32,
661 out_ptr: u32,
662 ) -> Result<(), TrapReason> {
663 self.charge_gas(RuntimeCosts::BalanceOf)?;
664 let address = memory.read_h160(addr_ptr)?;
665 Ok(self.write_fixed_sandbox_output(
666 memory,
667 out_ptr,
668 &self.ext.balance_of(&address).to_little_endian(),
669 false,
670 already_charged,
671 )?)
672 }
673
674 fn chain_id(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
677 Ok(self.write_fixed_sandbox_output(
678 memory,
679 out_ptr,
680 &U256::from(<E::T as Config>::ChainId::get()).to_little_endian(),
681 false,
682 |_| Some(RuntimeCosts::CopyToContract(32)),
683 )?)
684 }
685
686 fn gas_limit(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
689 self.charge_gas(RuntimeCosts::GasLimit)?;
690 Ok(self.ext.gas_limit())
691 }
692
693 fn value_transferred(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
696 self.charge_gas(RuntimeCosts::ValueTransferred)?;
697 Ok(self.write_fixed_sandbox_output(
698 memory,
699 out_ptr,
700 &self.ext.value_transferred().to_little_endian(),
701 false,
702 already_charged,
703 )?)
704 }
705
706 fn gas_price(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
709 self.charge_gas(RuntimeCosts::GasPrice)?;
710 Ok(self.ext.effective_gas_price().saturated_into())
711 }
712
713 fn base_fee(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
716 self.charge_gas(RuntimeCosts::BaseFee)?;
717 Ok(self.write_fixed_sandbox_output(
718 memory,
719 out_ptr,
720 &Pallet::<E::T>::evm_base_fee().to_little_endian(),
721 false,
722 already_charged,
723 )?)
724 }
725
726 fn now(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
729 self.charge_gas(RuntimeCosts::Now)?;
730 Ok(self.write_fixed_sandbox_output(
731 memory,
732 out_ptr,
733 &self.ext.now().to_little_endian(),
734 false,
735 already_charged,
736 )?)
737 }
738
739 #[mutating]
742 fn deposit_event(
743 &mut self,
744 memory: &mut M,
745 topics_ptr: u32,
746 num_topic: u32,
747 data_ptr: u32,
748 data_len: u32,
749 ) -> Result<(), TrapReason> {
750 self.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len })?;
751
752 if num_topic > limits::NUM_EVENT_TOPICS {
753 return Err(Error::<E::T>::TooManyTopics.into());
754 }
755
756 if data_len > limits::EVENT_BYTES {
757 return Err(Error::<E::T>::ValueTooLarge.into());
758 }
759
760 let topics: Vec<H256> = match num_topic {
761 0 => Vec::new(),
762 _ => {
763 let mut v = Vec::with_capacity(num_topic as usize);
764 let topics_len = num_topic * H256::len_bytes() as u32;
765 let buf = memory.read(topics_ptr, topics_len)?;
766 for chunk in buf.chunks_exact(H256::len_bytes()) {
767 v.push(H256::from_slice(chunk));
768 }
769 v
770 },
771 };
772
773 let event_data = memory.read(data_ptr, data_len)?;
774 self.ext.deposit_event(topics, event_data);
775 Ok(())
776 }
777
778 fn block_number(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
781 self.charge_gas(RuntimeCosts::BlockNumber)?;
782 Ok(self.write_fixed_sandbox_output(
783 memory,
784 out_ptr,
785 &self.ext.block_number().to_little_endian(),
786 false,
787 already_charged,
788 )?)
789 }
790
791 fn block_hash(
794 &mut self,
795 memory: &mut M,
796 block_number_ptr: u32,
797 out_ptr: u32,
798 ) -> Result<(), TrapReason> {
799 self.charge_gas(RuntimeCosts::BlockHash)?;
800 let block_number = memory.read_u256(block_number_ptr)?;
801 let block_hash = self.ext.block_hash(block_number).unwrap_or(H256::zero());
802 Ok(self.write_fixed_sandbox_output(
803 memory,
804 out_ptr,
805 &block_hash.as_bytes(),
806 false,
807 already_charged,
808 )?)
809 }
810
811 fn block_author(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> {
814 self.charge_gas(RuntimeCosts::BlockAuthor)?;
815 let block_author = self.ext.block_author();
816
817 Ok(self.write_fixed_sandbox_output(
818 memory,
819 out_ptr,
820 &block_author.as_bytes(),
821 false,
822 already_charged,
823 )?)
824 }
825
826 fn hash_keccak_256(
829 &mut self,
830 memory: &mut M,
831 input_ptr: u32,
832 input_len: u32,
833 output_ptr: u32,
834 ) -> Result<(), TrapReason> {
835 self.charge_gas(RuntimeCosts::HashKeccak256(input_len))?;
836 Ok(self.compute_hash_on_intermediate_buffer(
837 memory, keccak_256, input_ptr, input_len, output_ptr,
838 )?)
839 }
840
841 fn return_data_size(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
844 self.charge_gas(RuntimeCosts::ReturnDataSize)?;
845 Ok(self
846 .ext
847 .last_frame_output()
848 .data
849 .len()
850 .try_into()
851 .expect("usize fits into u64; qed"))
852 }
853
854 fn return_data_copy(
857 &mut self,
858 memory: &mut M,
859 out_ptr: u32,
860 out_len_ptr: u32,
861 offset: u32,
862 ) -> Result<(), TrapReason> {
863 let output = mem::take(self.ext.last_frame_output_mut());
864 let result = if offset as usize > output.data.len() {
865 Err(Error::<E::T>::OutOfBounds.into())
866 } else {
867 self.write_sandbox_output(
868 memory,
869 out_ptr,
870 out_len_ptr,
871 &output.data[offset as usize..],
872 false,
873 |len| Some(RuntimeCosts::CopyToContract(len)),
874 )
875 };
876 *self.ext.last_frame_output_mut() = output;
877 Ok(result?)
878 }
879
880 fn ref_time_left(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
887 self.charge_gas(RuntimeCosts::RefTimeLeft)?;
888 Ok(self.ext.gas_left())
889 }
890
891 fn consume_all_gas(&mut self, memory: &mut M) -> Result<(), TrapReason> {
895 self.ext.frame_meter_mut().consume_all_weight();
896 Err(TrapReason::Return(ReturnData {
897 flags: ReturnFlags::REVERT.bits(),
898 data: Default::default(),
899 }))
900 }
901
902 fn ecdsa_to_eth_address(
905 &mut self,
906 memory: &mut M,
907 key_ptr: u32,
908 out_ptr: u32,
909 ) -> Result<ReturnErrorCode, TrapReason> {
910 self.charge_gas(RuntimeCosts::EcdsaToEthAddress)?;
911 let mut compressed_key: [u8; 33] = [0; 33];
912 memory.read_into_buf(key_ptr, &mut compressed_key)?;
913 let result = self.ext.ecdsa_to_eth_address(&compressed_key);
914 match result {
915 Ok(eth_address) => {
916 memory.write(out_ptr, eth_address.as_ref())?;
917 Ok(ReturnErrorCode::Success)
918 },
919 Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed),
920 }
921 }
922
923 fn sr25519_verify(
926 &mut self,
927 memory: &mut M,
928 signature_ptr: u32,
929 pub_key_ptr: u32,
930 message_len: u32,
931 message_ptr: u32,
932 ) -> Result<ReturnErrorCode, TrapReason> {
933 self.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?;
934
935 let mut signature: [u8; 64] = [0; 64];
936 memory.read_into_buf(signature_ptr, &mut signature)?;
937
938 let mut pub_key: [u8; 32] = [0; 32];
939 memory.read_into_buf(pub_key_ptr, &mut pub_key)?;
940
941 let message: Vec<u8> = memory.read(message_ptr, message_len)?;
942
943 if self.ext.sr25519_verify(&signature, &message, &pub_key) {
944 Ok(ReturnErrorCode::Success)
945 } else {
946 Ok(ReturnErrorCode::Sr25519VerifyFailed)
947 }
948 }
949
950 #[mutating]
954 fn terminate(&mut self, memory: &mut M, beneficiary_ptr: u32) -> Result<(), TrapReason> {
955 let charged = self.charge_gas(RuntimeCosts::Terminate { code_removed: true })?;
956 let beneficiary = memory.read_h160(beneficiary_ptr)?;
957 if matches!(self.ext.terminate_if_same_tx(&beneficiary)?, crate::CodeRemoved::No) {
958 self.adjust_gas(charged, RuntimeCosts::Terminate { code_removed: false });
959 }
960 Err(TrapReason::Termination)
961 }
962}
963
964#[cfg(test)]
965mod tests {
966 use super::*;
967 use pallet_revive_types::runtime_api::*;
968 use strum::VariantArray;
969
970 #[test]
971 fn wire_has_all_syscalls() {
972 let wire_syscalls = PolkavmSyscallV1::VARIANTS
973 .iter()
974 .copied()
975 .map(<&'static str>::from)
976 .collect::<Vec<_>>();
977 let canonical_syscalls = list_trace_ops()
978 .iter()
979 .map(|bytes| str::from_utf8(bytes).unwrap())
980 .collect::<Vec<_>>();
981
982 assert_eq!(
983 wire_syscalls, canonical_syscalls,
984 "There is a difference between the syscalls defined for the wire and the syscalls \
985 available in the system. Wire = {wire_syscalls:?}. Available = {canonical_syscalls:?}"
986 )
987 }
988}