| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284 |
- // Create WASM virtual machine like substrate
- use num_derive::FromPrimitive;
- use num_traits::FromPrimitive;
- use rand::Rng;
- use sha2::{Digest, Sha256};
- use std::{collections::HashMap, ffi::OsStr, fmt};
- use tiny_keccak::{Hasher, Keccak};
- use wasmi::memory_units::Pages;
- use wasmi::*;
- use solang::abi;
- use solang::file_resolver::FileResolver;
- use solang::{compile, Target};
- mod substrate_tests;
- type StorageKey = [u8; 32];
- type Account = [u8; 32];
- fn account_new() -> Account {
- let mut rng = rand::thread_rng();
- let mut a = [0u8; 32];
- rng.fill(&mut a[..]);
- a
- }
- #[derive(Debug, Clone, PartialEq)]
- struct HostCodeTerminate {}
- impl HostError for HostCodeTerminate {}
- impl fmt::Display for HostCodeTerminate {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(f, "seal_terminate")
- }
- }
- #[derive(Debug, Clone, PartialEq)]
- struct HostCodeReturn(i32);
- impl fmt::Display for HostCodeReturn {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(f, "return {}", self.0)
- }
- }
- impl HostError for HostCodeReturn {}
- #[derive(FromPrimitive)]
- #[allow(non_camel_case_types)]
- enum SubstrateExternal {
- seal_input = 0,
- seal_set_storage,
- seal_clear_storage,
- seal_get_storage,
- seal_return,
- seal_hash_keccak_256,
- seal_println,
- seal_call,
- seal_instantiate,
- seal_value_transferred,
- seal_minimum_balance,
- seal_random,
- seal_address,
- seal_balance,
- seal_terminate,
- seal_hash_sha2_256,
- seal_hash_blake2_128,
- seal_hash_blake2_256,
- seal_block_number,
- seal_now,
- seal_weight_to_fee,
- seal_gas_left,
- seal_caller,
- seal_tombstone_deposit,
- seal_deposit_event,
- seal_transfer,
- }
- pub struct Event {
- topics: Vec<[u8; 32]>,
- data: Vec<u8>,
- }
- pub struct VirtualMachine {
- account: Account,
- caller: Account,
- memory: MemoryRef,
- input: Vec<u8>,
- pub output: Vec<u8>,
- pub value: u128,
- }
- impl VirtualMachine {
- fn new(account: Account, caller: Account, value: u128) -> Self {
- VirtualMachine {
- memory: MemoryInstance::alloc(Pages(16), Some(Pages(16))).unwrap(),
- input: Vec::new(),
- output: Vec::new(),
- account,
- caller,
- value,
- }
- }
- }
- pub struct Program {
- abi: abi::substrate::Abi,
- code: Vec<u8>,
- }
- pub struct MockSubstrate {
- pub store: HashMap<(Account, StorageKey), Vec<u8>>,
- pub programs: Vec<Program>,
- pub printbuf: String,
- pub accounts: HashMap<Account, (Vec<u8>, u128)>,
- pub current_program: usize,
- pub vm: VirtualMachine,
- pub events: Vec<Event>,
- }
- impl Externals for MockSubstrate {
- #[allow(clippy::cognitive_complexity)]
- fn invoke_index(
- &mut self,
- index: usize,
- args: RuntimeArgs,
- ) -> Result<Option<RuntimeValue>, Trap> {
- macro_rules! set_seal_value {
- ($name:literal, $dest_ptr:expr, $len_ptr:expr, $buf:expr) => {{
- println!("{}: {}", $name, hex::encode($buf));
- let len = self
- .vm
- .memory
- .get_value::<u32>($len_ptr)
- .expect(&format!("{} len_ptr should be valid", $name));
- assert!(
- (len as usize) >= $buf.len(),
- "{} input is {} buffer is {}",
- $name,
- $buf.len(),
- len
- );
- if let Err(e) = self.vm.memory.set($dest_ptr, $buf) {
- panic!("{}: {}", $name, e);
- }
- self.vm
- .memory
- .set_value($len_ptr, $buf.len() as u32)
- .expect(&format!("{} len_ptr should be valid", $name));
- }};
- }
- match FromPrimitive::from_usize(index) {
- Some(SubstrateExternal::seal_input) => {
- let dest_ptr: u32 = args.nth_checked(0)?;
- let len_ptr: u32 = args.nth_checked(1)?;
- let len = self
- .vm
- .memory
- .get_value::<u32>(len_ptr)
- .expect("seal_input len_ptr should be valid");
- assert!(
- (len as usize) >= self.vm.input.len(),
- "input is {} seal_input buffer {}",
- self.vm.input.len(),
- len
- );
- if let Err(e) = self.vm.memory.set(dest_ptr, &self.vm.input) {
- panic!("seal_input: {}", e);
- }
- self.vm
- .memory
- .set_value(len_ptr, self.vm.input.len() as u32)
- .expect("seal_input len_ptr should be valid");
- Ok(None)
- }
- Some(SubstrateExternal::seal_get_storage) => {
- assert_eq!(args.len(), 3);
- let key_ptr: u32 = args.nth_checked(0)?;
- let dest_ptr: u32 = args.nth_checked(1)?;
- let len_ptr: u32 = args.nth_checked(2)?;
- let mut key: StorageKey = [0; 32];
- if let Err(e) = self.vm.memory.get_into(key_ptr, &mut key) {
- panic!("seal_get_storage: {}", e);
- }
- if let Some(value) = self.store.get(&(self.vm.account, key)) {
- println!("seal_get_storage: {:?} = {:?}", key, value);
- let len = self
- .vm
- .memory
- .get_value::<u32>(len_ptr)
- .expect("seal_get_storage len_ptr should be valid");
- assert!(
- (len as usize) >= value.len(),
- "seal_get_storage buffer is too small"
- );
- if let Err(e) = self.vm.memory.set(dest_ptr, value) {
- panic!("seal_get_storage: {}", e);
- }
- self.vm
- .memory
- .set_value(len_ptr, value.len() as u32)
- .expect("seal_get_storage len_ptr should be valid");
- Ok(Some(RuntimeValue::I32(0)))
- } else {
- println!("seal_get_storage: {:?} = nil", key);
- Ok(Some(RuntimeValue::I32(1)))
- }
- }
- Some(SubstrateExternal::seal_clear_storage) => {
- let key_ptr: u32 = args.nth_checked(0)?;
- let mut key: StorageKey = [0; 32];
- if let Err(e) = self.vm.memory.get_into(key_ptr, &mut key) {
- panic!("seal_clear_storage: {}", e);
- }
- println!("seal_clear_storage: {:?}", key);
- self.store.remove(&(self.vm.account, key));
- Ok(None)
- }
- Some(SubstrateExternal::seal_set_storage) => {
- assert_eq!(args.len(), 3);
- let key_ptr: u32 = args.nth_checked(0)?;
- let data_ptr: u32 = args.nth_checked(1)?;
- let len: u32 = args.nth_checked(2)?;
- let mut key: StorageKey = [0; 32];
- if let Err(e) = self.vm.memory.get_into(key_ptr, &mut key) {
- panic!("seal_set_storage: {}", e);
- }
- let mut data = Vec::new();
- data.resize(len as usize, 0u8);
- if let Err(e) = self.vm.memory.get_into(data_ptr, &mut data) {
- panic!("seal_set_storage: {}", e);
- }
- println!("seal_set_storage: {:?} = {:?}", key, data);
- self.store.insert((self.vm.account, key), data);
- Ok(None)
- }
- Some(SubstrateExternal::seal_hash_keccak_256) => {
- let data_ptr: u32 = args.nth_checked(0)?;
- let len: u32 = args.nth_checked(1)?;
- let out_ptr: u32 = args.nth_checked(2)?;
- let mut data = Vec::new();
- data.resize(len as usize, 0);
- if let Err(e) = self.vm.memory.get_into(data_ptr, &mut data) {
- panic!("seal_hash_keccak_256: {}", e);
- }
- let mut hasher = Keccak::v256();
- let mut hash = [0u8; 32];
- hasher.update(&data);
- hasher.finalize(&mut hash);
- println!(
- "seal_hash_keccak_256: {} = {}",
- hex::encode(data),
- hex::encode(hash)
- );
- if let Err(e) = self.vm.memory.set(out_ptr, &hash) {
- panic!("seal_hash_keccak_256: {}", e);
- }
- Ok(None)
- }
- Some(SubstrateExternal::seal_hash_sha2_256) => {
- let data_ptr: u32 = args.nth_checked(0)?;
- let len: u32 = args.nth_checked(1)?;
- let out_ptr: u32 = args.nth_checked(2)?;
- let mut data = Vec::new();
- data.resize(len as usize, 0);
- if let Err(e) = self.vm.memory.get_into(data_ptr, &mut data) {
- panic!("seal_hash_sha2_256: {}", e);
- }
- let mut hasher = Sha256::new();
- hasher.update(&data);
- let hash = hasher.finalize();
- println!(
- "seal_hash_sha2_256: {} = {}",
- hex::encode(data),
- hex::encode(hash)
- );
- if let Err(e) = self.vm.memory.set(out_ptr, &hash) {
- panic!("seal_hash_sha2_256: {}", e);
- }
- Ok(None)
- }
- Some(SubstrateExternal::seal_hash_blake2_128) => {
- let data_ptr: u32 = args.nth_checked(0)?;
- let len: u32 = args.nth_checked(1)?;
- let out_ptr: u32 = args.nth_checked(2)?;
- let mut data = Vec::new();
- data.resize(len as usize, 0);
- if let Err(e) = self.vm.memory.get_into(data_ptr, &mut data) {
- panic!("seal_hash_blake2_128: {}", e);
- }
- let hash = blake2_rfc::blake2b::blake2b(16, &[], &data);
- println!(
- "seal_hash_blake2_128: {} = {}",
- hex::encode(data),
- hex::encode(hash)
- );
- if let Err(e) = self.vm.memory.set(out_ptr, hash.as_bytes()) {
- panic!("seal_hash_blake2_128: {}", e);
- }
- Ok(None)
- }
- Some(SubstrateExternal::seal_hash_blake2_256) => {
- let data_ptr: u32 = args.nth_checked(0)?;
- let len: u32 = args.nth_checked(1)?;
- let out_ptr: u32 = args.nth_checked(2)?;
- let mut data = Vec::new();
- data.resize(len as usize, 0);
- if let Err(e) = self.vm.memory.get_into(data_ptr, &mut data) {
- panic!("seal_hash_blake2_256: {}", e);
- }
- let hash = blake2_rfc::blake2b::blake2b(32, &[], &data);
- println!(
- "seal_hash_blake2_256: {} = {}",
- hex::encode(data),
- hex::encode(hash)
- );
- if let Err(e) = self.vm.memory.set(out_ptr, hash.as_bytes()) {
- panic!("seal_hash_blake2_256: {}", e);
- }
- Ok(None)
- }
- Some(SubstrateExternal::seal_return) => {
- let flags: i32 = args.nth_checked(0)?;
- let data_ptr: u32 = args.nth_checked(1)?;
- let len: u32 = args.nth_checked(2)?;
- self.vm.output.resize(len as usize, 0u8);
- if let Err(e) = self.vm.memory.get_into(data_ptr, &mut self.vm.output) {
- panic!("seal_return: {}", e);
- }
- match flags {
- 0 | 1 => Err(Trap::new(TrapKind::Host(Box::new(HostCodeReturn(flags))))),
- _ => panic!("seal_return flag {} not valid", flags),
- }
- }
- Some(SubstrateExternal::seal_println) => {
- let data_ptr: u32 = args.nth_checked(0)?;
- let len: u32 = args.nth_checked(1)?;
- let mut buf = Vec::new();
- buf.resize(len as usize, 0u8);
- if let Err(e) = self.vm.memory.get_into(data_ptr, &mut buf) {
- panic!("seal_println: {}", e);
- }
- let s = String::from_utf8_lossy(&buf);
- println!("seal_println: {}", s);
- self.printbuf.push_str(&s);
- Ok(None)
- }
- Some(SubstrateExternal::seal_random) => {
- let data_ptr: u32 = args.nth_checked(0)?;
- let len: u32 = args.nth_checked(1)?;
- let dest_ptr: u32 = args.nth_checked(2)?;
- let len_ptr: u32 = args.nth_checked(3)?;
- let mut buf = Vec::new();
- buf.resize(len as usize, 0u8);
- if let Err(e) = self.vm.memory.get_into(data_ptr, &mut buf) {
- panic!("seal_random: {}", e);
- }
- let mut hash = [0u8; 32];
- hash.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], &buf).as_bytes());
- println!("seal_random: {} {}", hex::encode(buf), hex::encode(&hash));
- let len = self
- .vm
- .memory
- .get_value::<u32>(len_ptr)
- .expect("seal_random len_ptr should be valid");
- assert!(
- (len as usize) >= hash.len(),
- "seal_random dest buffer is too small"
- );
- if let Err(e) = self.vm.memory.set(dest_ptr, &hash) {
- panic!("seal_random: {}", e);
- }
- self.vm
- .memory
- .set_value(len_ptr, hash.len() as u32)
- .expect("seal_random len_ptr should be valid");
- Ok(None)
- }
- Some(SubstrateExternal::seal_call) => {
- let account_ptr: u32 = args.nth_checked(0)?;
- let account_len: u32 = args.nth_checked(1)?;
- //let gas: u64 = args.nth_checked(2)?;
- let value_ptr: u32 = args.nth_checked(3)?;
- let value_len: u32 = args.nth_checked(4)?;
- let input_ptr: u32 = args.nth_checked(5)?;
- let input_len: u32 = args.nth_checked(6)?;
- let output_ptr: u32 = args.nth_checked(7)?;
- let output_len_ptr: u32 = args.nth_checked(8)?;
- let mut account = [0u8; 32];
- assert!(account_len == 32, "seal_call: len = {}", account_len);
- if let Err(e) = self.vm.memory.get_into(account_ptr, &mut account) {
- panic!("seal_call: {}", e);
- }
- let mut value = [0u8; 16];
- assert!(value_len == 16, "seal_call: len = {}", value_len);
- if let Err(e) = self.vm.memory.get_into(value_ptr, &mut value) {
- panic!("seal_call: {}", e);
- }
- let value = u128::from_le_bytes(value);
- if !self.accounts.contains_key(&account) {
- // substrate would return NotCallable
- return Ok(Some(RuntimeValue::I32(0x8)));
- }
- let mut input = Vec::new();
- input.resize(input_len as usize, 0u8);
- if let Err(e) = self.vm.memory.get_into(input_ptr, &mut input) {
- panic!("seal_call: {}", e);
- }
- println!(
- "seal_call: account={} input={}",
- hex::encode(account),
- hex::encode(&input)
- );
- let mut vm = VirtualMachine::new(account, self.vm.account, value);
- std::mem::swap(&mut self.vm, &mut vm);
- let module = self.create_module(&self.accounts.get(&self.vm.account).unwrap().0);
- self.vm.input = input;
- let ret = module.invoke_export("call", &[], self);
- let ret = match ret {
- Err(wasmi::Error::Trap(trap)) => match trap.kind() {
- TrapKind::Host(host_error) => {
- if let Some(ret) = host_error.downcast_ref::<HostCodeReturn>() {
- Some(RuntimeValue::I32(ret.0))
- } else if host_error.downcast_ref::<HostCodeTerminate>().is_some() {
- Some(RuntimeValue::I32(1))
- } else {
- return Err(trap);
- }
- }
- _ => {
- return Err(trap);
- }
- },
- Ok(v) => v,
- Err(e) => panic!("fail to invoke call: {}", e),
- };
- let output = self.vm.output.clone();
- std::mem::swap(&mut self.vm, &mut vm);
- println!("seal_call ret={:?} buf={}", ret, hex::encode(&output));
- if let Some(acc) = self.accounts.get_mut(&vm.account) {
- acc.1 += vm.value;
- }
- set_seal_value!("seal_call return buf", output_ptr, output_len_ptr, &output);
- Ok(ret)
- }
- Some(SubstrateExternal::seal_transfer) => {
- let account_ptr: u32 = args.nth_checked(0)?;
- let account_len: u32 = args.nth_checked(1)?;
- let value_ptr: u32 = args.nth_checked(2)?;
- let value_len: u32 = args.nth_checked(3)?;
- let mut account = [0u8; 32];
- assert!(account_len == 32, "seal_transfer: len = {}", account_len);
- if let Err(e) = self.vm.memory.get_into(account_ptr, &mut account) {
- panic!("seal_transfer: {}", e);
- }
- let mut value = [0u8; 16];
- assert!(value_len == 16, "seal_transfer: len = {}", value_len);
- if let Err(e) = self.vm.memory.get_into(value_ptr, &mut value) {
- panic!("seal_transfer: {}", e);
- }
- let value = u128::from_le_bytes(value);
- if !self.accounts.contains_key(&account) {
- // substrate would return TransferFailed
- return Ok(Some(RuntimeValue::I32(0x5)));
- }
- if let Some(acc) = self.accounts.get_mut(&account) {
- acc.1 += value;
- }
- Ok(Some(RuntimeValue::I32(0)))
- }
- Some(SubstrateExternal::seal_instantiate) => {
- let codehash_ptr: u32 = args.nth_checked(0)?;
- let codehash_len: u32 = args.nth_checked(1)?;
- //let gas: u64 = args.nth_checked(2)?;
- let value_ptr: u32 = args.nth_checked(3)?;
- let value_len: u32 = args.nth_checked(4)?;
- let input_ptr: u32 = args.nth_checked(5)?;
- let input_len: u32 = args.nth_checked(6)?;
- let account_ptr: u32 = args.nth_checked(7)?;
- let account_len_ptr: u32 = args.nth_checked(8)?;
- let output_ptr: u32 = args.nth_checked(9)?;
- let output_len_ptr: u32 = args.nth_checked(10)?;
- let salt_ptr: u32 = args.nth_checked(11)?;
- let salt_len: u32 = args.nth_checked(12)?;
- let mut codehash = [0u8; 32];
- assert!(
- codehash_len == 32,
- "seal_instantiate: len = {}",
- codehash_len
- );
- if let Err(e) = self.vm.memory.get_into(codehash_ptr, &mut codehash) {
- panic!("seal_instantiate: {}", e);
- }
- let mut value = [0u8; 16];
- assert!(value_len == 16, "seal_instantiate: len = {}", value_len);
- if let Err(e) = self.vm.memory.get_into(value_ptr, &mut value) {
- panic!("seal_instantiate: {}", e);
- }
- let value = u128::from_le_bytes(value);
- let mut input = Vec::new();
- input.resize(input_len as usize, 0u8);
- if let Err(e) = self.vm.memory.get_into(input_ptr, &mut input) {
- panic!("seal_instantiate: {}", e);
- }
- let mut salt = Vec::new();
- salt.resize(salt_len as usize, 0u8);
- if let Err(e) = self.vm.memory.get_into(salt_ptr, &mut salt) {
- panic!("seal_instantiate: {}", e);
- }
- println!(
- "seal_instantiate value:{} input={} salt={}",
- value,
- hex::encode(&input),
- hex::encode(&salt),
- );
- let mut account = [0u8; 32];
- let hash_data: Vec<u8> = input.iter().chain(salt.iter()).cloned().collect();
- account
- .copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], &hash_data).as_bytes());
- if self.accounts.contains_key(&account) {
- // substrate would return TRAP_RETURN_CODE (0x0100)
- return Ok(Some(RuntimeValue::I32(0x100)));
- }
- let program = self
- .programs
- .iter()
- .find(|program| {
- blake2_rfc::blake2b::blake2b(32, &[], &program.code).as_bytes() == codehash
- })
- .expect("codehash not found");
- self.accounts.insert(account, (program.code.clone(), 0));
- let mut input = Vec::new();
- input.resize(input_len as usize, 0u8);
- if let Err(e) = self.vm.memory.get_into(input_ptr, &mut input) {
- panic!("seal_instantiate: {}", e);
- }
- let mut vm = VirtualMachine::new(account, self.vm.account, value);
- std::mem::swap(&mut self.vm, &mut vm);
- let module = self.create_module(&program.code);
- self.vm.input = input;
- let ret = match module.invoke_export("deploy", &[], self) {
- Err(wasmi::Error::Trap(trap)) => match trap.kind() {
- TrapKind::Host(host_error) => {
- if let Some(ret) = host_error.downcast_ref::<HostCodeReturn>() {
- Some(RuntimeValue::I32(ret.0))
- } else {
- return Err(trap);
- }
- }
- _ => {
- return Err(trap);
- }
- },
- Ok(v) => v,
- Err(e) => panic!("fail to invoke deploy: {}", e),
- };
- let output = self.vm.output.clone();
- std::mem::swap(&mut self.vm, &mut vm);
- set_seal_value!(
- "seal_instantiate output",
- output_ptr,
- output_len_ptr,
- &output
- );
- if let Some(RuntimeValue::I32(0)) = ret {
- self.accounts.get_mut(&vm.account).unwrap().1 += vm.value;
- set_seal_value!(
- "seal_instantiate account",
- account_ptr,
- account_len_ptr,
- &account
- );
- }
- println!("seal_instantiate ret:{:?}", ret);
- Ok(ret)
- }
- Some(SubstrateExternal::seal_value_transferred) => {
- let dest_ptr: u32 = args.nth_checked(0)?;
- let len_ptr: u32 = args.nth_checked(1)?;
- let scratch = self.vm.value.to_le_bytes();
- set_seal_value!("seal_value_transferred", dest_ptr, len_ptr, &scratch);
- Ok(None)
- }
- Some(SubstrateExternal::seal_address) => {
- let dest_ptr: u32 = args.nth_checked(0)?;
- let len_ptr: u32 = args.nth_checked(1)?;
- let scratch = self.vm.account;
- set_seal_value!("seal_address", dest_ptr, len_ptr, &scratch);
- Ok(None)
- }
- Some(SubstrateExternal::seal_caller) => {
- let dest_ptr: u32 = args.nth_checked(0)?;
- let len_ptr: u32 = args.nth_checked(1)?;
- let scratch = self.vm.caller;
- set_seal_value!("seal_caller", dest_ptr, len_ptr, &scratch);
- Ok(None)
- }
- Some(SubstrateExternal::seal_balance) => {
- let dest_ptr: u32 = args.nth_checked(0)?;
- let len_ptr: u32 = args.nth_checked(1)?;
- let scratch = self.accounts[&self.vm.account].1.to_le_bytes();
- set_seal_value!("seal_balance", dest_ptr, len_ptr, &scratch);
- Ok(None)
- }
- Some(SubstrateExternal::seal_minimum_balance) => {
- let dest_ptr: u32 = args.nth_checked(0)?;
- let len_ptr: u32 = args.nth_checked(1)?;
- let scratch = 500u128.to_le_bytes();
- set_seal_value!("seal_minimum_balance", dest_ptr, len_ptr, &scratch);
- Ok(None)
- }
- Some(SubstrateExternal::seal_block_number) => {
- let dest_ptr: u32 = args.nth_checked(0)?;
- let len_ptr: u32 = args.nth_checked(1)?;
- let scratch = 950_119_597u32.to_le_bytes();
- set_seal_value!("seal_block_number", dest_ptr, len_ptr, &scratch);
- Ok(None)
- }
- Some(SubstrateExternal::seal_now) => {
- let dest_ptr: u32 = args.nth_checked(0)?;
- let len_ptr: u32 = args.nth_checked(1)?;
- let scratch = 1594035638000u64.to_le_bytes();
- set_seal_value!("seal_now", dest_ptr, len_ptr, &scratch);
- Ok(None)
- }
- Some(SubstrateExternal::seal_gas_left) => {
- let dest_ptr: u32 = args.nth_checked(0)?;
- let len_ptr: u32 = args.nth_checked(1)?;
- let scratch = 2_224_097_461u64.to_le_bytes();
- set_seal_value!("seal_gas_left", dest_ptr, len_ptr, &scratch);
- Ok(None)
- }
- Some(SubstrateExternal::seal_weight_to_fee) => {
- let units: u64 = args.nth_checked(0)?;
- let dest_ptr: u32 = args.nth_checked(1)?;
- let len_ptr: u32 = args.nth_checked(2)?;
- let scratch = (59_541_253_813_967u128 * units as u128).to_le_bytes();
- set_seal_value!("seal_weight_to_fee", dest_ptr, len_ptr, &scratch);
- Ok(None)
- }
- Some(SubstrateExternal::seal_tombstone_deposit) => {
- let dest_ptr: u32 = args.nth_checked(0)?;
- let len_ptr: u32 = args.nth_checked(1)?;
- let scratch = 93_603_701_976_053u128.to_le_bytes();
- set_seal_value!("seal_tombstone_deposit", dest_ptr, len_ptr, &scratch);
- Ok(None)
- }
- Some(SubstrateExternal::seal_terminate) => {
- let account_ptr: u32 = args.nth_checked(0)?;
- let account_len: u32 = args.nth_checked(1)?;
- let mut account = [0u8; 32];
- assert!(account_len == 32, "seal_terminate: len = {}", account_len);
- if let Err(e) = self.vm.memory.get_into(account_ptr, &mut account) {
- panic!("seal_terminate: {}", e);
- }
- let remaining = self.accounts[&self.vm.account].1;
- self.accounts.get_mut(&account).unwrap().1 += remaining;
- println!("seal_terminate: {} {}", hex::encode(&account), remaining);
- self.accounts.remove(&self.vm.account);
- Err(Trap::new(TrapKind::Host(Box::new(HostCodeTerminate {}))))
- }
- Some(SubstrateExternal::seal_deposit_event) => {
- let mut topic_ptr: u32 = args.nth_checked(0)?;
- let topic_len: u32 = args.nth_checked(1)?;
- let data_ptr: u32 = args.nth_checked(2)?;
- let data_len: u32 = args.nth_checked(3)?;
- let mut topics = Vec::new();
- if topic_len != 0 {
- assert_eq!(topic_len % 32, 1);
- assert_eq!((topic_len - 1) % 32, 0);
- let mut vec_length = [0u8];
- if let Err(e) = self.vm.memory.get_into(topic_ptr, &mut vec_length) {
- panic!("seal_deposit_event: topic: {}", e);
- }
- println!("topic_len: {} first byte: {}", topic_len, vec_length[0]);
- assert_eq!(vec_length[0] as u32, (topic_len - 1) / 8);
- topic_ptr += 1;
- }
- for _ in 0..topic_len / 32 {
- let mut topic = [0u8; 32];
- if let Err(e) = self.vm.memory.get_into(topic_ptr, &mut topic) {
- panic!("seal_deposit_event: topic: {}", e);
- }
- topics.push(topic);
- topic_ptr += 32;
- }
- let mut data = Vec::new();
- data.resize(data_len as usize, 0);
- if let Err(e) = self.vm.memory.get_into(data_ptr, &mut data) {
- panic!("seal_deposit_event: data: {}", e);
- }
- println!(
- "seal_deposit_event: topic: {} data: {}",
- topics
- .iter()
- .map(|t| hex::encode(&t))
- .collect::<Vec<String>>()
- .join(" "),
- hex::encode(&data)
- );
- self.events.push(Event { topics, data });
- Ok(None)
- }
- _ => panic!("external {} unknown", index),
- }
- }
- }
- impl ModuleImportResolver for MockSubstrate {
- fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {
- let index = match field_name {
- "seal_input" => SubstrateExternal::seal_input,
- "seal_get_storage" => SubstrateExternal::seal_get_storage,
- "seal_set_storage" => SubstrateExternal::seal_set_storage,
- "seal_clear_storage" => SubstrateExternal::seal_clear_storage,
- "seal_return" => SubstrateExternal::seal_return,
- "seal_hash_sha2_256" => SubstrateExternal::seal_hash_sha2_256,
- "seal_hash_keccak_256" => SubstrateExternal::seal_hash_keccak_256,
- "seal_hash_blake2_128" => SubstrateExternal::seal_hash_blake2_128,
- "seal_hash_blake2_256" => SubstrateExternal::seal_hash_blake2_256,
- "seal_println" => SubstrateExternal::seal_println,
- "seal_call" => SubstrateExternal::seal_call,
- "seal_instantiate" => SubstrateExternal::seal_instantiate,
- "seal_value_transferred" => SubstrateExternal::seal_value_transferred,
- "seal_minimum_balance" => SubstrateExternal::seal_minimum_balance,
- "seal_random" => SubstrateExternal::seal_random,
- "seal_address" => SubstrateExternal::seal_address,
- "seal_balance" => SubstrateExternal::seal_balance,
- "seal_terminate" => SubstrateExternal::seal_terminate,
- "seal_block_number" => SubstrateExternal::seal_block_number,
- "seal_now" => SubstrateExternal::seal_now,
- "seal_weight_to_fee" => SubstrateExternal::seal_weight_to_fee,
- "seal_gas_left" => SubstrateExternal::seal_gas_left,
- "seal_caller" => SubstrateExternal::seal_caller,
- "seal_tombstone_deposit" => SubstrateExternal::seal_tombstone_deposit,
- "seal_deposit_event" => SubstrateExternal::seal_deposit_event,
- "seal_transfer" => SubstrateExternal::seal_transfer,
- _ => {
- panic!("{} not implemented", field_name);
- }
- };
- Ok(FuncInstance::alloc_host(signature.clone(), index as usize))
- }
- fn resolve_memory(
- &self,
- _field_name: &str,
- _memory_type: &MemoryDescriptor,
- ) -> Result<MemoryRef, Error> {
- Ok(self.vm.memory.clone())
- }
- }
- impl MockSubstrate {
- fn create_module(&self, code: &[u8]) -> ModuleRef {
- let module = Module::from_buffer(&code).expect("parse wasm should work");
- ModuleInstance::new(
- &module,
- &ImportsBuilder::new()
- .with_resolver("env", self)
- .with_resolver("seal0", self),
- )
- .expect("Failed to instantiate module")
- .run_start(&mut NopExternals)
- .expect("Failed to run start function in module")
- }
- fn invoke_deploy(&mut self, module: ModuleRef) -> Option<RuntimeValue> {
- match module.invoke_export("deploy", &[], self) {
- Err(wasmi::Error::Trap(trap)) => match trap.kind() {
- TrapKind::Host(host_error) => {
- if let Some(ret) = host_error.downcast_ref::<HostCodeReturn>() {
- Some(RuntimeValue::I32(ret.0))
- } else {
- panic!("did not go as planned");
- }
- }
- _ => panic!("fail to invoke deploy: {}", trap),
- },
- Ok(v) => v,
- Err(e) => panic!("fail to invoke deploy: {}", e),
- }
- }
- fn invoke_call(&mut self, module: ModuleRef) -> Option<RuntimeValue> {
- match module.invoke_export("call", &[], self) {
- Err(wasmi::Error::Trap(trap)) => match trap.kind() {
- TrapKind::Host(host_error) => {
- if let Some(ret) = host_error.downcast_ref::<HostCodeReturn>() {
- Some(RuntimeValue::I32(ret.0))
- } else if host_error.downcast_ref::<HostCodeTerminate>().is_some() {
- Some(RuntimeValue::I32(1))
- } else {
- panic!("did not go as planned");
- }
- }
- _ => panic!("fail to invoke call: {}", trap),
- },
- Ok(v) => v,
- Err(e) => panic!("fail to invoke call: {}", e),
- }
- }
- pub fn set_program(&mut self, index: usize) {
- let account = account_new();
- let code = self.programs[index].code.clone();
- self.accounts.insert(account, (code, 0));
- self.vm = VirtualMachine::new(account, account_new(), 0);
- self.current_program = index;
- }
- pub fn constructor(&mut self, index: usize, args: Vec<u8>) {
- let m = &self.programs[self.current_program].abi.spec.constructors[index];
- let module = self.create_module(&self.accounts.get(&self.vm.account).unwrap().0);
- self.vm.input = m.selector().into_iter().chain(args).collect();
- let ret = self.invoke_deploy(module);
- if let Some(RuntimeValue::I32(ret)) = ret {
- if ret != 0 {
- panic!("non zero return")
- }
- }
- }
- pub fn constructor_expect_return(&mut self, index: usize, expected_ret: i32, args: Vec<u8>) {
- let m = &self.programs[self.current_program].abi.spec.constructors[index];
- let module = self.create_module(&self.accounts.get(&self.vm.account).unwrap().0);
- self.vm.input = m.selector().into_iter().chain(args).collect();
- let ret = self.invoke_deploy(module);
- if let Some(RuntimeValue::I32(ret)) = ret {
- println!(
- "function_expected_return: got {} expected {}",
- ret, expected_ret
- );
- if expected_ret != ret {
- panic!("non one return")
- }
- }
- }
- pub fn function(&mut self, name: &str, args: Vec<u8>) {
- let m = self.programs[self.current_program]
- .abi
- .get_function(name)
- .unwrap();
- let module = self.create_module(&self.accounts.get(&self.vm.account).unwrap().0);
- self.vm.input = m.selector().into_iter().chain(args).collect();
- println!("input:{}", hex::encode(&self.vm.input));
- if let Some(RuntimeValue::I32(ret)) = self.invoke_call(module) {
- assert!(ret == 0, "non zero return: {}", ret);
- }
- }
- pub fn function_expect_failure(&mut self, name: &str, args: Vec<u8>) {
- let m = self.programs[self.current_program]
- .abi
- .get_function(name)
- .unwrap();
- let module = self.create_module(&self.accounts.get(&self.vm.account).unwrap().0);
- self.vm.input = m.selector().into_iter().chain(args).collect();
- match module.invoke_export("call", &[], self) {
- Err(wasmi::Error::Trap(trap)) => match trap.kind() {
- TrapKind::Unreachable => (),
- _ => panic!("trap: {:?}", trap),
- },
- Err(err) => {
- panic!("unexpected error: {:?}", err);
- }
- Ok(v) => {
- panic!("unexpected return value: {:?}", v);
- }
- }
- }
- pub fn raw_function(&mut self, input: Vec<u8>) {
- let module = self.create_module(&self.accounts.get(&self.vm.account).unwrap().0);
- self.vm.input = input;
- if let Some(RuntimeValue::I32(ret)) = self.invoke_call(module) {
- if ret != 0 {
- panic!("non zero return")
- }
- }
- }
- pub fn raw_function_failure(&mut self, input: Vec<u8>) {
- let module = self.create_module(&self.accounts.get(&self.vm.account).unwrap().0);
- self.vm.input = input;
- match module.invoke_export("call", &[], self) {
- Err(wasmi::Error::Trap(trap)) => match trap.kind() {
- TrapKind::Unreachable => (),
- _ => panic!("trap: {:?}", trap),
- },
- Err(err) => {
- panic!("unexpected error: {:?}", err);
- }
- Ok(v) => {
- panic!("unexpected return value: {:?}", v);
- }
- }
- }
- pub fn raw_constructor(&mut self, input: Vec<u8>) {
- let module = self.create_module(&self.accounts.get(&self.vm.account).unwrap().0);
- self.vm.input = input;
- if let Some(RuntimeValue::I32(ret)) = self.invoke_deploy(module) {
- if ret != 0 {
- panic!("non zero return")
- }
- }
- }
- pub fn heap_verify(&self) {
- let memsize = self.vm.memory.current_size().0 as usize * 0x10000;
- println!("memory size:{}", memsize);
- let mut buf = Vec::new();
- buf.resize(memsize, 0);
- let mut current_elem = 0x10000;
- let mut last_elem = 0u32;
- loop {
- let next: u32 = self.vm.memory.get_value(current_elem).unwrap();
- let prev: u32 = self.vm.memory.get_value(current_elem + 4).unwrap();
- let length: u32 = self.vm.memory.get_value(current_elem + 8).unwrap();
- let allocated: u32 = self.vm.memory.get_value(current_elem + 12).unwrap();
- println!(
- "next:{:08x} prev:{:08x} length:{} allocated:{}",
- next, prev, length, allocated
- );
- let mut buf = vec![0u8; length as usize];
- self.vm
- .memory
- .get_into(current_elem + 16, &mut buf)
- .unwrap();
- if allocated == 0 {
- println!("{:08x} {} not allocated", current_elem + 16, length);
- } else {
- println!("{:08x} {} allocated", current_elem + 16, length);
- assert_eq!(allocated & 0xffff, 1);
- for offset in (0..buf.len()).step_by(16) {
- let mut hex = "\t".to_string();
- let mut chars = "\t".to_string();
- for i in 0..16 {
- if offset + i >= buf.len() {
- break;
- }
- let b = buf[offset + i];
- hex.push_str(&format!(" {:02x}", b));
- if b.is_ascii() && !b.is_ascii_control() {
- chars.push_str(&format!(" {}", b as char));
- } else {
- chars.push_str(" ");
- }
- }
- println!("{}\n{}", hex, chars);
- }
- }
- assert_eq!(last_elem, prev);
- if next == 0 {
- break;
- }
- last_elem = current_elem;
- current_elem = next;
- }
- }
- }
- pub fn build_solidity(src: &'static str) -> MockSubstrate {
- let mut cache = FileResolver::new();
- cache.set_file_contents("test.sol", src.to_string());
- let (res, ns) = compile(
- OsStr::new("test.sol"),
- &mut cache,
- inkwell::OptimizationLevel::Default,
- Target::default_substrate(),
- false,
- );
- ns.print_diagnostics_in_plain(&cache, false);
- assert!(!ns.diagnostics.any_errors());
- assert!(!res.is_empty());
- let programs: Vec<Program> = res
- .iter()
- .map(|res| Program {
- code: res.0.clone(),
- abi: abi::substrate::load(&res.1).unwrap(),
- })
- .collect();
- let mut accounts = HashMap::new();
- let account = account_new();
- accounts.insert(account, (programs[0].code.clone(), 0));
- let vm = VirtualMachine::new(account, account_new(), 0);
- MockSubstrate {
- accounts,
- printbuf: String::new(),
- store: HashMap::new(),
- programs,
- vm,
- current_program: 0,
- events: Vec::new(),
- }
- }
- pub fn build_solidity_with_overflow_check(src: &'static str) -> MockSubstrate {
- let mut cache = FileResolver::new();
- cache.set_file_contents("test.sol", src.to_string());
- let (res, ns) = compile(
- OsStr::new("test.sol"),
- &mut cache,
- inkwell::OptimizationLevel::Default,
- Target::default_substrate(),
- true,
- );
- ns.print_diagnostics_in_plain(&cache, false);
- assert!(!res.is_empty());
- let programs: Vec<Program> = res
- .iter()
- .map(|res| Program {
- code: res.0.clone(),
- abi: abi::substrate::load(&res.1).unwrap(),
- })
- .collect();
- let mut accounts = HashMap::new();
- let account = account_new();
- accounts.insert(account, (programs[0].code.clone(), 0));
- let vm = VirtualMachine::new(account, account_new(), 0);
- MockSubstrate {
- accounts,
- printbuf: String::new(),
- store: HashMap::new(),
- programs,
- vm,
- current_program: 0,
- events: Vec::new(),
- }
- }
|