pallet_revive_uapi/host/
riscv64.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![allow(unused_variables)]
16
17use crate::{
18	host::{CallFlags, HostFn, HostFnImpl, Result, StorageFlags},
19	pack_hi_lo, ReturnFlags,
20};
21use pallet_revive_proc_macro::unstable_hostfn;
22
23mod sys {
24	use crate::ReturnCode;
25
26	#[polkavm_derive::polkavm_define_abi]
27	mod abi {}
28
29	impl abi::FromHost for ReturnCode {
30		type Regs = (u64,);
31
32		fn from_host((a0,): Self::Regs) -> Self {
33			ReturnCode(a0 as _)
34		}
35	}
36
37	#[polkavm_derive::polkavm_import(abi = self::abi)]
38	extern "C" {
39		pub fn set_storage(
40			flags: u32,
41			key_ptr: *const u8,
42			key_len: u32,
43			value_ptr: *const u8,
44			value_len: u32,
45		) -> ReturnCode;
46		pub fn clear_storage(flags: u32, key_ptr: *const u8, key_len: u32) -> ReturnCode;
47		pub fn get_storage(
48			flags: u32,
49			key_ptr: *const u8,
50			key_len: u32,
51			out_ptr: *mut u8,
52			out_len_ptr: *mut u32,
53		) -> ReturnCode;
54		pub fn contains_storage(flags: u32, key_ptr: *const u8, key_len: u32) -> ReturnCode;
55		pub fn take_storage(
56			flags: u32,
57			key_ptr: *const u8,
58			key_len: u32,
59			out_ptr: *mut u8,
60			out_len_ptr: *mut u32,
61		) -> ReturnCode;
62		pub fn call(
63			flags_and_callee: u64,
64			ref_time_limit: u64,
65			proof_size_limit: u64,
66			deposit_and_value: u64,
67			input_data: u64,
68			output_data: u64,
69		) -> ReturnCode;
70		pub fn delegate_call(
71			flags_and_callee: u64,
72			ref_time_limit: u64,
73			proof_size_limit: u64,
74			deposit_ptr: *const u8,
75			input_data: u64,
76			output_data: u64,
77		) -> ReturnCode;
78		pub fn instantiate(
79			ref_time_limit: u64,
80			proof_size_limit: u64,
81			deposit_and_value: u64,
82			input_data: u64,
83			output_data: u64,
84			address_and_salt: u64,
85		) -> ReturnCode;
86		pub fn terminate(beneficiary_ptr: *const u8);
87		pub fn call_data_copy(out_ptr: *mut u8, out_len: u32, offset: u32);
88		pub fn call_data_load(out_ptr: *mut u8, offset: u32);
89		pub fn seal_return(flags: u32, data_ptr: *const u8, data_len: u32);
90		pub fn caller(out_ptr: *mut u8);
91		pub fn origin(out_ptr: *mut u8);
92		pub fn is_contract(account_ptr: *const u8) -> ReturnCode;
93		pub fn to_account_id(address_ptr: *const u8, out_ptr: *mut u8);
94		pub fn code_hash(address_ptr: *const u8, out_ptr: *mut u8);
95		pub fn code_size(address_ptr: *const u8) -> u64;
96		pub fn own_code_hash(out_ptr: *mut u8);
97		pub fn caller_is_origin() -> ReturnCode;
98		pub fn caller_is_root() -> ReturnCode;
99		pub fn address(out_ptr: *mut u8);
100		pub fn weight_to_fee(ref_time: u64, proof_size: u64, out_ptr: *mut u8);
101		pub fn weight_left(out_ptr: *mut u8, out_len_ptr: *mut u32);
102		pub fn ref_time_left() -> u64;
103		pub fn get_immutable_data(out_ptr: *mut u8, out_len_ptr: *mut u32);
104		pub fn set_immutable_data(ptr: *const u8, len: u32);
105		pub fn balance(out_ptr: *mut u8);
106		pub fn balance_of(addr_ptr: *const u8, out_ptr: *mut u8);
107		pub fn chain_id(out_ptr: *mut u8);
108		pub fn value_transferred(out_ptr: *mut u8);
109		pub fn now(out_ptr: *mut u8);
110		pub fn gas_limit() -> u64;
111		pub fn minimum_balance(out_ptr: *mut u8);
112		pub fn deposit_event(
113			topics_ptr: *const [u8; 32],
114			num_topic: u32,
115			data_ptr: *const u8,
116			data_len: u32,
117		);
118		pub fn gas_price() -> u64;
119		pub fn base_fee(out_ptr: *mut u8);
120		pub fn call_data_size() -> u64;
121		pub fn block_number(out_ptr: *mut u8);
122		pub fn block_hash(block_number_ptr: *const u8, out_ptr: *mut u8);
123		pub fn block_author(out_ptr: *mut u8);
124		pub fn hash_keccak_256(input_ptr: *const u8, input_len: u32, out_ptr: *mut u8);
125		pub fn hash_blake2_256(input_ptr: *const u8, input_len: u32, out_ptr: *mut u8);
126		pub fn hash_blake2_128(input_ptr: *const u8, input_len: u32, out_ptr: *mut u8);
127		pub fn call_chain_extension(
128			id: u32,
129			input_ptr: *const u8,
130			input_len: u32,
131			out_ptr: *mut u8,
132			out_len_ptr: *mut u32,
133		) -> ReturnCode;
134		pub fn call_runtime(call_ptr: *const u8, call_len: u32) -> ReturnCode;
135		pub fn sr25519_verify(
136			signature_ptr: *const u8,
137			pub_key_ptr: *const u8,
138			message_len: u32,
139			message_ptr: *const u8,
140		) -> ReturnCode;
141		pub fn set_code_hash(code_hash_ptr: *const u8);
142		pub fn ecdsa_to_eth_address(key_ptr: *const u8, out_ptr: *mut u8) -> ReturnCode;
143		pub fn instantiation_nonce() -> u64;
144		pub fn xcm_execute(msg_ptr: *const u8, msg_len: u32) -> ReturnCode;
145		pub fn xcm_send(
146			dest_ptr: *const u8,
147			dest_len: *const u8,
148			msg_ptr: *const u8,
149			msg_len: u32,
150			out_ptr: *mut u8,
151		) -> ReturnCode;
152		pub fn return_data_size() -> u64;
153		pub fn return_data_copy(out_ptr: *mut u8, out_len_ptr: *mut u32, offset: u32);
154	}
155}
156
157#[inline(always)]
158fn extract_from_slice(output: &mut &mut [u8], new_len: usize) {
159	debug_assert!(new_len <= output.len());
160	let tmp = core::mem::take(output);
161	*output = &mut tmp[..new_len];
162}
163
164#[inline(always)]
165fn ptr_len_or_sentinel(data: &mut Option<&mut &mut [u8]>) -> (*mut u8, u32) {
166	match data {
167		Some(ref mut data) => (data.as_mut_ptr(), data.len() as _),
168		None => (crate::SENTINEL as _, 0),
169	}
170}
171
172#[inline(always)]
173fn ptr_or_sentinel(data: &Option<&[u8; 32]>) -> *const u8 {
174	match data {
175		Some(ref data) => data.as_ptr(),
176		None => crate::SENTINEL as _,
177	}
178}
179
180impl HostFn for HostFnImpl {
181	fn instantiate(
182		ref_time_limit: u64,
183		proof_size_limit: u64,
184		deposit_limit: &[u8; 32],
185		value: &[u8; 32],
186		input: &[u8],
187		mut address: Option<&mut [u8; 20]>,
188		mut output: Option<&mut &mut [u8]>,
189		salt: Option<&[u8; 32]>,
190	) -> Result {
191		let address = match address {
192			Some(ref mut data) => data.as_mut_ptr(),
193			None => crate::SENTINEL as _,
194		};
195		let (output_ptr, mut output_len_ptr) = ptr_len_or_sentinel(&mut output);
196		let deposit_limit_ptr = deposit_limit.as_ptr();
197		let salt_ptr = ptr_or_sentinel(&salt);
198
199		let deposit_and_value = pack_hi_lo(deposit_limit_ptr as _, value.as_ptr() as _);
200		let address_and_salt = pack_hi_lo(address as _, salt_ptr as _);
201		let input_data = pack_hi_lo(input.len() as _, input.as_ptr() as _);
202		let output_data = pack_hi_lo(&mut output_len_ptr as *mut _ as _, output_ptr as _);
203
204		let ret_code = unsafe {
205			sys::instantiate(
206				ref_time_limit,
207				proof_size_limit,
208				deposit_and_value,
209				input_data,
210				output_data,
211				address_and_salt,
212			)
213		};
214
215		if let Some(ref mut output) = output {
216			extract_from_slice(output, output_len_ptr as usize);
217		}
218
219		ret_code.into()
220	}
221
222	fn call(
223		flags: CallFlags,
224		callee: &[u8; 20],
225		ref_time_limit: u64,
226		proof_size_limit: u64,
227		deposit_limit: &[u8; 32],
228		value: &[u8; 32],
229		input: &[u8],
230		mut output: Option<&mut &mut [u8]>,
231	) -> Result {
232		let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output);
233		let deposit_limit_ptr = deposit_limit.as_ptr();
234
235		let flags_and_callee = pack_hi_lo(flags.bits(), callee.as_ptr() as _);
236		let deposit_and_value = pack_hi_lo(deposit_limit_ptr as _, value.as_ptr() as _);
237		let input_data = pack_hi_lo(input.len() as _, input.as_ptr() as _);
238		let output_data = pack_hi_lo(&mut output_len as *mut _ as _, output_ptr as _);
239
240		let ret_code = unsafe {
241			sys::call(
242				flags_and_callee,
243				ref_time_limit,
244				proof_size_limit,
245				deposit_and_value,
246				input_data,
247				output_data,
248			)
249		};
250
251		if let Some(ref mut output) = output {
252			extract_from_slice(output, output_len as usize);
253		}
254
255		ret_code.into()
256	}
257
258	fn delegate_call(
259		flags: CallFlags,
260		address: &[u8; 20],
261		ref_time_limit: u64,
262		proof_size_limit: u64,
263		deposit_limit: &[u8; 32],
264		input: &[u8],
265		mut output: Option<&mut &mut [u8]>,
266	) -> Result {
267		let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output);
268		let deposit_limit_ptr = deposit_limit.as_ptr();
269
270		let flags_and_callee = pack_hi_lo(flags.bits(), address.as_ptr() as u32);
271		let input_data = pack_hi_lo(input.len() as u32, input.as_ptr() as u32);
272		let output_data = pack_hi_lo(&mut output_len as *mut _ as u32, output_ptr as u32);
273
274		let ret_code = unsafe {
275			sys::delegate_call(
276				flags_and_callee,
277				ref_time_limit,
278				proof_size_limit,
279				deposit_limit_ptr as _,
280				input_data,
281				output_data,
282			)
283		};
284
285		if let Some(ref mut output) = output {
286			extract_from_slice(output, output_len as usize);
287		}
288
289		ret_code.into()
290	}
291
292	fn deposit_event(topics: &[[u8; 32]], data: &[u8]) {
293		unsafe {
294			sys::deposit_event(
295				topics.as_ptr(),
296				topics.len() as u32,
297				data.as_ptr(),
298				data.len() as u32,
299			)
300		}
301	}
302
303	fn set_storage(flags: StorageFlags, key: &[u8], encoded_value: &[u8]) -> Option<u32> {
304		let ret_code = unsafe {
305			sys::set_storage(
306				flags.bits(),
307				key.as_ptr(),
308				key.len() as u32,
309				encoded_value.as_ptr(),
310				encoded_value.len() as u32,
311			)
312		};
313		ret_code.into()
314	}
315
316	fn get_storage(flags: StorageFlags, key: &[u8], output: &mut &mut [u8]) -> Result {
317		let mut output_len = output.len() as u32;
318		let ret_code = {
319			unsafe {
320				sys::get_storage(
321					flags.bits(),
322					key.as_ptr(),
323					key.len() as u32,
324					output.as_mut_ptr(),
325					&mut output_len,
326				)
327			}
328		};
329		extract_from_slice(output, output_len as usize);
330		ret_code.into()
331	}
332
333	fn call_data_load(out_ptr: &mut [u8; 32], offset: u32) {
334		unsafe { sys::call_data_load(out_ptr.as_mut_ptr(), offset) };
335	}
336
337	fn gas_limit() -> u64 {
338		unsafe { sys::gas_limit() }
339	}
340
341	fn call_data_size() -> u64 {
342		unsafe { sys::call_data_size() }
343	}
344
345	fn return_value(flags: ReturnFlags, return_value: &[u8]) -> ! {
346		unsafe { sys::seal_return(flags.bits(), return_value.as_ptr(), return_value.len() as u32) }
347		panic!("seal_return does not return");
348	}
349
350	fn gas_price() -> u64 {
351		unsafe { sys::gas_price() }
352	}
353
354	fn base_fee(output: &mut [u8; 32]) {
355		unsafe { sys::base_fee(output.as_mut_ptr()) }
356	}
357
358	fn balance(output: &mut [u8; 32]) {
359		unsafe { sys::balance(output.as_mut_ptr()) }
360	}
361
362	fn value_transferred(output: &mut [u8; 32]) {
363		unsafe { sys::value_transferred(output.as_mut_ptr()) }
364	}
365
366	fn now(output: &mut [u8; 32]) {
367		unsafe { sys::now(output.as_mut_ptr()) }
368	}
369
370	fn chain_id(output: &mut [u8; 32]) {
371		unsafe { sys::chain_id(output.as_mut_ptr()) }
372	}
373
374	fn address(output: &mut [u8; 20]) {
375		unsafe { sys::address(output.as_mut_ptr()) }
376	}
377
378	fn caller(output: &mut [u8; 20]) {
379		unsafe { sys::caller(output.as_mut_ptr()) }
380	}
381
382	fn origin(output: &mut [u8; 20]) {
383		unsafe { sys::origin(output.as_mut_ptr()) }
384	}
385
386	fn block_number(output: &mut [u8; 32]) {
387		unsafe { sys::block_number(output.as_mut_ptr()) }
388	}
389
390	fn block_author(output: &mut [u8; 20]) {
391		unsafe { sys::block_author(output.as_mut_ptr()) }
392	}
393
394	fn weight_to_fee(ref_time_limit: u64, proof_size_limit: u64, output: &mut [u8; 32]) {
395		unsafe { sys::weight_to_fee(ref_time_limit, proof_size_limit, output.as_mut_ptr()) };
396	}
397
398	fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]) {
399		unsafe { sys::hash_keccak_256(input.as_ptr(), input.len() as u32, output.as_mut_ptr()) }
400	}
401
402	fn get_immutable_data(output: &mut &mut [u8]) {
403		let mut output_len = output.len() as u32;
404		unsafe { sys::get_immutable_data(output.as_mut_ptr(), &mut output_len) };
405		extract_from_slice(output, output_len as usize);
406	}
407
408	fn set_immutable_data(data: &[u8]) {
409		unsafe { sys::set_immutable_data(data.as_ptr(), data.len() as u32) }
410	}
411
412	fn balance_of(address: &[u8; 20], output: &mut [u8; 32]) {
413		unsafe { sys::balance_of(address.as_ptr(), output.as_mut_ptr()) };
414	}
415
416	fn code_hash(address: &[u8; 20], output: &mut [u8; 32]) {
417		unsafe { sys::code_hash(address.as_ptr(), output.as_mut_ptr()) }
418	}
419
420	fn code_size(address: &[u8; 20]) -> u64 {
421		unsafe { sys::code_size(address.as_ptr()) }
422	}
423
424	fn return_data_size() -> u64 {
425		unsafe { sys::return_data_size() }
426	}
427
428	fn return_data_copy(output: &mut &mut [u8], offset: u32) {
429		let mut output_len = output.len() as u32;
430		{
431			unsafe { sys::return_data_copy(output.as_mut_ptr(), &mut output_len, offset) };
432		}
433		extract_from_slice(output, output_len as usize);
434	}
435
436	fn ref_time_left() -> u64 {
437		unsafe { sys::ref_time_left() }
438	}
439
440	#[unstable_hostfn]
441	fn to_account_id(address: &[u8; 20], output: &mut [u8]) {
442		unsafe { sys::to_account_id(address.as_ptr(), output.as_mut_ptr()) }
443	}
444
445	#[unstable_hostfn]
446	fn block_hash(block_number_ptr: &[u8; 32], output: &mut [u8; 32]) {
447		unsafe { sys::block_hash(block_number_ptr.as_ptr(), output.as_mut_ptr()) };
448	}
449
450	#[unstable_hostfn]
451	fn call_chain_extension(func_id: u32, input: &[u8], mut output: Option<&mut &mut [u8]>) -> u32 {
452		let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output);
453		let ret_code = {
454			unsafe {
455				sys::call_chain_extension(
456					func_id,
457					input.as_ptr(),
458					input.len() as u32,
459					output_ptr,
460					&mut output_len,
461				)
462			}
463		};
464
465		if let Some(ref mut output) = output {
466			extract_from_slice(output, output_len as usize);
467		}
468		ret_code.into_u32()
469	}
470
471	fn call_data_copy(output: &mut [u8], offset: u32) {
472		let len = output.len() as u32;
473		unsafe { sys::call_data_copy(output.as_mut_ptr(), len, offset) };
474	}
475
476	#[unstable_hostfn]
477	fn call_runtime(call: &[u8]) -> Result {
478		let ret_code = unsafe { sys::call_runtime(call.as_ptr(), call.len() as u32) };
479		ret_code.into()
480	}
481
482	#[unstable_hostfn]
483	fn caller_is_origin() -> bool {
484		let ret_val = unsafe { sys::caller_is_origin() };
485		ret_val.into_bool()
486	}
487
488	#[unstable_hostfn]
489	fn caller_is_root() -> bool {
490		let ret_val = unsafe { sys::caller_is_root() };
491		ret_val.into_bool()
492	}
493
494	#[unstable_hostfn]
495	fn clear_storage(flags: StorageFlags, key: &[u8]) -> Option<u32> {
496		let ret_code = unsafe { sys::clear_storage(flags.bits(), key.as_ptr(), key.len() as u32) };
497		ret_code.into()
498	}
499
500	#[unstable_hostfn]
501	fn contains_storage(flags: StorageFlags, key: &[u8]) -> Option<u32> {
502		let ret_code =
503			unsafe { sys::contains_storage(flags.bits(), key.as_ptr(), key.len() as u32) };
504		ret_code.into()
505	}
506
507	#[unstable_hostfn]
508	fn ecdsa_to_eth_address(pubkey: &[u8; 33], output: &mut [u8; 20]) -> Result {
509		let ret_code = unsafe { sys::ecdsa_to_eth_address(pubkey.as_ptr(), output.as_mut_ptr()) };
510		ret_code.into()
511	}
512
513	#[unstable_hostfn]
514	fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]) {
515		unsafe { sys::hash_blake2_256(input.as_ptr(), input.len() as u32, output.as_mut_ptr()) }
516	}
517
518	#[unstable_hostfn]
519	fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]) {
520		unsafe { sys::hash_blake2_128(input.as_ptr(), input.len() as u32, output.as_mut_ptr()) }
521	}
522
523	#[unstable_hostfn]
524	fn is_contract(address: &[u8; 20]) -> bool {
525		let ret_val = unsafe { sys::is_contract(address.as_ptr()) };
526		ret_val.into_bool()
527	}
528
529	#[unstable_hostfn]
530	fn minimum_balance(output: &mut [u8; 32]) {
531		unsafe { sys::minimum_balance(output.as_mut_ptr()) }
532	}
533
534	#[unstable_hostfn]
535	fn own_code_hash(output: &mut [u8; 32]) {
536		unsafe { sys::own_code_hash(output.as_mut_ptr()) }
537	}
538
539	#[unstable_hostfn]
540	fn set_code_hash(code_hash: &[u8; 32]) {
541		unsafe { sys::set_code_hash(code_hash.as_ptr()) }
542	}
543
544	#[unstable_hostfn]
545	fn sr25519_verify(signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> Result {
546		let ret_code = unsafe {
547			sys::sr25519_verify(
548				signature.as_ptr(),
549				pub_key.as_ptr(),
550				message.len() as u32,
551				message.as_ptr(),
552			)
553		};
554		ret_code.into()
555	}
556
557	#[unstable_hostfn]
558	fn take_storage(flags: StorageFlags, key: &[u8], output: &mut &mut [u8]) -> Result {
559		let mut output_len = output.len() as u32;
560		let ret_code = {
561			unsafe {
562				sys::take_storage(
563					flags.bits(),
564					key.as_ptr(),
565					key.len() as u32,
566					output.as_mut_ptr(),
567					&mut output_len,
568				)
569			}
570		};
571		extract_from_slice(output, output_len as usize);
572		ret_code.into()
573	}
574
575	#[unstable_hostfn]
576	fn terminate(beneficiary: &[u8; 20]) -> ! {
577		unsafe { sys::terminate(beneficiary.as_ptr()) }
578		panic!("terminate does not return");
579	}
580
581	#[unstable_hostfn]
582	fn weight_left(output: &mut &mut [u8]) {
583		let mut output_len = output.len() as u32;
584		unsafe { sys::weight_left(output.as_mut_ptr(), &mut output_len) }
585		extract_from_slice(output, output_len as usize)
586	}
587
588	#[unstable_hostfn]
589	fn xcm_execute(msg: &[u8]) -> Result {
590		let ret_code = unsafe { sys::xcm_execute(msg.as_ptr(), msg.len() as _) };
591		ret_code.into()
592	}
593
594	#[unstable_hostfn]
595	fn xcm_send(dest: &[u8], msg: &[u8], output: &mut [u8; 32]) -> Result {
596		let ret_code = unsafe {
597			sys::xcm_send(
598				dest.as_ptr(),
599				dest.len() as _,
600				msg.as_ptr(),
601				msg.len() as _,
602				output.as_mut_ptr(),
603			)
604		};
605		ret_code.into()
606	}
607}