pallet_revive_uapi/lib.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//! External C API to communicate with Polkadot SDK's `pallet-revive` module.
16//!
17//! Refer to the FRAME `pallet-revive` module for more documentation.
18
19#![no_std]
20#![cfg_attr(docsrs, feature(doc_cfg))]
21
22mod flags;
23pub use flags::*;
24mod host;
25mod macros;
26
27pub mod precompiles;
28pub use precompiles::{system::SYSTEM_PRECOMPILE_ADDR, utils::solidity_selector};
29
30pub use host::{HostFn, HostFnImpl};
31
32/// Convert a u64 into a [u8; 32].
33pub const fn u256_bytes(value: u64) -> [u8; 32] {
34 let mut buffer = [0u8; 32];
35 let bytes = value.to_le_bytes();
36
37 buffer[0] = bytes[0];
38 buffer[1] = bytes[1];
39 buffer[2] = bytes[2];
40 buffer[3] = bytes[3];
41 buffer[4] = bytes[4];
42 buffer[5] = bytes[5];
43 buffer[6] = bytes[6];
44 buffer[7] = bytes[7];
45 buffer
46}
47
48macro_rules! define_error_codes {
49 (
50 $(
51 $( #[$attr:meta] )*
52 $name:ident = $discr:literal,
53 )*
54 ) => {
55 /// Every error that can be returned to a contract when it calls any of the host functions.
56 #[derive(Debug, PartialEq, Eq)]
57 #[repr(u32)]
58 pub enum ReturnErrorCode {
59 /// API call successful.
60 Success = 0,
61 $(
62 $( #[$attr] )*
63 $name = $discr,
64 )*
65 /// Returns if an unknown error was received from the host module.
66 Unknown,
67 }
68
69 impl From<ReturnCode> for Result {
70 fn from(return_code: ReturnCode) -> Self {
71 match return_code.0 {
72 0 => Ok(()),
73 $(
74 $discr => Err(ReturnErrorCode::$name),
75 )*
76 _ => Err(ReturnErrorCode::Unknown),
77 }
78 }
79 }
80 };
81}
82
83impl From<ReturnErrorCode> for u32 {
84 fn from(code: ReturnErrorCode) -> u32 {
85 code as u32
86 }
87}
88
89impl From<ReturnErrorCode> for u64 {
90 fn from(error: ReturnErrorCode) -> Self {
91 u32::from(error).into()
92 }
93}
94
95define_error_codes! {
96 /// The called function trapped and has its state changes reverted.
97 /// In this case no output buffer is returned.
98 /// Can only be returned from `call` and `instantiate`.
99 CalleeTrapped = 1,
100 /// The called function ran to completion but decided to revert its state.
101 /// An output buffer is returned when one was supplied.
102 /// Can only be returned from `call` and `instantiate`.
103 CalleeReverted = 2,
104 /// The passed key does not exist in storage.
105 KeyNotFound = 3,
106 /// Transfer failed for other not further specified reason. Most probably
107 /// reserved or locked balance of the sender that was preventing the transfer.
108 TransferFailed = 4,
109 /// The subcall ran out of weight or storage deposit.
110 OutOfResources = 5,
111 /// ECDSA public key recovery failed. Most probably wrong recovery id or signature.
112 EcdsaRecoveryFailed = 7,
113 /// sr25519 signature verification failed.
114 Sr25519VerifyFailed = 8,
115 /// Contract instantiation failed because the address already exists.
116 /// Occurs when instantiating the same contract with the same salt more than once.
117 DuplicateContractAddress = 11,
118}
119
120/// The raw return code returned by the host side.
121#[repr(transparent)]
122pub struct ReturnCode(u32);
123
124/// Used as a sentinel value when reading and writing contract memory.
125///
126/// We use this value to signal `None` to a contract when only a primitive is
127/// allowed and we don't want to go through encoding a full Rust type.
128/// Using `u32::Max` is a safe sentinel because contracts are never
129/// allowed to use such a large amount of resources. So this value doesn't
130/// make sense for a memory location or length.
131const SENTINEL: u32 = u32::MAX;
132
133impl From<ReturnCode> for Option<u32> {
134 fn from(code: ReturnCode) -> Self {
135 (code.0 < SENTINEL).then_some(code.0)
136 }
137}
138
139impl ReturnCode {
140 /// Returns the raw underlying `u32` representation.
141 pub fn into_u32(self) -> u32 {
142 self.0
143 }
144 /// Returns the underlying `u32` converted into `bool`.
145 pub fn into_bool(self) -> bool {
146 self.0.ne(&0)
147 }
148}
149
150type Result = core::result::Result<(), ReturnErrorCode>;
151
152/// Helper to pack two `u32` values into a `u64` register.
153///
154/// Pointers to PVM memory are always 32 bit in size. Thus contracts can pack two
155/// pointers into a single register when calling a syscall API method.
156///
157/// This is done in syscall API methods where the number of arguments is exceeding
158/// the available registers.
159pub fn pack_hi_lo(hi: u32, lo: u32) -> u64 {
160 ((hi as u64) << 32) | lo as u64
161}