├── .cargo └── config ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── circle.yml └── src ├── bignum.rs ├── convert.rs ├── debug.rs ├── eth2.rs ├── lib.rs ├── native.rs ├── types.rs └── utils.rs /.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm_api" 3 | version = "0.11.0" 4 | authors = ["Alex Beregszaszi ", "Jake Lang "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-rust-api" 7 | description = "ewasm API for Rust" 8 | edition = "2018" 9 | 10 | [dependencies] 11 | cfg-if = "0.1.7" 12 | wee_alloc = { version = "0.4.4", optional = true } 13 | qimalloc = { version = "0.1", optional = true } 14 | 15 | [features] 16 | default = ["std", "wee_alloc"] 17 | std = [] 18 | debug = [] 19 | experimental = [] 20 | eth2 = [] 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ewasm-rust-api 2 | 3 | ![Build](https://circleci.com/gh/ewasm/ewasm-rust-api.svg?style=shield&circle-token=:circle-token) 4 | ![Version](https://img.shields.io/crates/v/ewasm-api.svg) 5 | 6 | This project aims to give a low-level and a high-level binding to ewasm from Rust. 7 | 8 | # Usage 9 | 10 | Add the dependency, as usual: 11 | ```toml 12 | [dependencies] 13 | ewasm-api = "0.11" 14 | ``` 15 | 16 | Make sure the project is a library of `cdylib` type: 17 | ```toml 18 | [lib] 19 | crate-type = ["cdylib"] 20 | ``` 21 | 22 | In your project, include the prelude: 23 | ```rust 24 | use ewasm_api::prelude::*; 25 | ``` 26 | 27 | Additionally there is support for some macros to make creating contracts easier: 28 | ```rust 29 | #[macro_use] 30 | extern crate ewasm_api; 31 | 32 | use ewasm_api::prelude::*; 33 | 34 | fn entry() { 35 | // The actual contract code goes here. 36 | } 37 | 38 | ewasm_entry_point!(entry); 39 | ``` 40 | 41 | Other modules are available as well, outside of the prelude. Refer to the documentation for more info. 42 | 43 | `ewasm-rust-api` builds with various feature sets: 44 | - `default`: Builds with `wee_alloc` as the global allocator and with the Rust standard library. 45 | - `qimalloc`: Builds with [qimalloc](https://github.com/wasmx/qimalloc) as the global allocator. 46 | - `debug`: Exposes the debugging interface. 47 | - `experimental`: Exposes the experimental bignum system library API. 48 | 49 | To enable specific features include the dependency as follows: 50 | ```toml 51 | [dependencies.ewasm_api] 52 | version = "0.11" 53 | default-features = false 54 | features = ["std", "qimalloc"] 55 | ``` 56 | Further documentation is available [here](https://docs.rs/ewasm_api/). 57 | 58 | ## Author(s) 59 | 60 | Alex Beregszaszi, Jake Lang 61 | 62 | ## License 63 | 64 | Apache 2.0 65 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | jobs: 4 | build: 5 | docker: 6 | - image: rust:1 7 | steps: 8 | - checkout 9 | - run: 10 | name: Update rustc 11 | command: | 12 | rustup target add wasm32-unknown-unknown 13 | rustup component add rustfmt 14 | rustup update 15 | - run: 16 | name: Check formatting 17 | command: | 18 | rustfmt --version 19 | cargo fmt --all -- --check 20 | - run: 21 | name: Test 22 | command: | 23 | cargo test --target=x86_64-unknown-linux-gnu 24 | cargo test --release --target=x86_64-unknown-linux-gnu 25 | - run: 26 | name: Build 27 | command: | 28 | # debug 29 | cargo build 30 | # release 31 | cargo build --release 32 | # different allocators 33 | cargo build --release --features wee_alloc 34 | cargo build --release --features qimalloc 35 | # different allocators (no_std) 36 | cargo build --release --no-default-features --features wee_alloc 37 | cargo build --release --no-default-features --features qimalloc 38 | # different feature sets 39 | cargo build --release --no-default-features 40 | cargo build --release --features debug 41 | cargo build --release --no-default-features --features debug 42 | cargo build --release --features experimental 43 | cargo build --release --no-default-features --features experimental 44 | cargo build --release --features experimental,debug 45 | cargo build --release --no-default-features --features experimental,debug 46 | cargo build --release --features eth2 47 | cargo build --release --no-default-features --features eth2 48 | -------------------------------------------------------------------------------- /src/bignum.rs: -------------------------------------------------------------------------------- 1 | //! The bignum system library. 2 | use crate::types::Uint256; 3 | 4 | /// The low-level interface to the system library. Use the wrapper functions unless you know what 5 | /// you're doing. 6 | pub mod native { 7 | extern "C" { 8 | pub fn bignum_mul256(a: *const u32, b: *const u32, ret: *const u32); 9 | pub fn bignum_umulmod256(a: *const u32, b: *const u32, modulo: *const u32, ret: *const u32); 10 | } 11 | } 12 | 13 | /// Unsigned 256-bit multiplication. 14 | pub fn mul256(a: &Uint256, b: &Uint256) -> Uint256 { 15 | let mut ret = Uint256::default(); 16 | 17 | unsafe { 18 | native::bignum_mul256( 19 | a.bytes.as_ptr() as *const u32, 20 | b.bytes.as_ptr() as *const u32, 21 | ret.bytes.as_mut_ptr() as *const u32, 22 | ) 23 | } 24 | 25 | ret 26 | } 27 | 28 | /// Unsigned 256-bit multiplication modulo n. 29 | pub fn umulmod256(a: &Uint256, b: &Uint256, modulo: &Uint256) -> Uint256 { 30 | let mut ret = Uint256::default(); 31 | 32 | unsafe { 33 | native::bignum_umulmod256( 34 | a.bytes.as_ptr() as *const u32, 35 | b.bytes.as_ptr() as *const u32, 36 | modulo.bytes.as_ptr() as *const u32, 37 | ret.bytes.as_mut_ptr() as *const u32, 38 | ) 39 | } 40 | 41 | ret 42 | } 43 | -------------------------------------------------------------------------------- /src/convert.rs: -------------------------------------------------------------------------------- 1 | //! Basic type conversion traits. Unlike the native standard library, `U: From` does not yet 2 | //! imply `T: Into`. 3 | 4 | pub trait From: Sized { 5 | fn from(_: T) -> Self; 6 | } 7 | 8 | pub trait Into: Sized { 9 | fn from(self) -> T; 10 | } 11 | -------------------------------------------------------------------------------- /src/debug.rs: -------------------------------------------------------------------------------- 1 | //! The native debug interface exposed to the ewasm contract. These functions are for testing 2 | //! purposes only. On a live VM, any bytecode trying to import these symbols will be rejected. 3 | 4 | use crate::types::StorageKey; 5 | 6 | /// The native interface for debugging functions. 7 | mod native { 8 | extern "C" { 9 | pub fn debug_print32(value: u32); 10 | pub fn debug_print64(value: u64); 11 | pub fn debug_printMem(offset: *const u32, len: u32); 12 | pub fn debug_printMemHex(offset: *const u32, len: u32); 13 | pub fn debug_printStorage(pathOffset: *const u32); 14 | pub fn debug_printStorageHex(pathOffset: *const u32); 15 | } 16 | } 17 | 18 | /// Prints a string. 19 | pub fn log(msg: &str) { 20 | unsafe { native::debug_printMem(msg.as_ptr() as *const u32, msg.len() as u32) } 21 | } 22 | 23 | /// Prints an unsigned 32-bit int. 24 | pub fn print32(value: u32) { 25 | unsafe { native::debug_print32(value) } 26 | } 27 | 28 | /// Prints an unsigned 64-bit int. 29 | pub fn print64(value: u64) { 30 | unsafe { native::debug_print64(value) } 31 | } 32 | 33 | /// Prints the contents of a slice. 34 | pub fn print_mem(slice: &[u8]) { 35 | unsafe { native::debug_printMem(slice.as_ptr() as *const u32, slice.len() as u32) } 36 | } 37 | 38 | /// Prints the contents of a slice in hexadecimal format. 39 | pub fn print_mem_hex(slice: &[u8]) { 40 | unsafe { native::debug_printMemHex(slice.as_ptr() as *const u32, slice.len() as u32) } 41 | } 42 | 43 | /// Prints the value of a storage key. 44 | pub fn print_storage(key: &StorageKey) { 45 | unsafe { native::debug_printStorage(key.bytes.as_ptr() as *const u32) } 46 | } 47 | 48 | /// Prints the value of a storage key in hexadecimal format. 49 | pub fn print_storage_hex(key: &StorageKey) { 50 | unsafe { native::debug_printStorageHex(key.bytes.as_ptr() as *const u32) } 51 | } 52 | -------------------------------------------------------------------------------- /src/eth2.rs: -------------------------------------------------------------------------------- 1 | //! This is the work in progress interface for Eth 2 Phase 2. 2 | //! 3 | //! Please check Ewasm [Scout](https://github.com/ewasm/scout) for more details. 4 | //! 5 | //! # Examples 6 | //! ``` 7 | //! use ewasm_api::prelude::*; 8 | //! 9 | //! fn process_block(pre_state_root: &Bytes32, block_data: &[u8]) -> (Bytes32, Vec) { 10 | //! unimplemented!() 11 | //! } 12 | //! 13 | //! eth2_shard_script!(process_block); 14 | //! ``` 15 | 16 | use super::*; 17 | 18 | mod native { 19 | extern "C" { 20 | pub fn eth2_loadPreStateRoot(offset: *const u32); 21 | pub fn eth2_blockDataSize() -> u32; 22 | pub fn eth2_blockDataCopy(outputOfset: *const u32, offset: u32, length: u32); 23 | pub fn eth2_savePostStateRoot(offset: *const u32); 24 | pub fn eth2_pushNewDeposit(offset: *const u32, length: u32); 25 | } 26 | } 27 | 28 | /// Load current state root. 29 | pub fn load_pre_state_root() -> Bytes32 { 30 | let mut ret = Bytes32::default(); 31 | 32 | unsafe { native::eth2_loadPreStateRoot(ret.bytes.as_mut_ptr() as *const u32) } 33 | 34 | ret 35 | } 36 | 37 | /// Returns the length of the "block data" supplied with the current block. 38 | pub fn block_data_size() -> usize { 39 | unsafe { native::eth2_blockDataSize() as usize } 40 | } 41 | 42 | /// Copies a slices from the "block data", but does not check for overflow. 43 | pub fn unsafe_block_data_copy(from: usize, length: usize, ret: &mut [u8]) { 44 | unsafe { 45 | native::eth2_blockDataCopy(ret.as_mut_ptr() as *const u32, from as u32, length as u32); 46 | } 47 | } 48 | 49 | #[cfg(feature = "std")] 50 | /// Returns a vector containing the entire "block data". 51 | pub fn acquire_block_data() -> Vec { 52 | let length = block_data_size(); 53 | 54 | let mut ret: Vec = unsafe_alloc_buffer(length); 55 | unsafe_block_data_copy(0, length, &mut ret); 56 | ret 57 | } 58 | 59 | /// Returns the segment of "block data" beginning at `from`, and continuing for `length` bytes. 60 | pub fn block_data_copy(from: usize, length: usize, ret: &mut [u8]) -> Result<(), Error> { 61 | let size = block_data_size(); 62 | 63 | if (size < from) || ((size - from) < length) || (ret.len() < length) { 64 | Err(Error::OutOfBoundsCopy) 65 | } else { 66 | unsafe_block_data_copy(from, length, ret); 67 | Ok(()) 68 | } 69 | } 70 | 71 | /// Push new deposit receipt. 72 | pub fn push_new_deposit(deposit: &[u8]) { 73 | unsafe { native::eth2_pushNewDeposit(deposit.as_ptr() as *const u32, deposit.len() as u32) } 74 | } 75 | 76 | /// Save new state root. 77 | pub fn save_post_state_root(state: &Bytes32) { 78 | unsafe { native::eth2_savePostStateRoot(state.bytes.as_ptr() as *const u32) } 79 | } 80 | 81 | /// Create shard script entry point. Expects a function to process blocks with the signature: 82 | /// ```ignore 83 | /// fn process_block(pre_state_root: &Bytes32, block_data: &[u8]) -> (Bytes32, Vec) {} 84 | /// ``` 85 | #[macro_export] 86 | macro_rules! eth2_shard_script { 87 | ($process_block:ident) => { 88 | #[cfg(target_arch = "wasm32")] 89 | #[no_mangle] 90 | pub extern "C" fn main() { 91 | let pre_state_root = eth2::load_pre_state_root(); 92 | // TODO: avoid using Vec here 93 | let block_data = eth2::acquire_block_data(); 94 | let (post_state_root, deposits) = $process_block(&pre_state_root, &block_data); 95 | eth2::push_new_deposit(&deposits); 96 | eth2::save_post_state_root(&post_state_root) 97 | } 98 | }; 99 | } 100 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! ewasm_api is a library used to interface with Ethereum's EEI in [Ewasm](https://github.com/ewasm/design), a set of enhancements to 2 | //! the Ethereum smart contract platform. 3 | //! ewasm_api exposes both a set of unsafe "native" functions representing the actual EEI 4 | //! functions, and a set of safe wrappers around them. It is recommended not to use the native 5 | //! functions as they do not perform bounds-checking. 6 | //! 7 | //! To use ewasm_api, simply include it as a dependency in your project. 8 | //! ewasm_api can be built with various feature sets: 9 | //! - `default`: Builds with `wee_alloc` as the global allocator and with the Rust standard 10 | //! library. 11 | //! - `qimalloc`: Builds with [qimalloc](https://github.com/wasmx/qimalloc) as the global 12 | //! allocator. 13 | //! - `debug`: Exposes the debugging interface. 14 | //! - `experimental`: Exposes the experimental bignum system library API. 15 | //! 16 | //! # Examples 17 | //! ``` 18 | //! use ewasm_api::prelude::*; 19 | //! 20 | //! fn entry() { 21 | //! let a: Hash = block_hash(1); 22 | //! finish_data(&a.bytes); 23 | //! } 24 | //! 25 | //! ewasm_entry_point!(entry); 26 | //! ``` 27 | //! 28 | //! Using lower-level primitives: 29 | //! ```ignore 30 | //! use ewasm_api::{types::Hash, block_hash, finish_data}; 31 | //! 32 | //! #[cfg(target_arch = "wasm32")] 33 | //! #[no_mangle] 34 | //! pub extern "C" fn main() { 35 | //! let a: types::Hash = block_hash(1); 36 | //! finish_data(&a.bytes); 37 | //! } 38 | //! ``` 39 | //! 40 | 41 | #[macro_use] 42 | extern crate cfg_if; 43 | 44 | cfg_if! { 45 | if #[cfg(feature = "wee_alloc")] { 46 | extern crate wee_alloc; 47 | #[global_allocator] 48 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; 49 | } else if #[cfg(feature = "qimalloc")] { 50 | extern crate qimalloc; 51 | #[global_allocator] 52 | static ALLOC: qimalloc::QIMalloc = qimalloc::QIMalloc::INIT; 53 | } 54 | } 55 | 56 | mod native; 57 | mod utils; 58 | 59 | pub mod types; 60 | 61 | #[cfg(feature = "debug")] 62 | pub mod debug; 63 | 64 | #[cfg(feature = "experimental")] 65 | pub mod bignum; 66 | 67 | #[cfg(feature = "eth2")] 68 | pub mod eth2; 69 | 70 | #[cfg(not(feature = "std"))] 71 | pub mod convert; 72 | 73 | #[cfg(feature = "std")] 74 | use std::vec::Vec; 75 | 76 | use types::*; 77 | #[cfg(feature = "std")] 78 | use utils::*; 79 | 80 | /// Re-export of all the basic features. 81 | pub mod prelude { 82 | pub use crate::*; 83 | 84 | pub use crate::types::*; 85 | 86 | #[cfg(not(feature = "std"))] 87 | pub use crate::convert::*; 88 | 89 | #[cfg(feature = "debug")] 90 | pub use crate::debug; 91 | 92 | #[cfg(feature = "experimental")] 93 | pub use crate::bignum; 94 | 95 | #[cfg(feature = "eth2")] 96 | pub use crate::eth2; 97 | } 98 | 99 | /// Declare entry point for a contract. Expects a Rust function name to be executed. 100 | /// This will only compile in when using the wasm32 target. 101 | #[macro_export] 102 | macro_rules! ewasm_entry_point { 103 | ($name:ident) => { 104 | #[cfg(target_arch = "wasm32")] 105 | #[no_mangle] 106 | pub extern "C" fn main() { 107 | $name() 108 | } 109 | }; 110 | } 111 | 112 | /// Enum representing an error code for EEI calls. Currently used by `codeCopy`, `callDataCopy`, 113 | /// `externalCodeCopy`, and `returnDataCopy`. 114 | pub enum Error { 115 | OutOfBoundsCopy, 116 | } 117 | 118 | /// Enum describing the result of a call. Used by `call`, `callCode`, `callDelegate`, and 119 | /// `callStatic`. 120 | pub enum CallResult { 121 | Successful, 122 | Failure, 123 | Revert, 124 | Unknown, 125 | } 126 | 127 | /// Enum describing the result of `create`. On success, the data contained is the address of the 128 | /// newly created contract. 129 | pub enum CreateResult { 130 | Successful(Address), 131 | Failure, 132 | Revert, 133 | Unknown, 134 | } 135 | 136 | /// Subtracts the given amount from the VM's gas counter. This is usually injected by the metering 137 | /// contract at deployment time, and hence is unneeded in most cases. 138 | pub fn consume_gas(amount: u64) { 139 | unsafe { 140 | native::ethereum_useGas(amount); 141 | } 142 | } 143 | 144 | /// Returns the gas left in the current call. 145 | pub fn gas_left() -> u64 { 146 | unsafe { native::ethereum_getGasLeft() } 147 | } 148 | 149 | /// Returns the executing address. 150 | pub fn current_address() -> Address { 151 | let mut ret = Address::default(); 152 | 153 | unsafe { 154 | native::ethereum_getAddress(ret.bytes.as_mut_ptr() as *const u32); 155 | } 156 | 157 | ret 158 | } 159 | 160 | /// Returns the balance of the address given. 161 | pub fn external_balance(address: &Address) -> EtherValue { 162 | let mut ret = EtherValue::default(); 163 | 164 | unsafe { 165 | native::ethereum_getExternalBalance( 166 | address.bytes.as_ptr() as *const u32, 167 | ret.bytes.as_mut_ptr() as *const u32, 168 | ); 169 | } 170 | 171 | ret 172 | } 173 | 174 | /// Returns the beneficiary address for the block this transaction is in (current block) 175 | pub fn block_coinbase() -> Address { 176 | let mut ret = Address::default(); 177 | 178 | unsafe { 179 | native::ethereum_getBlockCoinbase(ret.bytes.as_mut_ptr() as *const u32); 180 | } 181 | 182 | ret 183 | } 184 | 185 | /// Returns the difficulty of the most recent block. 186 | pub fn block_difficulty() -> Difficulty { 187 | let mut ret = Difficulty::default(); 188 | 189 | unsafe { 190 | native::ethereum_getBlockDifficulty(ret.bytes.as_mut_ptr() as *const u32); 191 | } 192 | 193 | ret 194 | } 195 | 196 | /// Returns the gas limit of the most recent block. 197 | pub fn block_gas_limit() -> u64 { 198 | unsafe { native::ethereum_getBlockGasLimit() } 199 | } 200 | 201 | /// Returns the hash of the `number`th most recent block. 202 | pub fn block_hash(number: u64) -> Hash { 203 | let mut ret = Hash::default(); 204 | 205 | unsafe { 206 | native::ethereum_getBlockHash(number, ret.bytes.as_mut_ptr() as *const u32); 207 | } 208 | 209 | ret 210 | } 211 | 212 | /// Returns the number of the most recent block. 213 | pub fn block_number() -> u64 { 214 | unsafe { native::ethereum_getBlockNumber() } 215 | } 216 | 217 | /// Returns the timestamp of the most recent block. 218 | pub fn block_timestamp() -> u64 { 219 | unsafe { native::ethereum_getBlockTimestamp() } 220 | } 221 | 222 | /// Returns the gas price of the currently executing call. 223 | pub fn tx_gas_price() -> EtherValue { 224 | let mut ret = EtherValue::default(); 225 | 226 | unsafe { 227 | native::ethereum_getTxGasPrice(ret.bytes.as_mut_ptr() as *const u32); 228 | } 229 | 230 | ret 231 | } 232 | 233 | /// Returns the address of the original transaction sender. 234 | pub fn tx_origin() -> Address { 235 | let mut ret = Address::default(); 236 | 237 | unsafe { 238 | native::ethereum_getTxOrigin(ret.bytes.as_mut_ptr() as *const u32); 239 | } 240 | 241 | ret 242 | } 243 | 244 | /// Appends log data to the transaction receipt, with a variable number of topics. 245 | fn log( 246 | data: &[u8], 247 | topic_count: usize, 248 | topic1: *const u8, 249 | topic2: *const u8, 250 | topic3: *const u8, 251 | topic4: *const u8, 252 | ) { 253 | unsafe { 254 | native::ethereum_log( 255 | data.as_ptr() as *const u32, 256 | data.len() as u32, 257 | topic_count as u32, 258 | topic1 as *const u32, 259 | topic2 as *const u32, 260 | topic3 as *const u32, 261 | topic4 as *const u32, 262 | ); 263 | } 264 | } 265 | 266 | /// Appends log data without a topic. 267 | pub fn log0(data: &[u8]) { 268 | log( 269 | data, 270 | 0, 271 | 0 as *const u8, 272 | 0 as *const u8, 273 | 0 as *const u8, 274 | 0 as *const u8, 275 | ) 276 | } 277 | 278 | /// Appends log data with one topic. 279 | pub fn log1(data: &[u8], topic1: &LogTopic) { 280 | log( 281 | data, 282 | 1, 283 | topic1.bytes.as_ptr() as *const u8, 284 | 0 as *const u8, 285 | 0 as *const u8, 286 | 0 as *const u8, 287 | ) 288 | } 289 | 290 | /// Appends log data with two topics. 291 | pub fn log2(data: &[u8], topic1: &LogTopic, topic2: &LogTopic) { 292 | log( 293 | data, 294 | 2, 295 | topic1.bytes.as_ptr() as *const u8, 296 | topic2.bytes.as_ptr() as *const u8, 297 | 0 as *const u8, 298 | 0 as *const u8, 299 | ) 300 | } 301 | 302 | /// Appends log data with three topics. 303 | pub fn log3(data: &[u8], topic1: &LogTopic, topic2: &LogTopic, topic3: &LogTopic) { 304 | log( 305 | data, 306 | 3, 307 | topic1.bytes.as_ptr() as *const u8, 308 | topic2.bytes.as_ptr() as *const u8, 309 | topic3.bytes.as_ptr() as *const u8, 310 | 0 as *const u8, 311 | ) 312 | } 313 | 314 | /// Appends log data with four topics. 315 | pub fn log4( 316 | data: &[u8], 317 | topic1: &LogTopic, 318 | topic2: &LogTopic, 319 | topic3: &LogTopic, 320 | topic4: &LogTopic, 321 | ) { 322 | log( 323 | data, 324 | 4, 325 | topic1.bytes.as_ptr() as *const u8, 326 | topic2.bytes.as_ptr() as *const u8, 327 | topic3.bytes.as_ptr() as *const u8, 328 | topic4.bytes.as_ptr() as *const u8, 329 | ) 330 | } 331 | 332 | /// Executes a standard call to the specified address with the given gas limit, ether value, and 333 | /// data. 334 | pub fn call_mutable( 335 | gas_limit: u64, 336 | address: &Address, 337 | value: &EtherValue, 338 | data: &[u8], 339 | ) -> CallResult { 340 | let ret = unsafe { 341 | native::ethereum_call( 342 | gas_limit, 343 | address.bytes.as_ptr() as *const u32, 344 | value.bytes.as_ptr() as *const u32, 345 | data.as_ptr() as *const u32, 346 | data.len() as u32, 347 | ) 348 | }; 349 | 350 | match ret { 351 | 0 => CallResult::Successful, 352 | 1 => CallResult::Failure, 353 | 2 => CallResult::Revert, 354 | _ => CallResult::Unknown, 355 | } 356 | } 357 | 358 | /// Executes another account's code in the context of the caller. 359 | pub fn call_code(gas_limit: u64, address: &Address, value: &EtherValue, data: &[u8]) -> CallResult { 360 | let ret = unsafe { 361 | native::ethereum_callCode( 362 | gas_limit, 363 | address.bytes.as_ptr() as *const u32, 364 | value.bytes.as_ptr() as *const u32, 365 | data.as_ptr() as *const u32, 366 | data.len() as u32, 367 | ) 368 | }; 369 | 370 | match ret { 371 | 0 => CallResult::Successful, 372 | 1 => CallResult::Failure, 373 | 2 => CallResult::Revert, 374 | _ => CallResult::Unknown, 375 | } 376 | } 377 | 378 | /// Executes a call similar to `call_code`, but retaining the currently executing call's sender 379 | /// and value. 380 | pub fn call_delegate(gas_limit: u64, address: &Address, data: &[u8]) -> CallResult { 381 | let ret = unsafe { 382 | native::ethereum_callDelegate( 383 | gas_limit, 384 | address.bytes.as_ptr() as *const u32, 385 | data.as_ptr() as *const u32, 386 | data.len() as u32, 387 | ) 388 | }; 389 | 390 | match ret { 391 | 0 => CallResult::Successful, 392 | 1 => CallResult::Failure, 393 | 2 => CallResult::Revert, 394 | _ => CallResult::Unknown, 395 | } 396 | } 397 | 398 | /// Executes a static call which cannot mutate the state. 399 | pub fn call_static(gas_limit: u64, address: &Address, data: &[u8]) -> CallResult { 400 | let ret = unsafe { 401 | native::ethereum_callStatic( 402 | gas_limit, 403 | address.bytes.as_ptr() as *const u32, 404 | data.as_ptr() as *const u32, 405 | data.len() as u32, 406 | ) 407 | }; 408 | 409 | match ret { 410 | 0 => CallResult::Successful, 411 | 1 => CallResult::Failure, 412 | 2 => CallResult::Revert, 413 | _ => CallResult::Unknown, 414 | } 415 | } 416 | 417 | /// Creates a contract with the the given code, sending the specified ether value to its address. 418 | pub fn create(value: &EtherValue, data: &[u8]) -> CreateResult { 419 | let mut address = Address::default(); 420 | 421 | let ret = unsafe { 422 | native::ethereum_create( 423 | value.bytes.as_ptr() as *const u32, 424 | data.as_ptr() as *const u32, 425 | data.len() as u32, 426 | address.bytes.as_mut_ptr() as *const u32, 427 | ) 428 | }; 429 | 430 | match ret { 431 | 0 => CreateResult::Successful(address), 432 | 1 => CreateResult::Failure, 433 | 2 => CreateResult::Revert, 434 | _ => CreateResult::Unknown, 435 | } 436 | } 437 | 438 | /// Executes callDataCopy, but does not check for overflow. 439 | pub fn unsafe_calldata_copy(from: usize, length: usize, ret: &mut [u8]) { 440 | unsafe { 441 | native::ethereum_callDataCopy(ret.as_mut_ptr() as *const u32, from as u32, length as u32); 442 | } 443 | } 444 | 445 | #[cfg(feature = "std")] 446 | /// Returns a vector containing all data passed with the currently executing call. 447 | pub fn calldata_acquire() -> Vec { 448 | let length = calldata_size(); 449 | 450 | let mut ret: Vec = unsafe_alloc_buffer(length); 451 | unsafe_calldata_copy(0, length, &mut ret); 452 | ret 453 | } 454 | 455 | /// Returns the segment of call data beginning at `from`, and continuing for `length` bytes. 456 | pub fn calldata_copy(from: usize, length: usize, ret: &mut [u8]) -> Result<(), Error> { 457 | let size = calldata_size(); 458 | 459 | if (size < from) || ((size - from) < length) || (ret.len() < length) { 460 | Err(Error::OutOfBoundsCopy) 461 | } else { 462 | unsafe_calldata_copy(from, length, ret); 463 | Ok(()) 464 | } 465 | } 466 | 467 | /// Returns the length of the call data supplied with the currently executing call. 468 | pub fn calldata_size() -> usize { 469 | unsafe { native::ethereum_getCallDataSize() as usize } 470 | } 471 | 472 | /// Returns the sender of the currently executing call. 473 | pub fn caller() -> Address { 474 | let mut ret = Address::default(); 475 | 476 | unsafe { 477 | native::ethereum_getCaller(ret.bytes.as_mut_ptr() as *const u32); 478 | } 479 | 480 | ret 481 | } 482 | 483 | /// Returns the value sent with the currently executing call. 484 | pub fn callvalue() -> EtherValue { 485 | let mut ret = EtherValue::default(); 486 | 487 | unsafe { 488 | native::ethereum_getCallValue(ret.bytes.as_mut_ptr() as *const u32); 489 | } 490 | 491 | ret 492 | } 493 | 494 | /// Executes codeCopy, but does not check for overflow. 495 | pub fn unsafe_code_copy(from: usize, length: usize, ret: &mut [u8]) { 496 | unsafe { 497 | native::ethereum_codeCopy(ret.as_mut_ptr() as *const u32, from as u32, length as u32); 498 | } 499 | } 500 | 501 | #[cfg(feature = "std")] 502 | /// Returns the currently executing code. 503 | pub fn code_acquire() -> Vec { 504 | let length = code_size(); 505 | 506 | let mut ret: Vec = unsafe_alloc_buffer(length); 507 | unsafe_code_copy(0, length, &mut ret); 508 | ret 509 | } 510 | 511 | /// Copies the segment of running code beginning at `from` and continuing for `length` bytes. 512 | pub fn code_copy(from: usize, length: usize, ret: &mut [u8]) -> Result<(), Error> { 513 | let size = code_size(); 514 | 515 | if (size < from) || ((size - from) < length) || (ret.len() < length) { 516 | Err(Error::OutOfBoundsCopy) 517 | } else { 518 | unsafe_code_copy(from, length, ret); 519 | Ok(()) 520 | } 521 | } 522 | 523 | /// Returns the size of the currently executing code. 524 | pub fn code_size() -> usize { 525 | unsafe { native::ethereum_getCodeSize() as usize } 526 | } 527 | 528 | /// Executes externalCodeCopy, but does not check for overflow. 529 | pub fn unsafe_external_code_copy(address: &Address, from: usize, length: usize, ret: &mut [u8]) { 530 | unsafe { 531 | native::ethereum_externalCodeCopy( 532 | address.bytes.as_ptr() as *const u32, 533 | ret.as_mut_ptr() as *const u32, 534 | from as u32, 535 | length as u32, 536 | ); 537 | } 538 | } 539 | 540 | #[cfg(feature = "std")] 541 | /// Returns the code at the specified address. 542 | pub fn external_code_acquire(address: &Address) -> Vec { 543 | let length = external_code_size(address); 544 | 545 | let mut ret: Vec = unsafe_alloc_buffer(length); 546 | unsafe_external_code_copy(address, 0, length, &mut ret); 547 | ret 548 | } 549 | 550 | /// Returns the segment of code at `address` beginning at `from` and continuing for `length` bytes. 551 | pub fn external_code_copy( 552 | address: &Address, 553 | from: usize, 554 | length: usize, 555 | ret: &mut [u8], 556 | ) -> Result<(), Error> { 557 | let size = external_code_size(address); 558 | 559 | if (size < from) || ((size - from) < length) || (ret.len() < length) { 560 | Err(Error::OutOfBoundsCopy) 561 | } else { 562 | unsafe_external_code_copy(address, from, length, ret); 563 | Ok(()) 564 | } 565 | } 566 | 567 | /// Returns the size of the code at the specified address. 568 | pub fn external_code_size(address: &Address) -> usize { 569 | unsafe { native::ethereum_getExternalCodeSize(address.bytes.as_ptr() as *const u32) as usize } 570 | } 571 | 572 | /// Executes returnDataCopy, but does not check for overflow. 573 | pub fn unsafe_returndata_copy(from: usize, length: usize, ret: &mut [u8]) { 574 | unsafe { 575 | native::ethereum_returnDataCopy(ret.as_mut_ptr() as *const u32, from as u32, length as u32); 576 | } 577 | } 578 | 579 | #[cfg(feature = "std")] 580 | /// Returns the data in the VM's return buffer. 581 | pub fn returndata_acquire() -> Vec { 582 | let length = returndata_size(); 583 | 584 | let mut ret: Vec = unsafe_alloc_buffer(length); 585 | unsafe_returndata_copy(0, length, &mut ret); 586 | ret 587 | } 588 | 589 | /// Returns the segment of return buffer data beginning at `from` and continuing for `length` bytes. 590 | pub fn returndata_copy(from: usize, length: usize, ret: &mut [u8]) -> Result<(), Error> { 591 | let size = returndata_size(); 592 | 593 | if (size < from) || ((size - from) < length) || (ret.len() < length) { 594 | Err(Error::OutOfBoundsCopy) 595 | } else { 596 | unsafe_returndata_copy(from, length, ret); 597 | Ok(()) 598 | } 599 | } 600 | 601 | /// Returns the length of the data in the VM's return buffer. 602 | pub fn returndata_size() -> usize { 603 | unsafe { native::ethereum_getReturnDataSize() as usize } 604 | } 605 | 606 | /// Halts execution, reverts all changes to the state and consumes all gas. 607 | pub fn abort() -> ! { 608 | // TODO: use assembly block with `unreachable` 609 | panic!() 610 | } 611 | 612 | /// Halts execution and reverts all changes to the state. 613 | pub fn revert() -> ! { 614 | unsafe { 615 | native::ethereum_revert(0 as *const u32, 0 as u32); 616 | } 617 | } 618 | 619 | /// Fills the return buffer with the given data and halts execution, reverting all state changes. 620 | pub fn revert_data(data: &[u8]) -> ! { 621 | unsafe { 622 | native::ethereum_revert(data.as_ptr() as *const u32, data.len() as u32); 623 | } 624 | } 625 | 626 | /// Ends execution, signalling success. 627 | pub fn finish() -> ! { 628 | unsafe { 629 | native::ethereum_finish(0 as *const u32, 0 as u32); 630 | } 631 | } 632 | 633 | /// Fills the return buffer with the given data and halts execution, signalling success. 634 | pub fn finish_data(data: &[u8]) -> ! { 635 | unsafe { 636 | native::ethereum_finish(data.as_ptr() as *const u32, data.len() as u32); 637 | } 638 | } 639 | 640 | /// Accesses the storage data at the specified key. 641 | pub fn storage_load(key: &StorageKey) -> StorageValue { 642 | let mut ret = StorageValue::default(); 643 | 644 | unsafe { 645 | native::ethereum_storageLoad( 646 | key.bytes.as_ptr() as *const u32, 647 | ret.bytes.as_mut_ptr() as *const u32, 648 | ); 649 | } 650 | 651 | ret 652 | } 653 | 654 | /// Sets the storage data at the specified key. 655 | pub fn storage_store(key: &StorageKey, value: &StorageValue) { 656 | unsafe { 657 | native::ethereum_storageStore( 658 | key.bytes.as_ptr() as *const u32, 659 | value.bytes.as_ptr() as *const u32, 660 | ); 661 | } 662 | } 663 | 664 | /// Self-destructs the running contract, sending all its ether to a specified beneficiary address. 665 | pub fn selfdestruct(address: &Address) -> ! { 666 | unsafe { 667 | native::ethereum_selfDestruct(address.bytes.as_ptr() as *const u32); 668 | } 669 | } 670 | -------------------------------------------------------------------------------- /src/native.rs: -------------------------------------------------------------------------------- 1 | //! The low-level bindings for the Ethereum Environment Interface (EEI). There is a safe set of wrappers for these functions, so use 2 | //! those unless you are certain you know what you're doing. 3 | 4 | extern "C" { 5 | pub fn ethereum_useGas(amount: u64); 6 | pub fn ethereum_getGasLeft() -> u64; 7 | pub fn ethereum_getAddress(resultOffset: *const u32); 8 | pub fn ethereum_getExternalBalance(addressOffset: *const u32, resultOffset: *const u32); 9 | pub fn ethereum_getBlockCoinbase(resultOffset: *const u32); 10 | pub fn ethereum_getBlockDifficulty(resultOffset: *const u32); 11 | pub fn ethereum_getBlockGasLimit() -> u64; 12 | pub fn ethereum_getBlockHash(number: u64, resultOffset: *const u32) -> u32; 13 | pub fn ethereum_getBlockNumber() -> u64; 14 | pub fn ethereum_getBlockTimestamp() -> u64; 15 | pub fn ethereum_getTxGasPrice(valueOffset: *const u32); 16 | pub fn ethereum_getTxOrigin(resultOffset: *const u32); 17 | pub fn ethereum_log( 18 | dataOffset: *const u32, 19 | length: u32, 20 | numberOfTopics: u32, 21 | topic1: *const u32, 22 | topic2: *const u32, 23 | topic3: *const u32, 24 | topic4: *const u32, 25 | ); 26 | pub fn ethereum_call( 27 | gas: u64, 28 | addressOffset: *const u32, 29 | valueOffset: *const u32, 30 | dataOffset: *const u32, 31 | dataLength: u32, 32 | ) -> u32; 33 | pub fn ethereum_callCode( 34 | gas: u64, 35 | addressOffset: *const u32, 36 | valueOffset: *const u32, 37 | dataOffset: *const u32, 38 | dataLength: u32, 39 | ) -> u32; 40 | pub fn ethereum_callDelegate( 41 | gas: u64, 42 | addressOffset: *const u32, 43 | dataOffset: *const u32, 44 | dataLength: u32, 45 | ) -> u32; 46 | pub fn ethereum_callStatic( 47 | gas: u64, 48 | addressOffset: *const u32, 49 | dataOffset: *const u32, 50 | dataLength: u32, 51 | ) -> u32; 52 | pub fn ethereum_create( 53 | valueOffset: *const u32, 54 | dataOffset: *const u32, 55 | dataLength: u32, 56 | resultOffset: *const u32, 57 | ) -> u32; 58 | pub fn ethereum_returnDataCopy(resultOffset: *const u32, dataOffset: u32, length: u32); 59 | pub fn ethereum_getReturnDataSize() -> u32; 60 | pub fn ethereum_finish(dataOffset: *const u32, length: u32) -> !; 61 | pub fn ethereum_revert(dataOffset: *const u32, length: u32) -> !; 62 | pub fn ethereum_callDataCopy(resultOffset: *const u32, dataOffset: u32, length: u32); 63 | pub fn ethereum_getCallDataSize() -> u32; 64 | pub fn ethereum_getCaller(resultOffset: *const u32); 65 | pub fn ethereum_getCallValue(resultOffset: *const u32); 66 | pub fn ethereum_codeCopy(resultOffset: *const u32, codeOffset: u32, length: u32); 67 | pub fn ethereum_getCodeSize() -> u32; 68 | pub fn ethereum_externalCodeCopy( 69 | addressOffset: *const u32, 70 | resultOffset: *const u32, 71 | codeOffset: u32, 72 | length: u32, 73 | ); 74 | pub fn ethereum_getExternalCodeSize(addressOfset: *const u32) -> u32; 75 | pub fn ethereum_storageLoad(keyOffset: *const u32, resultOffset: *const u32); 76 | pub fn ethereum_storageStore(keyOffset: *const u32, valueOffset: *const u32); 77 | pub fn ethereum_selfDestruct(addressOffset: *const u32) -> !; 78 | } 79 | -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | //! High-level types commonly used in Ethereum contracts. 2 | 3 | /// A little-endian unsigned 128-bit integer. 4 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 5 | pub struct Uint128 { 6 | pub bytes: [u8; 16], 7 | } 8 | 9 | /// A little-endian unsigned 256-bit integer. 10 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 11 | pub struct Uint256 { 12 | pub bytes: [u8; 32], 13 | } 14 | 15 | /// An array of 160 bits. 16 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 17 | pub struct Bytes20 { 18 | pub bytes: [u8; 20], 19 | } 20 | 21 | /// An array of 256 bits. 22 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 23 | pub struct Bytes32 { 24 | pub bytes: [u8; 32], 25 | } 26 | 27 | /// Type definition representing a value in wei. 28 | pub type EtherValue = Uint128; 29 | 30 | /// Type definition representing an address. 31 | pub type Address = Bytes20; 32 | 33 | /// Type definition representing a storage key. 34 | pub type StorageKey = Bytes32; 35 | 36 | /// Type definition representing a storage value. 37 | pub type StorageValue = Bytes32; 38 | 39 | /// Type definition representing a log topic. 40 | pub type LogTopic = Bytes32; 41 | 42 | /// Type definition representing a Keccak-256 or SHA-256 hash. 43 | pub type Hash = Bytes32; 44 | 45 | /// Type definition representing a block's difficulty. 46 | pub type Difficulty = Uint256; 47 | 48 | macro_rules! from_primitive_impl { 49 | ($f:ident, $size:expr, $to:ident) => { 50 | impl From<[$f; $size]> for $to { 51 | fn from(a: [$f; $size]) -> Self { 52 | $to { bytes: a } 53 | } 54 | } 55 | }; 56 | } 57 | 58 | macro_rules! from_primitive_ref_impl { 59 | ($f:ident, $size:expr, $to:ident) => { 60 | impl From<&[$f; $size]> for $to { 61 | fn from(a: &[$f; $size]) -> Self { 62 | $to { bytes: a.clone() } 63 | } 64 | } 65 | }; 66 | } 67 | 68 | macro_rules! from_type_for_primitive_impl { 69 | ($f:ident, $size:expr, $to:ident) => { 70 | impl From<$f> for [$to; $size] { 71 | fn from(a: $f) -> Self { 72 | a.bytes 73 | } 74 | } 75 | }; 76 | } 77 | 78 | from_primitive_impl!(u8, 16, Uint128); 79 | from_primitive_impl!(u8, 32, Uint256); 80 | from_primitive_impl!(u8, 20, Bytes20); 81 | from_primitive_impl!(u8, 32, Bytes32); 82 | 83 | from_primitive_ref_impl!(u8, 16, Uint128); 84 | from_primitive_ref_impl!(u8, 32, Uint256); 85 | from_primitive_ref_impl!(u8, 20, Bytes20); 86 | from_primitive_ref_impl!(u8, 32, Bytes32); 87 | 88 | from_type_for_primitive_impl!(Uint128, 16, u8); 89 | from_type_for_primitive_impl!(Uint256, 32, u8); 90 | from_type_for_primitive_impl!(Bytes20, 20, u8); 91 | from_type_for_primitive_impl!(Bytes32, 32, u8); 92 | 93 | #[cfg(test)] 94 | mod tests { 95 | use super::{Bytes20, Bytes32, Uint128, Uint256}; 96 | 97 | macro_rules! test_conversions { 98 | ($type: ident, $size: expr, $test_name: ident) => { 99 | #[test] 100 | fn $test_name() { 101 | let raw = [1; $size]; 102 | 103 | let uint = $type::from(raw); 104 | assert_eq!(uint.bytes[$size - 1], 1); 105 | let uint = $type::from(&raw); 106 | assert_eq!(uint.bytes[$size - 1], 1); 107 | 108 | let uint: $type = raw.into(); 109 | assert_eq!(uint.bytes[$size - 1], 1); 110 | let uint: $type = (&raw).into(); 111 | assert_eq!(uint.bytes[$size - 1], 1); 112 | 113 | let r: [u8; $size] = uint.into(); 114 | assert_eq!(r[$size - 1], 1); 115 | } 116 | }; 117 | } 118 | 119 | test_conversions!(Uint128, 16, test_uint128); 120 | test_conversions!(Uint256, 32, test_uint256); 121 | test_conversions!(Bytes20, 20, test_bytes20); 122 | test_conversions!(Bytes32, 32, test_bytes32); 123 | } 124 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | //! General utility functions. 2 | 3 | /// Allocate an owned buffer using the global allocator. 4 | /// Only enabled with `std`. 5 | #[cfg(feature = "std")] 6 | pub fn unsafe_alloc_buffer(len: usize) -> Vec { 7 | let mut ret: Vec = Vec::with_capacity(len); 8 | unsafe { 9 | ret.set_len(len); 10 | } 11 | ret 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use super::*; 17 | 18 | #[test] 19 | fn smoke() { 20 | let ret = unsafe_alloc_buffer(42); 21 | assert_eq!(ret.len(), 42); 22 | } 23 | } 24 | --------------------------------------------------------------------------------