From 55bfaf02acb42acbafa5c51f11176cabb0dc6361 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Fri, 28 Aug 2020 12:56:34 -0700 Subject: [PATCH 01/82] Adding near-evm-runner crate that uses Parity EVM as an interpreter for EVM bytecode --- Cargo.toml | 1 + runtime/near-evm-runner/Cargo.toml | 30 ++ runtime/near-evm-runner/src/builtins.rs | 576 +++++++++++++++++++++ runtime/near-evm-runner/src/errors.rs | 19 + runtime/near-evm-runner/src/evm_state.rs | 465 +++++++++++++++++ runtime/near-evm-runner/src/interpreter.rs | 265 ++++++++++ runtime/near-evm-runner/src/lib.rs | 97 ++++ runtime/near-evm-runner/src/near_ext.rs | 345 ++++++++++++ runtime/near-evm-runner/src/utils.rs | 120 +++++ 9 files changed, 1918 insertions(+) create mode 100644 runtime/near-evm-runner/Cargo.toml create mode 100644 runtime/near-evm-runner/src/builtins.rs create mode 100644 runtime/near-evm-runner/src/errors.rs create mode 100644 runtime/near-evm-runner/src/evm_state.rs create mode 100644 runtime/near-evm-runner/src/interpreter.rs create mode 100644 runtime/near-evm-runner/src/lib.rs create mode 100644 runtime/near-evm-runner/src/near_ext.rs create mode 100644 runtime/near-evm-runner/src/utils.rs diff --git a/Cargo.toml b/Cargo.toml index a0602994f58..649369daac7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "runtime/near-vm-logic", "runtime/near-vm-runner", "runtime/near-vm-runner-standalone", + "runtime/near-evm-runner", "runtime/runtime-params-estimator", "chain/chain", "chain/chunks", diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml new file mode 100644 index 00000000000..2744e95f279 --- /dev/null +++ b/runtime/near-evm-runner/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "near-evm-runner" +version = "0.1.0" +authors = ["Near Inc "] +edition = "2018" +license = "Apache-2.0" +repository = "https://github.com/nearprotocol/nearcore" +homepage = "https://github.com/nearprotocol/nearcore" + +[dependencies] +evm = { git = "https://github.com/paritytech/parity-ethereum", rev = "eed630a002bbebed3a3097127f2483213ff52079" } +vm = { git = "https://github.com/paritytech/parity-ethereum", rev = "eed630a002bbebed3a3097127f2483213ff52079" } +bn = { git = "https://github.com/paritytech/bn", default-features = false } +parity-bytes = "0.1.0" +ethereum-types = "0.6.0" +keccak-hash = "0.2.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1" +sha2 = "0.8" +sha3 = "0.8" +rlp = "0.4.2" +hex = "0.3.2" +byteorder = "1.0" +num-bigint = { version = "0.3", default-features = false } +num-traits = "0.2.12" +ripemd160 = "0.9.0" +libsecp256k1 = "0.3.5" +near-vm-logic = { path = "../near-vm-logic" } +near-vm-errors = { path = "../near-vm-errors" } +near-primitives = { path = "../../core/primitives" } \ No newline at end of file diff --git a/runtime/near-evm-runner/src/builtins.rs b/runtime/near-evm-runner/src/builtins.rs new file mode 100644 index 00000000000..3397db9a46a --- /dev/null +++ b/runtime/near-evm-runner/src/builtins.rs @@ -0,0 +1,576 @@ +use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt}; +use ethereum_types::{Address, H256, U256}; +use num_bigint::BigUint; +use num_traits::{One, Zero}; + +use parity_bytes::BytesRef; +use ripemd160::Digest; +use std::{ + cmp::{max, min}, + io::{self, Cursor, Read}, + mem::size_of, +}; +use vm::{MessageCallResult, ReturnData}; + +pub static COUNT: u64 = 9; + +pub fn is_precompile(addr: &Address) -> bool { + *addr <= Address::from_low_u64_be(COUNT) +} + +pub fn precompile(id: u64) -> Box { + match id { + 1 => Box::new(EcRecover) as Box, + 2 => Box::new(Sha256) as Box, + 3 => Box::new(Ripemd160) as Box, + 4 => Box::new(Identity) as Box, + 5 => Box::new(ModexpImpl) as Box, + 6 => Box::new(Bn128AddImpl) as Box, + 7 => Box::new(Bn128MulImpl) as Box, + 8 => Box::new(Bn128PairingImpl) as Box, + 9 => Box::new(Blake2FImpl) as Box, + _ => panic!("Invalid builtin ID: {}", id), + } +} + +pub fn process_precompile(addr: &Address, input: &[u8]) -> MessageCallResult { + let f = precompile(addr.to_low_u64_be()); + let mut bytes = vec![]; + let mut output = parity_bytes::BytesRef::Flexible(&mut bytes); + + // mutates bytes + f.execute(input, &mut output).expect("No errors in precompiles"); + + let size = bytes.len(); + + MessageCallResult::Success(1_000_000_000.into(), ReturnData::new(bytes, 0, size)) +} + +/** the following is copied from ethcore/src/builtin.rs **/ + +// Copyright 2015-2019 Parity Technologies (UK) Ltd. +// This file is part of Parity Ethereum. + +// Parity Ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Ethereum. If not, see . + +/// Execution error. +#[derive(Debug)] +pub struct Error(pub &'static str); + +impl From<&'static str> for Error { + fn from(val: &'static str) -> Self { + Error(val) + } +} + +impl Into for Error { + fn into(self) -> ::vm::Error { + vm::Error::BuiltIn(self.0) + } +} +#[derive(Debug)] +struct EcRecover; + +#[derive(Debug)] +struct Sha256; + +#[derive(Debug)] +struct Ripemd160; + +#[derive(Debug)] +struct Identity; + +#[derive(Debug)] +struct ModexpImpl; + +#[derive(Debug)] +struct Bn128AddImpl; + +#[derive(Debug)] +struct Bn128MulImpl; + +#[derive(Debug)] +struct Bn128PairingImpl; + +#[derive(Debug)] +pub struct Blake2FImpl; + +/// Native implementation of a built-in contract. +pub trait Impl: Send + Sync { + /// execute this built-in on the given input, writing to the given output. + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error>; +} + +impl Impl for Identity { + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + output.write(0, input); + Ok(()) + } +} + +impl Impl for EcRecover { + fn execute(&self, i: &[u8], output: &mut BytesRef) -> Result<(), Error> { + use sha3::Digest; + + let len = min(i.len(), 128); + + let mut input = [0; 128]; + input[..len].copy_from_slice(&i[..len]); + + let hash = secp256k1::Message::parse(&H256::from_slice(&input[0..32]).0); + let v = &input[32..64]; + let r = &input[64..96]; + let s = &input[96..128]; + + let bit = match v[31] { + 27..=30 => v[31] - 27, + _ => { + return Ok(()); + } + }; + + let mut sig = [0u8; 64]; + sig[..32].copy_from_slice(&r); + sig[32..].copy_from_slice(&s); + let s = secp256k1::Signature::parse(&sig); + + if let Ok(rec_id) = secp256k1::RecoveryId::parse(bit) { + if let Ok(p) = secp256k1::recover(&hash, &s, &rec_id) { + // recover returns the 65-byte key, but addresses come from the raw 64-byte key + let r = sha3::Keccak256::digest(&p.serialize()[1..]); + output.write(0, &[0; 12]); + output.write(12, &r[12..]); + } + } + + Ok(()) + } +} + +impl Impl for Sha256 { + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + use sha2::Digest; + let d = sha2::Sha256::digest(input); + output.write(0, &*d); + Ok(()) + } +} + +impl Impl for Ripemd160 { + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + let hash = ripemd160::Ripemd160::digest(input); + output.write(0, &[0; 12][..]); + output.write(12, &hash); + Ok(()) + } +} + +// calculate modexp: left-to-right binary exponentiation to keep multiplicands lower +fn modexp(mut base: BigUint, exp: Vec, modulus: BigUint) -> BigUint { + const BITS_PER_DIGIT: usize = 8; + + // n^m % 0 || n^m % 1 + if modulus <= BigUint::one() { + return BigUint::zero(); + } + + // normalize exponent + let mut exp = exp.into_iter().skip_while(|d| *d == 0).peekable(); + + // n^0 % m + if exp.peek().is_none() { + return BigUint::one(); + } + + // 0^n % m, n > 0 + if base.is_zero() { + return BigUint::zero(); + } + + base %= &modulus; + + // Fast path for base divisible by modulus. + if base.is_zero() { + return BigUint::zero(); + } + + // Left-to-right binary exponentiation (Handbook of Applied Cryptography - Algorithm 14.79). + // http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf + let mut result = BigUint::one(); + + for digit in exp { + let mut mask = 1 << (BITS_PER_DIGIT - 1); + + for _ in 0..BITS_PER_DIGIT { + result = &result * &result % &modulus; + + if digit & mask > 0 { + result = result * &base % &modulus; + } + + mask >>= 1; + } + } + + result +} + +impl Impl for ModexpImpl { + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + let mut reader = input.chain(io::repeat(0)); + let mut buf = [0; 32]; + + // read lengths as usize. + // ignoring the first 24 bytes might technically lead us to fall out of consensus, + // but so would running out of addressable memory! + let mut read_len = |reader: &mut io::Chain<&[u8], io::Repeat>| { + reader + .read_exact(&mut buf[..]) + .expect("reading from zero-extended memory cannot fail; qed"); + BigEndian::read_u64(&buf[24..]) as usize + }; + + let base_len = read_len(&mut reader); + let exp_len = read_len(&mut reader); + let mod_len = read_len(&mut reader); + + // Gas formula allows arbitrary large exp_len when base and modulus are empty, so we need to handle empty base first. + let r = if base_len == 0 && mod_len == 0 { + BigUint::zero() + } else { + // read the numbers themselves. + let mut buf = vec![0; max(mod_len, max(base_len, exp_len))]; + let mut read_num = |reader: &mut io::Chain<&[u8], io::Repeat>, len: usize| { + reader + .read_exact(&mut buf[..len]) + .expect("reading from zero-extended memory cannot fail; qed"); + BigUint::from_bytes_be(&buf[..len]) + }; + + let base = read_num(&mut reader, base_len); + + let mut exp_buf = vec![0; exp_len]; + reader + .read_exact(&mut exp_buf[..exp_len]) + .expect("reading from zero-extended memory cannot fail; qed"); + + let modulus = read_num(&mut reader, mod_len); + + modexp(base, exp_buf, modulus) + }; + + // write output to given memory, left padded and same length as the modulus. + let bytes = r.to_bytes_be(); + + // always true except in the case of zero-length modulus, which leads to + // output of length and value 1. + if bytes.len() <= mod_len { + let res_start = mod_len - bytes.len(); + output.write(res_start, &bytes); + } + + Ok(()) + } +} + +fn read_fr(reader: &mut io::Chain<&[u8], io::Repeat>) -> Result<::bn::Fr, Error> { + let mut buf = [0u8; 32]; + + reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed"); + ::bn::Fr::from_slice(&buf[0..32]).map_err(|_| Error::from("Invalid field element")) +} + +fn read_point(reader: &mut io::Chain<&[u8], io::Repeat>) -> Result<::bn::G1, Error> { + use bn::{AffineG1, Fq, Group, G1}; + + let mut buf = [0u8; 32]; + + reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed"); + let px = Fq::from_slice(&buf[0..32]).map_err(|_| Error::from("Invalid point x coordinate"))?; + + reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed"); + let py = Fq::from_slice(&buf[0..32]).map_err(|_| Error::from("Invalid point y coordinate"))?; + Ok(if px == Fq::zero() && py == Fq::zero() { + G1::zero() + } else { + AffineG1::new(px, py).map_err(|_| Error::from("Invalid curve point"))?.into() + }) +} + +impl Impl for Bn128AddImpl { + // Can fail if any of the 2 points does not belong the bn128 curve + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + use bn::AffineG1; + + let mut padded_input = input.chain(io::repeat(0)); + let p1 = read_point(&mut padded_input)?; + let p2 = read_point(&mut padded_input)?; + + let mut write_buf = [0u8; 64]; + if let Some(sum) = AffineG1::from_jacobian(p1 + p2) { + // point not at infinity + sum.x() + .to_big_endian(&mut write_buf[0..32]) + .expect("Cannot fail since 0..32 is 32-byte length"); + sum.y() + .to_big_endian(&mut write_buf[32..64]) + .expect("Cannot fail since 32..64 is 32-byte length"); + } + output.write(0, &write_buf); + + Ok(()) + } +} + +impl Impl for Bn128MulImpl { + // Can fail if first paramter (bn128 curve point) does not actually belong to the curve + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + use bn::AffineG1; + + let mut padded_input = input.chain(io::repeat(0)); + let p = read_point(&mut padded_input)?; + let fr = read_fr(&mut padded_input)?; + + let mut write_buf = [0u8; 64]; + if let Some(sum) = AffineG1::from_jacobian(p * fr) { + // point not at infinity + sum.x() + .to_big_endian(&mut write_buf[0..32]) + .expect("Cannot fail since 0..32 is 32-byte length"); + sum.y() + .to_big_endian(&mut write_buf[32..64]) + .expect("Cannot fail since 32..64 is 32-byte length"); + } + output.write(0, &write_buf); + Ok(()) + } +} + +impl Impl for Bn128PairingImpl { + /// Can fail if: + /// - input length is not a multiple of 192 + /// - any of odd points does not belong to bn128 curve + /// - any of even points does not belong to the twisted bn128 curve over the field F_p^2 = F_p[i] / (i^2 + 1) + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + if input.len() % 192 != 0 { + return Err("Invalid input length, must be multiple of 192 (3 * (32*2))".into()); + } + + if let Err(err) = self.execute_with_error(input, output) { + panic!("Pairining error: {:?}", err); + } + Ok(()) + } +} + +impl Bn128PairingImpl { + fn execute_with_error(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + use bn::{pairing, AffineG1, AffineG2, Fq, Fq2, Group, Gt, G1, G2}; + + let elements = input.len() / 192; // (a, b_a, b_b - each 64-byte affine coordinates) + let ret_val = if input.is_empty() { + U256::one() + } else { + let mut vals = Vec::new(); + for idx in 0..elements { + let a_x = Fq::from_slice(&input[idx * 192..idx * 192 + 32]) + .map_err(|_| Error::from("Invalid a argument x coordinate"))?; + + let a_y = Fq::from_slice(&input[idx * 192 + 32..idx * 192 + 64]) + .map_err(|_| Error::from("Invalid a argument y coordinate"))?; + + let b_a_y = Fq::from_slice(&input[idx * 192 + 64..idx * 192 + 96]) + .map_err(|_| Error::from("Invalid b argument imaginary coeff x coordinate"))?; + + let b_a_x = Fq::from_slice(&input[idx * 192 + 96..idx * 192 + 128]) + .map_err(|_| Error::from("Invalid b argument imaginary coeff y coordinate"))?; + + let b_b_y = Fq::from_slice(&input[idx * 192 + 128..idx * 192 + 160]) + .map_err(|_| Error::from("Invalid b argument real coeff x coordinate"))?; + + let b_b_x = Fq::from_slice(&input[idx * 192 + 160..idx * 192 + 192]) + .map_err(|_| Error::from("Invalid b argument real coeff y coordinate"))?; + + let b_a = Fq2::new(b_a_x, b_a_y); + let b_b = Fq2::new(b_b_x, b_b_y); + let b = if b_a.is_zero() && b_b.is_zero() { + G2::zero() + } else { + G2::from( + AffineG2::new(b_a, b_b) + .map_err(|_| Error::from("Invalid b argument - not on curve"))?, + ) + }; + let a = if a_x.is_zero() && a_y.is_zero() { + G1::zero() + } else { + G1::from( + AffineG1::new(a_x, a_y) + .map_err(|_| Error::from("Invalid a argument - not on curve"))?, + ) + }; + vals.push((a, b)); + } + + let mul = vals.into_iter().fold(Gt::one(), |s, (a, b)| s * pairing(a, b)); + + if mul == Gt::one() { + U256::one() + } else { + U256::zero() + } + }; + + let mut buf = [0u8; 32]; + ret_val.to_big_endian(&mut buf); + output.write(0, &buf); + + Ok(()) + } +} + +/// The precomputed values for BLAKE2b [from the spec](https://tools.ietf.org/html/rfc7693#section-2.7) +/// There are 10 16-byte arrays - one for each round +/// the entries are calculated from the sigma constants. +const SIGMA: [[usize; 16]; 10] = [ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], + [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], + [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], + [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], + [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], + [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], + [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], + [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], + [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], +]; + +/// IV is the initialization vector for BLAKE2b. See https://tools.ietf.org/html/rfc7693#section-2.6 +/// for details. +const IV: [u64; 8] = [ + 0x6a09e667f3bcc908, + 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, + 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, + 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, + 0x5be0cd19137e2179, +]; + +#[inline(always)] +#[allow(clippy::many_single_char_names)] +fn g(v: &mut [u64], a: usize, b: usize, c: usize, d: usize, x: u64, y: u64) { + v[a] = v[a].wrapping_add(v[b]).wrapping_add(x); + v[d] = (v[d] ^ v[a]).rotate_right(32); + v[c] = v[c].wrapping_add(v[d]); + v[b] = (v[b] ^ v[c]).rotate_right(24); + + v[a] = v[a].wrapping_add(v[b]).wrapping_add(y); + v[d] = (v[d] ^ v[a]).rotate_right(16); + v[c] = v[c].wrapping_add(v[d]); + v[b] = (v[b] ^ v[c]).rotate_right(63); +} + +/// The Blake2b compression function F. See https://tools.ietf.org/html/rfc7693#section-3.2 +/// Takes as an argument the state vector `h`, message block vector `m`, offset counter `t`, final +/// block indicator flag `f`, and number of rounds `rounds`. The state vector provided as the first +/// parameter is modified by the function. +#[allow(clippy::many_single_char_names)] +pub fn compress(h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool, rounds: usize) { + let mut v = [0u64; 16]; + v[..8].copy_from_slice(h); // First half from state. + v[8..].copy_from_slice(&IV); // Second half from IV. + + v[12] ^= t[0]; + v[13] ^= t[1]; + + if f { + v[14] = !v[14]; // Invert all bits if the last-block-flag is set. + } + + for i in 0..rounds { + // Message word selection permutation for this round. + let s = &SIGMA[i % 10]; + g(&mut v, 0, 4, 8, 12, m[s[0]], m[s[1]]); + g(&mut v, 1, 5, 9, 13, m[s[2]], m[s[3]]); + g(&mut v, 2, 6, 10, 14, m[s[4]], m[s[5]]); + g(&mut v, 3, 7, 11, 15, m[s[6]], m[s[7]]); + + g(&mut v, 0, 5, 10, 15, m[s[8]], m[s[9]]); + g(&mut v, 1, 6, 11, 12, m[s[10]], m[s[11]]); + g(&mut v, 2, 7, 8, 13, m[s[12]], m[s[13]]); + g(&mut v, 3, 4, 9, 14, m[s[14]], m[s[15]]); + } + + for i in 0..8 { + h[i] ^= v[i] ^ v[i + 8]; + } +} + +impl Impl for Blake2FImpl { + /// Format of `input`: + /// [4 bytes for rounds][64 bytes for h][128 bytes for m][8 bytes for t_0][8 bytes for t_1][1 byte for f] + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + const BLAKE2_F_ARG_LEN: usize = 213; + const PROOF: &str = "Checked the length of the input above; qed"; + + if input.len() != BLAKE2_F_ARG_LEN { + panic!( + "input length for Blake2 F precompile should be exactly 213 bytes, was {}", + input.len() + ); + // return Err("input length for Blake2 F precompile should be exactly 213 bytes") + } + + let mut cursor = Cursor::new(input); + let rounds = cursor.read_u32::().expect(PROOF); + + // state vector, h + let mut h = [0u64; 8]; + for state_word in &mut h { + *state_word = cursor.read_u64::().expect(PROOF); + } + + // message block vector, m + let mut m = [0u64; 16]; + for msg_word in &mut m { + *msg_word = cursor.read_u64::().expect(PROOF); + } + + // 2w-bit offset counter, t + let t = [ + cursor.read_u64::().expect(PROOF), + cursor.read_u64::().expect(PROOF), + ]; + + // final block indicator flag, "f" + let f = match input.last() { + Some(1) => true, + Some(0) => false, + _ => { + panic!("incorrect final block indicator flag, was: {:?}", input.last()); + } + }; + + compress(&mut h, m, t, f, rounds as usize); + + let mut output_buf = [0u8; 8 * size_of::()]; + for (i, state_word) in h.iter().enumerate() { + output_buf[i * 8..(i + 1) * 8].copy_from_slice(&state_word.to_le_bytes()); + } + output.write(0, &output_buf[..]); + Ok(()) + } +} diff --git a/runtime/near-evm-runner/src/errors.rs b/runtime/near-evm-runner/src/errors.rs new file mode 100644 index 00000000000..a85e0552fa5 --- /dev/null +++ b/runtime/near-evm-runner/src/errors.rs @@ -0,0 +1,19 @@ +use ethereum_types::{Address, U256}; + +#[derive(Debug)] +pub enum EvmError { + /// Unknown error, catch all for unexpected things. + UnknownError, + /// Fatal failure due conflicting addresses on contract deployment. + DuplicateContract(Address), + /// Contract deployment failure. + DeployFail(Vec), + /// Contract execution failed, revert the state. + Revert(Vec), +} + +impl std::fmt::Display for EvmError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + f.write_str(&format!("{:?}", self)) + } +} diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs new file mode 100644 index 00000000000..6fa87ea7662 --- /dev/null +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -0,0 +1,465 @@ +use std::collections::{BTreeMap, HashMap, HashSet}; + +use ethereum_types::{Address, U256}; + +use near_primitives::{account::AccountId, types::Balance}; + +use crate::utils; + +pub trait EvmState { + fn code_at(&self, address: &Address) -> Option>; + fn set_code(&mut self, address: &Address, bytecode: &[u8]); + + fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]>; + fn set_balance(&mut self, address: &Address, balance: U256) -> Option { + let mut bin = [0u8; 32]; + balance.to_big_endian(&mut bin); + let internal_addr = utils::evm_account_to_internal_address(*address); + self._set_balance(internal_addr, bin).map(|v| v.into()) + } + + fn _balance_of(&self, address: [u8; 20]) -> [u8; 32]; + fn balance_of(&self, address: &Address) -> U256 { + let internal_addr = utils::evm_account_to_internal_address(*address); + self._balance_of(internal_addr).into() + } + + fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]>; + fn set_nonce(&mut self, address: &Address, nonce: U256) -> Option { + let mut bin = [0u8; 32]; + nonce.to_big_endian(&mut bin); + let internal_addr = utils::evm_account_to_internal_address(*address); + self._set_nonce(internal_addr, bin).map(|v| v.into()) + } + + fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32]; + fn nonce_of(&self, address: &Address) -> U256 { + let internal_addr = utils::evm_account_to_internal_address(*address); + self._nonce_of(internal_addr).into() + } + + fn next_nonce(&mut self, address: &Address) -> U256 { + let nonce = self.nonce_of(address); + self.set_nonce(address, nonce + 1); + nonce + } + + fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]>; + fn read_contract_storage(&self, address: &Address, key: [u8; 32]) -> Option<[u8; 32]> { + self._read_contract_storage(utils::internal_storage_key(address, key)) + } + + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Option<[u8; 32]>; + + fn set_contract_storage( + &mut self, + address: &Address, + key: [u8; 32], + value: [u8; 32], + ) -> Option<[u8; 32]> { + self._set_contract_storage(utils::internal_storage_key(address, key), value) + } + + fn commit_changes(&mut self, other: &StateStore); + + // Panics on u256 overflow + // This represents NEAR tokens, so it can never _actually_ go above 2**128 + // That'd be silly. + fn add_balance(&mut self, address: &Address, incr: U256) -> Option { + let balance = self.balance_of(address); + let new_balance = balance.checked_add(incr).expect("overflow during add_balance"); + self.set_balance(address, new_balance) + } + + // Panics if insufficient balance + fn sub_balance(&mut self, address: &Address, decr: U256) -> Option { + let balance = self.balance_of(address); + let new_balance = balance.checked_sub(decr).expect("underflow during sub_balance"); + self.set_balance(address, new_balance) + } + + fn transfer_balance(&mut self, sender: &Address, recipient: &Address, amnt: U256) { + self.sub_balance(sender, amnt); + self.add_balance(recipient, amnt); + } +} + +#[derive(Default, Debug)] +pub struct StateStore { + pub code: HashMap<[u8; 20], Vec>, + pub balances: HashMap<[u8; 20], [u8; 32]>, + pub nonces: HashMap<[u8; 20], [u8; 32]>, + pub storages: BTreeMap, [u8; 32]>, + pub logs: Vec, + pub self_destructs: HashSet<[u8; 20]>, + pub recreated: HashSet<[u8; 20]>, +} + +impl StateStore { + fn overwrite_storage(&mut self, addr: [u8; 20]) { + let address_key = addr.to_vec(); + let mut next_address_key = address_key.clone(); + *(next_address_key.last_mut().unwrap()) += 1; + + let range = + (std::ops::Bound::Excluded(address_key), std::ops::Bound::Excluded(next_address_key)); + + let keys: Vec<_> = self.storages.range(range).map(|(k, _)| k.clone()).collect(); + for k in keys.iter() { + self.storages.remove(k); + } + } + + pub fn recreate(&mut self, addr: [u8; 20]) { + self.code.remove(&addr); + // We do not delete balance here, as balances persist across recreation + self.nonces.remove(&addr); + self.overwrite_storage(addr); + self.self_destructs.remove(&addr); + self.recreated.insert(addr); + } + + pub fn commit_code(&mut self, other: &HashMap<[u8; 20], Vec>) { + self.code.extend(other.iter().map(|(k, v)| (*k, v.clone()))); + } + + pub fn commit_balances(&mut self, other: &HashMap<[u8; 20], [u8; 32]>) { + self.balances.extend(other.iter().map(|(k, v)| (*k, *v))); + } + + pub fn commit_nonces(&mut self, other: &HashMap<[u8; 20], [u8; 32]>) { + self.nonces.extend(other.iter().map(|(k, v)| (*k, *v))); + } + + pub fn commit_storages(&mut self, other: &BTreeMap, [u8; 32]>) { + self.storages.extend(other.iter().map(|(k, v)| (k.clone(), *v))) + } + + pub fn commit_self_destructs(&mut self, other: &HashSet<[u8; 20]>) { + self.self_destructs.extend(other); + } + + pub fn commit_recreated(&mut self, other: &HashSet<[u8; 20]>) { + self.recreated.extend(other); + } +} + +impl EvmState for StateStore { + fn code_at(&self, address: &Address) -> Option> { + let internal_addr = utils::evm_account_to_internal_address(*address); + if self.self_destructs.contains(&internal_addr) { + None + } else { + self.code.get(&internal_addr).cloned() + } + } + + fn set_code(&mut self, address: &Address, bytecode: &[u8]) { + let internal_addr = utils::evm_account_to_internal_address(*address); + self.code.insert(internal_addr, bytecode.to_vec()); + } + + fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { + self.balances.get(&address).copied().unwrap_or([0u8; 32]) + } + + fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]> { + self.balances.insert(address, balance) + } + + fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32] { + let empty = [0u8; 32]; + if self.self_destructs.contains(&address) { + empty + } else { + self.nonces.get(&address).copied().unwrap_or(empty) + } + } + + fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { + self.nonces.insert(address, nonce) + } + + fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { + let mut addr = [0u8; 20]; + addr.copy_from_slice(&key[..20]); + if self.self_destructs.contains(&addr) { + None + } else { + self.storages.get(&key.to_vec()).cloned() + } + } + + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Option<[u8; 32]> { + self.storages.insert(key.to_vec(), value) + } + + fn commit_changes(&mut self, other: &StateStore) { + self.commit_self_destructs(&other.self_destructs); + self.commit_recreated(&other.recreated); + self.commit_code(&other.code); + self.commit_balances(&other.balances); + self.commit_nonces(&other.nonces); + self.commit_storages(&other.storages); + self.logs.extend(other.logs.iter().cloned()); + } +} + +pub struct SubState<'a> { + pub msg_sender: &'a Address, + pub state: &'a mut StateStore, + pub parent: &'a dyn EvmState, +} + +impl SubState<'_> { + pub fn new<'a>( + msg_sender: &'a Address, + state: &'a mut StateStore, + parent: &'a dyn EvmState, + ) -> SubState<'a> { + SubState { msg_sender, state, parent } + } +} + +impl EvmState for SubState<'_> { + fn code_at(&self, address: &Address) -> Option> { + let internal_addr = utils::evm_account_to_internal_address(*address); + if self.state.self_destructs.contains(&internal_addr) { + None + } else { + self.state + .code + .get(&internal_addr) + .map_or_else(|| self.parent.code_at(address), |k| Some(k.to_vec())) + } + } + + fn set_code(&mut self, address: &Address, bytecode: &[u8]) { + let internal_addr = utils::evm_account_to_internal_address(*address); + self.state.code.insert(internal_addr, bytecode.to_vec()); + } + + fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { + self.state.balances.get(&address).map_or_else(|| self.parent._balance_of(address), |k| *k) + } + + fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]> { + self.state.balances.insert(address, balance) + } + + fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32] { + let empty = [0u8; 32]; + if self.state.self_destructs.contains(&address) { + empty + } else { + self.state.nonces.get(&address).map_or_else(|| self.parent._nonce_of(address), |k| *k) + } + } + + fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { + self.state.nonces.insert(address, nonce) + } + + fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { + let mut addr = [0u8; 20]; + addr.copy_from_slice(&key[..20]); + if self.state.self_destructs.contains(&addr) { + None + } else { + self.state + .storages + .get(&key.to_vec()) + .copied() + .or_else(|| self.parent._read_contract_storage(key)) + } + } + + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Option<[u8; 32]> { + self.state.storages.insert(key.to_vec(), value) + } + + fn commit_changes(&mut self, other: &StateStore) { + self.state.commit_self_destructs(&other.self_destructs); + self.state.commit_recreated(&other.recreated); + self.state.commit_code(&other.code); + self.state.commit_balances(&other.balances); + self.state.commit_nonces(&other.nonces); + self.state.commit_storages(&other.storages); + self.state.logs.extend(other.logs.iter().cloned()); + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn substate_tests() { + let addr_0 = Address::repeat_byte(0); + let addr_1 = Address::repeat_byte(1); + let addr_2 = Address::repeat_byte(2); + // let addr_3 = Address::repeat_byte(3); + let zero = U256::zero(); + let code: [u8; 3] = [0, 1, 2]; + let nonce = U256::from_dec_str("103030303").unwrap(); + let balance = U256::from_dec_str("3838209").unwrap(); + let storage_key_0 = [4u8; 32]; + let storage_key_1 = [5u8; 32]; + let storage_value_0 = [6u8; 32]; + let storage_value_1 = [7u8; 32]; + + // Create the top-level store + let mut top = StateStore::default(); + + top.set_code(&addr_0, &code); + assert_eq!(top.code_at(&addr_0), Some(code.to_vec())); + assert_eq!(top.code_at(&addr_1), None); + assert_eq!(top.code_at(&addr_2), None); + + top.set_nonce(&addr_0, nonce); + assert_eq!(top.nonce_of(&addr_0), nonce); + assert_eq!(top.nonce_of(&addr_1), zero); + assert_eq!(top.nonce_of(&addr_2), zero); + + top.set_balance(&addr_0, balance); + assert_eq!(top.balance_of(&addr_0), balance); + assert_eq!(top.balance_of(&addr_1), zero); + assert_eq!(top.balance_of(&addr_2), zero); + + top.set_contract_storage(&addr_0, storage_key_0, storage_value_0); + assert_eq!(top.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); + assert_eq!(top.read_contract_storage(&addr_1, storage_key_0), None); + assert_eq!(top.read_contract_storage(&addr_2, storage_key_0), None); + + let next = { + // Open a new store + let mut next = StateStore::default(); + let mut sub_1 = SubState::new(&addr_0, &mut next, &mut top); + + sub_1.set_code(&addr_1, &code); + assert_eq!(sub_1.code_at(&addr_0), Some(code.to_vec())); + assert_eq!(sub_1.code_at(&addr_1), Some(code.to_vec())); + assert_eq!(sub_1.code_at(&addr_2), None); + + sub_1.set_nonce(&addr_1, nonce); + assert_eq!(sub_1.nonce_of(&addr_0), nonce); + assert_eq!(sub_1.nonce_of(&addr_1), nonce); + assert_eq!(sub_1.nonce_of(&addr_2), zero); + + sub_1.set_balance(&addr_1, balance); + assert_eq!(sub_1.balance_of(&addr_0), balance); + assert_eq!(sub_1.balance_of(&addr_1), balance); + assert_eq!(sub_1.balance_of(&addr_2), zero); + + sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_0); + assert_eq!(sub_1.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); + assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_0), Some(storage_value_0)); + assert_eq!(sub_1.read_contract_storage(&addr_2, storage_key_0), None); + + sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_1); + assert_eq!(sub_1.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); + assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_0), Some(storage_value_1)); + assert_eq!(sub_1.read_contract_storage(&addr_2, storage_key_0), None); + + sub_1.set_contract_storage(&addr_1, storage_key_1, storage_value_1); + assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_0), Some(storage_value_1)); + assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_1), Some(storage_value_1)); + + sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_0); + assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_0), Some(storage_value_0)); + assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_1), Some(storage_value_1)); + + next + }; + + top.commit_changes(&next); + assert_eq!(top.code_at(&addr_0), Some(code.to_vec())); + assert_eq!(top.code_at(&addr_1), Some(code.to_vec())); + assert_eq!(top.code_at(&addr_2), None); + assert_eq!(top.nonce_of(&addr_0), nonce); + assert_eq!(top.nonce_of(&addr_1), nonce); + assert_eq!(top.nonce_of(&addr_2), zero); + assert_eq!(top.balance_of(&addr_0), balance); + assert_eq!(top.balance_of(&addr_1), balance); + assert_eq!(top.balance_of(&addr_2), zero); + assert_eq!(top.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); + assert_eq!(top.read_contract_storage(&addr_1, storage_key_0), Some(storage_value_0)); + assert_eq!(top.read_contract_storage(&addr_1, storage_key_1), Some(storage_value_1)); + assert_eq!(top.read_contract_storage(&addr_2, storage_key_0), None); + } + + #[test] + fn self_destruct_tests() { + let addr_0 = Address::repeat_byte(0); + let addr_1 = Address::repeat_byte(1); + let zero = U256::zero(); + let code: [u8; 3] = [0, 1, 2]; + let nonce = U256::from_dec_str("103030303").unwrap(); + let balance_0 = U256::from_dec_str("3838209").unwrap(); + let balance_1 = U256::from_dec_str("11223344").unwrap(); + let storage_key_0 = [4u8; 32]; + let storage_key_1 = [5u8; 32]; + let storage_value_0 = [6u8; 32]; + let storage_value_1 = [7u8; 32]; + + // Create the top-level store + let mut top = StateStore::default(); + + top.set_code(&addr_0, &code); + top.set_nonce(&addr_0, nonce); + top.set_balance(&addr_0, balance_0); + top.set_contract_storage(&addr_0, storage_key_0, storage_value_0); + + top.set_code(&addr_1, &code); + top.set_nonce(&addr_1, nonce); + top.set_balance(&addr_1, balance_0); + top.set_contract_storage(&addr_1, storage_key_1, storage_value_1); + + assert_eq!(top.code_at(&addr_0), Some(code.to_vec())); + assert_eq!(top.code_at(&addr_1), Some(code.to_vec())); + + assert_eq!(top.nonce_of(&addr_0), nonce); + assert_eq!(top.nonce_of(&addr_1), nonce); + + assert_eq!(top.balance_of(&addr_0), balance_0); + assert_eq!(top.balance_of(&addr_1), balance_0); + + assert_eq!(top.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); + assert_eq!(top.read_contract_storage(&addr_1, storage_key_1), Some(storage_value_1)); + + let next = { + // Open a new store + let mut next = StateStore::default(); + let mut sub_1 = SubState::new(&addr_0, &mut next, &mut top); + + assert_eq!(sub_1.code_at(&addr_1), Some(code.to_vec())); + assert_eq!(sub_1.nonce_of(&addr_1), nonce); + assert_eq!(sub_1.balance_of(&addr_1), balance_0); + assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_1), Some(storage_value_1)); + + sub_1.state.self_destructs.insert(addr_1.0); + sub_1.set_balance(&addr_1, balance_1); + + assert_eq!(sub_1.code_at(&addr_1), None); + assert_eq!(sub_1.nonce_of(&addr_1), zero); + assert_eq!(sub_1.balance_of(&addr_1), balance_1); + assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_1), None); + + next + }; + + top.commit_changes(&next); + + assert_eq!(top.code_at(&addr_0), Some(code.to_vec())); + assert_eq!(top.code_at(&addr_1), None); + + assert_eq!(top.nonce_of(&addr_0), nonce); + assert_eq!(top.nonce_of(&addr_1), zero); + + assert_eq!(top.balance_of(&addr_0), balance_0); + assert_eq!(top.balance_of(&addr_1), balance_1); + + assert_eq!(top.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); + assert_eq!(top.read_contract_storage(&addr_1, storage_key_1), None); + } +} diff --git a/runtime/near-evm-runner/src/interpreter.rs b/runtime/near-evm-runner/src/interpreter.rs new file mode 100644 index 00000000000..cd72af5050b --- /dev/null +++ b/runtime/near-evm-runner/src/interpreter.rs @@ -0,0 +1,265 @@ +use std::sync::Arc; + +use ethereum_types::{Address, U256}; +use evm::{CreateContractAddress, Factory}; +use vm::{ActionParams, ActionValue, CallType, Ext, GasLeft, ParamsType, ReturnData, Schedule}; + +use crate::errors::EvmError; +use crate::evm_state::{EvmState, StateStore, SubState}; +use crate::near_ext::NearExt; +use crate::utils; + +pub fn deploy_code( + state: &mut T, + origin: &Address, + sender: &Address, + value: U256, + call_stack_depth: usize, + code: &[u8], +) -> Result { + let nonce = state.next_nonce(&sender); + let (address, _) = utils::evm_contract_address( + CreateContractAddress::FromSenderAndNonce, + &sender, + &nonce, + &code, + ); + + if state.code_at(&address).is_some() { + return Err(EvmError::DuplicateContract(address)); + } + + let (result, state_updates) = + _create(state, origin, sender, value, call_stack_depth, &address, code); + + // Apply known gas amount changes (all reverts are NeedsReturn) + // Apply NeedsReturn changes if apply_state + // Return the result unmodified + let (return_data, apply) = match result { + Some(GasLeft::Known(_)) => (ReturnData::empty(), true), + Some(GasLeft::NeedsReturn { gas_left: _, data, apply_state }) => (data, apply_state), + _ => return Err(EvmError::UnknownError), + }; + + if apply { + state.commit_changes(&state_updates.unwrap()); + state.set_code(&address, &return_data.to_vec()); + } else { + return Err(EvmError::DeployFail(return_data.to_vec())); + } + Ok(address) +} + +pub fn _create( + state: &mut T, + origin: &Address, + sender: &Address, + value: U256, + call_stack_depth: usize, + address: &Address, + code: &[u8], +) -> (Option, Option) { + let mut store = StateStore::default(); + let mut sub_state = SubState::new(sender, &mut store, state); + + let params = ActionParams { + code_address: *address, + address: *address, + sender: *sender, + origin: *origin, + gas: 1_000_000_000.into(), + gas_price: 1.into(), + value: ActionValue::Transfer(value), + code: Some(Arc::new(code.to_vec())), + code_hash: None, + data: None, + call_type: CallType::None, + params_type: vm::ParamsType::Embedded, + }; + + sub_state.transfer_balance(sender, address, value); + + let mut ext = NearExt::new(*address, *origin, &mut sub_state, call_stack_depth + 1, false); + ext.info.gas_limit = U256::from(1_000_000_000); + ext.schedule = Schedule::new_constantinople(); + + let instance = Factory::default().create(params, ext.schedule(), ext.depth()); + + // Run the code + let result = instance.exec(&mut ext); + + (result.ok().unwrap().ok(), Some(store)) +} + +#[allow(clippy::too_many_arguments)] +pub fn call( + state: &mut T, + origin: &Address, + sender: &Address, + value: Option, + call_stack_depth: usize, + contract_address: &Address, + input: &[u8], + should_commit: bool, +) -> Result { + run_and_commit_if_success( + state, + origin, + sender, + value, + call_stack_depth, + CallType::Call, + contract_address, + contract_address, + input, + false, + should_commit, + ) +} + +pub fn delegate_call( + state: &mut T, + origin: &Address, + sender: &Address, + call_stack_depth: usize, + context: &Address, + delegee: &Address, + input: &[u8], +) -> Result { + run_and_commit_if_success( + state, + origin, + sender, + None, + call_stack_depth, + CallType::DelegateCall, + context, + delegee, + input, + false, + true, + ) +} + +pub fn static_call( + state: &mut T, + origin: &Address, + sender: &Address, + call_stack_depth: usize, + contract_address: &Address, + input: &[u8], +) -> Result { + run_and_commit_if_success( + state, + origin, + sender, + None, + call_stack_depth, + CallType::StaticCall, + contract_address, + contract_address, + input, + true, + false, + ) +} + +#[allow(clippy::too_many_arguments)] +fn run_and_commit_if_success( + state: &mut T, + origin: &Address, + sender: &Address, + value: Option, + call_stack_depth: usize, + call_type: CallType, + state_address: &Address, + code_address: &Address, + input: &[u8], + is_static: bool, + should_commit: bool, +) -> Result { + // run the interpreter and + let (result, state_updates) = run_against_state( + state, + origin, + sender, + value, + call_stack_depth, + call_type, + state_address, + code_address, + input, + is_static, + ); + + // Apply known gas amount changes (all reverts are NeedsReturn) + // Apply NeedsReturn changes if apply_state + // Return the result unmodified + let return_data = match result { + Some(GasLeft::Known(_)) => Ok(ReturnData::empty()), + Some(GasLeft::NeedsReturn { gas_left: _, data, apply_state: true }) => Ok(data), + Some(GasLeft::NeedsReturn { gas_left: _, data, apply_state: false }) => { + Err(EvmError::Revert(data.to_vec())) + } + _ => Err(EvmError::UnknownError), + }; + + // Don't apply changes from a static context (these _should_ error in the ext) + if !is_static && return_data.is_ok() && should_commit { + state.commit_changes(&state_updates.unwrap()); + } + + return_data +} + +/// Runs the interpreter. Produces state diffs +#[allow(clippy::too_many_arguments)] +fn run_against_state( + state: &mut T, + origin: &Address, + sender: &Address, + value: Option, + call_stack_depth: usize, + call_type: CallType, + state_address: &Address, + code_address: &Address, + input: &[u8], + is_static: bool, +) -> (Option, Option) { + let code = state.code_at(code_address).unwrap_or_else(Vec::new); + + let mut store = StateStore::default(); + let mut sub_state = SubState::new(sender, &mut store, state); + + let mut params = ActionParams { + code_address: *code_address, + code_hash: None, + address: *state_address, + sender: *sender, + origin: *origin, + gas: 1_000_000_000.into(), + gas_price: 1.into(), + value: ActionValue::Apparent(0.into()), + code: Some(Arc::new(code)), + data: Some(input.to_vec()), + call_type, + params_type: ParamsType::Separate, + }; + + if let Some(val) = value { + params.value = ActionValue::Transfer(val); + // substate transfer will get reverted if the call fails + sub_state.transfer_balance(sender, state_address, val); + } + + let mut ext = + NearExt::new(*state_address, *origin, &mut sub_state, call_stack_depth + 1, is_static); + ext.info.gas_limit = U256::from(1_000_000_000); + ext.schedule = Schedule::new_constantinople(); + + let instance = Factory::default().create(params, ext.schedule(), ext.depth()); + + // Run the code + let result = instance.exec(&mut ext); + (result.ok().unwrap().ok(), Some(store)) +} diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs new file mode 100644 index 00000000000..2b251e64fb6 --- /dev/null +++ b/runtime/near-evm-runner/src/lib.rs @@ -0,0 +1,97 @@ +mod builtins; +mod errors; +mod evm_state; +mod interpreter; +mod near_ext; +mod utils; + +use crate::evm_state::{EvmState, StateStore}; +use ethereum_types::H160; +use near_primitives::{account::AccountId, types::Balance}; +use near_vm_errors::VMError; +use near_vm_logic::VMOutcome; +use vm::Address; + +struct EvmContext { + sender_id: AccountId, + attached_deposit: Balance, +} + +impl EvmState for EvmContext { + fn code_at(&self, address: &H160) -> Option> { + unimplemented!() + } + + fn set_code(&mut self, address: &H160, bytecode: &[u8]) { + unimplemented!() + } + + fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]> { + unimplemented!() + } + + fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { + unimplemented!() + } + + fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { + unimplemented!() + } + + fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32] { + unimplemented!() + } + + fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { + unimplemented!() + } + + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Option<[u8; 32]> { + unimplemented!() + } + + fn commit_changes(&mut self, other: &StateStore) { + unimplemented!() + } +} + +pub fn run_evm( + sender_id: AccountId, + attached_deposit: Balance, + method_name: String, + args: Vec, +) -> (Option, Option) { + let mut context = EvmContext { sender_id, attached_deposit }; + let sender = utils::near_account_id_to_evm_address(sender_id); + let result = match method_name.as_str() { + "deploy_code" => interpreter::deploy_code(&mut context, &sender, &sender, val, 0, &args), + "get_code" => { + let address = Address::from(args); + context.get_code(address) + } + "call_function" => { + let contract_address = args[:20]; + let input = args[20:]; + let result = interpreter::call( + &mut context, + sender, + sender, + value, + 0, // call-stack depth + &contract_address, + &input, + true, + ); + } + _ => (), + }; + (None, None) +} + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs new file mode 100644 index 00000000000..3b3028a80f0 --- /dev/null +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -0,0 +1,345 @@ +use std::sync::Arc; + +use ethereum_types::{Address, H160, H256, U256}; +use keccak_hash::keccak; +use parity_bytes::Bytes; +use vm::{ + CallType, ContractCreateResult, CreateContractAddress, EnvInfo, Error as VmError, + MessageCallResult, Result as EvmResult, ReturnData, Schedule, TrapKind, +}; + +use crate::evm_state::{EvmState, SubState}; +use crate::interpreter; +use crate::utils; + +// https://github.com/paritytech/parity-ethereum/blob/77643c13e80ca09d9a6b10631034f5a1568ba6d3/ethcore/machine/src/externalities.rs +// #[derive(Debug)] +pub struct NearExt<'a> { + pub info: EnvInfo, + pub origin: Address, + pub schedule: Schedule, + pub context_addr: Address, + pub selfdestruct_address: Option
, + pub sub_state: &'a mut SubState<'a>, + pub static_flag: bool, + pub depth: usize, +} + +impl std::fmt::Debug for NearExt<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "\nNearExt {{")?; + write!(f, "\n\tinfo: {:?}", self.info)?; + write!(f, "\n\torigin: {:?}", self.origin)?; + write!(f, "\n\tcontext_addr: {:?}", self.context_addr)?; + write!(f, "\n\tstatic_flag: {:?}", self.static_flag)?; + write!(f, "\n\tdepth: {:?}", self.depth)?; + write!(f, "\n}}") + } +} + +impl<'a> NearExt<'a> { + pub fn new( + context_addr: Address, + origin: Address, + sub_state: &'a mut SubState<'a>, + depth: usize, + static_flag: bool, + ) -> Self { + Self { + info: Default::default(), + origin, + schedule: Default::default(), + context_addr, + selfdestruct_address: Default::default(), + sub_state, + static_flag, + depth, + } + } +} + +fn not_implemented(name: &str) { + // near_sdk::env::log(format!("not implemented: {}", name).as_bytes()); +} + +impl<'a> vm::Ext for NearExt<'a> { + /// Returns the storage value for a given key if reversion happens on the current transaction. + fn initial_storage_at(&self, key: &H256) -> EvmResult { + let raw_val = self + .sub_state + .parent // Read from the unmodified parent state + .read_contract_storage(&self.context_addr, key.0) + .unwrap_or([0u8; 32]); // default to an empty value + Ok(H256(raw_val)) + } + + /// Returns a value for given key. + fn storage_at(&self, key: &H256) -> EvmResult { + let raw_val = + self.sub_state.read_contract_storage(&self.context_addr, key.0).unwrap_or([0u8; 32]); // default to an empty value + Ok(H256(raw_val)) + } + + /// Stores a value for given key. + fn set_storage(&mut self, key: H256, value: H256) -> EvmResult<()> { + if self.is_static() { + return Err(VmError::MutableCallInStaticContext); + } + self.sub_state.set_contract_storage(&self.context_addr, key.0, value.0); + Ok(()) + } + + // TODO: research why these are different + fn exists(&self, address: &Address) -> EvmResult { + Ok(self.sub_state.balance_of(address) > U256::from(0) + || self.sub_state.code_at(address).is_some()) + } + + fn exists_and_not_null(&self, address: &Address) -> EvmResult { + Ok(self.sub_state.balance_of(address) > 0.into() + || self.sub_state.code_at(address).is_some()) + } + + fn origin_balance(&self) -> EvmResult { + // self.balance(&utils::predecessor_as_evm()) + // TODO: ?? + self.balance(&H160([0; 20])) + } + + fn balance(&self, address: &Address) -> EvmResult { + Ok(self.sub_state.balance_of(address)) + } + + fn blockhash(&mut self, number: &U256) -> H256 { + let mut buf = [0u8; 32]; + number.to_big_endian(&mut buf); + keccak(&buf[..]) + } + + fn create( + &mut self, + _gas: &U256, + value: &U256, + code: &[u8], + address_type: CreateContractAddress, + _trap: bool, + ) -> Result { + if self.is_static() { + panic!("MutableCallInStaticContext") + } + + let mut nonce = U256::default(); + // TODO: move this into deploy_code + if address_type == CreateContractAddress::FromSenderAndNonce { + nonce = self.sub_state.next_nonce(&self.context_addr); + }; + + // discarded argument here is the codehash. + // CONSIDER: storing codehash instead of calculating + let (addr, _) = utils::evm_contract_address(address_type, &self.context_addr, &nonce, code); + self.sub_state.state.recreate(addr.0); + + interpreter::deploy_code( + self.sub_state, + &self.origin, + &self.context_addr, + *value, + self.depth, + &addr, + &code.to_vec(), + ); + + Ok(ContractCreateResult::Created(addr, 1_000_000_000.into())) + } + + /// Message call. + /// + /// Returns Err, if we run out of gas. + /// Otherwise returns call_result which contains gas left + /// and true if subcall was successful. + fn call( + &mut self, + _gas: &U256, + sender_address: &Address, + receive_address: &Address, + value: Option, + data: &[u8], + code_address: &Address, + call_type: CallType, + _trap: bool, + ) -> Result { + if self.is_static() && call_type != CallType::StaticCall { + panic!("MutableCallInStaticContext") + } + + // hijack builtins + if crate::builtins::is_precompile(receive_address) { + return Ok(crate::builtins::process_precompile(receive_address, data)); + } + + let result = match call_type { + CallType::None => { + // Can stay unimplemented + not_implemented("CallType=None"); + unimplemented!() + } + CallType::Call => interpreter::call( + self.sub_state, + &self.origin, + sender_address, + value, + self.depth, + receive_address, + &data.to_vec(), + true, // should_commit + ), + CallType::StaticCall => interpreter::static_call( + self.sub_state, + &self.origin, + sender_address, + self.depth, + receive_address, + &data.to_vec(), + ), + CallType::CallCode => { + // Call another contract using storage of the current contract + // Can leave unimplemented, no longer used. + not_implemented("CallCode"); + unimplemented!() + } + CallType::DelegateCall => interpreter::delegate_call( + self.sub_state, + &self.origin, + sender_address, + self.depth, + receive_address, + code_address, + &data.to_vec(), + ), + }; + + let msg_call_result = match result { + Ok(data) => MessageCallResult::Success(1_000_000_000.into(), data), + Err(err) => { + let message = err.to_string().as_bytes().to_vec(); + let message_len = message.len(); + MessageCallResult::Reverted( + 1_000_000_000.into(), + ReturnData::new(message, 0, message_len), + ) + } + }; + Ok(msg_call_result) + } + + /// Returns code at given address + fn extcode(&self, address: &Address) -> EvmResult>> { + let code = self.sub_state.code_at(address).map(Arc::new); + Ok(code) + } + + /// Returns code hash at given address + fn extcodehash(&self, address: &Address) -> EvmResult> { + let code_opt = self.sub_state.code_at(address); + let code = match code_opt { + Some(code) => code, + None => return Ok(None), + }; + if code.is_empty() { + Ok(None) + } else { + Ok(Some(keccak(code))) + } + } + + /// Returns code size at given address + fn extcodesize(&self, address: &Address) -> EvmResult> { + Ok(self.sub_state.code_at(address).map(|c| c.len())) + } + + /// Creates log entry with given topics and data + fn log(&mut self, _topics: Vec, data: &[u8]) -> EvmResult<()> { + if self.is_static() { + return Err(VmError::MutableCallInStaticContext); + } + + // TODO: Develop a NearCall logspec + // hijack NearCall logs here + // make a Vec that accumulates committed logs + // return them after execution completes + // dispatch promises + + self.sub_state.state.logs.push(hex::encode(data)); + Ok(()) + } + + /// Should be called when transaction calls `RETURN` opcode. + /// Returns gas_left if cost of returning the data is not too high. + fn ret(self, _gas: &U256, _data: &ReturnData, _apply_state: bool) -> EvmResult { + // NOTE: this is only called through finalize(), but we are not using it + // so it should be safe to ignore it here + not_implemented("ret"); + unimplemented!() + } + + /// Should be called when contract commits suicide. + /// Address to which funds should be refunded. + /// Deletes code, moves balance + fn suicide(&mut self, refund_address: &Address) -> EvmResult<()> { + self.sub_state.state.self_destructs.insert(self.context_addr.0); + + let balance = self.sub_state.balance_of(&self.context_addr); + self.sub_state.add_balance(refund_address, balance); + self.sub_state.sub_balance(&self.context_addr, balance); + Ok(()) + } + + /// Returns schedule. + fn schedule(&self) -> &Schedule { + &self.schedule + } + + /// Returns environment info. + fn env_info(&self) -> &EnvInfo { + &self.info + } + + /// Returns current depth of execution. + /// + /// If contract A calls contract B, and contract B calls C, + /// then A depth is 0, B is 1, C is 2 and so on. + fn depth(&self) -> usize { + self.depth + } + + /// Increments sstore refunds counter. + fn add_sstore_refund(&mut self, _value: usize) {} + + /// Decrements sstore refunds counter. + /// Left as NOP as evm gas is not metered + fn sub_sstore_refund(&mut self, _value: usize) {} + + /// Decide if any more operations should be traced. Passthrough for the VM trace. + fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8, _current_gas: U256) -> bool { + false + } + + /// Prepare to trace an operation. Passthrough for the VM trace. + fn trace_prepare_execute( + &mut self, + _pc: usize, + _instruction: u8, + _gas_cost: U256, + _mem_written: Option<(usize, usize)>, + _store_written: Option<(U256, U256)>, + ) { + } + + /// Trace the finalised execution of a single instruction. + fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem: &[u8]) {} + + /// Check if running in static context. + fn is_static(&self) -> bool { + self.static_flag + } +} diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs new file mode 100644 index 00000000000..68a450d8116 --- /dev/null +++ b/runtime/near-evm-runner/src/utils.rs @@ -0,0 +1,120 @@ +use ethereum_types::{Address, H256, U256}; +use keccak_hash::keccak; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use vm::CreateContractAddress; + +pub fn internal_storage_key(address: &Address, key: [u8; 32]) -> [u8; 52] { + let mut k = [0u8; 52]; + k[..20].copy_from_slice(address.as_ref()); + k[20..].copy_from_slice(&key); + k +} + +pub fn evm_account_to_internal_address(addr: Address) -> [u8; 20] { + addr.0 +} + +pub fn near_account_bytes_to_evm_address(addr: &[u8]) -> Address { + Address::from_slice(&keccak(addr)[12..]) +} + +pub fn near_account_id_to_evm_address(account_id: &str) -> Address { + near_account_bytes_to_evm_address(&account_id.to_string().into_bytes()) +} + +pub fn near_account_id_to_internal_address(account_id: &str) -> [u8; 20] { + evm_account_to_internal_address(near_account_id_to_evm_address(account_id)) +} + +pub fn hex_to_evm_address(address: &str) -> Address { + let addr = hex::decode(&address).expect("Hex string not valid hex"); + Address::from_slice(&addr) +} + +pub fn balance_to_u256(val: &Balance) -> U256 { + let mut bin = [0u8; 32]; + bin[16..].copy_from_slice(&val.to_be_bytes()); + bin.into() +} + +pub fn u256_to_balance(val: &U256) -> Balance { + let mut scratch = [0u8; 32]; + let mut bin = [0u8; 16]; + val.to_big_endian(&mut scratch); + bin.copy_from_slice(&scratch[16..]); + Balance::from_be_bytes(bin) +} + +/// Returns new address created from address, nonce, and code hash +/// Copied directly from the parity codebase +pub fn evm_contract_address( + address_scheme: CreateContractAddress, + sender: &Address, + nonce: &U256, + code: &[u8], +) -> (Address, Option) { + use rlp::RlpStream; + + match address_scheme { + CreateContractAddress::FromSenderAndNonce => { + let mut stream = RlpStream::new_list(2); + stream.append(sender); + stream.append(nonce); + (From::from(keccak(stream.as_raw())), None) + } + CreateContractAddress::FromSenderSaltAndCodeHash(salt) => { + let code_hash = keccak(code); + let mut buffer = [0u8; 1 + 20 + 32 + 32]; + buffer[0] = 0xff; + buffer[1..(1 + 20)].copy_from_slice(&sender[..]); + buffer[(1 + 20)..(1 + 20 + 32)].copy_from_slice(&salt[..]); + buffer[(1 + 20 + 32)..].copy_from_slice(&code_hash[..]); + (From::from(keccak(&buffer[..])), Some(code_hash)) + } + CreateContractAddress::FromSenderAndCodeHash => { + let code_hash = keccak(code); + let mut buffer = [0u8; 20 + 32]; + buffer[..20].copy_from_slice(&sender[..]); + buffer[20..].copy_from_slice(&code_hash[..]); + (From::from(keccak(&buffer[..])), Some(code_hash)) + } + } +} + +#[derive(Eq, PartialEq, Debug, Ord, PartialOrd)] +pub struct Balance(pub u128); + +impl Balance { + pub fn from_be_bytes(bytes: [u8; 16]) -> Self { + Balance(u128::from_be_bytes(bytes)) + } + + pub fn to_be_bytes(&self) -> [u8; 16] { + self.0.to_be_bytes() + } +} + +impl Serialize for Balance { + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + serializer.serialize_str(&format!("{}", &self.0)) + } +} + +impl<'de> Deserialize<'de> for Balance { + fn deserialize(deserializer: D) -> Result>::Error> + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + u128::from_str_radix(&s, 10).map(Balance).map_err(serde::de::Error::custom) + } +} + +impl From for u128 { + fn from(balance: Balance) -> Self { + balance.0 + } +} From 2f45ddd78e35d2ceab33f27412e39b9b7b01756a Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Fri, 28 Aug 2020 13:39:23 -0700 Subject: [PATCH 02/82] Shifting things a bit to interpreter from duplicated code around deploy_code --- runtime/near-evm-runner/Cargo.toml | 3 +- runtime/near-evm-runner/src/evm_state.rs | 50 +++++++++------- runtime/near-evm-runner/src/interpreter.rs | 18 +++--- runtime/near-evm-runner/src/lib.rs | 68 +++++++++++++++------- runtime/near-evm-runner/src/near_ext.rs | 22 +++---- 5 files changed, 94 insertions(+), 67 deletions(-) diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 2744e95f279..e0027449a51 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -27,4 +27,5 @@ ripemd160 = "0.9.0" libsecp256k1 = "0.3.5" near-vm-logic = { path = "../near-vm-logic" } near-vm-errors = { path = "../near-vm-errors" } -near-primitives = { path = "../../core/primitives" } \ No newline at end of file +near-primitives = { path = "../../core/primitives" } +near-store = { path = "../../core/store" } \ No newline at end of file diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index 6fa87ea7662..9c9a0e3f5a4 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use ethereum_types::{Address, U256}; -use near_primitives::{account::AccountId, types::Balance}; +use near_primitives::types::{AccountId, Balance}; use crate::utils; @@ -82,6 +82,8 @@ pub trait EvmState { self.sub_balance(sender, amnt); self.add_balance(recipient, amnt); } + + fn recreate(&mut self, address: [u8; 20]); } #[derive(Default, Debug)] @@ -110,15 +112,6 @@ impl StateStore { } } - pub fn recreate(&mut self, addr: [u8; 20]) { - self.code.remove(&addr); - // We do not delete balance here, as balances persist across recreation - self.nonces.remove(&addr); - self.overwrite_storage(addr); - self.self_destructs.remove(&addr); - self.recreated.insert(addr); - } - pub fn commit_code(&mut self, other: &HashMap<[u8; 20], Vec>) { self.code.extend(other.iter().map(|(k, v)| (*k, v.clone()))); } @@ -159,12 +152,16 @@ impl EvmState for StateStore { self.code.insert(internal_addr, bytecode.to_vec()); } + fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]> { + self.balances.insert(address, balance) + } + fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { self.balances.get(&address).copied().unwrap_or([0u8; 32]) } - fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]> { - self.balances.insert(address, balance) + fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { + self.nonces.insert(address, nonce) } fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32] { @@ -176,10 +173,6 @@ impl EvmState for StateStore { } } - fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { - self.nonces.insert(address, nonce) - } - fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { let mut addr = [0u8; 20]; addr.copy_from_slice(&key[..20]); @@ -203,6 +196,15 @@ impl EvmState for StateStore { self.commit_storages(&other.storages); self.logs.extend(other.logs.iter().cloned()); } + + fn recreate(&mut self, addr: [u8; 20]) { + self.code.remove(&addr); + // We do not delete balance here, as balances persist across recreation + self.nonces.remove(&addr); + self.overwrite_storage(addr); + self.self_destructs.remove(&addr); + self.recreated.insert(addr); + } } pub struct SubState<'a> { @@ -239,12 +241,16 @@ impl EvmState for SubState<'_> { self.state.code.insert(internal_addr, bytecode.to_vec()); } + fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]> { + self.state.balances.insert(address, balance) + } + fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { self.state.balances.get(&address).map_or_else(|| self.parent._balance_of(address), |k| *k) } - fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]> { - self.state.balances.insert(address, balance) + fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { + self.state.nonces.insert(address, nonce) } fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32] { @@ -256,10 +262,6 @@ impl EvmState for SubState<'_> { } } - fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { - self.state.nonces.insert(address, nonce) - } - fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { let mut addr = [0u8; 20]; addr.copy_from_slice(&key[..20]); @@ -287,6 +289,10 @@ impl EvmState for SubState<'_> { self.state.commit_storages(&other.storages); self.state.logs.extend(other.logs.iter().cloned()); } + + fn recreate(&mut self, address: [u8; 20]) { + unimplemented!() + } } #[cfg(test)] diff --git a/runtime/near-evm-runner/src/interpreter.rs b/runtime/near-evm-runner/src/interpreter.rs index cd72af5050b..77d488fefa4 100644 --- a/runtime/near-evm-runner/src/interpreter.rs +++ b/runtime/near-evm-runner/src/interpreter.rs @@ -15,17 +15,19 @@ pub fn deploy_code( sender: &Address, value: U256, call_stack_depth: usize, + address_type: CreateContractAddress, + recreate: bool, code: &[u8], ) -> Result { - let nonce = state.next_nonce(&sender); - let (address, _) = utils::evm_contract_address( - CreateContractAddress::FromSenderAndNonce, - &sender, - &nonce, - &code, - ); + let mut nonce = U256::default(); + if address_type == CreateContractAddress::FromSenderAndNonce { + nonce = state.next_nonce(&sender); + }; + let (address, _) = utils::evm_contract_address(address_type, &sender, &nonce, &code); - if state.code_at(&address).is_some() { + if recreate { + state.recreate(address.0); + } else if state.code_at(&address).is_some() { return Err(EvmError::DuplicateContract(address)); } diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 2b251e64fb6..bd1742b90ec 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -1,3 +1,14 @@ +use ethereum_types::{Address, H160, U256}; +use evm::CreateContractAddress; + +use near_primitives::types::{AccountId, Balance}; +use near_store::TrieUpdate; +use near_vm_errors::VMError; +use near_vm_logic::VMOutcome; + +use crate::errors::EvmError; +use crate::evm_state::{EvmState, StateStore}; + mod builtins; mod errors; mod evm_state; @@ -5,19 +16,13 @@ mod interpreter; mod near_ext; mod utils; -use crate::evm_state::{EvmState, StateStore}; -use ethereum_types::H160; -use near_primitives::{account::AccountId, types::Balance}; -use near_vm_errors::VMError; -use near_vm_logic::VMOutcome; -use vm::Address; - -struct EvmContext { +struct EvmContext<'a> { + trie_update: &'a mut TrieUpdate, sender_id: AccountId, attached_deposit: Balance, } -impl EvmState for EvmContext { +impl<'a> EvmState for EvmContext<'a> { fn code_at(&self, address: &H160) -> Option> { unimplemented!() } @@ -53,37 +58,58 @@ impl EvmState for EvmContext { fn commit_changes(&mut self, other: &StateStore) { unimplemented!() } + + fn recreate(&mut self, address: [u8; 20]) { + unimplemented!() + } } pub fn run_evm( - sender_id: AccountId, + mut state_update: &mut TrieUpdate, + predecessor_id: AccountId, attached_deposit: Balance, method_name: String, args: Vec, ) -> (Option, Option) { - let mut context = EvmContext { sender_id, attached_deposit }; - let sender = utils::near_account_id_to_evm_address(sender_id); + let mut context = EvmContext { + trie_update: &mut state_update, + sender_id: predecessor_id.clone(), + attached_deposit, + }; + let sender = utils::near_account_id_to_evm_address(&predecessor_id); + let value = U256::from(attached_deposit); let result = match method_name.as_str() { - "deploy_code" => interpreter::deploy_code(&mut context, &sender, &sender, val, 0, &args), + "deploy_code" => interpreter::deploy_code( + &mut context, + &sender, + &sender, + value, + 0, + CreateContractAddress::FromSenderAndNonce, + true, + &args, + ), "get_code" => { - let address = Address::from(args); - context.get_code(address) + let address = Address::from_slice(&args); + // context.get_code(address) + Ok(address) } "call_function" => { - let contract_address = args[:20]; - let input = args[20:]; + let contract_address = Address::from_slice(&args[..20]); + let input = &args[20..]; let result = interpreter::call( &mut context, - sender, - sender, - value, + &sender, + &sender, + Some(value), 0, // call-stack depth &contract_address, &input, true, ); + Ok(contract_address) } - _ => (), + _ => Err(EvmError::UnknownError), }; (None, None) } diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 3b3028a80f0..ee9c7c3250b 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -11,6 +11,7 @@ use vm::{ use crate::evm_state::{EvmState, SubState}; use crate::interpreter; use crate::utils; +use evm::ActionParams; // https://github.com/paritytech/parity-ethereum/blob/77643c13e80ca09d9a6b10631034f5a1568ba6d3/ethcore/machine/src/externalities.rs // #[derive(Debug)] @@ -128,28 +129,19 @@ impl<'a> vm::Ext for NearExt<'a> { panic!("MutableCallInStaticContext") } - let mut nonce = U256::default(); - // TODO: move this into deploy_code - if address_type == CreateContractAddress::FromSenderAndNonce { - nonce = self.sub_state.next_nonce(&self.context_addr); - }; - - // discarded argument here is the codehash. - // CONSIDER: storing codehash instead of calculating - let (addr, _) = utils::evm_contract_address(address_type, &self.context_addr, &nonce, code); - self.sub_state.state.recreate(addr.0); - + // TODO: better error propagation. interpreter::deploy_code( self.sub_state, &self.origin, &self.context_addr, *value, self.depth, - &addr, + address_type, + true, &code.to_vec(), - ); - - Ok(ContractCreateResult::Created(addr, 1_000_000_000.into())) + ) + .map(|result| ContractCreateResult::Created(result, 1_000_000_000.into())) + .map_err(|err| TrapKind::Call(ActionParams::default())) } /// Message call. From 1bacc5ad2882542e7b5f2e23ac8de9a3d5ef611b Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sat, 29 Aug 2020 00:29:31 -0700 Subject: [PATCH 03/82] Toward first test: depositing and withdrawing funds into evm --- Cargo.lock | 28 ++++ runtime/near-evm-runner/Cargo.toml | 1 + runtime/near-evm-runner/src/errors.rs | 6 + runtime/near-evm-runner/src/lib.rs | 129 +++++++++++------- runtime/near-evm-runner/src/types.rs | 23 ++++ runtime/near-evm-runner/src/utils.rs | 10 ++ runtime/near-evm-runner/tests/standard_ops.rs | 34 +++++ runtime/near-vm-logic/src/types.rs | 10 ++ 8 files changed, 194 insertions(+), 47 deletions(-) create mode 100644 runtime/near-evm-runner/src/types.rs create mode 100644 runtime/near-evm-runner/tests/standard_ops.rs diff --git a/Cargo.lock b/Cargo.lock index d3f03a78013..3a7c93c29a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2525,6 +2525,34 @@ dependencies = [ "smart-default", ] +[[package]] +name = "near-evm-runner" +version = "0.1.0" +dependencies = [ + "bn", + "borsh", + "byteorder", + "ethereum-types", + "evm", + "hex 0.3.2", + "keccak-hash", + "libsecp256k1", + "near-primitives", + "near-store", + "near-vm-errors", + "near-vm-logic", + "num-bigint 0.3.0", + "num-traits", + "parity-bytes", + "ripemd160", + "rlp", + "serde", + "serde_json", + "sha2", + "sha3", + "vm", +] + [[package]] name = "near-indexer" version = "0.1.0" diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index e0027449a51..5a534f30a24 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -14,6 +14,7 @@ bn = { git = "https://github.com/paritytech/bn", default-features = false } parity-bytes = "0.1.0" ethereum-types = "0.6.0" keccak-hash = "0.2.0" +borsh = "0.7.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1" sha2 = "0.8" diff --git a/runtime/near-evm-runner/src/errors.rs b/runtime/near-evm-runner/src/errors.rs index a85e0552fa5..49e2235754e 100644 --- a/runtime/near-evm-runner/src/errors.rs +++ b/runtime/near-evm-runner/src/errors.rs @@ -10,6 +10,12 @@ pub enum EvmError { DeployFail(Vec), /// Contract execution failed, revert the state. Revert(Vec), + /// Failed to parse arguments. + ArgumentParseError, + /// No deposit when expected. + MissingDeposit, + /// Insufficient funds to finish the operation. + InsufficientFunds, } impl std::fmt::Display for EvmError { diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index bd1742b90ec..00a9cd5eba1 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -1,3 +1,4 @@ +use borsh::BorshDeserialize; use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; @@ -8,15 +9,17 @@ use near_vm_logic::VMOutcome; use crate::errors::EvmError; use crate::evm_state::{EvmState, StateStore}; +use crate::types::{GetCodeArgs, GetStorageAtArgs, WithdrawNearArgs}; mod builtins; mod errors; mod evm_state; mod interpreter; mod near_ext; -mod utils; +mod types; +pub mod utils; -struct EvmContext<'a> { +pub struct EvmContext<'a> { trie_update: &'a mut TrieUpdate, sender_id: AccountId, attached_deposit: Balance, @@ -64,6 +67,74 @@ impl<'a> EvmState for EvmContext<'a> { } } +impl<'a> EvmContext<'a> { + pub fn deploy_code(&mut self, bytecode: Vec) -> Result, EvmError> { + let sender = utils::near_account_id_to_evm_address(&self.sender_id); + interpreter::deploy_code( + self, + &sender, + &sender, + U256::from(self.attached_deposit), + 0, + CreateContractAddress::FromSenderAndNonce, + true, + &bytecode, + ) + .map(|address| utils::address_to_vec(&address)) + } + + pub fn call_function(&mut self, args: Vec) -> Result, EvmError> { + let contract_address = Address::from_slice(&args[..20]); + let input = &args[20..]; + let sender = utils::near_account_id_to_evm_address(&self.sender_id); + let value = + if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; + interpreter::call(self, &sender, &sender, value, 0, &contract_address, &input, true) + .map(|rd| rd.to_vec()) + } + + pub fn get_code(&self, args: Vec) -> Result, EvmError> { + let args = GetCodeArgs::try_from_slice(&args).map_err(|_| EvmError::ArgumentParseError)?; + Ok(self.code_at(&Address::from_slice(&args.address)).unwrap_or(vec![])) + } + + pub fn get_storage_at(&self, args: Vec) -> Result, EvmError> { + let args = + GetStorageAtArgs::try_from_slice(&args).map_err(|_| EvmError::ArgumentParseError)?; + Ok(self + .read_contract_storage(&Address::from_slice(&args.address), args.key) + .unwrap_or([0u8; 32]) + .to_vec()) + } + + pub fn get_balance(&self, args: Vec) -> Result, EvmError> { + Ok(utils::u256_to_vec(&self.balance_of(&Address::from_slice(&args)))) + } + + pub fn deposit_near(&mut self, args: Vec) -> Result, EvmError> { + if self.attached_deposit == 0 { + return Err(EvmError::MissingDeposit); + } + let sender = utils::near_account_id_to_evm_address(&self.sender_id); + let address = Address::from_slice(&args); + self.add_balance(&address, U256::from(self.attached_deposit)); + Ok(utils::u256_to_vec(&self.balance_of(&address))) + } + + pub fn withdraw_near(&mut self, args: Vec) -> Result, EvmError> { + let args = + WithdrawNearArgs::try_from_slice(&args).map_err(|err| EvmError::ArgumentParseError)?; + let sender = utils::near_account_id_to_evm_address(&self.sender_id); + let amount = U256::from(args.amount); + if amount > self.balance_of(&sender) { + return Err(EvmError::InsufficientFunds); + } + self.sub_balance(&sender, amount); + // TODO: add outgoing promise. + Ok(vec![]) + } +} + pub fn run_evm( mut state_update: &mut TrieUpdate, predecessor_id: AccountId, @@ -71,53 +142,17 @@ pub fn run_evm( method_name: String, args: Vec, ) -> (Option, Option) { - let mut context = EvmContext { - trie_update: &mut state_update, - sender_id: predecessor_id.clone(), - attached_deposit, - }; - let sender = utils::near_account_id_to_evm_address(&predecessor_id); - let value = U256::from(attached_deposit); + let mut context = + EvmContext { trie_update: &mut state_update, sender_id: predecessor_id, attached_deposit }; let result = match method_name.as_str() { - "deploy_code" => interpreter::deploy_code( - &mut context, - &sender, - &sender, - value, - 0, - CreateContractAddress::FromSenderAndNonce, - true, - &args, - ), - "get_code" => { - let address = Address::from_slice(&args); - // context.get_code(address) - Ok(address) - } - "call_function" => { - let contract_address = Address::from_slice(&args[..20]); - let input = &args[20..]; - let result = interpreter::call( - &mut context, - &sender, - &sender, - Some(value), - 0, // call-stack depth - &contract_address, - &input, - true, - ); - Ok(contract_address) - } + "deploy_code" => context.deploy_code(args), + "get_code" => context.get_code(args), + "call_function" => context.call_function(args), + "get_storage_at" => context.get_storage_at(args), + "get_balance" => context.get_balance(args), + "deposit_near" => context.deposit_near(args), + "withdraw_near" => context.withdraw_near(args), _ => Err(EvmError::UnknownError), }; (None, None) } - -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs new file mode 100644 index 00000000000..533c91dbd2d --- /dev/null +++ b/runtime/near-evm-runner/src/types.rs @@ -0,0 +1,23 @@ +use borsh::BorshDeserialize; + +use near_primitives::types::Balance; + +pub type RawAddress = [u8; 20]; +pub type RawHash = [u8; 32]; + +#[derive(BorshDeserialize)] +pub struct GetCodeArgs { + pub address: RawAddress, +} + +#[derive(BorshDeserialize)] +pub struct GetStorageAtArgs { + pub address: RawAddress, + pub key: RawHash, +} + +#[derive(BorshDeserialize)] +pub struct WithdrawNearArgs { + pub account_id: String, + pub amount: Balance, +} diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index 68a450d8116..72a930b2965 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -45,6 +45,16 @@ pub fn u256_to_balance(val: &U256) -> Balance { Balance::from_be_bytes(bin) } +pub fn u256_to_vec(val: &U256) -> Vec { + let mut result = [0u8; 32]; + val.to_big_endian(&mut result); + result.to_vec() +} + +pub fn address_to_vec(val: &Address) -> Vec { + val.to_fixed_bytes().to_vec() +} + /// Returns new address created from address, nonce, and code hash /// Copied directly from the parity codebase pub fn evm_contract_address( diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs new file mode 100644 index 00000000000..a76a1276a45 --- /dev/null +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -0,0 +1,34 @@ +use ethereum_types::{Address, U256}; + +use near_evm_runner::utils::{address_to_vec, near_account_id_to_evm_address}; +use near_evm_runner::{run_evm, EvmContext}; +use near_primitives::hash::CryptoHash; +use near_store::test_utils::create_tries; +use near_store::ShardTries; + +fn accounts(account_id: usize) -> String { + vec!["alice", "bob", "chad"][account_id].to_string() +} + +fn setup() -> (ShardTries, CryptoHash) { + let tries = create_tries(); + let root = CryptoHash::default(); + (tries, root) +} + +#[test] +fn test_sends() { + let (tries, root) = setup(); + let mut state_update = tries.new_trie_update(0, root); + let (outcome, error) = run_evm( + &mut state_update, + accounts(0), + 0, + "get_balance".to_string(), + address_to_vec(&near_account_id_to_evm_address(&accounts(0))), + ); + assert_eq!( + U256::from_big_endian(&outcome.unwrap().return_data.as_value().unwrap()), + U256::from(0) + ); +} diff --git a/runtime/near-vm-logic/src/types.rs b/runtime/near-vm-logic/src/types.rs index 3416fd713cb..21745e20be6 100644 --- a/runtime/near-vm-logic/src/types.rs +++ b/runtime/near-vm-logic/src/types.rs @@ -29,6 +29,16 @@ pub enum ReturnData { None, } +impl ReturnData { + /// Function to extract value from ReturnData. + pub fn as_value(self) -> Option> { + match self { + ReturnData::Value(value) => Some(value), + _ => None, + } + } +} + /// When there is a callback attached to one or more contract calls the execution results of these /// calls are available to the contract invoked through the callback. #[derive(Debug, PartialEq, Serialize, Deserialize)] From b99eedcd82c571fcfe32d9c7de073a28dc2bd260 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sat, 29 Aug 2020 00:54:15 -0700 Subject: [PATCH 04/82] First test: deposit near into evm --- runtime/near-evm-runner/src/errors.rs | 2 +- runtime/near-evm-runner/src/evm_state.rs | 28 ++++---- runtime/near-evm-runner/src/lib.rs | 70 +++++++++++++------ runtime/near-evm-runner/src/near_ext.rs | 1 - runtime/near-evm-runner/src/utils.rs | 6 ++ runtime/near-evm-runner/tests/standard_ops.rs | 19 ++--- 6 files changed, 78 insertions(+), 48 deletions(-) diff --git a/runtime/near-evm-runner/src/errors.rs b/runtime/near-evm-runner/src/errors.rs index 49e2235754e..c4b94f9e89f 100644 --- a/runtime/near-evm-runner/src/errors.rs +++ b/runtime/near-evm-runner/src/errors.rs @@ -1,4 +1,4 @@ -use ethereum_types::{Address, U256}; +use ethereum_types::Address; #[derive(Debug)] pub enum EvmError { diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index 9c9a0e3f5a4..bce59d9a5b0 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -2,20 +2,18 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use ethereum_types::{Address, U256}; -use near_primitives::types::{AccountId, Balance}; - use crate::utils; pub trait EvmState { fn code_at(&self, address: &Address) -> Option>; fn set_code(&mut self, address: &Address, bytecode: &[u8]); - fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]>; - fn set_balance(&mut self, address: &Address, balance: U256) -> Option { + fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]); + fn set_balance(&mut self, address: &Address, balance: U256) { let mut bin = [0u8; 32]; balance.to_big_endian(&mut bin); let internal_addr = utils::evm_account_to_internal_address(*address); - self._set_balance(internal_addr, bin).map(|v| v.into()) + self._set_balance(internal_addr, bin); } fn _balance_of(&self, address: [u8; 20]) -> [u8; 32]; @@ -62,17 +60,17 @@ pub trait EvmState { fn commit_changes(&mut self, other: &StateStore); - // Panics on u256 overflow - // This represents NEAR tokens, so it can never _actually_ go above 2**128 - // That'd be silly. - fn add_balance(&mut self, address: &Address, incr: U256) -> Option { + /// Panics on u256 overflow + /// This represents NEAR tokens, so it can never _actually_ go above 2**128 + /// That'd be silly. + fn add_balance(&mut self, address: &Address, incr: U256) { let balance = self.balance_of(address); let new_balance = balance.checked_add(incr).expect("overflow during add_balance"); self.set_balance(address, new_balance) } - // Panics if insufficient balance - fn sub_balance(&mut self, address: &Address, decr: U256) -> Option { + /// Panics if insufficient balance. + fn sub_balance(&mut self, address: &Address, decr: U256) { let balance = self.balance_of(address); let new_balance = balance.checked_sub(decr).expect("underflow during sub_balance"); self.set_balance(address, new_balance) @@ -152,8 +150,8 @@ impl EvmState for StateStore { self.code.insert(internal_addr, bytecode.to_vec()); } - fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]> { - self.balances.insert(address, balance) + fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) { + self.balances.insert(address, balance); } fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { @@ -241,8 +239,8 @@ impl EvmState for SubState<'_> { self.state.code.insert(internal_addr, bytecode.to_vec()); } - fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]> { - self.state.balances.insert(address, balance) + fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) { + self.state.balances.insert(address, balance); } fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 00a9cd5eba1..38781a2158c 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -10,18 +10,20 @@ use near_vm_logic::VMOutcome; use crate::errors::EvmError; use crate::evm_state::{EvmState, StateStore}; use crate::types::{GetCodeArgs, GetStorageAtArgs, WithdrawNearArgs}; +use near_primitives::trie_key::TrieKey; mod builtins; mod errors; mod evm_state; mod interpreter; mod near_ext; -mod types; +pub mod types; pub mod utils; pub struct EvmContext<'a> { trie_update: &'a mut TrieUpdate, - sender_id: AccountId, + account_id: AccountId, + predecessor_id: AccountId, attached_deposit: Balance, } @@ -34,12 +36,22 @@ impl<'a> EvmState for EvmContext<'a> { unimplemented!() } - fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) -> Option<[u8; 32]> { - unimplemented!() + fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) { + self.trie_update.set( + TrieKey::ContractData { account_id: self.account_id.clone(), key: address.to_vec() }, + balance.to_vec(), + ) } fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { - unimplemented!() + self.trie_update + .get(&TrieKey::ContractData { + account_id: self.account_id.clone(), + key: address.to_vec(), + }) + .unwrap_or_else(|_| None) + .map(|value| utils::vec_to_arr_32(value)) + .unwrap_or([0; 32]) } fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { @@ -68,8 +80,22 @@ impl<'a> EvmState for EvmContext<'a> { } impl<'a> EvmContext<'a> { - pub fn deploy_code(&mut self, bytecode: Vec) -> Result, EvmError> { - let sender = utils::near_account_id_to_evm_address(&self.sender_id); + pub fn new( + mut state_update: &'a mut TrieUpdate, + account_id: AccountId, + predecessor_id: AccountId, + attached_deposit: Balance, + ) -> Self { + Self { + trie_update: state_update, + account_id, + predecessor_id: predecessor_id, + attached_deposit, + } + } + + pub fn deploy_code(&mut self, bytecode: Vec) -> Result { + let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); interpreter::deploy_code( self, &sender, @@ -80,13 +106,12 @@ impl<'a> EvmContext<'a> { true, &bytecode, ) - .map(|address| utils::address_to_vec(&address)) } pub fn call_function(&mut self, args: Vec) -> Result, EvmError> { let contract_address = Address::from_slice(&args[..20]); let input = &args[20..]; - let sender = utils::near_account_id_to_evm_address(&self.sender_id); + let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); let value = if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; interpreter::call(self, &sender, &sender, value, 0, &contract_address, &input, true) @@ -107,51 +132,52 @@ impl<'a> EvmContext<'a> { .to_vec()) } - pub fn get_balance(&self, args: Vec) -> Result, EvmError> { - Ok(utils::u256_to_vec(&self.balance_of(&Address::from_slice(&args)))) + pub fn get_balance(&self, args: Vec) -> Result { + Ok(self.balance_of(&Address::from_slice(&args))) } - pub fn deposit_near(&mut self, args: Vec) -> Result, EvmError> { + pub fn deposit_near(&mut self, args: Vec) -> Result { if self.attached_deposit == 0 { return Err(EvmError::MissingDeposit); } - let sender = utils::near_account_id_to_evm_address(&self.sender_id); + let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); let address = Address::from_slice(&args); self.add_balance(&address, U256::from(self.attached_deposit)); - Ok(utils::u256_to_vec(&self.balance_of(&address))) + Ok(self.balance_of(&address)) } - pub fn withdraw_near(&mut self, args: Vec) -> Result, EvmError> { + pub fn withdraw_near(&mut self, args: Vec) -> Result<(), EvmError> { let args = WithdrawNearArgs::try_from_slice(&args).map_err(|err| EvmError::ArgumentParseError)?; - let sender = utils::near_account_id_to_evm_address(&self.sender_id); + let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); let amount = U256::from(args.amount); if amount > self.balance_of(&sender) { return Err(EvmError::InsufficientFunds); } self.sub_balance(&sender, amount); // TODO: add outgoing promise. - Ok(vec![]) + Ok(()) } } pub fn run_evm( mut state_update: &mut TrieUpdate, + account_id: AccountId, predecessor_id: AccountId, attached_deposit: Balance, method_name: String, args: Vec, ) -> (Option, Option) { let mut context = - EvmContext { trie_update: &mut state_update, sender_id: predecessor_id, attached_deposit }; + EvmContext::new(&mut state_update, account_id, predecessor_id, attached_deposit); let result = match method_name.as_str() { - "deploy_code" => context.deploy_code(args), + "deploy_code" => context.deploy_code(args).map(|address| utils::address_to_vec(&address)), "get_code" => context.get_code(args), "call_function" => context.call_function(args), "get_storage_at" => context.get_storage_at(args), - "get_balance" => context.get_balance(args), - "deposit_near" => context.deposit_near(args), - "withdraw_near" => context.withdraw_near(args), + "get_balance" => context.get_balance(args).map(|balance| utils::u256_to_vec(&balance)), + "deposit_near" => context.deposit_near(args).map(|balance| utils::u256_to_vec(&balance)), + "withdraw_near" => context.withdraw_near(args).map(|_| vec![]), _ => Err(EvmError::UnknownError), }; (None, None) diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index ee9c7c3250b..f0baf5feb8f 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -10,7 +10,6 @@ use vm::{ use crate::evm_state::{EvmState, SubState}; use crate::interpreter; -use crate::utils; use evm::ActionParams; // https://github.com/paritytech/parity-ethereum/blob/77643c13e80ca09d9a6b10631034f5a1568ba6d3/ethcore/machine/src/externalities.rs diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index 72a930b2965..a82a6d0987c 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -55,6 +55,12 @@ pub fn address_to_vec(val: &Address) -> Vec { val.to_fixed_bytes().to_vec() } +pub fn vec_to_arr_32(v: Vec) -> [u8; 32] { + let mut result = [0; 32]; + result.copy_from_slice(&v); + result +} + /// Returns new address created from address, nonce, and code hash /// Copied directly from the parity codebase pub fn evm_contract_address( diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index a76a1276a45..393596f28ba 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -7,7 +7,7 @@ use near_store::test_utils::create_tries; use near_store::ShardTries; fn accounts(account_id: usize) -> String { - vec!["alice", "bob", "chad"][account_id].to_string() + vec!["evm", "alice", "bob", "chad"][account_id].to_string() } fn setup() -> (ShardTries, CryptoHash) { @@ -20,15 +20,16 @@ fn setup() -> (ShardTries, CryptoHash) { fn test_sends() { let (tries, root) = setup(); let mut state_update = tries.new_trie_update(0, root); - let (outcome, error) = run_evm( - &mut state_update, - accounts(0), - 0, - "get_balance".to_string(), - address_to_vec(&near_account_id_to_evm_address(&accounts(0))), - ); + let context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); assert_eq!( - U256::from_big_endian(&outcome.unwrap().return_data.as_value().unwrap()), + context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), U256::from(0) ); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + assert_eq!( + context + .deposit_near(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))) + .unwrap(), + U256::from(100) + ); } From 542e05e040ebe8ffff3edb9d198513c287704e66 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sat, 29 Aug 2020 01:32:49 -0700 Subject: [PATCH 05/82] Clean up from unimplemented errors --- runtime/near-evm-runner/src/near_ext.rs | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index f0baf5feb8f..59423cef1ba 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -58,10 +58,6 @@ impl<'a> NearExt<'a> { } } -fn not_implemented(name: &str) { - // near_sdk::env::log(format!("not implemented: {}", name).as_bytes()); -} - impl<'a> vm::Ext for NearExt<'a> { /// Returns the storage value for a given key if reversion happens on the current transaction. fn initial_storage_at(&self, key: &H256) -> EvmResult { @@ -125,10 +121,11 @@ impl<'a> vm::Ext for NearExt<'a> { _trap: bool, ) -> Result { if self.is_static() { - panic!("MutableCallInStaticContext") + return Err(TrapKind::Call(ActionParams::default())); } // TODO: better error propagation. + // TODO: gas metering. interpreter::deploy_code( self.sub_state, &self.origin, @@ -140,7 +137,7 @@ impl<'a> vm::Ext for NearExt<'a> { &code.to_vec(), ) .map(|result| ContractCreateResult::Created(result, 1_000_000_000.into())) - .map_err(|err| TrapKind::Call(ActionParams::default())) + .map_err(|_| TrapKind::Call(ActionParams::default())) } /// Message call. @@ -170,9 +167,8 @@ impl<'a> vm::Ext for NearExt<'a> { let result = match call_type { CallType::None => { - // Can stay unimplemented - not_implemented("CallType=None"); - unimplemented!() + // Is not used. + return Err(TrapKind::Call(ActionParams::default())); } CallType::Call => interpreter::call( self.sub_state, @@ -193,10 +189,8 @@ impl<'a> vm::Ext for NearExt<'a> { &data.to_vec(), ), CallType::CallCode => { - // Call another contract using storage of the current contract - // Can leave unimplemented, no longer used. - not_implemented("CallCode"); - unimplemented!() + // Call another contract using storage of the current contract. No longer used. + return Err(TrapKind::Call(ActionParams::default())); } CallType::DelegateCall => interpreter::delegate_call( self.sub_state, @@ -268,9 +262,8 @@ impl<'a> vm::Ext for NearExt<'a> { /// Returns gas_left if cost of returning the data is not too high. fn ret(self, _gas: &U256, _data: &ReturnData, _apply_state: bool) -> EvmResult { // NOTE: this is only called through finalize(), but we are not using it - // so it should be safe to ignore it here - not_implemented("ret"); - unimplemented!() + // so it should be safe to ignore it here. + Err(vm::Error::Internal("ret".to_string())) } /// Should be called when contract commits suicide. From 4a1e7d054e139cf78439811c10077b816763d3bb Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sat, 29 Aug 2020 02:22:32 -0700 Subject: [PATCH 06/82] Adding test contracts --- runtime/near-evm-runner/tests/build.sh | 24 ++++++ .../tests/contracts/ConstructorRevert.sol | 7 ++ .../tests/contracts/Create2.sol | 66 +++++++++++++++++ .../tests/contracts/SolTests.sol | 74 +++++++++++++++++++ .../near-evm-runner/tests/truffle-config.js | 7 ++ 5 files changed, 178 insertions(+) create mode 100755 runtime/near-evm-runner/tests/build.sh create mode 100644 runtime/near-evm-runner/tests/contracts/ConstructorRevert.sol create mode 100644 runtime/near-evm-runner/tests/contracts/Create2.sol create mode 100644 runtime/near-evm-runner/tests/contracts/SolTests.sol create mode 100644 runtime/near-evm-runner/tests/truffle-config.js diff --git a/runtime/near-evm-runner/tests/build.sh b/runtime/near-evm-runner/tests/build.sh new file mode 100755 index 00000000000..391db5242a6 --- /dev/null +++ b/runtime/near-evm-runner/tests/build.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +contracts=( + "SolTests" + "SubContract" + "Create2Factory" + "SelfDestruct" + "ConstructorRevert" +) + +truffle compile || exit 1 +for contractName in "${contracts[@]}" + do + cat build/contracts/"$contractName".json | \ + jq .bytecode | \ + awk '{ print substr($1,4,length($1)-4) }' | \ + tr -d '\n' \ + > build/"$contractName".bin + + cat build/contracts/"$contractName".json | \ + jq .abi \ + > build/"$contractName".abi + done +rm -rf build/contracts diff --git a/runtime/near-evm-runner/tests/contracts/ConstructorRevert.sol b/runtime/near-evm-runner/tests/contracts/ConstructorRevert.sol new file mode 100644 index 00000000000..4b67a7311ce --- /dev/null +++ b/runtime/near-evm-runner/tests/contracts/ConstructorRevert.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.5.8; + +contract ConstructorRevert { + constructor() public { + require(2 + 2 == 5, "Error Deploying Contract"); + } +} diff --git a/runtime/near-evm-runner/tests/contracts/Create2.sol b/runtime/near-evm-runner/tests/contracts/Create2.sol new file mode 100644 index 00000000000..d217352750b --- /dev/null +++ b/runtime/near-evm-runner/tests/contracts/Create2.sol @@ -0,0 +1,66 @@ +pragma solidity ^0.5.8; + +contract Create2Factory { + function deploy(bytes32 _salt, bytes memory _contractBytecode) public returns (address payable addr) { + assembly { + addr := create2(0, add(_contractBytecode, 0x20), mload(_contractBytecode), _salt) + } + } + + function testDoubleDeploy(bytes32 _salt, bytes memory _contractBytecode) public payable returns (bool) { + // deploy + address payable addr = deploy(_salt, _contractBytecode); + SelfDestruct other = SelfDestruct(addr); + + // use once + other.storeUint(5); + require(other.storedUint() == 5, "pre-destruction wrong uint"); + + // destroy and check if still exists + other.destruction(); + bytes memory code = getCode(address(other)); + require(code.length == 0, "post-destruction code length"); + + // redeploy and use again + deploy(_salt, _contractBytecode); + require(other.storedUint() == 0, "post-destruction wrong uint"); + other.storeUint(3); + require(other.storedUint() == 3, "post-destruction stored wrong uint"); + return true; + } + + function getCode(address other) internal view returns (bytes memory code) { + assembly { + code := mload(0x40) + let size := extcodesize(other) + mstore(code, size) + let body := add(code, 0x20) + extcodecopy(other, body, 0, size) + mstore(code, size) + mstore(0x40, add(body, size)) + } + } + + + function () external payable {} + +} + +contract SelfDestruct { + address public storedAddress; + uint public storedUint; + + function () external payable {} + + function storeAddress() public { + storedAddress = msg.sender; + } + + function storeUint(uint _number) public { + storedUint = _number; + } + + function destruction() public { + selfdestruct(msg.sender); + } +} diff --git a/runtime/near-evm-runner/tests/contracts/SolTests.sol b/runtime/near-evm-runner/tests/contracts/SolTests.sol new file mode 100644 index 00000000000..5a2de01c88f --- /dev/null +++ b/runtime/near-evm-runner/tests/contracts/SolTests.sol @@ -0,0 +1,74 @@ +pragma solidity ^0.5.8; + +contract ExposesBalance { + function balance() public view returns (uint256) { + return address(this).balance; + } + + // Unpermissioned. Don't deploy for real :D + function transferTo(address _recipient, uint256 _amount) public returns (uint256) { + address(uint160(_recipient)).transfer(_amount); + return balance(); + } +} + +contract SolTests is ExposesBalance { + constructor() public payable {} + + event SomeEvent(uint256 _number); + + function () external payable {} + + function deployNewGuy(uint256 _aNumber) public payable returns (address, uint256) { + SubContract _newGuy = new SubContract(_aNumber); + address(_newGuy).transfer(msg.value); + return (address(_newGuy), msg.value); + } + + function payNewGuy(uint256 _aNumber) public payable returns (address, uint256) { + SubContract _newGuy = (new SubContract).value(msg.value)(_aNumber); + return (address(_newGuy), msg.value); + } + + function returnSomeFunds() public payable returns (address, uint256) { + address(msg.sender).transfer(msg.value / 2); + return (msg.sender, msg.value); + } + + function emitIt(uint256 _aNumber) public returns (bool) { + emit SomeEvent(_aNumber); + return true; + } + + function precompileTest() public pure { + require(sha256("") == hex"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "sha2 digest mismatch"); + require(ripemd160("") == hex"9c1185a5c5e9fc54612808977ee8f548b2258d31", "rmd160 digest mismatch"); + + // signed with hex"2222222222222222222222222222222222222222222222222222222222222222" + address addr = ecrecover( + hex"1111111111111111111111111111111111111111111111111111111111111111", + 27, + hex"b9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b698", // r + hex"12ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb644744" // s + ); + + require( + addr == 0x1563915e194D8CfBA1943570603F7606A3115508, + "ecrecover mismatch" + ); + } +} + +contract SubContract is ExposesBalance { + uint256 public aNumber = 6; + + constructor(uint256 _aNumber) public payable { + aNumber = _aNumber; + } + + function aFunction() public pure returns (bool) { + return true; + } + + function () external payable {} +} diff --git a/runtime/near-evm-runner/tests/truffle-config.js b/runtime/near-evm-runner/tests/truffle-config.js new file mode 100644 index 00000000000..f036f7b7bf4 --- /dev/null +++ b/runtime/near-evm-runner/tests/truffle-config.js @@ -0,0 +1,7 @@ +// empty, but necessary for truffle compile +module.exports = { + networks: {}, + compilers: { + solc: {} + } +} From 8ad0bafa52cbad03d5317c50a8db7f3d2de351cb Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sat, 29 Aug 2020 02:22:57 -0700 Subject: [PATCH 07/82] Updating dependencies --- .gitignore | 1 + Cargo.lock | 351 ++++++++++++++++++++--------- runtime/near-evm-runner/Cargo.toml | 9 +- 3 files changed, 257 insertions(+), 104 deletions(-) diff --git a/.gitignore b/.gitignore index c928a1b7bdd..d44928dbc9c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ docker-build /keystore/ /chain/client/tmp_bench testdir/ +runtime/near-evm-runner/tests/build # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html diff --git a/Cargo.lock b/Cargo.lock index 3a7c93c29a7..f022571e78d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,8 +127,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21705adc76bbe4bc98434890e73a89cd00c6015e5704a60bb6eea6c3b72316b6" dependencies = [ - "quote", - "syn", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -297,9 +297,9 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f00371942083469785f7e28c540164af1913ee7c96a4534acb9cea92c39f057" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -308,9 +308,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b95aceadaf327f18f0df5962fedc1bde2f870566a0b9f65c89508a3b1f79334c" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -373,9 +373,9 @@ version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da71fef07bc806586090247e971229289f64c210a278ee5ae419314eb386b31d" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -491,8 +491,8 @@ dependencies = [ "lazycell", "log", "peeking_take_while", - "proc-macro2", - "quote", + "proc-macro2 1.0.10", + "quote 1.0.3", "regex", "rustc-hash", "shlex", @@ -581,7 +581,7 @@ checksum = "b2d74755d937d261d5e9bdef87e0addfbc1ace0214f7776f21532d6e97325356" dependencies = [ "borsh-derive-internal", "borsh-schema-derive-internal", - "syn", + "syn 1.0.18", ] [[package]] @@ -590,9 +590,9 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c9f966cb7a42c8ed83546ef481bc1d1dec888fe5f84a4737d5c2094a483e41e" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -601,9 +601,9 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5df2543b56ebc2b4493e70d024ebde2cbb48d97bf7b1a16318eff30bd02669b8" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -1123,9 +1123,9 @@ version = "0.99.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2323f3f47db9a0e77ce7a300605d8d2098597fc451ed1a97bb1f6411bb550a7" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -1134,9 +1134,9 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3df5480412da86cdf5d6b7f3b682422c84359ff7399aa658df1d15ee83244b1d" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -1202,9 +1202,9 @@ dependencies = [ "byteorder", "lazy_static", "owning_ref", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -1223,8 +1223,8 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2a9b11b96248fc9efa0c093e6406fea7e55a7e893c932dbdf47074f34ec52e7" dependencies = [ - "quote", - "syn", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -1276,9 +1276,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc4bfcfacb61d231109d1d55202c1f33263319668b168843e02ad4652725ec9c" dependencies = [ "heck", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -1315,6 +1315,105 @@ dependencies = [ "libc", ] +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + +[[package]] +name = "ethabi" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebdeeea85a6d217b9fcc862906d7e283c047e04114165c433756baf5dce00a6c" +dependencies = [ + "error-chain", + "ethereum-types", + "rustc-hex 2.1.0", + "serde", + "serde_derive", + "serde_json", + "tiny-keccak", +] + +[[package]] +name = "ethabi-contract" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d6314f57a5451692753696f40903bacf870adf65d452911ab6b15bf6be41f8" + +[[package]] +name = "ethabi-derive" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65cdef3199bf5d1821dc53b5ab992f853a13b2e28d7a63983095d9d61fae58d3" +dependencies = [ + "ethabi", + "heck", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "ethbloom" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3932e82d64d347a045208924002930dc105a138995ccdc1479d0f05f0359f17c" +dependencies = [ + "crunchy", + "fixed-hash 0.3.2", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d1bc682337e2c5ec98930853674dd2b4bd5d0d246933a9e98e5280f7c76c5f" +dependencies = [ + "ethbloom", + "fixed-hash 0.3.2", + "impl-rlp", + "impl-serde", + "primitive-types 0.3.0", + "uint 0.7.1", +] + +[[package]] +name = "ethjson" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +dependencies = [ + "ethereum-types", + "rustc-hex 1.0.0", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "evm" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +dependencies = [ + "bit-set", + "ethereum-types", + "heapsize", + "keccak-hash", + "lazy_static", + "log", + "memory-cache", + "parity-bytes", + "parking_lot 0.7.1", + "vm", +] + [[package]] name = "faerie" version = "0.15.0" @@ -1346,9 +1445,9 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", "synstructure", ] @@ -1493,9 +1592,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" dependencies = [ "proc-macro-hack", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -1640,9 +1739,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34a97a52fdee1870a34fa6e4b77570cba531b27d1838874fef4429a791a3d657" dependencies = [ "proc-macro-hack", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -1965,8 +2064,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cdea9771bec3d95893f6c665a4fcd477af7858446a46bc2772f560534eee43b" dependencies = [ "derive_utils", - "quote", - "syn", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -2063,6 +2162,17 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" +[[package]] +name = "lazy-static-include" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10200e516c7a80a6dcfb1cdc23cd01ca0d8e97df71e9c5aa6d116302b89a928" +dependencies = [ + "lazy_static", + "starts-ends-with-caseless", + "syn 1.0.18", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -2532,10 +2642,15 @@ dependencies = [ "bn", "borsh", "byteorder", + "ethabi", + "ethabi-contract", + "ethabi-derive", "ethereum-types", "evm", "hex 0.3.2", "keccak-hash", + "lazy-static-include", + "lazy_static", "libsecp256k1", "near-primitives", "near-store", @@ -2739,11 +2854,11 @@ dependencies = [ name = "near-rpc-error-core" version = "0.1.0" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.10", + "quote 1.0.3", "serde", "serde_json", - "syn", + "syn 1.0.18", ] [[package]] @@ -2751,11 +2866,11 @@ name = "near-rpc-error-macro" version = "0.1.0" dependencies = [ "near-rpc-error-core", - "proc-macro2", - "quote", + "proc-macro2 1.0.10", + "quote 1.0.3", "serde", "serde_json", - "syn", + "syn 1.0.18", ] [[package]] @@ -3372,9 +3487,9 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8988430ce790d8682672117bc06dda364c0be32d3abd738234f19f3240bad99a" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -3449,9 +3564,9 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", "syn-mid", "version_check", ] @@ -3481,11 +3596,20 @@ checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" [[package]] name = "proc-macro2" -version = "1.0.19" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" dependencies = [ - "unicode-xid", + "unicode-xid 0.2.0", ] [[package]] @@ -3525,13 +3649,22 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + [[package]] name = "quote" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.10", ] [[package]] @@ -3999,9 +4132,9 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e367622f934864ffa1c704ba2b82280aab856e3d8213c84c5720257eb34b15b9" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -4095,9 +4228,9 @@ version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -4210,9 +4343,9 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -4239,6 +4372,12 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +[[package]] +name = "starts-ends-with-caseless" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1c13a0dff1a602924cf45fcb409855d46a5fd470a15b76ddcb61be675296d3" + [[package]] name = "state-viewer" version = "0.1.0" @@ -4334,9 +4473,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" dependencies = [ "heck", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -4357,9 +4496,9 @@ version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4" dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "proc-macro2 1.0.10", + "quote 1.0.3", + "unicode-xid 0.2.0", ] [[package]] @@ -4368,9 +4507,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -4379,10 +4518,10 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", + "unicode-xid 0.2.0", ] [[package]] @@ -4494,9 +4633,9 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -4557,9 +4696,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -4654,8 +4793,8 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fbad39da2f9af1cae3016339ad7f2c7a9e870f12e8fd04c4fd7ef35b30c0d2b" dependencies = [ - "quote", - "syn", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -4825,6 +4964,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "unicode-xid" version = "0.2.0" @@ -4900,10 +5045,10 @@ checksum = "e668e9cd05c5009b833833aa1147e5727b5396ea401f22dd1167618eed4a10c9" dependencies = [ "if_chain", "lazy_static", - "proc-macro2", - "quote", + "proc-macro2 1.0.10", + "quote 1.0.3", "regex", - "syn", + "syn 1.0.18", "validator", ] @@ -4975,9 +5120,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c2bb690b44cb1b0fdcc54d4998d21f8bdaf706b93775425e440b174f39ad16" dependencies = [ "heck", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", ] [[package]] @@ -5017,9 +5162,9 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", "wasm-bindgen-shared", ] @@ -5041,7 +5186,7 @@ version = "0.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4" dependencies = [ - "quote", + "quote 1.0.3", "wasm-bindgen-macro-support", ] @@ -5051,9 +5196,9 @@ version = "0.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 5a534f30a24..a0a915bb142 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -29,4 +29,11 @@ libsecp256k1 = "0.3.5" near-vm-logic = { path = "../near-vm-logic" } near-vm-errors = { path = "../near-vm-errors" } near-primitives = { path = "../../core/primitives" } -near-store = { path = "../../core/store" } \ No newline at end of file +near-store = { path = "../../core/store" } + +[dev-dependencies] +ethabi = "8.0.0" +ethabi-contract = "8.0.0" +ethabi-derive = "8.0.0" +lazy_static = "1.4" +lazy-static-include = "2.2.2" From 98efef508c3033397bd036671a44220da2d15d9d Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sat, 29 Aug 2020 02:23:18 -0700 Subject: [PATCH 08/82] Factor balance + nonce into EvmAccount structure --- runtime/near-evm-runner/src/errors.rs | 2 + runtime/near-evm-runner/src/evm_state.rs | 218 ++++++++++-------- runtime/near-evm-runner/src/lib.rs | 37 ++- runtime/near-evm-runner/src/near_ext.rs | 9 +- runtime/near-evm-runner/src/types.rs | 3 +- runtime/near-evm-runner/tests/standard_ops.rs | 27 ++- 6 files changed, 174 insertions(+), 122 deletions(-) diff --git a/runtime/near-evm-runner/src/errors.rs b/runtime/near-evm-runner/src/errors.rs index c4b94f9e89f..aad09369686 100644 --- a/runtime/near-evm-runner/src/errors.rs +++ b/runtime/near-evm-runner/src/errors.rs @@ -16,6 +16,8 @@ pub enum EvmError { MissingDeposit, /// Insufficient funds to finish the operation. InsufficientFunds, + /// U256 overflow. + IntegerOverflow, } impl std::fmt::Display for EvmError { diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index bce59d9a5b0..3f818cb2f2e 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -2,43 +2,78 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use ethereum_types::{Address, U256}; +use borsh::{BorshDeserialize, BorshSerialize}; + +use crate::errors::EvmError; +use crate::types::RawAddress; use crate::utils; +use std::io::{Error, Write}; -pub trait EvmState { - fn code_at(&self, address: &Address) -> Option>; - fn set_code(&mut self, address: &Address, bytecode: &[u8]); +#[derive(Default, Clone, Copy, Debug)] +pub struct EvmAccount { + pub balance: U256, + pub nonce: U256, +} - fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]); - fn set_balance(&mut self, address: &Address, balance: U256) { - let mut bin = [0u8; 32]; - balance.to_big_endian(&mut bin); - let internal_addr = utils::evm_account_to_internal_address(*address); - self._set_balance(internal_addr, bin); +impl BorshSerialize for EvmAccount { + fn serialize(&self, writer: &mut W) -> Result<(), Error> { + self.balance.0.serialize(writer)?; + self.nonce.0.serialize(writer) } +} - fn _balance_of(&self, address: [u8; 20]) -> [u8; 32]; - fn balance_of(&self, address: &Address) -> U256 { - let internal_addr = utils::evm_account_to_internal_address(*address); - self._balance_of(internal_addr).into() +impl BorshDeserialize for EvmAccount { + fn deserialize(buf: &mut &[u8]) -> Result { + let balance = U256(<[u64; 4]>::deserialize(buf)?); + let nonce = U256(<[u64; 4]>::deserialize(buf)?); + Ok(Self { balance, nonce }) } +} - fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]>; - fn set_nonce(&mut self, address: &Address, nonce: U256) -> Option { - let mut bin = [0u8; 32]; - nonce.to_big_endian(&mut bin); - let internal_addr = utils::evm_account_to_internal_address(*address); - self._set_nonce(internal_addr, bin).map(|v| v.into()) - } +pub trait EvmState { + fn code_at(&self, address: &Address) -> Option>; + fn set_code(&mut self, address: &Address, bytecode: &[u8]); - fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32]; - fn nonce_of(&self, address: &Address) -> U256 { - let internal_addr = utils::evm_account_to_internal_address(*address); - self._nonce_of(internal_addr).into() - } + fn set_account(&mut self, address: &Address, account: &EvmAccount); + fn get_account(&self, address: &Address) -> EvmAccount; + + fn balance_of(&self, address: &Address) -> U256 { + let account = self.get_account(address); + account.balance.into() + } + // fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]); + // fn set_balance(&mut self, address: &Address, balance: U256) { + // let mut bin = [0u8; 32]; + // balance.to_big_endian(&mut bin); + // let internal_addr = utils::evm_account_to_internal_address(*address); + // self._set_balance(internal_addr, bin); + // } + + // fn _balance_of(&self, address: [u8; 20]) -> [u8; 32]; + // fn balance_of(&self, address: &Address) -> U256 { + // let internal_addr = utils::evm_account_to_internal_address(*address); + // self._balance_of(internal_addr).into() + // } + // + // fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]>; + // fn set_nonce(&mut self, address: &Address, nonce: U256) -> Option { + // let mut bin = [0u8; 32]; + // nonce.to_big_endian(&mut bin); + // let internal_addr = utils::evm_account_to_internal_address(*address); + // self._set_nonce(internal_addr, bin).map(|v| v.into()) + // } + // + // fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32]; + // fn nonce_of(&self, address: &Address) -> U256 { + // let internal_addr = utils::evm_account_to_internal_address(*address); + // self._nonce_of(internal_addr).into() + // } fn next_nonce(&mut self, address: &Address) -> U256 { - let nonce = self.nonce_of(address); - self.set_nonce(address, nonce + 1); + let mut account = self.get_account(address); + let nonce = account.nonce; + account.nonce += U256::from(1); + self.set_account(address, &account); nonce } @@ -60,25 +95,30 @@ pub trait EvmState { fn commit_changes(&mut self, other: &StateStore); - /// Panics on u256 overflow - /// This represents NEAR tokens, so it can never _actually_ go above 2**128 - /// That'd be silly. - fn add_balance(&mut self, address: &Address, incr: U256) { - let balance = self.balance_of(address); - let new_balance = balance.checked_add(incr).expect("overflow during add_balance"); - self.set_balance(address, new_balance) + fn add_balance(&mut self, address: &Address, incr: U256) -> Result<(), EvmError> { + let mut account = self.get_account(address); + account.balance = + account.balance.checked_add(incr).ok_or_else(|| EvmError::IntegerOverflow)?; + self.set_account(address, &account); + Ok(()) } - /// Panics if insufficient balance. - fn sub_balance(&mut self, address: &Address, decr: U256) { - let balance = self.balance_of(address); - let new_balance = balance.checked_sub(decr).expect("underflow during sub_balance"); - self.set_balance(address, new_balance) + fn sub_balance(&mut self, address: &Address, decr: U256) -> Result<(), EvmError> { + let mut account = self.get_account(address); + account.balance = + account.balance.checked_add(decr).ok_or_else(|| EvmError::InsufficientFunds)?; + self.set_account(address, &account); + Ok(()) } - fn transfer_balance(&mut self, sender: &Address, recipient: &Address, amnt: U256) { - self.sub_balance(sender, amnt); - self.add_balance(recipient, amnt); + fn transfer_balance( + &mut self, + sender: &Address, + recipient: &Address, + amnt: U256, + ) -> Result<(), EvmError> { + self.sub_balance(sender, amnt)?; + self.add_balance(recipient, amnt) } fn recreate(&mut self, address: [u8; 20]); @@ -86,9 +126,8 @@ pub trait EvmState { #[derive(Default, Debug)] pub struct StateStore { - pub code: HashMap<[u8; 20], Vec>, - pub balances: HashMap<[u8; 20], [u8; 32]>, - pub nonces: HashMap<[u8; 20], [u8; 32]>, + pub code: HashMap>, + pub accounts: HashMap, pub storages: BTreeMap, [u8; 32]>, pub logs: Vec, pub self_destructs: HashSet<[u8; 20]>, @@ -114,12 +153,8 @@ impl StateStore { self.code.extend(other.iter().map(|(k, v)| (*k, v.clone()))); } - pub fn commit_balances(&mut self, other: &HashMap<[u8; 20], [u8; 32]>) { - self.balances.extend(other.iter().map(|(k, v)| (*k, *v))); - } - - pub fn commit_nonces(&mut self, other: &HashMap<[u8; 20], [u8; 32]>) { - self.nonces.extend(other.iter().map(|(k, v)| (*k, *v))); + pub fn commit_accounts(&mut self, other: &HashMap<[u8; 20], EvmAccount>) { + self.accounts.extend(other.iter().map(|(k, v)| (*k, *v))); } pub fn commit_storages(&mut self, other: &BTreeMap, [u8; 32]>) { @@ -150,25 +185,17 @@ impl EvmState for StateStore { self.code.insert(internal_addr, bytecode.to_vec()); } - fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) { - self.balances.insert(address, balance); + fn set_account(&mut self, address: &Address, account: &EvmAccount) { + self.accounts.insert(address.0, account.clone()); } - fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { - self.balances.get(&address).copied().unwrap_or([0u8; 32]) - } - - fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { - self.nonces.insert(address, nonce) - } - - fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32] { - let empty = [0u8; 32]; - if self.self_destructs.contains(&address) { - empty + fn get_account(&self, address: &Address) -> EvmAccount { + if self.self_destructs.contains(&address.0) { + None } else { - self.nonces.get(&address).copied().unwrap_or(empty) + self.accounts.get(&address.0).map(|account| account.clone()) } + .unwrap_or_else(|| EvmAccount::default()) } fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { @@ -189,16 +216,15 @@ impl EvmState for StateStore { self.commit_self_destructs(&other.self_destructs); self.commit_recreated(&other.recreated); self.commit_code(&other.code); - self.commit_balances(&other.balances); - self.commit_nonces(&other.nonces); + self.commit_accounts(&other.accounts); self.commit_storages(&other.storages); self.logs.extend(other.logs.iter().cloned()); } fn recreate(&mut self, addr: [u8; 20]) { self.code.remove(&addr); - // We do not delete balance here, as balances persist across recreation - self.nonces.remove(&addr); + // We do not remove account because balances persist across recreation. + self.accounts.entry(addr).or_insert(EvmAccount::default()).nonce = U256::from(0); self.overwrite_storage(addr); self.self_destructs.remove(&addr); self.recreated.insert(addr); @@ -239,26 +265,33 @@ impl EvmState for SubState<'_> { self.state.code.insert(internal_addr, bytecode.to_vec()); } - fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) { - self.state.balances.insert(address, balance); - } - - fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { - self.state.balances.get(&address).map_or_else(|| self.parent._balance_of(address), |k| *k) - } - - fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { - self.state.nonces.insert(address, nonce) - } - - fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32] { - let empty = [0u8; 32]; - if self.state.self_destructs.contains(&address) { - empty - } else { - self.state.nonces.get(&address).map_or_else(|| self.parent._nonce_of(address), |k| *k) - } - } + fn set_account(&mut self, address: &Address, account: &EvmAccount) { + self.state.set_account(address, account); + } + + fn get_account(&self, address: &Address) -> EvmAccount { + self.state.get_account(address) + } + // fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) { + // self.state.balances.insert(address, balance); + // } + // + // fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { + // self.state.balances.get(&address).map_or_else(|| self.parent._balance_of(address), |k| *k) + // } + // + // fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { + // self.state.nonces.insert(address, nonce) + // } + // + // fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32] { + // let empty = [0u8; 32]; + // if self.state.self_destructs.contains(&address) { + // empty + // } else { + // self.state.nonces.get(&address).map_or_else(|| self.parent._nonce_of(address), |k| *k) + // } + // } fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { let mut addr = [0u8; 20]; @@ -282,13 +315,12 @@ impl EvmState for SubState<'_> { self.state.commit_self_destructs(&other.self_destructs); self.state.commit_recreated(&other.recreated); self.state.commit_code(&other.code); - self.state.commit_balances(&other.balances); - self.state.commit_nonces(&other.nonces); + self.state.commit_accounts(&other.accounts); self.state.commit_storages(&other.storages); self.state.logs.extend(other.logs.iter().cloned()); } - fn recreate(&mut self, address: [u8; 20]) { + fn recreate(&mut self, _address: [u8; 20]) { unimplemented!() } } diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 38781a2158c..caeaccd4d96 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -1,4 +1,4 @@ -use borsh::BorshDeserialize; +use borsh::{BorshDeserialize, BorshSerialize}; use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; @@ -8,7 +8,7 @@ use near_vm_errors::VMError; use near_vm_logic::VMOutcome; use crate::errors::EvmError; -use crate::evm_state::{EvmState, StateStore}; +use crate::evm_state::{EvmAccount, EvmState, StateStore}; use crate::types::{GetCodeArgs, GetStorageAtArgs, WithdrawNearArgs}; use near_primitives::trie_key::TrieKey; @@ -36,30 +36,24 @@ impl<'a> EvmState for EvmContext<'a> { unimplemented!() } - fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) { + fn set_account(&mut self, address: &Address, account: &EvmAccount) { self.trie_update.set( - TrieKey::ContractData { account_id: self.account_id.clone(), key: address.to_vec() }, - balance.to_vec(), + TrieKey::ContractData { account_id: self.account_id.clone(), key: address.0.to_vec() }, + account.try_to_vec().expect("Failed to serialize"), ) } - fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { + fn get_account(&self, address: &Address) -> EvmAccount { + // TODO: handle error propagation? self.trie_update .get(&TrieKey::ContractData { account_id: self.account_id.clone(), - key: address.to_vec(), + key: address.0.to_vec(), }) .unwrap_or_else(|_| None) - .map(|value| utils::vec_to_arr_32(value)) - .unwrap_or([0; 32]) - } - - fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { - unimplemented!() - } - - fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32] { - unimplemented!() + .map(|value| EvmAccount::try_from_slice(&value)) + .unwrap_or_else(|| Ok(EvmAccount::default())) + .unwrap_or_else(|_| EvmAccount::default()) } fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { @@ -70,18 +64,18 @@ impl<'a> EvmState for EvmContext<'a> { unimplemented!() } - fn commit_changes(&mut self, other: &StateStore) { + fn commit_changes(&mut self, _other: &StateStore) { unimplemented!() } - fn recreate(&mut self, address: [u8; 20]) { + fn recreate(&mut self, _address: [u8; 20]) { unimplemented!() } } impl<'a> EvmContext<'a> { pub fn new( - mut state_update: &'a mut TrieUpdate, + state_update: &'a mut TrieUpdate, account_id: AccountId, predecessor_id: AccountId, attached_deposit: Balance, @@ -140,7 +134,6 @@ impl<'a> EvmContext<'a> { if self.attached_deposit == 0 { return Err(EvmError::MissingDeposit); } - let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); let address = Address::from_slice(&args); self.add_balance(&address, U256::from(self.attached_deposit)); Ok(self.balance_of(&address)) @@ -148,7 +141,7 @@ impl<'a> EvmContext<'a> { pub fn withdraw_near(&mut self, args: Vec) -> Result<(), EvmError> { let args = - WithdrawNearArgs::try_from_slice(&args).map_err(|err| EvmError::ArgumentParseError)?; + WithdrawNearArgs::try_from_slice(&args).map_err(|_| EvmError::ArgumentParseError)?; let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); let amount = U256::from(args.amount); if amount > self.balance_of(&sender) { diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 59423cef1ba..90d026d8aed 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -103,7 +103,8 @@ impl<'a> vm::Ext for NearExt<'a> { } fn balance(&self, address: &Address) -> EvmResult { - Ok(self.sub_state.balance_of(address)) + let account = self.sub_state.get_account(address); + Ok(account.balance.into()) } fn blockhash(&mut self, number: &U256) -> H256 { @@ -272,9 +273,9 @@ impl<'a> vm::Ext for NearExt<'a> { fn suicide(&mut self, refund_address: &Address) -> EvmResult<()> { self.sub_state.state.self_destructs.insert(self.context_addr.0); - let balance = self.sub_state.balance_of(&self.context_addr); - self.sub_state.add_balance(refund_address, balance); - self.sub_state.sub_balance(&self.context_addr, balance); + let account = self.sub_state.get_account(&self.context_addr); + self.sub_state.add_balance(refund_address, account.balance.into()); + self.sub_state.sub_balance(&self.context_addr, account.balance.into()); Ok(()) } diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index 533c91dbd2d..22fc2f7cc90 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -1,4 +1,5 @@ -use borsh::BorshDeserialize; +use borsh::{BorshDeserialize, BorshSerialize}; +use ethereum_types::U256; use near_primitives::types::Balance; diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 393596f28ba..9cbbd57e989 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -1,11 +1,24 @@ -use ethereum_types::{Address, U256}; +use ethereum_types::U256; +#[macro_use] +extern crate lazy_static_include; +use ethabi_contract::use_contract; use near_evm_runner::utils::{address_to_vec, near_account_id_to_evm_address}; -use near_evm_runner::{run_evm, EvmContext}; +use near_evm_runner::EvmContext; use near_primitives::hash::CryptoHash; use near_store::test_utils::create_tries; use near_store::ShardTries; +use_contract!(soltest, "tests/build/SolTests.abi"); +use_contract!(subcontract, "tests/build/SubContract.abi"); +use_contract!(create2factory, "tests/build/Create2Factory.abi"); +use_contract!(selfdestruct, "tests/build/SelfDestruct.abi"); + +lazy_static_include_str!(TEST, "tests/build/SolTests.bin"); +lazy_static_include_str!(FACTORY_TEST, "tests/build/Create2Factory.bin"); +lazy_static_include_str!(DESTRUCT_TEST, "tests/build/SelfDestruct.bin"); +lazy_static_include_str!(CONSTRUCTOR_TEST, "tests/build/ConstructorRevert.bin"); + fn accounts(account_id: usize) -> String { vec!["evm", "alice", "bob", "chad"][account_id].to_string() } @@ -33,3 +46,13 @@ fn test_sends() { U256::from(100) ); } + +#[test] +fn test_deploy_with_nonce() { + let (tries, root) = setup(); + let mut state_update = tries.new_trie_update(0, root); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + let address1 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + let address2 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_ne!(address1, address2); +} From 44235f9ea5566686214bcaa266c39ec3b1e0266d Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sun, 30 Aug 2020 07:09:46 -0700 Subject: [PATCH 09/82] Finish implementing functions in EvmContext, adding more tests --- runtime/near-evm-runner/src/evm_state.rs | 121 +++++++----------- runtime/near-evm-runner/src/lib.rs | 81 +++++++++--- runtime/near-evm-runner/src/near_ext.rs | 4 +- runtime/near-evm-runner/src/types.rs | 3 +- runtime/near-evm-runner/src/utils.rs | 15 +++ runtime/near-evm-runner/tests/standard_ops.rs | 56 ++++++-- 6 files changed, 173 insertions(+), 107 deletions(-) diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index 3f818cb2f2e..3e1526c69f8 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -35,42 +35,33 @@ pub trait EvmState { fn set_code(&mut self, address: &Address, bytecode: &[u8]); fn set_account(&mut self, address: &Address, account: &EvmAccount); - fn get_account(&self, address: &Address) -> EvmAccount; + fn get_account(&self, address: &Address) -> Option; fn balance_of(&self, address: &Address) -> U256 { - let account = self.get_account(address); + let account = self.get_account(address).unwrap_or_default(); account.balance.into() } - // fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]); - // fn set_balance(&mut self, address: &Address, balance: U256) { - // let mut bin = [0u8; 32]; - // balance.to_big_endian(&mut bin); - // let internal_addr = utils::evm_account_to_internal_address(*address); - // self._set_balance(internal_addr, bin); - // } - - // fn _balance_of(&self, address: [u8; 20]) -> [u8; 32]; - // fn balance_of(&self, address: &Address) -> U256 { - // let internal_addr = utils::evm_account_to_internal_address(*address); - // self._balance_of(internal_addr).into() - // } - // - // fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]>; - // fn set_nonce(&mut self, address: &Address, nonce: U256) -> Option { - // let mut bin = [0u8; 32]; - // nonce.to_big_endian(&mut bin); - // let internal_addr = utils::evm_account_to_internal_address(*address); - // self._set_nonce(internal_addr, bin).map(|v| v.into()) - // } - // - // fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32]; - // fn nonce_of(&self, address: &Address) -> U256 { - // let internal_addr = utils::evm_account_to_internal_address(*address); - // self._nonce_of(internal_addr).into() - // } + + fn nonce_of(&self, address: &Address) -> U256 { + let account = self.get_account(address).unwrap_or_default(); + account.nonce.into() + } + + fn set_nonce(&mut self, address: &Address, nonce: U256) -> Option { + let mut account = self.get_account(address).unwrap_or_default(); + account.nonce = nonce; + self.set_account(address, &account); + Some(account.nonce) + } + + fn set_balance(&mut self, address: &Address, balance: U256) { + let mut account = self.get_account(address).unwrap_or_default(); + account.balance = balance; + self.set_account(address, &account); + } fn next_nonce(&mut self, address: &Address) -> U256 { - let mut account = self.get_account(address); + let mut account = self.get_account(address).unwrap_or_default(); let nonce = account.nonce; account.nonce += U256::from(1); self.set_account(address, &account); @@ -82,21 +73,16 @@ pub trait EvmState { self._read_contract_storage(utils::internal_storage_key(address, key)) } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Option<[u8; 32]>; + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]); - fn set_contract_storage( - &mut self, - address: &Address, - key: [u8; 32], - value: [u8; 32], - ) -> Option<[u8; 32]> { + fn set_contract_storage(&mut self, address: &Address, key: [u8; 32], value: [u8; 32]) { self._set_contract_storage(utils::internal_storage_key(address, key), value) } fn commit_changes(&mut self, other: &StateStore); fn add_balance(&mut self, address: &Address, incr: U256) -> Result<(), EvmError> { - let mut account = self.get_account(address); + let mut account = self.get_account(address).unwrap_or_default(); account.balance = account.balance.checked_add(incr).ok_or_else(|| EvmError::IntegerOverflow)?; self.set_account(address, &account); @@ -104,7 +90,7 @@ pub trait EvmState { } fn sub_balance(&mut self, address: &Address, decr: U256) -> Result<(), EvmError> { - let mut account = self.get_account(address); + let mut account = self.get_account(address).unwrap_or_default(); account.balance = account.balance.checked_add(decr).ok_or_else(|| EvmError::InsufficientFunds)?; self.set_account(address, &account); @@ -189,13 +175,8 @@ impl EvmState for StateStore { self.accounts.insert(address.0, account.clone()); } - fn get_account(&self, address: &Address) -> EvmAccount { - if self.self_destructs.contains(&address.0) { - None - } else { - self.accounts.get(&address.0).map(|account| account.clone()) - } - .unwrap_or_else(|| EvmAccount::default()) + fn get_account(&self, address: &Address) -> Option { + self.accounts.get(&address.0).map(|account| account.clone()) } fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { @@ -208,8 +189,8 @@ impl EvmState for StateStore { } } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Option<[u8; 32]> { - self.storages.insert(key.to_vec(), value) + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) { + self.storages.insert(key.to_vec(), value); } fn commit_changes(&mut self, other: &StateStore) { @@ -245,6 +226,13 @@ impl SubState<'_> { ) -> SubState<'a> { SubState { msg_sender, state, parent } } + + pub fn self_destruct(&mut self, address: &Address) { + self.state.self_destructs.insert(address.0); + let mut account = self.get_account(address).unwrap_or_default(); + account.nonce = U256::from(0); + self.state.set_account(address, &account); + } } impl EvmState for SubState<'_> { @@ -269,29 +257,9 @@ impl EvmState for SubState<'_> { self.state.set_account(address, account); } - fn get_account(&self, address: &Address) -> EvmAccount { - self.state.get_account(address) - } - // fn _set_balance(&mut self, address: [u8; 20], balance: [u8; 32]) { - // self.state.balances.insert(address, balance); - // } - // - // fn _balance_of(&self, address: [u8; 20]) -> [u8; 32] { - // self.state.balances.get(&address).map_or_else(|| self.parent._balance_of(address), |k| *k) - // } - // - // fn _set_nonce(&mut self, address: [u8; 20], nonce: [u8; 32]) -> Option<[u8; 32]> { - // self.state.nonces.insert(address, nonce) - // } - // - // fn _nonce_of(&self, address: [u8; 20]) -> [u8; 32] { - // let empty = [0u8; 32]; - // if self.state.self_destructs.contains(&address) { - // empty - // } else { - // self.state.nonces.get(&address).map_or_else(|| self.parent._nonce_of(address), |k| *k) - // } - // } + fn get_account(&self, address: &Address) -> Option { + self.state.get_account(address).or_else(|| self.parent.get_account(address)) + } fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { let mut addr = [0u8; 20]; @@ -307,8 +275,8 @@ impl EvmState for SubState<'_> { } } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Option<[u8; 32]> { - self.state.storages.insert(key.to_vec(), value) + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) { + self.state.storages.insert(key.to_vec(), value); } fn commit_changes(&mut self, other: &StateStore) { @@ -320,8 +288,8 @@ impl EvmState for SubState<'_> { self.state.logs.extend(other.logs.iter().cloned()); } - fn recreate(&mut self, _address: [u8; 20]) { - unimplemented!() + fn recreate(&mut self, address: [u8; 20]) { + self.state.recreate(address); } } @@ -334,7 +302,6 @@ mod test { let addr_0 = Address::repeat_byte(0); let addr_1 = Address::repeat_byte(1); let addr_2 = Address::repeat_byte(2); - // let addr_3 = Address::repeat_byte(3); let zero = U256::zero(); let code: [u8; 3] = [0, 1, 2]; let nonce = U256::from_dec_str("103030303").unwrap(); @@ -473,7 +440,7 @@ mod test { assert_eq!(sub_1.balance_of(&addr_1), balance_0); assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_1), Some(storage_value_1)); - sub_1.state.self_destructs.insert(addr_1.0); + sub_1.self_destruct(&addr_1); sub_1.set_balance(&addr_1, balance_1); assert_eq!(sub_1.code_at(&addr_1), None); diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index caeaccd4d96..18a1e595ad3 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -7,7 +7,7 @@ use near_store::TrieUpdate; use near_vm_errors::VMError; use near_vm_logic::VMOutcome; -use crate::errors::EvmError; +pub use crate::errors::EvmError; use crate::evm_state::{EvmAccount, EvmState, StateStore}; use crate::types::{GetCodeArgs, GetStorageAtArgs, WithdrawNearArgs}; use near_primitives::trie_key::TrieKey; @@ -27,49 +27,94 @@ pub struct EvmContext<'a> { attached_deposit: Balance, } +enum KeyPrefix { + Account = 0, + Contract = 1, +} + +fn address_to_key(prefix: KeyPrefix, address: &H160) -> Vec { + let mut result = Vec::with_capacity(21); + result.push(prefix as u8); + result.extend_from_slice(&address.0); + result +} + impl<'a> EvmState for EvmContext<'a> { fn code_at(&self, address: &H160) -> Option> { - unimplemented!() + self.trie_update + .get(&TrieKey::ContractData { + account_id: self.account_id.clone(), + key: address_to_key(KeyPrefix::Contract, address), + }) + .unwrap_or(None) } fn set_code(&mut self, address: &H160, bytecode: &[u8]) { - unimplemented!() + self.trie_update.set( + TrieKey::ContractData { + account_id: self.account_id.clone(), + key: address_to_key(KeyPrefix::Contract, address), + }, + bytecode.to_vec(), + ) } fn set_account(&mut self, address: &Address, account: &EvmAccount) { self.trie_update.set( - TrieKey::ContractData { account_id: self.account_id.clone(), key: address.0.to_vec() }, + TrieKey::ContractData { + account_id: self.account_id.clone(), + key: address_to_key(KeyPrefix::Account, address), + }, account.try_to_vec().expect("Failed to serialize"), ) } - fn get_account(&self, address: &Address) -> EvmAccount { + fn get_account(&self, address: &Address) -> Option { // TODO: handle error propagation? self.trie_update .get(&TrieKey::ContractData { account_id: self.account_id.clone(), - key: address.0.to_vec(), + key: address_to_key(KeyPrefix::Account, address), }) .unwrap_or_else(|_| None) - .map(|value| EvmAccount::try_from_slice(&value)) - .unwrap_or_else(|| Ok(EvmAccount::default())) - .unwrap_or_else(|_| EvmAccount::default()) + .map(|value| EvmAccount::try_from_slice(&value).unwrap_or_default()) } fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { - unimplemented!() + self.trie_update + .get(&TrieKey::ContractData { account_id: self.account_id.clone(), key: key.to_vec() }) + .unwrap_or_else(|_| None) + .map(utils::vec_to_arr_32) } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Option<[u8; 32]> { - unimplemented!() + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) { + self.trie_update.set( + TrieKey::ContractData { account_id: self.account_id.clone(), key: key.to_vec() }, + value.to_vec(), + ); } - fn commit_changes(&mut self, _other: &StateStore) { - unimplemented!() + fn commit_changes(&mut self, other: &StateStore) { + // self.commit_self_destructs(&other.self_destructs); + // self.commit_self_destructs(&other.recreated); + for (address, code) in other.code.iter() { + self.set_code(&H160(*address), code); + } + for (address, account) in other.accounts.iter() { + self.set_account(&H160(*address), account); + } + for (key, value) in other.storages.iter() { + let mut arr = [0; 52]; + arr.copy_from_slice(&key); + self._set_contract_storage(arr, *value); + } + // for log in &other.logs { + // near_sdk::env::log(format!("evm log: {}", log).as_bytes()); + // } } fn recreate(&mut self, _address: [u8; 20]) { - unimplemented!() + unreachable!() } } @@ -97,7 +142,7 @@ impl<'a> EvmContext<'a> { U256::from(self.attached_deposit), 0, CreateContractAddress::FromSenderAndNonce, - true, + false, &bytecode, ) } @@ -130,6 +175,10 @@ impl<'a> EvmContext<'a> { Ok(self.balance_of(&Address::from_slice(&args))) } + pub fn get_nonce(&self, args: Vec) -> Result { + Ok(self.nonce_of(&Address::from_slice(&args))) + } + pub fn deposit_near(&mut self, args: Vec) -> Result { if self.attached_deposit == 0 { return Err(EvmError::MissingDeposit); diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 90d026d8aed..0ee51dce154 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -103,7 +103,7 @@ impl<'a> vm::Ext for NearExt<'a> { } fn balance(&self, address: &Address) -> EvmResult { - let account = self.sub_state.get_account(address); + let account = self.sub_state.get_account(address).unwrap_or_default(); Ok(account.balance.into()) } @@ -273,7 +273,7 @@ impl<'a> vm::Ext for NearExt<'a> { fn suicide(&mut self, refund_address: &Address) -> EvmResult<()> { self.sub_state.state.self_destructs.insert(self.context_addr.0); - let account = self.sub_state.get_account(&self.context_addr); + let account = self.sub_state.get_account(&self.context_addr).unwrap_or_default(); self.sub_state.add_balance(refund_address, account.balance.into()); self.sub_state.sub_balance(&self.context_addr, account.balance.into()); Ok(()) diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index 22fc2f7cc90..533c91dbd2d 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -1,5 +1,4 @@ -use borsh::{BorshDeserialize, BorshSerialize}; -use ethereum_types::U256; +use borsh::BorshDeserialize; use near_primitives::types::Balance; diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index a82a6d0987c..af072a32884 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -31,6 +31,20 @@ pub fn hex_to_evm_address(address: &str) -> Address { Address::from_slice(&addr) } +pub fn encode_call_function_args(address: Address, input: Vec) -> Vec { + let mut result = Vec::with_capacity(20 + input.len()); + result.extend_from_slice(&address.0); + result.extend_from_slice(&input); + result +} + +pub fn address_from_arr(arr: &[u8]) -> Address { + assert_eq!(arr.len(), 20); + let mut address = [0u8; 20]; + address.copy_from_slice(&arr); + Address::from(address) +} + pub fn balance_to_u256(val: &Balance) -> U256 { let mut bin = [0u8; 32]; bin[16..].copy_from_slice(&val.to_be_bytes()); @@ -56,6 +70,7 @@ pub fn address_to_vec(val: &Address) -> Vec { } pub fn vec_to_arr_32(v: Vec) -> [u8; 32] { + assert_eq!(v.len(), 32); let mut result = [0; 32]; result.copy_from_slice(&v); result diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 9cbbd57e989..693c008dcfa 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -1,13 +1,16 @@ -use ethereum_types::U256; #[macro_use] extern crate lazy_static_include; use ethabi_contract::use_contract; -use near_evm_runner::utils::{address_to_vec, near_account_id_to_evm_address}; -use near_evm_runner::EvmContext; +use ethereum_types::{Address, U256}; + +use near_evm_runner::utils::{ + address_from_arr, address_to_vec, encode_call_function_args, near_account_id_to_evm_address, +}; +use near_evm_runner::{EvmContext, EvmError}; use near_primitives::hash::CryptoHash; use near_store::test_utils::create_tries; -use near_store::ShardTries; +use near_store::{ShardTries, TrieUpdate}; use_contract!(soltest, "tests/build/SolTests.abi"); use_contract!(subcontract, "tests/build/SubContract.abi"); @@ -23,16 +26,15 @@ fn accounts(account_id: usize) -> String { vec!["evm", "alice", "bob", "chad"][account_id].to_string() } -fn setup() -> (ShardTries, CryptoHash) { +fn setup() -> TrieUpdate { let tries = create_tries(); let root = CryptoHash::default(); - (tries, root) + tries.new_trie_update(0, root) } #[test] fn test_sends() { - let (tries, root) = setup(); - let mut state_update = tries.new_trie_update(0, root); + let mut state_update = setup(); let context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); assert_eq!( context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), @@ -49,10 +51,44 @@ fn test_sends() { #[test] fn test_deploy_with_nonce() { - let (tries, root) = setup(); - let mut state_update = tries.new_trie_update(0, root); + let mut state_update = setup(); let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + let address = near_account_id_to_evm_address(&accounts(1)); + assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(0)); let address1 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(1)); let address2 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(2)); assert_ne!(address1, address2); } + +#[test] +fn test_failed_deploy_returns_error() { + let mut state_update = setup(); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + if let Err(EvmError::DeployFail(_)) = + context.deploy_code(hex::decode(&CONSTRUCTOR_TEST).unwrap()) + { + } else { + panic!("Should fail"); + } +} + +#[test] +fn test_internal_create() { + let mut state_update = setup(); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); + + // This should increment the nonce of the deploying contract + let (input, _) = soltest::functions::deploy_new_guy::call(8); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(1)); + + let sub_addr = address_from_arr(&raw[12..32]); + let (new_input, _) = subcontract::functions::a_number::call(); + let new_raw = context.call_function(encode_call_function_args(sub_addr, new_input)).unwrap(); + let output = subcontract::functions::a_number::decode_output(&new_raw).unwrap(); + assert_eq!(output, U256::from(8)); +} From 457d6370f5adfba34f922506c3de4ecc81132065 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sun, 30 Aug 2020 08:17:39 -0700 Subject: [PATCH 10/82] End to end test: deploy contract into evm via runtime --- Cargo.lock | 710 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 576 insertions(+), 134 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f022571e78d..37f9eb8c0c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,7 @@ dependencies = [ "log", "parking_lot 0.10.2", "pin-project", - "smallvec", + "smallvec 1.4.0", "tokio", "tokio-util 0.2.0", "trust-dns-proto", @@ -128,7 +128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21705adc76bbe4bc98434890e73a89cd00c6015e5704a60bb6eea6c3b72316b6" dependencies = [ "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -155,7 +155,7 @@ dependencies = [ "copyless", "futures-channel", "futures-util", - "smallvec", + "smallvec 1.4.0", "tokio", ] @@ -297,9 +297,9 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f00371942083469785f7e28c540164af1913ee7c96a4534acb9cea92c39f057" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -308,9 +308,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b95aceadaf327f18f0df5962fedc1bde2f870566a0b9f65c89508a3b1f79334c" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -355,6 +355,15 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +dependencies = [ + "nodrop", +] + [[package]] name = "arrayvec" version = "0.5.1" @@ -373,9 +382,9 @@ version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da71fef07bc806586090247e971229289f64c210a278ee5ae419314eb386b31d" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -491,7 +500,7 @@ dependencies = [ "lazycell", "log", "peeking_take_while", - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", "regex", "rustc-hash", @@ -499,6 +508,21 @@ dependencies = [ "which", ] +[[package]] +name = "bit-set" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" + [[package]] name = "bitflags" version = "1.2.1" @@ -513,8 +537,8 @@ checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330" dependencies = [ "byte-tools", "crypto-mac", - "digest", - "opaque-debug", + "digest 0.8.1", + "opaque-debug 0.2.3", ] [[package]] @@ -524,7 +548,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" dependencies = [ "arrayref", - "arrayvec", + "arrayvec 0.5.1", "constant_time_eq", ] @@ -535,12 +559,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "423897d97e11b810c9da22458400b28ec866991c711409073662eb34dc44bfff" dependencies = [ "arrayref", - "arrayvec", + "arrayvec 0.5.1", "cc", "cfg-if", "constant_time_eq", "crypto-mac", - "digest", + "digest 0.8.1", ] [[package]] @@ -552,7 +576,16 @@ dependencies = [ "block-padding", "byte-tools", "byteorder", - "generic-array", + "generic-array 0.12.3", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.4", ] [[package]] @@ -564,6 +597,18 @@ dependencies = [ "byte-tools", ] +[[package]] +name = "bn" +version = "0.4.4" +source = "git+https://github.com/paritytech/bn#635c4cdd560bc0c8b262e6bf809dc709da8bcd7e" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand 0.5.6", + "rustc-hex 2.1.0", +] + [[package]] name = "borsh" version = "0.7.1" @@ -581,7 +626,7 @@ checksum = "b2d74755d937d261d5e9bdef87e0addfbc1ace0214f7776f21532d6e97325356" dependencies = [ "borsh-derive-internal", "borsh-schema-derive-internal", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -590,9 +635,9 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c9f966cb7a42c8ed83546ef481bc1d1dec888fe5f84a4737d5c2094a483e41e" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -601,9 +646,9 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5df2543b56ebc2b4493e70d024ebde2cbb48d97bf7b1a16318eff30bd02669b8" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -804,9 +849,9 @@ checksum = "fb51c9e75b94452505acd21d929323f5a5c6c4735a852adbd39ef5fb1b014f30" dependencies = [ "heck", "proc-macro-error 0.4.12", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.20", + "quote 1.0.3", + "syn 1.0.38", ] [[package]] @@ -925,7 +970,7 @@ dependencies = [ "log", "regalloc", "serde", - "smallvec", + "smallvec 1.4.0", "target-lexicon", "thiserror", ] @@ -963,7 +1008,7 @@ checksum = "3062a6fce384623ac2d19e98e7c774c944584bb5a8e42910e93dcebed7c44d87" dependencies = [ "cranelift-codegen", "log", - "smallvec", + "smallvec 1.4.0", "target-lexicon", ] @@ -1035,7 +1080,7 @@ dependencies = [ "lazy_static", "maybe-uninit", "memoffset", - "scopeguard", + "scopeguard 1.1.0", ] [[package]] @@ -1071,7 +1116,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" dependencies = [ - "generic-array", + "generic-array 0.12.3", "subtle 1.0.0", ] @@ -1104,7 +1149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26778518a7f6cffa1d25a44b602b62b979bd88adb9e99ffec546998cf3404839" dependencies = [ "byteorder", - "digest", + "digest 0.8.1", "rand_core 0.5.1", "subtle 2.2.2", "zeroize", @@ -1123,9 +1168,9 @@ version = "0.99.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2323f3f47db9a0e77ce7a300605d8d2098597fc451ed1a97bb1f6411bb550a7" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -1134,9 +1179,9 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3df5480412da86cdf5d6b7f3b682422c84359ff7399aa658df1d15ee83244b1d" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -1145,7 +1190,16 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array", + "generic-array 0.12.3", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.4", ] [[package]] @@ -1202,9 +1256,9 @@ dependencies = [ "byteorder", "lazy_static", "owning_ref", - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -1224,7 +1278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2a9b11b96248fc9efa0c093e6406fea7e55a7e893c932dbdf47074f34ec52e7" dependencies = [ "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -1245,6 +1299,15 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +[[package]] +name = "elastic-array" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "580f3768bd6465780d063f5b8213a2ebd506e139b345e4a81eb301ceae3d61e1" +dependencies = [ + "heapsize", +] + [[package]] name = "elastic-array" version = "0.11.0" @@ -1276,9 +1339,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc4bfcfacb61d231109d1d55202c1f33263319668b168843e02ad4652725ec9c" dependencies = [ "heck", - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -1445,9 +1508,9 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", "synstructure", ] @@ -1473,13 +1536,26 @@ dependencies = [ "log", ] +[[package]] +name = "fixed-hash" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1a683d1234507e4f3bf2736eeddf0de1dc65996dc0164d57eba0a74bcf29489" +dependencies = [ + "byteorder", + "heapsize", + "rand 0.5.6", + "rustc-hex 2.1.0", + "static_assertions 0.2.5", +] + [[package]] name = "fixed-hash" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32529fc42e86ec06e5047092082aab9ad459b070c5d2a76b14f4f5ce70bf2e84" dependencies = [ - "static_assertions", + "static_assertions 1.1.0", ] [[package]] @@ -1521,6 +1597,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -1592,9 +1674,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -1656,6 +1738,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "genesis-csv-to-json" version = "0.1.0" @@ -1714,11 +1806,11 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81dd6190aad0f05ddbbf3245c54ed14ca4aa6dd32f22312b70d8f168c3e3e633" dependencies = [ - "arrayvec", + "arrayvec 0.5.1", "byteorder", "fallible-iterator", "indexmap", - "smallvec", + "smallvec 1.4.0", "stable_deref_trait", ] @@ -1739,9 +1831,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34a97a52fdee1870a34fa6e4b77570cba531b27d1838874fef4429a791a3d657" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -1795,6 +1887,12 @@ dependencies = [ "tokio-util 0.3.1", ] +[[package]] +name = "hash-db" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b03501f6e1a2a97f1618879aba3156f14ca2847faa530c4e28859638bd11483" + [[package]] name = "heapsize" version = "0.4.2" @@ -1822,6 +1920,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" + [[package]] name = "hex" version = "0.4.2" @@ -1847,6 +1951,27 @@ dependencies = [ "proc-macro-hack", ] +[[package]] +name = "hmac" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" +dependencies = [ + "crypto-mac", + "digest 0.8.1", +] + +[[package]] +name = "hmac-drbg" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" +dependencies = [ + "digest 0.8.1", + "generic-array 0.12.3", + "hmac", +] + [[package]] name = "hostname" version = "0.3.1" @@ -1981,6 +2106,33 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d" +[[package]] +name = "impl-codec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2050d823639fbeae26b2b5ba09aca8907793117324858070ade0673c49f793b" +dependencies = [ + "parity-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f7a72f11830b52333f36e3b09a288333888bf54380fd0ac0790a3c31ab0f3c5" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8" +dependencies = [ + "serde", +] + [[package]] name = "indexer-example" version = "0.1.0" @@ -2065,7 +2217,7 @@ checksum = "2cdea9771bec3d95893f6c665a4fcd477af7858446a46bc2772f560534eee43b" dependencies = [ "derive_utils", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -2137,6 +2289,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" +[[package]] +name = "keccak-hash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e8ee697b9aa6dcc34d7657565fa5052763a1627a5b59e4c3c0ae3ed0d70a65" +dependencies = [ + "primitive-types 0.3.0", + "tiny-keccak", +] + +[[package]] +name = "keccak-hasher" +version = "0.1.1" +source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +dependencies = [ + "ethereum-types", + "hash-db", + "plain_hasher", + "tiny-keccak", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -2170,7 +2343,7 @@ checksum = "e10200e516c7a80a6dcfb1cdc23cd01ca0d8e97df71e9c5aa6d116302b89a928" dependencies = [ "lazy_static", "starts-ends-with-caseless", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -2178,6 +2351,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "lazycell" @@ -2218,6 +2394,22 @@ dependencies = [ "libc", ] +[[package]] +name = "libsecp256k1" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" +dependencies = [ + "arrayref", + "crunchy", + "digest 0.8.1", + "hmac-drbg", + "rand 0.7.3", + "sha2", + "subtle 2.2.2", + "typenum", +] + [[package]] name = "lightbeam" version = "0.17.0" @@ -2233,7 +2425,7 @@ dependencies = [ "itertools 0.8.2", "memoffset", "more-asserts", - "smallvec", + "smallvec 1.4.0", "staticvec", "thiserror", "typemap", @@ -2270,13 +2462,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "lock_api" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +dependencies = [ + "owning_ref", + "scopeguard 0.3.3", +] + [[package]] name = "lock_api" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" dependencies = [ - "scopeguard", + "scopeguard 1.1.0", ] [[package]] @@ -2285,7 +2487,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c" dependencies = [ - "scopeguard", + "scopeguard 1.1.0", "serde", ] @@ -2368,6 +2570,15 @@ dependencies = [ "autocfg 1.0.0", ] +[[package]] +name = "memory-cache" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +dependencies = [ + "heapsize", + "lru-cache", +] + [[package]] name = "mime" version = "0.3.16" @@ -2601,7 +2812,7 @@ dependencies = [ "bs58", "c2-chacha", "curve25519-dalek", - "digest", + "digest 0.8.1", "ed25519-dalek", "hex-literal", "lazy_static", @@ -2627,7 +2838,7 @@ dependencies = [ "near-primitives", "near-store", "num-rational 0.2.4", - "primitive-types", + "primitive-types 0.7.0", "rand 0.6.5", "rand 0.7.3", "serde", @@ -2808,14 +3019,14 @@ dependencies = [ "chrono", "derive_more", "easy-ext", - "hex", + "hex 0.4.2", "jemallocator", "lazy_static", "near-crypto", "near-rpc-error-macro", "near-vm-errors", "num-rational 0.2.4", - "primitive-types", + "primitive-types 0.7.0", "rand 0.7.3", "reed-solomon-erasure", "regex", @@ -2854,11 +3065,11 @@ dependencies = [ name = "near-rpc-error-core" version = "0.1.0" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", "serde", "serde_json", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -2866,11 +3077,11 @@ name = "near-rpc-error-macro" version = "0.1.0" dependencies = [ "near-rpc-error-core", - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", "serde", "serde_json", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -2916,7 +3127,7 @@ dependencies = [ "byteorder", "cached", "derive_more", - "elastic-array", + "elastic-array 0.11.0", "lazy_static", "near-crypto", "near-primitives", @@ -3106,7 +3317,7 @@ dependencies = [ "borsh", "byteorder", "cached", - "hex", + "hex 0.4.2", "indicatif 0.13.0", "lazy_static", "log", @@ -3132,6 +3343,12 @@ dependencies = [ "testlib", ] +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + [[package]] name = "nom" version = "5.1.1" @@ -3210,9 +3427,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" dependencies = [ "autocfg 1.0.0", ] @@ -3245,6 +3462,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "openssl" version = "0.10.29" @@ -3379,11 +3602,27 @@ dependencies = [ "http", "lazy_static", "proc-macro-error 1.0.4", - "proc-macro2", - "quote", + "proc-macro2 1.0.20", + "quote 1.0.3", "strum", "strum_macros", - "syn", + "syn 1.0.38", +] + +[[package]] +name = "parity-bytes" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b56e3a2420138bdb970f84dfb9c774aea80fa0e7371549eedec0d80c209c67" + +[[package]] +name = "parity-codec" +version = "3.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b9df1283109f542d8852cd6b30e9341acc2137481eb6157d2e62af68b0afec9" +dependencies = [ + "arrayvec 0.4.12", + "serde", ] [[package]] @@ -3392,7 +3631,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fca4f82fccae37e8bbdaeb949a4a218a1bbc485d11598f193d2a908042e5fc1" dependencies = [ - "arrayvec", + "arrayvec 0.5.1", "cc", "cfg-if", "rand 0.7.3", @@ -3404,6 +3643,16 @@ version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" +[[package]] +name = "parking_lot" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +dependencies = [ + "lock_api 0.1.5", + "parking_lot_core 0.4.0", +] + [[package]] name = "parking_lot" version = "0.10.2" @@ -3425,6 +3674,19 @@ dependencies = [ "parking_lot_core 0.8.0", ] +[[package]] +name = "parking_lot_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +dependencies = [ + "libc", + "rand 0.6.5", + "rustc_version", + "smallvec 0.6.13", + "winapi 0.3.8", +] + [[package]] name = "parking_lot_core" version = "0.7.2" @@ -3435,7 +3697,7 @@ dependencies = [ "cloudabi 0.0.3", "libc", "redox_syscall", - "smallvec", + "smallvec 1.4.0", "winapi 0.3.8", ] @@ -3450,10 +3712,24 @@ dependencies = [ "instant", "libc", "redox_syscall", - "smallvec", + "smallvec 1.4.0", "winapi 0.3.8", ] +[[package]] +name = "patricia-trie-ethereum" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +dependencies = [ + "elastic-array 0.10.3", + "ethereum-types", + "hash-db", + "keccak-hasher", + "parity-bytes", + "rlp", + "trie-db", +] + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -3487,9 +3763,9 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8988430ce790d8682672117bc06dda364c0be32d3abd738234f19f3240bad99a" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -3516,20 +3792,42 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "plain_hasher" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e19e6491bdde87c2c43d70f4c194bc8a758f2eb732df00f61e43f7362e3b4cc" +dependencies = [ + "crunchy", +] + [[package]] name = "ppv-lite86" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +[[package]] +name = "primitive-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2288eb2a39386c4bc817974cc413afe173010dc80e470fcb1e9a35580869f024" +dependencies = [ + "fixed-hash 0.3.2", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint 0.7.1", +] + [[package]] name = "primitive-types" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5e4b9943a2da369aec5e96f7c10ebc74fcf434d39590d974b0a3460e6f67fbb" dependencies = [ - "fixed-hash", - "uint", + "fixed-hash 0.6.0", + "uint 0.8.2", ] [[package]] @@ -3539,9 +3837,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" dependencies = [ "proc-macro-error-attr 0.4.12", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.20", + "quote 1.0.3", + "syn 1.0.38", "version_check", ] @@ -3552,9 +3850,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr 1.0.4", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.20", + "quote 1.0.3", + "syn 1.0.38", "version_check", ] @@ -3564,9 +3862,9 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", "syn-mid", "version_check", ] @@ -3577,8 +3875,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.20", + "quote 1.0.3", "version_check", ] @@ -3605,9 +3903,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.10" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" +checksum = "175c513d55719db99da20232b06cda8bab6b83ec2d04e3283edf0213c37c1a29" dependencies = [ "unicode-xid 0.2.0", ] @@ -3664,7 +3962,20 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", +] + +[[package]] +name = "rand" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" +dependencies = [ + "cloudabi 0.0.3", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "winapi 0.3.8", ] [[package]] @@ -3680,6 +3991,7 @@ dependencies = [ "rand_hc 0.1.0", "rand_isaac", "rand_jitter", + "rand_os", "rand_pcg", "rand_xorshift 0.1.1", "winapi 0.3.8", @@ -3780,6 +4092,20 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi 0.0.3", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi 0.3.8", +] + [[package]] name = "rand_pcg" version = "0.1.2" @@ -3843,6 +4169,15 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.1.56" @@ -3866,7 +4201,7 @@ version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a415a013dd7c5d4221382329a5a3482566da675737494935cbbbcdec04662f9d" dependencies = [ - "smallvec", + "smallvec 1.4.0", ] [[package]] @@ -3877,7 +4212,7 @@ checksum = "cca5b48c9db66c5ba084e4660b4c0cfe8b551a96074bc04b7c11de86ad0bf1f9" dependencies = [ "log", "rustc-hash", - "smallvec", + "smallvec 1.4.0", ] [[package]] @@ -4007,6 +4342,26 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "ripemd160" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "rlp" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a7d3f9bed94764eac15b8f14af59fac420c236adaff743b7bcc88e265cb4345" +dependencies = [ + "rustc-hex 2.1.0", +] + [[package]] name = "rocksdb" version = "0.14.0" @@ -4067,6 +4422,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -4111,6 +4472,12 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "scopeguard" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" + [[package]] name = "scopeguard" version = "1.1.0" @@ -4132,9 +4499,9 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e367622f934864ffa1c704ba2b82280aab856e3d8213c84c5720257eb34b15b9" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -4228,9 +4595,9 @@ version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -4281,10 +4648,10 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" dependencies = [ - "block-buffer", - "digest", + "block-buffer 0.7.3", + "digest 0.8.1", "fake-simd", - "opaque-debug", + "opaque-debug 0.2.3", ] [[package]] @@ -4293,11 +4660,11 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" dependencies = [ - "block-buffer", + "block-buffer 0.7.3", "byte-tools", - "digest", + "digest 0.8.1", "keccak", - "opaque-debug", + "opaque-debug 0.2.3", ] [[package]] @@ -4331,6 +4698,15 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +[[package]] +name = "smallvec" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" +dependencies = [ + "maybe-uninit", +] + [[package]] name = "smallvec" version = "1.4.0" @@ -4343,9 +4719,9 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -4398,6 +4774,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "static_assertions" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" + [[package]] name = "static_assertions" version = "1.1.0" @@ -4433,7 +4815,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" dependencies = [ - "generic-array", + "generic-array 0.12.3", ] [[package]] @@ -4473,9 +4855,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" dependencies = [ "heck", - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -4490,13 +4872,24 @@ version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + [[package]] name = "syn" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", "unicode-xid 0.2.0", ] @@ -4507,9 +4900,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -4518,9 +4911,9 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", "unicode-xid 0.2.0", ] @@ -4586,7 +4979,7 @@ dependencies = [ "byteorder", "clap 2.33.0", "futures", - "hex", + "hex 0.4.2", "lazy_static", "log", "near-chain", @@ -4633,9 +5026,9 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -4666,6 +5059,15 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "tiny-keccak" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8a021c69bb74a44ccedb824a046447e2c84a01df9e5c20779750acb38e11b2" +dependencies = [ + "crunchy", +] + [[package]] name = "tokio" version = "0.2.18" @@ -4696,9 +5098,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -4794,7 +5196,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fbad39da2f9af1cae3016339ad7f2c7a9e870f12e8fd04c4fd7ef35b30c0d2b" dependencies = [ "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -4841,7 +5243,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec", + "smallvec 1.4.0", "tracing-core", "tracing-log", "tracing-serde", @@ -4853,6 +5255,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +[[package]] +name = "trie-db" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c7319e28ca295f27359d944a682f7f65b419158bf1590c92cadc0000258d788" +dependencies = [ + "elastic-array 0.10.3", + "hash-db", + "log", + "rand 0.6.5", +] + [[package]] name = "trust-dns-proto" version = "0.18.0-alpha.2" @@ -4867,7 +5281,7 @@ dependencies = [ "lazy_static", "log", "rand 0.7.3", - "smallvec", + "smallvec 1.4.0", "socket2", "tokio", "url 2.1.1", @@ -4887,7 +5301,7 @@ dependencies = [ "log", "lru-cache", "resolv-conf", - "smallvec", + "smallvec 1.4.0", "tokio", "trust-dns-proto", ] @@ -4913,6 +5327,18 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +[[package]] +name = "uint" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2143cded94692b156c356508d92888acc824db5bffc0b4089732264c6fcf86d4" +dependencies = [ + "byteorder", + "crunchy", + "heapsize", + "rustc-hex 2.1.0", +] + [[package]] name = "uint" version = "0.8.2" @@ -4921,8 +5347,8 @@ checksum = "e75a4cdd7b87b28840dba13c483b9a88ee6bbf16ba5c951ee1ecfcf723078e0d" dependencies = [ "byteorder", "crunchy", - "rustc-hex", - "static_assertions", + "rustc-hex 2.1.0", + "static_assertions 1.1.0", ] [[package]] @@ -4949,7 +5375,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" dependencies = [ - "smallvec", + "smallvec 1.4.0", ] [[package]] @@ -5045,10 +5471,10 @@ checksum = "e668e9cd05c5009b833833aa1147e5727b5396ea401f22dd1167618eed4a10c9" dependencies = [ "if_chain", "lazy_static", - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", "regex", - "syn 1.0.18", + "syn 1.0.38", "validator", ] @@ -5070,6 +5496,22 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" +[[package]] +name = "vm" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +dependencies = [ + "byteorder", + "ethereum-types", + "ethjson", + "keccak-hash", + "log", + "parity-bytes", + "patricia-trie-ethereum", + "rlp", + "trie-db", +] + [[package]] name = "void" version = "1.0.2" @@ -5120,9 +5562,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c2bb690b44cb1b0fdcc54d4998d21f8bdaf706b93775425e440b174f39ad16" dependencies = [ "heck", - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", ] [[package]] @@ -5162,9 +5604,9 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", "wasm-bindgen-shared", ] @@ -5196,9 +5638,9 @@ version = "0.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.20", "quote 1.0.3", - "syn 1.0.18", + "syn 1.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5232,9 +5674,9 @@ dependencies = [ "bincode", "blake3", "cc", - "digest", + "digest 0.8.1", "errno", - "hex", + "hex 0.4.2", "indexmap", "lazy_static", "libc", @@ -5246,7 +5688,7 @@ dependencies = [ "serde-bench", "serde_bytes", "serde_derive", - "smallvec", + "smallvec 1.4.0", "target-lexicon", "wasmparser 0.51.4", "winapi 0.3.8", @@ -5267,7 +5709,7 @@ dependencies = [ "nix", "serde", "serde_derive", - "smallvec", + "smallvec 1.4.0", "wasmer-runtime-core", ] From 7244105b887743b9d8f50714b6cd58549f1f15a1 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 31 Aug 2020 11:28:02 -0700 Subject: [PATCH 11/82] Adding zombieattack calls in the runtime tests. Transfer functions & tests. --- Cargo.lock | 4 ++ core/primitives/src/test_utils.rs | 21 ++++++++- core/primitives/src/views.rs | 15 +++++- runtime/near-evm-runner/src/evm_state.rs | 2 +- runtime/near-evm-runner/src/lib.rs | 47 +++++++++++++++---- runtime/near-evm-runner/src/types.rs | 16 +++++-- runtime/near-evm-runner/tests/standard_ops.rs | 32 ++++++++++--- test-utils/testlib/Cargo.toml | 4 ++ test-utils/testlib/src/standard_test_cases.rs | 43 +++++++++++++++++ test-utils/testlib/src/user/mod.rs | 11 ++++- test-utils/testlib/src/user/rpc_user.rs | 12 ++++- test-utils/testlib/src/user/runtime_user.rs | 31 +++++++++++- tests/test_cases_testnet_rpc.rs | 5 ++ 13 files changed, 214 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 37f9eb8c0c5..f9c0abbbb92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4978,6 +4978,9 @@ dependencies = [ "borsh", "byteorder", "clap 2.33.0", + "ethabi", + "ethabi-contract", + "ethabi-derive", "futures", "hex 0.4.2", "lazy_static", @@ -4986,6 +4989,7 @@ dependencies = [ "near-chain-configs", "near-client", "near-crypto", + "near-evm-runner", "near-jsonrpc", "near-jsonrpc-client", "near-logger-utils", diff --git a/core/primitives/src/test_utils.rs b/core/primitives/src/test_utils.rs index bed6920006b..543bae2f914 100644 --- a/core/primitives/src/test_utils.rs +++ b/core/primitives/src/test_utils.rs @@ -1,3 +1,7 @@ +use std::collections::HashMap; + +use num_rational::Rational; + use near_crypto::{EmptySigner, PublicKey, Signature, Signer}; use crate::account::{AccessKey, AccessKeyPermission, Account}; @@ -6,6 +10,7 @@ use crate::block_header::{BlockHeader, BlockHeaderV2}; use crate::errors::EpochError; use crate::hash::CryptoHash; use crate::merkle::PartialMerkleTree; +use crate::serialize::from_base64; use crate::transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, FunctionCallAction, SignedTransaction, StakeAction, Transaction, @@ -14,8 +19,7 @@ use crate::transaction::{ use crate::types::{AccountId, Balance, BlockHeight, EpochId, EpochInfoProvider, Gas, Nonce}; use crate::validator_signer::ValidatorSigner; use crate::version::PROTOCOL_VERSION; -use num_rational::Rational; -use std::collections::HashMap; +use crate::views::FinalExecutionStatus; pub fn account_new(amount: Balance, code_hash: CryptoHash) -> Account { Account { amount, locked: 0, code_hash, storage_usage: std::mem::size_of::() as u64 } @@ -414,3 +418,16 @@ impl EpochInfoProvider for MockEpochInfoProvider { Ok(0) } } + +impl FinalExecutionStatus { + pub fn as_success(self) -> Option { + match self { + FinalExecutionStatus::SuccessValue(value) => Some(value), + _ => None, + } + } + + pub fn as_success_decoded(self) -> Option> { + self.as_success().and_then(|value| from_base64(&value).ok()) + } +} diff --git a/core/primitives/src/views.rs b/core/primitives/src/views.rs index 4e2b8de85b0..cf4d68b6e52 100644 --- a/core/primitives/src/views.rs +++ b/core/primitives/src/views.rs @@ -174,7 +174,9 @@ pub struct ViewStateResult { pub proof: TrieProofPath, } -#[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +#[derive( + BorshSerialize, BorshDeserialize, Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default, +)] pub struct CallResult { pub result: Vec, pub logs: Vec, @@ -296,6 +298,17 @@ impl TryFrom for AccountView { } } +impl TryFrom for CallResult { + type Error = String; + + fn try_from(query_response: QueryResponse) -> Result { + match query_response.kind { + QueryResponseKind::CallResult(res) => Ok(res), + _ => Err("Invalid type of response".into()), + } + } +} + impl TryFrom for ViewStateResult { type Error = String; diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index 3e1526c69f8..926647465dc 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -92,7 +92,7 @@ pub trait EvmState { fn sub_balance(&mut self, address: &Address, decr: U256) -> Result<(), EvmError> { let mut account = self.get_account(address).unwrap_or_default(); account.balance = - account.balance.checked_add(decr).ok_or_else(|| EvmError::InsufficientFunds)?; + account.balance.checked_sub(decr).ok_or_else(|| EvmError::InsufficientFunds)?; self.set_account(address, &account); Ok(()) } diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 18a1e595ad3..ab9930b5043 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -9,8 +9,10 @@ use near_vm_logic::VMOutcome; pub use crate::errors::EvmError; use crate::evm_state::{EvmAccount, EvmState, StateStore}; -use crate::types::{GetCodeArgs, GetStorageAtArgs, WithdrawNearArgs}; -use near_primitives::trie_key::TrieKey; +use crate::types::{GetCodeArgs, GetStorageAtArgs, TransferArgs, WithdrawArgs}; +use near_primitives::receipt::Receipt; +use near_vm_errors::FunctionCallError; +use near_vm_logic::types::ReturnData; mod builtins; mod errors; @@ -157,6 +159,19 @@ impl<'a> EvmContext<'a> { .map(|rd| rd.to_vec()) } + /// Make an EVM transaction. Calls `contract_address` with `encoded_input`. Execution + /// continues until all EVM messages have been processed. We expect this to behave identically + /// to an Ethereum transaction, however there may be some edge cases. + /// + /// This function serves the eth_call functionality, and will NOT apply state changes. + pub fn view_call_function(&mut self, args: Vec) -> Result, EvmError> { + let contract_address = Address::from_slice(&args[..20]); + let input = &args[20..]; + let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); + interpreter::call(self, &sender, &sender, None, 0, &contract_address, &input, false) + .map(|rd| rd.to_vec()) + } + pub fn get_code(&self, args: Vec) -> Result, EvmError> { let args = GetCodeArgs::try_from_slice(&args).map_err(|_| EvmError::ArgumentParseError)?; Ok(self.code_at(&Address::from_slice(&args.address)).unwrap_or(vec![])) @@ -179,27 +194,37 @@ impl<'a> EvmContext<'a> { Ok(self.nonce_of(&Address::from_slice(&args))) } - pub fn deposit_near(&mut self, args: Vec) -> Result { + pub fn deposit(&mut self, args: Vec) -> Result { if self.attached_deposit == 0 { return Err(EvmError::MissingDeposit); } let address = Address::from_slice(&args); - self.add_balance(&address, U256::from(self.attached_deposit)); + self.add_balance(&address, U256::from(self.attached_deposit))?; Ok(self.balance_of(&address)) } - pub fn withdraw_near(&mut self, args: Vec) -> Result<(), EvmError> { - let args = - WithdrawNearArgs::try_from_slice(&args).map_err(|_| EvmError::ArgumentParseError)?; + pub fn withdraw(&mut self, args: Vec) -> Result<(), EvmError> { + let args = WithdrawArgs::try_from_slice(&args).map_err(|_| EvmError::ArgumentParseError)?; let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); let amount = U256::from(args.amount); if amount > self.balance_of(&sender) { return Err(EvmError::InsufficientFunds); } - self.sub_balance(&sender, amount); + self.sub_balance(&sender, amount)?; // TODO: add outgoing promise. Ok(()) } + + /// Transfer tokens from sender to given EVM address. + pub fn transfer(&mut self, args: Vec) -> Result<(), EvmError> { + let args = TransferArgs::try_from_slice(&args).map_err(|_| EvmError::ArgumentParseError)?; + let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); + let amount = U256::from(args.amount); + if amount > self.balance_of(&sender) { + return Err(EvmError::InsufficientFunds); + } + self.transfer_balance(&sender, &Address::from(args.account_id), amount) + } } pub fn run_evm( @@ -216,10 +241,12 @@ pub fn run_evm( "deploy_code" => context.deploy_code(args).map(|address| utils::address_to_vec(&address)), "get_code" => context.get_code(args), "call_function" => context.call_function(args), + "view_call_contract" => context.view_call_function(args), "get_storage_at" => context.get_storage_at(args), "get_balance" => context.get_balance(args).map(|balance| utils::u256_to_vec(&balance)), - "deposit_near" => context.deposit_near(args).map(|balance| utils::u256_to_vec(&balance)), - "withdraw_near" => context.withdraw_near(args).map(|_| vec![]), + "deposit" => context.deposit(args).map(|balance| utils::u256_to_vec(&balance)), + "withdraw" => context.withdraw(args).map(|_| vec![]), + "transfer" => context.transfer(args).map(|_| vec![]), _ => Err(EvmError::UnknownError), }; (None, None) diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index 533c91dbd2d..e1a8aa8f60b 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -1,23 +1,29 @@ -use borsh::BorshDeserialize; +use borsh::{BorshDeserialize, BorshSerialize}; use near_primitives::types::Balance; pub type RawAddress = [u8; 20]; pub type RawHash = [u8; 32]; -#[derive(BorshDeserialize)] +#[derive(BorshSerialize, BorshDeserialize)] pub struct GetCodeArgs { pub address: RawAddress, } -#[derive(BorshDeserialize)] +#[derive(BorshSerialize, BorshDeserialize)] pub struct GetStorageAtArgs { pub address: RawAddress, pub key: RawHash, } -#[derive(BorshDeserialize)] -pub struct WithdrawNearArgs { +#[derive(BorshSerialize, BorshDeserialize)] +pub struct WithdrawArgs { pub account_id: String, pub amount: Balance, } + +#[derive(BorshSerialize, BorshDeserialize)] +pub struct TransferArgs { + pub account_id: RawAddress, + pub amount: Balance, +} diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 693c008dcfa..3865f15ef59 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -1,16 +1,18 @@ #[macro_use] extern crate lazy_static_include; +use borsh::BorshSerialize; use ethabi_contract::use_contract; -use ethereum_types::{Address, U256}; +use ethereum_types::U256; +use near_evm_runner::types::{TransferArgs, WithdrawArgs}; use near_evm_runner::utils::{ address_from_arr, address_to_vec, encode_call_function_args, near_account_id_to_evm_address, }; use near_evm_runner::{EvmContext, EvmError}; use near_primitives::hash::CryptoHash; use near_store::test_utils::create_tries; -use near_store::{ShardTries, TrieUpdate}; +use near_store::TrieUpdate; use_contract!(soltest, "tests/build/SolTests.abi"); use_contract!(subcontract, "tests/build/SubContract.abi"); @@ -33,7 +35,7 @@ fn setup() -> TrieUpdate { } #[test] -fn test_sends() { +fn test_funds_transfers() { let mut state_update = setup(); let context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); assert_eq!( @@ -42,11 +44,29 @@ fn test_sends() { ); let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); assert_eq!( - context - .deposit_near(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))) - .unwrap(), + context.deposit(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), U256::from(100) ); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + context + .transfer( + TransferArgs { account_id: near_account_id_to_evm_address(&accounts(2)).0, amount: 50 } + .try_to_vec() + .unwrap(), + ) + .unwrap(); + assert_eq!( + context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))).unwrap(), + U256::from(50) + ); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(2), 0); + context + .withdraw(WithdrawArgs { account_id: accounts(2), amount: 50 }.try_to_vec().unwrap()) + .unwrap(); + assert_eq!( + context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))).unwrap(), + U256::from(0) + ); } #[test] diff --git a/test-utils/testlib/Cargo.toml b/test-utils/testlib/Cargo.toml index ec3755f6407..c3c5ab80f06 100644 --- a/test-utils/testlib/Cargo.toml +++ b/test-utils/testlib/Cargo.toml @@ -20,6 +20,9 @@ tempfile = "3" assert_matches = "1.3" num-rational = "0.2.4" hex = "0.4.2" +ethabi = "8.0.0" +ethabi-contract = "8.0.0" +ethabi-derive = "8.0.0" borsh = "0.7.1" @@ -30,6 +33,7 @@ near-primitives = { path = "../../core/primitives" } near-store = { path = "../../core/store" } node-runtime = { path = "../../runtime/runtime" } near-vm-errors = { path = "../../runtime/near-vm-errors" } +near-evm-runner = { path = "../../runtime/near-evm-runner" } near-chain = { path = "../../chain/chain" } near-client = { path = "../../chain/client" } near-jsonrpc = { path = "../../chain/jsonrpc" } diff --git a/test-utils/testlib/src/standard_test_cases.rs b/test-utils/testlib/src/standard_test_cases.rs index ed14f1c8485..a4bb6060094 100644 --- a/test-utils/testlib/src/standard_test_cases.rs +++ b/test-utils/testlib/src/standard_test_cases.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use assert_matches::assert_matches; +use ethabi_contract::use_contract; use near_crypto::{InMemorySigner, KeyType}; use near_jsonrpc::ServerError; use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermission}; @@ -19,6 +20,7 @@ use crate::fees_utils::FeeHelper; use crate::node::Node; use crate::runtime_utils::{alice_account, bob_account, eve_dot_alice_account}; use crate::user::User; +use near_evm_runner::U256; /// The amount to send with function call. const FUNCTION_CALL_AMOUNT: Balance = TESTING_INIT_BALANCE / 10; @@ -1272,3 +1274,44 @@ pub fn test_smart_contract_free(node: impl Node) { let new_root = node_user.get_state_root(); assert_ne!(root, new_root); } + +use_contract!(cryptozombies, "../../runtime/near-evm-runner/tests/build/zombieAttack.abi"); + +pub fn test_evm_deploy_call(node: impl Node) { + let node_user = node.user(); + let bytes = hex::decode( + include_bytes!("../../../runtime/near-evm-runner/tests/build/zombieAttack.bin").to_vec(), + ) + .unwrap(); + let contract_id = node_user + .function_call(alice_account(), evm_account(), "deploy_code", bytes, 10u64.pow(14), 0) + .unwrap() + .status + .as_success_decoded() + .unwrap(); + + let (input, _decoder) = cryptozombies::functions::create_random_zombie::call("test"); + let args = vec![contract_id.clone(), input].concat(); + assert_eq!( + node_user + .function_call(alice_account(), evm_account(), "call_function", args, 10u64.pow(14), 0) + .unwrap() + .status + .as_success_decoded() + .unwrap(), + Vec::::new() + ); + + let (input, _decoder) = cryptozombies::functions::get_zombies_by_owner::call( + near_evm_runner::utils::near_account_id_to_evm_address(&alice_account()), + ); + let args = vec![contract_id, input].concat(); + let bytes = node_user + .function_call(alice_account(), evm_account(), "view_call_contract", args, 10u64.pow(14), 0) + .unwrap() + .status + .as_success_decoded() + .unwrap(); + let res = cryptozombies::functions::get_zombies_by_owner::decode_output(&bytes).unwrap(); + assert_eq!(res, vec![U256::from(0)]); +} diff --git a/test-utils/testlib/src/user/mod.rs b/test-utils/testlib/src/user/mod.rs index 16467957190..78907a5581b 100644 --- a/test-utils/testlib/src/user/mod.rs +++ b/test-utils/testlib/src/user/mod.rs @@ -12,8 +12,8 @@ use near_primitives::transaction::{ DeployContractAction, ExecutionOutcome, FunctionCallAction, SignedTransaction, StakeAction, TransferAction, }; -use near_primitives::types::{AccountId, Balance, BlockHeight, Gas, MerkleHash, ShardId}; -use near_primitives::views::{AccessKeyView, AccountView, BlockView, ChunkView, ViewStateResult}; +use near_primitives::types::{AccountId, Balance, BlockHeight, Gas, MerkleHash}; +use near_primitives::views::{AccessKeyView, AccountView, BlockView, CallResult, ViewStateResult}; use near_primitives::views::{ExecutionOutcomeView, FinalExecutionOutcomeView}; pub use crate::user::runtime_user::RuntimeUser; @@ -32,6 +32,13 @@ pub trait User { fn view_state(&self, account_id: &AccountId, prefix: &[u8]) -> Result; + fn view_call( + &self, + account_id: &AccountId, + method_name: &str, + args: &[u8], + ) -> Result; + fn add_transaction(&self, signed_transaction: SignedTransaction) -> Result<(), ServerError>; fn commit_transaction( diff --git a/test-utils/testlib/src/user/rpc_user.rs b/test-utils/testlib/src/user/rpc_user.rs index 580999555c5..9a3c39b8366 100644 --- a/test-utils/testlib/src/user/rpc_user.rs +++ b/test-utils/testlib/src/user/rpc_user.rs @@ -19,7 +19,7 @@ use near_primitives::types::{ AccountId, BlockHeight, BlockId, BlockReference, MaybeBlockId, ShardId, }; use near_primitives::views::{ - AccessKeyView, AccountView, BlockView, ChunkView, EpochValidatorInfo, ExecutionOutcomeView, + AccessKeyView, AccountView, BlockView, CallResult, EpochValidatorInfo, ExecutionOutcomeView, FinalExecutionOutcomeView, QueryResponse, ViewStateResult, }; @@ -70,6 +70,16 @@ impl User for RpcUser { self.query(format!("contract/{}", account_id), prefix)?.try_into() } + fn view_call( + &self, + account_id: &AccountId, + method_name: &str, + args: &[u8], + ) -> Result { + self.query(format!("call/{}/{}", account_id, method_name), args) + .and_then(|value| value.try_into()) + } + fn add_transaction(&self, transaction: SignedTransaction) -> Result<(), ServerError> { let bytes = transaction.try_to_vec().unwrap(); let _ = self.actix(move |client| client.broadcast_tx_async(to_base64(&bytes))).map_err( diff --git a/test-utils/testlib/src/user/runtime_user.rs b/test-utils/testlib/src/user/runtime_user.rs index 4a4e99711aa..f6537f31e20 100644 --- a/test-utils/testlib/src/user/runtime_user.rs +++ b/test-utils/testlib/src/user/runtime_user.rs @@ -11,7 +11,7 @@ use near_primitives::transaction::SignedTransaction; use near_primitives::types::{AccountId, BlockHeightDelta, MerkleHash}; use near_primitives::version::PROTOCOL_VERSION; use near_primitives::views::{ - AccessKeyView, AccountView, BlockView, ChunkView, ExecutionOutcomeView, + AccessKeyView, AccountView, BlockView, CallResult, ExecutionOutcomeView, ExecutionOutcomeWithIdView, ExecutionStatusView, ViewStateResult, }; use near_primitives::views::{FinalExecutionOutcomeView, FinalExecutionStatus}; @@ -207,6 +207,35 @@ impl User for RuntimeUser { .map_err(|err| err.to_string()) } + fn view_call( + &self, + account_id: &AccountId, + method_name: &str, + args: &[u8], + ) -> Result { + let apply_state = self.apply_state(); + let client = self.client.read().expect(POISONED_LOCK_ERR); + let state_update = client.get_state_update(); + let mut result = CallResult::default(); + result.result = self + .trie_viewer + .call_function( + state_update, + apply_state.block_index, + apply_state.block_timestamp, + &apply_state.last_block_hash, + apply_state.epoch_height, + &apply_state.epoch_id, + account_id, + method_name, + args, + &mut result.logs, + &self.epoch_info_provider, + ) + .map_err(|err| err.to_string())?; + Ok(result) + } + fn add_transaction(&self, transaction: SignedTransaction) -> Result<(), ServerError> { self.apply_all(self.apply_state(), vec![], vec![transaction])?; Ok(()) diff --git a/tests/test_cases_testnet_rpc.rs b/tests/test_cases_testnet_rpc.rs index 724c06dbb8b..dd56a7160b5 100644 --- a/tests/test_cases_testnet_rpc.rs +++ b/tests/test_cases_testnet_rpc.rs @@ -196,4 +196,9 @@ mod test { fn test_access_key_smart_contract_testnet() { run_testnet_test!(test_access_key_smart_contract); } + + #[test] + fn test_evm_deploy_call_testnet() { + run_testnet_test!(test_evm_deploy_call(node)); + } } From a56cb591a91f248bb0beed85ed3f7d02015c4e7d Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Wed, 2 Sep 2020 23:34:29 -0700 Subject: [PATCH 12/82] Refactor to use Externals in EVM --- Cargo.lock | 19 +- runtime/near-evm-runner/Cargo.toml | 4 +- runtime/near-evm-runner/src/errors.rs | 26 -- runtime/near-evm-runner/src/evm_state.rs | 413 ++++++++++-------- runtime/near-evm-runner/src/interpreter.rs | 52 +-- runtime/near-evm-runner/src/lib.rs | 333 +++++++++----- runtime/near-evm-runner/src/near_ext.rs | 49 ++- runtime/near-evm-runner/src/types.rs | 7 +- runtime/near-evm-runner/tests/standard_ops.rs | 112 ++++- runtime/near-vm-errors/src/lib.rs | 35 ++ test-utils/testlib/Cargo.toml | 3 +- test-utils/testlib/src/standard_test_cases.rs | 5 +- 12 files changed, 690 insertions(+), 368 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9c0abbbb92..e602285e229 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1920,12 +1920,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" - [[package]] name = "hex" version = "0.4.2" @@ -2858,13 +2852,11 @@ dependencies = [ "ethabi-derive", "ethereum-types", "evm", - "hex 0.3.2", + "hex", "keccak-hash", "lazy-static-include", "lazy_static", "libsecp256k1", - "near-primitives", - "near-store", "near-vm-errors", "near-vm-logic", "num-bigint 0.3.0", @@ -3019,7 +3011,7 @@ dependencies = [ "chrono", "derive_more", "easy-ext", - "hex 0.4.2", + "hex", "jemallocator", "lazy_static", "near-crypto", @@ -3317,7 +3309,7 @@ dependencies = [ "borsh", "byteorder", "cached", - "hex 0.4.2", + "hex", "indicatif 0.13.0", "lazy_static", "log", @@ -4981,8 +4973,9 @@ dependencies = [ "ethabi", "ethabi-contract", "ethabi-derive", + "ethereum-types", "futures", - "hex 0.4.2", + "hex", "lazy_static", "log", "near-chain", @@ -5680,7 +5673,7 @@ dependencies = [ "cc", "digest 0.8.1", "errno", - "hex 0.4.2", + "hex", "indexmap", "lazy_static", "libc", diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index a0a915bb142..ee3f90eeace 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -20,7 +20,7 @@ serde_json = "1" sha2 = "0.8" sha3 = "0.8" rlp = "0.4.2" -hex = "0.3.2" +hex = "0.4" byteorder = "1.0" num-bigint = { version = "0.3", default-features = false } num-traits = "0.2.12" @@ -28,8 +28,6 @@ ripemd160 = "0.9.0" libsecp256k1 = "0.3.5" near-vm-logic = { path = "../near-vm-logic" } near-vm-errors = { path = "../near-vm-errors" } -near-primitives = { path = "../../core/primitives" } -near-store = { path = "../../core/store" } [dev-dependencies] ethabi = "8.0.0" diff --git a/runtime/near-evm-runner/src/errors.rs b/runtime/near-evm-runner/src/errors.rs index aad09369686..8b137891791 100644 --- a/runtime/near-evm-runner/src/errors.rs +++ b/runtime/near-evm-runner/src/errors.rs @@ -1,27 +1 @@ -use ethereum_types::Address; -#[derive(Debug)] -pub enum EvmError { - /// Unknown error, catch all for unexpected things. - UnknownError, - /// Fatal failure due conflicting addresses on contract deployment. - DuplicateContract(Address), - /// Contract deployment failure. - DeployFail(Vec), - /// Contract execution failed, revert the state. - Revert(Vec), - /// Failed to parse arguments. - ArgumentParseError, - /// No deposit when expected. - MissingDeposit, - /// Insufficient funds to finish the operation. - InsufficientFunds, - /// U256 overflow. - IntegerOverflow, -} - -impl std::fmt::Display for EvmError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - f.write_str(&format!("{:?}", self)) - } -} diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index 926647465dc..b167bd4f190 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -1,13 +1,14 @@ use std::collections::{BTreeMap, HashMap, HashSet}; +use std::io::{Error, Write}; +use borsh::{BorshDeserialize, BorshSerialize}; use ethereum_types::{Address, U256}; -use borsh::{BorshDeserialize, BorshSerialize}; +use near_vm_errors::EvmError; +use near_vm_logic::VMLogicError; -use crate::errors::EvmError; -use crate::types::RawAddress; +use crate::types::{RawAddress, Result}; use crate::utils; -use std::io::{Error, Write}; #[derive(Default, Clone, Copy, Debug)] pub struct EvmAccount { @@ -16,14 +17,14 @@ pub struct EvmAccount { } impl BorshSerialize for EvmAccount { - fn serialize(&self, writer: &mut W) -> Result<(), Error> { + fn serialize(&self, writer: &mut W) -> std::result::Result<(), Error> { self.balance.0.serialize(writer)?; self.nonce.0.serialize(writer) } } impl BorshDeserialize for EvmAccount { - fn deserialize(buf: &mut &[u8]) -> Result { + fn deserialize(buf: &mut &[u8]) -> std::result::Result { let balance = U256(<[u64; 4]>::deserialize(buf)?); let nonce = U256(<[u64; 4]>::deserialize(buf)?); Ok(Self { balance, nonce }) @@ -31,70 +32,77 @@ impl BorshDeserialize for EvmAccount { } pub trait EvmState { - fn code_at(&self, address: &Address) -> Option>; - fn set_code(&mut self, address: &Address, bytecode: &[u8]); + fn code_at(&self, address: &Address) -> Result>>; + fn set_code(&mut self, address: &Address, bytecode: &[u8]) -> Result<()>; - fn set_account(&mut self, address: &Address, account: &EvmAccount); - fn get_account(&self, address: &Address) -> Option; + fn get_account(&self, address: &Address) -> Result>; + fn set_account(&mut self, address: &Address, account: &EvmAccount) -> Result<()>; - fn balance_of(&self, address: &Address) -> U256 { - let account = self.get_account(address).unwrap_or_default(); - account.balance.into() + fn balance_of(&self, address: &Address) -> Result { + let account = self.get_account(address)?.unwrap_or_default(); + Ok(account.balance.into()) } - fn nonce_of(&self, address: &Address) -> U256 { - let account = self.get_account(address).unwrap_or_default(); - account.nonce.into() + fn nonce_of(&self, address: &Address) -> Result { + let account = self.get_account(address)?.unwrap_or_default(); + Ok(account.nonce.into()) } - fn set_nonce(&mut self, address: &Address, nonce: U256) -> Option { - let mut account = self.get_account(address).unwrap_or_default(); + fn set_nonce(&mut self, address: &Address, nonce: U256) -> Result> { + let mut account = self.get_account(address)?.unwrap_or_default(); account.nonce = nonce; - self.set_account(address, &account); - Some(account.nonce) + self.set_account(address, &account)?; + Ok(Some(account.nonce)) } - fn set_balance(&mut self, address: &Address, balance: U256) { - let mut account = self.get_account(address).unwrap_or_default(); + fn set_balance(&mut self, address: &Address, balance: U256) -> Result<()> { + let mut account = self.get_account(address)?.unwrap_or_default(); account.balance = balance; - self.set_account(address, &account); + self.set_account(address, &account) } - fn next_nonce(&mut self, address: &Address) -> U256 { - let mut account = self.get_account(address).unwrap_or_default(); + fn next_nonce(&mut self, address: &Address) -> Result { + let mut account = self.get_account(address)?.unwrap_or_default(); let nonce = account.nonce; account.nonce += U256::from(1); - self.set_account(address, &account); - nonce + self.set_account(address, &account)?; + Ok(nonce) } - fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]>; - fn read_contract_storage(&self, address: &Address, key: [u8; 32]) -> Option<[u8; 32]> { + fn _read_contract_storage(&self, key: [u8; 52]) -> Result>; + fn read_contract_storage(&self, address: &Address, key: [u8; 32]) -> Result> { self._read_contract_storage(utils::internal_storage_key(address, key)) } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]); + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Result<()>; - fn set_contract_storage(&mut self, address: &Address, key: [u8; 32], value: [u8; 32]) { + fn set_contract_storage( + &mut self, + address: &Address, + key: [u8; 32], + value: [u8; 32], + ) -> Result<()> { self._set_contract_storage(utils::internal_storage_key(address, key), value) } - fn commit_changes(&mut self, other: &StateStore); + fn commit_changes(&mut self, other: &StateStore) -> Result<()>; - fn add_balance(&mut self, address: &Address, incr: U256) -> Result<(), EvmError> { - let mut account = self.get_account(address).unwrap_or_default(); - account.balance = - account.balance.checked_add(incr).ok_or_else(|| EvmError::IntegerOverflow)?; - self.set_account(address, &account); - Ok(()) + fn add_balance(&mut self, address: &Address, incr: U256) -> Result<()> { + let mut account = self.get_account(address)?.unwrap_or_default(); + account.balance = account + .balance + .checked_add(incr) + .ok_or_else(|| VMLogicError::EvmError(EvmError::IntegerOverflow))?; + self.set_account(address, &account) } - fn sub_balance(&mut self, address: &Address, decr: U256) -> Result<(), EvmError> { - let mut account = self.get_account(address).unwrap_or_default(); - account.balance = - account.balance.checked_sub(decr).ok_or_else(|| EvmError::InsufficientFunds)?; - self.set_account(address, &account); - Ok(()) + fn sub_balance(&mut self, address: &Address, decr: U256) -> Result<()> { + let mut account = self.get_account(address)?.unwrap_or_default(); + account.balance = account + .balance + .checked_sub(decr) + .ok_or_else(|| VMLogicError::EvmError(EvmError::InsufficientFunds))?; + self.set_account(address, &account) } fn transfer_balance( @@ -102,7 +110,7 @@ pub trait EvmState { sender: &Address, recipient: &Address, amnt: U256, - ) -> Result<(), EvmError> { + ) -> Result<()> { self.sub_balance(sender, amnt)?; self.add_balance(recipient, amnt) } @@ -157,49 +165,53 @@ impl StateStore { } impl EvmState for StateStore { - fn code_at(&self, address: &Address) -> Option> { + fn code_at(&self, address: &Address) -> Result>> { let internal_addr = utils::evm_account_to_internal_address(*address); if self.self_destructs.contains(&internal_addr) { - None + Ok(None) } else { - self.code.get(&internal_addr).cloned() + Ok(self.code.get(&internal_addr).cloned()) } } - fn set_code(&mut self, address: &Address, bytecode: &[u8]) { + fn set_code(&mut self, address: &Address, bytecode: &[u8]) -> Result<()> { let internal_addr = utils::evm_account_to_internal_address(*address); self.code.insert(internal_addr, bytecode.to_vec()); + Ok(()) } - fn set_account(&mut self, address: &Address, account: &EvmAccount) { - self.accounts.insert(address.0, account.clone()); + fn get_account(&self, address: &Address) -> Result> { + Ok(self.accounts.get(&address.0).map(|account| account.clone())) } - fn get_account(&self, address: &Address) -> Option { - self.accounts.get(&address.0).map(|account| account.clone()) + fn set_account(&mut self, address: &Address, account: &EvmAccount) -> Result<()> { + self.accounts.insert(address.0, account.clone()); + Ok(()) } - fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { + fn _read_contract_storage(&self, key: [u8; 52]) -> Result> { let mut addr = [0u8; 20]; addr.copy_from_slice(&key[..20]); if self.self_destructs.contains(&addr) { - None + Ok(None) } else { - self.storages.get(&key.to_vec()).cloned() + Ok(self.storages.get(&key.to_vec()).cloned()) } } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) { + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Result<()> { self.storages.insert(key.to_vec(), value); + Ok(()) } - fn commit_changes(&mut self, other: &StateStore) { + fn commit_changes(&mut self, other: &StateStore) -> Result<()> { self.commit_self_destructs(&other.self_destructs); self.commit_recreated(&other.recreated); self.commit_code(&other.code); self.commit_accounts(&other.accounts); self.commit_storages(&other.storages); self.logs.extend(other.logs.iter().cloned()); + Ok(()) } fn recreate(&mut self, addr: [u8; 20]) { @@ -227,65 +239,70 @@ impl SubState<'_> { SubState { msg_sender, state, parent } } - pub fn self_destruct(&mut self, address: &Address) { + pub fn self_destruct(&mut self, address: &Address) -> Result<()> { self.state.self_destructs.insert(address.0); - let mut account = self.get_account(address).unwrap_or_default(); + let mut account = self.get_account(address)?.unwrap_or_default(); account.nonce = U256::from(0); - self.state.set_account(address, &account); + self.state.set_account(address, &account) } } impl EvmState for SubState<'_> { - fn code_at(&self, address: &Address) -> Option> { + fn code_at(&self, address: &Address) -> Result>> { let internal_addr = utils::evm_account_to_internal_address(*address); if self.state.self_destructs.contains(&internal_addr) { - None + Ok(None) } else { self.state .code .get(&internal_addr) - .map_or_else(|| self.parent.code_at(address), |k| Some(k.to_vec())) + .map_or_else(|| self.parent.code_at(address), |k| Ok(Some(k.to_vec()))) } } - fn set_code(&mut self, address: &Address, bytecode: &[u8]) { + fn set_code(&mut self, address: &Address, bytecode: &[u8]) -> Result<()> { let internal_addr = utils::evm_account_to_internal_address(*address); self.state.code.insert(internal_addr, bytecode.to_vec()); + Ok(()) } - fn set_account(&mut self, address: &Address, account: &EvmAccount) { - self.state.set_account(address, account); + fn get_account(&self, address: &Address) -> Result> { + self.state + .get_account(address)? + .map_or_else(|| self.parent.get_account(address), |v| Ok(Some(v))) } - fn get_account(&self, address: &Address) -> Option { - self.state.get_account(address).or_else(|| self.parent.get_account(address)) + fn set_account(&mut self, address: &Address, account: &EvmAccount) -> Result<()> { + self.state.set_account(address, account) } - fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { + fn _read_contract_storage(&self, key: [u8; 52]) -> Result> { let mut addr = [0u8; 20]; addr.copy_from_slice(&key[..20]); if self.state.self_destructs.contains(&addr) { - None + Ok(None) } else { self.state .storages .get(&key.to_vec()) .copied() - .or_else(|| self.parent._read_contract_storage(key)) + .map_or_else(|| self.parent._read_contract_storage(key), |v| Ok(Some(v))) } } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) { + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Result<()> { self.state.storages.insert(key.to_vec(), value); + Ok(()) } - fn commit_changes(&mut self, other: &StateStore) { + fn commit_changes(&mut self, other: &StateStore) -> Result<()> { self.state.commit_self_destructs(&other.self_destructs); self.state.commit_recreated(&other.recreated); self.state.commit_code(&other.code); self.state.commit_accounts(&other.accounts); self.state.commit_storages(&other.storages); self.state.logs.extend(other.logs.iter().cloned()); + Ok(()) } fn recreate(&mut self, address: [u8; 20]) { @@ -314,81 +331,117 @@ mod test { // Create the top-level store let mut top = StateStore::default(); - top.set_code(&addr_0, &code); - assert_eq!(top.code_at(&addr_0), Some(code.to_vec())); - assert_eq!(top.code_at(&addr_1), None); - assert_eq!(top.code_at(&addr_2), None); - - top.set_nonce(&addr_0, nonce); - assert_eq!(top.nonce_of(&addr_0), nonce); - assert_eq!(top.nonce_of(&addr_1), zero); - assert_eq!(top.nonce_of(&addr_2), zero); - - top.set_balance(&addr_0, balance); - assert_eq!(top.balance_of(&addr_0), balance); - assert_eq!(top.balance_of(&addr_1), zero); - assert_eq!(top.balance_of(&addr_2), zero); - - top.set_contract_storage(&addr_0, storage_key_0, storage_value_0); - assert_eq!(top.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); - assert_eq!(top.read_contract_storage(&addr_1, storage_key_0), None); - assert_eq!(top.read_contract_storage(&addr_2, storage_key_0), None); + top.set_code(&addr_0, &code).unwrap(); + assert_eq!(top.code_at(&addr_0).unwrap(), Some(code.to_vec())); + assert_eq!(top.code_at(&addr_1).unwrap(), None); + assert_eq!(top.code_at(&addr_2).unwrap(), None); + + top.set_nonce(&addr_0, nonce).unwrap(); + assert_eq!(top.nonce_of(&addr_0).unwrap(), nonce); + assert_eq!(top.nonce_of(&addr_1).unwrap(), zero); + assert_eq!(top.nonce_of(&addr_2).unwrap(), zero); + + top.set_balance(&addr_0, balance).unwrap(); + assert_eq!(top.balance_of(&addr_0).unwrap(), balance); + assert_eq!(top.balance_of(&addr_1).unwrap(), zero); + assert_eq!(top.balance_of(&addr_2).unwrap(), zero); + + top.set_contract_storage(&addr_0, storage_key_0, storage_value_0).unwrap(); + assert_eq!( + top.read_contract_storage(&addr_0, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!(top.read_contract_storage(&addr_1, storage_key_0).unwrap(), None); + assert_eq!(top.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); let next = { // Open a new store let mut next = StateStore::default(); let mut sub_1 = SubState::new(&addr_0, &mut next, &mut top); - sub_1.set_code(&addr_1, &code); - assert_eq!(sub_1.code_at(&addr_0), Some(code.to_vec())); - assert_eq!(sub_1.code_at(&addr_1), Some(code.to_vec())); - assert_eq!(sub_1.code_at(&addr_2), None); - - sub_1.set_nonce(&addr_1, nonce); - assert_eq!(sub_1.nonce_of(&addr_0), nonce); - assert_eq!(sub_1.nonce_of(&addr_1), nonce); - assert_eq!(sub_1.nonce_of(&addr_2), zero); - - sub_1.set_balance(&addr_1, balance); - assert_eq!(sub_1.balance_of(&addr_0), balance); - assert_eq!(sub_1.balance_of(&addr_1), balance); - assert_eq!(sub_1.balance_of(&addr_2), zero); - - sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_0); - assert_eq!(sub_1.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); - assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_0), Some(storage_value_0)); - assert_eq!(sub_1.read_contract_storage(&addr_2, storage_key_0), None); - - sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_1); - assert_eq!(sub_1.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); - assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_0), Some(storage_value_1)); - assert_eq!(sub_1.read_contract_storage(&addr_2, storage_key_0), None); - - sub_1.set_contract_storage(&addr_1, storage_key_1, storage_value_1); - assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_0), Some(storage_value_1)); - assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_1), Some(storage_value_1)); - - sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_0); - assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_0), Some(storage_value_0)); - assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_1), Some(storage_value_1)); + sub_1.set_code(&addr_1, &code).unwrap(); + assert_eq!(sub_1.code_at(&addr_0).unwrap(), Some(code.to_vec())); + assert_eq!(sub_1.code_at(&addr_1).unwrap(), Some(code.to_vec())); + assert_eq!(sub_1.code_at(&addr_2).unwrap(), None); + + sub_1.set_nonce(&addr_1, nonce).unwrap(); + assert_eq!(sub_1.nonce_of(&addr_0).unwrap(), nonce); + assert_eq!(sub_1.nonce_of(&addr_1).unwrap(), nonce); + assert_eq!(sub_1.nonce_of(&addr_2).unwrap(), zero); + + sub_1.set_balance(&addr_1, balance).unwrap(); + assert_eq!(sub_1.balance_of(&addr_0).unwrap(), balance); + assert_eq!(sub_1.balance_of(&addr_1).unwrap(), balance); + assert_eq!(sub_1.balance_of(&addr_2).unwrap(), zero); + + sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_0).unwrap(); + assert_eq!( + sub_1.read_contract_storage(&addr_0, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + sub_1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!(sub_1.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + + sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_1).unwrap(); + assert_eq!( + sub_1.read_contract_storage(&addr_0, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + sub_1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + Some(storage_value_1) + ); + assert_eq!(sub_1.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + + sub_1.set_contract_storage(&addr_1, storage_key_1, storage_value_1).unwrap(); + assert_eq!( + sub_1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + Some(storage_value_1) + ); + assert_eq!( + sub_1.read_contract_storage(&addr_1, storage_key_1).unwrap(), + Some(storage_value_1) + ); + + sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_0).unwrap(); + assert_eq!( + sub_1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + sub_1.read_contract_storage(&addr_1, storage_key_1).unwrap(), + Some(storage_value_1) + ); next }; - top.commit_changes(&next); - assert_eq!(top.code_at(&addr_0), Some(code.to_vec())); - assert_eq!(top.code_at(&addr_1), Some(code.to_vec())); - assert_eq!(top.code_at(&addr_2), None); - assert_eq!(top.nonce_of(&addr_0), nonce); - assert_eq!(top.nonce_of(&addr_1), nonce); - assert_eq!(top.nonce_of(&addr_2), zero); - assert_eq!(top.balance_of(&addr_0), balance); - assert_eq!(top.balance_of(&addr_1), balance); - assert_eq!(top.balance_of(&addr_2), zero); - assert_eq!(top.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); - assert_eq!(top.read_contract_storage(&addr_1, storage_key_0), Some(storage_value_0)); - assert_eq!(top.read_contract_storage(&addr_1, storage_key_1), Some(storage_value_1)); - assert_eq!(top.read_contract_storage(&addr_2, storage_key_0), None); + top.commit_changes(&next).unwrap(); + assert_eq!(top.code_at(&addr_0).unwrap(), Some(code.to_vec())); + assert_eq!(top.code_at(&addr_1).unwrap(), Some(code.to_vec())); + assert_eq!(top.code_at(&addr_2).unwrap(), None); + assert_eq!(top.nonce_of(&addr_0).unwrap(), nonce); + assert_eq!(top.nonce_of(&addr_1).unwrap(), nonce); + assert_eq!(top.nonce_of(&addr_2).unwrap(), zero); + assert_eq!(top.balance_of(&addr_0).unwrap(), balance); + assert_eq!(top.balance_of(&addr_1).unwrap(), balance); + assert_eq!(top.balance_of(&addr_2).unwrap(), zero); + assert_eq!( + top.read_contract_storage(&addr_0, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + top.read_contract_storage(&addr_1, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + top.read_contract_storage(&addr_1, storage_key_1).unwrap(), + Some(storage_value_1) + ); + assert_eq!(top.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); } #[test] @@ -408,61 +461,73 @@ mod test { // Create the top-level store let mut top = StateStore::default(); - top.set_code(&addr_0, &code); - top.set_nonce(&addr_0, nonce); - top.set_balance(&addr_0, balance_0); - top.set_contract_storage(&addr_0, storage_key_0, storage_value_0); + top.set_code(&addr_0, &code).unwrap(); + top.set_nonce(&addr_0, nonce).unwrap(); + top.set_balance(&addr_0, balance_0).unwrap(); + top.set_contract_storage(&addr_0, storage_key_0, storage_value_0).unwrap(); - top.set_code(&addr_1, &code); - top.set_nonce(&addr_1, nonce); - top.set_balance(&addr_1, balance_0); - top.set_contract_storage(&addr_1, storage_key_1, storage_value_1); + top.set_code(&addr_1, &code).unwrap(); + top.set_nonce(&addr_1, nonce).unwrap(); + top.set_balance(&addr_1, balance_0).unwrap(); + top.set_contract_storage(&addr_1, storage_key_1, storage_value_1).unwrap(); - assert_eq!(top.code_at(&addr_0), Some(code.to_vec())); - assert_eq!(top.code_at(&addr_1), Some(code.to_vec())); + assert_eq!(top.code_at(&addr_0).unwrap(), Some(code.to_vec())); + assert_eq!(top.code_at(&addr_1).unwrap(), Some(code.to_vec())); - assert_eq!(top.nonce_of(&addr_0), nonce); - assert_eq!(top.nonce_of(&addr_1), nonce); + assert_eq!(top.nonce_of(&addr_0).unwrap(), nonce); + assert_eq!(top.nonce_of(&addr_1).unwrap(), nonce); - assert_eq!(top.balance_of(&addr_0), balance_0); - assert_eq!(top.balance_of(&addr_1), balance_0); + assert_eq!(top.balance_of(&addr_0).unwrap(), balance_0); + assert_eq!(top.balance_of(&addr_1).unwrap(), balance_0); - assert_eq!(top.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); - assert_eq!(top.read_contract_storage(&addr_1, storage_key_1), Some(storage_value_1)); + assert_eq!( + top.read_contract_storage(&addr_0, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + top.read_contract_storage(&addr_1, storage_key_1).unwrap(), + Some(storage_value_1) + ); let next = { // Open a new store let mut next = StateStore::default(); let mut sub_1 = SubState::new(&addr_0, &mut next, &mut top); - assert_eq!(sub_1.code_at(&addr_1), Some(code.to_vec())); - assert_eq!(sub_1.nonce_of(&addr_1), nonce); - assert_eq!(sub_1.balance_of(&addr_1), balance_0); - assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_1), Some(storage_value_1)); + assert_eq!(sub_1.code_at(&addr_1).unwrap(), Some(code.to_vec())); + assert_eq!(sub_1.nonce_of(&addr_1).unwrap(), nonce); + assert_eq!(sub_1.balance_of(&addr_1).unwrap(), balance_0); + assert_eq!( + sub_1.read_contract_storage(&addr_1, storage_key_1).unwrap(), + Some(storage_value_1) + ); - sub_1.self_destruct(&addr_1); - sub_1.set_balance(&addr_1, balance_1); + sub_1.self_destruct(&addr_1).unwrap(); + sub_1.set_balance(&addr_1, balance_1).unwrap(); - assert_eq!(sub_1.code_at(&addr_1), None); - assert_eq!(sub_1.nonce_of(&addr_1), zero); - assert_eq!(sub_1.balance_of(&addr_1), balance_1); - assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_1), None); + assert_eq!(sub_1.code_at(&addr_1).unwrap(), None); + assert_eq!(sub_1.nonce_of(&addr_1).unwrap(), zero); + assert_eq!(sub_1.balance_of(&addr_1).unwrap(), balance_1); + assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_1).unwrap(), None); next }; - top.commit_changes(&next); + top.commit_changes(&next).unwrap(); - assert_eq!(top.code_at(&addr_0), Some(code.to_vec())); - assert_eq!(top.code_at(&addr_1), None); + assert_eq!(top.code_at(&addr_0).unwrap(), Some(code.to_vec())); + assert_eq!(top.code_at(&addr_1).unwrap(), None); - assert_eq!(top.nonce_of(&addr_0), nonce); - assert_eq!(top.nonce_of(&addr_1), zero); + assert_eq!(top.nonce_of(&addr_0).unwrap(), nonce); + assert_eq!(top.nonce_of(&addr_1).unwrap(), zero); - assert_eq!(top.balance_of(&addr_0), balance_0); - assert_eq!(top.balance_of(&addr_1), balance_1); + assert_eq!(top.balance_of(&addr_0).unwrap(), balance_0); + assert_eq!(top.balance_of(&addr_1).unwrap(), balance_1); - assert_eq!(top.read_contract_storage(&addr_0, storage_key_0), Some(storage_value_0)); - assert_eq!(top.read_contract_storage(&addr_1, storage_key_1), None); + assert_eq!( + top.read_contract_storage(&addr_0, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!(top.read_contract_storage(&addr_1, storage_key_1).unwrap(), None); } } diff --git a/runtime/near-evm-runner/src/interpreter.rs b/runtime/near-evm-runner/src/interpreter.rs index 77d488fefa4..330c48a6dea 100644 --- a/runtime/near-evm-runner/src/interpreter.rs +++ b/runtime/near-evm-runner/src/interpreter.rs @@ -4,9 +4,11 @@ use ethereum_types::{Address, U256}; use evm::{CreateContractAddress, Factory}; use vm::{ActionParams, ActionValue, CallType, Ext, GasLeft, ParamsType, ReturnData, Schedule}; -use crate::errors::EvmError; +use near_vm_errors::{EvmError, VMLogicError}; + use crate::evm_state::{EvmState, StateStore, SubState}; use crate::near_ext::NearExt; +use crate::types::Result; use crate::utils; pub fn deploy_code( @@ -18,21 +20,21 @@ pub fn deploy_code( address_type: CreateContractAddress, recreate: bool, code: &[u8], -) -> Result { +) -> Result
{ let mut nonce = U256::default(); if address_type == CreateContractAddress::FromSenderAndNonce { - nonce = state.next_nonce(&sender); + nonce = state.next_nonce(&sender)?; }; let (address, _) = utils::evm_contract_address(address_type, &sender, &nonce, &code); if recreate { state.recreate(address.0); - } else if state.code_at(&address).is_some() { - return Err(EvmError::DuplicateContract(address)); + } else if state.code_at(&address)?.is_some() { + return Err(VMLogicError::EvmError(EvmError::DuplicateContract(address.0))); } let (result, state_updates) = - _create(state, origin, sender, value, call_stack_depth, &address, code); + _create(state, origin, sender, value, call_stack_depth, &address, code)?; // Apply known gas amount changes (all reverts are NeedsReturn) // Apply NeedsReturn changes if apply_state @@ -40,14 +42,14 @@ pub fn deploy_code( let (return_data, apply) = match result { Some(GasLeft::Known(_)) => (ReturnData::empty(), true), Some(GasLeft::NeedsReturn { gas_left: _, data, apply_state }) => (data, apply_state), - _ => return Err(EvmError::UnknownError), + _ => return Err(VMLogicError::EvmError(EvmError::UnknownError)), }; if apply { - state.commit_changes(&state_updates.unwrap()); - state.set_code(&address, &return_data.to_vec()); + state.commit_changes(&state_updates.unwrap())?; + state.set_code(&address, &return_data.to_vec())?; } else { - return Err(EvmError::DeployFail(return_data.to_vec())); + return Err(VMLogicError::EvmError(EvmError::DeployFail(return_data.to_vec()))); } Ok(address) } @@ -60,7 +62,7 @@ pub fn _create( call_stack_depth: usize, address: &Address, code: &[u8], -) -> (Option, Option) { +) -> Result<(Option, Option)> { let mut store = StateStore::default(); let mut sub_state = SubState::new(sender, &mut store, state); @@ -79,7 +81,7 @@ pub fn _create( params_type: vm::ParamsType::Embedded, }; - sub_state.transfer_balance(sender, address, value); + sub_state.transfer_balance(sender, address, value)?; let mut ext = NearExt::new(*address, *origin, &mut sub_state, call_stack_depth + 1, false); ext.info.gas_limit = U256::from(1_000_000_000); @@ -90,7 +92,7 @@ pub fn _create( // Run the code let result = instance.exec(&mut ext); - (result.ok().unwrap().ok(), Some(store)) + Ok((result.ok().unwrap().ok(), Some(store))) } #[allow(clippy::too_many_arguments)] @@ -103,7 +105,7 @@ pub fn call( contract_address: &Address, input: &[u8], should_commit: bool, -) -> Result { +) -> Result { run_and_commit_if_success( state, origin, @@ -127,7 +129,7 @@ pub fn delegate_call( context: &Address, delegee: &Address, input: &[u8], -) -> Result { +) -> Result { run_and_commit_if_success( state, origin, @@ -150,7 +152,7 @@ pub fn static_call( call_stack_depth: usize, contract_address: &Address, input: &[u8], -) -> Result { +) -> Result { run_and_commit_if_success( state, origin, @@ -179,7 +181,7 @@ fn run_and_commit_if_success( input: &[u8], is_static: bool, should_commit: bool, -) -> Result { +) -> Result { // run the interpreter and let (result, state_updates) = run_against_state( state, @@ -192,7 +194,7 @@ fn run_and_commit_if_success( code_address, input, is_static, - ); + )?; // Apply known gas amount changes (all reverts are NeedsReturn) // Apply NeedsReturn changes if apply_state @@ -201,14 +203,14 @@ fn run_and_commit_if_success( Some(GasLeft::Known(_)) => Ok(ReturnData::empty()), Some(GasLeft::NeedsReturn { gas_left: _, data, apply_state: true }) => Ok(data), Some(GasLeft::NeedsReturn { gas_left: _, data, apply_state: false }) => { - Err(EvmError::Revert(data.to_vec())) + Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) } - _ => Err(EvmError::UnknownError), + _ => Err(VMLogicError::EvmError(EvmError::UnknownError)), }; // Don't apply changes from a static context (these _should_ error in the ext) if !is_static && return_data.is_ok() && should_commit { - state.commit_changes(&state_updates.unwrap()); + state.commit_changes(&state_updates.unwrap())?; } return_data @@ -227,8 +229,8 @@ fn run_against_state( code_address: &Address, input: &[u8], is_static: bool, -) -> (Option, Option) { - let code = state.code_at(code_address).unwrap_or_else(Vec::new); +) -> Result<(Option, Option)> { + let code = state.code_at(code_address)?.unwrap_or_else(Vec::new); let mut store = StateStore::default(); let mut sub_state = SubState::new(sender, &mut store, state); @@ -251,7 +253,7 @@ fn run_against_state( if let Some(val) = value { params.value = ActionValue::Transfer(val); // substate transfer will get reverted if the call fails - sub_state.transfer_balance(sender, state_address, val); + sub_state.transfer_balance(sender, state_address, val)?; } let mut ext = @@ -263,5 +265,5 @@ fn run_against_state( // Run the code let result = instance.exec(&mut ext); - (result.ok().unwrap().ok(), Some(store)) + Ok((result.ok().unwrap().ok(), Some(store))) } diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index ab9930b5043..c3b6adcd197 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -2,20 +2,14 @@ use borsh::{BorshDeserialize, BorshSerialize}; use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; -use near_primitives::types::{AccountId, Balance}; -use near_store::TrieUpdate; -use near_vm_errors::VMError; -use near_vm_logic::VMOutcome; +use near_vm_errors::{EvmError, FunctionCallError, VMError}; +use near_vm_logic::types::{AccountId, Balance, ReturnData}; +use near_vm_logic::{External, VMLogicError, VMOutcome}; -pub use crate::errors::EvmError; use crate::evm_state::{EvmAccount, EvmState, StateStore}; -use crate::types::{GetCodeArgs, GetStorageAtArgs, TransferArgs, WithdrawArgs}; -use near_primitives::receipt::Receipt; -use near_vm_errors::FunctionCallError; -use near_vm_logic::types::ReturnData; +use crate::types::{GetCodeArgs, GetStorageAtArgs, Result, TransferArgs, WithdrawArgs}; mod builtins; -mod errors; mod evm_state; mod interpreter; mod near_ext; @@ -23,10 +17,10 @@ pub mod types; pub mod utils; pub struct EvmContext<'a> { - trie_update: &'a mut TrieUpdate, - account_id: AccountId, + ext: &'a mut dyn External, predecessor_id: AccountId, attached_deposit: Balance, + logs: Vec, } enum KeyPrefix { @@ -42,77 +36,57 @@ fn address_to_key(prefix: KeyPrefix, address: &H160) -> Vec { } impl<'a> EvmState for EvmContext<'a> { - fn code_at(&self, address: &H160) -> Option> { - self.trie_update - .get(&TrieKey::ContractData { - account_id: self.account_id.clone(), - key: address_to_key(KeyPrefix::Contract, address), - }) - .unwrap_or(None) + fn code_at(&self, address: &H160) -> Result>> { + self.ext + .storage_get(&address_to_key(KeyPrefix::Contract, address)) + .map(|value| value.map(|x| x.deref().unwrap_or(vec![]))) } - fn set_code(&mut self, address: &H160, bytecode: &[u8]) { - self.trie_update.set( - TrieKey::ContractData { - account_id: self.account_id.clone(), - key: address_to_key(KeyPrefix::Contract, address), - }, - bytecode.to_vec(), - ) + fn set_code(&mut self, address: &H160, bytecode: &[u8]) -> Result<()> { + self.ext.storage_set(&address_to_key(KeyPrefix::Contract, address), bytecode) } - fn set_account(&mut self, address: &Address, account: &EvmAccount) { - self.trie_update.set( - TrieKey::ContractData { - account_id: self.account_id.clone(), - key: address_to_key(KeyPrefix::Account, address), - }, - account.try_to_vec().expect("Failed to serialize"), - ) + fn get_account(&self, address: &Address) -> Result> { + self.ext.storage_get(&address_to_key(KeyPrefix::Account, address)).map(|value| { + value.map(|x| { + EvmAccount::try_from_slice(&x.deref().expect("Failed to deref")).unwrap_or_default() + }) + }) } - fn get_account(&self, address: &Address) -> Option { - // TODO: handle error propagation? - self.trie_update - .get(&TrieKey::ContractData { - account_id: self.account_id.clone(), - key: address_to_key(KeyPrefix::Account, address), - }) - .unwrap_or_else(|_| None) - .map(|value| EvmAccount::try_from_slice(&value).unwrap_or_default()) + fn set_account(&mut self, address: &Address, account: &EvmAccount) -> Result<()> { + self.ext.storage_set( + &address_to_key(KeyPrefix::Account, address), + &account.try_to_vec().expect("Failed to serialize"), + ) } - fn _read_contract_storage(&self, key: [u8; 52]) -> Option<[u8; 32]> { - self.trie_update - .get(&TrieKey::ContractData { account_id: self.account_id.clone(), key: key.to_vec() }) - .unwrap_or_else(|_| None) - .map(utils::vec_to_arr_32) + fn _read_contract_storage(&self, key: [u8; 52]) -> Result> { + self.ext + .storage_get(&key) + .map(|value| value.map(|x| utils::vec_to_arr_32(x.deref().expect("Failed to deref")))) } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) { - self.trie_update.set( - TrieKey::ContractData { account_id: self.account_id.clone(), key: key.to_vec() }, - value.to_vec(), - ); + fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Result<()> { + self.ext.storage_set(&key, &value) } - fn commit_changes(&mut self, other: &StateStore) { + fn commit_changes(&mut self, other: &StateStore) -> Result<()> { // self.commit_self_destructs(&other.self_destructs); // self.commit_self_destructs(&other.recreated); for (address, code) in other.code.iter() { - self.set_code(&H160(*address), code); + self.set_code(&H160(*address), code)?; } for (address, account) in other.accounts.iter() { - self.set_account(&H160(*address), account); + self.set_account(&H160(*address), account)?; } for (key, value) in other.storages.iter() { let mut arr = [0; 52]; arr.copy_from_slice(&key); - self._set_contract_storage(arr, *value); + self._set_contract_storage(arr, *value)?; } - // for log in &other.logs { - // near_sdk::env::log(format!("evm log: {}", log).as_bytes()); - // } + self.logs.extend_from_slice(&other.logs); + Ok(()) } fn recreate(&mut self, _address: [u8; 20]) { @@ -122,21 +96,16 @@ impl<'a> EvmState for EvmContext<'a> { impl<'a> EvmContext<'a> { pub fn new( - state_update: &'a mut TrieUpdate, - account_id: AccountId, + ext: &'a mut dyn External, predecessor_id: AccountId, attached_deposit: Balance, ) -> Self { - Self { - trie_update: state_update, - account_id, - predecessor_id: predecessor_id, - attached_deposit, - } + Self { ext, predecessor_id, attached_deposit, logs: Vec::default() } } - pub fn deploy_code(&mut self, bytecode: Vec) -> Result { + pub fn deploy_code(&mut self, bytecode: Vec) -> Result
{ let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); + self.add_balance(&sender, U256::from(self.attached_deposit))?; interpreter::deploy_code( self, &sender, @@ -149,10 +118,11 @@ impl<'a> EvmContext<'a> { ) } - pub fn call_function(&mut self, args: Vec) -> Result, EvmError> { + pub fn call_function(&mut self, args: Vec) -> Result> { let contract_address = Address::from_slice(&args[..20]); let input = &args[20..]; let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); + self.add_balance(&sender, U256::from(self.attached_deposit))?; let value = if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; interpreter::call(self, &sender, &sender, value, 0, &contract_address, &input, true) @@ -164,7 +134,7 @@ impl<'a> EvmContext<'a> { /// to an Ethereum transaction, however there may be some edge cases. /// /// This function serves the eth_call functionality, and will NOT apply state changes. - pub fn view_call_function(&mut self, args: Vec) -> Result, EvmError> { + pub fn view_call_function(&mut self, args: Vec) -> Result> { let contract_address = Address::from_slice(&args[..20]); let input = &args[20..]; let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); @@ -172,71 +142,73 @@ impl<'a> EvmContext<'a> { .map(|rd| rd.to_vec()) } - pub fn get_code(&self, args: Vec) -> Result, EvmError> { - let args = GetCodeArgs::try_from_slice(&args).map_err(|_| EvmError::ArgumentParseError)?; - Ok(self.code_at(&Address::from_slice(&args.address)).unwrap_or(vec![])) + pub fn get_code(&self, args: Vec) -> Result> { + let args = GetCodeArgs::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + Ok(self.code_at(&Address::from_slice(&args.address)).unwrap_or(None).unwrap_or(vec![])) } - pub fn get_storage_at(&self, args: Vec) -> Result, EvmError> { - let args = - GetStorageAtArgs::try_from_slice(&args).map_err(|_| EvmError::ArgumentParseError)?; + pub fn get_storage_at(&self, args: Vec) -> Result> { + let args = GetStorageAtArgs::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; Ok(self - .read_contract_storage(&Address::from_slice(&args.address), args.key) + .read_contract_storage(&Address::from_slice(&args.address), args.key)? .unwrap_or([0u8; 32]) .to_vec()) } - pub fn get_balance(&self, args: Vec) -> Result { - Ok(self.balance_of(&Address::from_slice(&args))) + pub fn get_balance(&self, args: Vec) -> Result { + self.balance_of(&Address::from_slice(&args)) } - pub fn get_nonce(&self, args: Vec) -> Result { - Ok(self.nonce_of(&Address::from_slice(&args))) + pub fn get_nonce(&self, args: Vec) -> Result { + self.nonce_of(&Address::from_slice(&args)) } - pub fn deposit(&mut self, args: Vec) -> Result { + pub fn deposit(&mut self, args: Vec) -> Result { if self.attached_deposit == 0 { - return Err(EvmError::MissingDeposit); + return Err(VMLogicError::EvmError(EvmError::MissingDeposit)); } let address = Address::from_slice(&args); self.add_balance(&address, U256::from(self.attached_deposit))?; - Ok(self.balance_of(&address)) + self.balance_of(&address) } - pub fn withdraw(&mut self, args: Vec) -> Result<(), EvmError> { - let args = WithdrawArgs::try_from_slice(&args).map_err(|_| EvmError::ArgumentParseError)?; + pub fn withdraw(&mut self, args: Vec) -> Result<()> { + let args = WithdrawArgs::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); let amount = U256::from(args.amount); - if amount > self.balance_of(&sender) { - return Err(EvmError::InsufficientFunds); + if amount > self.balance_of(&sender)? { + return Err(VMLogicError::EvmError(EvmError::InsufficientFunds)); } self.sub_balance(&sender, amount)?; - // TODO: add outgoing promise. - Ok(()) + let receipt_index = self.ext.create_receipt(vec![], args.account_id)?; + self.ext.append_action_transfer(receipt_index, args.amount).map_err(|err| err.into()) } /// Transfer tokens from sender to given EVM address. - pub fn transfer(&mut self, args: Vec) -> Result<(), EvmError> { - let args = TransferArgs::try_from_slice(&args).map_err(|_| EvmError::ArgumentParseError)?; + pub fn transfer(&mut self, args: Vec) -> Result<()> { + let args = TransferArgs::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); let amount = U256::from(args.amount); - if amount > self.balance_of(&sender) { - return Err(EvmError::InsufficientFunds); + if amount > self.balance_of(&sender)? { + return Err(VMLogicError::EvmError(EvmError::InsufficientFunds)); } self.transfer_balance(&sender, &Address::from(args.account_id), amount) } } pub fn run_evm( - mut state_update: &mut TrieUpdate, - account_id: AccountId, - predecessor_id: AccountId, + ext: &mut dyn External, + predecessor_id: &AccountId, + amount: Balance, attached_deposit: Balance, method_name: String, args: Vec, ) -> (Option, Option) { - let mut context = - EvmContext::new(&mut state_update, account_id, predecessor_id, attached_deposit); + let mut context = EvmContext::new(ext, predecessor_id.clone(), attached_deposit); let result = match method_name.as_str() { "deploy_code" => context.deploy_code(args).map(|address| utils::address_to_vec(&address)), "get_code" => context.get_code(args), @@ -247,7 +219,162 @@ pub fn run_evm( "deposit" => context.deposit(args).map(|balance| utils::u256_to_vec(&balance)), "withdraw" => context.withdraw(args).map(|_| vec![]), "transfer" => context.transfer(args).map(|_| vec![]), - _ => Err(EvmError::UnknownError), + _ => Err(VMLogicError::EvmError(EvmError::MethodNotFound)), }; - (None, None) + match result { + Ok(value) => { + let outcome = VMOutcome { + balance: amount, + storage_usage: 0, + return_data: ReturnData::Value(value), + burnt_gas: 0, + used_gas: 0, + logs: context.logs, + }; + (Some(outcome), None) + } + Err(VMLogicError::EvmError(err)) => { + (None, Some(VMError::FunctionCallError(FunctionCallError::EvmError(err)))) + } + Err(_) => (None, Some(VMError::FunctionCallError(FunctionCallError::WasmUnknownError))), + } +} + +#[cfg(test)] +mod tests { + use near_vm_logic::mocks::mock_external::MockedExternal; + + use crate::evm_state::SubState; + + use super::*; + + #[test] + fn state_management() { + let mut fake_external = MockedExternal::new(); + let mut context = EvmContext::new(&mut fake_external, "alice".to_string(), 0); + let addr_0 = Address::repeat_byte(0); + let addr_1 = Address::repeat_byte(1); + let addr_2 = Address::repeat_byte(2); + + let zero = U256::zero(); + let code: [u8; 3] = [0, 1, 2]; + let nonce = U256::from_dec_str("103030303").unwrap(); + let balance = U256::from_dec_str("3838209").unwrap(); + let storage_key_0 = [4u8; 32]; + let storage_key_1 = [5u8; 32]; + let storage_value_0 = [6u8; 32]; + let storage_value_1 = [7u8; 32]; + + context.set_code(&addr_0, &code).unwrap(); + assert_eq!(context.code_at(&addr_0).unwrap(), Some(code.to_vec())); + assert_eq!(context.code_at(&addr_1).unwrap(), None); + assert_eq!(context.code_at(&addr_2).unwrap(), None); + + context.set_nonce(&addr_0, nonce).unwrap(); + assert_eq!(context.nonce_of(&addr_0).unwrap(), nonce); + assert_eq!(context.nonce_of(&addr_1).unwrap(), zero); + assert_eq!(context.nonce_of(&addr_2).unwrap(), zero); + + context.set_balance(&addr_0, balance).unwrap(); + assert_eq!(context.balance_of(&addr_0).unwrap(), balance); + assert_eq!(context.balance_of(&addr_1).unwrap(), zero); + assert_eq!(context.balance_of(&addr_2).unwrap(), zero); + + context.set_contract_storage(&addr_0, storage_key_0, storage_value_0).unwrap(); + assert_eq!( + context.read_contract_storage(&addr_0, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!(context.read_contract_storage(&addr_1, storage_key_0).unwrap(), None); + assert_eq!(context.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + + let next = { + // Open a new store + let mut next = StateStore::default(); + let mut sub1 = SubState::new(&addr_0, &mut next, &context); + + sub1.set_code(&addr_1, &code).unwrap(); + assert_eq!(sub1.code_at(&addr_0).unwrap(), Some(code.to_vec())); + assert_eq!(sub1.code_at(&addr_1).unwrap(), Some(code.to_vec())); + assert_eq!(sub1.code_at(&addr_2).unwrap(), None); + + sub1.set_nonce(&addr_1, nonce).unwrap(); + assert_eq!(sub1.nonce_of(&addr_0).unwrap(), nonce); + assert_eq!(sub1.nonce_of(&addr_1).unwrap(), nonce); + assert_eq!(sub1.nonce_of(&addr_2).unwrap(), zero); + + sub1.set_balance(&addr_1, balance).unwrap(); + assert_eq!(sub1.balance_of(&addr_0).unwrap(), balance); + assert_eq!(sub1.balance_of(&addr_1).unwrap(), balance); + assert_eq!(sub1.balance_of(&addr_2).unwrap(), zero); + + sub1.set_contract_storage(&addr_1, storage_key_0, storage_value_0).unwrap(); + assert_eq!( + sub1.read_contract_storage(&addr_0, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + sub1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!(sub1.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + + sub1.set_contract_storage(&addr_1, storage_key_0, storage_value_1).unwrap(); + assert_eq!( + sub1.read_contract_storage(&addr_0, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + sub1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + Some(storage_value_1) + ); + assert_eq!(sub1.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + + sub1.set_contract_storage(&addr_1, storage_key_1, storage_value_1).unwrap(); + assert_eq!( + sub1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + Some(storage_value_1) + ); + assert_eq!( + sub1.read_contract_storage(&addr_1, storage_key_1).unwrap(), + Some(storage_value_1) + ); + + sub1.set_contract_storage(&addr_1, storage_key_0, storage_value_0).unwrap(); + assert_eq!( + sub1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + sub1.read_contract_storage(&addr_1, storage_key_1).unwrap(), + Some(storage_value_1) + ); + + next + }; + + context.commit_changes(&next).unwrap(); + assert_eq!(context.code_at(&addr_0).unwrap(), Some(code.to_vec())); + assert_eq!(context.code_at(&addr_1).unwrap(), Some(code.to_vec())); + assert_eq!(context.code_at(&addr_2).unwrap(), None); + assert_eq!(context.nonce_of(&addr_0).unwrap(), nonce); + assert_eq!(context.nonce_of(&addr_1).unwrap(), nonce); + assert_eq!(context.nonce_of(&addr_2).unwrap(), zero); + assert_eq!(context.balance_of(&addr_0).unwrap(), balance); + assert_eq!(context.balance_of(&addr_1).unwrap(), balance); + assert_eq!(context.balance_of(&addr_2).unwrap(), zero); + assert_eq!( + context.read_contract_storage(&addr_0, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + context.read_contract_storage(&addr_1, storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + context.read_contract_storage(&addr_1, storage_key_1).unwrap(), + Some(storage_value_1) + ); + assert_eq!(context.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + } } diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 0ee51dce154..6d93dfa0bf7 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -65,14 +65,18 @@ impl<'a> vm::Ext for NearExt<'a> { .sub_state .parent // Read from the unmodified parent state .read_contract_storage(&self.context_addr, key.0) + .unwrap_or(None) .unwrap_or([0u8; 32]); // default to an empty value Ok(H256(raw_val)) } /// Returns a value for given key. fn storage_at(&self, key: &H256) -> EvmResult { - let raw_val = - self.sub_state.read_contract_storage(&self.context_addr, key.0).unwrap_or([0u8; 32]); // default to an empty value + let raw_val = self + .sub_state + .read_contract_storage(&self.context_addr, key.0) + .unwrap_or(None) + .unwrap_or([0u8; 32]); // default to an empty value Ok(H256(raw_val)) } @@ -81,19 +85,20 @@ impl<'a> vm::Ext for NearExt<'a> { if self.is_static() { return Err(VmError::MutableCallInStaticContext); } - self.sub_state.set_contract_storage(&self.context_addr, key.0, value.0); - Ok(()) + self.sub_state + .set_contract_storage(&self.context_addr, key.0, value.0) + .map_err(|err| vm::Error::Internal(err.to_string())) } // TODO: research why these are different fn exists(&self, address: &Address) -> EvmResult { - Ok(self.sub_state.balance_of(address) > U256::from(0) - || self.sub_state.code_at(address).is_some()) + Ok(self.sub_state.balance_of(address).unwrap_or_else(|_| U256::from(0)) > U256::from(0) + || self.sub_state.code_at(address).unwrap_or(None).is_some()) } fn exists_and_not_null(&self, address: &Address) -> EvmResult { - Ok(self.sub_state.balance_of(address) > 0.into() - || self.sub_state.code_at(address).is_some()) + Ok(self.sub_state.balance_of(address).unwrap_or_else(|_| U256::from(0)) > 0.into() + || self.sub_state.code_at(address).unwrap_or(None).is_some()) } fn origin_balance(&self) -> EvmResult { @@ -103,7 +108,7 @@ impl<'a> vm::Ext for NearExt<'a> { } fn balance(&self, address: &Address) -> EvmResult { - let account = self.sub_state.get_account(address).unwrap_or_default(); + let account = self.sub_state.get_account(address).unwrap_or(None).unwrap_or_default(); Ok(account.balance.into()) } @@ -163,6 +168,7 @@ impl<'a> vm::Ext for NearExt<'a> { // hijack builtins if crate::builtins::is_precompile(receive_address) { + println!("{:?}", receive_address); return Ok(crate::builtins::process_precompile(receive_address, data)); } @@ -207,7 +213,7 @@ impl<'a> vm::Ext for NearExt<'a> { let msg_call_result = match result { Ok(data) => MessageCallResult::Success(1_000_000_000.into(), data), Err(err) => { - let message = err.to_string().as_bytes().to_vec(); + let message = format!("{:?}", err).as_bytes().to_vec(); let message_len = message.len(); MessageCallResult::Reverted( 1_000_000_000.into(), @@ -220,13 +226,13 @@ impl<'a> vm::Ext for NearExt<'a> { /// Returns code at given address fn extcode(&self, address: &Address) -> EvmResult>> { - let code = self.sub_state.code_at(address).map(Arc::new); + let code = self.sub_state.code_at(address).unwrap_or(None).map(Arc::new); Ok(code) } /// Returns code hash at given address fn extcodehash(&self, address: &Address) -> EvmResult> { - let code_opt = self.sub_state.code_at(address); + let code_opt = self.sub_state.code_at(address).unwrap_or(None); let code = match code_opt { Some(code) => code, None => return Ok(None), @@ -240,7 +246,7 @@ impl<'a> vm::Ext for NearExt<'a> { /// Returns code size at given address fn extcodesize(&self, address: &Address) -> EvmResult> { - Ok(self.sub_state.code_at(address).map(|c| c.len())) + Ok(self.sub_state.code_at(address).unwrap_or(None).map(|c| c.len())) } /// Creates log entry with given topics and data @@ -271,11 +277,18 @@ impl<'a> vm::Ext for NearExt<'a> { /// Address to which funds should be refunded. /// Deletes code, moves balance fn suicide(&mut self, refund_address: &Address) -> EvmResult<()> { - self.sub_state.state.self_destructs.insert(self.context_addr.0); - - let account = self.sub_state.get_account(&self.context_addr).unwrap_or_default(); - self.sub_state.add_balance(refund_address, account.balance.into()); - self.sub_state.sub_balance(&self.context_addr, account.balance.into()); + self.sub_state + .self_destruct(&self.context_addr) + .map_err(|err| vm::Error::Internal(err.to_string()))?; + + let account = + self.sub_state.get_account(&self.context_addr).unwrap_or(None).unwrap_or_default(); + self.sub_state + .add_balance(refund_address, account.balance.into()) + .map_err(|err| vm::Error::Internal(err.to_string()))?; + self.sub_state + .sub_balance(&self.context_addr, account.balance.into()) + .map_err(|err| vm::Error::Internal(err.to_string()))?; Ok(()) } diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index e1a8aa8f60b..0f62072899e 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -1,10 +1,13 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use near_primitives::types::Balance; +use near_vm_errors::VMLogicError; +use near_vm_logic::types::{AccountId, Balance}; pub type RawAddress = [u8; 20]; pub type RawHash = [u8; 32]; +pub type Result = std::result::Result; + #[derive(BorshSerialize, BorshDeserialize)] pub struct GetCodeArgs { pub address: RawAddress, @@ -18,7 +21,7 @@ pub struct GetStorageAtArgs { #[derive(BorshSerialize, BorshDeserialize)] pub struct WithdrawArgs { - pub account_id: String, + pub account_id: AccountId, pub amount: Balance, } diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 3865f15ef59..ea59bcb898b 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -3,7 +3,7 @@ extern crate lazy_static_include; use borsh::BorshSerialize; use ethabi_contract::use_contract; -use ethereum_types::U256; +use ethereum_types::{Address, H256, U256}; use near_evm_runner::types::{TransferArgs, WithdrawArgs}; use near_evm_runner::utils::{ @@ -112,3 +112,113 @@ fn test_internal_create() { let output = subcontract::functions::a_number::decode_output(&new_raw).unwrap(); assert_eq!(output, U256::from(8)); } + +#[test] +fn test_precompiles() { + let mut state_update = setup(); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + + let (input, _) = soltest::functions::precompile_test::call(); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + assert_eq!(raw.len(), 0); +} + +fn setup_and_deploy_test() -> (TrieUpdate, Address) { + let mut state_update = setup(); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); + (state_update, test_addr) +} + +#[test] +fn test_deploy_and_transfer() { + let (mut state_update, test_addr) = setup_and_deploy_test(); + + // This should increment the nonce of the deploying contract. + // There is 100 attached to this that should be passed through. + let (input, _) = soltest::functions::deploy_new_guy::call(8); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + + // The sub_addr should have been transferred 100 yoctoN. + let sub_addr = raw[12..32].to_vec(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); + assert_eq!(context.get_balance(sub_addr).unwrap(), U256::from(100)); +} + +#[test] +fn test_deploy_with_value() { + let (mut state_update, test_addr) = setup_and_deploy_test(); + + // This should increment the nonce of the deploying contract + // There is 100 attached to this that should be passed through + let (input, _) = soltest::functions::pay_new_guy::call(8); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + + // The sub_addr should have been transferred 100 tokens. + let sub_addr = raw[12..32].to_vec(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); + assert_eq!(context.get_balance(sub_addr).unwrap(), U256::from(100)); +} + +#[test] +fn test_contract_to_eoa_transfer() { + let (mut state_update, test_addr) = setup_and_deploy_test(); + + let (input, _) = soltest::functions::return_some_funds::call(); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + + let sender_addr = raw[12..32].to_vec(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); + assert_eq!(context.get_balance(sender_addr).unwrap(), U256::from(50)); +} + +#[test] +fn test_get_code() { + let (mut state_update, test_addr) = setup_and_deploy_test(); + let context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + + assert!(context.get_code(test_addr.0.to_vec()).unwrap().len() > 1500); // contract code should roughly be over length 1500 + assert_eq!(context.get_code(vec![0u8; 20]).unwrap().len(), 0); +} + +#[test] +fn test_view_call() { + let (mut state_update, test_addr) = setup_and_deploy_test(); + + // This should NOT increment the nonce of the deploying contract + // And NO CODE should be deployed + let (input, _) = soltest::functions::deploy_new_guy::call(8); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + let raw = context.view_call_function(encode_call_function_args(test_addr, input)).unwrap(); + assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); + + let sub_addr = raw[12..32].to_vec(); + assert_eq!(context.get_code(sub_addr).unwrap().len(), 0); +} + +#[test] +fn test_solidity_accurate_storage_on_selfdestruct() { + let mut state_update = setup(); + let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + assert_eq!( + context.deposit(near_account_id_to_evm_address(&accounts(1)).0.to_vec()).unwrap(), + U256::from(100) + ); + + let salt = H256([0u8; 32]); + let destruct_code = hex::decode(&DESTRUCT_TEST).unwrap(); + + // Deploy CREATE2 Factory + let factory_addr = context.deploy_code(hex::decode(&FACTORY_TEST).unwrap()).unwrap(); + + // Deploy + SelfDestruct in one transaction + let input = create2factory::functions::test_double_deploy::call(salt, destruct_code.clone()).0; + let raw = context.call_function(encode_call_function_args(factory_addr, input)).unwrap(); + println!("{:?}", raw); + // assert_eq!(1, raw.parse::().unwrap()); +} diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index 60b43a96f5f..f8b0c69dccb 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -1,5 +1,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use near_rpc_error_macro::RpcError; +use serde::export::fmt::Error; +use serde::export::Formatter; use serde::{Deserialize, Serialize}; use std::fmt; @@ -29,6 +31,7 @@ pub enum FunctionCallError { WasmTrap(WasmTrap), WasmUnknownError, HostError(HostError), + EvmError(EvmError), } /// A kind of a trap happened during execution of a binary #[derive( @@ -168,6 +171,29 @@ pub enum HostError { Deprecated { method_name: String }, } +/// Errors specifically from EVM pre-compile. +#[derive(Debug, Clone, Eq, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] +pub enum EvmError { + /// Unknown error, catch all for unexpected things. + UnknownError, + /// Fatal failure due conflicting addresses on contract deployment. + DuplicateContract([u8; 20]), + /// Contract deployment failure. + DeployFail(Vec), + /// Contract execution failed, revert the state. + Revert(Vec), + /// Failed to parse arguments. + ArgumentParseError, + /// No deposit when expected. + MissingDeposit, + /// Insufficient funds to finish the operation. + InsufficientFunds, + /// U256 overflow. + IntegerOverflow, + /// Method not found. + MethodNotFound, +} + #[derive(Debug, Clone, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] pub enum VMLogicError { HostError(HostError), @@ -175,6 +201,8 @@ pub enum VMLogicError { ExternalError(Vec), /// An error that is caused by an operation on an inconsistent state. InconsistentStateError(InconsistentStateError), + /// An error coming from EVM precompile. + EvmError(EvmError), } /// An error that is caused by an operation on an inconsistent state. @@ -205,6 +233,12 @@ impl From for VMError { } } +impl fmt::Display for VMLogicError { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { + write!(f, "{:?}", self) + } +} + impl fmt::Display for PrepareError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { use PrepareError::*; @@ -233,6 +267,7 @@ impl fmt::Display for FunctionCallError { FunctionCallError::WasmUnknownError => { write!(f, "Unknown error during Wasm contract execution") } + FunctionCallError::EvmError(e) => write!(f, "EVM: {:?}", e), } } } diff --git a/test-utils/testlib/Cargo.toml b/test-utils/testlib/Cargo.toml index c3c5ab80f06..d34b121f020 100644 --- a/test-utils/testlib/Cargo.toml +++ b/test-utils/testlib/Cargo.toml @@ -19,10 +19,11 @@ byteorder = "1.2" tempfile = "3" assert_matches = "1.3" num-rational = "0.2.4" -hex = "0.4.2" +hex = "0.4" ethabi = "8.0.0" ethabi-contract = "8.0.0" ethabi-derive = "8.0.0" +ethereum-types = "0.6.0" borsh = "0.7.1" diff --git a/test-utils/testlib/src/standard_test_cases.rs b/test-utils/testlib/src/standard_test_cases.rs index a4bb6060094..0d2e38ee73f 100644 --- a/test-utils/testlib/src/standard_test_cases.rs +++ b/test-utils/testlib/src/standard_test_cases.rs @@ -1,7 +1,9 @@ use std::sync::Arc; -use assert_matches::assert_matches; use ethabi_contract::use_contract; + +use assert_matches::assert_matches; +use ethereum_types::U256; use near_crypto::{InMemorySigner, KeyType}; use near_jsonrpc::ServerError; use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermission}; @@ -20,7 +22,6 @@ use crate::fees_utils::FeeHelper; use crate::node::Node; use crate::runtime_utils::{alice_account, bob_account, eve_dot_alice_account}; use crate::user::User; -use near_evm_runner::U256; /// The amount to send with function call. const FUNCTION_CALL_AMOUNT: Balance = TESTING_INIT_BALANCE / 10; From 3d5e99e471a461102da9917891201baa7a0766d4 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Thu, 3 Sep 2020 00:27:33 -0700 Subject: [PATCH 13/82] Finished wiring up back with Externals --- Cargo.lock | 1 + runtime/near-vm-runner/src/wasmer_runner.rs | 1 + runtime/runtime/Cargo.toml | 1 + runtime/runtime/src/actions.rs | 134 ++++++++++++-------- runtime/runtime/src/ext.rs | 15 ++- runtime/runtime/src/state_viewer.rs | 7 +- 6 files changed, 102 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e602285e229..cc574e53a99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3309,6 +3309,7 @@ dependencies = [ "borsh", "byteorder", "cached", + "ethereum-types", "hex", "indicatif 0.13.0", "lazy_static", diff --git a/runtime/near-vm-runner/src/wasmer_runner.rs b/runtime/near-vm-runner/src/wasmer_runner.rs index 9d97ce85256..0b5d8513e7f 100644 --- a/runtime/near-vm-runner/src/wasmer_runner.rs +++ b/runtime/near-vm-runner/src/wasmer_runner.rs @@ -160,6 +160,7 @@ impl IntoVMError for wasmer_runtime::error::RuntimeError { VMLogicError::InconsistentStateError(e) => { VMError::InconsistentStateError(e.clone()) } + VMLogicError::EvmError(e) => VMError::FunctionCallError(FunctionCallError::EvmError(e.clone())), } } else { panic!( diff --git a/runtime/runtime/Cargo.toml b/runtime/runtime/Cargo.toml index 4c1172f3639..cc123884bb5 100644 --- a/runtime/runtime/Cargo.toml +++ b/runtime/runtime/Cargo.toml @@ -16,6 +16,7 @@ num-rational = "0.2.4" num-bigint = "0.2.6" num-traits = "0.2.11" hex = "0.4.2" +ethereum-types = "0.6.0" borsh = "0.7.1" cached = "0.12.0" diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index ba718159202..cc4b7492867 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -1,7 +1,6 @@ use std::sync::Arc; -use borsh::{BorshDeserialize, BorshSerialize}; -use log::debug; +use borsh::BorshSerialize; use near_primitives::account::{AccessKey, AccessKeyPermission, Account}; use near_primitives::contract::ContractCode; @@ -37,19 +36,8 @@ use near_runtime_configs::AccountCreationConfig; use near_vm_errors::{CompilationError, FunctionCallError}; use near_vm_runner::VMError; -pub(crate) fn get_code_with_cache( - state_update: &TrieUpdate, - account_id: &AccountId, - account: &Account, -) -> Result>, StorageError> { - debug!(target:"runtime", "Calling the contract at account {}", account_id); - let code_hash = account.code_hash; - let code = || get_code(state_update, account_id, Some(code_hash)); - crate::cache::get_code(code_hash, code) -} - -pub(crate) fn action_function_call( - state_update: &mut TrieUpdate, +fn run_wasm( + runtime_ext: &mut RuntimeExt, apply_state: &ApplyState, account: &mut Account, receipt: &Receipt, @@ -61,40 +49,8 @@ pub(crate) fn action_function_call( action_hash: &CryptoHash, config: &RuntimeConfig, is_last_action: bool, - epoch_info_provider: &dyn EpochInfoProvider, -) -> Result<(), RuntimeError> { - let code = match get_code_with_cache(state_update, account_id, &account) { - Ok(Some(code)) => code, - Ok(None) => { - let error = FunctionCallError::CompilationError(CompilationError::CodeDoesNotExist { - account_id: account_id.clone(), - }); - result.result = Err(ActionErrorKind::FunctionCallError(error).into()); - return Ok(()); - } - Err(e) => { - return Err(e.into()); - } - }; - - if account.amount.checked_add(function_call.deposit).is_none() { - return Err(StorageError::StorageInconsistentState( - "Account balance integer overflow during function call deposit".to_string(), - ) - .into()); - } - - let mut runtime_ext = RuntimeExt::new( - state_update, - account_id, - &action_receipt.signer_id, - &action_receipt.signer_public_key, - action_receipt.gas_price, - action_hash, - &apply_state.epoch_id, - &apply_state.last_block_hash, - epoch_info_provider, - ); + code: Arc, +) -> (Option, Option) { // Output data receipts are ignored if the function call is not the last action in the batch. let output_data_receivers: Vec<_> = if is_last_action { action_receipt.output_data_receivers.iter().map(|r| r.receiver_id.clone()).collect() @@ -132,13 +88,87 @@ pub(crate) fn action_function_call( code.hash.as_ref().to_vec(), &code.code, function_call.method_name.as_bytes(), - &mut runtime_ext, + runtime_ext, context, &config.wasm_config, &config.transaction_costs, promise_results, - apply_state.current_protocol_version, ); + (outcome, err) +} + +pub(crate) fn action_function_call( + state_update: &mut TrieUpdate, + apply_state: &ApplyState, + account: &mut Account, + receipt: &Receipt, + action_receipt: &ActionReceipt, + promise_results: &[PromiseResult], + result: &mut ActionResult, + account_id: &AccountId, + function_call: &FunctionCallAction, + action_hash: &CryptoHash, + config: &RuntimeConfig, + is_last_action: bool, + epoch_info_provider: &dyn EpochInfoProvider, +) -> Result<(), RuntimeError> { + if account.amount.checked_add(function_call.deposit).is_none() { + return Err(StorageError::StorageInconsistentState( + "Account balance integer overflow during function call deposit".to_string(), + ) + .into()); + } + let mut runtime_ext = RuntimeExt::new( + state_update, + account_id, + &action_receipt.signer_id, + &action_receipt.signer_public_key, + action_receipt.gas_price, + action_hash, + &apply_state.epoch_id, + &apply_state.last_block_hash, + epoch_info_provider, + ); + let (outcome, err) = + if ethereum_types::U256::from((account.code_hash.0).0) == ethereum_types::U256::from(1) { + near_evm_runner::run_evm( + &mut runtime_ext, + &receipt.predecessor_id, + account.amount, + function_call.deposit, + function_call.method_name.clone(), + function_call.args.clone(), + ) + } else { + let code = match runtime_ext.get_code(account.code_hash) { + Ok(Some(code)) => code, + Ok(None) => { + let error = + FunctionCallError::CompilationError(CompilationError::CodeDoesNotExist { + account_id: account_id.clone(), + }); + result.result = Err(ActionErrorKind::FunctionCallError(error).into()); + return Ok(()); + } + Err(e) => { + return Err(e.into()); + } + }; + run_wasm( + &mut runtime_ext, + apply_state, + account, + receipt, + action_receipt, + promise_results, + account_id, + function_call, + action_hash, + config, + is_last_action, + code, + ) + }; let execution_succeeded = match err { Some(VMError::FunctionCallError(err)) => { result.result = Err(ActionErrorKind::FunctionCallError(err).into()); @@ -171,7 +201,7 @@ pub(crate) fn action_function_call( account.amount = outcome.balance; account.storage_usage = outcome.storage_usage; result.result = Ok(outcome.return_data); - result.new_receipts.extend(runtime_ext.into_receipts(account_id)); + result.new_receipts.extend(runtime_ext.into_receipts(&receipt.predecessor_id)); } } else { assert!(!execution_succeeded, "Outcome should always be available if execution succeeded") diff --git a/runtime/runtime/src/ext.rs b/runtime/runtime/src/ext.rs index 3ea9a064838..af362038f24 100644 --- a/runtime/runtime/src/ext.rs +++ b/runtime/runtime/src/ext.rs @@ -1,6 +1,9 @@ use borsh::BorshDeserialize; +use log::debug; + use near_crypto::PublicKey; use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermission}; +use near_primitives::contract::ContractCode; use near_primitives::errors::{ExternalError, StorageError}; use near_primitives::hash::CryptoHash; use near_primitives::receipt::{ActionReceipt, DataReceiver, Receipt, ReceiptEnum}; @@ -11,8 +14,9 @@ use near_primitives::transaction::{ use near_primitives::trie_key::TrieKey; use near_primitives::types::{AccountId, Balance, EpochId, EpochInfoProvider}; use near_primitives::utils::create_nonce_with_nonce; -use near_store::{TrieUpdate, TrieUpdateValuePtr}; +use near_store::{get_code, TrieUpdate, TrieUpdateValuePtr}; use near_vm_logic::{External, HostError, VMLogicError, ValuePtr}; +use std::sync::Arc; pub struct RuntimeExt<'a> { trie_update: &'a mut TrieUpdate, @@ -67,6 +71,15 @@ impl<'a> RuntimeExt<'a> { } } + pub fn get_code( + &self, + code_hash: CryptoHash, + ) -> Result>, StorageError> { + debug!(target:"runtime", "Calling the contract at account {}", self.account_id); + let code = || get_code(self.trie_update, self.account_id, Some(code_hash)); + crate::cache::get_code(code_hash, code) + } + pub fn create_storage_key(&self, key: &[u8]) -> TrieKey { TrieKey::ContractData { account_id: self.account_id.clone(), key: key.to_vec() } } diff --git a/runtime/runtime/src/state_viewer.rs b/runtime/runtime/src/state_viewer.rs index b0ef11406e8..84494378f95 100644 --- a/runtime/runtime/src/state_viewer.rs +++ b/runtime/runtime/src/state_viewer.rs @@ -17,7 +17,6 @@ use near_runtime_fees::RuntimeFeesConfig; use near_store::{get_access_key, get_account, TrieUpdate}; use near_vm_logic::{ReturnData, VMConfig, VMContext}; -use crate::actions::get_code_with_cache; use crate::ext::RuntimeExt; use near_primitives::version::ProtocolVersion; @@ -106,9 +105,6 @@ impl TrieViewer { let root = state_update.get_root(); let account = get_account(&state_update, contract_id)? .ok_or_else(|| format!("Account {:?} doesn't exist", contract_id))?; - let code = get_code_with_cache(&state_update, contract_id, &account)?.ok_or_else(|| { - format!("cannot find contract code for account {}", contract_id.clone()) - })?; // TODO(#1015): Add ability to pass public key and originator_id let originator_id = contract_id; let public_key = PublicKey::empty(KeyType::ED25519); @@ -125,6 +121,9 @@ impl TrieViewer { last_block_hash, epoch_info_provider, ); + let code = runtime_ext.get_code(account.code_hash)?.ok_or_else(|| { + format!("cannot find contract code for account {}", contract_id.clone()) + })?; let context = VMContext { current_account_id: contract_id.clone(), From 8ced86bee18b98b560029f732e3683a81b114a4b Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Thu, 3 Sep 2020 01:15:46 -0700 Subject: [PATCH 14/82] Refactor for view calls to use exactly the same VM calling code --- runtime/near-vm-errors/src/lib.rs | 2 + runtime/runtime/src/actions.rs | 180 +++++++++--------- runtime/runtime/src/ext.rs | 5 + runtime/runtime/src/state_viewer.rs | 120 +++++++----- test-utils/testlib/src/standard_test_cases.rs | 14 +- 5 files changed, 180 insertions(+), 141 deletions(-) diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index f8b0c69dccb..f86bb664773 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -209,6 +209,7 @@ pub enum VMLogicError { /// E.g. a deserialization error or an integer overflow. #[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] pub enum InconsistentStateError { + StorageError(String), /// Math operation with a value from the state resulted in a integer overflow. IntegerOverflow, } @@ -325,6 +326,7 @@ impl fmt::Display for VMError { impl std::fmt::Display for InconsistentStateError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match self { + InconsistentStateError::StorageError(err) => write!(f, "Storage error: {:?}", err), InconsistentStateError::IntegerOverflow => write!( f, "Math operation with a value from the state resulted in a integer overflow.", diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index cc4b7492867..0174044dd01 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use borsh::BorshSerialize; use near_primitives::account::{AccessKey, AccessKeyPermission, Account}; @@ -20,6 +18,7 @@ use near_store::{ get_access_key, get_code, remove_access_key, remove_account, set_access_key, set_code, StorageError, TrieUpdate, }; +use near_vm_errors::{CompilationError, FunctionCallError, InconsistentStateError}; use near_vm_logic::types::PromiseResult; use near_vm_logic::VMContext; @@ -36,65 +35,95 @@ use near_runtime_configs::AccountCreationConfig; use near_vm_errors::{CompilationError, FunctionCallError}; use near_vm_runner::VMError; -fn run_wasm( - runtime_ext: &mut RuntimeExt, +/// Runs given function call with given context / apply state. +/// Precompiles: +/// - 0x1: EVM interpreter; +pub(crate) fn execute_function_call( apply_state: &ApplyState, + runtime_ext: &mut RuntimeExt, account: &mut Account, - receipt: &Receipt, + predecessor_id: &AccountId, action_receipt: &ActionReceipt, promise_results: &[PromiseResult], - result: &mut ActionResult, - account_id: &AccountId, function_call: &FunctionCallAction, action_hash: &CryptoHash, config: &RuntimeConfig, is_last_action: bool, - code: Arc, + is_view: bool, ) -> (Option, Option) { - // Output data receipts are ignored if the function call is not the last action in the batch. - let output_data_receivers: Vec<_> = if is_last_action { - action_receipt.output_data_receivers.iter().map(|r| r.receiver_id.clone()).collect() + if ethereum_types::U256::from((account.code_hash.0).0) == ethereum_types::U256::from(1) { + near_evm_runner::run_evm( + runtime_ext, + predecessor_id, + account.amount, + function_call.deposit, + function_call.method_name.clone(), + function_call.args.clone(), + ) } else { - vec![] - }; - let context = VMContext { - current_account_id: account_id.clone(), - signer_account_id: action_receipt.signer_id.clone(), - signer_account_pk: action_receipt - .signer_public_key - .try_to_vec() - .expect("Failed to serialize"), - predecessor_account_id: receipt.predecessor_id.clone(), - input: function_call.args.clone(), - block_index: apply_state.block_index, - block_timestamp: apply_state.block_timestamp, - epoch_height: apply_state.epoch_height, - account_balance: account.amount, - account_locked_balance: account.locked, - storage_usage: account.storage_usage, - attached_deposit: function_call.deposit, - prepaid_gas: function_call.gas, - random_seed: if apply_state.current_protocol_version < CORRECT_RANDOM_VALUE_PROTOCOL_VERSION - { - action_hash.as_ref().to_vec() + let code = match runtime_ext.get_code(account.code_hash) { + Ok(Some(code)) => code, + Ok(None) => { + let error = + FunctionCallError::CompilationError(CompilationError::CodeDoesNotExist { + account_id: runtime_ext.account_id().clone(), + }); + return (None, Some(VMError::FunctionCallError(error))); + } + Err(e) => { + return ( + None, + Some(VMError::InconsistentStateError(InconsistentStateError::StorageError( + e.to_string(), + ))), + ); + } + }; + // Output data receipts are ignored if the function call is not the last action in the batch. + let output_data_receivers: Vec<_> = if is_last_action { + action_receipt.output_data_receivers.iter().map(|r| r.receiver_id.clone()).collect() } else { - apply_state.random_seed.as_ref().to_vec() - }, - is_view: false, - output_data_receivers, - }; + vec![] + }; + let context = VMContext { + current_account_id: runtime_ext.account_id().clone(), + signer_account_id: action_receipt.signer_id.clone(), + signer_account_pk: action_receipt + .signer_public_key + .try_to_vec() + .expect("Failed to serialize"), + predecessor_account_id: predecessor_id.clone(), + input: function_call.args.clone(), + block_index: apply_state.block_index, + block_timestamp: apply_state.block_timestamp, + epoch_height: apply_state.epoch_height, + account_balance: account.amount, + account_locked_balance: account.locked, + storage_usage: account.storage_usage, + attached_deposit: function_call.deposit, + prepaid_gas: function_call.gas, + random_seed: if apply_state.current_protocol_version + < CORRECT_RANDOM_VALUE_PROTOCOL_VERSION + { + action_hash.as_ref().to_vec() + } else { + apply_state.random_seed.as_ref().to_vec() + }, + is_view, + output_data_receivers, + }; - let (outcome, err) = near_vm_runner::run( - code.hash.as_ref().to_vec(), - &code.code, - function_call.method_name.as_bytes(), - runtime_ext, - context, - &config.wasm_config, - &config.transaction_costs, - promise_results, - ); - (outcome, err) + near_vm_runner::run( + code.hash.as_ref().to_vec(), + &code.code, + function_call.method_name.as_bytes(), + runtime_ext, + context, + &config.wasm_config, + &config.transaction_costs, + promise_results, + ) + } } pub(crate) fn action_function_call( @@ -129,46 +158,19 @@ pub(crate) fn action_function_call( &apply_state.last_block_hash, epoch_info_provider, ); - let (outcome, err) = - if ethereum_types::U256::from((account.code_hash.0).0) == ethereum_types::U256::from(1) { - near_evm_runner::run_evm( - &mut runtime_ext, - &receipt.predecessor_id, - account.amount, - function_call.deposit, - function_call.method_name.clone(), - function_call.args.clone(), - ) - } else { - let code = match runtime_ext.get_code(account.code_hash) { - Ok(Some(code)) => code, - Ok(None) => { - let error = - FunctionCallError::CompilationError(CompilationError::CodeDoesNotExist { - account_id: account_id.clone(), - }); - result.result = Err(ActionErrorKind::FunctionCallError(error).into()); - return Ok(()); - } - Err(e) => { - return Err(e.into()); - } - }; - run_wasm( - &mut runtime_ext, - apply_state, - account, - receipt, - action_receipt, - promise_results, - account_id, - function_call, - action_hash, - config, - is_last_action, - code, - ) - }; + let (outcome, err) = execute_function_call( + apply_state, + &mut runtime_ext, + account, + &receipt.predecessor_id, + action_receipt, + promise_results, + function_call, + action_hash, + config, + is_last_action, + false, + ); let execution_succeeded = match err { Some(VMError::FunctionCallError(err)) => { result.result = Err(ActionErrorKind::FunctionCallError(err).into()); diff --git a/runtime/runtime/src/ext.rs b/runtime/runtime/src/ext.rs index af362038f24..804ef438a7a 100644 --- a/runtime/runtime/src/ext.rs +++ b/runtime/runtime/src/ext.rs @@ -71,6 +71,11 @@ impl<'a> RuntimeExt<'a> { } } + #[inline] + pub fn account_id(&self) -> &'a AccountId { + self.account_id + } + pub fn get_code( &self, code_hash: CryptoHash, diff --git a/runtime/runtime/src/state_viewer.rs b/runtime/runtime/src/state_viewer.rs index 84494378f95..24dd6e0c4bc 100644 --- a/runtime/runtime/src/state_viewer.rs +++ b/runtime/runtime/src/state_viewer.rs @@ -1,7 +1,6 @@ use std::str; use std::time::Instant; -use borsh::BorshSerialize; use log::debug; use near_crypto::{KeyType, PublicKey}; @@ -13,12 +12,17 @@ use near_primitives::types::EpochHeight; use near_primitives::types::{AccountId, BlockHeight, EpochId, EpochInfoProvider}; use near_primitives::utils::is_valid_account_id; use near_primitives::views::{StateItem, ViewStateResult}; -use near_runtime_fees::RuntimeFeesConfig; use near_store::{get_access_key, get_account, TrieUpdate}; -use near_vm_logic::{ReturnData, VMConfig, VMContext}; +use near_vm_logic::ReturnData; +use crate::actions::execute_function_call; use crate::ext::RuntimeExt; +use crate::ApplyState; +use near_primitives::receipt::ActionReceipt; +use near_primitives::transaction::FunctionCallAction; use near_primitives::version::ProtocolVersion; +use near_primitives::version::PROTOCOL_VERSION; +use near_runtime_configs::RuntimeConfig; pub struct TrieViewer {} @@ -103,59 +107,73 @@ impl TrieViewer { return Err(format!("Contract ID {:?} is not valid", contract_id).into()); } let root = state_update.get_root(); - let account = get_account(&state_update, contract_id)? + let mut account = get_account(&state_update, contract_id)? .ok_or_else(|| format!("Account {:?} doesn't exist", contract_id))?; // TODO(#1015): Add ability to pass public key and originator_id let originator_id = contract_id; let public_key = PublicKey::empty(KeyType::ED25519); - let (outcome, err) = { - let empty_hash = CryptoHash::default(); - let mut runtime_ext = RuntimeExt::new( - &mut state_update, - contract_id, - originator_id, - &public_key, - 0, - &empty_hash, - epoch_id, - last_block_hash, - epoch_info_provider, - ); - let code = runtime_ext.get_code(account.code_hash)?.ok_or_else(|| { - format!("cannot find contract code for account {}", contract_id.clone()) - })?; - - let context = VMContext { - current_account_id: contract_id.clone(), - signer_account_id: originator_id.clone(), - signer_account_pk: public_key.try_to_vec().expect("Failed to serialize"), - predecessor_account_id: originator_id.clone(), - input: args.to_owned(), - block_index: block_height, - block_timestamp, - epoch_height, - account_balance: account.amount, - account_locked_balance: account.locked, - storage_usage: account.storage_usage, - attached_deposit: 0, - prepaid_gas: 0, - random_seed: root.as_ref().into(), - is_view: true, - output_data_receivers: vec![], - }; - - near_vm_runner::run( - code.hash.as_ref().to_vec(), - &code.code, - method_name.as_bytes(), - &mut runtime_ext, - context, - &VMConfig::default(), - &RuntimeFeesConfig::default(), - &[], - current_protocol_version, - ) + let empty_hash = CryptoHash::default(); + let mut runtime_ext = RuntimeExt::new( + &mut state_update, + contract_id, + originator_id, + &public_key, + 0, + &empty_hash, + epoch_id, + last_block_hash, + epoch_info_provider, + ); + let config = RuntimeConfig::default(); + let apply_state = ApplyState { + block_index: block_height, + last_block_hash: last_block_hash.clone(), + epoch_id: epoch_id.clone(), + epoch_height, + gas_price: 0, + block_timestamp, + gas_limit: None, + random_seed: root, + current_protocol_version: PROTOCOL_VERSION, + }; + let action_receipt = ActionReceipt { + signer_id: originator_id.clone(), + signer_public_key: public_key.clone(), + gas_price: 0, + output_data_receivers: vec![], + input_data_ids: vec![], + actions: vec![], + }; + let function_call = FunctionCallAction { + method_name: method_name.to_string(), + args: args.to_vec(), + gas: 0, + deposit: 0, }; + let (outcome, err) = execute_function_call( + &apply_state, + &mut runtime_ext, + &mut account, + &originator_id, + &action_receipt, + &[], + &function_call, + &empty_hash, + &config, + true, + true, + ); + // near_vm_runner::run( + // code.hash.as_ref().to_vec(), + // &code.code, + // method_name.as_bytes(), + // &mut runtime_ext, + // context, + // &VMConfig::default(), + // &RuntimeFeesConfig::default(), + // &[], + // ) + // }; let elapsed = now.elapsed(); let time_ms = (elapsed.as_secs() as f64 / 1_000.0) + f64::from(elapsed.subsec_nanos()) / 1_000_000.0; diff --git a/test-utils/testlib/src/standard_test_cases.rs b/test-utils/testlib/src/standard_test_cases.rs index 0d2e38ee73f..ac77f438d7a 100644 --- a/test-utils/testlib/src/standard_test_cases.rs +++ b/test-utils/testlib/src/standard_test_cases.rs @@ -1308,11 +1308,23 @@ pub fn test_evm_deploy_call(node: impl Node) { ); let args = vec![contract_id, input].concat(); let bytes = node_user - .function_call(alice_account(), evm_account(), "view_call_contract", args, 10u64.pow(14), 0) + .function_call( + alice_account(), + evm_account(), + "view_call_contract", + args.clone(), + 10u64.pow(14), + 0, + ) .unwrap() .status .as_success_decoded() .unwrap(); let res = cryptozombies::functions::get_zombies_by_owner::decode_output(&bytes).unwrap(); assert_eq!(res, vec![U256::from(0)]); + + let result = node_user.view_call(&evm_account(), "view_call_contract", &args).unwrap(); + let res = + cryptozombies::functions::get_zombies_by_owner::decode_output(&result.result).unwrap(); + assert_eq!(res, vec![U256::from(0)]); } From 1a5037c774a31f5b879bb68da60e97faacf3a897 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Fri, 4 Sep 2020 13:46:51 -0700 Subject: [PATCH 15/82] Clean up EVM_CODE_HASH usage. Clean up standard_ops tests. Add failure tests. --- core/primitives/src/utils.rs | 13 +++- neard/src/config.rs | 61 +++++++++------- runtime/near-evm-runner/src/lib.rs | 46 ++++++++---- runtime/near-evm-runner/src/types.rs | 2 +- runtime/near-evm-runner/tests/failures.rs | 24 ++++++ runtime/near-evm-runner/tests/standard_ops.rs | 73 +++++++++---------- runtime/runtime/src/actions.rs | 5 +- test-utils/testlib/src/node/runtime_node.rs | 14 +++- test-utils/testlib/src/standard_test_cases.rs | 7 +- tests/test_cases_testnet_rpc.rs | 2 +- 10 files changed, 158 insertions(+), 89 deletions(-) create mode 100644 runtime/near-evm-runner/tests/failures.rs diff --git a/core/primitives/src/utils.rs b/core/primitives/src/utils.rs index e74a4dc5c8d..1fe621dfea5 100644 --- a/core/primitives/src/utils.rs +++ b/core/primitives/src/utils.rs @@ -11,7 +11,7 @@ use serde; use lazy_static::lazy_static; -use crate::hash::{hash, CryptoHash}; +use crate::hash::{hash, CryptoHash, Digest}; use crate::types::{AccountId, NumSeats, NumShards, ShardId}; pub const MIN_ACCOUNT_ID_LEN: usize = 2; @@ -20,6 +20,17 @@ pub const MAX_ACCOUNT_ID_LEN: usize = 64; /// Number of nano seconds in a second. const NS_IN_SECOND: u64 = 1_000_000_000; +lazy_static! { + /// Predetermined code hash used for EVM precompile. + pub static ref EVM_CODE_HASH: CryptoHash = code_hash(1); +} + +fn code_hash(num: u8) -> CryptoHash { + let mut buf = [0; 32]; + buf[0] = num; + return CryptoHash(Digest(buf)); +} + pub fn get_block_shard_id(block_hash: &CryptoHash, shard_id: ShardId) -> Vec { let mut res = Vec::with_capacity(40); res.extend_from_slice(block_hash.as_ref()); diff --git a/neard/src/config.rs b/neard/src/config.rs index a7b12353297..b2c03d39ca1 100644 --- a/neard/src/config.rs +++ b/neard/src/config.rs @@ -28,7 +28,7 @@ use near_primitives::types::{ AccountId, AccountInfo, Balance, BlockHeightDelta, EpochHeight, Gas, NumBlocks, NumSeats, NumShards, ShardId, }; -use near_primitives::utils::{generate_random_string, get_num_seats_per_shard}; +use near_primitives::utils::{generate_random_string, get_num_seats_per_shard, EVM_CODE_HASH}; use near_primitives::validator_signer::{InMemoryValidatorSigner, ValidatorSigner}; use near_primitives::version::PROTOCOL_VERSION; #[cfg(feature = "rosetta_rpc")] @@ -463,16 +463,13 @@ impl Genesis { amount: TESTING_INIT_STAKE, }); } - records.extend( - state_records_account_with_key( - account, - &signer.public_key.clone(), - TESTING_INIT_BALANCE - - if i < num_validator_seats { TESTING_INIT_STAKE } else { 0 }, - if i < num_validator_seats { TESTING_INIT_STAKE } else { 0 }, - CryptoHash::default(), - ) - .into_iter(), + add_account_with_key( + &mut records, + account, + &signer.public_key.clone(), + TESTING_INIT_BALANCE - if i < num_validator_seats { TESTING_INIT_STAKE } else { 0 }, + if i < num_validator_seats { TESTING_INIT_STAKE } else { 0 }, + CryptoHash::default(), ); } add_protocol_account(&mut records); @@ -661,37 +658,37 @@ fn add_protocol_account(records: &mut Vec) { KeyType::ED25519, PROTOCOL_TREASURY_ACCOUNT, ); - records.extend(state_records_account_with_key( + add_account_with_key( + records, PROTOCOL_TREASURY_ACCOUNT, &signer.public_key, TESTING_INIT_BALANCE, 0, CryptoHash::default(), - )); + ); } fn random_chain_id() -> String { format!("test-chain-{}", generate_random_string(5)) } -fn state_records_account_with_key( +fn add_account_with_key( + records: &mut Vec, account_id: &str, public_key: &PublicKey, amount: u128, staked: u128, code_hash: CryptoHash, -) -> Vec { - vec![ - StateRecord::Account { - account_id: account_id.to_string(), - account: Account { amount, locked: staked, code_hash, storage_usage: 0 }, - }, - StateRecord::AccessKey { - account_id: account_id.to_string(), - public_key: public_key.clone(), - access_key: AccessKey::full_access(), - }, - ] +) { + records.push(StateRecord::Account { + account_id: account_id.to_string(), + account: Account { amount, locked: staked, code_hash, storage_usage: 0 }, + }); + records.push(StateRecord::AccessKey { + account_id: account_id.to_string(), + public_key: public_key.clone(), + access_key: AccessKey::full_access(), + }); } /// Generate a validator key and save it to the file path. @@ -810,13 +807,23 @@ pub fn init_configs( let network_signer = InMemorySigner::from_random("".to_string(), KeyType::ED25519); network_signer.write_to_file(&dir.join(config.node_key_file)); - let mut records = state_records_account_with_key( + let mut records = vec![]; + add_account_with_key( + &mut records, &account_id, &signer.public_key(), TESTING_INIT_BALANCE, TESTING_INIT_STAKE, CryptoHash::default(), ); + add_account_with_key( + &mut records, + "evm", + &signer.public_key(), + TESTING_INIT_BALANCE, + 0, + *EVM_CODE_HASH, + ); add_protocol_account(&mut records); let genesis_config = GenesisConfig { diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index c3b6adcd197..a82d1bc10c3 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -3,11 +3,11 @@ use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; use near_vm_errors::{EvmError, FunctionCallError, VMError}; -use near_vm_logic::types::{AccountId, Balance, ReturnData}; +use near_vm_logic::types::{AccountId, Balance, ReturnData, StorageUsage}; use near_vm_logic::{External, VMLogicError, VMOutcome}; use crate::evm_state::{EvmAccount, EvmState, StateStore}; -use crate::types::{GetCodeArgs, GetStorageAtArgs, Result, TransferArgs, WithdrawArgs}; +use crate::types::{AddressArg, GetStorageAtArgs, Result, TransferArgs, WithdrawArgs}; mod builtins; mod evm_state; @@ -20,6 +20,7 @@ pub struct EvmContext<'a> { ext: &'a mut dyn External, predecessor_id: AccountId, attached_deposit: Balance, + storage_usage: StorageUsage, logs: Vec, } @@ -99,8 +100,9 @@ impl<'a> EvmContext<'a> { ext: &'a mut dyn External, predecessor_id: AccountId, attached_deposit: Balance, + storage_usage: StorageUsage, ) -> Self { - Self { ext, predecessor_id, attached_deposit, logs: Vec::default() } + Self { ext, predecessor_id, attached_deposit, storage_usage, logs: Vec::default() } } pub fn deploy_code(&mut self, bytecode: Vec) -> Result
{ @@ -119,6 +121,9 @@ impl<'a> EvmContext<'a> { } pub fn call_function(&mut self, args: Vec) -> Result> { + if args.len() <= 20 { + return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); + } let contract_address = Address::from_slice(&args[..20]); let input = &args[20..]; let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); @@ -135,6 +140,9 @@ impl<'a> EvmContext<'a> { /// /// This function serves the eth_call functionality, and will NOT apply state changes. pub fn view_call_function(&mut self, args: Vec) -> Result> { + if args.len() <= 20 { + return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); + } let contract_address = Address::from_slice(&args[..20]); let input = &args[20..]; let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); @@ -143,7 +151,7 @@ impl<'a> EvmContext<'a> { } pub fn get_code(&self, args: Vec) -> Result> { - let args = GetCodeArgs::try_from_slice(&args) + let args = AddressArg::try_from_slice(&args) .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; Ok(self.code_at(&Address::from_slice(&args.address)).unwrap_or(None).unwrap_or(vec![])) } @@ -158,11 +166,15 @@ impl<'a> EvmContext<'a> { } pub fn get_balance(&self, args: Vec) -> Result { - self.balance_of(&Address::from_slice(&args)) + let args = AddressArg::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + self.balance_of(&Address::from_slice(&args.address)) } pub fn get_nonce(&self, args: Vec) -> Result { - self.nonce_of(&Address::from_slice(&args)) + let args = AddressArg::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + self.nonce_of(&Address::from_slice(&args.address)) } pub fn deposit(&mut self, args: Vec) -> Result { @@ -205,28 +217,36 @@ pub fn run_evm( predecessor_id: &AccountId, amount: Balance, attached_deposit: Balance, + storage_usage: StorageUsage, method_name: String, args: Vec, ) -> (Option, Option) { - let mut context = EvmContext::new(ext, predecessor_id.clone(), attached_deposit); + let mut context = EvmContext::new(ext, predecessor_id.clone(), attached_deposit, storage_usage); let result = match method_name.as_str() { + // Change the state methods. "deploy_code" => context.deploy_code(args).map(|address| utils::address_to_vec(&address)), - "get_code" => context.get_code(args), "call_function" => context.call_function(args), - "view_call_contract" => context.view_call_function(args), - "get_storage_at" => context.get_storage_at(args), - "get_balance" => context.get_balance(args).map(|balance| utils::u256_to_vec(&balance)), "deposit" => context.deposit(args).map(|balance| utils::u256_to_vec(&balance)), "withdraw" => context.withdraw(args).map(|_| vec![]), "transfer" => context.transfer(args).map(|_| vec![]), + // View methods. + "view_call_contract" => context.view_call_function(args), + "get_code" => context.get_code(args), + "get_storage_at" => context.get_storage_at(args), + "get_nonce" => context.get_nonce(args).map(|nonce| utils::u256_to_vec(&nonce)), + "get_balance" => context.get_balance(args).map(|balance| utils::u256_to_vec(&balance)), _ => Err(VMLogicError::EvmError(EvmError::MethodNotFound)), }; match result { Ok(value) => { let outcome = VMOutcome { - balance: amount, - storage_usage: 0, + // This is total amount of all $NEAR inside this EVM. + // Outcome balance is equal to amount with attached deposit, because all the accounting happens internally. + // Should already validate that will not overflow external to this call. + balance: amount.checked_add(attached_deposit).unwrap_or(amount), + storage_usage: context.storage_usage, return_data: ReturnData::Value(value), + // TODO: calculate how much gas was used. burnt_gas: 0, used_gas: 0, logs: context.logs, diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index 0f62072899e..61214a04504 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -9,7 +9,7 @@ pub type RawHash = [u8; 32]; pub type Result = std::result::Result; #[derive(BorshSerialize, BorshDeserialize)] -pub struct GetCodeArgs { +pub struct AddressArg { pub address: RawAddress, } diff --git a/runtime/near-evm-runner/tests/failures.rs b/runtime/near-evm-runner/tests/failures.rs new file mode 100644 index 00000000000..8511f0243b2 --- /dev/null +++ b/runtime/near-evm-runner/tests/failures.rs @@ -0,0 +1,24 @@ +use near_evm_runner::EvmContext; +use near_vm_logic::mocks::mock_external::MockedExternal; + +fn accounts(num: usize) -> String { + ["evm", "alice"][num].to_string() +} + +/// Test various invalid inputs to function calls. +#[test] +fn test_invalid_input() { + let mut fake_external = MockedExternal::new(); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); + assert!(context.get_nonce(vec![]).is_err()); + assert!(context.get_balance(vec![]).is_err()); + assert!(context.get_code(vec![]).is_err()); + assert!(context.get_storage_at(vec![]).is_err()); + assert!(context.view_call_function(vec![]).is_err()); + assert!(context.view_call_function(vec![0u8; 20]).is_err()); + assert!(context.call_function(vec![]).is_err()); + assert!(context.call_function(vec![0u8; 20]).is_err()); + assert!(context.deposit(vec![]).is_err()); + assert!(context.withdraw(vec![]).is_err()); + assert!(context.transfer(vec![]).is_err()); +} diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index ea59bcb898b..84c056a7844 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -9,10 +9,9 @@ use near_evm_runner::types::{TransferArgs, WithdrawArgs}; use near_evm_runner::utils::{ address_from_arr, address_to_vec, encode_call_function_args, near_account_id_to_evm_address, }; -use near_evm_runner::{EvmContext, EvmError}; -use near_primitives::hash::CryptoHash; -use near_store::test_utils::create_tries; -use near_store::TrieUpdate; +use near_evm_runner::EvmContext; +use near_vm_errors::{EvmError, VMLogicError}; +use near_vm_logic::mocks::mock_external::MockedExternal; use_contract!(soltest, "tests/build/SolTests.abi"); use_contract!(subcontract, "tests/build/SubContract.abi"); @@ -28,26 +27,20 @@ fn accounts(account_id: usize) -> String { vec!["evm", "alice", "bob", "chad"][account_id].to_string() } -fn setup() -> TrieUpdate { - let tries = create_tries(); - let root = CryptoHash::default(); - tries.new_trie_update(0, root) -} - #[test] fn test_funds_transfers() { - let mut state_update = setup(); - let context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + let mut fake_external = MockedExternal::new(); + let context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); assert_eq!( context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), U256::from(0) ); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); assert_eq!( context.deposit(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), U256::from(100) ); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); context .transfer( TransferArgs { account_id: near_account_id_to_evm_address(&accounts(2)).0, amount: 50 } @@ -59,7 +52,7 @@ fn test_funds_transfers() { context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))).unwrap(), U256::from(50) ); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(2), 0); + let mut context = EvmContext::new(&mut fake_external, accounts(2), 0, 0); context .withdraw(WithdrawArgs { account_id: accounts(2), amount: 50 }.try_to_vec().unwrap()) .unwrap(); @@ -71,8 +64,8 @@ fn test_funds_transfers() { #[test] fn test_deploy_with_nonce() { - let mut state_update = setup(); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + let mut fake_external = MockedExternal::new(); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); let address = near_account_id_to_evm_address(&accounts(1)); assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(0)); let address1 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); @@ -84,9 +77,9 @@ fn test_deploy_with_nonce() { #[test] fn test_failed_deploy_returns_error() { - let mut state_update = setup(); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); - if let Err(EvmError::DeployFail(_)) = + let mut fake_external = MockedExternal::new(); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); + if let Err(VMLogicError::EvmError(EvmError::DeployFail(_))) = context.deploy_code(hex::decode(&CONSTRUCTOR_TEST).unwrap()) { } else { @@ -96,8 +89,8 @@ fn test_failed_deploy_returns_error() { #[test] fn test_internal_create() { - let mut state_update = setup(); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + let mut fake_external = MockedExternal::new(); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); @@ -115,8 +108,8 @@ fn test_internal_create() { #[test] fn test_precompiles() { - let mut state_update = setup(); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + let mut fake_external = MockedExternal::new(); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); let (input, _) = soltest::functions::precompile_test::call(); @@ -124,22 +117,22 @@ fn test_precompiles() { assert_eq!(raw.len(), 0); } -fn setup_and_deploy_test() -> (TrieUpdate, Address) { - let mut state_update = setup(); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); +fn setup_and_deploy_test() -> (MockedExternal, Address) { + let mut fake_external = MockedExternal::new(); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); - (state_update, test_addr) + (fake_external, test_addr) } #[test] fn test_deploy_and_transfer() { - let (mut state_update, test_addr) = setup_and_deploy_test(); + let (mut fake_external, test_addr) = setup_and_deploy_test(); // This should increment the nonce of the deploying contract. // There is 100 attached to this that should be passed through. let (input, _) = soltest::functions::deploy_new_guy::call(8); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); // The sub_addr should have been transferred 100 yoctoN. @@ -150,12 +143,12 @@ fn test_deploy_and_transfer() { #[test] fn test_deploy_with_value() { - let (mut state_update, test_addr) = setup_and_deploy_test(); + let (mut fake_external, test_addr) = setup_and_deploy_test(); // This should increment the nonce of the deploying contract // There is 100 attached to this that should be passed through let (input, _) = soltest::functions::pay_new_guy::call(8); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); // The sub_addr should have been transferred 100 tokens. @@ -166,10 +159,10 @@ fn test_deploy_with_value() { #[test] fn test_contract_to_eoa_transfer() { - let (mut state_update, test_addr) = setup_and_deploy_test(); + let (mut fake_external, test_addr) = setup_and_deploy_test(); let (input, _) = soltest::functions::return_some_funds::call(); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); let sender_addr = raw[12..32].to_vec(); @@ -179,8 +172,8 @@ fn test_contract_to_eoa_transfer() { #[test] fn test_get_code() { - let (mut state_update, test_addr) = setup_and_deploy_test(); - let context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + let (mut fake_external, test_addr) = setup_and_deploy_test(); + let context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); assert!(context.get_code(test_addr.0.to_vec()).unwrap().len() > 1500); // contract code should roughly be over length 1500 assert_eq!(context.get_code(vec![0u8; 20]).unwrap().len(), 0); @@ -188,12 +181,12 @@ fn test_get_code() { #[test] fn test_view_call() { - let (mut state_update, test_addr) = setup_and_deploy_test(); + let (mut fake_external, test_addr) = setup_and_deploy_test(); // This should NOT increment the nonce of the deploying contract // And NO CODE should be deployed let (input, _) = soltest::functions::deploy_new_guy::call(8); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 0); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); let raw = context.view_call_function(encode_call_function_args(test_addr, input)).unwrap(); assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); @@ -203,8 +196,8 @@ fn test_view_call() { #[test] fn test_solidity_accurate_storage_on_selfdestruct() { - let mut state_update = setup(); - let mut context = EvmContext::new(&mut state_update, accounts(0), accounts(1), 100); + let mut fake_external = MockedExternal::new(); + let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); assert_eq!( context.deposit(near_account_id_to_evm_address(&accounts(1)).0.to_vec()).unwrap(), U256::from(100) diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 0174044dd01..c4c7bc47b22 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -10,7 +10,7 @@ use near_primitives::transaction::{ }; use near_primitives::types::{AccountId, EpochInfoProvider, ValidatorStake}; use near_primitives::utils::{ - is_valid_account_id, is_valid_sub_account_id, is_valid_top_level_account_id, + is_valid_account_id, is_valid_sub_account_id, is_valid_top_level_account_id, EVM_CODE_HASH, }; use near_runtime_fees::RuntimeFeesConfig; use near_runtime_utils::is_account_id_64_len_hex; @@ -51,12 +51,13 @@ pub(crate) fn execute_function_call( is_last_action: bool, is_view: bool, ) -> (Option, Option) { - if ethereum_types::U256::from((account.code_hash.0).0) == ethereum_types::U256::from(1) { + if account.code_hash == *EVM_CODE_HASH { near_evm_runner::run_evm( runtime_ext, predecessor_id, account.amount, function_call.deposit, + account.storage_usage, function_call.method_name.clone(), function_call.args.clone(), ) diff --git a/test-utils/testlib/src/node/runtime_node.rs b/test-utils/testlib/src/node/runtime_node.rs index 989e2b8fe33..9e8293b30fb 100644 --- a/test-utils/testlib/src/node/runtime_node.rs +++ b/test-utils/testlib/src/node/runtime_node.rs @@ -3,11 +3,12 @@ use std::sync::{Arc, RwLock}; use near_chain_configs::Genesis; use near_crypto::{InMemorySigner, KeyType, Signer}; use near_primitives::types::AccountId; -use neard::config::GenesisExt; +use near_primitives::utils::EVM_CODE_HASH; +use neard::config::{GenesisExt, TESTING_INIT_BALANCE}; use crate::node::Node; use crate::runtime_utils::{ - add_test_contract, alice_account, bob_account, get_runtime_and_trie_from_genesis, + add_test_contract, alice_account, bob_account, evm_account, get_runtime_and_trie_from_genesis, }; use crate::user::runtime_user::MockClient; use crate::user::{RuntimeUser, User}; @@ -23,6 +24,15 @@ impl RuntimeNode { let mut genesis = Genesis::test(vec![&alice_account(), &bob_account(), "carol.near"], 3); add_test_contract(&mut genesis, &alice_account()); add_test_contract(&mut genesis, &bob_account()); + genesis.records.as_mut().push(StateRecord::Account { + account_id: evm_account(), + account: Account { + amount: TESTING_INIT_BALANCE, + locked: 0, + code_hash: *EVM_CODE_HASH, + storage_usage: 0, + }, + }); Self::new_from_genesis(account_id, genesis) } diff --git a/test-utils/testlib/src/standard_test_cases.rs b/test-utils/testlib/src/standard_test_cases.rs index ac77f438d7a..8174b150ce5 100644 --- a/test-utils/testlib/src/standard_test_cases.rs +++ b/test-utils/testlib/src/standard_test_cases.rs @@ -1285,7 +1285,7 @@ pub fn test_evm_deploy_call(node: impl Node) { ) .unwrap(); let contract_id = node_user - .function_call(alice_account(), evm_account(), "deploy_code", bytes, 10u64.pow(14), 0) + .function_call(alice_account(), evm_account(), "deploy_code", bytes, 10u64.pow(14), 10) .unwrap() .status .as_success_decoded() @@ -1306,7 +1306,7 @@ pub fn test_evm_deploy_call(node: impl Node) { let (input, _decoder) = cryptozombies::functions::get_zombies_by_owner::call( near_evm_runner::utils::near_account_id_to_evm_address(&alice_account()), ); - let args = vec![contract_id, input].concat(); + let args = vec![contract_id.clone(), input].concat(); let bytes = node_user .function_call( alice_account(), @@ -1327,4 +1327,7 @@ pub fn test_evm_deploy_call(node: impl Node) { let res = cryptozombies::functions::get_zombies_by_owner::decode_output(&result.result).unwrap(); assert_eq!(res, vec![U256::from(0)]); + + let result = node_user.view_call(&evm_account(), "get_balance", &contract_id).unwrap(); + assert_eq!(U256::from_big_endian(&result.result), U256::from(10)); } diff --git a/tests/test_cases_testnet_rpc.rs b/tests/test_cases_testnet_rpc.rs index dd56a7160b5..2ca9ac33e1a 100644 --- a/tests/test_cases_testnet_rpc.rs +++ b/tests/test_cases_testnet_rpc.rs @@ -199,6 +199,6 @@ mod test { #[test] fn test_evm_deploy_call_testnet() { - run_testnet_test!(test_evm_deploy_call(node)); + run_testnet_test!(test_evm_deploy_call); } } From 9163a7e4981bc0cfb6dea8bbdee1e6568cac2fb0 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sat, 5 Sep 2020 04:29:20 -0700 Subject: [PATCH 16/82] Adding basic gas counting to EVM, specifically for withdrawal receipts to pass check balance --- Cargo.lock | 1 + runtime/near-evm-runner/Cargo.toml | 22 +-- runtime/near-evm-runner/src/lib.rs | 147 +++++++++++++++--- runtime/near-evm-runner/src/types.rs | 9 +- runtime/near-evm-runner/src/utils.rs | 4 +- runtime/near-evm-runner/tests/failures.rs | 11 +- runtime/near-evm-runner/tests/standard_ops.rs | 92 ++++++----- runtime/near-evm-runner/tests/utils.rs | 36 +++++ runtime/near-vm-logic/src/lib.rs | 2 +- runtime/runtime/src/actions.rs | 6 +- runtime/runtime/src/state_viewer.rs | 12 +- test-utils/testlib/src/standard_test_cases.rs | 44 +++++- 12 files changed, 290 insertions(+), 96 deletions(-) create mode 100644 runtime/near-evm-runner/tests/utils.rs diff --git a/Cargo.lock b/Cargo.lock index cc574e53a99..63b962150b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2857,6 +2857,7 @@ dependencies = [ "lazy-static-include", "lazy_static", "libsecp256k1", + "near-runtime-fees", "near-vm-errors", "near-vm-logic", "num-bigint 0.3.0", diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index ee3f90eeace..6349fc8f723 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -8,26 +8,30 @@ repository = "https://github.com/nearprotocol/nearcore" homepage = "https://github.com/nearprotocol/nearcore" [dependencies] -evm = { git = "https://github.com/paritytech/parity-ethereum", rev = "eed630a002bbebed3a3097127f2483213ff52079" } -vm = { git = "https://github.com/paritytech/parity-ethereum", rev = "eed630a002bbebed3a3097127f2483213ff52079" } -bn = { git = "https://github.com/paritytech/bn", default-features = false } -parity-bytes = "0.1.0" -ethereum-types = "0.6.0" -keccak-hash = "0.2.0" borsh = "0.7.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1" -sha2 = "0.8" -sha3 = "0.8" -rlp = "0.4.2" hex = "0.4" byteorder = "1.0" num-bigint = { version = "0.3", default-features = false } num-traits = "0.2.12" + +sha2 = "0.8" +sha3 = "0.8" +rlp = "0.4.2" +keccak-hash = "0.2.0" ripemd160 = "0.9.0" libsecp256k1 = "0.3.5" + +evm = { git = "https://github.com/paritytech/parity-ethereum", rev = "eed630a002bbebed3a3097127f2483213ff52079" } +vm = { git = "https://github.com/paritytech/parity-ethereum", rev = "eed630a002bbebed3a3097127f2483213ff52079" } +bn = { git = "https://github.com/paritytech/bn", default-features = false } +parity-bytes = "0.1.0" +ethereum-types = "0.6.0" + near-vm-logic = { path = "../near-vm-logic" } near-vm-errors = { path = "../near-vm-errors" } +near-runtime-fees = { path = "../near-runtime-fees", version = "2.1.0" } [dev-dependencies] ethabi = "8.0.0" diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index a82d1bc10c3..3fde4c1cc94 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -2,9 +2,11 @@ use borsh::{BorshDeserialize, BorshSerialize}; use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; +use near_runtime_fees::RuntimeFeesConfig; use near_vm_errors::{EvmError, FunctionCallError, VMError}; -use near_vm_logic::types::{AccountId, Balance, ReturnData, StorageUsage}; -use near_vm_logic::{External, VMLogicError, VMOutcome}; +use near_vm_logic::gas_counter::GasCounter; +use near_vm_logic::types::{AccountId, Balance, Gas, ReturnData, StorageUsage}; +use near_vm_logic::{ActionCosts, External, VMConfig, VMLogicError, VMOutcome}; use crate::evm_state::{EvmAccount, EvmState, StateStore}; use crate::types::{AddressArg, GetStorageAtArgs, Result, TransferArgs, WithdrawArgs}; @@ -19,9 +21,12 @@ pub mod utils; pub struct EvmContext<'a> { ext: &'a mut dyn External, predecessor_id: AccountId, + current_amount: Balance, attached_deposit: Balance, storage_usage: StorageUsage, logs: Vec, + gas_counter: GasCounter, + fees_config: &'a RuntimeFeesConfig, } enum KeyPrefix { @@ -98,11 +103,36 @@ impl<'a> EvmState for EvmContext<'a> { impl<'a> EvmContext<'a> { pub fn new( ext: &'a mut dyn External, + config: &'a VMConfig, + fees_config: &'a RuntimeFeesConfig, + current_amount: Balance, predecessor_id: AccountId, attached_deposit: Balance, storage_usage: StorageUsage, + prepaid_gas: Gas, + is_view: bool, ) -> Self { - Self { ext, predecessor_id, attached_deposit, storage_usage, logs: Vec::default() } + let max_gas_burnt = if is_view { + config.limit_config.max_gas_burnt_view + } else { + config.limit_config.max_gas_burnt + }; + Self { + ext, + predecessor_id, + current_amount, + attached_deposit, + storage_usage, + logs: Vec::default(), + gas_counter: GasCounter::new( + config.ext_costs.clone(), + max_gas_burnt, + prepaid_gas, + is_view, + None, + ), + fees_config, + } } pub fn deploy_code(&mut self, bytecode: Vec) -> Result
{ @@ -178,10 +208,12 @@ impl<'a> EvmContext<'a> { } pub fn deposit(&mut self, args: Vec) -> Result { + let args = AddressArg::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; if self.attached_deposit == 0 { return Err(VMLogicError::EvmError(EvmError::MissingDeposit)); } - let address = Address::from_slice(&args); + let address = Address::from_slice(&args.address); self.add_balance(&address, U256::from(self.attached_deposit))?; self.balance_of(&address) } @@ -196,7 +228,20 @@ impl<'a> EvmContext<'a> { } self.sub_balance(&sender, amount)?; let receipt_index = self.ext.create_receipt(vec![], args.account_id)?; - self.ext.append_action_transfer(receipt_index, args.amount).map_err(|err| err.into()) + // We use low_u128, because NEAR native currency fits into u128. + let amount = amount.low_u128(); + self.current_amount = self + .current_amount + .checked_sub(amount) + .ok_or_else(|| VMLogicError::EvmError(EvmError::InsufficientFunds))?; + self.pay_gas_for_new_receipt(false, &[])?; + self.gas_counter.pay_action_base( + &self.fees_config.action_creation_config.transfer_cost, + // TOOD: Hm, what if they withdraw to itself? We should probably close circuit that here. + false, + ActionCosts::transfer, + )?; + self.ext.append_action_transfer(receipt_index, amount).map_err(|err| err.into()) } /// Transfer tokens from sender to given EVM address. @@ -208,47 +253,93 @@ impl<'a> EvmContext<'a> { if amount > self.balance_of(&sender)? { return Err(VMLogicError::EvmError(EvmError::InsufficientFunds)); } - self.transfer_balance(&sender, &Address::from(args.account_id), amount) + self.transfer_balance(&sender, &Address::from(args.address), amount) + } + + /// A helper function to pay gas fee for creating a new receipt without actions. + /// # Args: + /// * `sir`: whether contract call is addressed to itself; + /// * `data_dependencies`: other contracts that this execution will be waiting on (or rather + /// their data receipts), where bool indicates whether this is sender=receiver communication. + /// + /// # Cost + /// + /// This is a convenience function that encapsulates several costs: + /// `burnt_gas := dispatch cost of the receipt + base dispatch cost cost of the data receipt` + /// `used_gas := burnt_gas + exec cost of the receipt + base exec cost cost of the data receipt` + /// Notice that we prepay all base cost upon the creation of the data dependency, we are going to + /// pay for the content transmitted through the dependency upon the actual creation of the + /// DataReceipt. + fn pay_gas_for_new_receipt(&mut self, sir: bool, data_dependencies: &[bool]) -> Result<()> { + let fees_config_cfg = &self.fees_config; + let mut burn_gas = fees_config_cfg.action_receipt_creation_config.send_fee(sir); + let mut use_gas = fees_config_cfg.action_receipt_creation_config.exec_fee(); + for dep in data_dependencies { + // Both creation and execution for data receipts are considered burnt gas. + burn_gas = burn_gas + .checked_add(fees_config_cfg.data_receipt_creation_config.base_cost.send_fee(*dep)) + .ok_or(VMLogicError::EvmError(EvmError::IntegerOverflow))? + .checked_add(fees_config_cfg.data_receipt_creation_config.base_cost.exec_fee()) + .ok_or(VMLogicError::EvmError(EvmError::IntegerOverflow))?; + } + use_gas = use_gas + .checked_add(burn_gas) + .ok_or(VMLogicError::EvmError(EvmError::IntegerOverflow))?; + self.gas_counter.pay_action_accumulated(burn_gas, use_gas, ActionCosts::new_receipt) } } pub fn run_evm( ext: &mut dyn External, + config: &VMConfig, + fees_config: &RuntimeFeesConfig, predecessor_id: &AccountId, amount: Balance, attached_deposit: Balance, storage_usage: StorageUsage, method_name: String, args: Vec, + prepaid_gas: Gas, + is_view: bool, ) -> (Option, Option) { - let mut context = EvmContext::new(ext, predecessor_id.clone(), attached_deposit, storage_usage); + let mut context = EvmContext::new( + ext, + config, + fees_config, + // This is total amount of all $NEAR inside this EVM. + // Should already validate that will not overflow external to this call. + amount.checked_add(attached_deposit).unwrap_or(amount), + predecessor_id.clone(), + attached_deposit, + storage_usage, + prepaid_gas, + is_view, + ); let result = match method_name.as_str() { // Change the state methods. "deploy_code" => context.deploy_code(args).map(|address| utils::address_to_vec(&address)), "call_function" => context.call_function(args), - "deposit" => context.deposit(args).map(|balance| utils::u256_to_vec(&balance)), + "deposit" => context.deposit(args).map(|balance| utils::u256_to_arr(&balance).to_vec()), "withdraw" => context.withdraw(args).map(|_| vec![]), "transfer" => context.transfer(args).map(|_| vec![]), // View methods. - "view_call_contract" => context.view_call_function(args), + "view_call_function" => context.view_call_function(args), "get_code" => context.get_code(args), "get_storage_at" => context.get_storage_at(args), - "get_nonce" => context.get_nonce(args).map(|nonce| utils::u256_to_vec(&nonce)), - "get_balance" => context.get_balance(args).map(|balance| utils::u256_to_vec(&balance)), + "get_nonce" => context.get_nonce(args).map(|nonce| utils::u256_to_arr(&nonce).to_vec()), + "get_balance" => { + context.get_balance(args).map(|balance| utils::u256_to_arr(&balance).to_vec()) + } _ => Err(VMLogicError::EvmError(EvmError::MethodNotFound)), }; match result { Ok(value) => { let outcome = VMOutcome { - // This is total amount of all $NEAR inside this EVM. - // Outcome balance is equal to amount with attached deposit, because all the accounting happens internally. - // Should already validate that will not overflow external to this call. - balance: amount.checked_add(attached_deposit).unwrap_or(amount), + balance: context.current_amount, storage_usage: context.storage_usage, return_data: ReturnData::Value(value), - // TODO: calculate how much gas was used. - burnt_gas: 0, - used_gas: 0, + burnt_gas: context.gas_counter.burnt_gas(), + used_gas: context.gas_counter.used_gas(), logs: context.logs, }; (Some(outcome), None) @@ -268,10 +359,26 @@ mod tests { use super::*; + fn setup() -> (MockedExternal, VMConfig, RuntimeFeesConfig) { + let vm_config = VMConfig::default(); + let fees_config = RuntimeFeesConfig::default(); + let fake_external = MockedExternal::new(); + (fake_external, vm_config, fees_config) + } + + fn create_context<'a>( + external: &'a mut MockedExternal, + vm_config: &'a VMConfig, + fees_config: &'a RuntimeFeesConfig, + account_id: &str, + ) -> EvmContext<'a> { + EvmContext::new(external, vm_config, fees_config, 0, account_id.to_string(), 0, 0, 0, false) + } + #[test] fn state_management() { - let mut fake_external = MockedExternal::new(); - let mut context = EvmContext::new(&mut fake_external, "alice".to_string(), 0); + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, "alice"); let addr_0 = Address::repeat_byte(0); let addr_1 = Address::repeat_byte(1); let addr_2 = Address::repeat_byte(2); diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index 61214a04504..6ef45f5861b 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -1,10 +1,11 @@ use borsh::{BorshDeserialize, BorshSerialize}; use near_vm_errors::VMLogicError; -use near_vm_logic::types::{AccountId, Balance}; +use near_vm_logic::types::AccountId; pub type RawAddress = [u8; 20]; pub type RawHash = [u8; 32]; +pub type RawU256 = [u8; 32]; pub type Result = std::result::Result; @@ -22,11 +23,11 @@ pub struct GetStorageAtArgs { #[derive(BorshSerialize, BorshDeserialize)] pub struct WithdrawArgs { pub account_id: AccountId, - pub amount: Balance, + pub amount: RawU256, } #[derive(BorshSerialize, BorshDeserialize)] pub struct TransferArgs { - pub account_id: RawAddress, - pub amount: Balance, + pub address: RawAddress, + pub amount: RawU256, } diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index af072a32884..611da6d6ffe 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -59,10 +59,10 @@ pub fn u256_to_balance(val: &U256) -> Balance { Balance::from_be_bytes(bin) } -pub fn u256_to_vec(val: &U256) -> Vec { +pub fn u256_to_arr(val: &U256) -> [u8; 32] { let mut result = [0u8; 32]; val.to_big_endian(&mut result); - result.to_vec() + result } pub fn address_to_vec(val: &Address) -> Vec { diff --git a/runtime/near-evm-runner/tests/failures.rs b/runtime/near-evm-runner/tests/failures.rs index 8511f0243b2..b86ffa8baf4 100644 --- a/runtime/near-evm-runner/tests/failures.rs +++ b/runtime/near-evm-runner/tests/failures.rs @@ -1,15 +1,12 @@ -use near_evm_runner::EvmContext; -use near_vm_logic::mocks::mock_external::MockedExternal; +use crate::utils::{accounts, create_context, setup}; -fn accounts(num: usize) -> String { - ["evm", "alice"][num].to_string() -} +mod utils; /// Test various invalid inputs to function calls. #[test] fn test_invalid_input() { - let mut fake_external = MockedExternal::new(); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 10); assert!(context.get_nonce(vec![]).is_err()); assert!(context.get_balance(vec![]).is_err()); assert!(context.get_code(vec![]).is_err()); diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 84c056a7844..10f36214f22 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -8,10 +8,16 @@ use ethereum_types::{Address, H256, U256}; use near_evm_runner::types::{TransferArgs, WithdrawArgs}; use near_evm_runner::utils::{ address_from_arr, address_to_vec, encode_call_function_args, near_account_id_to_evm_address, + u256_to_arr, }; -use near_evm_runner::EvmContext; +use near_runtime_fees::RuntimeFeesConfig; use near_vm_errors::{EvmError, VMLogicError}; use near_vm_logic::mocks::mock_external::MockedExternal; +use near_vm_logic::VMConfig; + +use crate::utils::{accounts, create_context, setup}; + +mod utils; use_contract!(soltest, "tests/build/SolTests.abi"); use_contract!(subcontract, "tests/build/SubContract.abi"); @@ -23,38 +29,42 @@ lazy_static_include_str!(FACTORY_TEST, "tests/build/Create2Factory.bin"); lazy_static_include_str!(DESTRUCT_TEST, "tests/build/SelfDestruct.bin"); lazy_static_include_str!(CONSTRUCTOR_TEST, "tests/build/ConstructorRevert.bin"); -fn accounts(account_id: usize) -> String { - vec!["evm", "alice", "bob", "chad"][account_id].to_string() -} - #[test] fn test_funds_transfers() { - let mut fake_external = MockedExternal::new(); - let context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); + let (mut fake_external, vm_config, fees_config) = setup(); + let context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); assert_eq!( context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), U256::from(0) ); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); assert_eq!( context.deposit(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), U256::from(100) ); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); context .transfer( - TransferArgs { account_id: near_account_id_to_evm_address(&accounts(2)).0, amount: 50 } - .try_to_vec() - .unwrap(), + TransferArgs { + address: near_account_id_to_evm_address(&accounts(2)).0, + amount: u256_to_arr(&U256::from(50)), + } + .try_to_vec() + .unwrap(), ) .unwrap(); assert_eq!( context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))).unwrap(), U256::from(50) ); - let mut context = EvmContext::new(&mut fake_external, accounts(2), 0, 0); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(2), 0); context - .withdraw(WithdrawArgs { account_id: accounts(2), amount: 50 }.try_to_vec().unwrap()) + .withdraw( + WithdrawArgs { account_id: accounts(2), amount: u256_to_arr(&U256::from(50)) } + .try_to_vec() + .unwrap(), + ) .unwrap(); assert_eq!( context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))).unwrap(), @@ -64,8 +74,8 @@ fn test_funds_transfers() { #[test] fn test_deploy_with_nonce() { - let mut fake_external = MockedExternal::new(); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); let address = near_account_id_to_evm_address(&accounts(1)); assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(0)); let address1 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); @@ -77,8 +87,8 @@ fn test_deploy_with_nonce() { #[test] fn test_failed_deploy_returns_error() { - let mut fake_external = MockedExternal::new(); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); if let Err(VMLogicError::EvmError(EvmError::DeployFail(_))) = context.deploy_code(hex::decode(&CONSTRUCTOR_TEST).unwrap()) { @@ -89,8 +99,8 @@ fn test_failed_deploy_returns_error() { #[test] fn test_internal_create() { - let mut fake_external = MockedExternal::new(); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); @@ -108,8 +118,9 @@ fn test_internal_create() { #[test] fn test_precompiles() { - let mut fake_external = MockedExternal::new(); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); let (input, _) = soltest::functions::precompile_test::call(); @@ -117,22 +128,24 @@ fn test_precompiles() { assert_eq!(raw.len(), 0); } -fn setup_and_deploy_test() -> (MockedExternal, Address) { - let mut fake_external = MockedExternal::new(); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); +fn setup_and_deploy_test() -> (MockedExternal, Address, VMConfig, RuntimeFeesConfig) { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); - (fake_external, test_addr) + (fake_external, test_addr, vm_config, fees_config) } #[test] fn test_deploy_and_transfer() { - let (mut fake_external, test_addr) = setup_and_deploy_test(); + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); // This should increment the nonce of the deploying contract. // There is 100 attached to this that should be passed through. let (input, _) = soltest::functions::deploy_new_guy::call(8); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); // The sub_addr should have been transferred 100 yoctoN. @@ -143,12 +156,13 @@ fn test_deploy_and_transfer() { #[test] fn test_deploy_with_value() { - let (mut fake_external, test_addr) = setup_and_deploy_test(); + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); // This should increment the nonce of the deploying contract // There is 100 attached to this that should be passed through let (input, _) = soltest::functions::pay_new_guy::call(8); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); // The sub_addr should have been transferred 100 tokens. @@ -159,10 +173,11 @@ fn test_deploy_with_value() { #[test] fn test_contract_to_eoa_transfer() { - let (mut fake_external, test_addr) = setup_and_deploy_test(); + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); let (input, _) = soltest::functions::return_some_funds::call(); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); let sender_addr = raw[12..32].to_vec(); @@ -172,8 +187,8 @@ fn test_contract_to_eoa_transfer() { #[test] fn test_get_code() { - let (mut fake_external, test_addr) = setup_and_deploy_test(); - let context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + let context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); assert!(context.get_code(test_addr.0.to_vec()).unwrap().len() > 1500); // contract code should roughly be over length 1500 assert_eq!(context.get_code(vec![0u8; 20]).unwrap().len(), 0); @@ -181,12 +196,12 @@ fn test_get_code() { #[test] fn test_view_call() { - let (mut fake_external, test_addr) = setup_and_deploy_test(); + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); // This should NOT increment the nonce of the deploying contract // And NO CODE should be deployed let (input, _) = soltest::functions::deploy_new_guy::call(8); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 0, 0); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); let raw = context.view_call_function(encode_call_function_args(test_addr, input)).unwrap(); assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); @@ -196,8 +211,9 @@ fn test_view_call() { #[test] fn test_solidity_accurate_storage_on_selfdestruct() { - let mut fake_external = MockedExternal::new(); - let mut context = EvmContext::new(&mut fake_external, accounts(1), 100, 0); + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); assert_eq!( context.deposit(near_account_id_to_evm_address(&accounts(1)).0.to_vec()).unwrap(), U256::from(100) diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs new file mode 100644 index 00000000000..c937363c949 --- /dev/null +++ b/runtime/near-evm-runner/tests/utils.rs @@ -0,0 +1,36 @@ +use near_evm_runner::EvmContext; +use near_runtime_fees::RuntimeFeesConfig; +use near_vm_logic::mocks::mock_external::MockedExternal; +use near_vm_logic::types::Balance; +use near_vm_logic::VMConfig; + +pub fn accounts(num: usize) -> String { + ["evm", "alice", "bob", "chad"][num].to_string() +} + +pub fn setup() -> (MockedExternal, VMConfig, RuntimeFeesConfig) { + let vm_config = VMConfig::default(); + let fees_config = RuntimeFeesConfig::default(); + let fake_external = MockedExternal::new(); + (fake_external, vm_config, fees_config) +} + +pub fn create_context<'a>( + external: &'a mut MockedExternal, + vm_config: &'a VMConfig, + fees_config: &'a RuntimeFeesConfig, + account_id: String, + attached_deposit: Balance, +) -> EvmContext<'a> { + EvmContext::new( + external, + vm_config, + fees_config, + 1000, + account_id.to_string(), + attached_deposit, + 0, + 10u64.pow(14), + false, + ) +} diff --git a/runtime/near-vm-logic/src/lib.rs b/runtime/near-vm-logic/src/lib.rs index 113afd33075..e76c348a03d 100644 --- a/runtime/near-vm-logic/src/lib.rs +++ b/runtime/near-vm-logic/src/lib.rs @@ -1,7 +1,7 @@ mod config; mod context; mod dependencies; -mod gas_counter; +pub mod gas_counter; mod logic; pub mod mocks; pub mod serde_with; diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index c4c7bc47b22..4677e383a0c 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -54,12 +54,16 @@ pub(crate) fn execute_function_call( if account.code_hash == *EVM_CODE_HASH { near_evm_runner::run_evm( runtime_ext, + &config.wasm_config, + &config.transaction_costs, predecessor_id, account.amount, function_call.deposit, account.storage_usage, function_call.method_name.clone(), function_call.args.clone(), + function_call.gas, + is_view, ) } else { let code = match runtime_ext.get_code(account.code_hash) { @@ -204,7 +208,7 @@ pub(crate) fn action_function_call( account.amount = outcome.balance; account.storage_usage = outcome.storage_usage; result.result = Ok(outcome.return_data); - result.new_receipts.extend(runtime_ext.into_receipts(&receipt.predecessor_id)); + result.new_receipts.extend(runtime_ext.into_receipts(account_id)); } } else { assert!(!execution_succeeded, "Outcome should always be available if execution succeeded") diff --git a/runtime/runtime/src/state_viewer.rs b/runtime/runtime/src/state_viewer.rs index 24dd6e0c4bc..9f3d619f25b 100644 --- a/runtime/runtime/src/state_viewer.rs +++ b/runtime/runtime/src/state_viewer.rs @@ -163,17 +163,7 @@ impl TrieViewer { true, true, ); - // near_vm_runner::run( - // code.hash.as_ref().to_vec(), - // &code.code, - // method_name.as_bytes(), - // &mut runtime_ext, - // context, - // &VMConfig::default(), - // &RuntimeFeesConfig::default(), - // &[], - // ) - // }; + let elapsed = now.elapsed(); let time_ms = (elapsed.as_secs() as f64 / 1_000.0) + f64::from(elapsed.subsec_nanos()) / 1_000_000.0; diff --git a/test-utils/testlib/src/standard_test_cases.rs b/test-utils/testlib/src/standard_test_cases.rs index 8174b150ce5..ffe11a10a96 100644 --- a/test-utils/testlib/src/standard_test_cases.rs +++ b/test-utils/testlib/src/standard_test_cases.rs @@ -1,10 +1,12 @@ use std::sync::Arc; +use borsh::BorshSerialize; use ethabi_contract::use_contract; +use ethereum_types::U256; use assert_matches::assert_matches; -use ethereum_types::U256; use near_crypto::{InMemorySigner, KeyType}; +use near_evm_runner::types::WithdrawArgs; use near_jsonrpc::ServerError; use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermission}; use near_primitives::errors::{ @@ -22,6 +24,7 @@ use crate::fees_utils::FeeHelper; use crate::node::Node; use crate::runtime_utils::{alice_account, bob_account, eve_dot_alice_account}; use crate::user::User; +use near_evm_runner::utils::near_account_id_to_evm_address; /// The amount to send with function call. const FUNCTION_CALL_AMOUNT: Balance = TESTING_INIT_BALANCE / 10; @@ -1311,7 +1314,7 @@ pub fn test_evm_deploy_call(node: impl Node) { .function_call( alice_account(), evm_account(), - "view_call_contract", + "view_call_function", args.clone(), 10u64.pow(14), 0, @@ -1323,11 +1326,46 @@ pub fn test_evm_deploy_call(node: impl Node) { let res = cryptozombies::functions::get_zombies_by_owner::decode_output(&bytes).unwrap(); assert_eq!(res, vec![U256::from(0)]); - let result = node_user.view_call(&evm_account(), "view_call_contract", &args).unwrap(); + let result = node_user.view_call(&evm_account(), "view_call_function", &args).unwrap(); let res = cryptozombies::functions::get_zombies_by_owner::decode_output(&result.result).unwrap(); assert_eq!(res, vec![U256::from(0)]); let result = node_user.view_call(&evm_account(), "get_balance", &contract_id).unwrap(); assert_eq!(U256::from_big_endian(&result.result), U256::from(10)); + + let alice_address = near_account_id_to_evm_address(&alice_account()).0; + assert!(node_user + .function_call( + alice_account(), + evm_account(), + "deposit", + alice_address.to_vec(), + 10u64.pow(14), + 1000, + ) + .unwrap() + .status + .as_success() + .is_some()); + + let result = node_user.view_call(&evm_account(), "get_balance", &alice_address).unwrap(); + assert_eq!(U256::from_big_endian(&result.result), U256::from(1000)); + + let result = node_user + .function_call( + alice_account(), + evm_account(), + "withdraw", + WithdrawArgs { account_id: alice_account(), amount: U256::from(10).into() } + .try_to_vec() + .unwrap(), + 10u64.pow(14), + 0, + ) + .unwrap() + .status + .as_success_decoded() + .unwrap(); + assert_eq!(result.len(), 0); } From b8a1b3e81aeae8abd22878a3ffe78e6cac7254ac Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sat, 5 Sep 2020 12:12:30 -0700 Subject: [PATCH 17/82] Addressing issues from running real contracts: events, view calls, removing double hex revert --- runtime/near-evm-runner/src/interpreter.rs | 8 ++- runtime/near-evm-runner/src/lib.rs | 28 ++++++--- runtime/near-evm-runner/src/near_ext.rs | 29 +++++---- runtime/near-evm-runner/src/types.rs | 62 +++++++++++++++++++ runtime/near-evm-runner/src/utils.rs | 27 ++++++++ .../tests/contracts/SolTests.sol | 6 ++ runtime/near-evm-runner/tests/standard_ops.rs | 14 ++++- runtime/near-vm-errors/src/lib.rs | 14 +++-- 8 files changed, 155 insertions(+), 33 deletions(-) diff --git a/runtime/near-evm-runner/src/interpreter.rs b/runtime/near-evm-runner/src/interpreter.rs index 330c48a6dea..5431fff3e0d 100644 --- a/runtime/near-evm-runner/src/interpreter.rs +++ b/runtime/near-evm-runner/src/interpreter.rs @@ -30,7 +30,7 @@ pub fn deploy_code( if recreate { state.recreate(address.0); } else if state.code_at(&address)?.is_some() { - return Err(VMLogicError::EvmError(EvmError::DuplicateContract(address.0))); + return Err(VMLogicError::EvmError(EvmError::DuplicateContract(hex::encode(address.0)))); } let (result, state_updates) = @@ -49,7 +49,9 @@ pub fn deploy_code( state.commit_changes(&state_updates.unwrap())?; state.set_code(&address, &return_data.to_vec())?; } else { - return Err(VMLogicError::EvmError(EvmError::DeployFail(return_data.to_vec()))); + return Err(VMLogicError::EvmError(EvmError::DeployFail(hex::encode( + return_data.to_vec(), + )))); } Ok(address) } @@ -203,7 +205,7 @@ fn run_and_commit_if_success( Some(GasLeft::Known(_)) => Ok(ReturnData::empty()), Some(GasLeft::NeedsReturn { gas_left: _, data, apply_state: true }) => Ok(data), Some(GasLeft::NeedsReturn { gas_left: _, data, apply_state: false }) => { - Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) + Err(VMLogicError::EvmError(EvmError::Revert(hex::encode(data.to_vec())))) } _ => Err(VMLogicError::EvmError(EvmError::UnknownError)), }; diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 3fde4c1cc94..7a86349a281 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -9,7 +9,9 @@ use near_vm_logic::types::{AccountId, Balance, Gas, ReturnData, StorageUsage}; use near_vm_logic::{ActionCosts, External, VMConfig, VMLogicError, VMOutcome}; use crate::evm_state::{EvmAccount, EvmState, StateStore}; -use crate::types::{AddressArg, GetStorageAtArgs, Result, TransferArgs, WithdrawArgs}; +use crate::types::{ + AddressArg, GetStorageAtArgs, Result, TransferArgs, ViewCallArgs, WithdrawArgs, +}; mod builtins; mod evm_state; @@ -24,7 +26,7 @@ pub struct EvmContext<'a> { current_amount: Balance, attached_deposit: Balance, storage_usage: StorageUsage, - logs: Vec, + pub logs: Vec, gas_counter: GasCounter, fees_config: &'a RuntimeFeesConfig, } @@ -170,14 +172,20 @@ impl<'a> EvmContext<'a> { /// /// This function serves the eth_call functionality, and will NOT apply state changes. pub fn view_call_function(&mut self, args: Vec) -> Result> { - if args.len() <= 20 { - return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); - } - let contract_address = Address::from_slice(&args[..20]); - let input = &args[20..]; - let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); - interpreter::call(self, &sender, &sender, None, 0, &contract_address, &input, false) - .map(|rd| rd.to_vec()) + let args = ViewCallArgs::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + let sender = Address::from(&args.sender); + interpreter::call( + self, + &sender, + &sender, + Some(U256::from(args.amount)), + 0, + &Address::from(&args.address), + &args.args, + false, + ) + .map(|rd| rd.to_vec()) } pub fn get_code(&self, args: Vec) -> Result> { diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 6d93dfa0bf7..4475d525b7f 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use ethereum_types::{Address, H160, H256, U256}; +use evm::ActionParams; use keccak_hash::keccak; use parity_bytes::Bytes; use vm::{ @@ -8,9 +9,11 @@ use vm::{ MessageCallResult, Result as EvmResult, ReturnData, Schedule, TrapKind, }; +use near_vm_errors::{EvmError, VMLogicError}; + use crate::evm_state::{EvmState, SubState}; use crate::interpreter; -use evm::ActionParams; +use crate::utils::format_log; // https://github.com/paritytech/parity-ethereum/blob/77643c13e80ca09d9a6b10631034f5a1568ba6d3/ethcore/machine/src/externalities.rs // #[derive(Debug)] @@ -213,7 +216,12 @@ impl<'a> vm::Ext for NearExt<'a> { let msg_call_result = match result { Ok(data) => MessageCallResult::Success(1_000_000_000.into(), data), Err(err) => { - let message = format!("{:?}", err).as_bytes().to_vec(); + let message = match err { + VMLogicError::EvmError(EvmError::Revert(encoded_message)) => { + hex::decode(encoded_message).unwrap_or(vec![]) + } + _ => format!("{:?}", err).as_bytes().to_vec(), + }; let message_len = message.len(); MessageCallResult::Reverted( 1_000_000_000.into(), @@ -250,18 +258,17 @@ impl<'a> vm::Ext for NearExt<'a> { } /// Creates log entry with given topics and data - fn log(&mut self, _topics: Vec, data: &[u8]) -> EvmResult<()> { + fn log(&mut self, topics: Vec, data: &[u8]) -> EvmResult<()> { if self.is_static() { return Err(VmError::MutableCallInStaticContext); } - - // TODO: Develop a NearCall logspec - // hijack NearCall logs here - // make a Vec that accumulates committed logs - // return them after execution completes - // dispatch promises - - self.sub_state.state.logs.push(hex::encode(data)); + if topics.len() > 256 { + return Err(VmError::Internal("Too many topics".to_string())); + } + self.sub_state.state.logs.push(hex::encode( + format_log(topics, data) + .map_err(|err| VmError::Internal(format!("Failed to format event: {}", err)))?, + )); Ok(()) } diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index 6ef45f5861b..1c34b90a405 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -2,6 +2,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use near_vm_errors::VMLogicError; use near_vm_logic::types::AccountId; +use std::io::{Read, Write}; pub type RawAddress = [u8; 20]; pub type RawHash = [u8; 32]; @@ -14,6 +15,14 @@ pub struct AddressArg { pub address: RawAddress, } +#[derive(Debug, Eq, PartialEq)] +pub struct ViewCallArgs { + pub sender: RawAddress, + pub address: RawAddress, + pub amount: RawU256, + pub args: Vec, +} + #[derive(BorshSerialize, BorshDeserialize)] pub struct GetStorageAtArgs { pub address: RawAddress, @@ -31,3 +40,56 @@ pub struct TransferArgs { pub address: RawAddress, pub amount: RawU256, } + +impl BorshSerialize for ViewCallArgs { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + writer.write(&self.sender)?; + writer.write(&self.address)?; + writer.write(&self.amount)?; + writer.write(&self.args)?; + Ok(()) + } +} + +impl BorshDeserialize for ViewCallArgs { + fn deserialize(buf: &mut &[u8]) -> std::io::Result { + if buf.len() < 72 { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Unexpected length of input", + )); + } + let sender = RawAddress::deserialize(buf)?; + let address = RawAddress::deserialize(buf)?; + let amount = RawU256::deserialize(buf)?; + let mut args = Vec::new(); + buf.read_to_end(&mut args)?; + Ok(Self { sender, address, amount, args }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_roundtrip_view_call() { + let x = ViewCallArgs { + sender: [1; 20], + address: [2; 20], + amount: [3; 32], + args: vec![1, 2, 3], + }; + let bytes = x.try_to_vec().unwrap(); + let res = ViewCallArgs::try_from_slice(&bytes).unwrap(); + assert_eq!(x, res); + let res = ViewCallArgs::try_from_slice(&[0; 72]).unwrap(); + assert_eq!(res.args.len(), 0); + } + + #[test] + fn test_view_call_fail() { + let bytes = [0; 71]; + let res = ViewCallArgs::try_from_slice(&bytes).unwrap_err(); + } +} diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index 611da6d6ffe..ffd9226068f 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -1,3 +1,6 @@ +use std::io::Write; + +use byteorder::WriteBytesExt; use ethereum_types::{Address, H256, U256}; use keccak_hash::keccak; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -38,6 +41,20 @@ pub fn encode_call_function_args(address: Address, input: Vec) -> Vec { result } +pub fn encode_view_call_function_args( + sender: Address, + address: Address, + amount: U256, + input: Vec, +) -> Vec { + let mut result = Vec::with_capacity(72 + input.len()); + result.extend_from_slice(&sender.0); + result.extend_from_slice(&address.0); + result.extend_from_slice(&u256_to_arr(&amount)); + result.extend_from_slice(&input); + result +} + pub fn address_from_arr(arr: &[u8]) -> Address { assert_eq!(arr.len(), 20); let mut address = [0u8; 20]; @@ -149,3 +166,13 @@ impl From for u128 { balance.0 } } + +pub fn format_log(topics: Vec, data: &[u8]) -> Result, std::io::Error> { + let mut result = Vec::with_capacity(1 + topics.len() * 32 + data.len()); + result.write_u8(topics.len() as u8)?; + for topic in topics.iter() { + result.write(&topic.0)?; + } + result.write(data)?; + Ok(result) +} diff --git a/runtime/near-evm-runner/tests/contracts/SolTests.sol b/runtime/near-evm-runner/tests/contracts/SolTests.sol index 5a2de01c88f..0e6973c4e46 100644 --- a/runtime/near-evm-runner/tests/contracts/SolTests.sol +++ b/runtime/near-evm-runner/tests/contracts/SolTests.sol @@ -17,11 +17,17 @@ contract SolTests is ExposesBalance { event SomeEvent(uint256 _number); + event DeployEvent( + address indexed _contract, + uint256 _amount + ); + function () external payable {} function deployNewGuy(uint256 _aNumber) public payable returns (address, uint256) { SubContract _newGuy = new SubContract(_aNumber); address(_newGuy).transfer(msg.value); + emit DeployEvent(address(_newGuy), msg.value); return (address(_newGuy), msg.value); } diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 10f36214f22..a741aab9384 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -7,8 +7,8 @@ use ethereum_types::{Address, H256, U256}; use near_evm_runner::types::{TransferArgs, WithdrawArgs}; use near_evm_runner::utils::{ - address_from_arr, address_to_vec, encode_call_function_args, near_account_id_to_evm_address, - u256_to_arr, + address_from_arr, address_to_vec, encode_call_function_args, encode_view_call_function_args, + near_account_id_to_evm_address, u256_to_arr, }; use near_runtime_fees::RuntimeFeesConfig; use near_vm_errors::{EvmError, VMLogicError}; @@ -147,6 +147,7 @@ fn test_deploy_and_transfer() { let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + assert!(context.logs.len() > 0); // The sub_addr should have been transferred 100 yoctoN. let sub_addr = raw[12..32].to_vec(); @@ -202,7 +203,14 @@ fn test_view_call() { // And NO CODE should be deployed let (input, _) = soltest::functions::deploy_new_guy::call(8); let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - let raw = context.view_call_function(encode_call_function_args(test_addr, input)).unwrap(); + let raw = context + .view_call_function(encode_view_call_function_args( + test_addr, + test_addr, + U256::from(0), + input, + )) + .unwrap(); assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); let sub_addr = raw[12..32].to_vec(); diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index f86bb664773..4def95f3cff 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -1,9 +1,11 @@ +use std::fmt; + use borsh::{BorshDeserialize, BorshSerialize}; -use near_rpc_error_macro::RpcError; use serde::export::fmt::Error; use serde::export::Formatter; use serde::{Deserialize, Serialize}; -use std::fmt; + +use near_rpc_error_macro::RpcError; #[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] pub enum VMError { @@ -176,12 +178,12 @@ pub enum HostError { pub enum EvmError { /// Unknown error, catch all for unexpected things. UnknownError, - /// Fatal failure due conflicting addresses on contract deployment. - DuplicateContract([u8; 20]), + /// Fatal failure due conflicting addresses on contract deployment. + DuplicateContract(String), /// Contract deployment failure. - DeployFail(Vec), + DeployFail(String), /// Contract execution failed, revert the state. - Revert(Vec), + Revert(String), /// Failed to parse arguments. ArgumentParseError, /// No deposit when expected. From cc4ec1fee29db42f7b14f79870fd1ddf3c891aca Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 7 Sep 2020 01:58:32 -0700 Subject: [PATCH 18/82] Add built artifacts for Ethereum contracts to simplify testing --- .gitignore | 1 - .../tests/build/ConstructorRevert.abi | 8 + .../tests/build/ConstructorRevert.bin | 1 + .../tests/build/Create2Factory.abi | 59 ++++++ .../tests/build/Create2Factory.bin | 1 + .../tests/build/SelfDestruct.abi | 70 +++++++ .../tests/build/SelfDestruct.bin | 1 + .../near-evm-runner/tests/build/SolTests.abi | 188 ++++++++++++++++++ .../near-evm-runner/tests/build/SolTests.bin | 1 + .../tests/build/SubContract.abi | 90 +++++++++ .../tests/build/SubContract.bin | 1 + .../tests/build/zombieAttack.abi | 1 + .../tests/build/zombieAttack.bin | 1 + 13 files changed, 422 insertions(+), 1 deletion(-) create mode 100644 runtime/near-evm-runner/tests/build/ConstructorRevert.abi create mode 100644 runtime/near-evm-runner/tests/build/ConstructorRevert.bin create mode 100644 runtime/near-evm-runner/tests/build/Create2Factory.abi create mode 100644 runtime/near-evm-runner/tests/build/Create2Factory.bin create mode 100644 runtime/near-evm-runner/tests/build/SelfDestruct.abi create mode 100644 runtime/near-evm-runner/tests/build/SelfDestruct.bin create mode 100644 runtime/near-evm-runner/tests/build/SolTests.abi create mode 100644 runtime/near-evm-runner/tests/build/SolTests.bin create mode 100644 runtime/near-evm-runner/tests/build/SubContract.abi create mode 100644 runtime/near-evm-runner/tests/build/SubContract.bin create mode 100644 runtime/near-evm-runner/tests/build/zombieAttack.abi create mode 100644 runtime/near-evm-runner/tests/build/zombieAttack.bin diff --git a/.gitignore b/.gitignore index d44928dbc9c..c928a1b7bdd 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ docker-build /keystore/ /chain/client/tmp_bench testdir/ -runtime/near-evm-runner/tests/build # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html diff --git a/runtime/near-evm-runner/tests/build/ConstructorRevert.abi b/runtime/near-evm-runner/tests/build/ConstructorRevert.abi new file mode 100644 index 00000000000..924c382d804 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/ConstructorRevert.abi @@ -0,0 +1,8 @@ +[ + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + } +] diff --git a/runtime/near-evm-runner/tests/build/ConstructorRevert.bin b/runtime/near-evm-runner/tests/build/ConstructorRevert.bin new file mode 100644 index 00000000000..eba8500764a --- /dev/null +++ b/runtime/near-evm-runner/tests/build/ConstructorRevert.bin @@ -0,0 +1 @@ +6080604052348015600f57600080fd5b5060056004146086576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f4572726f72204465706c6f79696e6720436f6e7472616374000000000000000081525060200191505060405180910390fd5b603e8060936000396000f3fe6080604052600080fdfea265627a7a723158203667e47f55606e5f72d16e0d9a81ed4435273fcfa1ee79bf9545dc524d930d2f64736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/Create2Factory.abi b/runtime/near-evm-runner/tests/build/Create2Factory.abi new file mode 100644 index 00000000000..0147fe22194 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/Create2Factory.abi @@ -0,0 +1,59 @@ +[ + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "bytes32", + "name": "_salt", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "_contractBytecode", + "type": "bytes" + } + ], + "name": "deploy", + "outputs": [ + { + "internalType": "address payable", + "name": "addr", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "bytes32", + "name": "_salt", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "_contractBytecode", + "type": "bytes" + } + ], + "name": "testDoubleDeploy", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": true, + "stateMutability": "payable", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/Create2Factory.bin b/runtime/near-evm-runner/tests/build/Create2Factory.bin new file mode 100644 index 00000000000..da4baf5279f --- /dev/null +++ b/runtime/near-evm-runner/tests/build/Create2Factory.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50610758806100206000396000f3fe6080604052600436106100295760003560e01c80639f45e8151461002b578063cdcb760a14610108575b005b6100ee6004803603604081101561004157600080fd5b81019080803590602001909291908035906020019064010000000081111561006857600080fd5b82018360208201111561007a57600080fd5b8035906020019184600183028401116401000000008311171561009c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061021a565b604051808215151515815260200191505060405180910390f35b34801561011457600080fd5b506101d86004803603604081101561012b57600080fd5b81019080803590602001909291908035906020019064010000000081111561015257600080fd5b82018360208201111561016457600080fd5b8035906020019184600183028401116401000000008311171561018657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506106c7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60008061022784846106c7565b905060008190508073ffffffffffffffffffffffffffffffffffffffff1663eef4c90f60056040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561028257600080fd5b505af1158015610296573d6000803e3d6000fd5b5050505060058173ffffffffffffffffffffffffffffffffffffffff16636e4d2a346040518163ffffffff1660e01b815260040160206040518083038186803b1580156102e257600080fd5b505afa1580156102f6573d6000803e3d6000fd5b505050506040513d602081101561030c57600080fd5b810190808051906020019092919050505014610390576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f7072652d6465737472756374696f6e2077726f6e672075696e7400000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663d37c6c9e6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156103d857600080fd5b505af11580156103ec573d6000803e3d6000fd5b5050505060606103fb826106db565b90506000815114610474576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f706f73742d6465737472756374696f6e20636f6465206c656e6774680000000081525060200191505060405180910390fd5b61047e86866106c7565b5060008273ffffffffffffffffffffffffffffffffffffffff16636e4d2a346040518163ffffffff1660e01b815260040160206040518083038186803b1580156104c757600080fd5b505afa1580156104db573d6000803e3d6000fd5b505050506040513d60208110156104f157600080fd5b810190808051906020019092919050505014610575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f706f73742d6465737472756374696f6e2077726f6e672075696e74000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663eef4c90f60036040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156105c957600080fd5b505af11580156105dd573d6000803e3d6000fd5b5050505060038273ffffffffffffffffffffffffffffffffffffffff16636e4d2a346040518163ffffffff1660e01b815260040160206040518083038186803b15801561062957600080fd5b505afa15801561063d573d6000803e3d6000fd5b505050506040513d602081101561065357600080fd5b8101908080519060200190929190505050146106ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806107026022913960400191505060405180910390fd5b6001935050505092915050565b6000828251602084016000f5905092915050565b60606040519050813b8082526020820181600082863c818352818101604052505091905056fe706f73742d6465737472756374696f6e2073746f7265642077726f6e672075696e74a265627a7a7231582057b6addf30c31c49aa94429f78664940ffa8f1922153be7c94c853fa4932031c64736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/SelfDestruct.abi b/runtime/near-evm-runner/tests/build/SelfDestruct.abi new file mode 100644 index 00000000000..b9d714edbba --- /dev/null +++ b/runtime/near-evm-runner/tests/build/SelfDestruct.abi @@ -0,0 +1,70 @@ +[ + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "constant": true, + "inputs": [], + "name": "storedAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "storedUint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "storeAddress", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "_number", + "type": "uint256" + } + ], + "name": "storeUint", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "destruction", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/SelfDestruct.bin b/runtime/near-evm-runner/tests/build/SelfDestruct.bin new file mode 100644 index 00000000000..fdf024159ad --- /dev/null +++ b/runtime/near-evm-runner/tests/build/SelfDestruct.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506101fc806100206000396000f3fe60806040526004361061004a5760003560e01c80636e4d2a341461004c5780638f63640e14610077578063d37c6c9e146100ce578063eef4c90f146100e5578063f2c4da9314610120575b005b34801561005857600080fd5b50610061610137565b6040518082815260200191505060405180910390f35b34801561008357600080fd5b5061008c61013d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156100da57600080fd5b506100e3610162565b005b3480156100f157600080fd5b5061011e6004803603602081101561010857600080fd5b810190808035906020019092919050505061017b565b005b34801561012c57600080fd5b50610135610185565b005b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b8060018190555050565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555056fea265627a7a7231582049134aca36ca008aa7d94838f31a297f561997c03ec02dedcb7b63aa26289cd664736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/SolTests.abi b/runtime/near-evm-runner/tests/build/SolTests.abi new file mode 100644 index 00000000000..94ded1f86dd --- /dev/null +++ b/runtime/near-evm-runner/tests/build/SolTests.abi @@ -0,0 +1,188 @@ +[ + { + "inputs": [], + "payable": true, + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_contract", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "DeployEvent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_number", + "type": "uint256" + } + ], + "name": "SomeEvent", + "type": "event" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "constant": true, + "inputs": [], + "name": "balance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "transferTo", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "_aNumber", + "type": "uint256" + } + ], + "name": "deployNewGuy", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "_aNumber", + "type": "uint256" + } + ], + "name": "payNewGuy", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "returnSomeFunds", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "_aNumber", + "type": "uint256" + } + ], + "name": "emitIt", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "precompileTest", + "outputs": [], + "payable": false, + "stateMutability": "pure", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/SolTests.bin b/runtime/near-evm-runner/tests/build/SolTests.bin new file mode 100644 index 00000000000..19949b48a34 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/SolTests.bin @@ -0,0 +1 @@ +6080604052610751806100136000396000f3fe6080604052600436106100705760003560e01c8063299fb0431161004e578063299fb043146101af5780632ccb1b30146101c65780639d9f9a6e14610235578063b69ef8a81461028657610070565b80630a84cba514610072578063111e0b12146100e757806314d54f541461015c575b005b61009e6004803603602081101561008857600080fd5b81019080803590602001909291905050506102b1565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b610113600480360360208110156100fd57600080fd5b8101908080359060200190929190505050610390565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561016857600080fd5b506101956004803603602081101561017f57600080fd5b81019080803590602001909291905050506103dc565b604051808215151515815260200191505060405180910390f35b3480156101bb57600080fd5b506101c461041e565b005b3480156101d257600080fd5b5061021f600480360360408110156101e957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610420565b6040518082815260200191505060405180910390f35b61023d610479565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561029257600080fd5b5061029b6104da565b6040518082815260200191505060405180910390f35b6000806000836040516102c3906104e2565b80828152602001915050604051809103906000f0801580156102e9573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610332573d6000803e3d6000fd5b508073ffffffffffffffffffffffffffffffffffffffff167fa53ffc4fb91f5ca8287e168fc73db3b0b384a6ca275650f885a1740ef7a0bc1c346040518082815260200191505060405180910390a280348191509250925050915091565b600080600034846040516103a3906104e2565b808281526020019150506040518091039082f0801580156103c8573d6000803e3d6000fd5b509050905080348191509250925050915091565b60007f379340f64b65a8890c7ea4f6d86d2359beaf41080f36a7ea64b78a2c06eee3f0826040518082815260200191505060405180910390a160019050919050565b565b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050158015610468573d6000803e3d6000fd5b506104716104da565b905092915050565b6000803373ffffffffffffffffffffffffffffffffffffffff166108fc600234816104a057fe5b049081150290604051600060405180830381858888f193505050501580156104cc573d6000803e3d6000fd5b503334819150915091509091565b600047905090565b61022d806104f08339019056fe6080604052600660005560405161022d38038061022d8339818101604052602081101561002b57600080fd5b810190808051906020019092919050505080600081905550506101da806100536000396000f3fe60806040526004361061003f5760003560e01c80632ccb1b301461004157806339c117a4146100b0578063b69ef8a8146100df578063e6a899b61461010a575b005b34801561004d57600080fd5b5061009a6004803603604081101561006457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610135565b6040518082815260200191505060405180910390f35b3480156100bc57600080fd5b506100c561018e565b604051808215151515815260200191505060405180910390f35b3480156100eb57600080fd5b506100f4610197565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b5061011f61019f565b6040518082815260200191505060405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561017d573d6000803e3d6000fd5b50610186610197565b905092915050565b60006001905090565b600047905090565b6000548156fea265627a7a72315820ea83af7ddb8234e4b841b684510c134b4b7a908fa8f04ffa0bc7a26e95ccc98064736f6c63430005100032a265627a7a72315820380ec69db676ca33c704f78f87c7eb2076dbf6b096c675fae266364c1b0587cc64736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/SubContract.abi b/runtime/near-evm-runner/tests/build/SubContract.abi new file mode 100644 index 00000000000..c3933cb84ba --- /dev/null +++ b/runtime/near-evm-runner/tests/build/SubContract.abi @@ -0,0 +1,90 @@ +[ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_aNumber", + "type": "uint256" + } + ], + "payable": true, + "stateMutability": "payable", + "type": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "constant": true, + "inputs": [], + "name": "aNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "balance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "transferTo", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "aFunction", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/SubContract.bin b/runtime/near-evm-runner/tests/build/SubContract.bin new file mode 100644 index 00000000000..9599d211abc --- /dev/null +++ b/runtime/near-evm-runner/tests/build/SubContract.bin @@ -0,0 +1 @@ +6080604052600660005560405161022d38038061022d8339818101604052602081101561002b57600080fd5b810190808051906020019092919050505080600081905550506101da806100536000396000f3fe60806040526004361061003f5760003560e01c80632ccb1b301461004157806339c117a4146100b0578063b69ef8a8146100df578063e6a899b61461010a575b005b34801561004d57600080fd5b5061009a6004803603604081101561006457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610135565b6040518082815260200191505060405180910390f35b3480156100bc57600080fd5b506100c561018e565b604051808215151515815260200191505060405180910390f35b3480156100eb57600080fd5b506100f4610197565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b5061011f61019f565b6040518082815260200191505060405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561017d573d6000803e3d6000fd5b50610186610197565b905092915050565b60006001905090565b600047905090565b6000548156fea265627a7a72315820ea83af7ddb8234e4b841b684510c134b4b7a908fa8f04ffa0bc7a26e95ccc98064736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/zombieAttack.abi b/runtime/near-evm-runner/tests/build/zombieAttack.abi new file mode 100644 index 00000000000..a0ced0c7c78 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/zombieAttack.abi @@ -0,0 +1 @@ +[{"constant":false,"inputs":[{"name":"_zombieId","type":"uint256"}],"name":"levelUp","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_zombieId","type":"uint256"},{"name":"_kittyId","type":"uint256"}],"name":"feedOnKitty","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"zombies","outputs":[{"name":"name","type":"string"},{"name":"dna","type":"uint256"},{"name":"level","type":"uint32"},{"name":"readyTime","type":"uint32"},{"name":"winCount","type":"uint16"},{"name":"lossCount","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getZombiesByOwner","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"zombieToOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"setKittyContractAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_zombieId","type":"uint256"},{"name":"_newDna","type":"uint256"}],"name":"changeDna","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"}],"name":"createRandomZombie","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_zombieId","type":"uint256"},{"name":"_newName","type":"string"}],"name":"changeName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_fee","type":"uint256"}],"name":"setLevelUpFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_zombieId","type":"uint256"},{"name":"_targetId","type":"uint256"}],"name":"attack","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"zombieId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"dna","type":"uint256"}],"name":"NewZombie","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}] diff --git a/runtime/near-evm-runner/tests/build/zombieAttack.bin b/runtime/near-evm-runner/tests/build/zombieAttack.bin new file mode 100644 index 00000000000..3e21cb25c22 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/zombieAttack.bin @@ -0,0 +1 @@ +60606040526010600155600154600a0a6002556201518060035566038d7ea4c6800060085560006009556046600a55336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506119d28061007d6000396000f3006060604052600436106100d0576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630ce90ec2146100d557806317a7f4cc146100ed5780632052465e146101195780633ccfd60b1461021d5780634412e10414610232578063528b7b8f146102c05780635f4623f1146103235780635faf28801461035c5780637bff0a01146103885780638da5cb5b146103e5578063c39cbef11461043a578063ccf670f814610471578063e1fa763814610494578063f2fde38b146104c0575b600080fd5b6100eb60048080359060200190919050506104f9565b005b34156100f857600080fd5b6101176004808035906020019091908035906020019091905050610565565b005b341561012457600080fd5b61013a60048080359060200190919050506106d2565b60405180806020018781526020018663ffffffff1663ffffffff1681526020018563ffffffff1663ffffffff1681526020018461ffff1661ffff1681526020018361ffff1661ffff1681526020018281038252888181546001816001161561010002031660029004815260200191508054600181600116156101000203166002900480156102095780601f106101de57610100808354040283529160200191610209565b820191906000526020600020905b8154815290600101906020018083116101ec57829003601f168201915b505097505050505050505060405180910390f35b341561022857600080fd5b610230610758565b005b341561023d57600080fd5b610269600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061082d565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156102ac578082015181840152602081019050610291565b505050509050019250505060405180910390f35b34156102cb57600080fd5b6102e1600480803590602001909190505061095b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561032e57600080fd5b61035a600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061098e565b005b341561036757600080fd5b6103866004808035906020019091908035906020019091905050610a2d565b005b341561039357600080fd5b6103e3600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610b0f565b005b34156103f057600080fd5b6103f8610b88565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561044557600080fd5b61046f60048080359060200190919080359060200190820180359060200191909192905050610bad565b005b341561047c57600080fd5b6104926004808035906020019091905050610c9b565b005b341561049f57600080fd5b6104be6004808035906020019091908035906020019091905050610d00565b005b34156104cb57600080fd5b6104f7600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610f93565b005b6008543414151561050957600080fd5b60048181548110151561051857fe5b9060005260206000209060030201600201600081819054906101000a900463ffffffff168092919060010191906101000a81548163ffffffff021916908363ffffffff1602179055505050565b6000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e98b7f4d83600060405161014001526040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018082815260200191505061014060405180830381600087803b151561060257600080fd5b6102c65a03f1151561061357600080fd5b50505060405180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519050909192939495969798509091929394959697509091929394959650909192939495509091929394509091929350909192509091509050809150506106cd83826040805190810160405280600581526020017f6b697474790000000000000000000000000000000000000000000000000000008152506110e8565b505050565b6004818154811015156106e157fe5b906000526020600020906003020160009150905080600001908060010154908060020160009054906101000a900463ffffffff16908060020160049054906101000a900463ffffffff16908060020160089054906101000a900461ffff169080600201600a9054906101000a900461ffff16905086565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156107b357600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050151561082b57600080fd5b565b610835611764565b61083d611764565b600080600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460405180591061088d5750595b9080825280602002602001820160405250925060009150600090505b600480549050811015610950578473ffffffffffffffffffffffffffffffffffffffff166005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156109435780838381518110151561092c57fe5b906020019060200201818152505081806001019250505b80806001019150506108a9565b829350505050919050565b60056020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156109e957600080fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60148281600482815481101515610a4057fe5b906000526020600020906003020160020160009054906101000a900463ffffffff1663ffffffff1610151515610a7557600080fd5b836005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610ae357600080fd5b83600486815481101515610af357fe5b9060005260206000209060030201600101819055505050505050565b600080600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054141515610b5e57600080fd5b610b67826112bd565b9050606481811515610b7557fe5b0681039050610b84828261133f565b5050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60028381600482815481101515610bc057fe5b906000526020600020906003020160020160009054906101000a900463ffffffff1663ffffffff1610151515610bf557600080fd5b846005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610c6357600080fd5b8484600488815481101515610c7457fe5b90600052602060002090600302016000019190610c92929190611778565b50505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610cf657600080fd5b8060088190555050565b6000806000846005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d7357600080fd5b600486815481101515610d8257fe5b90600052602060002090600302019350600485815481101515610da157fe5b90600052602060002090600302019250610dbb606461160e565b9150600a5482111515610ef157610df260018560020160089054906101000a900461ffff1661ffff166116a590919063ffffffff16565b8460020160086101000a81548161ffff021916908361ffff160217905550610e3e60018560020160009054906101000a900463ffffffff1663ffffffff166116cb90919063ffffffff16565b8460020160006101000a81548163ffffffff021916908363ffffffff160217905550610e8a600184600201600a9054906101000a900461ffff1661ffff166116a590919063ffffffff16565b83600201600a6101000a81548161ffff021916908361ffff160217905550610eec8684600101546040805190810160405280600681526020017f7a6f6d62696500000000000000000000000000000000000000000000000000008152506110e8565b610f8b565b610f1b600185600201600a9054906101000a900461ffff1661ffff166116a590919063ffffffff16565b84600201600a6101000a81548161ffff021916908361ffff160217905550610f6360018460020160089054906101000a900461ffff1661ffff166116a590919063ffffffff16565b8360020160086101000a81548161ffff021916908361ffff160217905550610f8a846116f5565b5b505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610fee57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561102a57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600080846005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561115957600080fd5b60048681548110151561116857fe5b906000526020600020906003020192506111818361171f565b151561118c57600080fd5b6002548581151561119957fe5b0694506002858460010154018115156111ae57fe5b04915060405180807f6b697474790000000000000000000000000000000000000000000000000000008152506005019050604051809103902060001916846040518082805190602001908083835b60208310151561122157805182526020820191506020810190506020830392506111fc565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916141561126d57606360648381151561126657fe5b0683030191505b6112ac6040805190810160405280600681526020017f4e6f4e616d6500000000000000000000000000000000000000000000000000008152508361133f565b6112b5836116f5565b505050505050565b600080826040518082805190602001908083835b6020831015156112f657805182526020820191506020810190506020830392506112d1565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206001900490506002548181151561133657fe5b06915050919050565b600060016004805480600101828161135791906117f8565b9160005260206000209060030201600060c060405190810160405280888152602001878152602001600163ffffffff168152602001600354420163ffffffff168152602001600061ffff168152602001600061ffff16815250909190915060008201518160000190805190602001906113d192919061182a565b506020820151816001015560408201518160020160006101000a81548163ffffffff021916908363ffffffff16021790555060608201518160020160046101000a81548163ffffffff021916908363ffffffff16021790555060808201518160020160086101000a81548161ffff021916908361ffff16021790555060a082015181600201600a6101000a81548161ffff021916908361ffff1602179055505050039050336005600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061151a6001600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461174690919063ffffffff16565b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f88f026aacbbecc90c18411df4b1185fd8d9be2470f1962f192bf84a27d0704b78184846040518084815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156115cd5780820151818401526020810190506115b2565b50505050905090810190601f1680156115fa5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1505050565b6000611626600160095461174690919063ffffffff16565b600981905550814233600954604051808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401828152602001935050505060405180910390206001900481151561169d57fe5b069050919050565b60008082840190508361ffff168161ffff16101515156116c157fe5b8091505092915050565b60008082840190508363ffffffff168163ffffffff16101515156116eb57fe5b8091505092915050565b60035442018160020160046101000a81548163ffffffff021916908363ffffffff16021790555050565b6000428260020160049054906101000a900463ffffffff1663ffffffff1611159050919050565b600080828401905083811015151561175a57fe5b8091505092915050565b602060405190810160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106117b957803560ff19168380011785556117e7565b828001600101855582156117e7579182015b828111156117e65782358255916020019190600101906117cb565b5b5090506117f491906118aa565b5090565b8154818355818115116118255760030281600302836000526020600020918201910161182491906118cf565b5b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061186b57805160ff1916838001178555611899565b82800160010185558215611899579182015b8281111561189857825182559160200191906001019061187d565b5b5090506118a691906118aa565b5090565b6118cc91905b808211156118c85760008160009055506001016118b0565b5090565b90565b61195b91905b8082111561195757600080820160006118ee919061195e565b60018201600090556002820160006101000a81549063ffffffff02191690556002820160046101000a81549063ffffffff02191690556002820160086101000a81549061ffff021916905560028201600a6101000a81549061ffff0219169055506003016118d5565b5090565b90565b50805460018160011615610100020316600290046000825580601f1061198457506119a3565b601f0160209004906000526020600020908101906119a291906118aa565b5b505600a165627a7a72305820132b51da42f560f7184ac5aae47f26c9658881610ed4c49b0c5c00f7456864e60029 \ No newline at end of file From 42e72b5d0e3402402832ab3404d5308329efe34a Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 7 Sep 2020 02:16:13 -0700 Subject: [PATCH 19/82] Fix up checks --- neard/res/genesis_config.json | 2 +- nightly/nightly.txt | 1 + runtime/runtime-params-estimator/src/vm_estimator.rs | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/neard/res/genesis_config.json b/neard/res/genesis_config.json index 014885e2570..0af001a8c59 100644 --- a/neard/res/genesis_config.json +++ b/neard/res/genesis_config.json @@ -230,7 +230,7 @@ 1, 20 ], - "total_supply": "2050000000000000000000000000000000", + "total_supply": "3050000000000000000000000000000000", "num_blocks_per_year": 31536000, "protocol_treasury_account": "test.near", "fishermen_threshold": "10000000000000000000000000", diff --git a/nightly/nightly.txt b/nightly/nightly.txt index 79d1e12640c..525cbc383ed 100644 --- a/nightly/nightly.txt +++ b/nightly/nightly.txt @@ -144,6 +144,7 @@ expensive nearcore test_cases_testnet_rpc test::test_delete_access_key_testnet expensive nearcore test_cases_testnet_rpc test::test_add_access_key_with_allowance_testnet expensive nearcore test_cases_testnet_rpc test::test_delete_access_key_with_allowance_testnet expensive nearcore test_cases_testnet_rpc test::test_access_key_smart_contract_testnet +expensive nearcore test_cases_testnet_rpc test::test_evm_deploy_call_testnet # GC tests expensive --timeout=900 near-chain gc tests::test_gc_remove_fork_large diff --git a/runtime/runtime-params-estimator/src/vm_estimator.rs b/runtime/runtime-params-estimator/src/vm_estimator.rs index a51707b1c4f..67e7a104ecd 100644 --- a/runtime/runtime-params-estimator/src/vm_estimator.rs +++ b/runtime/runtime-params-estimator/src/vm_estimator.rs @@ -156,12 +156,13 @@ pub fn cost_to_compile( "Abount to compile {}", match vm_kind { VMKind::Wasmer => "wasmer", - VMKind::Wasmtime => + VMKind::Wasmtime => { if USING_LIGHTBEAM { "wasmtime-lightbeam" } else { "wasmtime" - }, + } + } } ); }; From cd1ccee276683053229a863a80f25605347a4092 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 7 Sep 2020 12:28:14 -0700 Subject: [PATCH 20/82] Make EVM precompile tests pass --- runtime/near-evm-runner/src/near_ext.rs | 1 - runtime/near-evm-runner/tests/build/SolTests.bin | 2 +- runtime/near-evm-runner/tests/build/SubContract.bin | 2 +- runtime/near-evm-runner/tests/standard_ops.rs | 1 + 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 4475d525b7f..137e7673d93 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -171,7 +171,6 @@ impl<'a> vm::Ext for NearExt<'a> { // hijack builtins if crate::builtins::is_precompile(receive_address) { - println!("{:?}", receive_address); return Ok(crate::builtins::process_precompile(receive_address, data)); } diff --git a/runtime/near-evm-runner/tests/build/SolTests.bin b/runtime/near-evm-runner/tests/build/SolTests.bin index 19949b48a34..186505b4e7f 100644 --- a/runtime/near-evm-runner/tests/build/SolTests.bin +++ b/runtime/near-evm-runner/tests/build/SolTests.bin @@ -1 +1 @@ -6080604052610751806100136000396000f3fe6080604052600436106100705760003560e01c8063299fb0431161004e578063299fb043146101af5780632ccb1b30146101c65780639d9f9a6e14610235578063b69ef8a81461028657610070565b80630a84cba514610072578063111e0b12146100e757806314d54f541461015c575b005b61009e6004803603602081101561008857600080fd5b81019080803590602001909291905050506102b1565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b610113600480360360208110156100fd57600080fd5b8101908080359060200190929190505050610390565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561016857600080fd5b506101956004803603602081101561017f57600080fd5b81019080803590602001909291905050506103dc565b604051808215151515815260200191505060405180910390f35b3480156101bb57600080fd5b506101c461041e565b005b3480156101d257600080fd5b5061021f600480360360408110156101e957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610420565b6040518082815260200191505060405180910390f35b61023d610479565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561029257600080fd5b5061029b6104da565b6040518082815260200191505060405180910390f35b6000806000836040516102c3906104e2565b80828152602001915050604051809103906000f0801580156102e9573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610332573d6000803e3d6000fd5b508073ffffffffffffffffffffffffffffffffffffffff167fa53ffc4fb91f5ca8287e168fc73db3b0b384a6ca275650f885a1740ef7a0bc1c346040518082815260200191505060405180910390a280348191509250925050915091565b600080600034846040516103a3906104e2565b808281526020019150506040518091039082f0801580156103c8573d6000803e3d6000fd5b509050905080348191509250925050915091565b60007f379340f64b65a8890c7ea4f6d86d2359beaf41080f36a7ea64b78a2c06eee3f0826040518082815260200191505060405180910390a160019050919050565b565b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050158015610468573d6000803e3d6000fd5b506104716104da565b905092915050565b6000803373ffffffffffffffffffffffffffffffffffffffff166108fc600234816104a057fe5b049081150290604051600060405180830381858888f193505050501580156104cc573d6000803e3d6000fd5b503334819150915091509091565b600047905090565b61022d806104f08339019056fe6080604052600660005560405161022d38038061022d8339818101604052602081101561002b57600080fd5b810190808051906020019092919050505080600081905550506101da806100536000396000f3fe60806040526004361061003f5760003560e01c80632ccb1b301461004157806339c117a4146100b0578063b69ef8a8146100df578063e6a899b61461010a575b005b34801561004d57600080fd5b5061009a6004803603604081101561006457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610135565b6040518082815260200191505060405180910390f35b3480156100bc57600080fd5b506100c561018e565b604051808215151515815260200191505060405180910390f35b3480156100eb57600080fd5b506100f4610197565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b5061011f61019f565b6040518082815260200191505060405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561017d573d6000803e3d6000fd5b50610186610197565b905092915050565b60006001905090565b600047905090565b6000548156fea265627a7a72315820ea83af7ddb8234e4b841b684510c134b4b7a908fa8f04ffa0bc7a26e95ccc98064736f6c63430005100032a265627a7a72315820380ec69db676ca33c704f78f87c7eb2076dbf6b096c675fae266364c1b0587cc64736f6c63430005100032 \ No newline at end of file +6080604052610a87806100136000396000f3fe6080604052600436106100705760003560e01c8063299fb0431161004e578063299fb043146101af5780632ccb1b30146101c65780639d9f9a6e14610235578063b69ef8a81461028657610070565b80630a84cba514610072578063111e0b12146100e757806314d54f541461015c575b005b61009e6004803603602081101561008857600080fd5b81019080803590602001909291905050506102b1565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b610113600480360360208110156100fd57600080fd5b8101908080359060200190929190505050610390565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561016857600080fd5b506101956004803603602081101561017f57600080fd5b81019080803590602001909291905050506103dc565b604051808215151515815260200191505060405180910390f35b3480156101bb57600080fd5b506101c461041e565b005b3480156101d257600080fd5b5061021f600480360360408110156101e957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610756565b6040518082815260200191505060405180910390f35b61023d6107af565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561029257600080fd5b5061029b610810565b6040518082815260200191505060405180910390f35b6000806000836040516102c390610818565b80828152602001915050604051809103906000f0801580156102e9573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610332573d6000803e3d6000fd5b508073ffffffffffffffffffffffffffffffffffffffff167fa53ffc4fb91f5ca8287e168fc73db3b0b384a6ca275650f885a1740ef7a0bc1c346040518082815260200191505060405180910390a280348191509250925050915091565b600080600034846040516103a390610818565b808281526020019150506040518091039082f0801580156103c8573d6000803e3d6000fd5b509050905080348191509250925050915091565b60007f379340f64b65a8890c7ea4f6d86d2359beaf41080f36a7ea64b78a2c06eee3f0826040518082815260200191505060405180910390a160019050919050565b7fe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556002604051806000019050602060405180830381855afa158015610467573d6000803e3d6000fd5b5050506040513d602081101561047c57600080fd5b810190808051906020019092919050505014610500576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f7368613220646967657374206d69736d6174636800000000000000000000000081525060200191505060405180910390fd5b7f9c1185a5c5e9fc54612808977ee8f548b2258d310000000000000000000000006003604051806000019050602060405180830381855afa158015610549573d6000803e3d6000fd5b5050506040515160601b6bffffffffffffffffffffffff1916146105d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f726d6431363020646967657374206d69736d617463680000000000000000000081525060200191505060405180910390fd5b60006001601b6040516000815260200160405260405180807f11111111111111111111111111111111111111111111111111111111111111118152506020018260ff168152602001807fb9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b698815250602001807f12ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb6447448152506020019150506020604051602081039080840390855afa158015610692573d6000803e3d6000fd5b505050602060405103519050731563915e194d8cfba1943570603f7606a311550873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610753576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f65637265636f766572206d69736d61746368000000000000000000000000000081525060200191505060405180910390fd5b50565b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561079e573d6000803e3d6000fd5b506107a7610810565b905092915050565b6000803373ffffffffffffffffffffffffffffffffffffffff166108fc600234816107d657fe5b049081150290604051600060405180830381858888f19350505050158015610802573d6000803e3d6000fd5b503334819150915091509091565b600047905090565b61022d806108268339019056fe6080604052600660005560405161022d38038061022d8339818101604052602081101561002b57600080fd5b810190808051906020019092919050505080600081905550506101da806100536000396000f3fe60806040526004361061003f5760003560e01c80632ccb1b301461004157806339c117a4146100b0578063b69ef8a8146100df578063e6a899b61461010a575b005b34801561004d57600080fd5b5061009a6004803603604081101561006457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610135565b6040518082815260200191505060405180910390f35b3480156100bc57600080fd5b506100c561018e565b604051808215151515815260200191505060405180910390f35b3480156100eb57600080fd5b506100f4610197565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b5061011f61019f565b6040518082815260200191505060405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561017d573d6000803e3d6000fd5b50610186610197565b905092915050565b60006001905090565b600047905090565b6000548156fea265627a7a72315820bc102b3933ad6112eb436087a67714bf08814e4c202d3118307a3e280f47b6cb64736f6c63430005100032a265627a7a72315820fe8c0773a06b1128d9c03d755c55071d775ebea7ee4959a672d257e75225a51064736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/SubContract.bin b/runtime/near-evm-runner/tests/build/SubContract.bin index 9599d211abc..54225e72d6b 100644 --- a/runtime/near-evm-runner/tests/build/SubContract.bin +++ b/runtime/near-evm-runner/tests/build/SubContract.bin @@ -1 +1 @@ -6080604052600660005560405161022d38038061022d8339818101604052602081101561002b57600080fd5b810190808051906020019092919050505080600081905550506101da806100536000396000f3fe60806040526004361061003f5760003560e01c80632ccb1b301461004157806339c117a4146100b0578063b69ef8a8146100df578063e6a899b61461010a575b005b34801561004d57600080fd5b5061009a6004803603604081101561006457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610135565b6040518082815260200191505060405180910390f35b3480156100bc57600080fd5b506100c561018e565b604051808215151515815260200191505060405180910390f35b3480156100eb57600080fd5b506100f4610197565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b5061011f61019f565b6040518082815260200191505060405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561017d573d6000803e3d6000fd5b50610186610197565b905092915050565b60006001905090565b600047905090565b6000548156fea265627a7a72315820ea83af7ddb8234e4b841b684510c134b4b7a908fa8f04ffa0bc7a26e95ccc98064736f6c63430005100032 \ No newline at end of file +6080604052600660005560405161022d38038061022d8339818101604052602081101561002b57600080fd5b810190808051906020019092919050505080600081905550506101da806100536000396000f3fe60806040526004361061003f5760003560e01c80632ccb1b301461004157806339c117a4146100b0578063b69ef8a8146100df578063e6a899b61461010a575b005b34801561004d57600080fd5b5061009a6004803603604081101561006457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610135565b6040518082815260200191505060405180910390f35b3480156100bc57600080fd5b506100c561018e565b604051808215151515815260200191505060405180910390f35b3480156100eb57600080fd5b506100f4610197565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b5061011f61019f565b6040518082815260200191505060405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561017d573d6000803e3d6000fd5b50610186610197565b905092915050565b60006001905090565b600047905090565b6000548156fea265627a7a72315820bc102b3933ad6112eb436087a67714bf08814e4c202d3118307a3e280f47b6cb64736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index a741aab9384..8ef3c133c51 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -123,6 +123,7 @@ fn test_precompiles() { create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); let (input, _) = soltest::functions::precompile_test::call(); let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); assert_eq!(raw.len(), 0); From 600423421bd04309558d89406046bb7a5a11eab8 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 7 Sep 2020 12:39:25 -0700 Subject: [PATCH 21/82] Removed panics in builtins and replace with enum precompiles --- runtime/near-evm-runner/src/builtins.rs | 71 +++++++++++++------------ 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/runtime/near-evm-runner/src/builtins.rs b/runtime/near-evm-runner/src/builtins.rs index 3397db9a46a..a3a1bd76215 100644 --- a/runtime/near-evm-runner/src/builtins.rs +++ b/runtime/near-evm-runner/src/builtins.rs @@ -1,48 +1,60 @@ +use std::{ + cmp::{max, min}, + io::{self, Cursor, Read}, + mem::size_of, +}; + use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt}; use ethereum_types::{Address, H256, U256}; use num_bigint::BigUint; use num_traits::{One, Zero}; - use parity_bytes::BytesRef; use ripemd160::Digest; -use std::{ - cmp::{max, min}, - io::{self, Cursor, Read}, - mem::size_of, -}; use vm::{MessageCallResult, ReturnData}; -pub static COUNT: u64 = 9; +enum Precompile { + EcRecover = 1, + Sha256 = 2, + Ripemd160 = 3, + Identity = 4, + ModexpImpl = 5, + Bn128AddImpl = 6, + Bn128MulImpl = 7, + Bn128PairingImpl = 8, + Blake2FImpl = 9, + LastPrecompile = 10, +} pub fn is_precompile(addr: &Address) -> bool { - *addr <= Address::from_low_u64_be(COUNT) + *addr < Address::from_low_u64_be(Precompile::LastPrecompile as u64) } -pub fn precompile(id: u64) -> Box { - match id { - 1 => Box::new(EcRecover) as Box, - 2 => Box::new(Sha256) as Box, - 3 => Box::new(Ripemd160) as Box, - 4 => Box::new(Identity) as Box, - 5 => Box::new(ModexpImpl) as Box, - 6 => Box::new(Bn128AddImpl) as Box, - 7 => Box::new(Bn128MulImpl) as Box, - 8 => Box::new(Bn128PairingImpl) as Box, - 9 => Box::new(Blake2FImpl) as Box, - _ => panic!("Invalid builtin ID: {}", id), - } +pub fn precompile(id: u64) -> Result, String> { + Ok(match id as Precompile { + Precompile::EcRecover => Box::new(EcRecover) as Box, + Precompile::Sha256 => Box::new(Sha256) as Box, + Precompile::Ripemd160 => Box::new(Ripemd160) as Box, + Precompile::Identity => Box::new(Identity) as Box, + Precompile::ModexpImpl => Box::new(ModexpImpl) as Box, + Precompile::Bn128AddImpl => Box::new(Bn128AddImpl) as Box, + Precompile::Bn128MulImpl => Box::new(Bn128MulImpl) as Box, + Precompile::Bn128PairingImpl => Box::new(Bn128PairingImpl) as Box, + Precompile::Blake2FImpl => Box::new(Blake2FImpl) as Box, + _ => return Err(format!("Invalid builtin ID: {}", id)), + }) } pub fn process_precompile(addr: &Address, input: &[u8]) -> MessageCallResult { - let f = precompile(addr.to_low_u64_be()); + let f = precompile(addr.to_low_u64_be()).map_err(|_| MessageCallResult::Failed)?; let mut bytes = vec![]; let mut output = parity_bytes::BytesRef::Flexible(&mut bytes); // mutates bytes - f.execute(input, &mut output).expect("No errors in precompiles"); + f.execute(input, &mut output).map_err(|_| MessageCallResult::Failed)?; let size = bytes.len(); + // TODO: add gas usage here. MessageCallResult::Success(1_000_000_000.into(), ReturnData::new(bytes, 0, size)) } @@ -367,10 +379,7 @@ impl Impl for Bn128PairingImpl { return Err("Invalid input length, must be multiple of 192 (3 * (32*2))".into()); } - if let Err(err) = self.execute_with_error(input, output) { - panic!("Pairining error: {:?}", err); - } - Ok(()) + self.execute_with_error(input, output) } } @@ -527,11 +536,7 @@ impl Impl for Blake2FImpl { const PROOF: &str = "Checked the length of the input above; qed"; if input.len() != BLAKE2_F_ARG_LEN { - panic!( - "input length for Blake2 F precompile should be exactly 213 bytes, was {}", - input.len() - ); - // return Err("input length for Blake2 F precompile should be exactly 213 bytes") + return Err(Error("input length for Blake2 F precompile should be exactly 213 bytes")); } let mut cursor = Cursor::new(input); @@ -560,7 +565,7 @@ impl Impl for Blake2FImpl { Some(1) => true, Some(0) => false, _ => { - panic!("incorrect final block indicator flag, was: {:?}", input.last()); + return Err(Error("incorrect final block indicator flag")); } }; From 7c40fb41fec6e150f4c0ade1cef38512fc602465 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 7 Sep 2020 13:09:58 -0700 Subject: [PATCH 22/82] Finishing the evm tests. Fixes in builtins --- Cargo.lock | 12 +++++++ runtime/near-evm-runner/Cargo.toml | 1 + runtime/near-evm-runner/src/builtins.rs | 36 +++++++++++-------- runtime/near-evm-runner/src/lib.rs | 3 ++ runtime/near-evm-runner/tests/standard_ops.rs | 9 +++-- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63b962150b1..8be6c21e340 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1344,6 +1344,17 @@ dependencies = [ "syn 1.0.38", ] +[[package]] +name = "enum-primitive-derive" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f52288f9a7ebb08959188872b58e7eaa12af9cb47da8e94158e16da7e143340" +dependencies = [ + "num-traits", + "quote 1.0.3", + "syn 1.0.38", +] + [[package]] name = "env_logger" version = "0.7.1" @@ -2847,6 +2858,7 @@ dependencies = [ "bn", "borsh", "byteorder", + "enum-primitive-derive", "ethabi", "ethabi-contract", "ethabi-derive", diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 6349fc8f723..3e85496668d 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -15,6 +15,7 @@ hex = "0.4" byteorder = "1.0" num-bigint = { version = "0.3", default-features = false } num-traits = "0.2.12" +enum-primitive-derive = "0.2" sha2 = "0.8" sha3 = "0.8" diff --git a/runtime/near-evm-runner/src/builtins.rs b/runtime/near-evm-runner/src/builtins.rs index a3a1bd76215..8e1c86314dc 100644 --- a/runtime/near-evm-runner/src/builtins.rs +++ b/runtime/near-evm-runner/src/builtins.rs @@ -7,11 +7,12 @@ use std::{ use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt}; use ethereum_types::{Address, H256, U256}; use num_bigint::BigUint; -use num_traits::{One, Zero}; +use num_traits::{FromPrimitive, One, ToPrimitive, Zero}; use parity_bytes::BytesRef; use ripemd160::Digest; use vm::{MessageCallResult, ReturnData}; +#[derive(Primitive)] enum Precompile { EcRecover = 1, Sha256 = 2, @@ -26,32 +27,37 @@ enum Precompile { } pub fn is_precompile(addr: &Address) -> bool { - *addr < Address::from_low_u64_be(Precompile::LastPrecompile as u64) + *addr < Address::from_low_u64_be(Precompile::LastPrecompile.to_u64().unwrap()) } pub fn precompile(id: u64) -> Result, String> { - Ok(match id as Precompile { - Precompile::EcRecover => Box::new(EcRecover) as Box, - Precompile::Sha256 => Box::new(Sha256) as Box, - Precompile::Ripemd160 => Box::new(Ripemd160) as Box, - Precompile::Identity => Box::new(Identity) as Box, - Precompile::ModexpImpl => Box::new(ModexpImpl) as Box, - Precompile::Bn128AddImpl => Box::new(Bn128AddImpl) as Box, - Precompile::Bn128MulImpl => Box::new(Bn128MulImpl) as Box, - Precompile::Bn128PairingImpl => Box::new(Bn128PairingImpl) as Box, - Precompile::Blake2FImpl => Box::new(Blake2FImpl) as Box, + Ok(match Precompile::from_u64(id) { + Some(Precompile::EcRecover) => Box::new(EcRecover) as Box, + Some(Precompile::Sha256) => Box::new(Sha256) as Box, + Some(Precompile::Ripemd160) => Box::new(Ripemd160) as Box, + Some(Precompile::Identity) => Box::new(Identity) as Box, + Some(Precompile::ModexpImpl) => Box::new(ModexpImpl) as Box, + Some(Precompile::Bn128AddImpl) => Box::new(Bn128AddImpl) as Box, + Some(Precompile::Bn128MulImpl) => Box::new(Bn128MulImpl) as Box, + Some(Precompile::Bn128PairingImpl) => Box::new(Bn128PairingImpl) as Box, + Some(Precompile::Blake2FImpl) => Box::new(Blake2FImpl) as Box, _ => return Err(format!("Invalid builtin ID: {}", id)), }) } pub fn process_precompile(addr: &Address, input: &[u8]) -> MessageCallResult { - let f = precompile(addr.to_low_u64_be()).map_err(|_| MessageCallResult::Failed)?; + let f = match precompile(addr.to_low_u64_be()) { + Ok(f) => f, + Err(_) => return MessageCallResult::Failed, + }; let mut bytes = vec![]; let mut output = parity_bytes::BytesRef::Flexible(&mut bytes); // mutates bytes - f.execute(input, &mut output).map_err(|_| MessageCallResult::Failed)?; - + match f.execute(input, &mut output) { + Ok(()) => {} + Err(_) => return MessageCallResult::Failed, + }; let size = bytes.len(); // TODO: add gas usage here. diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 7a86349a281..7debf96dc8f 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -1,3 +1,6 @@ +#[macro_use] +extern crate enum_primitive_derive; + use borsh::{BorshDeserialize, BorshSerialize}; use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 8ef3c133c51..de2e86a981a 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -228,15 +228,14 @@ fn test_solidity_accurate_storage_on_selfdestruct() { U256::from(100) ); - let salt = H256([0u8; 32]); - let destruct_code = hex::decode(&DESTRUCT_TEST).unwrap(); - // Deploy CREATE2 Factory + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); let factory_addr = context.deploy_code(hex::decode(&FACTORY_TEST).unwrap()).unwrap(); // Deploy + SelfDestruct in one transaction + let salt = H256([0u8; 32]); + let destruct_code = hex::decode(&DESTRUCT_TEST).unwrap(); let input = create2factory::functions::test_double_deploy::call(salt, destruct_code.clone()).0; let raw = context.call_function(encode_call_function_args(factory_addr, input)).unwrap(); - println!("{:?}", raw); - // assert_eq!(1, raw.parse::().unwrap()); + assert!(create2factory::functions::test_double_deploy::decode_output(&raw).unwrap()); } From 0314802277d5b5b239be4faa4bbc065a2295b1a0 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 7 Sep 2020 13:27:25 -0700 Subject: [PATCH 23/82] Marking where gas usage should be added --- runtime/near-evm-runner/src/errors.rs | 1 - runtime/near-evm-runner/src/interpreter.rs | 4 ++++ runtime/near-evm-runner/src/lib.rs | 1 + runtime/near-evm-runner/src/near_ext.rs | 3 +++ runtime/near-evm-runner/src/types.rs | 2 +- 5 files changed, 9 insertions(+), 2 deletions(-) delete mode 100644 runtime/near-evm-runner/src/errors.rs diff --git a/runtime/near-evm-runner/src/errors.rs b/runtime/near-evm-runner/src/errors.rs deleted file mode 100644 index 8b137891791..00000000000 --- a/runtime/near-evm-runner/src/errors.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/runtime/near-evm-runner/src/interpreter.rs b/runtime/near-evm-runner/src/interpreter.rs index 5431fff3e0d..7f2a45040eb 100644 --- a/runtime/near-evm-runner/src/interpreter.rs +++ b/runtime/near-evm-runner/src/interpreter.rs @@ -73,6 +73,7 @@ pub fn _create( address: *address, sender: *sender, origin: *origin, + // TODO: gas usage. gas: 1_000_000_000.into(), gas_price: 1.into(), value: ActionValue::Transfer(value), @@ -86,6 +87,7 @@ pub fn _create( sub_state.transfer_balance(sender, address, value)?; let mut ext = NearExt::new(*address, *origin, &mut sub_state, call_stack_depth + 1, false); + // TODO: gas usage. ext.info.gas_limit = U256::from(1_000_000_000); ext.schedule = Schedule::new_constantinople(); @@ -243,6 +245,7 @@ fn run_against_state( address: *state_address, sender: *sender, origin: *origin, + // TODO: gas usage. gas: 1_000_000_000.into(), gas_price: 1.into(), value: ActionValue::Apparent(0.into()), @@ -260,6 +263,7 @@ fn run_against_state( let mut ext = NearExt::new(*state_address, *origin, &mut sub_state, call_stack_depth + 1, is_static); + // TODO: gas usage. ext.info.gas_limit = U256::from(1_000_000_000); ext.schedule = Schedule::new_constantinople(); diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 7debf96dc8f..61b5d458426 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -83,6 +83,7 @@ impl<'a> EvmState for EvmContext<'a> { } fn commit_changes(&mut self, other: &StateStore) -> Result<()> { + // TODO: figure out how to handle this on the top level. // self.commit_self_destructs(&other.self_destructs); // self.commit_self_destructs(&other.recreated); for (address, code) in other.code.iter() { diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 137e7673d93..ef9a849e112 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -145,6 +145,7 @@ impl<'a> vm::Ext for NearExt<'a> { true, &code.to_vec(), ) + // TODO: gas usage. .map(|result| ContractCreateResult::Created(result, 1_000_000_000.into())) .map_err(|_| TrapKind::Call(ActionParams::default())) } @@ -213,6 +214,7 @@ impl<'a> vm::Ext for NearExt<'a> { }; let msg_call_result = match result { + // TODO: gas usage. Ok(data) => MessageCallResult::Success(1_000_000_000.into(), data), Err(err) => { let message = match err { @@ -222,6 +224,7 @@ impl<'a> vm::Ext for NearExt<'a> { _ => format!("{:?}", err).as_bytes().to_vec(), }; let message_len = message.len(); + // TODO: gas usage. MessageCallResult::Reverted( 1_000_000_000.into(), ReturnData::new(message, 0, message_len), diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index 1c34b90a405..cb8c074fc9c 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -90,6 +90,6 @@ mod tests { #[test] fn test_view_call_fail() { let bytes = [0; 71]; - let res = ViewCallArgs::try_from_slice(&bytes).unwrap_err(); + let _ = ViewCallArgs::try_from_slice(&bytes).unwrap_err(); } } From 820cbe53ab821db8d6d9fb78bb6bd1d39f73e2d4 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 7 Sep 2020 13:58:13 -0700 Subject: [PATCH 24/82] Fix all merge conflicts --- Cargo.lock | 1 + runtime/near-vm-runner/src/wasmer_runner.rs | 4 +++- runtime/near-vm-runner/src/wasmtime_runner.rs | 3 +++ runtime/runtime/Cargo.toml | 1 + runtime/runtime/src/actions.rs | 22 +++++++++---------- runtime/runtime/src/state_viewer.rs | 15 ++++++------- test-utils/testlib/src/node/runtime_node.rs | 2 ++ test-utils/testlib/src/runtime_utils.rs | 3 +++ test-utils/testlib/src/standard_test_cases.rs | 2 +- test-utils/testlib/src/user/mod.rs | 8 ++++--- test-utils/testlib/src/user/rpc_user.rs | 6 ++--- test-utils/testlib/src/user/runtime_user.rs | 11 +++++----- 12 files changed, 46 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8be6c21e340..f5a351c03f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3328,6 +3328,7 @@ dependencies = [ "lazy_static", "log", "near-crypto", + "near-evm-runner", "near-metrics", "near-primitives", "near-runtime-configs", diff --git a/runtime/near-vm-runner/src/wasmer_runner.rs b/runtime/near-vm-runner/src/wasmer_runner.rs index 0b5d8513e7f..26eea94f559 100644 --- a/runtime/near-vm-runner/src/wasmer_runner.rs +++ b/runtime/near-vm-runner/src/wasmer_runner.rs @@ -160,7 +160,9 @@ impl IntoVMError for wasmer_runtime::error::RuntimeError { VMLogicError::InconsistentStateError(e) => { VMError::InconsistentStateError(e.clone()) } - VMLogicError::EvmError(e) => VMError::FunctionCallError(FunctionCallError::EvmError(e.clone())), + VMLogicError::EvmError(e) => { + VMError::FunctionCallError(FunctionCallError::EvmError(e.clone())) + } } } else { panic!( diff --git a/runtime/near-vm-runner/src/wasmtime_runner.rs b/runtime/near-vm-runner/src/wasmtime_runner.rs index 046e3444a36..42236f5dc15 100644 --- a/runtime/near-vm-runner/src/wasmtime_runner.rs +++ b/runtime/near-vm-runner/src/wasmtime_runner.rs @@ -78,6 +78,9 @@ pub mod wasmtime_runner { Some(VMLogicError::InconsistentStateError(e)) => { VMError::InconsistentStateError(e.clone()) } + Some(VMLogicError::EvmError(e)) => { + VMError::FunctionCallError(FunctionCallError::EvmError(e.clone())) + } None => panic!("Error is not properly set"), } } else { diff --git a/runtime/runtime/Cargo.toml b/runtime/runtime/Cargo.toml index cc123884bb5..23f5ee0e657 100644 --- a/runtime/runtime/Cargo.toml +++ b/runtime/runtime/Cargo.toml @@ -30,6 +30,7 @@ near-runtime-fees = { path = "../../runtime/near-runtime-fees" } near-runtime-utils = { path = "../../runtime/near-runtime-utils" } near-vm-logic = { path = "../../runtime/near-vm-logic" } near-vm-runner = { path = "../../runtime/near-vm-runner" } +near-evm-runner = { path = "../../runtime/near-evm-runner" } near-vm-errors = { path = "../../runtime/near-vm-errors" } [features] diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 4677e383a0c..0047d4ca527 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -1,7 +1,9 @@ -use borsh::BorshSerialize; +use borsh::{BorshDeserialize, BorshSerialize}; +use near_crypto::PublicKey; use near_primitives::account::{AccessKey, AccessKeyPermission, Account}; use near_primitives::contract::ContractCode; +use near_primitives::errors::{ActionError, ActionErrorKind, ExternalError, RuntimeError}; use near_primitives::hash::CryptoHash; use near_primitives::receipt::{ActionReceipt, Receipt}; use near_primitives::transaction::{ @@ -12,6 +14,11 @@ use near_primitives::types::{AccountId, EpochInfoProvider, ValidatorStake}; use near_primitives::utils::{ is_valid_account_id, is_valid_sub_account_id, is_valid_top_level_account_id, EVM_CODE_HASH, }; +use near_primitives::version::{ + ProtocolVersion, CORRECT_RANDOM_VALUE_PROTOCOL_VERSION, + IMPLICIT_ACCOUNT_CREATION_PROTOCOL_VERSION, +}; +use near_runtime_configs::AccountCreationConfig; use near_runtime_fees::RuntimeFeesConfig; use near_runtime_utils::is_account_id_64_len_hex; use near_store::{ @@ -20,20 +27,12 @@ use near_store::{ }; use near_vm_errors::{CompilationError, FunctionCallError, InconsistentStateError}; use near_vm_logic::types::PromiseResult; -use near_vm_logic::VMContext; +use near_vm_logic::{VMContext, VMOutcome}; +use near_vm_runner::VMError; use crate::config::{safe_add_gas, RuntimeConfig}; use crate::ext::RuntimeExt; use crate::{ActionResult, ApplyState}; -use near_crypto::PublicKey; -use near_primitives::errors::{ActionError, ActionErrorKind, ExternalError, RuntimeError}; -use near_primitives::version::{ - ProtocolVersion, CORRECT_RANDOM_VALUE_PROTOCOL_VERSION, - IMPLICIT_ACCOUNT_CREATION_PROTOCOL_VERSION, -}; -use near_runtime_configs::AccountCreationConfig; -use near_vm_errors::{CompilationError, FunctionCallError}; -use near_vm_runner::VMError; /// Runs given function call with given context / apply state. /// Precompiles: @@ -127,6 +126,7 @@ pub(crate) fn execute_function_call( &config.wasm_config, &config.transaction_costs, promise_results, + apply_state.current_protocol_version, ) } } diff --git a/runtime/runtime/src/state_viewer.rs b/runtime/runtime/src/state_viewer.rs index 9f3d619f25b..74830a33c50 100644 --- a/runtime/runtime/src/state_viewer.rs +++ b/runtime/runtime/src/state_viewer.rs @@ -6,23 +6,22 @@ use log::debug; use near_crypto::{KeyType, PublicKey}; use near_primitives::account::{AccessKey, Account}; use near_primitives::hash::CryptoHash; +use near_primitives::receipt::ActionReceipt; use near_primitives::serialize::to_base64; +use near_primitives::transaction::FunctionCallAction; use near_primitives::trie_key::trie_key_parsers; use near_primitives::types::EpochHeight; use near_primitives::types::{AccountId, BlockHeight, EpochId, EpochInfoProvider}; use near_primitives::utils::is_valid_account_id; +use near_primitives::version::ProtocolVersion; use near_primitives::views::{StateItem, ViewStateResult}; +use near_runtime_configs::RuntimeConfig; use near_store::{get_access_key, get_account, TrieUpdate}; use near_vm_logic::ReturnData; use crate::actions::execute_function_call; use crate::ext::RuntimeExt; use crate::ApplyState; -use near_primitives::receipt::ActionReceipt; -use near_primitives::transaction::FunctionCallAction; -use near_primitives::version::ProtocolVersion; -use near_primitives::version::PROTOCOL_VERSION; -use near_runtime_configs::RuntimeConfig; pub struct TrieViewer {} @@ -134,7 +133,7 @@ impl TrieViewer { block_timestamp, gas_limit: None, random_seed: root, - current_protocol_version: PROTOCOL_VERSION, + current_protocol_version, }; let action_receipt = ActionReceipt { signer_id: originator_id.clone(), @@ -191,16 +190,16 @@ impl TrieViewer { #[cfg(test)] mod tests { + use near_primitives::test_utils::MockEpochInfoProvider; use near_primitives::trie_key::TrieKey; use near_primitives::types::StateChangeCause; + use near_primitives::version::PROTOCOL_VERSION; use near_primitives::views::StateItem; use testlib::runtime_utils::{ alice_account, encode_int, get_runtime_and_trie, get_test_trie_viewer, }; use super::*; - use near_primitives::test_utils::MockEpochInfoProvider; - use near_primitives::version::PROTOCOL_VERSION; #[test] fn test_view_call() { diff --git a/test-utils/testlib/src/node/runtime_node.rs b/test-utils/testlib/src/node/runtime_node.rs index 9e8293b30fb..101ebe8208d 100644 --- a/test-utils/testlib/src/node/runtime_node.rs +++ b/test-utils/testlib/src/node/runtime_node.rs @@ -2,6 +2,8 @@ use std::sync::{Arc, RwLock}; use near_chain_configs::Genesis; use near_crypto::{InMemorySigner, KeyType, Signer}; +use near_primitives::account::Account; +use near_primitives::state_record::StateRecord; use near_primitives::types::AccountId; use near_primitives::utils::EVM_CODE_HASH; use neard::config::{GenesisExt, TESTING_INIT_BALANCE}; diff --git a/test-utils/testlib/src/runtime_utils.rs b/test-utils/testlib/src/runtime_utils.rs index bcb86e596ce..34c65326421 100644 --- a/test-utils/testlib/src/runtime_utils.rs +++ b/test-utils/testlib/src/runtime_utils.rs @@ -22,6 +22,9 @@ pub fn bob_account() -> AccountId { pub fn eve_dot_alice_account() -> AccountId { "eve.alice.near".to_string() } +pub fn evm_account() -> AccountId { + "evm".to_string() +} pub fn default_code_hash() -> CryptoHash { let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); diff --git a/test-utils/testlib/src/standard_test_cases.rs b/test-utils/testlib/src/standard_test_cases.rs index ffe11a10a96..531c0c56be4 100644 --- a/test-utils/testlib/src/standard_test_cases.rs +++ b/test-utils/testlib/src/standard_test_cases.rs @@ -22,7 +22,7 @@ use neard::config::{NEAR_BASE, TESTING_INIT_BALANCE, TESTING_INIT_STAKE}; use crate::fees_utils::FeeHelper; use crate::node::Node; -use crate::runtime_utils::{alice_account, bob_account, eve_dot_alice_account}; +use crate::runtime_utils::{alice_account, bob_account, eve_dot_alice_account, evm_account}; use crate::user::User; use near_evm_runner::utils::near_account_id_to_evm_address; diff --git a/test-utils/testlib/src/user/mod.rs b/test-utils/testlib/src/user/mod.rs index 78907a5581b..5e74aacba9e 100644 --- a/test-utils/testlib/src/user/mod.rs +++ b/test-utils/testlib/src/user/mod.rs @@ -12,9 +12,11 @@ use near_primitives::transaction::{ DeployContractAction, ExecutionOutcome, FunctionCallAction, SignedTransaction, StakeAction, TransferAction, }; -use near_primitives::types::{AccountId, Balance, BlockHeight, Gas, MerkleHash}; -use near_primitives::views::{AccessKeyView, AccountView, BlockView, CallResult, ViewStateResult}; -use near_primitives::views::{ExecutionOutcomeView, FinalExecutionOutcomeView}; +use near_primitives::types::{AccountId, Balance, BlockHeight, Gas, MerkleHash, ShardId}; +use near_primitives::views::{ + AccessKeyView, AccountView, BlockView, CallResult, ChunkView, ExecutionOutcomeView, + FinalExecutionOutcomeView, ViewStateResult, +}; pub use crate::user::runtime_user::RuntimeUser; diff --git a/test-utils/testlib/src/user/rpc_user.rs b/test-utils/testlib/src/user/rpc_user.rs index 9a3c39b8366..50d19bc3484 100644 --- a/test-utils/testlib/src/user/rpc_user.rs +++ b/test-utils/testlib/src/user/rpc_user.rs @@ -11,6 +11,7 @@ use near_client::StatusResponse; use near_crypto::{PublicKey, Signer}; use near_jsonrpc::client::{new_client, JsonRpcClient}; use near_jsonrpc::ServerError; +use near_jsonrpc_client::ChunkId; use near_primitives::hash::CryptoHash; use near_primitives::receipt::Receipt; use near_primitives::serialize::{to_base, to_base64}; @@ -19,12 +20,11 @@ use near_primitives::types::{ AccountId, BlockHeight, BlockId, BlockReference, MaybeBlockId, ShardId, }; use near_primitives::views::{ - AccessKeyView, AccountView, BlockView, CallResult, EpochValidatorInfo, ExecutionOutcomeView, - FinalExecutionOutcomeView, QueryResponse, ViewStateResult, + AccessKeyView, AccountView, BlockView, CallResult, ChunkView, EpochValidatorInfo, + ExecutionOutcomeView, FinalExecutionOutcomeView, QueryResponse, ViewStateResult, }; use crate::user::User; -use near_jsonrpc_client::ChunkId; pub struct RpcUser { account_id: AccountId, diff --git a/test-utils/testlib/src/user/runtime_user.rs b/test-utils/testlib/src/user/runtime_user.rs index f6537f31e20..4ec54f15d47 100644 --- a/test-utils/testlib/src/user/runtime_user.rs +++ b/test-utils/testlib/src/user/runtime_user.rs @@ -7,21 +7,21 @@ use near_jsonrpc::ServerError; use near_primitives::errors::{RuntimeError, TxExecutionError}; use near_primitives::hash::CryptoHash; use near_primitives::receipt::Receipt; +use near_primitives::test_utils::MockEpochInfoProvider; use near_primitives::transaction::SignedTransaction; use near_primitives::types::{AccountId, BlockHeightDelta, MerkleHash}; use near_primitives::version::PROTOCOL_VERSION; use near_primitives::views::{ - AccessKeyView, AccountView, BlockView, CallResult, ExecutionOutcomeView, - ExecutionOutcomeWithIdView, ExecutionStatusView, ViewStateResult, + AccessKeyView, AccountView, BlockView, CallResult, ChunkView, ExecutionOutcomeView, + ExecutionOutcomeWithIdView, ExecutionStatusView, FinalExecutionOutcomeView, + FinalExecutionStatus, ViewStateResult, }; -use near_primitives::views::{FinalExecutionOutcomeView, FinalExecutionStatus}; use near_store::{ShardTries, TrieUpdate}; +use neard::config::MIN_GAS_PRICE; use node_runtime::state_viewer::TrieViewer; use node_runtime::{ApplyState, Runtime}; use crate::user::{User, POISONED_LOCK_ERR}; -use near_primitives::test_utils::MockEpochInfoProvider; -use neard::config::MIN_GAS_PRICE; /// Mock client without chain, used in RuntimeUser and RuntimeNode pub struct MockClient { @@ -231,6 +231,7 @@ impl User for RuntimeUser { args, &mut result.logs, &self.epoch_info_provider, + PROTOCOL_VERSION, ) .map_err(|err| err.to_string())?; Ok(result) From ddac296f2ea9a29c2079c7b5cb1ff63199863506 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Tue, 8 Sep 2020 00:31:27 -0700 Subject: [PATCH 25/82] Adding a bunch skips to deny.toml, because parity modules are not maintained at this point --- deny.toml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/deny.toml b/deny.toml index aba92b92ae0..0b3111eb9cb 100644 --- a/deny.toml +++ b/deny.toml @@ -43,4 +43,27 @@ skip = [ { name = "idna", version = "=0.1.5" }, { name = "semver", version = "=0.9.0" }, { name = "percent-encoding", version = "=1.0.1" }, + + # evm support has some legacy. Updating it fails at this point. + # to fully update, need to fork half of parity libraries, as they stopped development. + { name = "unicode-xid", version = "=0.1.0" }, + { name = "uint", version = "=0.7.1" }, + { name = "syn", version = "=0.15.44" }, + { name = "static_assertions", version = "=0.2.5" }, + { name = "parking_lot", version = "=0.7.1" }, + { name = "smallvec", version = "=0.6.13" }, + { name = "scopeguard", version = "=0.3.3" }, + { name = "rustc-hex", version = "=1.0.0" }, + { name = "rand", version = "=0.5.6" }, + { name = "quote", version = "=0.6.13" }, + { name = "proc-macro2", version = "=0.4.30" }, + { name = "primitive-types", version = "=0.3.0" }, + { name = "opaque-debug", version = "=0.2.3" }, + { name = "num-bigint", version = "=0.2.6" }, + { name = "generic-array", version = "=0.12.3" }, + { name = "fixed-hash", version = "=0.3.2" }, + { name = "elastic-array", version = "=0.10.3" }, + { name = "digest", version = "=0.8.1" }, + { name = "arrayvec", version = "=0.4.12" }, + { name = "block-buffer", version = "=0.7.3" }, ] From 01045f270c5646a0f9be8251a1638a9d2ea8109f Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Wed, 9 Sep 2020 10:29:05 -0700 Subject: [PATCH 26/82] Adding unwrap_or around time to not fail when time goes back on the laptop --- chain/client/src/client_actor.rs | 6 +++--- deny.toml | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/chain/client/src/client_actor.rs b/chain/client/src/client_actor.rs index e853cf0f1a0..0f6bef9c119 100644 --- a/chain/client/src/client_actor.rs +++ b/chain/client/src/client_actor.rs @@ -744,7 +744,7 @@ impl ClientActor { ); delay = core::cmp::min( delay, - self.doomslug_timer_next_attempt.signed_duration_since(now).to_std().unwrap(), + self.doomslug_timer_next_attempt.signed_duration_since(now).to_std().unwrap_or(delay), ) } if self.block_production_started { @@ -761,7 +761,7 @@ impl ClientActor { delay = core::cmp::min( delay, - self.block_production_next_attempt.signed_duration_since(now).to_std().unwrap(), + self.block_production_next_attempt.signed_duration_since(now).to_std().unwrap_or(delay), ) } self.chunk_request_retry_next_attempt = self.run_timer( @@ -772,7 +772,7 @@ impl ClientActor { ); core::cmp::min( delay, - self.chunk_request_retry_next_attempt.signed_duration_since(now).to_std().unwrap(), + self.chunk_request_retry_next_attempt.signed_duration_since(now).to_std().unwrap_or(delay), ) } diff --git a/deny.toml b/deny.toml index 0b3111eb9cb..78be1219745 100644 --- a/deny.toml +++ b/deny.toml @@ -51,6 +51,8 @@ skip = [ { name = "syn", version = "=0.15.44" }, { name = "static_assertions", version = "=0.2.5" }, { name = "parking_lot", version = "=0.7.1" }, + { name = "parking_lot_core", version = "=0.4.0" }, + { name = "lock_api", version = "=0.1.5" }, { name = "smallvec", version = "=0.6.13" }, { name = "scopeguard", version = "=0.3.3" }, { name = "rustc-hex", version = "=1.0.0" }, From e5f3c123fbcb9968035583a7b19fbc8b7e10e1dd Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sun, 13 Sep 2020 03:56:09 -0700 Subject: [PATCH 27/82] Fix overflow / under-delete in overwrite_storage --- runtime/near-evm-runner/src/evm_state.rs | 29 ++++++++++++++++---- runtime/near-evm-runner/src/utils.rs | 35 ++++++++++++------------ 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index b167bd4f190..ec5218b20fd 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -64,7 +64,7 @@ pub trait EvmState { fn next_nonce(&mut self, address: &Address) -> Result { let mut account = self.get_account(address)?.unwrap_or_default(); let nonce = account.nonce; - account.nonce += U256::from(1); + account.nonce += account.nonce.saturating_add(U256::from(1)); self.set_account(address, &account)?; Ok(nonce) } @@ -131,13 +131,21 @@ pub struct StateStore { impl StateStore { fn overwrite_storage(&mut self, addr: [u8; 20]) { let address_key = addr.to_vec(); - let mut next_address_key = address_key.clone(); - *(next_address_key.last_mut().unwrap()) += 1; + // If address in the last, use RangeFrom to remove all elements until the end. + let keys: Vec<_> = if addr == [255; 20] { + self.storages.range(std::ops::RangeFrom { start: address_key }) + } else { + let next_address = utils::safe_next_address(&addr); - let range = - (std::ops::Bound::Excluded(address_key), std::ops::Bound::Excluded(next_address_key)); + let range = ( + std::ops::Bound::Excluded(address_key), + std::ops::Bound::Excluded(next_address.to_vec()), + ); - let keys: Vec<_> = self.storages.range(range).map(|(k, _)| k.clone()).collect(); + self.storages.range(range) + } + .map(|(k, _)| k.clone()) + .collect(); for k in keys.iter() { self.storages.remove(k); } @@ -444,6 +452,15 @@ mod test { assert_eq!(top.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); } + #[test] + fn test_overflows() { + let mut top = StateStore::default(); + let mut address = [0; 20]; + address[19] = 255; + top.overwrite_storage(address); + top.overwrite_storage([255; 20]); + } + #[test] fn self_destruct_tests() { let addr_0 = Address::repeat_byte(0); diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index ffd9226068f..2ac3d93cca7 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -6,6 +6,18 @@ use keccak_hash::keccak; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use vm::CreateContractAddress; +pub fn safe_next_address(addr: &[u8; 20]) -> [u8; 20] { + let mut expanded_addr = [0u8; 32]; + expanded_addr[12..].copy_from_slice(addr); + let mut result = [0u8; 32]; + U256::from_big_endian(&expanded_addr) + .saturating_add(U256::from(1u8)) + .to_big_endian(&mut result); + let mut address = [0u8; 20]; + address.copy_from_slice(&result[12..]); + address +} + pub fn internal_storage_key(address: &Address, key: [u8; 32]) -> [u8; 52] { let mut k = [0u8; 52]; k[..20].copy_from_slice(address.as_ref()); @@ -62,20 +74,6 @@ pub fn address_from_arr(arr: &[u8]) -> Address { Address::from(address) } -pub fn balance_to_u256(val: &Balance) -> U256 { - let mut bin = [0u8; 32]; - bin[16..].copy_from_slice(&val.to_be_bytes()); - bin.into() -} - -pub fn u256_to_balance(val: &U256) -> Balance { - let mut scratch = [0u8; 32]; - let mut bin = [0u8; 16]; - val.to_big_endian(&mut scratch); - bin.copy_from_slice(&scratch[16..]); - Balance::from_be_bytes(bin) -} - pub fn u256_to_arr(val: &U256) -> [u8; 32] { let mut result = [0u8; 32]; val.to_big_endian(&mut result); @@ -143,7 +141,10 @@ impl Balance { } impl Serialize for Balance { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + fn serialize( + &self, + serializer: S, + ) -> std::result::Result<::Ok, ::Error> where S: Serializer, { @@ -152,7 +153,7 @@ impl Serialize for Balance { } impl<'de> Deserialize<'de> for Balance { - fn deserialize(deserializer: D) -> Result>::Error> + fn deserialize(deserializer: D) -> std::result::Result>::Error> where D: Deserializer<'de>, { @@ -167,7 +168,7 @@ impl From for u128 { } } -pub fn format_log(topics: Vec, data: &[u8]) -> Result, std::io::Error> { +pub fn format_log(topics: Vec, data: &[u8]) -> std::result::Result, std::io::Error> { let mut result = Vec::with_capacity(1 + topics.len() * 32 + data.len()); result.write_u8(topics.len() as u8)?; for topic in topics.iter() { From d21cb9c52140fc9e9869bfc88fd3dadb78fdee9d Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Wed, 16 Sep 2020 06:58:58 -0700 Subject: [PATCH 28/82] Removing storage for given contract in EVM --- runtime/near-evm-runner/src/lib.rs | 13 +++++++-- runtime/near-vm-logic/src/dependencies.rs | 28 +++++++++++++++++-- .../near-vm-logic/src/mocks/mock_external.rs | 12 ++++++++ runtime/runtime/src/ext.rs | 23 ++++++++++++++- 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 61b5d458426..f1dce037b33 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -83,9 +83,12 @@ impl<'a> EvmState for EvmContext<'a> { } fn commit_changes(&mut self, other: &StateStore) -> Result<()> { - // TODO: figure out how to handle this on the top level. - // self.commit_self_destructs(&other.self_destructs); - // self.commit_self_destructs(&other.recreated); + for address in other.self_destructs.iter() { + self.clear_contract_info(address)?; + } + for address in other.recreated.iter() { + self.clear_contract_info(address)?; + } for (address, code) in other.code.iter() { self.set_code(&H160(*address), code)?; } @@ -141,6 +144,10 @@ impl<'a> EvmContext<'a> { } } + fn clear_contract_info(&mut self, other: &[u8; 20]) -> Result<()> { + self.ext.storage_remove_subtree(other) + } + pub fn deploy_code(&mut self, bytecode: Vec) -> Result
{ let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); self.add_balance(&sender, U256::from(self.attached_deposit))?; diff --git a/runtime/near-vm-logic/src/dependencies.rs b/runtime/near-vm-logic/src/dependencies.rs index 60f9074627c..db66e10c0be 100644 --- a/runtime/near-vm-logic/src/dependencies.rs +++ b/runtime/near-vm-logic/src/dependencies.rs @@ -111,13 +111,37 @@ pub trait External { /// /// # let mut external = MockedExternal::new(); /// external.storage_set(b"key42", b"value1337").unwrap(); - /// // Returns value if exists + /// // Returns Ok if exists /// assert_eq!(external.storage_remove(b"key42"), Ok(())); - /// // Returns None if there was no value + /// // Returns Ok if there was no value /// assert_eq!(external.storage_remove(b"no_value_key"), Ok(())); /// ``` fn storage_remove(&mut self, key: &[u8]) -> Result<()>; + /// Removes all keys under given suffix in the storage. + /// + /// # Arguments + /// + /// * `prefix` - a prefix for all keys to remove + /// + /// # Errors + /// + /// This function could return HostErrorOrStorageError::StorageError on underlying DB failure + /// + /// # Example + /// ``` + /// # use near_vm_logic::mocks::mock_external::MockedExternal; + /// # use near_vm_logic::External; + /// + /// # let mut external = MockedExternal::new(); + /// external.storage_set(b"key1", b"value1337").unwrap(); + /// external.storage_set(b"key2", b"value1337").unwrap(); + /// assert_eq!(external.storage_remove_subtree(b"key"), Ok(())); + /// assert!(!external.storage_has_key(b"key1").unwrap()); + /// assert!(!external.storage_has_key(b"key2").unwrap()); + /// ``` + fn storage_remove_subtree(&mut self, prefix: &[u8]) -> Result<()>; + /// Check whether key exists. Returns Ok(true) if key exists or Ok(false) otherwise /// /// # Arguments diff --git a/runtime/near-vm-logic/src/mocks/mock_external.rs b/runtime/near-vm-logic/src/mocks/mock_external.rs index 123a4534203..2f5906acf55 100644 --- a/runtime/near-vm-logic/src/mocks/mock_external.rs +++ b/runtime/near-vm-logic/src/mocks/mock_external.rs @@ -66,6 +66,18 @@ impl External for MockedExternal { Ok(()) } + fn storage_remove_subtree(&mut self, prefix: &[u8]) -> Result<()> { + let keys: Vec<_> = self + .fake_trie + .iter() + .filter_map(|(key, _)| if key.starts_with(prefix) { Some(key.clone()) } else { None }) + .collect(); + for key in keys { + self.fake_trie.remove(&key); + } + Ok(()) + } + fn storage_has_key(&mut self, key: &[u8]) -> Result { Ok(self.fake_trie.contains_key(key)) } diff --git a/runtime/runtime/src/ext.rs b/runtime/runtime/src/ext.rs index 804ef438a7a..e548528a499 100644 --- a/runtime/runtime/src/ext.rs +++ b/runtime/runtime/src/ext.rs @@ -11,7 +11,7 @@ use near_primitives::transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, FunctionCallAction, StakeAction, TransferAction, }; -use near_primitives::trie_key::TrieKey; +use near_primitives::trie_key::{trie_key_parsers, TrieKey}; use near_primitives::types::{AccountId, Balance, EpochId, EpochInfoProvider}; use near_primitives::utils::create_nonce_with_nonce; use near_store::{get_code, TrieUpdate, TrieUpdateValuePtr}; @@ -152,6 +152,27 @@ impl<'a> External for RuntimeExt<'a> { self.trie_update.get_ref(&storage_key).map(|x| x.is_some()).map_err(wrap_storage_error) } + fn storage_remove_subtree(&mut self, prefix: &[u8]) -> ExtResult<()> { + let data_keys = this + .trie_update + .iter(&trie_key_parsers::get_raw_prefix_for_contract_data(&self.account_id, prefix))? + .map(|raw_key| { + trie_key_parsers::parse_data_key_from_contract_data_key(&raw_key?, self.account_id) + .map_err(|_e| { + StorageError::StorageInconsistentState( + "Can't parse data key from raw key for ContractData".to_string(), + ) + }) + .map(Vec::from) + }) + .collect::, _>>()?; + for key in data_keys { + state_update + .remove(TrieKey::ContractData { account_id: self.account_id.clone(), key })?; + } + Ok(()) + } + fn create_receipt(&mut self, receipt_indices: Vec, receiver_id: String) -> ExtResult { let mut input_data_ids = vec![]; for receipt_index in receipt_indices { From c2131d0e6630ebd3e0e744c89b03db006bdf1749 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sun, 20 Sep 2020 23:19:03 -0700 Subject: [PATCH 29/82] Fix approximation of meta transactions in EVM --- Cargo.lock | 1 + core/crypto/src/signature.rs | 12 ++++ runtime/near-evm-runner/Cargo.toml | 2 + runtime/near-evm-runner/src/lib.rs | 55 ++++++++++++++++++- runtime/near-evm-runner/src/utils.rs | 36 ++++++++++++ runtime/near-evm-runner/tests/standard_ops.rs | 20 ++++++- runtime/near-evm-runner/tests/utils.rs | 43 +++++++++++++++ runtime/near-vm-errors/src/lib.rs | 2 + runtime/runtime/src/actions.rs | 1 + 9 files changed, 169 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f5a351c03f9..46e78048576 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2869,6 +2869,7 @@ dependencies = [ "lazy-static-include", "lazy_static", "libsecp256k1", + "near-crypto", "near-runtime-fees", "near-vm-errors", "near-vm-logic", diff --git a/core/crypto/src/signature.rs b/core/crypto/src/signature.rs index 2e1f62838ac..9c3d4a55f20 100644 --- a/core/crypto/src/signature.rs +++ b/core/crypto/src/signature.rs @@ -75,6 +75,12 @@ impl std::fmt::Debug for Secp256K1PublicKey { } } +impl From for [u8; 64] { + fn from(pubkey: Secp256K1PublicKey) -> Self { + pubkey.0 + } +} + impl PartialEq for Secp256K1PublicKey { fn eq(&self, other: &Self) -> bool { self.0[..] == other.0[..] @@ -479,6 +485,12 @@ impl Debug for Secp256K1Signature { } } +impl From for [u8; 65] { + fn from(sig: Secp256K1Signature) -> [u8; 65] { + sig.0 + } +} + /// Signature container supporting different curves. #[derive(Clone, PartialEq, Eq)] pub enum Signature { diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 3e85496668d..7215a1b06f8 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -40,3 +40,5 @@ ethabi-contract = "8.0.0" ethabi-derive = "8.0.0" lazy_static = "1.4" lazy-static-include = "2.2.2" + +near-crypto = { path = "../../core/crypto" } \ No newline at end of file diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index f1dce037b33..96f7f6157ca 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -4,6 +4,7 @@ extern crate enum_primitive_derive; use borsh::{BorshDeserialize, BorshSerialize}; use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; +use keccak_hash::keccak; use near_runtime_fees::RuntimeFeesConfig; use near_vm_errors::{EvmError, FunctionCallError, VMError}; @@ -15,6 +16,7 @@ use crate::evm_state::{EvmAccount, EvmState, StateStore}; use crate::types::{ AddressArg, GetStorageAtArgs, Result, TransferArgs, ViewCallArgs, WithdrawArgs, }; +use crate::utils::ecrecover_address; mod builtins; mod evm_state; @@ -25,6 +27,7 @@ pub mod utils; pub struct EvmContext<'a> { ext: &'a mut dyn External, + signer_id: AccountId, predecessor_id: AccountId, current_amount: Balance, attached_deposit: Balance, @@ -115,6 +118,7 @@ impl<'a> EvmContext<'a> { config: &'a VMConfig, fees_config: &'a RuntimeFeesConfig, current_amount: Balance, + signer_id: AccountId, predecessor_id: AccountId, attached_deposit: Balance, storage_usage: StorageUsage, @@ -128,6 +132,7 @@ impl<'a> EvmContext<'a> { }; Self { ext, + signer_id, predecessor_id, current_amount, attached_deposit, @@ -163,14 +168,44 @@ impl<'a> EvmContext<'a> { ) } + /// Make an EVM transaction. Calls `contract_address` with RLP encoded `input`. Execution + /// continues until all EVM messages have been processed. We expect this to behave identically + /// to an Ethereum transaction, however there may be some edge cases. pub fn call_function(&mut self, args: Vec) -> Result> { if args.len() <= 20 { return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); } let contract_address = Address::from_slice(&args[..20]); let input = &args[20..]; + let origin = utils::near_account_id_to_evm_address(&self.signer_id); let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); self.add_balance(&sender, U256::from(self.attached_deposit))?; + let value = + if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; + interpreter::call(self, &origin, &sender, value, 0, &contract_address, &input, true) + .map(|rd| rd.to_vec()) + } + + /// Make an EVM call via a meta transaction pattern. + /// Specifically, providing signature and NEAREvm message that determines which contract and arguments to be called. + /// Format + /// 0..95: signature: v - 32 bytes, s - 32 bytes, r - 32 bytes + /// 96..115: contract_id: address for contract to call + /// 116..: RLP encoded arguments. + pub fn meta_call_function(&mut self, args: Vec) -> Result> { + if args.len() <= 116 { + return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); + } + let mut signature: [u8; 96] = [0; 96]; + signature.copy_from_slice(&args[..96]); + let args = &args[96..]; + let sender = ecrecover_address(&keccak(args).0, &signature)?; + if sender == Address::zero() { + return Err(VMLogicError::EvmError(EvmError::InvalidEcRecoverSignature)); + } + let contract_address = Address::from_slice(&args[..20]); + let input = &args[20..]; + self.add_balance(&sender, U256::from(self.attached_deposit))?; let value = if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; interpreter::call(self, &sender, &sender, value, 0, &contract_address, &input, true) @@ -312,6 +347,7 @@ pub fn run_evm( ext: &mut dyn External, config: &VMConfig, fees_config: &RuntimeFeesConfig, + signer_id: &AccountId, predecessor_id: &AccountId, amount: Balance, attached_deposit: Balance, @@ -328,6 +364,7 @@ pub fn run_evm( // This is total amount of all $NEAR inside this EVM. // Should already validate that will not overflow external to this call. amount.checked_add(attached_deposit).unwrap_or(amount), + signer_id.clone(), predecessor_id.clone(), attached_deposit, storage_usage, @@ -338,11 +375,14 @@ pub fn run_evm( // Change the state methods. "deploy_code" => context.deploy_code(args).map(|address| utils::address_to_vec(&address)), "call_function" => context.call_function(args), + "call" => context.call_function(args), + "meta_call" => context.meta_call_function(args), "deposit" => context.deposit(args).map(|balance| utils::u256_to_arr(&balance).to_vec()), "withdraw" => context.withdraw(args).map(|_| vec![]), "transfer" => context.transfer(args).map(|_| vec![]), // View methods. - "view_call_function" => context.view_call_function(args), + "view_function_call" => context.view_call_function(args), + "view" => context.view_call_function(args), "get_code" => context.get_code(args), "get_storage_at" => context.get_storage_at(args), "get_nonce" => context.get_nonce(args).map(|nonce| utils::u256_to_arr(&nonce).to_vec()), @@ -391,7 +431,18 @@ mod tests { fees_config: &'a RuntimeFeesConfig, account_id: &str, ) -> EvmContext<'a> { - EvmContext::new(external, vm_config, fees_config, 0, account_id.to_string(), 0, 0, 0, false) + EvmContext::new( + external, + vm_config, + fees_config, + 0, + account_id.to_string(), + account_id.to_string(), + 0, + 0, + 0, + false, + ) } #[test] diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index 2ac3d93cca7..93551e07e52 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -6,6 +6,10 @@ use keccak_hash::keccak; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use vm::CreateContractAddress; +use near_vm_errors::{EvmError, VMLogicError}; + +use crate::types; + pub fn safe_next_address(addr: &[u8; 20]) -> [u8; 20] { let mut expanded_addr = [0u8; 32]; expanded_addr[12..].copy_from_slice(addr); @@ -177,3 +181,35 @@ pub fn format_log(topics: Vec, data: &[u8]) -> std::result::Result result.write(data)?; Ok(result) } + +/// Given signature and data, validates that signature is valid for given data and returns ecrecover address. +pub fn ecrecover_address(hash: &[u8; 32], signature: &[u8; 96]) -> types::Result
{ + use sha3::Digest; + + let hash = secp256k1::Message::parse(&H256::from_slice(hash).0); + let v = &signature[..32]; + let r = &signature[32..64]; + let s = &signature[64..96]; + + let bit = match v[31] { + 27..=30 => v[31] - 27, + _ => { + // ?? + return Ok(Address::zero()); + } + }; + + let mut sig = [0u8; 64]; + sig[..32].copy_from_slice(&r); + sig[32..].copy_from_slice(&s); + let s = secp256k1::Signature::parse(&sig); + + if let Ok(rec_id) = secp256k1::RecoveryId::parse(bit) { + if let Ok(p) = secp256k1::recover(&hash, &s, &rec_id) { + // recover returns the 65-byte key, but addresses come from the raw 64-byte key + let r = sha3::Keccak256::digest(&p.serialize()[1..]); + return Ok(address_from_arr(&r[12..])); + } + } + Err(VMLogicError::EvmError(EvmError::InvalidEcRecoverSignature)) +} diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index de2e86a981a..6578f27170f 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -5,6 +5,7 @@ use borsh::BorshSerialize; use ethabi_contract::use_contract; use ethereum_types::{Address, H256, U256}; +use near_crypto::{InMemorySigner, KeyType}; use near_evm_runner::types::{TransferArgs, WithdrawArgs}; use near_evm_runner::utils::{ address_from_arr, address_to_vec, encode_call_function_args, encode_view_call_function_args, @@ -15,7 +16,9 @@ use near_vm_errors::{EvmError, VMLogicError}; use near_vm_logic::mocks::mock_external::MockedExternal; use near_vm_logic::VMConfig; -use crate::utils::{accounts, create_context, setup}; +use crate::utils::{ + accounts, create_context, encode_meta_call_function_args, public_key_to_address, setup, +}; mod utils; @@ -239,3 +242,18 @@ fn test_solidity_accurate_storage_on_selfdestruct() { let raw = context.call_function(encode_call_function_args(factory_addr, input)).unwrap(); assert!(create2factory::functions::test_double_deploy::decode_output(&raw).unwrap()); } + +#[test] +fn test_meta_call() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + let signer = InMemorySigner::from_random("doesnt".to_string(), KeyType::SECP256K1); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let (input, _) = soltest::functions::return_some_funds::call(); + let _ = context + .meta_call_function(encode_meta_call_function_args(&signer, test_addr, input)) + .unwrap(); + let signer_addr = public_key_to_address(signer.public_key); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); + assert_eq!(context.get_balance(signer_addr.0.to_vec()).unwrap(), U256::from(50)); +} diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index c937363c949..bad6ffa0a6d 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -1,3 +1,7 @@ +use ethereum_types::Address; +use keccak_hash::keccak_256; +use near_crypto::{PublicKey, Signature, Signer}; +use near_evm_runner::utils::encode_call_function_args; use near_evm_runner::EvmContext; use near_runtime_fees::RuntimeFeesConfig; use near_vm_logic::mocks::mock_external::MockedExternal; @@ -28,9 +32,48 @@ pub fn create_context<'a>( fees_config, 1000, account_id.to_string(), + account_id.to_string(), attached_deposit, 0, 10u64.pow(14), false, ) } + +fn hash(message: &[u8]) -> [u8; 32] { + let mut bytes = [0u8; 32]; + keccak_256(message, &mut bytes); + bytes +} + +pub fn public_key_to_address(public_key: PublicKey) -> Address { + match public_key { + PublicKey::ED25519(_) => panic!("Wrong PublicKey"), + PublicKey::SECP256K1(pubkey) => { + let pk: [u8; 64] = pubkey.into(); + let bytes = hash(&pk); + let mut result = Address::zero(); + result.as_bytes_mut().copy_from_slice(&bytes[12..]); + result + } + } +} + +pub fn encode_meta_call_function_args( + signer: &dyn Signer, + address: Address, + input: Vec, +) -> Vec { + let call_args = encode_call_function_args(address, input); + let hash = hash(&call_args); + match signer.sign(&hash) { + Signature::ED25519(_) => panic!("Wrong Signer"), + Signature::SECP256K1(sig) => { + let sig: [u8; 65] = sig.into(); + let mut vsr = vec![0u8; 96]; + vsr[31] = sig[64] + 27; + vsr[32..].copy_from_slice(&sig[..64]); + [vsr, call_args].concat() + } + } +} diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index 4def95f3cff..73f16b47448 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -194,6 +194,8 @@ pub enum EvmError { IntegerOverflow, /// Method not found. MethodNotFound, + /// Invalid signature when recovering. + InvalidEcRecoverSignature, } #[derive(Debug, Clone, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 0047d4ca527..715f592cf1e 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -55,6 +55,7 @@ pub(crate) fn execute_function_call( runtime_ext, &config.wasm_config, &config.transaction_costs, + &action_receipt.signer_id, predecessor_id, account.amount, function_call.deposit, From 77edc0b08b19745b0b7d74a55f9e5433ef795f84 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 21 Sep 2020 09:34:50 -0700 Subject: [PATCH 30/82] Updated meta tx to include domain / types. Updating to use evm/*.evm as accounts that have evm contracts --- core/primitives/src/utils.rs | 13 +------- neard/src/config.rs | 4 +-- runtime/near-evm-runner/src/lib.rs | 18 +++++++++-- runtime/near-evm-runner/src/utils.rs | 35 +++++++++++++++++++++ runtime/near-evm-runner/tests/utils.rs | 22 ++++++------- runtime/runtime/src/actions.rs | 6 ++-- runtime/runtime/src/ext.rs | 24 ++++++++++---- test-utils/testlib/src/node/runtime_node.rs | 4 +-- 8 files changed, 87 insertions(+), 39 deletions(-) diff --git a/core/primitives/src/utils.rs b/core/primitives/src/utils.rs index 1fe621dfea5..e74a4dc5c8d 100644 --- a/core/primitives/src/utils.rs +++ b/core/primitives/src/utils.rs @@ -11,7 +11,7 @@ use serde; use lazy_static::lazy_static; -use crate::hash::{hash, CryptoHash, Digest}; +use crate::hash::{hash, CryptoHash}; use crate::types::{AccountId, NumSeats, NumShards, ShardId}; pub const MIN_ACCOUNT_ID_LEN: usize = 2; @@ -20,17 +20,6 @@ pub const MAX_ACCOUNT_ID_LEN: usize = 64; /// Number of nano seconds in a second. const NS_IN_SECOND: u64 = 1_000_000_000; -lazy_static! { - /// Predetermined code hash used for EVM precompile. - pub static ref EVM_CODE_HASH: CryptoHash = code_hash(1); -} - -fn code_hash(num: u8) -> CryptoHash { - let mut buf = [0; 32]; - buf[0] = num; - return CryptoHash(Digest(buf)); -} - pub fn get_block_shard_id(block_hash: &CryptoHash, shard_id: ShardId) -> Vec { let mut res = Vec::with_capacity(40); res.extend_from_slice(block_hash.as_ref()); diff --git a/neard/src/config.rs b/neard/src/config.rs index b2c03d39ca1..a723f145a2f 100644 --- a/neard/src/config.rs +++ b/neard/src/config.rs @@ -28,7 +28,7 @@ use near_primitives::types::{ AccountId, AccountInfo, Balance, BlockHeightDelta, EpochHeight, Gas, NumBlocks, NumSeats, NumShards, ShardId, }; -use near_primitives::utils::{generate_random_string, get_num_seats_per_shard, EVM_CODE_HASH}; +use near_primitives::utils::{generate_random_string, get_num_seats_per_shard}; use near_primitives::validator_signer::{InMemoryValidatorSigner, ValidatorSigner}; use near_primitives::version::PROTOCOL_VERSION; #[cfg(feature = "rosetta_rpc")] @@ -822,7 +822,7 @@ pub fn init_configs( &signer.public_key(), TESTING_INIT_BALANCE, 0, - *EVM_CODE_HASH, + CryptoHash::default(), ); add_protocol_account(&mut records); diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 96f7f6157ca..43542832795 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -4,7 +4,6 @@ extern crate enum_primitive_derive; use borsh::{BorshDeserialize, BorshSerialize}; use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; -use keccak_hash::keccak; use near_runtime_fees::RuntimeFeesConfig; use near_vm_errors::{EvmError, FunctionCallError, VMError}; @@ -16,7 +15,7 @@ use crate::evm_state::{EvmAccount, EvmState, StateStore}; use crate::types::{ AddressArg, GetStorageAtArgs, Result, TransferArgs, ViewCallArgs, WithdrawArgs, }; -use crate::utils::ecrecover_address; +use crate::utils::{ecrecover_address, near_erc721_domain, prepare_meta_call_args}; mod builtins; mod evm_state; @@ -27,6 +26,7 @@ pub mod utils; pub struct EvmContext<'a> { ext: &'a mut dyn External, + account_id: AccountId, signer_id: AccountId, predecessor_id: AccountId, current_amount: Balance, @@ -35,6 +35,7 @@ pub struct EvmContext<'a> { pub logs: Vec, gas_counter: GasCounter, fees_config: &'a RuntimeFeesConfig, + domain_separator: [u8; 32], } enum KeyPrefix { @@ -118,6 +119,7 @@ impl<'a> EvmContext<'a> { config: &'a VMConfig, fees_config: &'a RuntimeFeesConfig, current_amount: Balance, + account_id: AccountId, signer_id: AccountId, predecessor_id: AccountId, attached_deposit: Balance, @@ -130,8 +132,11 @@ impl<'a> EvmContext<'a> { } else { config.limit_config.max_gas_burnt }; + // TODO: pass chain id from ??? genesis / config. + let domain_separator = near_erc721_domain(U256::from(0x4e454152)); Self { ext, + account_id, signer_id, predecessor_id, current_amount, @@ -146,6 +151,7 @@ impl<'a> EvmContext<'a> { None, ), fees_config, + domain_separator, } } @@ -199,7 +205,10 @@ impl<'a> EvmContext<'a> { let mut signature: [u8; 96] = [0; 96]; signature.copy_from_slice(&args[..96]); let args = &args[96..]; - let sender = ecrecover_address(&keccak(args).0, &signature)?; + let sender = ecrecover_address( + &prepare_meta_call_args(&self.domain_separator, &self.account_id, args), + &signature, + )?; if sender == Address::zero() { return Err(VMLogicError::EvmError(EvmError::InvalidEcRecoverSignature)); } @@ -347,6 +356,7 @@ pub fn run_evm( ext: &mut dyn External, config: &VMConfig, fees_config: &RuntimeFeesConfig, + account_id: &AccountId, signer_id: &AccountId, predecessor_id: &AccountId, amount: Balance, @@ -364,6 +374,7 @@ pub fn run_evm( // This is total amount of all $NEAR inside this EVM. // Should already validate that will not overflow external to this call. amount.checked_add(attached_deposit).unwrap_or(amount), + account_id.clone(), signer_id.clone(), predecessor_id.clone(), attached_deposit, @@ -436,6 +447,7 @@ mod tests { vm_config, fees_config, 0, + "evm".to_string(), account_id.to_string(), account_id.to_string(), 0, diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index 93551e07e52..a3f88b872bd 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -9,6 +9,7 @@ use vm::CreateContractAddress; use near_vm_errors::{EvmError, VMLogicError}; use crate::types; +use near_vm_logic::types::AccountId; pub fn safe_next_address(addr: &[u8; 20]) -> [u8; 20] { let mut expanded_addr = [0u8; 32]; @@ -182,6 +183,40 @@ pub fn format_log(topics: Vec, data: &[u8]) -> std::result::Result Ok(result) } +pub fn near_erc721_domain(chain_id: U256) -> [u8; 32] { + let mut bytes = Vec::with_capacity(70); + bytes.extend_from_slice( + &keccak("EIP712Domain(string name,string version,uint256 chainId)".as_bytes()).as_bytes(), + ); + bytes.extend_from_slice(b"NEAR"); + bytes.extend_from_slice(&[0x01]); + bytes.extend_from_slice(&u256_to_arr(&chain_id)); + keccak(&bytes).into() +} + +pub fn prepare_meta_call_args( + domain_separator: &[u8; 32], + account_id: &AccountId, + args: &[u8], +) -> [u8; 32] { + let mut bytes = Vec::with_capacity(32 + account_id.len() + args.len()); + bytes.extend_from_slice( + &keccak( + "NearTx(string evmId, uint256 nonce, address contractAddress, bytes arguments)" + .as_bytes(), + ) + .as_bytes(), + ); + bytes.extend_from_slice(account_id.as_bytes()); + bytes.extend_from_slice(args); + let message: [u8; 32] = keccak(&bytes).into(); + let mut bytes = Vec::with_capacity(2 + 32 + 32); + bytes.extend_from_slice(&[0x19, 0x01]); + bytes.extend_from_slice(domain_separator); + bytes.extend_from_slice(&message); + keccak(&bytes).into() +} + /// Given signature and data, validates that signature is valid for given data and returns ecrecover address. pub fn ecrecover_address(hash: &[u8; 32], signature: &[u8; 96]) -> types::Result
{ use sha3::Digest; diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index bad6ffa0a6d..7b0537f4d5a 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -1,7 +1,9 @@ -use ethereum_types::Address; -use keccak_hash::keccak_256; +use ethereum_types::{Address, U256}; +use keccak_hash::keccak; use near_crypto::{PublicKey, Signature, Signer}; -use near_evm_runner::utils::encode_call_function_args; +use near_evm_runner::utils::{ + encode_call_function_args, near_erc721_domain, prepare_meta_call_args, +}; use near_evm_runner::EvmContext; use near_runtime_fees::RuntimeFeesConfig; use near_vm_logic::mocks::mock_external::MockedExternal; @@ -31,6 +33,7 @@ pub fn create_context<'a>( vm_config, fees_config, 1000, + "evm".to_string(), account_id.to_string(), account_id.to_string(), attached_deposit, @@ -40,18 +43,12 @@ pub fn create_context<'a>( ) } -fn hash(message: &[u8]) -> [u8; 32] { - let mut bytes = [0u8; 32]; - keccak_256(message, &mut bytes); - bytes -} - pub fn public_key_to_address(public_key: PublicKey) -> Address { match public_key { PublicKey::ED25519(_) => panic!("Wrong PublicKey"), PublicKey::SECP256K1(pubkey) => { let pk: [u8; 64] = pubkey.into(); - let bytes = hash(&pk); + let bytes = keccak(&pk.to_vec()); let mut result = Address::zero(); result.as_bytes_mut().copy_from_slice(&bytes[12..]); result @@ -64,9 +61,10 @@ pub fn encode_meta_call_function_args( address: Address, input: Vec, ) -> Vec { + let domain_separator = near_erc721_domain(U256::from(0x4e454152)); let call_args = encode_call_function_args(address, input); - let hash = hash(&call_args); - match signer.sign(&hash) { + let args = prepare_meta_call_args(&domain_separator, &"evm".to_string(), &call_args); + match signer.sign(&args) { Signature::ED25519(_) => panic!("Wrong Signer"), Signature::SECP256K1(sig) => { let sig: [u8; 65] = sig.into(); diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 715f592cf1e..bf7508df7a2 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -12,7 +12,7 @@ use near_primitives::transaction::{ }; use near_primitives::types::{AccountId, EpochInfoProvider, ValidatorStake}; use near_primitives::utils::{ - is_valid_account_id, is_valid_sub_account_id, is_valid_top_level_account_id, EVM_CODE_HASH, + is_valid_account_id, is_valid_sub_account_id, is_valid_top_level_account_id, }; use near_primitives::version::{ ProtocolVersion, CORRECT_RANDOM_VALUE_PROTOCOL_VERSION, @@ -50,11 +50,13 @@ pub(crate) fn execute_function_call( is_last_action: bool, is_view: bool, ) -> (Option, Option) { - if account.code_hash == *EVM_CODE_HASH { + let account_id = runtime_ext.account_id(); + if account_id == "evm" || account_id.ends_with(".evm") { near_evm_runner::run_evm( runtime_ext, &config.wasm_config, &config.transaction_costs, + &account_id, &action_receipt.signer_id, predecessor_id, account.amount, diff --git a/runtime/runtime/src/ext.rs b/runtime/runtime/src/ext.rs index e548528a499..3abb2ae5826 100644 --- a/runtime/runtime/src/ext.rs +++ b/runtime/runtime/src/ext.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use borsh::BorshDeserialize; use log::debug; @@ -15,8 +17,8 @@ use near_primitives::trie_key::{trie_key_parsers, TrieKey}; use near_primitives::types::{AccountId, Balance, EpochId, EpochInfoProvider}; use near_primitives::utils::create_nonce_with_nonce; use near_store::{get_code, TrieUpdate, TrieUpdateValuePtr}; +use near_vm_errors::InconsistentStateError; use near_vm_logic::{External, HostError, VMLogicError, ValuePtr}; -use std::sync::Arc; pub struct RuntimeExt<'a> { trie_update: &'a mut TrieUpdate, @@ -153,9 +155,14 @@ impl<'a> External for RuntimeExt<'a> { } fn storage_remove_subtree(&mut self, prefix: &[u8]) -> ExtResult<()> { - let data_keys = this + let data_keys = self .trie_update - .iter(&trie_key_parsers::get_raw_prefix_for_contract_data(&self.account_id, prefix))? + .iter(&trie_key_parsers::get_raw_prefix_for_contract_data(&self.account_id, prefix)) + .map_err(|err| { + VMLogicError::InconsistentStateError(InconsistentStateError::StorageError( + err.to_string(), + )) + })? .map(|raw_key| { trie_key_parsers::parse_data_key_from_contract_data_key(&raw_key?, self.account_id) .map_err(|_e| { @@ -165,10 +172,15 @@ impl<'a> External for RuntimeExt<'a> { }) .map(Vec::from) }) - .collect::, _>>()?; + .collect::, _>>() + .map_err(|err| { + VMLogicError::InconsistentStateError(InconsistentStateError::StorageError( + err.to_string(), + )) + })?; for key in data_keys { - state_update - .remove(TrieKey::ContractData { account_id: self.account_id.clone(), key })?; + self.trie_update + .remove(TrieKey::ContractData { account_id: self.account_id.clone(), key }); } Ok(()) } diff --git a/test-utils/testlib/src/node/runtime_node.rs b/test-utils/testlib/src/node/runtime_node.rs index 101ebe8208d..c345b54c83d 100644 --- a/test-utils/testlib/src/node/runtime_node.rs +++ b/test-utils/testlib/src/node/runtime_node.rs @@ -3,9 +3,9 @@ use std::sync::{Arc, RwLock}; use near_chain_configs::Genesis; use near_crypto::{InMemorySigner, KeyType, Signer}; use near_primitives::account::Account; +use near_primitives::hash::CryptoHash; use near_primitives::state_record::StateRecord; use near_primitives::types::AccountId; -use near_primitives::utils::EVM_CODE_HASH; use neard::config::{GenesisExt, TESTING_INIT_BALANCE}; use crate::node::Node; @@ -31,7 +31,7 @@ impl RuntimeNode { account: Account { amount: TESTING_INIT_BALANCE, locked: 0, - code_hash: *EVM_CODE_HASH, + code_hash: CryptoHash::default(), storage_usage: 0, }, }); From 8e546affd2f4506be7d89f4176f5ebff20a4d6b3 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sun, 27 Sep 2020 04:38:09 -0700 Subject: [PATCH 31/82] Adding nonce to meta_call --- runtime/near-evm-runner/src/lib.rs | 12 ++++++++--- runtime/near-evm-runner/src/types.rs | 21 ++++++++++--------- runtime/near-evm-runner/src/utils.rs | 2 ++ runtime/near-evm-runner/tests/standard_ops.rs | 9 +++++--- runtime/near-evm-runner/tests/utils.rs | 7 ++++--- runtime/near-vm-errors/src/lib.rs | 2 ++ 6 files changed, 34 insertions(+), 19 deletions(-) diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 43542832795..e82fd7e3745 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -199,19 +199,23 @@ impl<'a> EvmContext<'a> { /// 96..115: contract_id: address for contract to call /// 116..: RLP encoded arguments. pub fn meta_call_function(&mut self, args: Vec) -> Result> { - if args.len() <= 116 { + if args.len() <= 148 { return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); } let mut signature: [u8; 96] = [0; 96]; signature.copy_from_slice(&args[..96]); - let args = &args[96..]; + let nonce = U256::from_big_endian(&args[96..128]); + let args = &args[128..]; let sender = ecrecover_address( - &prepare_meta_call_args(&self.domain_separator, &self.account_id, args), + &prepare_meta_call_args(&self.domain_separator, &self.account_id, nonce, args), &signature, )?; if sender == Address::zero() { return Err(VMLogicError::EvmError(EvmError::InvalidEcRecoverSignature)); } + if self.next_nonce(&sender)? != nonce { + return Err(VMLogicError::EvmError(EvmError::InvalidNonce)); + } let contract_address = Address::from_slice(&args[..20]); let input = &args[20..]; self.add_balance(&sender, U256::from(self.attached_deposit))?; @@ -385,6 +389,7 @@ pub fn run_evm( let result = match method_name.as_str() { // Change the state methods. "deploy_code" => context.deploy_code(args).map(|address| utils::address_to_vec(&address)), + // TODO: remove this function name if no one is using it. "call_function" => context.call_function(args), "call" => context.call_function(args), "meta_call" => context.meta_call_function(args), @@ -392,6 +397,7 @@ pub fn run_evm( "withdraw" => context.withdraw(args).map(|_| vec![]), "transfer" => context.transfer(args).map(|_| vec![]), // View methods. + // TODO: remove this function name if no one is using it. "view_function_call" => context.view_call_function(args), "view" => context.view_call_function(args), "get_code" => context.get_code(args), diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index cb8c074fc9c..46bdbd16c37 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -1,8 +1,9 @@ +use std::io::{Read, Write}; + use borsh::{BorshDeserialize, BorshSerialize}; use near_vm_errors::VMLogicError; use near_vm_logic::types::AccountId; -use std::io::{Read, Write}; pub type RawAddress = [u8; 20]; pub type RawHash = [u8; 32]; @@ -15,14 +16,6 @@ pub struct AddressArg { pub address: RawAddress, } -#[derive(Debug, Eq, PartialEq)] -pub struct ViewCallArgs { - pub sender: RawAddress, - pub address: RawAddress, - pub amount: RawU256, - pub args: Vec, -} - #[derive(BorshSerialize, BorshDeserialize)] pub struct GetStorageAtArgs { pub address: RawAddress, @@ -41,6 +34,14 @@ pub struct TransferArgs { pub amount: RawU256, } +#[derive(Debug, Eq, PartialEq)] +pub struct ViewCallArgs { + pub sender: RawAddress, + pub address: RawAddress, + pub amount: RawU256, + pub args: Vec, +} + impl BorshSerialize for ViewCallArgs { fn serialize(&self, writer: &mut W) -> std::io::Result<()> { writer.write(&self.sender)?; @@ -62,7 +63,7 @@ impl BorshDeserialize for ViewCallArgs { let sender = RawAddress::deserialize(buf)?; let address = RawAddress::deserialize(buf)?; let amount = RawU256::deserialize(buf)?; - let mut args = Vec::new(); + let mut args = Vec::with_capacity(buf.len()); buf.read_to_end(&mut args)?; Ok(Self { sender, address, amount, args }) } diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index a3f88b872bd..7b9d2064f42 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -197,6 +197,7 @@ pub fn near_erc721_domain(chain_id: U256) -> [u8; 32] { pub fn prepare_meta_call_args( domain_separator: &[u8; 32], account_id: &AccountId, + nonce: U256, args: &[u8], ) -> [u8; 32] { let mut bytes = Vec::with_capacity(32 + account_id.len() + args.len()); @@ -208,6 +209,7 @@ pub fn prepare_meta_call_args( .as_bytes(), ); bytes.extend_from_slice(account_id.as_bytes()); + bytes.extend_from_slice(&u256_to_arr(&nonce)); bytes.extend_from_slice(args); let message: [u8; 32] = keccak(&bytes).into(); let mut bytes = Vec::with_capacity(2 + 32 + 32); diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 6578f27170f..e4a49d91535 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -250,10 +250,13 @@ fn test_meta_call() { let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); let (input, _) = soltest::functions::return_some_funds::call(); - let _ = context - .meta_call_function(encode_meta_call_function_args(&signer, test_addr, input)) - .unwrap(); + let meta_tx = encode_meta_call_function_args(&signer, test_addr, U256::from(0), input); + let _ = context.meta_call_function(meta_tx.clone()).unwrap(); let signer_addr = public_key_to_address(signer.public_key); assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); assert_eq!(context.get_balance(signer_addr.0.to_vec()).unwrap(), U256::from(50)); + assert_eq!( + context.meta_call_function(meta_tx).unwrap_err().to_string(), + "EvmError(InvalidNonce)" + ); } diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index 7b0537f4d5a..bc42ee3271b 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -2,7 +2,7 @@ use ethereum_types::{Address, U256}; use keccak_hash::keccak; use near_crypto::{PublicKey, Signature, Signer}; use near_evm_runner::utils::{ - encode_call_function_args, near_erc721_domain, prepare_meta_call_args, + encode_call_function_args, near_erc721_domain, prepare_meta_call_args, u256_to_arr, }; use near_evm_runner::EvmContext; use near_runtime_fees::RuntimeFeesConfig; @@ -59,11 +59,12 @@ pub fn public_key_to_address(public_key: PublicKey) -> Address { pub fn encode_meta_call_function_args( signer: &dyn Signer, address: Address, + nonce: U256, input: Vec, ) -> Vec { let domain_separator = near_erc721_domain(U256::from(0x4e454152)); let call_args = encode_call_function_args(address, input); - let args = prepare_meta_call_args(&domain_separator, &"evm".to_string(), &call_args); + let args = prepare_meta_call_args(&domain_separator, &"evm".to_string(), nonce, &call_args); match signer.sign(&args) { Signature::ED25519(_) => panic!("Wrong Signer"), Signature::SECP256K1(sig) => { @@ -71,7 +72,7 @@ pub fn encode_meta_call_function_args( let mut vsr = vec![0u8; 96]; vsr[31] = sig[64] + 27; vsr[32..].copy_from_slice(&sig[..64]); - [vsr, call_args].concat() + [vsr, u256_to_arr(&nonce).to_vec(), call_args].concat() } } } diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index 73f16b47448..8d5139db8cc 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -196,6 +196,8 @@ pub enum EvmError { MethodNotFound, /// Invalid signature when recovering. InvalidEcRecoverSignature, + /// Invalid nonce. + InvalidNonce, } #[derive(Debug, Clone, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] From 600cbf2f3c8e7c07506eeeb2cbd91b892512e62e Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sun, 27 Sep 2020 05:48:06 -0700 Subject: [PATCH 32/82] Support creating sub-evms. Moved is_valid_account and related to runtime-utils --- Cargo.lock | 7 +- chain/jsonrpc/Cargo.toml | 1 + chain/jsonrpc/src/lib.rs | 2 +- core/primitives/Cargo.toml | 1 - core/primitives/src/errors.rs | 4 +- core/primitives/src/test_utils.rs | 9 +- core/primitives/src/utils.rs | 270 +---------------- .../genesis-csv-to-json/src/csv_parser.rs | 3 +- runtime/near-evm-runner/Cargo.toml | 3 +- runtime/near-evm-runner/src/evm_state.rs | 2 +- runtime/near-evm-runner/src/lib.rs | 37 ++- runtime/near-runtime-fees/src/lib.rs | 7 + runtime/near-runtime-utils/Cargo.toml | 2 + runtime/near-runtime-utils/src/lib.rs | 280 ++++++++++++++++++ runtime/near-vm-errors/src/lib.rs | 4 + runtime/runtime/src/actions.rs | 10 +- runtime/runtime/src/state_viewer.rs | 2 +- runtime/runtime/src/verifier.rs | 2 +- test-utils/testlib/src/standard_test_cases.rs | 39 +++ tests/test_cases_runtime.rs | 12 + 20 files changed, 412 insertions(+), 285 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46e78048576..ec707dcf121 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2871,6 +2871,7 @@ dependencies = [ "libsecp256k1", "near-crypto", "near-runtime-fees", + "near-runtime-utils", "near-vm-errors", "near-vm-logic", "num-bigint 0.3.0", @@ -2919,6 +2920,7 @@ dependencies = [ "near-network", "near-primitives", "near-rpc-error-macro", + "near-runtime-utils", "prometheus", "serde", "serde_json", @@ -3027,7 +3029,6 @@ dependencies = [ "easy-ext", "hex", "jemallocator", - "lazy_static", "near-crypto", "near-rpc-error-macro", "near-vm-errors", @@ -3123,6 +3124,10 @@ dependencies = [ [[package]] name = "near-runtime-utils" version = "2.2.0" +dependencies = [ + "lazy_static", + "regex", +] [[package]] name = "near-store" diff --git a/chain/jsonrpc/Cargo.toml b/chain/jsonrpc/Cargo.toml index e258c3feecf..a99dd813d8f 100644 --- a/chain/jsonrpc/Cargo.toml +++ b/chain/jsonrpc/Cargo.toml @@ -25,6 +25,7 @@ near-client = { path = "../client" } near-network = { path = "../network" } near-jsonrpc-client = { path = "client" } near-rpc-error-macro = { path = "../../tools/rpctypegen/macro" } +near-runtime-utils = { path = "../../runtime/near-runtime-utils" } [dev-dependencies] near-logger-utils = { path = "../../test-utils/logger" } diff --git a/chain/jsonrpc/src/lib.rs b/chain/jsonrpc/src/lib.rs index 686bcd98b07..4a19c4ac316 100644 --- a/chain/jsonrpc/src/lib.rs +++ b/chain/jsonrpc/src/lib.rs @@ -43,8 +43,8 @@ use near_primitives::rpc::{ use near_primitives::serialize::{from_base, from_base64, BaseEncode}; use near_primitives::transaction::SignedTransaction; use near_primitives::types::{AccountId, BlockId, BlockReference, MaybeBlockId}; -use near_primitives::utils::is_valid_account_id; use near_primitives::views::{FinalExecutionOutcomeView, GenesisRecordsView, QueryRequest}; +use near_runtime_utils::is_valid_account_id; mod metrics; /// Max size of the query path (soft-deprecated) diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index 8dfb3d78c3d..3305ff55099 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -13,7 +13,6 @@ chrono = { version = "0.4.4", features = ["serde"] } derive_more = "0.99.3" easy-ext = "0.2" sha2 = "0.8" -lazy_static = "1.4" serde = { version = "1", features = ["derive"] } serde_json = "1" smart-default = "0.6" diff --git a/core/primitives/src/errors.rs b/core/primitives/src/errors.rs index 40a1112f5f4..0143966636c 100644 --- a/core/primitives/src/errors.rs +++ b/core/primitives/src/errors.rs @@ -107,13 +107,13 @@ impl std::error::Error for StorageError {} pub enum InvalidTxError { /// Happens if a wrong AccessKey used or AccessKey has not enough permissions InvalidAccessKeyError(InvalidAccessKeyError), - /// TX signer_id is not in a valid format or not satisfy requirements see `near_core::primitives::utils::is_valid_account_id` + /// TX signer_id is not in a valid format or not satisfy requirements see `near_runtime_utils::utils::is_valid_account_id` InvalidSignerId { signer_id: AccountId }, /// TX signer_id is not found in a storage SignerDoesNotExist { signer_id: AccountId }, /// Transaction nonce must be account[access_key].nonce + 1 InvalidNonce { tx_nonce: Nonce, ak_nonce: Nonce }, - /// TX receiver_id is not in a valid format or not satisfy requirements see `near_core::primitives::utils::is_valid_account_id` + /// TX receiver_id is not in a valid format or not satisfy requirements see `near_runtime_utils::is_valid_account_id` InvalidReceiverId { receiver_id: AccountId }, /// TX signature is not valid InvalidSignature, diff --git a/core/primitives/src/test_utils.rs b/core/primitives/src/test_utils.rs index 543bae2f914..a885293172a 100644 --- a/core/primitives/src/test_utils.rs +++ b/core/primitives/src/test_utils.rs @@ -7,7 +7,7 @@ use near_crypto::{EmptySigner, PublicKey, Signature, Signer}; use crate::account::{AccessKey, AccessKeyPermission, Account}; use crate::block::{Block, BlockV1}; use crate::block_header::{BlockHeader, BlockHeaderV2}; -use crate::errors::EpochError; +use crate::errors::{EpochError, TxExecutionError}; use crate::hash::CryptoHash; use crate::merkle::PartialMerkleTree; use crate::serialize::from_base64; @@ -427,6 +427,13 @@ impl FinalExecutionStatus { } } + pub fn as_failure(self) -> Option { + match self { + FinalExecutionStatus::Failure(failure) => Some(failure), + _ => None, + } + } + pub fn as_success_decoded(self) -> Option> { self.as_success().and_then(|value| from_base64(&value).ok()) } diff --git a/core/primitives/src/utils.rs b/core/primitives/src/utils.rs index e74a4dc5c8d..7052a5fd337 100644 --- a/core/primitives/src/utils.rs +++ b/core/primitives/src/utils.rs @@ -6,17 +6,11 @@ use byteorder::{LittleEndian, WriteBytesExt}; use chrono::{DateTime, NaiveDateTime, Utc}; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; -use regex::Regex; use serde; -use lazy_static::lazy_static; - use crate::hash::{hash, CryptoHash}; use crate::types::{AccountId, NumSeats, NumShards, ShardId}; -pub const MIN_ACCOUNT_ID_LEN: usize = 2; -pub const MAX_ACCOUNT_ID_LEN: usize = 64; - /// Number of nano seconds in a second. const NS_IN_SECOND: u64 = 1_000_000_000; @@ -55,54 +49,12 @@ pub fn index_to_bytes(index: u64) -> Vec { bytes } -lazy_static! { - /// See NEP#0006 - static ref VALID_ACCOUNT_ID: Regex = - Regex::new(r"^(([a-z\d]+[\-_])*[a-z\d]+\.)*([a-z\d]+[\-_])*[a-z\d]+$").unwrap(); - /// Represents a part of an account ID with a suffix of as a separator `.`. - static ref VALID_ACCOUNT_PART_ID_WITH_TAIL_SEPARATOR: Regex = - Regex::new(r"^([a-z\d]+[\-_])*[a-z\d]+\.$").unwrap(); - /// Represents a top level account ID. - static ref VALID_TOP_LEVEL_ACCOUNT_ID: Regex = - Regex::new(r"^([a-z\d]+[\-_])*[a-z\d]+$").unwrap(); -} - -/// const does not allow function call, so have to resort to this +/// This is duplicate of near_runtime_utils::system_account. +/// TODO: code that uses this system_account should be moved into runtime and depend on it. pub fn system_account() -> AccountId { "system".to_string() } -pub fn is_valid_account_id(account_id: &AccountId) -> bool { - account_id.len() >= MIN_ACCOUNT_ID_LEN - && account_id.len() <= MAX_ACCOUNT_ID_LEN - && VALID_ACCOUNT_ID.is_match(account_id) -} - -pub fn is_valid_top_level_account_id(account_id: &AccountId) -> bool { - account_id.len() >= MIN_ACCOUNT_ID_LEN - && account_id.len() <= MAX_ACCOUNT_ID_LEN - && account_id != &system_account() - && VALID_TOP_LEVEL_ACCOUNT_ID.is_match(account_id) -} - -/// Returns true if the signer_id can create a direct sub-account with the given account Id. -/// It assumes the signer_id is a valid account_id -pub fn is_valid_sub_account_id(signer_id: &AccountId, sub_account_id: &AccountId) -> bool { - if !is_valid_account_id(sub_account_id) { - return false; - } - if signer_id.len() >= sub_account_id.len() { - return false; - } - // Will not panic, since valid account id is utf-8 only and the length is checked above. - // e.g. when `near` creates `aa.near`, it splits into `aa.` and `near` - let (prefix, suffix) = sub_account_id.split_at(sub_account_id.len() - signer_id.len()); - if suffix != signer_id { - return false; - } - VALID_ACCOUNT_PART_ID_WITH_TAIL_SEPARATOR.is_match(prefix) -} - /// A wrapper around Option that provides native Display trait. /// Simplifies propagating automatic Display trait on parent structs. pub struct DisplayOption(pub Option); @@ -242,224 +194,6 @@ where mod tests { use super::*; - const OK_ACCOUNT_IDS: &[&str] = &[ - "aa", - "a-a", - "a-aa", - "100", - "0o", - "com", - "near", - "bowen", - "b-o_w_e-n", - "b.owen", - "bro.wen", - "a.ha", - "a.b-a.ra", - "system", - "over.9000", - "google.com", - "illia.cheapaccounts.near", - "0o0ooo00oo00o", - "alex-skidanov", - "10-4.8-2", - "b-o_w_e-n", - "no_lols", - "0123456789012345678901234567890123456789012345678901234567890123", - // Valid, but can't be created - "near.a", - ]; - - #[test] - fn test_is_valid_account_id() { - for account_id in OK_ACCOUNT_IDS { - assert!( - is_valid_account_id(&account_id.to_string()), - "Valid account id {:?} marked invalid", - account_id - ); - } - - let bad_account_ids = vec![ - "a", - "A", - "Abc", - "-near", - "near-", - "-near-", - "near.", - ".near", - "near@", - "@near", - "неар", - "@@@@@", - "0__0", - "0_-_0", - "0_-_0", - "..", - "a..near", - "nEar", - "_bowen", - "hello world", - "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz", - "01234567890123456789012345678901234567890123456789012345678901234", - // `@` separators are banned now - "some-complex-address@gmail.com", - "sub.buy_d1gitz@atata@b0-rg.c_0_m", - ]; - for account_id in bad_account_ids { - assert!( - !is_valid_account_id(&account_id.to_string()), - "Invalid account id {:?} marked valid", - account_id - ); - } - } - - #[test] - fn test_is_valid_top_level_account_id() { - let ok_top_level_account_ids = vec![ - "aa", - "a-a", - "a-aa", - "100", - "0o", - "com", - "near", - "bowen", - "b-o_w_e-n", - "0o0ooo00oo00o", - "alex-skidanov", - "b-o_w_e-n", - "no_lols", - "0123456789012345678901234567890123456789012345678901234567890123", - ]; - for account_id in ok_top_level_account_ids { - assert!( - is_valid_top_level_account_id(&account_id.to_string()), - "Valid top level account id {:?} marked invalid", - account_id - ); - } - - let bad_top_level_account_ids = vec![ - "near.a", - "b.owen", - "bro.wen", - "a.ha", - "a.b-a.ra", - "some-complex-address@gmail.com", - "sub.buy_d1gitz@atata@b0-rg.c_0_m", - "over.9000", - "google.com", - "illia.cheapaccounts.near", - "10-4.8-2", - "a", - "A", - "Abc", - "-near", - "near-", - "-near-", - "near.", - ".near", - "near@", - "@near", - "неар", - "@@@@@", - "0__0", - "0_-_0", - "0_-_0", - "..", - "a..near", - "nEar", - "_bowen", - "hello world", - "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz", - "01234567890123456789012345678901234567890123456789012345678901234", - // Valid regex and length, but reserved - "system", - ]; - for account_id in bad_top_level_account_ids { - assert!( - !is_valid_top_level_account_id(&account_id.to_string()), - "Invalid top level account id {:?} marked valid", - account_id - ); - } - } - - #[test] - fn test_is_valid_sub_account_id() { - let ok_pairs = vec![ - ("test", "a.test"), - ("test-me", "abc.test-me"), - ("gmail.com", "abc.gmail.com"), - ("gmail.com", "abc-lol.gmail.com"), - ("gmail.com", "abc_lol.gmail.com"), - ("gmail.com", "bro-abc_lol.gmail.com"), - ("g0", "0g.g0"), - ("1g", "1g.1g"), - ("5-3", "4_2.5-3"), - ]; - for (signer_id, sub_account_id) in ok_pairs { - assert!( - is_valid_sub_account_id(&signer_id.to_string(), &sub_account_id.to_string()), - "Failed to create sub-account {:?} by account {:?}", - sub_account_id, - signer_id - ); - } - - let bad_pairs = vec![ - ("test", ".test"), - ("test", "test"), - ("test", "est"), - ("test", ""), - ("test", "st"), - ("test5", "ббб"), - ("test", "a-test"), - ("test", "etest"), - ("test", "a.etest"), - ("test", "retest"), - ("test-me", "abc-.test-me"), - ("test-me", "Abc.test-me"), - ("test-me", "-abc.test-me"), - ("test-me", "a--c.test-me"), - ("test-me", "a_-c.test-me"), - ("test-me", "a-_c.test-me"), - ("test-me", "_abc.test-me"), - ("test-me", "abc_.test-me"), - ("test-me", "..test-me"), - ("test-me", "a..test-me"), - ("gmail.com", "a.abc@gmail.com"), - ("gmail.com", ".abc@gmail.com"), - ("gmail.com", ".abc@gmail@com"), - ("gmail.com", "abc@gmail@com"), - ("test", "a@test"), - ("test_me", "abc@test_me"), - ("gmail.com", "abc@gmail.com"), - ("gmail@com", "abc.gmail@com"), - ("gmail.com", "abc-lol@gmail.com"), - ("gmail@com", "abc_lol.gmail@com"), - ("gmail@com", "bro-abc_lol.gmail@com"), - ("gmail.com", "123456789012345678901234567890123456789012345678901234567890@gmail.com"), - ( - "123456789012345678901234567890123456789012345678901234567890", - "1234567890.123456789012345678901234567890123456789012345678901234567890", - ), - ("aa", "ъ@aa"), - ("aa", "ъ.aa"), - ]; - for (signer_id, sub_account_id) in bad_pairs { - assert!( - !is_valid_sub_account_id(&signer_id.to_string(), &sub_account_id.to_string()), - "Invalid sub-account {:?} created by account {:?}", - sub_account_id, - signer_id - ); - } - } - #[test] fn test_num_chunk_producers() { for num_seats in 1..50 { diff --git a/genesis-tools/genesis-csv-to-json/src/csv_parser.rs b/genesis-tools/genesis-csv-to-json/src/csv_parser.rs index d8a4037a21f..cffa6873c3b 100644 --- a/genesis-tools/genesis-csv-to-json/src/csv_parser.rs +++ b/genesis-tools/genesis-csv-to-json/src/csv_parser.rs @@ -15,7 +15,8 @@ use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum}; use near_primitives::state_record::StateRecord; use near_primitives::transaction::{Action, FunctionCallAction}; use near_primitives::types::{AccountId, AccountInfo, Balance, Gas}; -use near_primitives::utils::{create_nonce_with_nonce, is_valid_account_id}; +use near_primitives::utils::create_nonce_with_nonce; +use near_runtime_utils::is_valid_account_id; /// Methods that can be called by a non-privileged access key. const REGULAR_METHOD_NAMES: &[&str] = &["stake", "transfer"]; diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 7215a1b06f8..2c075d7fb7d 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -32,7 +32,8 @@ ethereum-types = "0.6.0" near-vm-logic = { path = "../near-vm-logic" } near-vm-errors = { path = "../near-vm-errors" } -near-runtime-fees = { path = "../near-runtime-fees", version = "2.1.0" } +near-runtime-utils = { path = "../near-runtime-utils" } +near-runtime-fees = { path = "../near-runtime-fees" } [dev-dependencies] ethabi = "8.0.0" diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index ec5218b20fd..f50746d7a9b 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -64,7 +64,7 @@ pub trait EvmState { fn next_nonce(&mut self, address: &Address) -> Result { let mut account = self.get_account(address)?.unwrap_or_default(); let nonce = account.nonce; - account.nonce += account.nonce.saturating_add(U256::from(1)); + account.nonce = account.nonce.saturating_add(U256::from(1)); self.set_account(address, &account)?; Ok(nonce) } diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index e82fd7e3745..de94dae6906 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -6,6 +6,7 @@ use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; use near_runtime_fees::RuntimeFeesConfig; +use near_runtime_utils::is_valid_sub_account_id; use near_vm_errors::{EvmError, FunctionCallError, VMError}; use near_vm_logic::gas_counter::GasCounter; use near_vm_logic::types::{AccountId, Balance, Gas, ReturnData, StorageUsage}; @@ -308,7 +309,7 @@ impl<'a> EvmContext<'a> { false, ActionCosts::transfer, )?; - self.ext.append_action_transfer(receipt_index, amount).map_err(|err| err.into()) + self.ext.append_action_transfer(receipt_index, amount) } /// Transfer tokens from sender to given EVM address. @@ -323,6 +324,39 @@ impl<'a> EvmContext<'a> { self.transfer_balance(&sender, &Address::from(args.address), amount) } + /// Creates new EVM under given sub account and sends attached balance to it. + /// If account id given is not a valid subaccount of the current account, will return InvalidSubAccount. + /// If balance attached was not enough, will return InsufficientDeposit. + pub fn create_evm(&mut self, args: Vec) -> Result<()> { + let new_account_id = std::str::from_utf8(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))? + .to_string(); + if !is_valid_sub_account_id(&self.account_id, &new_account_id) { + return Err(VMLogicError::EvmError(EvmError::InvalidSubAccount)); + } + if self.attached_deposit < self.fees_config.evm_deposit { + return Err(VMLogicError::EvmError(EvmError::InsufficientDeposit)); + } + self.current_amount = self + .current_amount + .checked_sub(self.attached_deposit) + .ok_or_else(|| VMLogicError::EvmError(EvmError::InsufficientFunds))?; + let receipt_index = self.ext.create_receipt(vec![], new_account_id)?; + self.pay_gas_for_new_receipt(false, &[])?; + self.gas_counter.pay_action_base( + &self.fees_config.action_creation_config.create_account_cost, + false, + ActionCosts::create_account, + )?; + self.ext.append_action_create_account(receipt_index)?; + self.gas_counter.pay_action_base( + &self.fees_config.action_creation_config.transfer_cost, + false, + ActionCosts::transfer, + )?; + self.ext.append_action_transfer(receipt_index, self.attached_deposit) + } + /// A helper function to pay gas fee for creating a new receipt without actions. /// # Args: /// * `sir`: whether contract call is addressed to itself; @@ -396,6 +430,7 @@ pub fn run_evm( "deposit" => context.deposit(args).map(|balance| utils::u256_to_arr(&balance).to_vec()), "withdraw" => context.withdraw(args).map(|_| vec![]), "transfer" => context.transfer(args).map(|_| vec![]), + "create" => context.create_evm(args).map(|_| vec![]), // View methods. // TODO: remove this function name if no one is using it. "view_function_call" => context.view_call_function(args), diff --git a/runtime/near-runtime-fees/src/lib.rs b/runtime/near-runtime-fees/src/lib.rs index 6e484a2a4be..1a0f29e88fc 100644 --- a/runtime/near-runtime-fees/src/lib.rs +++ b/runtime/near-runtime-fees/src/lib.rs @@ -6,6 +6,7 @@ use num_rational::Rational; use serde::{Deserialize, Serialize}; +pub type Balance = u128; pub type Gas = u64; /// Costs associated with an object that can only be sent over the network (and executed @@ -63,6 +64,9 @@ pub struct RuntimeFeesConfig { /// Pessimistic gas price inflation ratio. pub pessimistic_gas_price_inflation_ratio: Rational, + + /// New EVM deposit. + pub evm_deposit: Balance, } /// Describes the cost of creating a data receipt, `DataReceipt`. @@ -228,6 +232,8 @@ impl Default for RuntimeFeesConfig { }, burnt_gas_reward: Rational::new(3, 10), pessimistic_gas_price_inflation_ratio: Rational::new(103, 100), + // The amount is 1000 * 10e24 = 1000 NEAR. + evm_deposit: 1_000_000_000_000_000_000_000_000_000, } } } @@ -263,6 +269,7 @@ impl RuntimeFeesConfig { }, burnt_gas_reward: Rational::from_integer(0), pessimistic_gas_price_inflation_ratio: Rational::from_integer(0), + evm_deposit: 0, } } diff --git a/runtime/near-runtime-utils/Cargo.toml b/runtime/near-runtime-utils/Cargo.toml index f2b806a04c3..b800610ccf9 100644 --- a/runtime/near-runtime-utils/Cargo.toml +++ b/runtime/near-runtime-utils/Cargo.toml @@ -17,3 +17,5 @@ This crate contains utility functions for NEAR runtime. # Historically, `near-primitives` contained a bunch of dependencies that prevented this crate from being compiled to Wasm. [dependencies] +lazy_static = "1.4" +regex = "1" diff --git a/runtime/near-runtime-utils/src/lib.rs b/runtime/near-runtime-utils/src/lib.rs index 2efd03702bf..2d80ed0d5bf 100644 --- a/runtime/near-runtime-utils/src/lib.rs +++ b/runtime/near-runtime-utils/src/lib.rs @@ -1,4 +1,61 @@ //! Contains utility functions for runtime. +#[macro_use] +extern crate lazy_static; + +use regex::Regex; + +type AccountId = String; + +pub const MIN_ACCOUNT_ID_LEN: usize = 2; +pub const MAX_ACCOUNT_ID_LEN: usize = 64; + +lazy_static! { + /// See NEP#0006 + static ref VALID_ACCOUNT_ID: Regex = + Regex::new(r"^(([a-z\d]+[\-_])*[a-z\d]+\.)*([a-z\d]+[\-_])*[a-z\d]+$").unwrap(); + /// Represents a part of an account ID with a suffix of as a separator `.`. + static ref VALID_ACCOUNT_PART_ID_WITH_TAIL_SEPARATOR: Regex = + Regex::new(r"^([a-z\d]+[\-_])*[a-z\d]+\.$").unwrap(); + /// Represents a top level account ID. + static ref VALID_TOP_LEVEL_ACCOUNT_ID: Regex = + Regex::new(r"^([a-z\d]+[\-_])*[a-z\d]+$").unwrap(); +} + +/// const does not allow function call, so have to resort to this +pub fn system_account() -> AccountId { + "system".to_string() +} + +pub fn is_valid_account_id(account_id: &AccountId) -> bool { + account_id.len() >= MIN_ACCOUNT_ID_LEN + && account_id.len() <= MAX_ACCOUNT_ID_LEN + && VALID_ACCOUNT_ID.is_match(account_id) +} + +pub fn is_valid_top_level_account_id(account_id: &AccountId) -> bool { + account_id.len() >= MIN_ACCOUNT_ID_LEN + && account_id.len() <= MAX_ACCOUNT_ID_LEN + && account_id != &system_account() + && VALID_TOP_LEVEL_ACCOUNT_ID.is_match(account_id) +} + +/// Returns true if the signer_id can create a direct sub-account with the given account Id. +/// It assumes the signer_id is a valid account_id +pub fn is_valid_sub_account_id(signer_id: &AccountId, sub_account_id: &AccountId) -> bool { + if !is_valid_account_id(sub_account_id) { + return false; + } + if signer_id.len() >= sub_account_id.len() { + return false; + } + // Will not panic, since valid account id is utf-8 only and the length is checked above. + // e.g. when `near` creates `aa.near`, it splits into `aa.` and `near` + let (prefix, suffix) = sub_account_id.split_at(sub_account_id.len() - signer_id.len()); + if suffix != signer_id { + return false; + } + VALID_ACCOUNT_PART_ID_WITH_TAIL_SEPARATOR.is_match(prefix) +} /// Returns true if the account ID length is 64 characters and it's a hex representation. pub fn is_account_id_64_len_hex(account_id: &str) -> bool { @@ -9,10 +66,233 @@ pub fn is_account_id_64_len_hex(account_id: &str) -> bool { }) } +/// Returns true if the account ID is suppose to be EVM machine. +pub fn is_account_evm(account_id: &str) -> bool { + account_id == "evm" || account_id.ends_with(".evm") +} + #[cfg(test)] mod tests { use super::*; + const OK_ACCOUNT_IDS: &[&str] = &[ + "aa", + "a-a", + "a-aa", + "100", + "0o", + "com", + "near", + "bowen", + "b-o_w_e-n", + "b.owen", + "bro.wen", + "a.ha", + "a.b-a.ra", + "system", + "over.9000", + "google.com", + "illia.cheapaccounts.near", + "0o0ooo00oo00o", + "alex-skidanov", + "10-4.8-2", + "b-o_w_e-n", + "no_lols", + "0123456789012345678901234567890123456789012345678901234567890123", + // Valid, but can't be created + "near.a", + ]; + + #[test] + fn test_is_valid_account_id() { + for account_id in OK_ACCOUNT_IDS { + assert!( + is_valid_account_id(&account_id.to_string()), + "Valid account id {:?} marked invalid", + account_id + ); + } + + let bad_account_ids = vec![ + "a", + "A", + "Abc", + "-near", + "near-", + "-near-", + "near.", + ".near", + "near@", + "@near", + "неар", + "@@@@@", + "0__0", + "0_-_0", + "0_-_0", + "..", + "a..near", + "nEar", + "_bowen", + "hello world", + "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz", + "01234567890123456789012345678901234567890123456789012345678901234", + // `@` separators are banned now + "some-complex-address@gmail.com", + "sub.buy_d1gitz@atata@b0-rg.c_0_m", + ]; + for account_id in bad_account_ids { + assert!( + !is_valid_account_id(&account_id.to_string()), + "Invalid account id {:?} marked valid", + account_id + ); + } + } + + #[test] + fn test_is_valid_top_level_account_id() { + let ok_top_level_account_ids = vec![ + "aa", + "a-a", + "a-aa", + "100", + "0o", + "com", + "near", + "bowen", + "b-o_w_e-n", + "0o0ooo00oo00o", + "alex-skidanov", + "b-o_w_e-n", + "no_lols", + "0123456789012345678901234567890123456789012345678901234567890123", + ]; + for account_id in ok_top_level_account_ids { + assert!( + is_valid_top_level_account_id(&account_id.to_string()), + "Valid top level account id {:?} marked invalid", + account_id + ); + } + + let bad_top_level_account_ids = vec![ + "near.a", + "b.owen", + "bro.wen", + "a.ha", + "a.b-a.ra", + "some-complex-address@gmail.com", + "sub.buy_d1gitz@atata@b0-rg.c_0_m", + "over.9000", + "google.com", + "illia.cheapaccounts.near", + "10-4.8-2", + "a", + "A", + "Abc", + "-near", + "near-", + "-near-", + "near.", + ".near", + "near@", + "@near", + "неар", + "@@@@@", + "0__0", + "0_-_0", + "0_-_0", + "..", + "a..near", + "nEar", + "_bowen", + "hello world", + "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz", + "01234567890123456789012345678901234567890123456789012345678901234", + // Valid regex and length, but reserved + "system", + ]; + for account_id in bad_top_level_account_ids { + assert!( + !is_valid_top_level_account_id(&account_id.to_string()), + "Invalid top level account id {:?} marked valid", + account_id + ); + } + } + + #[test] + fn test_is_valid_sub_account_id() { + let ok_pairs = vec![ + ("test", "a.test"), + ("test-me", "abc.test-me"), + ("gmail.com", "abc.gmail.com"), + ("gmail.com", "abc-lol.gmail.com"), + ("gmail.com", "abc_lol.gmail.com"), + ("gmail.com", "bro-abc_lol.gmail.com"), + ("g0", "0g.g0"), + ("1g", "1g.1g"), + ("5-3", "4_2.5-3"), + ]; + for (signer_id, sub_account_id) in ok_pairs { + assert!( + is_valid_sub_account_id(&signer_id.to_string(), &sub_account_id.to_string()), + "Failed to create sub-account {:?} by account {:?}", + sub_account_id, + signer_id + ); + } + + let bad_pairs = vec![ + ("test", ".test"), + ("test", "test"), + ("test", "est"), + ("test", ""), + ("test", "st"), + ("test5", "ббб"), + ("test", "a-test"), + ("test", "etest"), + ("test", "a.etest"), + ("test", "retest"), + ("test-me", "abc-.test-me"), + ("test-me", "Abc.test-me"), + ("test-me", "-abc.test-me"), + ("test-me", "a--c.test-me"), + ("test-me", "a_-c.test-me"), + ("test-me", "a-_c.test-me"), + ("test-me", "_abc.test-me"), + ("test-me", "abc_.test-me"), + ("test-me", "..test-me"), + ("test-me", "a..test-me"), + ("gmail.com", "a.abc@gmail.com"), + ("gmail.com", ".abc@gmail.com"), + ("gmail.com", ".abc@gmail@com"), + ("gmail.com", "abc@gmail@com"), + ("test", "a@test"), + ("test_me", "abc@test_me"), + ("gmail.com", "abc@gmail.com"), + ("gmail@com", "abc.gmail@com"), + ("gmail.com", "abc-lol@gmail.com"), + ("gmail@com", "abc_lol.gmail@com"), + ("gmail@com", "bro-abc_lol.gmail@com"), + ("gmail.com", "123456789012345678901234567890123456789012345678901234567890@gmail.com"), + ( + "123456789012345678901234567890123456789012345678901234567890", + "1234567890.123456789012345678901234567890123456789012345678901234567890", + ), + ("aa", "ъ@aa"), + ("aa", "ъ.aa"), + ]; + for (signer_id, sub_account_id) in bad_pairs { + assert!( + !is_valid_sub_account_id(&signer_id.to_string(), &sub_account_id.to_string()), + "Invalid sub-account {:?} created by account {:?}", + sub_account_id, + signer_id + ); + } + } + #[test] fn test_is_account_id_64_len_hex() { let valid_64_len_hex_account_ids = vec![ diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index 8d5139db8cc..4179b4a9faf 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -198,6 +198,10 @@ pub enum EvmError { InvalidEcRecoverSignature, /// Invalid nonce. InvalidNonce, + /// Invalid sub EVM account. + InvalidSubAccount, + /// Too small NEAR deposit. + InsufficientDeposit, } #[derive(Debug, Clone, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index bf7508df7a2..5da3e41d037 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -11,16 +11,16 @@ use near_primitives::transaction::{ FunctionCallAction, StakeAction, TransferAction, }; use near_primitives::types::{AccountId, EpochInfoProvider, ValidatorStake}; -use near_primitives::utils::{ - is_valid_account_id, is_valid_sub_account_id, is_valid_top_level_account_id, -}; use near_primitives::version::{ ProtocolVersion, CORRECT_RANDOM_VALUE_PROTOCOL_VERSION, IMPLICIT_ACCOUNT_CREATION_PROTOCOL_VERSION, }; use near_runtime_configs::AccountCreationConfig; use near_runtime_fees::RuntimeFeesConfig; -use near_runtime_utils::is_account_id_64_len_hex; +use near_runtime_utils::{ + is_account_evm, is_account_id_64_len_hex, is_valid_account_id, is_valid_sub_account_id, + is_valid_top_level_account_id, +}; use near_store::{ get_access_key, get_code, remove_access_key, remove_account, set_access_key, set_code, StorageError, TrieUpdate, @@ -51,7 +51,7 @@ pub(crate) fn execute_function_call( is_view: bool, ) -> (Option, Option) { let account_id = runtime_ext.account_id(); - if account_id == "evm" || account_id.ends_with(".evm") { + if is_account_evm(&account_id) { near_evm_runner::run_evm( runtime_ext, &config.wasm_config, diff --git a/runtime/runtime/src/state_viewer.rs b/runtime/runtime/src/state_viewer.rs index 74830a33c50..7b5a62d2d86 100644 --- a/runtime/runtime/src/state_viewer.rs +++ b/runtime/runtime/src/state_viewer.rs @@ -12,10 +12,10 @@ use near_primitives::transaction::FunctionCallAction; use near_primitives::trie_key::trie_key_parsers; use near_primitives::types::EpochHeight; use near_primitives::types::{AccountId, BlockHeight, EpochId, EpochInfoProvider}; -use near_primitives::utils::is_valid_account_id; use near_primitives::version::ProtocolVersion; use near_primitives::views::{StateItem, ViewStateResult}; use near_runtime_configs::RuntimeConfig; +use near_runtime_utils::is_valid_account_id; use near_store::{get_access_key, get_account, TrieUpdate}; use near_vm_logic::ReturnData; diff --git a/runtime/runtime/src/verifier.rs b/runtime/runtime/src/verifier.rs index 58678115d22..357af1fcedb 100644 --- a/runtime/runtime/src/verifier.rs +++ b/runtime/runtime/src/verifier.rs @@ -9,9 +9,9 @@ use near_primitives::transaction::{ Action, AddKeyAction, DeleteAccountAction, DeployContractAction, FunctionCallAction, SignedTransaction, StakeAction, }; -use near_primitives::utils::is_valid_account_id; use near_primitives::version::ProtocolVersion; use near_runtime_configs::get_insufficient_storage_stake; +use near_runtime_utils::is_valid_account_id; use near_store::{ get_access_key, get_account, set_access_key, set_account, StorageError, TrieUpdate, }; diff --git a/test-utils/testlib/src/standard_test_cases.rs b/test-utils/testlib/src/standard_test_cases.rs index 531c0c56be4..d3e45aaa978 100644 --- a/test-utils/testlib/src/standard_test_cases.rs +++ b/test-utils/testlib/src/standard_test_cases.rs @@ -1369,3 +1369,42 @@ pub fn test_evm_deploy_call(node: impl Node) { .unwrap(); assert_eq!(result.len(), 0); } + +pub fn test_sub_evm(node: impl Node) { + let node_user = node.user(); + assert_eq!( + node_user.view_account(&"sub.evm".to_string()).unwrap_err().to_string(), + "account sub.evm does not exist while viewing" + ); + assert_eq!( + node_user + .function_call( + alice_account(), + evm_account(), + "create", + b"sub.evm".to_vec(), + 10u64.pow(14), + 0, + ) + .unwrap() + .status + .as_failure() + .unwrap() + .to_string(), + "Action #0: EVM: InsufficientDeposit" + ); + node_user + .function_call( + alice_account(), + evm_account(), + "create", + b"sub.evm".to_vec(), + 10u64.pow(14), + 10u128.pow(27), + ) + .unwrap() + .status + .as_success() + .unwrap(); + assert_eq!(node_user.view_account(&"sub.evm".to_string()).unwrap().amount, 10u128.pow(27)); +} diff --git a/tests/test_cases_runtime.rs b/tests/test_cases_runtime.rs index c5f55c35d2c..98e835153f1 100644 --- a/tests/test_cases_runtime.rs +++ b/tests/test_cases_runtime.rs @@ -303,4 +303,16 @@ mod test { let node = create_free_runtime_node(); test_smart_contract_free(node); } + + #[test] + fn test_evm_deploy_call_runtime() { + let node = create_runtime_node(); + test_evm_deploy_call(node); + } + + #[test] + fn test_sub_evm_runtime() { + let node = create_runtime_node(); + test_sub_evm(node); + } } From 965265edf114cea435d03304dcd901a46f149478 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sun, 27 Sep 2020 07:07:00 -0700 Subject: [PATCH 33/82] Clean up errors --- Cargo.lock | 1 + runtime/near-evm-runner/src/interpreter.rs | 45 ++++++----- runtime/near-evm-runner/src/lib.rs | 10 ++- runtime/near-evm-runner/src/near_ext.rs | 1 + runtime/near-evm-runner/src/types.rs | 40 +++++++++- runtime/near-evm-runner/tests/failures.rs | 11 +++ runtime/near-evm-runner/tests/standard_ops.rs | 11 +++ runtime/near-vm-errors/Cargo.toml | 1 + runtime/near-vm-errors/src/lib.rs | 77 +++++++++++++++++-- test-utils/testlib/src/standard_test_cases.rs | 16 ++-- 10 files changed, 175 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec707dcf121..735155d69a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3170,6 +3170,7 @@ name = "near-vm-errors" version = "2.2.0" dependencies = [ "borsh", + "hex", "near-rpc-error-macro", "serde", ] diff --git a/runtime/near-evm-runner/src/interpreter.rs b/runtime/near-evm-runner/src/interpreter.rs index 7f2a45040eb..8cfc78845ca 100644 --- a/runtime/near-evm-runner/src/interpreter.rs +++ b/runtime/near-evm-runner/src/interpreter.rs @@ -2,13 +2,16 @@ use std::sync::Arc; use ethereum_types::{Address, U256}; use evm::{CreateContractAddress, Factory}; -use vm::{ActionParams, ActionValue, CallType, Ext, GasLeft, ParamsType, ReturnData, Schedule}; +use vm::{ + ActionParams, ActionValue, CallType, ExecTrapResult, Ext, GasLeft, ParamsType, ReturnData, + Schedule, +}; use near_vm_errors::{EvmError, VMLogicError}; use crate::evm_state::{EvmState, StateStore, SubState}; use crate::near_ext::NearExt; -use crate::types::Result; +use crate::types::{convert_vm_error, Result}; use crate::utils; pub fn deploy_code( @@ -30,7 +33,7 @@ pub fn deploy_code( if recreate { state.recreate(address.0); } else if state.code_at(&address)?.is_some() { - return Err(VMLogicError::EvmError(EvmError::DuplicateContract(hex::encode(address.0)))); + return Err(VMLogicError::EvmError(EvmError::DuplicateContract(address.0.to_vec()))); } let (result, state_updates) = @@ -40,18 +43,17 @@ pub fn deploy_code( // Apply NeedsReturn changes if apply_state // Return the result unmodified let (return_data, apply) = match result { - Some(GasLeft::Known(_)) => (ReturnData::empty(), true), - Some(GasLeft::NeedsReturn { gas_left: _, data, apply_state }) => (data, apply_state), - _ => return Err(VMLogicError::EvmError(EvmError::UnknownError)), + Ok(Ok(GasLeft::Known(_))) => (ReturnData::empty(), true), + Ok(Ok(GasLeft::NeedsReturn { gas_left: _, data, apply_state })) => (data, apply_state), + Ok(Err(err)) => return Err(convert_vm_error(err)), + Err(_) => return Err(VMLogicError::EvmError(EvmError::Reverted)), }; if apply { state.commit_changes(&state_updates.unwrap())?; state.set_code(&address, &return_data.to_vec())?; } else { - return Err(VMLogicError::EvmError(EvmError::DeployFail(hex::encode( - return_data.to_vec(), - )))); + return Err(VMLogicError::EvmError(EvmError::DeployFail(return_data.to_vec()))); } Ok(address) } @@ -64,7 +66,7 @@ pub fn _create( call_stack_depth: usize, address: &Address, code: &[u8], -) -> Result<(Option, Option)> { +) -> Result<(ExecTrapResult, Option)> { let mut store = StateStore::default(); let mut sub_state = SubState::new(sender, &mut store, state); @@ -96,7 +98,7 @@ pub fn _create( // Run the code let result = instance.exec(&mut ext); - Ok((result.ok().unwrap().ok(), Some(store))) + Ok((result, Some(store))) } #[allow(clippy::too_many_arguments)] @@ -204,12 +206,13 @@ fn run_and_commit_if_success( // Apply NeedsReturn changes if apply_state // Return the result unmodified let return_data = match result { - Some(GasLeft::Known(_)) => Ok(ReturnData::empty()), - Some(GasLeft::NeedsReturn { gas_left: _, data, apply_state: true }) => Ok(data), - Some(GasLeft::NeedsReturn { gas_left: _, data, apply_state: false }) => { - Err(VMLogicError::EvmError(EvmError::Revert(hex::encode(data.to_vec())))) + Ok(Ok(GasLeft::Known(_))) => Ok(ReturnData::empty()), + Ok(Ok(GasLeft::NeedsReturn { gas_left: _, data, apply_state: true })) => Ok(data), + Ok(Ok(GasLeft::NeedsReturn { gas_left: _, data, apply_state: false })) => { + Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) } - _ => Err(VMLogicError::EvmError(EvmError::UnknownError)), + Ok(Err(err)) => Err(convert_vm_error(err)), + Err(_) => Err(VMLogicError::EvmError(EvmError::Reverted)), }; // Don't apply changes from a static context (these _should_ error in the ext) @@ -233,9 +236,15 @@ fn run_against_state( code_address: &Address, input: &[u8], is_static: bool, -) -> Result<(Option, Option)> { +) -> Result<(ExecTrapResult, Option)> { let code = state.code_at(code_address)?.unwrap_or_else(Vec::new); + // Check that if there are arguments this is contract call. + // Otherwise, this is just transfer call. + if code.len() == 0 && input.len() > 0 { + return Err(VMLogicError::EvmError(EvmError::ContractNotFound)); + } + let mut store = StateStore::default(); let mut sub_state = SubState::new(sender, &mut store, state); @@ -271,5 +280,5 @@ fn run_against_state( // Run the code let result = instance.exec(&mut ext); - Ok((result.ok().unwrap().ok(), Some(store))) + Ok((result, Some(store))) } diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index de94dae6906..2e25698b789 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -235,17 +235,21 @@ impl<'a> EvmContext<'a> { let args = ViewCallArgs::try_from_slice(&args) .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; let sender = Address::from(&args.sender); - interpreter::call( + let attached_amount = U256::from(args.amount); + self.add_balance(&sender, attached_amount)?; + let result = interpreter::call( self, &sender, &sender, - Some(U256::from(args.amount)), + Some(attached_amount), 0, &Address::from(&args.address), &args.args, false, ) - .map(|rd| rd.to_vec()) + .map(|rd| rd.to_vec()); + self.sub_balance(&sender, attached_amount)?; + result } pub fn get_code(&self, args: Vec) -> Result> { diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index ef9a849e112..b580795f371 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -221,6 +221,7 @@ impl<'a> vm::Ext for NearExt<'a> { VMLogicError::EvmError(EvmError::Revert(encoded_message)) => { hex::decode(encoded_message).unwrap_or(vec![]) } + // TODO: this is potentially error prone if there are non runtime errors here, but we can only return vector here. _ => format!("{:?}", err).as_bytes().to_vec(), }; let message_len = message.len(); diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index 46bdbd16c37..b08e169c42f 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -1,8 +1,9 @@ +use std::convert::TryInto; use std::io::{Read, Write}; use borsh::{BorshDeserialize, BorshSerialize}; -use near_vm_errors::VMLogicError; +use near_vm_errors::{EvmError, InconsistentStateError, VMLogicError}; use near_vm_logic::types::AccountId; pub type RawAddress = [u8; 20]; @@ -69,6 +70,43 @@ impl BorshDeserialize for ViewCallArgs { } } +pub fn convert_vm_error(err: vm::Error) -> VMLogicError { + match err { + vm::Error::OutOfGas => VMLogicError::EvmError(EvmError::OutOfGas), + vm::Error::BadJumpDestination { destination } => { + VMLogicError::EvmError(EvmError::BadJumpDestination { + destination: destination.try_into().unwrap_or(0), + }) + } + vm::Error::BadInstruction { instruction } => { + VMLogicError::EvmError(EvmError::BadInstruction { instruction }) + } + vm::Error::StackUnderflow { instruction, wanted, on_stack } => { + VMLogicError::EvmError(EvmError::StackUnderflow { + instruction: instruction.to_string(), + wanted: wanted.try_into().unwrap_or(0), + on_stack: on_stack.try_into().unwrap_or(0), + }) + } + vm::Error::OutOfStack { instruction, wanted, limit } => { + VMLogicError::EvmError(EvmError::OutOfStack { + instruction: instruction.to_string(), + wanted: wanted.try_into().unwrap_or(0), + limit: limit.try_into().unwrap_or(0), + }) + } + vm::Error::BuiltIn(msg) => VMLogicError::EvmError(EvmError::BuiltIn(msg.to_string())), + vm::Error::MutableCallInStaticContext => VMLogicError::EvmError(EvmError::OutOfBounds), + vm::Error::Internal(err) => { + VMLogicError::InconsistentStateError(InconsistentStateError::StorageError(err)) + } + // This should not happen ever, because NEAR EVM is not using WASM. + vm::Error::Wasm(_) => unreachable!(), + vm::Error::OutOfBounds => VMLogicError::EvmError(EvmError::OutOfBounds), + vm::Error::Reverted => VMLogicError::EvmError(EvmError::Reverted), + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/runtime/near-evm-runner/tests/failures.rs b/runtime/near-evm-runner/tests/failures.rs index b86ffa8baf4..1a9c960d8cd 100644 --- a/runtime/near-evm-runner/tests/failures.rs +++ b/runtime/near-evm-runner/tests/failures.rs @@ -19,3 +19,14 @@ fn test_invalid_input() { assert!(context.withdraw(vec![]).is_err()); assert!(context.transfer(vec![]).is_err()); } + +#[test] +fn test_invalid_view_args() { + let args = vec![vec![1u8; 20], vec![2u8; 20], vec![0u8; 32], vec![1]].concat(); + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + assert_eq!( + context.view_call_function(args).unwrap_err().to_string(), + "EvmError(ContractNotFound)" + ); +} diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index e4a49d91535..0e84cdb1e86 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -219,6 +219,17 @@ fn test_view_call() { let sub_addr = raw[12..32].to_vec(); assert_eq!(context.get_code(sub_addr).unwrap().len(), 0); + + let (input, _) = soltest::functions::return_some_funds::call(); + let raw = context + .view_call_function(encode_view_call_function_args( + test_addr, + test_addr, + U256::from(10u128.pow(27)), + input, + )) + .unwrap(); + assert_eq!(raw[12..32], test_addr.0); } #[test] diff --git a/runtime/near-vm-errors/Cargo.toml b/runtime/near-vm-errors/Cargo.toml index 2373b78b2d0..3bdefd976e1 100644 --- a/runtime/near-vm-errors/Cargo.toml +++ b/runtime/near-vm-errors/Cargo.toml @@ -13,6 +13,7 @@ Error that can occur inside Near Runtime encapsulated in a separate crate. Might """ [dependencies] +hex = "0.4" serde = { version = "1", features = ["derive"] } borsh = "0.7.1" diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index 4179b4a9faf..60d036dfc26 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -176,14 +176,14 @@ pub enum HostError { /// Errors specifically from EVM pre-compile. #[derive(Debug, Clone, Eq, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] pub enum EvmError { - /// Unknown error, catch all for unexpected things. - UnknownError, + /// Contract not found. + ContractNotFound, /// Fatal failure due conflicting addresses on contract deployment. - DuplicateContract(String), + DuplicateContract(#[serde(with = "hex_format")] Vec), /// Contract deployment failure. - DeployFail(String), + DeployFail(#[serde(with = "hex_format")] Vec), /// Contract execution failed, revert the state. - Revert(String), + Revert(#[serde(with = "hex_format")] Vec), /// Failed to parse arguments. ArgumentParseError, /// No deposit when expected. @@ -202,6 +202,49 @@ pub enum EvmError { InvalidSubAccount, /// Too small NEAR deposit. InsufficientDeposit, + /// `OutOfGas` is returned when transaction execution runs out of gas. + /// The state should be reverted to the state from before the + /// transaction execution. But it does not mean that transaction + /// was invalid. Balance still should be transfered and nonce + /// should be increased. + OutOfGas, + /// `BadJumpDestination` is returned when execution tried to move + /// to position that wasn't marked with JUMPDEST instruction + BadJumpDestination { + /// Position the code tried to jump to. + destination: u64, + }, + /// `BadInstructions` is returned when given instruction is not supported + BadInstruction { + /// Unrecognized opcode + instruction: u8, + }, + /// `StackUnderflow` when there is not enough stack elements to execute instruction + StackUnderflow { + /// Invoked instruction + instruction: String, + /// How many stack elements was requested by instruction + wanted: u64, + /// How many elements were on stack + on_stack: u64, + }, + /// When execution would exceed defined Stack Limit + OutOfStack { + /// Invoked instruction + instruction: String, + /// How many stack elements instruction wanted to push + wanted: u64, + /// What was the stack limit + limit: u64, + }, + /// Built-in contract failed on given input + BuiltIn(String), + /// When execution tries to modify the state in static context + MutableCallInStaticContext, + /// Out of bounds access in RETURNDATACOPY. + OutOfBounds, + /// Execution has been reverted with REVERT. + Reverted, } #[derive(Debug, Clone, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] @@ -383,6 +426,30 @@ impl std::fmt::Display for HostError { } } +pub mod hex_format { + use hex::{decode, encode}; + + use serde::de; + use serde::{Deserialize, Deserializer, Serializer}; + + pub fn serialize(data: T, serializer: S) -> Result + where + S: Serializer, + T: AsRef<[u8]>, + { + serializer.serialize_str(&encode(data)) + } + + pub fn deserialize<'de, D, T>(deserializer: D) -> Result + where + D: Deserializer<'de>, + T: From>, + { + let s = String::deserialize(deserializer)?; + decode(&s).map_err(|err| de::Error::custom(err.to_string())).map(Into::into) + } +} + #[cfg(test)] mod tests { use crate::{CompilationError, FunctionCallError, MethodResolveError, PrepareError, VMError}; diff --git a/test-utils/testlib/src/standard_test_cases.rs b/test-utils/testlib/src/standard_test_cases.rs index d3e45aaa978..52776d0088e 100644 --- a/test-utils/testlib/src/standard_test_cases.rs +++ b/test-utils/testlib/src/standard_test_cases.rs @@ -1298,7 +1298,7 @@ pub fn test_evm_deploy_call(node: impl Node) { let args = vec![contract_id.clone(), input].concat(); assert_eq!( node_user - .function_call(alice_account(), evm_account(), "call_function", args, 10u64.pow(14), 0) + .function_call(alice_account(), evm_account(), "call", args, 10u64.pow(14), 0) .unwrap() .status .as_success_decoded() @@ -1309,16 +1309,10 @@ pub fn test_evm_deploy_call(node: impl Node) { let (input, _decoder) = cryptozombies::functions::get_zombies_by_owner::call( near_evm_runner::utils::near_account_id_to_evm_address(&alice_account()), ); - let args = vec![contract_id.clone(), input].concat(); + // sender, to, attached amount, args + let args = vec![contract_id.clone(), contract_id.clone(), vec![0u8; 32], input].concat(); let bytes = node_user - .function_call( - alice_account(), - evm_account(), - "view_call_function", - args.clone(), - 10u64.pow(14), - 0, - ) + .function_call(alice_account(), evm_account(), "view", args.clone(), 10u64.pow(14), 0) .unwrap() .status .as_success_decoded() @@ -1326,7 +1320,7 @@ pub fn test_evm_deploy_call(node: impl Node) { let res = cryptozombies::functions::get_zombies_by_owner::decode_output(&bytes).unwrap(); assert_eq!(res, vec![U256::from(0)]); - let result = node_user.view_call(&evm_account(), "view_call_function", &args).unwrap(); + let result = node_user.view_call(&evm_account(), "view", &args).unwrap(); let res = cryptozombies::functions::get_zombies_by_owner::decode_output(&result.result).unwrap(); assert_eq!(res, vec![U256::from(0)]); From 15bafd8f87214a9a373ea160372698c4c6af8f04 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sun, 27 Sep 2020 07:18:12 -0700 Subject: [PATCH 34/82] Fixing some comments --- runtime/near-evm-runner/src/builtins.rs | 2 +- runtime/near-evm-runner/src/lib.rs | 8 +++++--- runtime/near-evm-runner/src/utils.rs | 8 +++++--- runtime/runtime/src/actions.rs | 13 ++++++------- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/runtime/near-evm-runner/src/builtins.rs b/runtime/near-evm-runner/src/builtins.rs index 8e1c86314dc..6200ebe2142 100644 --- a/runtime/near-evm-runner/src/builtins.rs +++ b/runtime/near-evm-runner/src/builtins.rs @@ -394,7 +394,7 @@ impl Bn128PairingImpl { use bn::{pairing, AffineG1, AffineG2, Fq, Fq2, Group, Gt, G1, G2}; let elements = input.len() / 192; // (a, b_a, b_b - each 64-byte affine coordinates) - let ret_val = if input.is_empty() { + let ret_val = if elements == 0 { U256::one() } else { let mut vals = Vec::new(); diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 2e25698b789..0aa4d96b40b 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -78,9 +78,11 @@ impl<'a> EvmState for EvmContext<'a> { } fn _read_contract_storage(&self, key: [u8; 52]) -> Result> { - self.ext - .storage_get(&key) - .map(|value| value.map(|x| utils::vec_to_arr_32(x.deref().expect("Failed to deref")))) + self.ext.storage_get(&key).map(|value| { + value.map(|x| { + utils::vec_to_arr_32(x.deref().expect("Failed to deref")).expect("Must be 32 bytes") + }) + }) } fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Result<()> { diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index 7b9d2064f42..3937f52d479 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -89,11 +89,13 @@ pub fn address_to_vec(val: &Address) -> Vec { val.to_fixed_bytes().to_vec() } -pub fn vec_to_arr_32(v: Vec) -> [u8; 32] { - assert_eq!(v.len(), 32); +pub fn vec_to_arr_32(v: Vec) -> Option<[u8; 32]> { + if v.len() != 32 { + return None; + } let mut result = [0; 32]; result.copy_from_slice(&v); - result + Some(result) } /// Returns new address created from address, nonce, and code hash diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 5da3e41d037..52377375713 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -92,6 +92,11 @@ pub(crate) fn execute_function_call( } else { vec![] }; + let random_seed = create_random_seed( + apply_state.current_protocol_version, + *action_hash, + apply_state.random_seed, + ); let context = VMContext { current_account_id: runtime_ext.account_id().clone(), signer_account_id: action_receipt.signer_id.clone(), @@ -109,13 +114,7 @@ pub(crate) fn execute_function_call( storage_usage: account.storage_usage, attached_deposit: function_call.deposit, prepaid_gas: function_call.gas, - random_seed: if apply_state.current_protocol_version - < CORRECT_RANDOM_VALUE_PROTOCOL_VERSION - { - action_hash.as_ref().to_vec() - } else { - apply_state.random_seed.as_ref().to_vec() - }, + random_seed, is_view, output_data_receivers, }; From b7b820abe7babc043ae6dc5087e40f097347d2ea Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sun, 27 Sep 2020 09:52:06 -0700 Subject: [PATCH 35/82] Dedup ec recovery code in evm runner --- runtime/near-evm-runner/Cargo.toml | 2 +- runtime/near-evm-runner/src/builtins.rs | 41 ++++++------------- runtime/near-evm-runner/src/lib.rs | 2 +- runtime/near-evm-runner/src/utils.rs | 12 +++--- .../example-contract/Cargo.toml | 2 +- 5 files changed, 20 insertions(+), 39 deletions(-) diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 2c075d7fb7d..c0599106e4b 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/nearprotocol/nearcore" homepage = "https://github.com/nearprotocol/nearcore" [dependencies] -borsh = "0.7.0" +borsh = "0.7.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1" hex = "0.4" diff --git a/runtime/near-evm-runner/src/builtins.rs b/runtime/near-evm-runner/src/builtins.rs index 6200ebe2142..35fac3ac54c 100644 --- a/runtime/near-evm-runner/src/builtins.rs +++ b/runtime/near-evm-runner/src/builtins.rs @@ -4,14 +4,17 @@ use std::{ mem::size_of, }; +use bn::arith::U256; use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt}; -use ethereum_types::{Address, H256, U256}; +use ethereum_types::Address; use num_bigint::BigUint; use num_traits::{FromPrimitive, One, ToPrimitive, Zero}; use parity_bytes::BytesRef; use ripemd160::Digest; use vm::{MessageCallResult, ReturnData}; +use crate::utils::ecrecover_address; + #[derive(Primitive)] enum Precompile { EcRecover = 1, @@ -139,38 +142,18 @@ impl Impl for Identity { impl Impl for EcRecover { fn execute(&self, i: &[u8], output: &mut BytesRef) -> Result<(), Error> { - use sha3::Digest; - let len = min(i.len(), 128); let mut input = [0; 128]; input[..len].copy_from_slice(&i[..len]); + let mut hash = [0; 32]; + hash.copy_from_slice(&input[..32]); + let mut signature = [0; 96]; + signature.copy_from_slice(&input[32..]); - let hash = secp256k1::Message::parse(&H256::from_slice(&input[0..32]).0); - let v = &input[32..64]; - let r = &input[64..96]; - let s = &input[96..128]; - - let bit = match v[31] { - 27..=30 => v[31] - 27, - _ => { - return Ok(()); - } - }; - - let mut sig = [0u8; 64]; - sig[..32].copy_from_slice(&r); - sig[32..].copy_from_slice(&s); - let s = secp256k1::Signature::parse(&sig); - - if let Ok(rec_id) = secp256k1::RecoveryId::parse(bit) { - if let Ok(p) = secp256k1::recover(&hash, &s, &rec_id) { - // recover returns the 65-byte key, but addresses come from the raw 64-byte key - let r = sha3::Keccak256::digest(&p.serialize()[1..]); - output.write(0, &[0; 12]); - output.write(12, &r[12..]); - } - } + let result = ecrecover_address(&hash, &signature); + output.write(0, &[0, 12]); + output.write(12, &result.0); Ok(()) } @@ -448,7 +431,7 @@ impl Bn128PairingImpl { }; let mut buf = [0u8; 32]; - ret_val.to_big_endian(&mut buf); + ret_val.to_big_endian(&mut buf).expect("Can't fail"); output.write(0, &buf); Ok(()) diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 0aa4d96b40b..a22eaedd925 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -212,7 +212,7 @@ impl<'a> EvmContext<'a> { let sender = ecrecover_address( &prepare_meta_call_args(&self.domain_separator, &self.account_id, nonce, args), &signature, - )?; + ); if sender == Address::zero() { return Err(VMLogicError::EvmError(EvmError::InvalidEcRecoverSignature)); } diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index 3937f52d479..fc23d03a824 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -6,9 +6,6 @@ use keccak_hash::keccak; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use vm::CreateContractAddress; -use near_vm_errors::{EvmError, VMLogicError}; - -use crate::types; use near_vm_logic::types::AccountId; pub fn safe_next_address(addr: &[u8; 20]) -> [u8; 20] { @@ -222,7 +219,8 @@ pub fn prepare_meta_call_args( } /// Given signature and data, validates that signature is valid for given data and returns ecrecover address. -pub fn ecrecover_address(hash: &[u8; 32], signature: &[u8; 96]) -> types::Result
{ +/// If signature is invalid or doesn't match, returns 0x0 address. +pub fn ecrecover_address(hash: &[u8; 32], signature: &[u8; 96]) -> Address { use sha3::Digest; let hash = secp256k1::Message::parse(&H256::from_slice(hash).0); @@ -234,7 +232,7 @@ pub fn ecrecover_address(hash: &[u8; 32], signature: &[u8; 96]) -> types::Result 27..=30 => v[31] - 27, _ => { // ?? - return Ok(Address::zero()); + return Address::zero(); } }; @@ -247,8 +245,8 @@ pub fn ecrecover_address(hash: &[u8; 32], signature: &[u8; 96]) -> types::Result if let Ok(p) = secp256k1::recover(&hash, &s, &rec_id) { // recover returns the 65-byte key, but addresses come from the raw 64-byte key let r = sha3::Keccak256::digest(&p.serialize()[1..]); - return Ok(address_from_arr(&r[12..])); + return address_from_arr(&r[12..]); } } - Err(VMLogicError::EvmError(EvmError::InvalidEcRecoverSignature)) + Address::zero() } diff --git a/runtime/near-vm-runner-standalone/example-contract/Cargo.toml b/runtime/near-vm-runner-standalone/example-contract/Cargo.toml index 91707826836..a839cfefff5 100644 --- a/runtime/near-vm-runner-standalone/example-contract/Cargo.toml +++ b/runtime/near-vm-runner-standalone/example-contract/Cargo.toml @@ -13,7 +13,7 @@ serde_json = "1" wee_alloc = "0.4.5" near-sdk = "0.6.0" -borsh = "0.6.0" +borsh = "0.7.1" [profile.release] codegen-units = 1 From b68b88c11d75650fd969019b8cc815304af0b807 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Sun, 27 Sep 2020 10:00:14 -0700 Subject: [PATCH 36/82] Fixing more comments --- runtime/near-evm-runner/src/evm_state.rs | 5 ++++- runtime/near-evm-runner/src/interpreter.rs | 2 +- runtime/near-evm-runner/src/lib.rs | 5 ++++- runtime/near-evm-runner/src/near_ext.rs | 6 ++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index f50746d7a9b..0013957e0d9 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -64,7 +64,10 @@ pub trait EvmState { fn next_nonce(&mut self, address: &Address) -> Result { let mut account = self.get_account(address)?.unwrap_or_default(); let nonce = account.nonce; - account.nonce = account.nonce.saturating_add(U256::from(1)); + account.nonce = account + .nonce + .checked_add(U256::from(1)) + .ok_or_else(|| VMLogicError::EvmError(EvmError::IntegerOverflow))?; self.set_account(address, &account)?; Ok(nonce) } diff --git a/runtime/near-evm-runner/src/interpreter.rs b/runtime/near-evm-runner/src/interpreter.rs index 8cfc78845ca..051d93bc26e 100644 --- a/runtime/near-evm-runner/src/interpreter.rs +++ b/runtime/near-evm-runner/src/interpreter.rs @@ -24,7 +24,7 @@ pub fn deploy_code( recreate: bool, code: &[u8], ) -> Result
{ - let mut nonce = U256::default(); + let mut nonce = U256::zero(); if address_type == CreateContractAddress::FromSenderAndNonce { nonce = state.next_nonce(&sender)?; }; diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index a22eaedd925..47389a3e69b 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -257,7 +257,10 @@ impl<'a> EvmContext<'a> { pub fn get_code(&self, args: Vec) -> Result> { let args = AddressArg::try_from_slice(&args) .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; - Ok(self.code_at(&Address::from_slice(&args.address)).unwrap_or(None).unwrap_or(vec![])) + Ok(self + .code_at(&Address::from_slice(&args.address)) + .unwrap_or(None) + .unwrap_or_else(|| Vec::new())) } pub fn get_storage_at(&self, args: Vec) -> Result> { diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index b580795f371..047ee079a18 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use ethereum_types::{Address, H160, H256, U256}; +use ethereum_types::{Address, H256, U256}; use evm::ActionParams; use keccak_hash::keccak; use parity_bytes::Bytes; @@ -105,9 +105,7 @@ impl<'a> vm::Ext for NearExt<'a> { } fn origin_balance(&self) -> EvmResult { - // self.balance(&utils::predecessor_as_evm()) - // TODO: ?? - self.balance(&H160([0; 20])) + self.balance(&self.origin) } fn balance(&self, address: &Address) -> EvmResult { From 268ba2b71d6767e648f0d6296e37ddd761c0b139 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 28 Sep 2020 01:10:11 -0700 Subject: [PATCH 37/82] Propagate evm chain id from genesis config --- chain/chain/src/test_utils.rs | 4 +++ chain/chain/src/types.rs | 2 ++ chain/rosetta-rpc/src/utils.rs | 10 +++--- core/chain-configs/src/genesis_config.rs | 12 ++++++- neard/src/config.rs | 2 ++ neard/src/runtime.rs | 8 +++++ runtime/near-evm-runner/src/lib.rs | 8 ++++- runtime/near-evm-runner/tests/standard_ops.rs | 4 ++- runtime/near-evm-runner/tests/utils.rs | 6 +++- runtime/near-runtime-fees/src/lib.rs | 35 +++++++++++++++++-- .../runtime-params-estimator/src/testbed.rs | 1 + runtime/runtime-standalone/src/lib.rs | 5 ++- runtime/runtime/src/actions.rs | 1 + runtime/runtime/src/adapter.rs | 1 + runtime/runtime/src/lib.rs | 3 ++ runtime/runtime/src/state_viewer.rs | 7 ++++ .../runtime/tests/runtime_group_tools/mod.rs | 1 + test-utils/testlib/src/user/runtime_user.rs | 4 ++- 18 files changed, 100 insertions(+), 14 deletions(-) diff --git a/chain/chain/src/test_utils.rs b/chain/chain/src/test_utils.rs index b81dc937716..79e12b4dbca 100644 --- a/chain/chain/src/test_utils.rs +++ b/chain/chain/src/test_utils.rs @@ -948,6 +948,10 @@ impl RuntimeAdapter for KeyValueRuntime { ) -> Result<(ValidatorStake, bool), Error> { Err(ErrorKind::NotAValidator.into()) } + + fn evm_chain_id(&self) -> u128 { + 0x99 + } } pub fn setup() -> (Chain, Arc, Arc) { diff --git a/chain/chain/src/types.rs b/chain/chain/src/types.rs index 94504b8ba66..cee8279576b 100644 --- a/chain/chain/src/types.rs +++ b/chain/chain/src/types.rs @@ -562,6 +562,8 @@ pub trait RuntimeAdapter: Send + Sync { header_head: &CryptoHash, ) -> Result; + fn evm_chain_id(&self) -> u128; + /// Build receipts hashes. // Due to borsh serialization constraints, we have to use `&Vec` instead of `&[Receipt]` // here. diff --git a/chain/rosetta-rpc/src/utils.rs b/chain/rosetta-rpc/src/utils.rs index 5f8e6288d90..e96641d9b66 100644 --- a/chain/rosetta-rpc/src/utils.rs +++ b/chain/rosetta-rpc/src/utils.rs @@ -361,12 +361,10 @@ pub(crate) async fn query_accounts( crate::errors::ErrorKind, > { account_ids - .map(|account_id| { - async move { - let (_, _, account_info) = - query_account(block_id.clone(), account_id.clone(), &view_client_addr).await?; - Ok((account_id.clone(), account_info)) - } + .map(|account_id| async move { + let (_, _, account_info) = + query_account(block_id.clone(), account_id.clone(), &view_client_addr).await?; + Ok((account_id.clone(), account_info)) }) .collect::>() .collect:: Rational { Rational::new(90, 100) } @@ -36,7 +40,9 @@ fn default_protocol_upgrade_stake_threshold() -> Rational { Rational::new(8, 10) } -const MAX_GAS_PRICE: Balance = 10_000_000_000_000_000_000_000; +fn default_evm_chain_id() -> u128 { + TEST_EVM_CHAIN_ID +} #[derive(Debug, Clone, SmartDefault, Serialize, Deserialize)] pub struct GenesisConfig { @@ -48,6 +54,10 @@ pub struct GenesisConfig { /// ID of the blockchain. This must be unique for every blockchain. /// If your testnet blockchains do not have unique chain IDs, you will have a bad time. pub chain_id: String, + /// ID of the EVM chain: https://github.com/ethereum-lists/chains + #[default(TEST_EVM_CHAIN_ID)] + #[serde(with = "u128_dec_format_compatible", default = "default_evm_chain_id")] + pub evm_chain_id: u128, /// Height of genesis block. pub genesis_height: BlockHeight, /// Number of block producer seats at genesis. diff --git a/neard/src/config.rs b/neard/src/config.rs index 8c5b3f9a75a..969a02e905c 100644 --- a/neard/src/config.rs +++ b/neard/src/config.rs @@ -129,6 +129,8 @@ pub const MINIMUM_STAKE_DIVISOR: u64 = 10; /// Number of epochs before protocol upgrade. pub const PROTOCOL_UPGRADE_NUM_EPOCHS: EpochHeight = 2; +pub const TEST_EVM_CHAIN_ID: u128 = 0x99; + pub const CONFIG_FILENAME: &str = "config.json"; pub const GENESIS_CONFIG_FILENAME: &str = "genesis.json"; pub const NODE_KEY_FILE: &str = "node_key.json"; diff --git a/neard/src/runtime.rs b/neard/src/runtime.rs index dbf118c2cd4..09843b4d021 100644 --- a/neard/src/runtime.rs +++ b/neard/src/runtime.rs @@ -407,6 +407,7 @@ impl NightshadeRuntime { gas_limit: Some(gas_limit), random_seed, current_protocol_version, + evm_chain_id: self.evm_chain_id(), }; let apply_result = self @@ -1091,6 +1092,7 @@ impl RuntimeAdapter for NightshadeRuntime { &mut logs, &self.epoch_manager, current_protocol_version, + self.evm_chain_id(), ) { Ok(result) => Ok(QueryResponse { kind: QueryResponseKind::CallResult(CallResult { result, logs }), @@ -1308,6 +1310,10 @@ impl RuntimeAdapter for NightshadeRuntime { && chunk_next_epoch_id != head_epoch_id && chunk_epoch_id != head_next_epoch_id) } + + fn evm_chain_id(&self) -> u128 { + self.genesis_config.evm_chain_id + } } impl node_runtime::adapter::ViewRuntimeAdapter for NightshadeRuntime { @@ -1336,6 +1342,7 @@ impl node_runtime::adapter::ViewRuntimeAdapter for NightshadeRuntime { logs: &mut Vec, epoch_info_provider: &dyn EpochInfoProvider, current_protocol_version: ProtocolVersion, + evm_chain_id: u128, ) -> Result, Box> { let state_update = self.get_tries().new_trie_update(shard_id, state_root); self.trie_viewer.call_function( @@ -1351,6 +1358,7 @@ impl node_runtime::adapter::ViewRuntimeAdapter for NightshadeRuntime { logs, epoch_info_provider, current_protocol_version, + evm_chain_id, ) } diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 47389a3e69b..5858a845f4c 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -119,6 +119,7 @@ impl<'a> EvmState for EvmContext<'a> { impl<'a> EvmContext<'a> { pub fn new( ext: &'a mut dyn External, + chain_id: u128, config: &'a VMConfig, fees_config: &'a RuntimeFeesConfig, current_amount: Balance, @@ -136,7 +137,7 @@ impl<'a> EvmContext<'a> { config.limit_config.max_gas_burnt }; // TODO: pass chain id from ??? genesis / config. - let domain_separator = near_erc721_domain(U256::from(0x4e454152)); + let domain_separator = near_erc721_domain(U256::from(chain_id)); Self { ext, account_id, @@ -401,6 +402,7 @@ impl<'a> EvmContext<'a> { pub fn run_evm( ext: &mut dyn External, + chain_id: u128, config: &VMConfig, fees_config: &RuntimeFeesConfig, account_id: &AccountId, @@ -416,6 +418,7 @@ pub fn run_evm( ) -> (Option, Option) { let mut context = EvmContext::new( ext, + chain_id, config, fees_config, // This is total amount of all $NEAR inside this EVM. @@ -479,6 +482,8 @@ mod tests { use super::*; + const CHAIN_ID: u128 = 0x99; + fn setup() -> (MockedExternal, VMConfig, RuntimeFeesConfig) { let vm_config = VMConfig::default(); let fees_config = RuntimeFeesConfig::default(); @@ -494,6 +499,7 @@ mod tests { ) -> EvmContext<'a> { EvmContext::new( external, + CHAIN_ID, vm_config, fees_config, 0, diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 0e84cdb1e86..b9d13575dea 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -18,6 +18,7 @@ use near_vm_logic::VMConfig; use crate::utils::{ accounts, create_context, encode_meta_call_function_args, public_key_to_address, setup, + CHAIN_ID, }; mod utils; @@ -261,7 +262,8 @@ fn test_meta_call() { let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); let (input, _) = soltest::functions::return_some_funds::call(); - let meta_tx = encode_meta_call_function_args(&signer, test_addr, U256::from(0), input); + let meta_tx = + encode_meta_call_function_args(&signer, CHAIN_ID, test_addr, U256::from(0), input); let _ = context.meta_call_function(meta_tx.clone()).unwrap(); let signer_addr = public_key_to_address(signer.public_key); assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index bc42ee3271b..1d06d5b1e7b 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -10,6 +10,8 @@ use near_vm_logic::mocks::mock_external::MockedExternal; use near_vm_logic::types::Balance; use near_vm_logic::VMConfig; +pub const CHAIN_ID: u128 = 0x99; + pub fn accounts(num: usize) -> String { ["evm", "alice", "bob", "chad"][num].to_string() } @@ -30,6 +32,7 @@ pub fn create_context<'a>( ) -> EvmContext<'a> { EvmContext::new( external, + CHAIN_ID, vm_config, fees_config, 1000, @@ -58,11 +61,12 @@ pub fn public_key_to_address(public_key: PublicKey) -> Address { pub fn encode_meta_call_function_args( signer: &dyn Signer, + chain_id: u128, address: Address, nonce: U256, input: Vec, ) -> Vec { - let domain_separator = near_erc721_domain(U256::from(0x4e454152)); + let domain_separator = near_erc721_domain(U256::from(chain_id)); let call_args = encode_call_function_args(address, input); let args = prepare_meta_call_args(&domain_separator, &"evm".to_string(), nonce, &call_args); match signer.sign(&args) { diff --git a/runtime/near-runtime-fees/src/lib.rs b/runtime/near-runtime-fees/src/lib.rs index 1a0f29e88fc..33f82a1fcfb 100644 --- a/runtime/near-runtime-fees/src/lib.rs +++ b/runtime/near-runtime-fees/src/lib.rs @@ -9,6 +9,13 @@ use serde::{Deserialize, Serialize}; pub type Balance = u128; pub type Gas = u64; +/// The amount is 1000 * 10e24 = 1000 NEAR. +const EVM_DEPOSIT: Balance = 1_000_000_000_000_000_000_000_000_000; + +fn default_evm_deposit() -> Balance { + EVM_DEPOSIT +} + /// Costs associated with an object that can only be sent over the network (and executed /// by the receiver). /// NOTE: `send_sir` or `send_not_sir` fees are usually burned when the item is being created. @@ -66,6 +73,7 @@ pub struct RuntimeFeesConfig { pub pessimistic_gas_price_inflation_ratio: Rational, /// New EVM deposit. + #[serde(with = "u128_dec_format", default = "default_evm_deposit")] pub evm_deposit: Balance, } @@ -232,8 +240,7 @@ impl Default for RuntimeFeesConfig { }, burnt_gas_reward: Rational::new(3, 10), pessimistic_gas_price_inflation_ratio: Rational::new(103, 100), - // The amount is 1000 * 10e24 = 1000 NEAR. - evm_deposit: 1_000_000_000_000_000_000_000_000_000, + evm_deposit: EVM_DEPOSIT, } } } @@ -283,6 +290,30 @@ impl RuntimeFeesConfig { } } +/// Serde serializer for u128 to integer. +/// This is copy from core/primitives/src/serialize.rs +/// It is required as this module doesn't depend on primitives. +/// TODO(3384): move basic primitives into a separate module and use in runtime. +pub mod u128_dec_format { + use serde::de; + use serde::{Deserialize, Deserializer, Serializer}; + + pub fn serialize(num: &u128, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&format!("{}", num)) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + u128::from_str_radix(&s, 10).map_err(de::Error::custom) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/runtime/runtime-params-estimator/src/testbed.rs b/runtime/runtime-params-estimator/src/testbed.rs index f9df04011fc..d66198666a7 100644 --- a/runtime/runtime-params-estimator/src/testbed.rs +++ b/runtime/runtime-params-estimator/src/testbed.rs @@ -86,6 +86,7 @@ impl RuntimeTestbed { gas_limit: None, random_seed: Default::default(), current_protocol_version: PROTOCOL_VERSION, + evm_chain_id: 0x99, }; Self { workdir, diff --git a/runtime/runtime-standalone/src/lib.rs b/runtime/runtime-standalone/src/lib.rs index 9acc60d0e3a..988a5562006 100644 --- a/runtime/runtime-standalone/src/lib.rs +++ b/runtime/runtime-standalone/src/lib.rs @@ -24,6 +24,8 @@ use node_runtime::{state_viewer::TrieViewer, ApplyState, Runtime}; const DEFAULT_EPOCH_LENGTH: u64 = 3; +const CHAIN_ID: u128 = 0x99; + pub fn init_runtime_and_signer(root_account_id: &AccountId) -> (RuntimeStandalone, InMemorySigner) { let mut genesis = GenesisConfig::default(); let signer = genesis.init_root_signer(root_account_id); @@ -216,6 +218,7 @@ impl RuntimeStandalone { last_block_hash: CryptoHash::default(), epoch_id: EpochId::default(), current_protocol_version: PROTOCOL_VERSION, + evm_chain_id: CHAIN_ID, }; let apply_result = self.runtime.apply( @@ -249,7 +252,6 @@ impl RuntimeStandalone { /// assert_eq!(runtime.current_block().block_height, 5); /// assert_eq!(runtime.current_block().epoch_height, 1); ///``` - pub fn produce_blocks(&mut self, num_of_blocks: u64) -> Result<(), RuntimeError> { for _ in 0..num_of_blocks { self.produce_block()?; @@ -305,6 +307,7 @@ impl RuntimeStandalone { &mut logs, self.epoch_info_provider.as_ref(), PROTOCOL_VERSION, + CHAIN_ID, )?; Ok((result, logs)) } diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 0d741984984..4490f5e8061 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -52,6 +52,7 @@ pub(crate) fn execute_function_call( if is_account_evm(&account_id) { near_evm_runner::run_evm( runtime_ext, + apply_state.evm_chain_id, &config.wasm_config, &config.transaction_costs, &account_id, diff --git a/runtime/runtime/src/adapter.rs b/runtime/runtime/src/adapter.rs index bdce1a91dbd..3922f1272ab 100644 --- a/runtime/runtime/src/adapter.rs +++ b/runtime/runtime/src/adapter.rs @@ -31,6 +31,7 @@ pub trait ViewRuntimeAdapter { logs: &mut Vec, epoch_info_provider: &dyn EpochInfoProvider, current_protocol_version: ProtocolVersion, + evm_chain_id: u128, ) -> Result, Box>; fn view_access_key( diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs index 1a016b080c8..07c56976734 100644 --- a/runtime/runtime/src/lib.rs +++ b/runtime/runtime/src/lib.rs @@ -79,6 +79,8 @@ pub struct ApplyState { pub random_seed: CryptoHash, /// Current Protocol version when we apply the state transition pub current_protocol_version: ProtocolVersion, + /// Ethereum chain id. + pub evm_chain_id: u128, } /// Contains information to update validators accounts at the first block of a new epoch. @@ -1521,6 +1523,7 @@ mod tests { gas_limit: Some(gas_limit), random_seed: Default::default(), current_protocol_version: PROTOCOL_VERSION, + evm_chain_id: 0x99, }; (runtime, tries, root, apply_state, signer, MockEpochInfoProvider::default()) diff --git a/runtime/runtime/src/state_viewer.rs b/runtime/runtime/src/state_viewer.rs index 178bd57ab9d..da436eeda3b 100644 --- a/runtime/runtime/src/state_viewer.rs +++ b/runtime/runtime/src/state_viewer.rs @@ -100,6 +100,7 @@ impl TrieViewer { logs: &mut Vec, epoch_info_provider: &dyn EpochInfoProvider, current_protocol_version: ProtocolVersion, + evm_chain_id: u128, ) -> Result, Box> { let now = Instant::now(); if !is_valid_account_id(contract_id) { @@ -135,6 +136,7 @@ impl TrieViewer { gas_limit: None, random_seed: root, current_protocol_version, + evm_chain_id, }; let action_receipt = ActionReceipt { signer_id: originator_id.clone(), @@ -220,6 +222,7 @@ mod tests { &mut logs, &MockEpochInfoProvider::default(), PROTOCOL_VERSION, + 0x99, ); assert_eq!(result.unwrap(), encode_int(10)); @@ -243,6 +246,7 @@ mod tests { &mut logs, &MockEpochInfoProvider::default(), PROTOCOL_VERSION, + 0x99, ); let err = result.unwrap_err(); @@ -270,6 +274,7 @@ mod tests { &mut logs, &MockEpochInfoProvider::default(), PROTOCOL_VERSION, + 0x99, ); let err = result.unwrap_err(); assert!( @@ -296,6 +301,7 @@ mod tests { &mut logs, &MockEpochInfoProvider::default(), PROTOCOL_VERSION, + 0x99, ); assert_eq!(view_call_result.unwrap(), 3u64.to_le_bytes().to_vec()); } @@ -376,6 +382,7 @@ mod tests { &mut logs, &MockEpochInfoProvider::default(), PROTOCOL_VERSION, + 0x99, ) .unwrap_err(); diff --git a/runtime/runtime/tests/runtime_group_tools/mod.rs b/runtime/runtime/tests/runtime_group_tools/mod.rs index 93de526f93a..c06945054d7 100644 --- a/runtime/runtime/tests/runtime_group_tools/mod.rs +++ b/runtime/runtime/tests/runtime_group_tools/mod.rs @@ -66,6 +66,7 @@ impl StandaloneRuntime { gas_limit: None, random_seed: Default::default(), current_protocol_version: PROTOCOL_VERSION, + evm_chain_id: 0x99, }; Self { diff --git a/test-utils/testlib/src/user/runtime_user.rs b/test-utils/testlib/src/user/runtime_user.rs index 4ec54f15d47..f951523c40a 100644 --- a/test-utils/testlib/src/user/runtime_user.rs +++ b/test-utils/testlib/src/user/runtime_user.rs @@ -17,7 +17,7 @@ use near_primitives::views::{ FinalExecutionStatus, ViewStateResult, }; use near_store::{ShardTries, TrieUpdate}; -use neard::config::MIN_GAS_PRICE; +use neard::config::{MIN_GAS_PRICE, TEST_EVM_CHAIN_ID}; use node_runtime::state_viewer::TrieViewer; use node_runtime::{ApplyState, Runtime}; @@ -129,6 +129,7 @@ impl RuntimeUser { random_seed: Default::default(), epoch_id: Default::default(), current_protocol_version: PROTOCOL_VERSION, + evm_chain_id: TEST_EVM_CHAIN_ID, } } @@ -232,6 +233,7 @@ impl User for RuntimeUser { &mut result.logs, &self.epoch_info_provider, PROTOCOL_VERSION, + TEST_EVM_CHAIN_ID, ) .map_err(|err| err.to_string())?; Ok(result) From 95acffacaaa004c0a7180e278acbfdc63857c644 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 5 Oct 2020 04:26:37 -0700 Subject: [PATCH 38/82] Adding protocol bump to 40 when EVM activates --- chain/jsonrpc/src/lib.rs | 5 ++++- core/primitives/src/version.rs | 5 ++++- runtime/runtime/src/actions.rs | 8 ++++++-- runtime/runtime/src/ext.rs | 5 +++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/chain/jsonrpc/src/lib.rs b/chain/jsonrpc/src/lib.rs index 63651aefa1d..cfe38b3d97d 100644 --- a/chain/jsonrpc/src/lib.rs +++ b/chain/jsonrpc/src/lib.rs @@ -38,8 +38,11 @@ use near_primitives::rpc::{ use near_primitives::serialize::{from_base, from_base64, BaseEncode}; use near_primitives::transaction::SignedTransaction; use near_primitives::types::{AccountId, BlockId, BlockReference, MaybeBlockId}; -use near_primitives::views::{FinalExecutionOutcomeView, QueryRequest}; +use near_primitives::views::{ + FinalExecutionOutcomeView, FinalExecutionOutcomeViewEnum, QueryRequest, +}; use near_runtime_utils::is_valid_account_id; + mod metrics; /// Max size of the query path (soft-deprecated) diff --git a/core/primitives/src/version.rs b/core/primitives/src/version.rs index 5a49e75c9ef..ee384f84a3f 100644 --- a/core/primitives/src/version.rs +++ b/core/primitives/src/version.rs @@ -18,7 +18,7 @@ pub const DB_VERSION: DbVersion = 12; pub type ProtocolVersion = u32; /// Current latest version of the protocol. -pub const PROTOCOL_VERSION: ProtocolVersion = 39; +pub const PROTOCOL_VERSION: ProtocolVersion = 40; /// Oldest supported version by this client. pub const OLDEST_BACKWARD_COMPATIBLE_PROTOCOL_VERSION: ProtocolVersion = 34; @@ -44,3 +44,6 @@ pub const UPGRADABILITY_FIX_PROTOCOL_VERSION: ProtocolVersion = 37; /// Updates the way receipt ID, data ID and random seeds are constructed. pub const CREATE_HASH_PROTOCOL_VERSION: ProtocolVersion = 38; + +/// Adding EVM precompile. +pub const EVM_PRECOMPILE_PROTOCOL_VERSION: ProtocolVersion = 40; diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 4490f5e8061..6f22b78a400 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -12,7 +12,9 @@ use near_primitives::transaction::{ }; use near_primitives::types::{AccountId, EpochInfoProvider, ValidatorStake}; use near_primitives::utils::create_random_seed; -use near_primitives::version::{ProtocolVersion, IMPLICIT_ACCOUNT_CREATION_PROTOCOL_VERSION}; +use near_primitives::version::{ + ProtocolVersion, EVM_PRECOMPILE_PROTOCOL_VERSION, IMPLICIT_ACCOUNT_CREATION_PROTOCOL_VERSION, +}; use near_runtime_configs::AccountCreationConfig; use near_runtime_fees::RuntimeFeesConfig; use near_runtime_utils::{ @@ -49,7 +51,9 @@ pub(crate) fn execute_function_call( is_view: bool, ) -> (Option, Option) { let account_id = runtime_ext.account_id(); - if is_account_evm(&account_id) { + if runtime_ext.protocol_version() >= EVM_PRECOMPILE_PROTOCOL_VERSION + && is_account_evm(&account_id) + { near_evm_runner::run_evm( runtime_ext, apply_state.evm_chain_id, diff --git a/runtime/runtime/src/ext.rs b/runtime/runtime/src/ext.rs index 7eed29898da..ac28e0b207d 100644 --- a/runtime/runtime/src/ext.rs +++ b/runtime/runtime/src/ext.rs @@ -126,6 +126,11 @@ impl<'a> RuntimeExt<'a> { .actions .push(action); } + + #[inline] + pub fn protocol_version(&self) -> ProtocolVersion { + self.current_protocol_version + } } fn wrap_storage_error(error: StorageError) -> VMLogicError { From 9e99e3967024302d8260b95214e9fd0c8f716127 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 5 Oct 2020 04:39:37 -0700 Subject: [PATCH 39/82] Cleanup usage of Address vs [u8; 20] --- runtime/near-evm-runner/src/evm_state.rs | 86 +++++++++++----------- runtime/near-evm-runner/src/interpreter.rs | 2 +- runtime/near-evm-runner/src/lib.rs | 10 +-- runtime/near-evm-runner/src/types.rs | 1 + runtime/near-evm-runner/src/utils.rs | 8 -- 5 files changed, 48 insertions(+), 59 deletions(-) diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index 0013957e0d9..5848d57bcf1 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -2,12 +2,12 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::io::{Error, Write}; use borsh::{BorshDeserialize, BorshSerialize}; -use ethereum_types::{Address, U256}; +use ethereum_types::{Address, H160, U256}; use near_vm_errors::EvmError; use near_vm_logic::VMLogicError; -use crate::types::{RawAddress, Result}; +use crate::types::{DataKey, RawU256, Result}; use crate::utils; #[derive(Default, Clone, Copy, Debug)] @@ -72,18 +72,18 @@ pub trait EvmState { Ok(nonce) } - fn _read_contract_storage(&self, key: [u8; 52]) -> Result>; - fn read_contract_storage(&self, address: &Address, key: [u8; 32]) -> Result> { + fn _read_contract_storage(&self, key: DataKey) -> Result>; + fn read_contract_storage(&self, address: &Address, key: RawU256) -> Result> { self._read_contract_storage(utils::internal_storage_key(address, key)) } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Result<()>; + fn _set_contract_storage(&mut self, key: DataKey, value: RawU256) -> Result<()>; fn set_contract_storage( &mut self, address: &Address, - key: [u8; 32], - value: [u8; 32], + key: RawU256, + value: RawU256, ) -> Result<()> { self._set_contract_storage(utils::internal_storage_key(address, key), value) } @@ -118,27 +118,27 @@ pub trait EvmState { self.add_balance(recipient, amnt) } - fn recreate(&mut self, address: [u8; 20]); + fn recreate(&mut self, address: Address); } #[derive(Default, Debug)] pub struct StateStore { - pub code: HashMap>, - pub accounts: HashMap, - pub storages: BTreeMap, [u8; 32]>, + pub code: HashMap>, + pub accounts: HashMap, + pub storages: BTreeMap, RawU256>, pub logs: Vec, - pub self_destructs: HashSet<[u8; 20]>, - pub recreated: HashSet<[u8; 20]>, + pub self_destructs: HashSet
, + pub recreated: HashSet
, } impl StateStore { - fn overwrite_storage(&mut self, addr: [u8; 20]) { - let address_key = addr.to_vec(); + fn overwrite_storage(&mut self, addr: Address) { + let address_key = addr.0.to_vec(); // If address in the last, use RangeFrom to remove all elements until the end. - let keys: Vec<_> = if addr == [255; 20] { + let keys: Vec<_> = if addr.0 == [255; 20] { self.storages.range(std::ops::RangeFrom { start: address_key }) } else { - let next_address = utils::safe_next_address(&addr); + let next_address = utils::safe_next_address(&addr.0); let range = ( std::ops::Bound::Excluded(address_key), @@ -154,63 +154,61 @@ impl StateStore { } } - pub fn commit_code(&mut self, other: &HashMap<[u8; 20], Vec>) { + pub fn commit_code(&mut self, other: &HashMap>) { self.code.extend(other.iter().map(|(k, v)| (*k, v.clone()))); } - pub fn commit_accounts(&mut self, other: &HashMap<[u8; 20], EvmAccount>) { + pub fn commit_accounts(&mut self, other: &HashMap) { self.accounts.extend(other.iter().map(|(k, v)| (*k, *v))); } - pub fn commit_storages(&mut self, other: &BTreeMap, [u8; 32]>) { + pub fn commit_storages(&mut self, other: &BTreeMap, RawU256>) { self.storages.extend(other.iter().map(|(k, v)| (k.clone(), *v))) } - pub fn commit_self_destructs(&mut self, other: &HashSet<[u8; 20]>) { + pub fn commit_self_destructs(&mut self, other: &HashSet
) { self.self_destructs.extend(other); } - pub fn commit_recreated(&mut self, other: &HashSet<[u8; 20]>) { + pub fn commit_recreated(&mut self, other: &HashSet
) { self.recreated.extend(other); } } impl EvmState for StateStore { fn code_at(&self, address: &Address) -> Result>> { - let internal_addr = utils::evm_account_to_internal_address(*address); - if self.self_destructs.contains(&internal_addr) { + if self.self_destructs.contains(address) { Ok(None) } else { - Ok(self.code.get(&internal_addr).cloned()) + Ok(self.code.get(address).cloned()) } } fn set_code(&mut self, address: &Address, bytecode: &[u8]) -> Result<()> { - let internal_addr = utils::evm_account_to_internal_address(*address); - self.code.insert(internal_addr, bytecode.to_vec()); + self.code.insert(address.clone(), bytecode.to_vec()); Ok(()) } fn get_account(&self, address: &Address) -> Result> { - Ok(self.accounts.get(&address.0).map(|account| account.clone())) + Ok(self.accounts.get(&address).map(|account| account.clone())) } fn set_account(&mut self, address: &Address, account: &EvmAccount) -> Result<()> { - self.accounts.insert(address.0, account.clone()); + self.accounts.insert(address.clone(), account.clone()); Ok(()) } - fn _read_contract_storage(&self, key: [u8; 52]) -> Result> { + fn _read_contract_storage(&self, key: DataKey) -> Result> { let mut addr = [0u8; 20]; addr.copy_from_slice(&key[..20]); - if self.self_destructs.contains(&addr) { + if self.self_destructs.contains(&H160(addr)) { Ok(None) } else { Ok(self.storages.get(&key.to_vec()).cloned()) } } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Result<()> { + fn _set_contract_storage(&mut self, key: DataKey, value: RawU256) -> Result<()> { self.storages.insert(key.to_vec(), value); Ok(()) } @@ -225,7 +223,7 @@ impl EvmState for StateStore { Ok(()) } - fn recreate(&mut self, addr: [u8; 20]) { + fn recreate(&mut self, addr: Address) { self.code.remove(&addr); // We do not remove account because balances persist across recreation. self.accounts.entry(addr).or_insert(EvmAccount::default()).nonce = U256::from(0); @@ -251,7 +249,7 @@ impl SubState<'_> { } pub fn self_destruct(&mut self, address: &Address) -> Result<()> { - self.state.self_destructs.insert(address.0); + self.state.self_destructs.insert(address.clone()); let mut account = self.get_account(address)?.unwrap_or_default(); account.nonce = U256::from(0); self.state.set_account(address, &account) @@ -260,20 +258,18 @@ impl SubState<'_> { impl EvmState for SubState<'_> { fn code_at(&self, address: &Address) -> Result>> { - let internal_addr = utils::evm_account_to_internal_address(*address); - if self.state.self_destructs.contains(&internal_addr) { + if self.state.self_destructs.contains(address) { Ok(None) } else { self.state .code - .get(&internal_addr) + .get(&address) .map_or_else(|| self.parent.code_at(address), |k| Ok(Some(k.to_vec()))) } } fn set_code(&mut self, address: &Address, bytecode: &[u8]) -> Result<()> { - let internal_addr = utils::evm_account_to_internal_address(*address); - self.state.code.insert(internal_addr, bytecode.to_vec()); + self.state.code.insert(address.clone(), bytecode.to_vec()); Ok(()) } @@ -287,10 +283,10 @@ impl EvmState for SubState<'_> { self.state.set_account(address, account) } - fn _read_contract_storage(&self, key: [u8; 52]) -> Result> { + fn _read_contract_storage(&self, key: DataKey) -> Result> { let mut addr = [0u8; 20]; addr.copy_from_slice(&key[..20]); - if self.state.self_destructs.contains(&addr) { + if self.state.self_destructs.contains(&H160(addr)) { Ok(None) } else { self.state @@ -301,7 +297,7 @@ impl EvmState for SubState<'_> { } } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Result<()> { + fn _set_contract_storage(&mut self, key: DataKey, value: RawU256) -> Result<()> { self.state.storages.insert(key.to_vec(), value); Ok(()) } @@ -316,7 +312,7 @@ impl EvmState for SubState<'_> { Ok(()) } - fn recreate(&mut self, address: [u8; 20]) { + fn recreate(&mut self, address: Address) { self.state.recreate(address); } } @@ -460,8 +456,8 @@ mod test { let mut top = StateStore::default(); let mut address = [0; 20]; address[19] = 255; - top.overwrite_storage(address); - top.overwrite_storage([255; 20]); + top.overwrite_storage(H160(address)); + top.overwrite_storage(H160([255; 20])); } #[test] diff --git a/runtime/near-evm-runner/src/interpreter.rs b/runtime/near-evm-runner/src/interpreter.rs index 051d93bc26e..aee86c9121d 100644 --- a/runtime/near-evm-runner/src/interpreter.rs +++ b/runtime/near-evm-runner/src/interpreter.rs @@ -31,7 +31,7 @@ pub fn deploy_code( let (address, _) = utils::evm_contract_address(address_type, &sender, &nonce, &code); if recreate { - state.recreate(address.0); + state.recreate(address); } else if state.code_at(&address)?.is_some() { return Err(VMLogicError::EvmError(EvmError::DuplicateContract(address.0.to_vec()))); } diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 5858a845f4c..76dd46bd323 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -97,10 +97,10 @@ impl<'a> EvmState for EvmContext<'a> { self.clear_contract_info(address)?; } for (address, code) in other.code.iter() { - self.set_code(&H160(*address), code)?; + self.set_code(address, code)?; } for (address, account) in other.accounts.iter() { - self.set_account(&H160(*address), account)?; + self.set_account(address, account)?; } for (key, value) in other.storages.iter() { let mut arr = [0; 52]; @@ -111,7 +111,7 @@ impl<'a> EvmState for EvmContext<'a> { Ok(()) } - fn recreate(&mut self, _address: [u8; 20]) { + fn recreate(&mut self, _address: Address) { unreachable!() } } @@ -159,8 +159,8 @@ impl<'a> EvmContext<'a> { } } - fn clear_contract_info(&mut self, other: &[u8; 20]) -> Result<()> { - self.ext.storage_remove_subtree(other) + fn clear_contract_info(&mut self, other: &Address) -> Result<()> { + self.ext.storage_remove_subtree(&other.0) } pub fn deploy_code(&mut self, bytecode: Vec) -> Result
{ diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index b08e169c42f..2c0fbd07dd5 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -9,6 +9,7 @@ use near_vm_logic::types::AccountId; pub type RawAddress = [u8; 20]; pub type RawHash = [u8; 32]; pub type RawU256 = [u8; 32]; +pub type DataKey = [u8; 52]; pub type Result = std::result::Result; diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index fc23d03a824..be2e5c8e0b3 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -27,10 +27,6 @@ pub fn internal_storage_key(address: &Address, key: [u8; 32]) -> [u8; 52] { k } -pub fn evm_account_to_internal_address(addr: Address) -> [u8; 20] { - addr.0 -} - pub fn near_account_bytes_to_evm_address(addr: &[u8]) -> Address { Address::from_slice(&keccak(addr)[12..]) } @@ -39,10 +35,6 @@ pub fn near_account_id_to_evm_address(account_id: &str) -> Address { near_account_bytes_to_evm_address(&account_id.to_string().into_bytes()) } -pub fn near_account_id_to_internal_address(account_id: &str) -> [u8; 20] { - evm_account_to_internal_address(near_account_id_to_evm_address(account_id)) -} - pub fn hex_to_evm_address(address: &str) -> Address { let addr = hex::decode(&address).expect("Hex string not valid hex"); Address::from_slice(&addr) From 8a96157302d91ac2d8b860a26380902886ad862e Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 5 Oct 2020 13:50:54 -0700 Subject: [PATCH 40/82] Continue addressing comments --- neard/res/genesis_config.json | 2 +- runtime/near-evm-runner/src/evm_state.rs | 90 +++++++++++++----------- runtime/near-evm-runner/src/lib.rs | 87 +++++++++++++++-------- runtime/near-evm-runner/src/near_ext.rs | 17 +++-- runtime/near-evm-runner/src/utils.rs | 45 +++++++----- runtime/near-evm-runner/tests/utils.rs | 4 ++ runtime/near-vm-errors/src/lib.rs | 2 + 7 files changed, 154 insertions(+), 93 deletions(-) diff --git a/neard/res/genesis_config.json b/neard/res/genesis_config.json index 188ebfe0855..fe475ef5378 100644 --- a/neard/res/genesis_config.json +++ b/neard/res/genesis_config.json @@ -1,5 +1,5 @@ { - "protocol_version": 39, + "protocol_version": 40, "genesis_time": "1970-01-01T00:00:00.000000000Z", "chain_id": "sample", "genesis_height": 0, diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index 5848d57bcf1..a47d037e55a 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -1,14 +1,15 @@ -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{HashMap, HashSet}; use std::io::{Error, Write}; use borsh::{BorshDeserialize, BorshSerialize}; -use ethereum_types::{Address, H160, U256}; +use ethereum_types::{Address, U256}; use near_vm_errors::EvmError; use near_vm_logic::VMLogicError; use crate::types::{DataKey, RawU256, Result}; use crate::utils; +use crate::utils::split_data_key; #[derive(Default, Clone, Copy, Debug)] pub struct EvmAccount { @@ -125,33 +126,34 @@ pub trait EvmState { pub struct StateStore { pub code: HashMap>, pub accounts: HashMap, - pub storages: BTreeMap, RawU256>, + pub storages: HashMap>, pub logs: Vec, pub self_destructs: HashSet
, pub recreated: HashSet
, } impl StateStore { - fn overwrite_storage(&mut self, addr: Address) { - let address_key = addr.0.to_vec(); - // If address in the last, use RangeFrom to remove all elements until the end. - let keys: Vec<_> = if addr.0 == [255; 20] { - self.storages.range(std::ops::RangeFrom { start: address_key }) - } else { - let next_address = utils::safe_next_address(&addr.0); - - let range = ( - std::ops::Bound::Excluded(address_key), - std::ops::Bound::Excluded(next_address.to_vec()), - ); - - self.storages.range(range) - } - .map(|(k, _)| k.clone()) - .collect(); - for k in keys.iter() { - self.storages.remove(k); - } + fn delete_from_storage(&mut self, addr: &Address) { + self.storages.remove(addr); + // let address_key = addr.0.to_vec(); + // // If address in the last, use RangeFrom to remove all elements until the end. + // let keys: Vec<_> = if addr.0 == [255; 20] { + // self.storages.range(std::ops::RangeFrom { start: address_key }) + // } else { + // let next_address = utils::safe_next_address(&addr.0); + // + // let range = ( + // std::ops::Bound::Excluded(address_key), + // std::ops::Bound::Excluded(next_address.to_vec()), + // ); + // + // self.storages.range(range) + // } + // .map(|(k, _)| k.clone()) + // .collect(); + // for k in keys.iter() { + // self.storages.remove(k); + // } } pub fn commit_code(&mut self, other: &HashMap>) { @@ -162,8 +164,14 @@ impl StateStore { self.accounts.extend(other.iter().map(|(k, v)| (*k, *v))); } - pub fn commit_storages(&mut self, other: &BTreeMap, RawU256>) { - self.storages.extend(other.iter().map(|(k, v)| (k.clone(), *v))) + pub fn commit_storages(&mut self, other: &HashMap>) { + for (address, values) in other.iter() { + if let Some(acc) = self.storages.get_mut(address) { + acc.extend(values.iter().map(|(k, v)| (k.clone(), *v))); + } else { + self.storages.insert(address.clone(), values.clone()); + } + } } pub fn commit_self_destructs(&mut self, other: &HashSet
) { @@ -199,17 +207,17 @@ impl EvmState for StateStore { } fn _read_contract_storage(&self, key: DataKey) -> Result> { - let mut addr = [0u8; 20]; - addr.copy_from_slice(&key[..20]); - if self.self_destructs.contains(&H160(addr)) { + let (addr, subkey) = split_data_key(&key); + if self.self_destructs.contains(&addr) { Ok(None) } else { - Ok(self.storages.get(&key.to_vec()).cloned()) + Ok(self.storages.get(&addr).and_then(|x| x.get(&subkey).cloned())) } } fn _set_contract_storage(&mut self, key: DataKey, value: RawU256) -> Result<()> { - self.storages.insert(key.to_vec(), value); + let (addr, subkey) = split_data_key(&key); + self.storages.entry(addr).or_insert_with(|| HashMap::default()).insert(subkey, value); Ok(()) } @@ -227,7 +235,7 @@ impl EvmState for StateStore { self.code.remove(&addr); // We do not remove account because balances persist across recreation. self.accounts.entry(addr).or_insert(EvmAccount::default()).nonce = U256::from(0); - self.overwrite_storage(addr); + self.delete_from_storage(&addr); self.self_destructs.remove(&addr); self.recreated.insert(addr); } @@ -284,21 +292,21 @@ impl EvmState for SubState<'_> { } fn _read_contract_storage(&self, key: DataKey) -> Result> { - let mut addr = [0u8; 20]; - addr.copy_from_slice(&key[..20]); - if self.state.self_destructs.contains(&H160(addr)) { + let (addr, subkey) = split_data_key(&key); + if self.state.self_destructs.contains(&addr) { Ok(None) } else { self.state .storages - .get(&key.to_vec()) - .copied() - .map_or_else(|| self.parent._read_contract_storage(key), |v| Ok(Some(v))) + .get(&addr) + .and_then(|x| x.get(&subkey)) + .map_or_else(|| self.parent._read_contract_storage(key), |v| Ok(Some(v.clone()))) } } fn _set_contract_storage(&mut self, key: DataKey, value: RawU256) -> Result<()> { - self.state.storages.insert(key.to_vec(), value); + let (addr, subkey) = split_data_key(&key); + self.state.storages.entry(addr).or_insert_with(|| HashMap::default()).insert(subkey, value); Ok(()) } @@ -321,6 +329,8 @@ impl EvmState for SubState<'_> { mod test { use super::*; + use ethereum_types::H160; + #[test] fn substate_tests() { let addr_0 = Address::repeat_byte(0); @@ -456,8 +466,8 @@ mod test { let mut top = StateStore::default(); let mut address = [0; 20]; address[19] = 255; - top.overwrite_storage(H160(address)); - top.overwrite_storage(H160([255; 20])); + top.delete_from_storage(&H160(address)); + top.delete_from_storage(&H160([255; 20])); } #[test] diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 76dd46bd323..66d9a88e5a2 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -6,7 +6,7 @@ use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; use near_runtime_fees::RuntimeFeesConfig; -use near_runtime_utils::is_valid_sub_account_id; +use near_runtime_utils::{is_account_id_64_len_hex, is_valid_sub_account_id}; use near_vm_errors::{EvmError, FunctionCallError, VMError}; use near_vm_logic::gas_counter::GasCounter; use near_vm_logic::types::{AccountId, Balance, Gas, ReturnData, StorageUsage}; @@ -16,7 +16,10 @@ use crate::evm_state::{EvmAccount, EvmState, StateStore}; use crate::types::{ AddressArg, GetStorageAtArgs, Result, TransferArgs, ViewCallArgs, WithdrawArgs, }; -use crate::utils::{ecrecover_address, near_erc721_domain, prepare_meta_call_args}; +use crate::utils::{ + combine_data_key, ecrecover_address, near_erc721_domain, prepare_meta_call_args, +}; +use near_vm_errors::InconsistentStateError::StorageError; mod builtins; mod evm_state; @@ -63,11 +66,16 @@ impl<'a> EvmState for EvmContext<'a> { } fn get_account(&self, address: &Address) -> Result> { - self.ext.storage_get(&address_to_key(KeyPrefix::Account, address)).map(|value| { - value.map(|x| { - EvmAccount::try_from_slice(&x.deref().expect("Failed to deref")).unwrap_or_default() - }) - }) + match self.ext.storage_get(&address_to_key(KeyPrefix::Account, address)).map(|value| { + value.map(|x| EvmAccount::try_from_slice(&x.deref().expect("Failed to deref"))) + }) { + Ok(Some(Ok(value))) => Ok(Some(value)), + Ok(None) => Ok(None), + Ok(Some(Err(_))) => Err(VMLogicError::InconsistentStateError(StorageError( + "Failed to deserialize".to_string(), + ))), + Err(e) => Err(e), + } } fn set_account(&mut self, address: &Address, account: &EvmAccount) -> Result<()> { @@ -78,11 +86,17 @@ impl<'a> EvmState for EvmContext<'a> { } fn _read_contract_storage(&self, key: [u8; 52]) -> Result> { - self.ext.storage_get(&key).map(|value| { - value.map(|x| { - utils::vec_to_arr_32(x.deref().expect("Failed to deref")).expect("Must be 32 bytes") - }) - }) + match self + .ext + .storage_get(&key) + .map(|value| value.map(|x| utils::vec_to_arr_32(x.deref().expect("Failed to deref")))) + { + Ok(Some(value)) => Ok(value), + Ok(None) => Err(VMLogicError::InconsistentStateError(StorageError( + "Must be 32 bytes".to_string(), + ))), + Err(err) => Err(err), + } } fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Result<()> { @@ -102,10 +116,11 @@ impl<'a> EvmState for EvmContext<'a> { for (address, account) in other.accounts.iter() { self.set_account(address, account)?; } - for (key, value) in other.storages.iter() { - let mut arr = [0; 52]; - arr.copy_from_slice(&key); - self._set_contract_storage(arr, *value)?; + for (address, values) in other.storages.iter() { + for (key, value) in values.iter() { + let key = combine_data_key(address, key); + self._set_contract_storage(key, *value)?; + } } self.logs.extend_from_slice(&other.logs); Ok(()) @@ -299,13 +314,16 @@ impl<'a> EvmContext<'a> { pub fn withdraw(&mut self, args: Vec) -> Result<()> { let args = WithdrawArgs::try_from_slice(&args) .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + if args.account_id == self.account_id { + return Err(VMLogicError::EvmError(EvmError::FailSelfWithdraw)); + } let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); let amount = U256::from(args.amount); if amount > self.balance_of(&sender)? { return Err(VMLogicError::EvmError(EvmError::InsufficientFunds)); } self.sub_balance(&sender, amount)?; - let receipt_index = self.ext.create_receipt(vec![], args.account_id)?; + let receipt_index = self.ext.create_receipt(vec![], args.account_id.clone())?; // We use low_u128, because NEAR native currency fits into u128. let amount = amount.low_u128(); self.current_amount = self @@ -313,12 +331,7 @@ impl<'a> EvmContext<'a> { .checked_sub(amount) .ok_or_else(|| VMLogicError::EvmError(EvmError::InsufficientFunds))?; self.pay_gas_for_new_receipt(false, &[])?; - self.gas_counter.pay_action_base( - &self.fees_config.action_creation_config.transfer_cost, - // TOOD: Hm, what if they withdraw to itself? We should probably close circuit that here. - false, - ActionCosts::transfer, - )?; + self.pay_gas_for_transfer(&args.account_id)?; self.ext.append_action_transfer(receipt_index, amount) } @@ -351,7 +364,7 @@ impl<'a> EvmContext<'a> { .current_amount .checked_sub(self.attached_deposit) .ok_or_else(|| VMLogicError::EvmError(EvmError::InsufficientFunds))?; - let receipt_index = self.ext.create_receipt(vec![], new_account_id)?; + let receipt_index = self.ext.create_receipt(vec![], new_account_id.clone())?; self.pay_gas_for_new_receipt(false, &[])?; self.gas_counter.pay_action_base( &self.fees_config.action_creation_config.create_account_cost, @@ -359,11 +372,7 @@ impl<'a> EvmContext<'a> { ActionCosts::create_account, )?; self.ext.append_action_create_account(receipt_index)?; - self.gas_counter.pay_action_base( - &self.fees_config.action_creation_config.transfer_cost, - false, - ActionCosts::transfer, - )?; + self.pay_gas_for_transfer(&new_account_id)?; self.ext.append_action_transfer(receipt_index, self.attached_deposit) } @@ -398,6 +407,26 @@ impl<'a> EvmContext<'a> { .ok_or(VMLogicError::EvmError(EvmError::IntegerOverflow))?; self.gas_counter.pay_action_accumulated(burn_gas, use_gas, ActionCosts::new_receipt) } + + fn pay_gas_for_transfer(&mut self, account_id: &AccountId) -> Result<()> { + if is_account_id_64_len_hex(&account_id) { + self.gas_counter.pay_action_base( + &self.fees_config.action_creation_config.create_account_cost, + false, + ActionCosts::transfer, + )?; + self.gas_counter.pay_action_base( + &self.fees_config.action_creation_config.add_key_cost.full_access_cost, + false, + ActionCosts::transfer, + )?; + } + self.gas_counter.pay_action_base( + &self.fees_config.action_creation_config.transfer_cost, + false, + ActionCosts::transfer, + ) + } } pub fn run_evm( diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 047ee079a18..b1b0cdf33c1 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -95,12 +95,12 @@ impl<'a> vm::Ext for NearExt<'a> { // TODO: research why these are different fn exists(&self, address: &Address) -> EvmResult { - Ok(self.sub_state.balance_of(address).unwrap_or_else(|_| U256::from(0)) > U256::from(0) + Ok(self.sub_state.balance_of(address).unwrap_or_else(|_| U256::zero()) > U256::zero() || self.sub_state.code_at(address).unwrap_or(None).is_some()) } fn exists_and_not_null(&self, address: &Address) -> EvmResult { - Ok(self.sub_state.balance_of(address).unwrap_or_else(|_| U256::from(0)) > 0.into() + Ok(self.sub_state.balance_of(address).unwrap_or_else(|_| U256::zero()) > 0.into() || self.sub_state.code_at(address).unwrap_or(None).is_some()) } @@ -109,11 +109,16 @@ impl<'a> vm::Ext for NearExt<'a> { } fn balance(&self, address: &Address) -> EvmResult { - let account = self.sub_state.get_account(address).unwrap_or(None).unwrap_or_default(); - Ok(account.balance.into()) + Ok(self + .sub_state + .get_account(address) + .unwrap_or(None) + .map(|account| account.balance.into()) + .unwrap_or(U256::zero())) } fn blockhash(&mut self, number: &U256) -> H256 { + // TODO(3456): Return actual block hashes. let mut buf = [0u8; 32]; number.to_big_endian(&mut buf); keccak(&buf[..]) @@ -219,8 +224,8 @@ impl<'a> vm::Ext for NearExt<'a> { VMLogicError::EvmError(EvmError::Revert(encoded_message)) => { hex::decode(encoded_message).unwrap_or(vec![]) } - // TODO: this is potentially error prone if there are non runtime errors here, but we can only return vector here. - _ => format!("{:?}", err).as_bytes().to_vec(), + // TODO(3455): Pass errors indirectly via state of the object. + _ => vec![], }; let message_len = message.len(); // TODO: gas usage. diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index be2e5c8e0b3..3d0d95e4b3e 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -1,15 +1,16 @@ use std::io::Write; use byteorder::WriteBytesExt; -use ethereum_types::{Address, H256, U256}; +use ethereum_types::{Address, H160, H256, U256}; use keccak_hash::keccak; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use vm::CreateContractAddress; +use crate::types::{DataKey, RawAddress, RawHash, RawU256}; use near_vm_logic::types::AccountId; -pub fn safe_next_address(addr: &[u8; 20]) -> [u8; 20] { - let mut expanded_addr = [0u8; 32]; +pub fn saturating_next_address(addr: &RawAddress) -> RawAddress { + let mut expanded_addr = [255u8; 32]; expanded_addr[12..].copy_from_slice(addr); let mut result = [0u8; 32]; U256::from_big_endian(&expanded_addr) @@ -20,7 +21,7 @@ pub fn safe_next_address(addr: &[u8; 20]) -> [u8; 20] { address } -pub fn internal_storage_key(address: &Address, key: [u8; 32]) -> [u8; 52] { +pub fn internal_storage_key(address: &Address, key: RawU256) -> DataKey { let mut k = [0u8; 52]; k[..20].copy_from_slice(address.as_ref()); k[20..].copy_from_slice(&key); @@ -32,12 +33,7 @@ pub fn near_account_bytes_to_evm_address(addr: &[u8]) -> Address { } pub fn near_account_id_to_evm_address(account_id: &str) -> Address { - near_account_bytes_to_evm_address(&account_id.to_string().into_bytes()) -} - -pub fn hex_to_evm_address(address: &str) -> Address { - let addr = hex::decode(&address).expect("Hex string not valid hex"); - Address::from_slice(&addr) + near_account_bytes_to_evm_address(&account_id.as_bytes().to_vec()) } pub fn encode_call_function_args(address: Address, input: Vec) -> Vec { @@ -47,6 +43,21 @@ pub fn encode_call_function_args(address: Address, input: Vec) -> Vec { result } +pub fn split_data_key(key: &DataKey) -> (Address, RawU256) { + let mut addr = [0u8; 20]; + addr.copy_from_slice(&key[..20]); + let mut subkey = [0u8; 32]; + subkey.copy_from_slice(&key[20..]); + (H160(addr), subkey) +} + +pub fn combine_data_key(addr: &Address, subkey: &RawU256) -> DataKey { + let mut key = [0u8; 52]; + key[..20].copy_from_slice(&addr.0); + key[20..52].copy_from_slice(subkey); + key +} + pub fn encode_view_call_function_args( sender: Address, address: Address, @@ -68,7 +79,7 @@ pub fn address_from_arr(arr: &[u8]) -> Address { Address::from(address) } -pub fn u256_to_arr(val: &U256) -> [u8; 32] { +pub fn u256_to_arr(val: &U256) -> RawU256 { let mut result = [0u8; 32]; val.to_big_endian(&mut result); result @@ -78,7 +89,7 @@ pub fn address_to_vec(val: &Address) -> Vec { val.to_fixed_bytes().to_vec() } -pub fn vec_to_arr_32(v: Vec) -> Option<[u8; 32]> { +pub fn vec_to_arr_32(v: Vec) -> Option { if v.len() != 32 { return None; } @@ -174,7 +185,7 @@ pub fn format_log(topics: Vec, data: &[u8]) -> std::result::Result Ok(result) } -pub fn near_erc721_domain(chain_id: U256) -> [u8; 32] { +pub fn near_erc721_domain(chain_id: U256) -> RawU256 { let mut bytes = Vec::with_capacity(70); bytes.extend_from_slice( &keccak("EIP712Domain(string name,string version,uint256 chainId)".as_bytes()).as_bytes(), @@ -186,11 +197,11 @@ pub fn near_erc721_domain(chain_id: U256) -> [u8; 32] { } pub fn prepare_meta_call_args( - domain_separator: &[u8; 32], + domain_separator: &RawU256, account_id: &AccountId, nonce: U256, args: &[u8], -) -> [u8; 32] { +) -> RawU256 { let mut bytes = Vec::with_capacity(32 + account_id.len() + args.len()); bytes.extend_from_slice( &keccak( @@ -202,7 +213,7 @@ pub fn prepare_meta_call_args( bytes.extend_from_slice(account_id.as_bytes()); bytes.extend_from_slice(&u256_to_arr(&nonce)); bytes.extend_from_slice(args); - let message: [u8; 32] = keccak(&bytes).into(); + let message: RawU256 = keccak(&bytes).into(); let mut bytes = Vec::with_capacity(2 + 32 + 32); bytes.extend_from_slice(&[0x19, 0x01]); bytes.extend_from_slice(domain_separator); @@ -212,7 +223,7 @@ pub fn prepare_meta_call_args( /// Given signature and data, validates that signature is valid for given data and returns ecrecover address. /// If signature is invalid or doesn't match, returns 0x0 address. -pub fn ecrecover_address(hash: &[u8; 32], signature: &[u8; 96]) -> Address { +pub fn ecrecover_address(hash: &RawHash, signature: &[u8; 96]) -> Address { use sha3::Digest; let hash = secp256k1::Message::parse(&H256::from_slice(hash).0); diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index 1d06d5b1e7b..4b291ab568a 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -46,6 +46,8 @@ pub fn create_context<'a>( ) } +/// Linter is suboptimal, because doesn't see that this is used in standard_ops.rs. +#[allow(dead_code)] pub fn public_key_to_address(public_key: PublicKey) -> Address { match public_key { PublicKey::ED25519(_) => panic!("Wrong PublicKey"), @@ -59,6 +61,8 @@ pub fn public_key_to_address(public_key: PublicKey) -> Address { } } +/// Linter is suboptimal, because doesn't see that this is used in standard_ops.rs. +#[allow(dead_code)] pub fn encode_meta_call_function_args( signer: &dyn Signer, chain_id: u128, diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index 60d036dfc26..4bef40f6462 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -200,6 +200,8 @@ pub enum EvmError { InvalidNonce, /// Invalid sub EVM account. InvalidSubAccount, + /// Won't withdraw to itself. + FailSelfWithdraw, /// Too small NEAR deposit. InsufficientDeposit, /// `OutOfGas` is returned when transaction execution runs out of gas. From 4a4ad9ee1b7fae0f5d6f7ed19519c4fdef4ae43c Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Mon, 5 Oct 2020 15:05:54 -0700 Subject: [PATCH 41/82] Update genesis config --- neard/res/genesis_config.json | 328 +++++++++++++++++----------------- 1 file changed, 165 insertions(+), 163 deletions(-) diff --git a/neard/res/genesis_config.json b/neard/res/genesis_config.json index fe475ef5378..236e66b1e7a 100644 --- a/neard/res/genesis_config.json +++ b/neard/res/genesis_config.json @@ -1,239 +1,241 @@ { - "protocol_version": 40, - "genesis_time": "1970-01-01T00:00:00.000000000Z", - "chain_id": "sample", - "genesis_height": 0, - "num_block_producer_seats": 50, + "protocol_version": 40, + "genesis_time": "1970-01-01T00:00:00.000000000Z", + "chain_id": "sample", + "evm_chain_id": "153", + "genesis_height": 0, + "num_block_producer_seats": 50, "num_block_producer_seats_per_shard": [ 50 - ], + ], "avg_hidden_validator_seats_per_shard": [ 0 - ], - "dynamic_resharding": false, + ], + "dynamic_resharding": false, "protocol_upgrade_stake_threshold": [ - 4, + 4, 5 - ], - "protocol_upgrade_num_epochs": 2, - "epoch_length": 500, - "gas_limit": 1000000000000000, - "min_gas_price": "1000000000", - "max_gas_price": "10000000000000000000000", - "block_producer_kickout_threshold": 90, - "chunk_producer_kickout_threshold": 90, + ], + "protocol_upgrade_num_epochs": 2, + "epoch_length": 500, + "gas_limit": 1000000000000000, + "min_gas_price": "1000000000", + "max_gas_price": "10000000000000000000000", + "block_producer_kickout_threshold": 90, + "chunk_producer_kickout_threshold": 90, "online_min_threshold": [ - 9, + 9, 10 - ], + ], "online_max_threshold": [ - 99, + 99, 100 - ], + ], "gas_price_adjustment_rate": [ - 1, + 1, 100 - ], + ], "runtime_config": { - "storage_amount_per_byte": "90900000000000000000", + "storage_amount_per_byte": "90900000000000000000", "transaction_costs": { "action_receipt_creation_config": { - "send_sir": 108059500000, - "send_not_sir": 108059500000, + "send_sir": 108059500000, + "send_not_sir": 108059500000, "execution": 108059500000 - }, + }, "data_receipt_creation_config": { "base_cost": { - "send_sir": 4697339419375, - "send_not_sir": 4697339419375, + "send_sir": 4697339419375, + "send_not_sir": 4697339419375, "execution": 4697339419375 - }, + }, "cost_per_byte": { - "send_sir": 59357464, - "send_not_sir": 59357464, + "send_sir": 59357464, + "send_not_sir": 59357464, "execution": 59357464 } - }, + }, "action_creation_config": { "create_account_cost": { - "send_sir": 99607375000, - "send_not_sir": 99607375000, + "send_sir": 99607375000, + "send_not_sir": 99607375000, "execution": 99607375000 - }, + }, "deploy_contract_cost": { - "send_sir": 184765750000, - "send_not_sir": 184765750000, + "send_sir": 184765750000, + "send_not_sir": 184765750000, "execution": 184765750000 - }, + }, "deploy_contract_cost_per_byte": { - "send_sir": 6812999, - "send_not_sir": 6812999, + "send_sir": 6812999, + "send_not_sir": 6812999, "execution": 6812999 - }, + }, "function_call_cost": { - "send_sir": 2319861500000, - "send_not_sir": 2319861500000, + "send_sir": 2319861500000, + "send_not_sir": 2319861500000, "execution": 2319861500000 - }, + }, "function_call_cost_per_byte": { - "send_sir": 2235934, - "send_not_sir": 2235934, + "send_sir": 2235934, + "send_not_sir": 2235934, "execution": 2235934 - }, + }, "transfer_cost": { - "send_sir": 115123062500, - "send_not_sir": 115123062500, + "send_sir": 115123062500, + "send_not_sir": 115123062500, "execution": 115123062500 - }, + }, "stake_cost": { - "send_sir": 141715687500, - "send_not_sir": 141715687500, + "send_sir": 141715687500, + "send_not_sir": 141715687500, "execution": 102217625000 - }, + }, "add_key_cost": { "full_access_cost": { - "send_sir": 101765125000, - "send_not_sir": 101765125000, + "send_sir": 101765125000, + "send_not_sir": 101765125000, "execution": 101765125000 - }, + }, "function_call_cost": { - "send_sir": 102217625000, - "send_not_sir": 102217625000, + "send_sir": 102217625000, + "send_not_sir": 102217625000, "execution": 102217625000 - }, + }, "function_call_cost_per_byte": { - "send_sir": 1925331, - "send_not_sir": 1925331, + "send_sir": 1925331, + "send_not_sir": 1925331, "execution": 1925331 } - }, + }, "delete_key_cost": { - "send_sir": 94946625000, - "send_not_sir": 94946625000, + "send_sir": 94946625000, + "send_not_sir": 94946625000, "execution": 94946625000 - }, + }, "delete_account_cost": { - "send_sir": 147489000000, - "send_not_sir": 147489000000, + "send_sir": 147489000000, + "send_not_sir": 147489000000, "execution": 147489000000 } - }, + }, "storage_usage_config": { - "num_bytes_account": 100, + "num_bytes_account": 100, "num_extra_bytes_record": 40 - }, + }, "burnt_gas_reward": [ - 3, + 3, 10 - ], + ], "pessimistic_gas_price_inflation_ratio": [ - 103, + 103, 100 - ] - }, + ], + "evm_deposit": "1000000000000000000000000000" + }, "wasm_config": { "ext_costs": { - "base": 264768111, - "contract_compile_base": 35445963, - "contract_compile_bytes": 216750, - "read_memory_base": 2609863200, - "read_memory_byte": 3801333, - "write_memory_base": 2803794861, - "write_memory_byte": 2723772, - "read_register_base": 2517165186, - "read_register_byte": 98562, - "write_register_base": 2865522486, - "write_register_byte": 3801564, - "utf8_decoding_base": 3111779061, - "utf8_decoding_byte": 291580479, - "utf16_decoding_base": 3543313050, - "utf16_decoding_byte": 163577493, - "sha256_base": 4540970250, - "sha256_byte": 24117351, - "keccak256_base": 5879491275, - "keccak256_byte": 21471105, - "keccak512_base": 5811388236, - "keccak512_byte": 36649701, - "log_base": 3543313050, - "log_byte": 13198791, - "storage_write_base": 64196736000, - "storage_write_key_byte": 70482867, - "storage_write_value_byte": 31018539, - "storage_write_evicted_byte": 32117307, - "storage_read_base": 56356845750, - "storage_read_key_byte": 30952533, - "storage_read_value_byte": 5611005, - "storage_remove_base": 53473030500, - "storage_remove_key_byte": 38220384, - "storage_remove_ret_value_byte": 11531556, - "storage_has_key_base": 54039896625, - "storage_has_key_byte": 30790845, - "storage_iter_create_prefix_base": 0, - "storage_iter_create_prefix_byte": 0, - "storage_iter_create_range_base": 0, - "storage_iter_create_from_byte": 0, - "storage_iter_create_to_byte": 0, - "storage_iter_next_base": 0, - "storage_iter_next_key_byte": 0, - "storage_iter_next_value_byte": 0, - "touching_trie_node": 16101955926, - "promise_and_base": 1465013400, - "promise_and_per_promise": 5452176, - "promise_return": 560152386, - "validator_stake_base": 911834726400, + "base": 264768111, + "contract_compile_base": 35445963, + "contract_compile_bytes": 216750, + "read_memory_base": 2609863200, + "read_memory_byte": 3801333, + "write_memory_base": 2803794861, + "write_memory_byte": 2723772, + "read_register_base": 2517165186, + "read_register_byte": 98562, + "write_register_base": 2865522486, + "write_register_byte": 3801564, + "utf8_decoding_base": 3111779061, + "utf8_decoding_byte": 291580479, + "utf16_decoding_base": 3543313050, + "utf16_decoding_byte": 163577493, + "sha256_base": 4540970250, + "sha256_byte": 24117351, + "keccak256_base": 5879491275, + "keccak256_byte": 21471105, + "keccak512_base": 5811388236, + "keccak512_byte": 36649701, + "log_base": 3543313050, + "log_byte": 13198791, + "storage_write_base": 64196736000, + "storage_write_key_byte": 70482867, + "storage_write_value_byte": 31018539, + "storage_write_evicted_byte": 32117307, + "storage_read_base": 56356845750, + "storage_read_key_byte": 30952533, + "storage_read_value_byte": 5611005, + "storage_remove_base": 53473030500, + "storage_remove_key_byte": 38220384, + "storage_remove_ret_value_byte": 11531556, + "storage_has_key_base": 54039896625, + "storage_has_key_byte": 30790845, + "storage_iter_create_prefix_base": 0, + "storage_iter_create_prefix_byte": 0, + "storage_iter_create_range_base": 0, + "storage_iter_create_from_byte": 0, + "storage_iter_create_to_byte": 0, + "storage_iter_next_base": 0, + "storage_iter_next_key_byte": 0, + "storage_iter_next_value_byte": 0, + "touching_trie_node": 16101955926, + "promise_and_base": 1465013400, + "promise_and_per_promise": 5452176, + "promise_return": 560152386, + "validator_stake_base": 911834726400, "validator_total_stake_base": 911834726400 - }, - "grow_mem_cost": 1, - "regular_op_cost": 3856371, + }, + "grow_mem_cost": 1, + "regular_op_cost": 3856371, "limit_config": { - "max_gas_burnt": 200000000000000, - "max_gas_burnt_view": 200000000000000, - "max_stack_height": 16384, - "initial_memory_pages": 1024, - "max_memory_pages": 2048, - "registers_memory_limit": 1073741824, - "max_register_size": 104857600, - "max_number_registers": 100, - "max_number_logs": 100, - "max_total_log_length": 16384, - "max_total_prepaid_gas": 300000000000000, - "max_actions_per_receipt": 100, - "max_number_bytes_method_names": 2000, - "max_length_method_name": 256, - "max_arguments_length": 4194304, - "max_length_returned_data": 4194304, - "max_contract_size": 4194304, - "max_length_storage_key": 4194304, - "max_length_storage_value": 4194304, - "max_promises_per_function_call_action": 1024, + "max_gas_burnt": 200000000000000, + "max_gas_burnt_view": 200000000000000, + "max_stack_height": 16384, + "initial_memory_pages": 1024, + "max_memory_pages": 2048, + "registers_memory_limit": 1073741824, + "max_register_size": 104857600, + "max_number_registers": 100, + "max_number_logs": 100, + "max_total_log_length": 16384, + "max_total_prepaid_gas": 300000000000000, + "max_actions_per_receipt": 100, + "max_number_bytes_method_names": 2000, + "max_length_method_name": 256, + "max_arguments_length": 4194304, + "max_length_returned_data": 4194304, + "max_contract_size": 4194304, + "max_length_storage_key": 4194304, + "max_length_storage_value": 4194304, + "max_promises_per_function_call_action": 1024, "max_number_input_data_dependencies": 128 } - }, + }, "account_creation_config": { - "min_allowed_top_level_account_length": 0, + "min_allowed_top_level_account_length": 0, "registrar_account_id": "registrar" } - }, + }, "validators": [ { - "account_id": "test.near", - "public_key": "ed25519:9BmAFNRTa5mRRXpSAm6MxSEeqRASDGNh2FuuwZ4gyxTw", + "account_id": "test.near", + "public_key": "ed25519:9BmAFNRTa5mRRXpSAm6MxSEeqRASDGNh2FuuwZ4gyxTw", "amount": "50000000000000000000000000000000" } - ], - "transaction_validity_period": 100, + ], + "transaction_validity_period": 100, "protocol_reward_rate": [ - 1, + 1, 10 - ], + ], "max_inflation_rate": [ - 1, + 1, 20 - ], - "total_supply": "3050000000000000000000000000000000", - "num_blocks_per_year": 31536000, - "protocol_treasury_account": "test.near", - "fishermen_threshold": "10000000000000000000000000", - "minimum_stake_divisor": 10, + ], + "total_supply": "3050000000000000000000000000000000", + "num_blocks_per_year": 31536000, + "protocol_treasury_account": "test.near", + "fishermen_threshold": "10000000000000000000000000", + "minimum_stake_divisor": 10, "records": [] } \ No newline at end of file From fccae1bf033f7545331e2d38ac074574263acf9d Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Tue, 6 Oct 2020 02:05:11 -0700 Subject: [PATCH 42/82] Address the comments --- runtime/near-evm-runner/src/lib.rs | 5 +++-- runtime/near-evm-runner/src/near_ext.rs | 1 - runtime/near-runtime-fees/src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 66d9a88e5a2..dc248605f04 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -91,10 +91,11 @@ impl<'a> EvmState for EvmContext<'a> { .storage_get(&key) .map(|value| value.map(|x| utils::vec_to_arr_32(x.deref().expect("Failed to deref")))) { - Ok(Some(value)) => Ok(value), - Ok(None) => Err(VMLogicError::InconsistentStateError(StorageError( + Ok(Some(Some(value))) => Ok(Some(value)), + Ok(Some(None)) => Err(VMLogicError::InconsistentStateError(StorageError( "Must be 32 bytes".to_string(), ))), + Ok(None) => Ok(None), Err(err) => Err(err), } } diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index b1b0cdf33c1..bdcafb8db3d 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -16,7 +16,6 @@ use crate::interpreter; use crate::utils::format_log; // https://github.com/paritytech/parity-ethereum/blob/77643c13e80ca09d9a6b10631034f5a1568ba6d3/ethcore/machine/src/externalities.rs -// #[derive(Debug)] pub struct NearExt<'a> { pub info: EnvInfo, pub origin: Address, diff --git a/runtime/near-runtime-fees/src/lib.rs b/runtime/near-runtime-fees/src/lib.rs index 33f82a1fcfb..f357c2d3456 100644 --- a/runtime/near-runtime-fees/src/lib.rs +++ b/runtime/near-runtime-fees/src/lib.rs @@ -72,7 +72,7 @@ pub struct RuntimeFeesConfig { /// Pessimistic gas price inflation ratio. pub pessimistic_gas_price_inflation_ratio: Rational, - /// New EVM deposit. + /// Fee to create new EVM account. #[serde(with = "u128_dec_format", default = "default_evm_deposit")] pub evm_deposit: Balance, } From d530fe730964fe541c998d9533683b1a09bcf29f Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Wed, 7 Oct 2020 09:29:29 -0700 Subject: [PATCH 43/82] Compress v in signature recovery to 1 byte --- runtime/near-evm-runner/src/builtins.rs | 4 ++-- runtime/near-evm-runner/src/lib.rs | 17 ++++++++++------- runtime/near-evm-runner/src/utils.rs | 12 ++++++------ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/runtime/near-evm-runner/src/builtins.rs b/runtime/near-evm-runner/src/builtins.rs index 35fac3ac54c..fe6f039b973 100644 --- a/runtime/near-evm-runner/src/builtins.rs +++ b/runtime/near-evm-runner/src/builtins.rs @@ -148,8 +148,8 @@ impl Impl for EcRecover { input[..len].copy_from_slice(&i[..len]); let mut hash = [0; 32]; hash.copy_from_slice(&input[..32]); - let mut signature = [0; 96]; - signature.copy_from_slice(&input[32..]); + let mut signature = [0; 65]; + signature.copy_from_slice(&input[63..]); let result = ecrecover_address(&hash, &signature); output.write(0, &[0, 12]); diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index dc248605f04..a719d562f80 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -215,17 +215,18 @@ impl<'a> EvmContext<'a> { /// Make an EVM call via a meta transaction pattern. /// Specifically, providing signature and NEAREvm message that determines which contract and arguments to be called. /// Format - /// 0..95: signature: v - 32 bytes, s - 32 bytes, r - 32 bytes - /// 96..115: contract_id: address for contract to call - /// 116..: RLP encoded arguments. + /// [0..65): signature: v - 1 byte, s - 32 bytes, r - 32 bytes + /// [65..97): nonce: nonce of the `signer` account of the `signature`. + /// [97..117): contract_id: address for contract to call + /// 117..: RLP encoded arguments. pub fn meta_call_function(&mut self, args: Vec) -> Result> { if args.len() <= 148 { return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); } - let mut signature: [u8; 96] = [0; 96]; - signature.copy_from_slice(&args[..96]); - let nonce = U256::from_big_endian(&args[96..128]); - let args = &args[128..]; + let mut signature: [u8; 65] = [0; 65]; + signature.copy_from_slice(&args[..65]); + let nonce = U256::from_big_endian(&args[65..97]); + let args = &args[97..]; let sender = ecrecover_address( &prepare_meta_call_args(&self.domain_separator, &self.account_id, nonce, args), &signature, @@ -267,6 +268,8 @@ impl<'a> EvmContext<'a> { false, ) .map(|rd| rd.to_vec()); + // Need to subtract amount back, because if view call is called inside the transaction state will be applied. + // The interpreter call is not committing changes, but `add_balance` did, so need to revert that. self.sub_balance(&sender, attached_amount)?; result } diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index 3d0d95e4b3e..fb364e1723f 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -223,16 +223,16 @@ pub fn prepare_meta_call_args( /// Given signature and data, validates that signature is valid for given data and returns ecrecover address. /// If signature is invalid or doesn't match, returns 0x0 address. -pub fn ecrecover_address(hash: &RawHash, signature: &[u8; 96]) -> Address { +pub fn ecrecover_address(hash: &RawHash, signature: &[u8; 65]) -> Address { use sha3::Digest; let hash = secp256k1::Message::parse(&H256::from_slice(hash).0); - let v = &signature[..32]; - let r = &signature[32..64]; - let s = &signature[64..96]; + let v = &signature[0]; + let r = &signature[1..33]; + let s = &signature[33..]; - let bit = match v[31] { - 27..=30 => v[31] - 27, + let bit = match v { + 27..=30 => v - 27, _ => { // ?? return Address::zero(); From 60de7fbf21f4a96431322597410ef97cb97317ff Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Thu, 22 Oct 2020 15:55:54 -0700 Subject: [PATCH 44/82] Update meta call parsing to new format --- runtime/near-evm-runner/src/lib.rs | 48 +++++------- runtime/near-evm-runner/src/types.rs | 10 +++ runtime/near-evm-runner/src/utils.rs | 78 +++++++++++++++++-- runtime/near-evm-runner/tests/standard_ops.rs | 42 +++++++++- runtime/near-evm-runner/tests/utils.rs | 43 +++++++--- 5 files changed, 167 insertions(+), 54 deletions(-) diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index a719d562f80..96bd3ed325c 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -14,11 +14,9 @@ use near_vm_logic::{ActionCosts, External, VMConfig, VMLogicError, VMOutcome}; use crate::evm_state::{EvmAccount, EvmState, StateStore}; use crate::types::{ - AddressArg, GetStorageAtArgs, Result, TransferArgs, ViewCallArgs, WithdrawArgs, -}; -use crate::utils::{ - combine_data_key, ecrecover_address, near_erc721_domain, prepare_meta_call_args, + AddressArg, GetStorageAtArgs, RawU256, Result, TransferArgs, ViewCallArgs, WithdrawArgs, }; +use crate::utils::{combine_data_key, near_erc721_domain, parse_meta_call}; use near_vm_errors::InconsistentStateError::StorageError; mod builtins; @@ -39,7 +37,7 @@ pub struct EvmContext<'a> { pub logs: Vec, gas_counter: GasCounter, fees_config: &'a RuntimeFeesConfig, - domain_separator: [u8; 32], + domain_separator: RawU256, } enum KeyPrefix { @@ -214,36 +212,26 @@ impl<'a> EvmContext<'a> { /// Make an EVM call via a meta transaction pattern. /// Specifically, providing signature and NEAREvm message that determines which contract and arguments to be called. - /// Format - /// [0..65): signature: v - 1 byte, s - 32 bytes, r - 32 bytes - /// [65..97): nonce: nonce of the `signer` account of the `signature`. - /// [97..117): contract_id: address for contract to call - /// 117..: RLP encoded arguments. + /// See `parse_meta_call` for arguments format. pub fn meta_call_function(&mut self, args: Vec) -> Result> { - if args.len() <= 148 { - return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); - } - let mut signature: [u8; 65] = [0; 65]; - signature.copy_from_slice(&args[..65]); - let nonce = U256::from_big_endian(&args[65..97]); - let args = &args[97..]; - let sender = ecrecover_address( - &prepare_meta_call_args(&self.domain_separator, &self.account_id, nonce, args), - &signature, - ); - if sender == Address::zero() { - return Err(VMLogicError::EvmError(EvmError::InvalidEcRecoverSignature)); - } - if self.next_nonce(&sender)? != nonce { + let meta_call_args = parse_meta_call(&self.domain_separator, &self.account_id, args)?; + if self.next_nonce(&meta_call_args.sender)? != meta_call_args.nonce { return Err(VMLogicError::EvmError(EvmError::InvalidNonce)); } - let contract_address = Address::from_slice(&args[..20]); - let input = &args[20..]; - self.add_balance(&sender, U256::from(self.attached_deposit))?; + self.add_balance(&meta_call_args.sender, U256::from(self.attached_deposit))?; let value = if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; - interpreter::call(self, &sender, &sender, value, 0, &contract_address, &input, true) - .map(|rd| rd.to_vec()) + interpreter::call( + self, + &meta_call_args.sender, + &meta_call_args.sender, + value, + 0, + &meta_call_args.contract_address, + &meta_call_args.input, + true, + ) + .map(|rd| rd.to_vec()) } /// Make an EVM transaction. Calls `contract_address` with `encoded_input`. Execution diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index 2c0fbd07dd5..53df6fa5cb9 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -2,6 +2,7 @@ use std::convert::TryInto; use std::io::{Read, Write}; use borsh::{BorshDeserialize, BorshSerialize}; +use ethereum_types::{Address, U256}; use near_vm_errors::{EvmError, InconsistentStateError, VMLogicError}; use near_vm_logic::types::AccountId; @@ -44,6 +45,15 @@ pub struct ViewCallArgs { pub args: Vec, } +pub struct MetaCallArgs { + pub sender: Address, + pub nonce: U256, + pub fee_amount: U256, + pub fee_address: Address, + pub contract_address: Address, + pub input: Vec, +} + impl BorshSerialize for ViewCallArgs { fn serialize(&self, writer: &mut W) -> std::io::Result<()> { writer.write(&self.sender)?; diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index fb364e1723f..4180c7b135e 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -6,7 +6,8 @@ use keccak_hash::keccak; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use vm::CreateContractAddress; -use crate::types::{DataKey, RawAddress, RawHash, RawU256}; +use crate::types::{DataKey, MetaCallArgs, RawAddress, RawHash, RawU256, Result}; +use near_vm_errors::{EvmError, VMLogicError}; use near_vm_logic::types::AccountId; pub fn saturating_next_address(addr: &RawAddress) -> RawAddress { @@ -196,22 +197,37 @@ pub fn near_erc721_domain(chain_id: U256) -> RawU256 { keccak(&bytes).into() } +pub fn method_name_to_rlp(method_name: String) -> [u8; 4] { + let mut result = [0u8; 4]; + result.copy_from_slice(&keccak(method_name)[..4]); + result +} + pub fn prepare_meta_call_args( domain_separator: &RawU256, account_id: &AccountId, nonce: U256, + fee_amount: U256, + fee_address: Address, + contract_address: Address, + method_name: &str, args: &[u8], ) -> RawU256 { - let mut bytes = Vec::with_capacity(32 + account_id.len() + args.len()); + let mut bytes = Vec::with_capacity(32 + 32 + 20 + account_id.len() + 4 + args.len()); bytes.extend_from_slice( &keccak( - "NearTx(string evmId, uint256 nonce, address contractAddress, bytes arguments)" + "NearTx(string evmId, uint256 nonce, uint256 feeAmount, uint256 feeAddress, address contractAddress, string contractMethod, Arguments arguments)" .as_bytes(), ) .as_bytes(), ); bytes.extend_from_slice(account_id.as_bytes()); bytes.extend_from_slice(&u256_to_arr(&nonce)); + bytes.extend_from_slice(&u256_to_arr(&fee_amount)); + bytes.extend_from_slice(&fee_address.0); + bytes.extend_from_slice(&contract_address.0); + bytes.extend_from_slice(&method_name.as_bytes()); + // TODO: hash? bytes.extend_from_slice(args); let message: RawU256 = keccak(&bytes).into(); let mut bytes = Vec::with_capacity(2 + 32 + 32); @@ -221,6 +237,56 @@ pub fn prepare_meta_call_args( keccak(&bytes).into() } +/// Format +/// [0..65): signature: v - 1 byte, s - 32 bytes, r - 32 bytes +/// [65..97): nonce: nonce of the `signer` account of the `signature`. +/// : fee_amount +/// : fee_address +/// [97..117): contract_id: address for contract to call +/// : method_name_length +/// : method_name +/// 117..: RLP encoded rest of arguments. +pub fn parse_meta_call( + domain_separator: &RawU256, + account_id: &AccountId, + args: Vec, +) -> Result { + if args.len() <= 169 { + return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); + } + let mut signature: [u8; 65] = [0; 65]; + signature.copy_from_slice(&args[..65]); + let nonce = U256::from_big_endian(&args[65..97]); + let fee_amount = U256::from_big_endian(&args[97..129]); + let fee_address = Address::from_slice(&args[129..149]); + let contract_address = Address::from_slice(&args[149..169]); + let method_name_len = args[169] as usize; + if args.len() < method_name_len + 170 { + return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); + } + let method_name = String::from_utf8(args[170..170 + method_name_len].to_vec()) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + let args = &args[170 + method_name_len..]; + + let msg = prepare_meta_call_args( + domain_separator, + account_id, + nonce, + fee_amount, + fee_address, + contract_address, + &method_name, + args, + ); + let sender = ecrecover_address(&msg, &signature); + if sender == Address::zero() { + return Err(VMLogicError::EvmError(EvmError::InvalidEcRecoverSignature)); + } + let method_name_rlp = method_name_to_rlp(method_name); + let input = [method_name_rlp.to_vec(), args.to_vec()].concat(); + Ok(MetaCallArgs { sender, nonce, fee_amount, fee_address, contract_address, input }) +} + /// Given signature and data, validates that signature is valid for given data and returns ecrecover address. /// If signature is invalid or doesn't match, returns 0x0 address. pub fn ecrecover_address(hash: &RawHash, signature: &[u8; 65]) -> Address { @@ -228,9 +294,6 @@ pub fn ecrecover_address(hash: &RawHash, signature: &[u8; 65]) -> Address { let hash = secp256k1::Message::parse(&H256::from_slice(hash).0); let v = &signature[0]; - let r = &signature[1..33]; - let s = &signature[33..]; - let bit = match v { 27..=30 => v - 27, _ => { @@ -240,8 +303,7 @@ pub fn ecrecover_address(hash: &RawHash, signature: &[u8; 65]) -> Address { }; let mut sig = [0u8; 64]; - sig[..32].copy_from_slice(&r); - sig[32..].copy_from_slice(&s); + sig.copy_from_slice(&signature[1..]); let s = secp256k1::Signature::parse(&sig); if let Ok(rec_id) = secp256k1::RecoveryId::parse(bit) { diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index b9d13575dea..be05e66e6ed 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -9,7 +9,7 @@ use near_crypto::{InMemorySigner, KeyType}; use near_evm_runner::types::{TransferArgs, WithdrawArgs}; use near_evm_runner::utils::{ address_from_arr, address_to_vec, encode_call_function_args, encode_view_call_function_args, - near_account_id_to_evm_address, u256_to_arr, + near_account_id_to_evm_address, near_erc721_domain, parse_meta_call, u256_to_arr, }; use near_runtime_fees::RuntimeFeesConfig; use near_vm_errors::{EvmError, VMLogicError}; @@ -261,9 +261,16 @@ fn test_meta_call() { let signer = InMemorySigner::from_random("doesnt".to_string(), KeyType::SECP256K1); let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let (input, _) = soltest::functions::return_some_funds::call(); - let meta_tx = - encode_meta_call_function_args(&signer, CHAIN_ID, test_addr, U256::from(0), input); + let meta_tx = encode_meta_call_function_args( + &signer, + CHAIN_ID, + U256::from(0), + U256::from(0), + Address::from_slice(&[0u8; 20]), + test_addr, + "returnSomeFunds()", + vec![], + ); let _ = context.meta_call_function(meta_tx.clone()).unwrap(); let signer_addr = public_key_to_address(signer.public_key); assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); @@ -273,3 +280,30 @@ fn test_meta_call() { "EvmError(InvalidNonce)" ); } + +#[test] +fn test_meta_call_sig_recover() { + let (mut fake_external, _, vm_config, fees_config) = setup_and_deploy_test(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let meta_tx = [ + // signature: 65 bytes + hex::decode("754d8919d909c6e2cfd81d824fc392658f7497b5c53bbb2f60af5aba40848fd2074463b0c75b94925780a074f5f44498d1031846b57817b30398e8e36ebc083f1b").unwrap(), + // nonce: 14 + u256_to_arr(&U256::from(14)).to_vec(), + // fee amount: 6 + u256_to_arr(&U256::from(6)).to_vec(), + // fee token: 0x0 + vec![0; 20], + // contract: address, + hex::decode("Ed2a1b3Fa739DAbBf8c07a059dE1333D20e8b482").unwrap(), + // contract method: length 1 byte + bytes for the name. + vec![14], + b"adopt(uint256)".to_vec(), + // arguments + u256_to_arr(&U256::from(9)).to_vec(), + ].concat(); + let domain_separator = near_erc721_domain(U256::from(chain_id)); + let result = parse_meta_call(&domain_separator, &"evm".to_string(), meta_tx).unwrap(); + assert_eq!(result.sender, hex::decode("Ed2a1b3Fa739DAbBf8c07a059dE1333D20e8b482").unwrap()); +} diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index 4b291ab568a..39f279e21d7 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -1,9 +1,7 @@ use ethereum_types::{Address, U256}; use keccak_hash::keccak; use near_crypto::{PublicKey, Signature, Signer}; -use near_evm_runner::utils::{ - encode_call_function_args, near_erc721_domain, prepare_meta_call_args, u256_to_arr, -}; +use near_evm_runner::utils::{near_erc721_domain, prepare_meta_call_args, u256_to_arr}; use near_evm_runner::EvmContext; use near_runtime_fees::RuntimeFeesConfig; use near_vm_logic::mocks::mock_external::MockedExternal; @@ -66,21 +64,42 @@ pub fn public_key_to_address(public_key: PublicKey) -> Address { pub fn encode_meta_call_function_args( signer: &dyn Signer, chain_id: u128, - address: Address, nonce: U256, - input: Vec, + fee_amount: U256, + fee_token: Address, + address: Address, + method_name: &str, + args: Vec, ) -> Vec { let domain_separator = near_erc721_domain(U256::from(chain_id)); - let call_args = encode_call_function_args(address, input); - let args = prepare_meta_call_args(&domain_separator, &"evm".to_string(), nonce, &call_args); - match signer.sign(&args) { + let msg = prepare_meta_call_args( + &domain_separator, + &"evm".to_string(), + nonce, + fee_amount, + fee_token, + address, + method_name, + &args, + ); + match signer.sign(&msg) { Signature::ED25519(_) => panic!("Wrong Signer"), Signature::SECP256K1(sig) => { let sig: [u8; 65] = sig.into(); - let mut vsr = vec![0u8; 96]; - vsr[31] = sig[64] + 27; - vsr[32..].copy_from_slice(&sig[..64]); - [vsr, u256_to_arr(&nonce).to_vec(), call_args].concat() + let mut vsr = [0u8; 65]; + vsr[0] = sig[64] + 27; + vsr[1..].copy_from_slice(&sig[..64]); + [ + vsr.to_vec(), + u256_to_arr(&nonce).to_vec(), + u256_to_arr(&fee_amount).to_vec(), + fee_token.0.to_vec(), + address.0.to_vec(), + vec![method_name.len() as u8], + method_name.as_bytes().to_vec(), + args, + ] + .concat() } } } From febbb41a6a8b5a4115e72afb4e4da52f802f083a Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Fri, 23 Oct 2020 15:41:23 -0700 Subject: [PATCH 45/82] Fix issues and disable for now full sig recovery test --- runtime/near-evm-runner/src/utils.rs | 4 ++- runtime/near-evm-runner/tests/standard_ops.rs | 11 ++++---- runtime/near-evm-runner/tests/utils.rs | 28 ++++++++----------- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index 4180c7b135e..98c4faede2b 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -255,7 +255,9 @@ pub fn parse_meta_call( return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); } let mut signature: [u8; 65] = [0; 65]; - signature.copy_from_slice(&args[..65]); + // Signatures coming from outside are srv but ecrecover takes vsr, so move last byte to first position. + signature[0] = args[64] + 27; + signature[1..].copy_from_slice(&args[..64]); let nonce = U256::from_big_endian(&args[65..97]); let fee_amount = U256::from_big_endian(&args[97..129]); let fee_address = Address::from_slice(&args[129..149]); diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index be05e66e6ed..08d9197e3b9 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -20,6 +20,7 @@ use crate::utils::{ accounts, create_context, encode_meta_call_function_args, public_key_to_address, setup, CHAIN_ID, }; +use parity_bytes::ToPretty; mod utils; @@ -282,13 +283,11 @@ fn test_meta_call() { } #[test] +#[ignore] fn test_meta_call_sig_recover() { - let (mut fake_external, _, vm_config, fees_config) = setup_and_deploy_test(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); let meta_tx = [ // signature: 65 bytes - hex::decode("754d8919d909c6e2cfd81d824fc392658f7497b5c53bbb2f60af5aba40848fd2074463b0c75b94925780a074f5f44498d1031846b57817b30398e8e36ebc083f1b").unwrap(), + hex::decode("1cb6f28f29524cf3ae5ce49f364b5ad798af5dd8ec3563744dc62792735ce5e222285df1e91c416e430d0a38ea3b51d6677e337e1b0684d7618f5a00a26a2ee21c").unwrap(), // nonce: 14 u256_to_arr(&U256::from(14)).to_vec(), // fee amount: 6 @@ -303,7 +302,7 @@ fn test_meta_call_sig_recover() { // arguments u256_to_arr(&U256::from(9)).to_vec(), ].concat(); - let domain_separator = near_erc721_domain(U256::from(chain_id)); + let domain_separator = near_erc721_domain(U256::from(CHAIN_ID)); let result = parse_meta_call(&domain_separator, &"evm".to_string(), meta_tx).unwrap(); - assert_eq!(result.sender, hex::decode("Ed2a1b3Fa739DAbBf8c07a059dE1333D20e8b482").unwrap()); + assert_eq!(result.sender.to_hex(), "2941022347348828A24a5ff33c775D67691681e9"); } diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index 39f279e21d7..1d574108cad 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -84,22 +84,16 @@ pub fn encode_meta_call_function_args( ); match signer.sign(&msg) { Signature::ED25519(_) => panic!("Wrong Signer"), - Signature::SECP256K1(sig) => { - let sig: [u8; 65] = sig.into(); - let mut vsr = [0u8; 65]; - vsr[0] = sig[64] + 27; - vsr[1..].copy_from_slice(&sig[..64]); - [ - vsr.to_vec(), - u256_to_arr(&nonce).to_vec(), - u256_to_arr(&fee_amount).to_vec(), - fee_token.0.to_vec(), - address.0.to_vec(), - vec![method_name.len() as u8], - method_name.as_bytes().to_vec(), - args, - ] - .concat() - } + Signature::SECP256K1(sig) => [ + Into::<[u8; 65]>::into(sig).to_vec(), + u256_to_arr(&nonce).to_vec(), + u256_to_arr(&fee_amount).to_vec(), + fee_token.0.to_vec(), + address.0.to_vec(), + vec![method_name.len() as u8], + method_name.as_bytes().to_vec(), + args, + ] + .concat(), } } From d66c9db89b698f7bfbb5c72e90c282b97b1c8d37 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Thu, 29 Oct 2020 11:30:15 -0700 Subject: [PATCH 46/82] Switching to use constant instead of hard coded --- Cargo.lock | 1 + core/chain-configs/src/genesis_config.rs | 3 +- core/chain-configs/src/lib.rs | 2 +- neard/res/genesis_config.json | 328 +++++++++++------------ runtime/near-evm-runner/tests/utils.rs | 3 +- runtime/runtime/Cargo.toml | 1 + runtime/runtime/src/state_viewer.rs | 5 +- 7 files changed, 174 insertions(+), 169 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f947744383b..33b7cda9ce4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3339,6 +3339,7 @@ dependencies = [ "indicatif 0.13.0", "lazy_static", "log", + "near-chain-configs", "near-crypto", "near-evm-runner", "near-metrics", diff --git a/core/chain-configs/src/genesis_config.rs b/core/chain-configs/src/genesis_config.rs index fc10d147769..70509ecb24d 100644 --- a/core/chain-configs/src/genesis_config.rs +++ b/core/chain-configs/src/genesis_config.rs @@ -22,7 +22,8 @@ use near_runtime_configs::RuntimeConfig; const MAX_GAS_PRICE: Balance = 10_000_000_000_000_000_000_000; -const TEST_EVM_CHAIN_ID: u128 = 0x99; +/// See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161555.json +pub const TEST_EVM_CHAIN_ID: u128 = 1313161555; fn default_online_min_threshold() -> Rational { Rational::new(90, 100) diff --git a/core/chain-configs/src/lib.rs b/core/chain-configs/src/lib.rs index b824e5f12b9..75e52a4977a 100644 --- a/core/chain-configs/src/lib.rs +++ b/core/chain-configs/src/lib.rs @@ -2,4 +2,4 @@ mod client_config; mod genesis_config; pub use client_config::ClientConfig; -pub use genesis_config::{Genesis, GenesisConfig, GenesisRecords}; +pub use genesis_config::{Genesis, GenesisConfig, GenesisRecords, TEST_EVM_CHAIN_ID}; diff --git a/neard/res/genesis_config.json b/neard/res/genesis_config.json index 236e66b1e7a..7fa800d9350 100644 --- a/neard/res/genesis_config.json +++ b/neard/res/genesis_config.json @@ -1,241 +1,241 @@ { - "protocol_version": 40, - "genesis_time": "1970-01-01T00:00:00.000000000Z", - "chain_id": "sample", - "evm_chain_id": "153", - "genesis_height": 0, - "num_block_producer_seats": 50, + "protocol_version": 40, + "genesis_time": "1970-01-01T00:00:00.000000000Z", + "chain_id": "sample", + "evm_chain_id": "153", + "genesis_height": 0, + "num_block_producer_seats": 50, "num_block_producer_seats_per_shard": [ 50 - ], + ], "avg_hidden_validator_seats_per_shard": [ 0 - ], - "dynamic_resharding": false, + ], + "dynamic_resharding": false, "protocol_upgrade_stake_threshold": [ - 4, + 4, 5 - ], - "protocol_upgrade_num_epochs": 2, - "epoch_length": 500, - "gas_limit": 1000000000000000, - "min_gas_price": "1000000000", - "max_gas_price": "10000000000000000000000", - "block_producer_kickout_threshold": 90, - "chunk_producer_kickout_threshold": 90, + ], + "protocol_upgrade_num_epochs": 2, + "epoch_length": 500, + "gas_limit": 1000000000000000, + "min_gas_price": "1000000000", + "max_gas_price": "10000000000000000000000", + "block_producer_kickout_threshold": 90, + "chunk_producer_kickout_threshold": 90, "online_min_threshold": [ - 9, + 9, 10 - ], + ], "online_max_threshold": [ - 99, + 99, 100 - ], + ], "gas_price_adjustment_rate": [ - 1, + 1, 100 - ], + ], "runtime_config": { - "storage_amount_per_byte": "90900000000000000000", + "storage_amount_per_byte": "90900000000000000000", "transaction_costs": { "action_receipt_creation_config": { - "send_sir": 108059500000, - "send_not_sir": 108059500000, + "send_sir": 108059500000, + "send_not_sir": 108059500000, "execution": 108059500000 - }, + }, "data_receipt_creation_config": { "base_cost": { - "send_sir": 4697339419375, - "send_not_sir": 4697339419375, + "send_sir": 4697339419375, + "send_not_sir": 4697339419375, "execution": 4697339419375 - }, + }, "cost_per_byte": { - "send_sir": 59357464, - "send_not_sir": 59357464, + "send_sir": 59357464, + "send_not_sir": 59357464, "execution": 59357464 } - }, + }, "action_creation_config": { "create_account_cost": { - "send_sir": 99607375000, - "send_not_sir": 99607375000, + "send_sir": 99607375000, + "send_not_sir": 99607375000, "execution": 99607375000 - }, + }, "deploy_contract_cost": { - "send_sir": 184765750000, - "send_not_sir": 184765750000, + "send_sir": 184765750000, + "send_not_sir": 184765750000, "execution": 184765750000 - }, + }, "deploy_contract_cost_per_byte": { - "send_sir": 6812999, - "send_not_sir": 6812999, + "send_sir": 6812999, + "send_not_sir": 6812999, "execution": 6812999 - }, + }, "function_call_cost": { - "send_sir": 2319861500000, - "send_not_sir": 2319861500000, + "send_sir": 2319861500000, + "send_not_sir": 2319861500000, "execution": 2319861500000 - }, + }, "function_call_cost_per_byte": { - "send_sir": 2235934, - "send_not_sir": 2235934, + "send_sir": 2235934, + "send_not_sir": 2235934, "execution": 2235934 - }, + }, "transfer_cost": { - "send_sir": 115123062500, - "send_not_sir": 115123062500, + "send_sir": 115123062500, + "send_not_sir": 115123062500, "execution": 115123062500 - }, + }, "stake_cost": { - "send_sir": 141715687500, - "send_not_sir": 141715687500, + "send_sir": 141715687500, + "send_not_sir": 141715687500, "execution": 102217625000 - }, + }, "add_key_cost": { "full_access_cost": { - "send_sir": 101765125000, - "send_not_sir": 101765125000, + "send_sir": 101765125000, + "send_not_sir": 101765125000, "execution": 101765125000 - }, + }, "function_call_cost": { - "send_sir": 102217625000, - "send_not_sir": 102217625000, + "send_sir": 102217625000, + "send_not_sir": 102217625000, "execution": 102217625000 - }, + }, "function_call_cost_per_byte": { - "send_sir": 1925331, - "send_not_sir": 1925331, + "send_sir": 1925331, + "send_not_sir": 1925331, "execution": 1925331 } - }, + }, "delete_key_cost": { - "send_sir": 94946625000, - "send_not_sir": 94946625000, + "send_sir": 94946625000, + "send_not_sir": 94946625000, "execution": 94946625000 - }, + }, "delete_account_cost": { - "send_sir": 147489000000, - "send_not_sir": 147489000000, + "send_sir": 147489000000, + "send_not_sir": 147489000000, "execution": 147489000000 } - }, + }, "storage_usage_config": { - "num_bytes_account": 100, + "num_bytes_account": 100, "num_extra_bytes_record": 40 - }, + }, "burnt_gas_reward": [ - 3, + 3, 10 - ], + ], "pessimistic_gas_price_inflation_ratio": [ - 103, + 103, 100 - ], + ], "evm_deposit": "1000000000000000000000000000" - }, + }, "wasm_config": { "ext_costs": { - "base": 264768111, - "contract_compile_base": 35445963, - "contract_compile_bytes": 216750, - "read_memory_base": 2609863200, - "read_memory_byte": 3801333, - "write_memory_base": 2803794861, - "write_memory_byte": 2723772, - "read_register_base": 2517165186, - "read_register_byte": 98562, - "write_register_base": 2865522486, - "write_register_byte": 3801564, - "utf8_decoding_base": 3111779061, - "utf8_decoding_byte": 291580479, - "utf16_decoding_base": 3543313050, - "utf16_decoding_byte": 163577493, - "sha256_base": 4540970250, - "sha256_byte": 24117351, - "keccak256_base": 5879491275, - "keccak256_byte": 21471105, - "keccak512_base": 5811388236, - "keccak512_byte": 36649701, - "log_base": 3543313050, - "log_byte": 13198791, - "storage_write_base": 64196736000, - "storage_write_key_byte": 70482867, - "storage_write_value_byte": 31018539, - "storage_write_evicted_byte": 32117307, - "storage_read_base": 56356845750, - "storage_read_key_byte": 30952533, - "storage_read_value_byte": 5611005, - "storage_remove_base": 53473030500, - "storage_remove_key_byte": 38220384, - "storage_remove_ret_value_byte": 11531556, - "storage_has_key_base": 54039896625, - "storage_has_key_byte": 30790845, - "storage_iter_create_prefix_base": 0, - "storage_iter_create_prefix_byte": 0, - "storage_iter_create_range_base": 0, - "storage_iter_create_from_byte": 0, - "storage_iter_create_to_byte": 0, - "storage_iter_next_base": 0, - "storage_iter_next_key_byte": 0, - "storage_iter_next_value_byte": 0, - "touching_trie_node": 16101955926, - "promise_and_base": 1465013400, - "promise_and_per_promise": 5452176, - "promise_return": 560152386, - "validator_stake_base": 911834726400, + "base": 264768111, + "contract_compile_base": 35445963, + "contract_compile_bytes": 216750, + "read_memory_base": 2609863200, + "read_memory_byte": 3801333, + "write_memory_base": 2803794861, + "write_memory_byte": 2723772, + "read_register_base": 2517165186, + "read_register_byte": 98562, + "write_register_base": 2865522486, + "write_register_byte": 3801564, + "utf8_decoding_base": 3111779061, + "utf8_decoding_byte": 291580479, + "utf16_decoding_base": 3543313050, + "utf16_decoding_byte": 163577493, + "sha256_base": 4540970250, + "sha256_byte": 24117351, + "keccak256_base": 5879491275, + "keccak256_byte": 21471105, + "keccak512_base": 5811388236, + "keccak512_byte": 36649701, + "log_base": 3543313050, + "log_byte": 13198791, + "storage_write_base": 64196736000, + "storage_write_key_byte": 70482867, + "storage_write_value_byte": 31018539, + "storage_write_evicted_byte": 32117307, + "storage_read_base": 56356845750, + "storage_read_key_byte": 30952533, + "storage_read_value_byte": 5611005, + "storage_remove_base": 53473030500, + "storage_remove_key_byte": 38220384, + "storage_remove_ret_value_byte": 11531556, + "storage_has_key_base": 54039896625, + "storage_has_key_byte": 30790845, + "storage_iter_create_prefix_base": 0, + "storage_iter_create_prefix_byte": 0, + "storage_iter_create_range_base": 0, + "storage_iter_create_from_byte": 0, + "storage_iter_create_to_byte": 0, + "storage_iter_next_base": 0, + "storage_iter_next_key_byte": 0, + "storage_iter_next_value_byte": 0, + "touching_trie_node": 16101955926, + "promise_and_base": 1465013400, + "promise_and_per_promise": 5452176, + "promise_return": 560152386, + "validator_stake_base": 911834726400, "validator_total_stake_base": 911834726400 - }, - "grow_mem_cost": 1, - "regular_op_cost": 3856371, + }, + "grow_mem_cost": 1, + "regular_op_cost": 3856371, "limit_config": { - "max_gas_burnt": 200000000000000, - "max_gas_burnt_view": 200000000000000, - "max_stack_height": 16384, - "initial_memory_pages": 1024, - "max_memory_pages": 2048, - "registers_memory_limit": 1073741824, - "max_register_size": 104857600, - "max_number_registers": 100, - "max_number_logs": 100, - "max_total_log_length": 16384, - "max_total_prepaid_gas": 300000000000000, - "max_actions_per_receipt": 100, - "max_number_bytes_method_names": 2000, - "max_length_method_name": 256, - "max_arguments_length": 4194304, - "max_length_returned_data": 4194304, - "max_contract_size": 4194304, - "max_length_storage_key": 4194304, - "max_length_storage_value": 4194304, - "max_promises_per_function_call_action": 1024, + "max_gas_burnt": 200000000000000, + "max_gas_burnt_view": 200000000000000, + "max_stack_height": 16384, + "initial_memory_pages": 1024, + "max_memory_pages": 2048, + "registers_memory_limit": 1073741824, + "max_register_size": 104857600, + "max_number_registers": 100, + "max_number_logs": 100, + "max_total_log_length": 16384, + "max_total_prepaid_gas": 300000000000000, + "max_actions_per_receipt": 100, + "max_number_bytes_method_names": 2000, + "max_length_method_name": 256, + "max_arguments_length": 4194304, + "max_length_returned_data": 4194304, + "max_contract_size": 4194304, + "max_length_storage_key": 4194304, + "max_length_storage_value": 4194304, + "max_promises_per_function_call_action": 1024, "max_number_input_data_dependencies": 128 } - }, + }, "account_creation_config": { - "min_allowed_top_level_account_length": 0, + "min_allowed_top_level_account_length": 0, "registrar_account_id": "registrar" } - }, + }, "validators": [ { - "account_id": "test.near", - "public_key": "ed25519:9BmAFNRTa5mRRXpSAm6MxSEeqRASDGNh2FuuwZ4gyxTw", + "account_id": "test.near", + "public_key": "ed25519:9BmAFNRTa5mRRXpSAm6MxSEeqRASDGNh2FuuwZ4gyxTw", "amount": "50000000000000000000000000000000" } - ], - "transaction_validity_period": 100, + ], + "transaction_validity_period": 100, "protocol_reward_rate": [ - 1, + 1, 10 - ], + ], "max_inflation_rate": [ - 1, + 1, 20 - ], - "total_supply": "3050000000000000000000000000000000", - "num_blocks_per_year": 31536000, - "protocol_treasury_account": "test.near", - "fishermen_threshold": "10000000000000000000000000", - "minimum_stake_divisor": 10, + ], + "total_supply": "3050000000000000000000000000000000", + "num_blocks_per_year": 31536000, + "protocol_treasury_account": "test.near", + "fishermen_threshold": "10000000000000000000000000", + "minimum_stake_divisor": 10, "records": [] } \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index 1d574108cad..30789eb9971 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -8,7 +8,8 @@ use near_vm_logic::mocks::mock_external::MockedExternal; use near_vm_logic::types::Balance; use near_vm_logic::VMConfig; -pub const CHAIN_ID: u128 = 0x99; +/// See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161555.json +pub const CHAIN_ID: u128 = 1313161555; pub fn accounts(num: usize) -> String { ["evm", "alice", "bob", "chad"][num].to_string() diff --git a/runtime/runtime/Cargo.toml b/runtime/runtime/Cargo.toml index 23f5ee0e657..fa5d1e22564 100644 --- a/runtime/runtime/Cargo.toml +++ b/runtime/runtime/Cargo.toml @@ -52,3 +52,4 @@ rayon = "^1.1" assert_matches = "1.3" testlib = { path = "../../test-utils/testlib" } +near-chain-configs = { path = "../../core/chain-configs" } \ No newline at end of file diff --git a/runtime/runtime/src/state_viewer.rs b/runtime/runtime/src/state_viewer.rs index da436eeda3b..aa3fd088b5d 100644 --- a/runtime/runtime/src/state_viewer.rs +++ b/runtime/runtime/src/state_viewer.rs @@ -193,6 +193,7 @@ impl TrieViewer { #[cfg(test)] mod tests { + use near_chain_configs::TEST_EVM_CHAIN_ID; use near_primitives::test_utils::MockEpochInfoProvider; use near_primitives::trie_key::TrieKey; use near_primitives::types::StateChangeCause; @@ -222,7 +223,7 @@ mod tests { &mut logs, &MockEpochInfoProvider::default(), PROTOCOL_VERSION, - 0x99, + TEST_EVM_CHAIN_ID, ); assert_eq!(result.unwrap(), encode_int(10)); @@ -246,7 +247,7 @@ mod tests { &mut logs, &MockEpochInfoProvider::default(), PROTOCOL_VERSION, - 0x99, + TEST_EVM_CHAIN_ID, ); let err = result.unwrap_err(); From e52bb03d663b5f7af0649cfa303f86096263b7ad Mon Sep 17 00:00:00 2001 From: Arto Bendiken Date: Fri, 30 Oct 2020 23:26:45 +0200 Subject: [PATCH 47/82] Upgrade OpenEthereum from pre-2.6.0 (Jun 2019) to 2.6.2 (Aug 2019). #3506 (#3542) As a first step in #3506, upgrade OpenEthereum from [pre-2.6.0](https://github.com/openethereum/openethereum/commit/eed630a002bbebed3a3097127f2483213ff52079) (Jun 2019) to [2.6.2](https://github.com/openethereum/openethereum/releases/tag/v2.6.2) (Aug 2019). OpenEthereum 2.6.2 is the last release that nearcore can currently pull in without build errors. Further upgrades will require code changes in near-evm-runner. (I'm working on those.) The upstream diff from what we currently pull in compared to 2.6.2: https://github.com/openethereum/openethereum/compare/eed630a...v2.6.2 --- ATTRIBUTIONS.md | 4 +- Cargo.lock | 60 ++++++++++++++++++------- core/crypto/src/signature.rs | 2 +- runtime/near-evm-runner/Cargo.toml | 4 +- runtime/near-evm-runner/src/near_ext.rs | 2 +- 5 files changed, 51 insertions(+), 21 deletions(-) diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index 559ca45140f..00768e04545 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -1,14 +1,14 @@ # NEAR Client Attributions We have taken inspiration and few pieces of code from: - * [Parity Ethereum](https://github.com/paritytech/parity-ethereum) + * [OpenEthereum](https://github.com/openethereum/openethereum) * [Parity Substrate](https://github.com/paritytech/substrate) * [Parity Trie](https://github.com/paritytech/trie) * [Grin](https://github.com/mimblewimble/grin/) ## Licenses -### Parity {Ethereum, Substrate} +### OpenEthereum, Parity Substrate GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 diff --git a/Cargo.lock b/Cargo.lock index b50f9a55055..daf748ae341 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1457,7 +1457,7 @@ dependencies = [ [[package]] name = "ethjson" version = "0.1.0" -source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" dependencies = [ "ethereum-types", "rustc-hex 1.0.0", @@ -1469,16 +1469,16 @@ dependencies = [ [[package]] name = "evm" version = "0.1.0" -source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" dependencies = [ "bit-set", "ethereum-types", - "heapsize", "keccak-hash", "lazy_static", "log", "memory-cache", "parity-bytes", + "parity-util-mem", "parking_lot 0.7.1", "vm", ] @@ -1896,9 +1896,15 @@ dependencies = [ [[package]] name = "hash-db" -version = "0.11.0" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03501f6e1a2a97f1618879aba3156f14ca2847faa530c4e28859638bd11483" +checksum = "0b3c95a428c86ed4633d83e07ef9e0a147a906da01e931f07e74a85bedce5a43" + +[[package]] +name = "hashmap_core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6852e5a86250521973b0c1d39677166d8a9c0047c908d7e04f1aa04177973c" [[package]] name = "heapsize" @@ -2317,7 +2323,7 @@ dependencies = [ [[package]] name = "keccak-hasher" version = "0.1.1" -source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" dependencies = [ "ethereum-types", "hash-db", @@ -2533,6 +2539,17 @@ dependencies = [ "libc", ] +[[package]] +name = "malloc_size_of_derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37c5d4cd9473c5f4c9c111f033f15d4df9bd378fdf615944e360a4f55a05f0b" +dependencies = [ + "proc-macro2 1.0.20", + "syn 1.0.38", + "synstructure", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -2588,10 +2605,10 @@ dependencies = [ [[package]] name = "memory-cache" version = "0.1.0" -source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" dependencies = [ - "heapsize", "lru-cache", + "parity-util-mem", ] [[package]] @@ -3669,6 +3686,21 @@ dependencies = [ "rand 0.7.3", ] +[[package]] +name = "parity-util-mem" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e80f22052161e0cb55cb5a8a75890420c525031f95c9d262dbb0434aa85dc1" +dependencies = [ + "cfg-if", + "clear_on_drop", + "elastic-array 0.10.3", + "ethereum-types", + "malloc_size_of_derive", + "parking_lot 0.7.1", + "winapi 0.3.8", +] + [[package]] name = "parity-wasm" version = "0.41.0" @@ -3751,7 +3783,7 @@ dependencies = [ [[package]] name = "patricia-trie-ethereum" version = "0.1.0" -source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" dependencies = [ "elastic-array 0.10.3", "ethereum-types", @@ -5305,12 +5337,13 @@ checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" [[package]] name = "trie-db" -version = "0.11.0" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7319e28ca295f27359d944a682f7f65b419158bf1590c92cadc0000258d788" +checksum = "ae063390324bfcf36c7e8e4fb1f85f6f0fb5dd04e1cd282581eb7b8b34b32de7" dependencies = [ "elastic-array 0.10.3", "hash-db", + "hashmap_core", "log", "rand 0.6.5", ] @@ -5547,17 +5580,14 @@ checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" [[package]] name = "vm" version = "0.1.0" -source = "git+https://github.com/paritytech/parity-ethereum?rev=eed630a002bbebed3a3097127f2483213ff52079#eed630a002bbebed3a3097127f2483213ff52079" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" dependencies = [ - "byteorder", "ethereum-types", "ethjson", "keccak-hash", - "log", "parity-bytes", "patricia-trie-ethereum", "rlp", - "trie-db", ] [[package]] diff --git a/core/crypto/src/signature.rs b/core/crypto/src/signature.rs index 907af8023e0..333791b9eac 100644 --- a/core/crypto/src/signature.rs +++ b/core/crypto/src/signature.rs @@ -625,7 +625,7 @@ impl Signature { .unwrap(); let sig = rsig.to_standard(&SECP256K1); let pdata: [u8; 65] = { - // code borrowed from https://github.com/paritytech/parity-ethereum/blob/98b7c07171cd320f32877dfa5aa528f585dc9a72/ethkey/src/signature.rs#L210 + // code borrowed from https://github.com/openethereum/openethereum/blob/98b7c07171cd320f32877dfa5aa528f585dc9a72/ethkey/src/signature.rs#L210 let mut temp = [4u8; 65]; temp[1..65].copy_from_slice(&public_key.0); temp diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index c0599106e4b..09c645b0292 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -24,8 +24,8 @@ keccak-hash = "0.2.0" ripemd160 = "0.9.0" libsecp256k1 = "0.3.5" -evm = { git = "https://github.com/paritytech/parity-ethereum", rev = "eed630a002bbebed3a3097127f2483213ff52079" } -vm = { git = "https://github.com/paritytech/parity-ethereum", rev = "eed630a002bbebed3a3097127f2483213ff52079" } +evm = { git = "https://github.com/openethereum/openethereum", rev = "v2.6.2" } +vm = { git = "https://github.com/openethereum/openethereum", rev = "v2.6.2" } bn = { git = "https://github.com/paritytech/bn", default-features = false } parity-bytes = "0.1.0" ethereum-types = "0.6.0" diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index bdcafb8db3d..144bd92cd06 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -15,7 +15,7 @@ use crate::evm_state::{EvmState, SubState}; use crate::interpreter; use crate::utils::format_log; -// https://github.com/paritytech/parity-ethereum/blob/77643c13e80ca09d9a6b10631034f5a1568ba6d3/ethcore/machine/src/externalities.rs +// https://github.com/openethereum/openethereum/blob/77643c13e80ca09d9a6b10631034f5a1568ba6d3/ethcore/machine/src/externalities.rs pub struct NearExt<'a> { pub info: EnvInfo, pub origin: Address, From e350e29540ec84932e0dbbfd6c1d76b343af436c Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Mon, 2 Nov 2020 14:01:48 -0800 Subject: [PATCH 48/82] Evm gas estimation (#3299) * initial gas used in evm interpreter * see what case in result * atempt of return different gas left * gas_left * all gas metering works * undo all debug prints * revert is not considered as error until top level to calc revert gas left * resolve all gas from revert * cost hook for precompile functions * basic evm gas counter * got evm gas used in all tests * count deploy evm code cost * compiles * wip measure functions * fix deploy cost * measure funcall cost, start adding contract function to know precompile function cost * all cost countings except bn256 precompiled functions * calc and deduct near gas from number given by evm gas * address illia comments * thread in prepaid function cost in evm * fix random fee * convert prepaid near gas to evm gas so evm gas convert to near wont overflow * made mistake of reverse base cost and per_evm_gas cost, correct it * wip measure evm include block cost, stuck in get account code hash same to EVM_CODE_HASH * deploy contract total cost calc works * fix small errors after resolve conflict * deploy cost works, function cost is 0, debug * evm cost of function call * comment * deduct action fee and todo on get correct evm addr to function call * fix deploy evm addr * correct deduct action receipt cost * saturating sub * adding warmup * remove some debug prints * costs counting only on recet sevm gas counter * some fixes * fix errors in semantic conflicts happens in merge * delete * nit * nit * nit * nit * refactor use test-utils.testlib to get evm contract addr * evm deploy cost based on both evm gas and contract size * lsq compiles * lsq compiles * my rust impl of 2d lsq, end result stable but lsq is incorrect * simplify * accurate evm deploy base cost, per evm gas and per byte * fix deploy evm contract to all accounts nonce issue * balancer contract binary suite * evm precompile function per byte evm gas, but they are too small * wire in evm gas per byte and update numbers * avoid pay evm bootstrap fee when evm is not started * do not measure action receipt fee for evm as they are deduct separately * new numbers * features for runtime-params-estimator * evm features works in runtime-param-estimator * undo debug print * undo disable lto --- Cargo.lock | 26 +- core/primitives/src/version.rs | 4 +- neard/Cargo.toml | 2 +- runtime/near-evm-runner/Cargo.toml | 10 +- runtime/near-evm-runner/src/builtins.rs | 43 +- runtime/near-evm-runner/src/evm_state.rs | 25 + runtime/near-evm-runner/src/interpreter.rs | 112 +- runtime/near-evm-runner/src/lib.rs | 218 ++- runtime/near-evm-runner/src/near_ext.rs | 51 +- runtime/near-evm-runner/tests/build.sh | 1 + .../near-evm-runner/tests/build/BBronze.abi | 17 + .../near-evm-runner/tests/build/BBronze.bin | 1 + .../near-evm-runner/tests/build/BColor.abi | 17 + .../near-evm-runner/tests/build/BConst.abi | 257 +++ .../near-evm-runner/tests/build/BConst.bin | 1 + .../near-evm-runner/tests/build/BFactory.abi | 142 ++ .../near-evm-runner/tests/build/BFactory.bin | 1 + runtime/near-evm-runner/tests/build/BMath.abi | 574 ++++++ runtime/near-evm-runner/tests/build/BMath.bin | 1 + runtime/near-evm-runner/tests/build/BNum.abi | 257 +++ runtime/near-evm-runner/tests/build/BNum.bin | 1 + runtime/near-evm-runner/tests/build/BPool.abi | 1630 +++++++++++++++++ runtime/near-evm-runner/tests/build/BPool.bin | 1 + .../near-evm-runner/tests/build/BToken.abi | 549 ++++++ .../near-evm-runner/tests/build/BToken.bin | 1 + .../tests/build/BTokenBase.abi | 307 ++++ .../tests/build/BTokenBase.bin | 1 + .../tests/build/ConstructorRevert.bin | 1 - .../tests/build/Create2Factory.bin | 2 +- .../near-evm-runner/tests/build/IERC20.abi | 197 ++ .../tests/build/Migrations.abi | 68 + .../tests/build/Migrations.bin | 1 + .../tests/build/PrecompiledFunction.abi | 204 +++ .../tests/build/PrecompiledFunction.bin | 1 + .../tests/build/SelfDestruct.bin | 2 +- .../near-evm-runner/tests/build/SolTests.bin | 2 +- .../tests/build/SubContract.bin | 1 - .../tests/build/TBPoolJoinExit.abi | 302 +++ .../tests/build/TBPoolJoinExit.bin | 1 + .../tests/build/TBPoolJoinExitNoFee.abi | 302 +++ .../tests/build/TBPoolJoinExitNoFee.bin | 1 + .../tests/build/TBPoolJoinPool.abi | 303 +++ .../tests/build/TBPoolJoinPool.bin | 1 + runtime/near-evm-runner/tests/build/TMath.abi | 834 +++++++++ runtime/near-evm-runner/tests/build/TMath.bin | 1 + .../near-evm-runner/tests/build/TToken.abi | 311 ++++ .../tests/build/zombieAttack.bin | 2 +- .../tests/contracts/SolTests.sol | 80 + runtime/near-evm-runner/tests/utils.rs | 6 + runtime/near-runtime-fees/src/lib.rs | 53 + runtime/near-vm-errors/Cargo.toml | 2 + runtime/near-vm-logic/src/gas_counter.rs | 37 +- runtime/near-vm-runner/Cargo.toml | 1 + runtime/runtime-params-estimator/Cargo.toml | 14 +- runtime/runtime-params-estimator/src/cases.rs | 70 +- runtime/runtime-params-estimator/src/main.rs | 2 + .../runtime-params-estimator/src/testbed.rs | 10 +- .../src/testbed_runners.rs | 2 +- .../src/vm_estimator.rs | 655 ++++++- runtime/runtime/Cargo.toml | 1 + runtime/runtime/src/lib.rs | 2 + .../runtime_group_tools/random_config.rs | 14 +- test-utils/state-viewer/src/lib.rs | 2 + 63 files changed, 7623 insertions(+), 115 deletions(-) create mode 100644 runtime/near-evm-runner/tests/build/BBronze.abi create mode 100644 runtime/near-evm-runner/tests/build/BBronze.bin create mode 100644 runtime/near-evm-runner/tests/build/BColor.abi create mode 100644 runtime/near-evm-runner/tests/build/BConst.abi create mode 100644 runtime/near-evm-runner/tests/build/BConst.bin create mode 100644 runtime/near-evm-runner/tests/build/BFactory.abi create mode 100644 runtime/near-evm-runner/tests/build/BFactory.bin create mode 100644 runtime/near-evm-runner/tests/build/BMath.abi create mode 100644 runtime/near-evm-runner/tests/build/BMath.bin create mode 100644 runtime/near-evm-runner/tests/build/BNum.abi create mode 100644 runtime/near-evm-runner/tests/build/BNum.bin create mode 100644 runtime/near-evm-runner/tests/build/BPool.abi create mode 100644 runtime/near-evm-runner/tests/build/BPool.bin create mode 100644 runtime/near-evm-runner/tests/build/BToken.abi create mode 100644 runtime/near-evm-runner/tests/build/BToken.bin create mode 100644 runtime/near-evm-runner/tests/build/BTokenBase.abi create mode 100644 runtime/near-evm-runner/tests/build/BTokenBase.bin delete mode 100644 runtime/near-evm-runner/tests/build/ConstructorRevert.bin create mode 100644 runtime/near-evm-runner/tests/build/IERC20.abi create mode 100644 runtime/near-evm-runner/tests/build/Migrations.abi create mode 100644 runtime/near-evm-runner/tests/build/Migrations.bin create mode 100644 runtime/near-evm-runner/tests/build/PrecompiledFunction.abi create mode 100644 runtime/near-evm-runner/tests/build/PrecompiledFunction.bin delete mode 100644 runtime/near-evm-runner/tests/build/SubContract.bin create mode 100644 runtime/near-evm-runner/tests/build/TBPoolJoinExit.abi create mode 100644 runtime/near-evm-runner/tests/build/TBPoolJoinExit.bin create mode 100644 runtime/near-evm-runner/tests/build/TBPoolJoinExitNoFee.abi create mode 100644 runtime/near-evm-runner/tests/build/TBPoolJoinExitNoFee.bin create mode 100644 runtime/near-evm-runner/tests/build/TBPoolJoinPool.abi create mode 100644 runtime/near-evm-runner/tests/build/TBPoolJoinPool.bin create mode 100644 runtime/near-evm-runner/tests/build/TMath.abi create mode 100644 runtime/near-evm-runner/tests/build/TMath.bin create mode 100644 runtime/near-evm-runner/tests/build/TToken.abi create mode 100644 test-utils/state-viewer/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index daf748ae341..3aeebeb5e98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1151,6 +1151,17 @@ dependencies = [ "log", ] +[[package]] +name = "derivative" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" +dependencies = [ + "proc-macro2 1.0.20", + "quote 1.0.3", + "syn 1.0.38", +] + [[package]] name = "derive_more" version = "0.99.9" @@ -2883,11 +2894,12 @@ dependencies = [ [[package]] name = "near-evm-runner" -version = "0.1.0" +version = "2.2.0" dependencies = [ "bn", "borsh", "byteorder", + "derivative", "enum-primitive-derive", "ethabi", "ethabi-contract", @@ -3204,6 +3216,7 @@ name = "near-vm-errors" version = "2.2.0" dependencies = [ "borsh", + "ethereum-types", "hex", "near-rpc-error-macro", "serde", @@ -3233,6 +3246,7 @@ dependencies = [ "assert_matches", "bencher", "cached", + "near-evm-runner", "near-runtime-fees", "near-vm-errors", "near-vm-logic", @@ -4442,11 +4456,18 @@ dependencies = [ "borsh", "clap 2.33.0", "csv", + "ethabi", + "ethabi-contract", + "ethabi-derive", + "ethereum-types", "glob 0.3.0", "gnuplot", + "hex", "indicatif 0.15.0", + "lazy-static-include", "near-chain-configs", "near-crypto", + "near-evm-runner", "near-primitives", "near-runtime-fees", "near-store", @@ -4455,11 +4476,14 @@ dependencies = [ "neard", "node-runtime", "num-rational 0.3.0", + "num-traits", "rand 0.7.3", "rand_xorshift 0.2.0", "rocksdb", "serde_json", + "state-viewer", "tempfile", + "testlib", "walrus", ] diff --git a/core/primitives/src/version.rs b/core/primitives/src/version.rs index c0f2aef157a..922fdee71ff 100644 --- a/core/primitives/src/version.rs +++ b/core/primitives/src/version.rs @@ -108,7 +108,9 @@ lazy_static! { let nightly_protocol_features_to_version_mapping: HashMap< ProtocolFeature, ProtocolVersion, - > = vec![(ProtocolFeature::ForwardChunkParts, 41)].into_iter().collect(); + > = vec![(ProtocolFeature::ForwardChunkParts, 41), (ProtocolFeature::EVM, 41)] + .into_iter() + .collect(); for (stable_protocol_feature, stable_protocol_version) in STABLE_PROTOCOL_FEATURES_TO_VERSION_MAPPING.iter() { diff --git a/neard/Cargo.toml b/neard/Cargo.toml index 427908647d8..aa2e65080f9 100644 --- a/neard/Cargo.toml +++ b/neard/Cargo.toml @@ -59,7 +59,7 @@ no_cache = ["node-runtime/no_cache", "near-store/no_cache", "near-chain/no_cache delay_detector = ["near-client/delay_detector"] rosetta_rpc = ["near-rosetta-rpc"] protocol_feature_forward_chunk_parts = ["near-client/protocol_feature_forward_chunk_parts"] -protocol_feature_evm = ["near-primitives/protocol_feature_evm"] +protocol_feature_evm = ["node-runtime/protocol_feature_evm", "near-primitives/protocol_feature_evm"] nightly_protocol_features = ["nightly_protocol", "protocol_feature_forward_chunk_parts", "near-client/nightly_protocol_features", "protocol_feature_evm"] nightly_protocol = ["near-primitives/nightly_protocol"] diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 09c645b0292..604fad9eb2d 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "near-evm-runner" -version = "0.1.0" +version = "2.2.0" authors = ["Near Inc "] edition = "2018" license = "Apache-2.0" @@ -35,6 +35,8 @@ near-vm-errors = { path = "../near-vm-errors" } near-runtime-utils = { path = "../near-runtime-utils" } near-runtime-fees = { path = "../near-runtime-fees" } +derivative = "2.1.1" + [dev-dependencies] ethabi = "8.0.0" ethabi-contract = "8.0.0" @@ -42,4 +44,8 @@ ethabi-derive = "8.0.0" lazy_static = "1.4" lazy-static-include = "2.2.2" -near-crypto = { path = "../../core/crypto" } \ No newline at end of file +near-crypto = { path = "../../core/crypto" } + +[features] +default = [] +costs_counting = [] \ No newline at end of file diff --git a/runtime/near-evm-runner/src/builtins.rs b/runtime/near-evm-runner/src/builtins.rs index fe6f039b973..a7f861ca3eb 100644 --- a/runtime/near-evm-runner/src/builtins.rs +++ b/runtime/near-evm-runner/src/builtins.rs @@ -4,9 +4,9 @@ use std::{ mem::size_of, }; -use bn::arith::U256; use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt}; -use ethereum_types::Address; +use ethereum_types::{Address, H256, U256}; +use near_runtime_fees::EvmCostConfig; use num_bigint::BigUint; use num_traits::{FromPrimitive, One, ToPrimitive, Zero}; use parity_bytes::BytesRef; @@ -48,13 +48,23 @@ pub fn precompile(id: u64) -> Result, String> { }) } -pub fn process_precompile(addr: &Address, input: &[u8]) -> MessageCallResult { +pub fn process_precompile( + addr: &Address, + input: &[u8], + gas: &U256, + evm_gas_config: &EvmCostConfig, +) -> MessageCallResult { let f = match precompile(addr.to_low_u64_be()) { Ok(f) => f, Err(_) => return MessageCallResult::Failed, }; let mut bytes = vec![]; let mut output = parity_bytes::BytesRef::Flexible(&mut bytes); + let cost = f.gas(input, evm_gas_config); + + if cost > *gas { + return MessageCallResult::Failed; + } // mutates bytes match f.execute(input, &mut output) { @@ -63,8 +73,7 @@ pub fn process_precompile(addr: &Address, input: &[u8]) -> MessageCallResult { }; let size = bytes.len(); - // TODO: add gas usage here. - MessageCallResult::Success(1_000_000_000.into(), ReturnData::new(bytes, 0, size)) + MessageCallResult::Success(*gas - cost, ReturnData::new(bytes, 0, size)) } /** the following is copied from ethcore/src/builtin.rs **/ @@ -131,6 +140,9 @@ pub struct Blake2FImpl; pub trait Impl: Send + Sync { /// execute this built-in on the given input, writing to the given output. fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error>; + fn gas(&self, _input: &[u8], _evm_gas_config: &EvmCostConfig) -> U256 { + 0.into() + } } impl Impl for Identity { @@ -138,6 +150,9 @@ impl Impl for Identity { output.write(0, input); Ok(()) } + fn gas(&self, _input: &[u8], evm_gas_config: &EvmCostConfig) -> U256 { + evm_gas_config.identity_cost.into() + } } impl Impl for EcRecover { @@ -157,6 +172,10 @@ impl Impl for EcRecover { Ok(()) } + + fn gas(&self, _input: &[u8], evm_gas_config: &EvmCostConfig) -> U256 { + evm_gas_config.ecrecover_cost.into() + } } impl Impl for Sha256 { @@ -166,6 +185,10 @@ impl Impl for Sha256 { output.write(0, &*d); Ok(()) } + + fn gas(&self, _input: &[u8], evm_gas_config: &EvmCostConfig) -> U256 { + evm_gas_config.sha256_cost.into() + } } impl Impl for Ripemd160 { @@ -175,6 +198,10 @@ impl Impl for Ripemd160 { output.write(12, &hash); Ok(()) } + + fn gas(&self, _input: &[u8], evm_gas_config: &EvmCostConfig) -> U256 { + evm_gas_config.ripemd160_cost.into() + } } // calculate modexp: left-to-right binary exponentiation to keep multiplicands lower @@ -283,6 +310,10 @@ impl Impl for ModexpImpl { Ok(()) } + + fn gas(&self, _input: &[u8], evm_gas_config: &EvmCostConfig) -> U256 { + evm_gas_config.modexp_cost.into() + } } fn read_fr(reader: &mut io::Chain<&[u8], io::Repeat>) -> Result<::bn::Fr, Error> { @@ -431,7 +462,7 @@ impl Bn128PairingImpl { }; let mut buf = [0u8; 32]; - ret_val.to_big_endian(&mut buf).expect("Can't fail"); + ret_val.to_big_endian(&mut buf); output.write(0, &buf); Ok(()) diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index a47d037e55a..28e2a92de63 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -325,6 +325,31 @@ impl EvmState for SubState<'_> { } } +#[derive(Debug)] +pub struct EvmGasCounter { + pub used_gas: U256, + pub max_gas: U256, +} + +impl EvmGasCounter { + pub fn new(used_gas: U256, max_gas: U256) -> EvmGasCounter { + Self { used_gas, max_gas } + } + + pub fn pay_gas(&mut self, amount: U256) { + debug_assert!(self.used_gas + amount <= self.max_gas); + self.used_gas += amount; + } + + pub fn set_gas_left(&mut self, left: U256) { + self.used_gas = self.max_gas.saturating_sub(left); + } + + pub fn gas_left(&self) -> U256 { + self.max_gas - self.used_gas + } +} + #[cfg(test)] mod test { use super::*; diff --git a/runtime/near-evm-runner/src/interpreter.rs b/runtime/near-evm-runner/src/interpreter.rs index aee86c9121d..f767cf85e55 100644 --- a/runtime/near-evm-runner/src/interpreter.rs +++ b/runtime/near-evm-runner/src/interpreter.rs @@ -2,9 +2,10 @@ use std::sync::Arc; use ethereum_types::{Address, U256}; use evm::{CreateContractAddress, Factory}; +use near_runtime_fees::EvmCostConfig; use vm::{ - ActionParams, ActionValue, CallType, ExecTrapResult, Ext, GasLeft, ParamsType, ReturnData, - Schedule, + ActionParams, ActionValue, CallType, ContractCreateResult, ExecTrapResult, Ext, GasLeft, + MessageCallResult, ParamsType, ReturnData, Schedule, }; use near_vm_errors::{EvmError, VMLogicError}; @@ -23,7 +24,9 @@ pub fn deploy_code( address_type: CreateContractAddress, recreate: bool, code: &[u8], -) -> Result
{ + gas: &U256, + evm_gas_config: &EvmCostConfig, +) -> Result { let mut nonce = U256::zero(); if address_type == CreateContractAddress::FromSenderAndNonce { nonce = state.next_nonce(&sender)?; @@ -36,15 +39,26 @@ pub fn deploy_code( return Err(VMLogicError::EvmError(EvmError::DuplicateContract(address.0.to_vec()))); } - let (result, state_updates) = - _create(state, origin, sender, value, call_stack_depth, &address, code)?; + let (result, state_updates) = _create( + state, + origin, + sender, + value, + call_stack_depth, + &address, + code, + gas, + evm_gas_config, + )?; // Apply known gas amount changes (all reverts are NeedsReturn) // Apply NeedsReturn changes if apply_state // Return the result unmodified - let (return_data, apply) = match result { - Ok(Ok(GasLeft::Known(_))) => (ReturnData::empty(), true), - Ok(Ok(GasLeft::NeedsReturn { gas_left: _, data, apply_state })) => (data, apply_state), + let (return_data, apply, gas_left) = match result { + Ok(Ok(GasLeft::Known(left))) => (ReturnData::empty(), true, left), + Ok(Ok(GasLeft::NeedsReturn { gas_left: left, data, apply_state })) => { + (data, apply_state, left) + } Ok(Err(err)) => return Err(convert_vm_error(err)), Err(_) => return Err(VMLogicError::EvmError(EvmError::Reverted)), }; @@ -52,10 +66,10 @@ pub fn deploy_code( if apply { state.commit_changes(&state_updates.unwrap())?; state.set_code(&address, &return_data.to_vec())?; + Ok(ContractCreateResult::Created(address, gas_left)) } else { - return Err(VMLogicError::EvmError(EvmError::DeployFail(return_data.to_vec()))); + Ok(ContractCreateResult::Reverted(gas_left, return_data)) } - Ok(address) } pub fn _create( @@ -66,6 +80,8 @@ pub fn _create( call_stack_depth: usize, address: &Address, code: &[u8], + gas: &U256, + evm_gas_config: &EvmCostConfig, ) -> Result<(ExecTrapResult, Option)> { let mut store = StateStore::default(); let mut sub_state = SubState::new(sender, &mut store, state); @@ -75,8 +91,7 @@ pub fn _create( address: *address, sender: *sender, origin: *origin, - // TODO: gas usage. - gas: 1_000_000_000.into(), + gas: *gas, gas_price: 1.into(), value: ActionValue::Transfer(value), code: Some(Arc::new(code.to_vec())), @@ -88,16 +103,21 @@ pub fn _create( sub_state.transfer_balance(sender, address, value)?; - let mut ext = NearExt::new(*address, *origin, &mut sub_state, call_stack_depth + 1, false); - // TODO: gas usage. - ext.info.gas_limit = U256::from(1_000_000_000); + let mut ext = NearExt::new( + *address, + *origin, + &mut sub_state, + call_stack_depth + 1, + false, + evm_gas_config, + ); + ext.info.gas_limit = U256::from(gas); ext.schedule = Schedule::new_constantinople(); let instance = Factory::default().create(params, ext.schedule(), ext.depth()); // Run the code let result = instance.exec(&mut ext); - Ok((result, Some(store))) } @@ -111,7 +131,9 @@ pub fn call( contract_address: &Address, input: &[u8], should_commit: bool, -) -> Result { + gas: &U256, + evm_gas_config: &EvmCostConfig, +) -> Result { run_and_commit_if_success( state, origin, @@ -124,6 +146,8 @@ pub fn call( input, false, should_commit, + gas, + evm_gas_config, ) } @@ -135,7 +159,9 @@ pub fn delegate_call( context: &Address, delegee: &Address, input: &[u8], -) -> Result { + gas: &U256, + evm_gas_config: &EvmCostConfig, +) -> Result { run_and_commit_if_success( state, origin, @@ -148,6 +174,8 @@ pub fn delegate_call( input, false, true, + gas, + evm_gas_config, ) } @@ -158,7 +186,9 @@ pub fn static_call( call_stack_depth: usize, contract_address: &Address, input: &[u8], -) -> Result { + gas: &U256, + evm_gas_config: &EvmCostConfig, +) -> Result { run_and_commit_if_success( state, origin, @@ -171,6 +201,8 @@ pub fn static_call( input, true, false, + gas, + evm_gas_config, ) } @@ -187,7 +219,9 @@ fn run_and_commit_if_success( input: &[u8], is_static: bool, should_commit: bool, -) -> Result { + gas: &U256, + evm_gas_config: &EvmCostConfig, +) -> Result { // run the interpreter and let (result, state_updates) = run_against_state( state, @@ -200,26 +234,33 @@ fn run_and_commit_if_success( code_address, input, is_static, + gas, + evm_gas_config, )?; // Apply known gas amount changes (all reverts are NeedsReturn) // Apply NeedsReturn changes if apply_state // Return the result unmodified + let mut should_apply_state = true; let return_data = match result { - Ok(Ok(GasLeft::Known(_))) => Ok(ReturnData::empty()), - Ok(Ok(GasLeft::NeedsReturn { gas_left: _, data, apply_state: true })) => Ok(data), - Ok(Ok(GasLeft::NeedsReturn { gas_left: _, data, apply_state: false })) => { - Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) + Ok(Ok(GasLeft::Known(gas_left))) => { + Ok(MessageCallResult::Success(gas_left, ReturnData::empty())) + } + Ok(Ok(GasLeft::NeedsReturn { gas_left, data, apply_state: true })) => { + Ok(MessageCallResult::Success(gas_left, data)) + } + Ok(Ok(GasLeft::NeedsReturn { gas_left, data, apply_state: false })) => { + should_apply_state = false; + Ok(MessageCallResult::Reverted(gas_left, data)) } Ok(Err(err)) => Err(convert_vm_error(err)), Err(_) => Err(VMLogicError::EvmError(EvmError::Reverted)), }; // Don't apply changes from a static context (these _should_ error in the ext) - if !is_static && return_data.is_ok() && should_commit { + if !is_static && return_data.is_ok() && should_apply_state && should_commit { state.commit_changes(&state_updates.unwrap())?; } - return_data } @@ -236,6 +277,8 @@ fn run_against_state( code_address: &Address, input: &[u8], is_static: bool, + gas: &U256, + evm_gas_config: &EvmCostConfig, ) -> Result<(ExecTrapResult, Option)> { let code = state.code_at(code_address)?.unwrap_or_else(Vec::new); @@ -254,8 +297,7 @@ fn run_against_state( address: *state_address, sender: *sender, origin: *origin, - // TODO: gas usage. - gas: 1_000_000_000.into(), + gas: *gas, gas_price: 1.into(), value: ActionValue::Apparent(0.into()), code: Some(Arc::new(code)), @@ -270,10 +312,16 @@ fn run_against_state( sub_state.transfer_balance(sender, state_address, val)?; } - let mut ext = - NearExt::new(*state_address, *origin, &mut sub_state, call_stack_depth + 1, is_static); - // TODO: gas usage. - ext.info.gas_limit = U256::from(1_000_000_000); + let mut ext = NearExt::new( + *state_address, + *origin, + &mut sub_state, + call_stack_depth + 1, + is_static, + evm_gas_config, + ); + // Gas limit is evm block gas limit, should at least prepaid gas. + ext.info.gas_limit = *gas; ext.schedule = Schedule::new_constantinople(); let instance = Factory::default().create(params, ext.schedule(), ext.depth()); diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 96bd3ed325c..13b5ccd8296 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -4,15 +4,16 @@ extern crate enum_primitive_derive; use borsh::{BorshDeserialize, BorshSerialize}; use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; +use vm::{ContractCreateResult, MessageCallResult}; -use near_runtime_fees::RuntimeFeesConfig; +use near_runtime_fees::{EvmCostConfig, RuntimeFeesConfig}; use near_runtime_utils::{is_account_id_64_len_hex, is_valid_sub_account_id}; use near_vm_errors::{EvmError, FunctionCallError, VMError}; use near_vm_logic::gas_counter::GasCounter; use near_vm_logic::types::{AccountId, Balance, Gas, ReturnData, StorageUsage}; use near_vm_logic::{ActionCosts, External, VMConfig, VMLogicError, VMOutcome}; -use crate::evm_state::{EvmAccount, EvmState, StateStore}; +use crate::evm_state::{EvmAccount, EvmGasCounter, EvmState, StateStore}; use crate::types::{ AddressArg, GetStorageAtArgs, RawU256, Result, TransferArgs, ViewCallArgs, WithdrawArgs, }; @@ -32,14 +33,23 @@ pub struct EvmContext<'a> { signer_id: AccountId, predecessor_id: AccountId, current_amount: Balance, - attached_deposit: Balance, + pub attached_deposit: Balance, storage_usage: StorageUsage, pub logs: Vec, gas_counter: GasCounter, + pub evm_gas_counter: EvmGasCounter, fees_config: &'a RuntimeFeesConfig, domain_separator: RawU256, } +// Different kind of evm operations that result in different gas calculation +pub enum EvmOpForGas { + // size of deployed evm contract after it's decoded from hex (0.5x) + Deploy(usize), + Funcall, + Other, +} + enum KeyPrefix { Account = 0, Contract = 1, @@ -144,6 +154,7 @@ impl<'a> EvmContext<'a> { storage_usage: StorageUsage, prepaid_gas: Gas, is_view: bool, + evm_gas: U256, ) -> Self { let max_gas_burnt = if is_view { config.limit_config.max_gas_burnt_view @@ -168,6 +179,7 @@ impl<'a> EvmContext<'a> { is_view, None, ), + evm_gas_counter: EvmGasCounter::new(0.into(), evm_gas), fees_config, domain_separator, } @@ -180,7 +192,7 @@ impl<'a> EvmContext<'a> { pub fn deploy_code(&mut self, bytecode: Vec) -> Result
{ let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); self.add_balance(&sender, U256::from(self.attached_deposit))?; - interpreter::deploy_code( + match interpreter::deploy_code( self, &sender, &sender, @@ -189,7 +201,19 @@ impl<'a> EvmContext<'a> { CreateContractAddress::FromSenderAndNonce, false, &bytecode, - ) + &self.evm_gas_counter.gas_left(), + &self.fees_config.evm_config, + )? { + ContractCreateResult::Created(address, gas_left) => { + self.evm_gas_counter.set_gas_left(gas_left); + Ok(address) + } + ContractCreateResult::Reverted(gas_left, return_data) => { + self.evm_gas_counter.set_gas_left(gas_left); + Err(VMLogicError::EvmError(EvmError::DeployFail(return_data.to_vec()))) + } + _ => unreachable!(), + } } /// Make an EVM transaction. Calls `contract_address` with RLP encoded `input`. Execution @@ -206,8 +230,29 @@ impl<'a> EvmContext<'a> { self.add_balance(&sender, U256::from(self.attached_deposit))?; let value = if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; - interpreter::call(self, &origin, &sender, value, 0, &contract_address, &input, true) - .map(|rd| rd.to_vec()) + let result = interpreter::call( + self, + &sender, + &sender, + value, + 0, + &contract_address, + &input, + true, + &self.evm_gas_counter.gas_left(), + &self.fees_config.evm_config, + )?; + match result { + MessageCallResult::Success(gas_left, data) => { + self.evm_gas_counter.set_gas_left(gas_left); + Ok(data.to_vec()) + } + MessageCallResult::Reverted(gas_left, data) => { + self.evm_gas_counter.set_gas_left(gas_left); + Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) + } + _ => unreachable!(), + } } /// Make an EVM call via a meta transaction pattern. @@ -221,7 +266,7 @@ impl<'a> EvmContext<'a> { self.add_balance(&meta_call_args.sender, U256::from(self.attached_deposit))?; let value = if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; - interpreter::call( + let result = interpreter::call( self, &meta_call_args.sender, &meta_call_args.sender, @@ -230,8 +275,20 @@ impl<'a> EvmContext<'a> { &meta_call_args.contract_address, &meta_call_args.input, true, - ) - .map(|rd| rd.to_vec()) + &self.evm_gas_counter.gas_left(), + &self.fees_config.evm_config, + )?; + match result { + MessageCallResult::Success(gas_left, data) => { + self.evm_gas_counter.set_gas_left(gas_left); + Ok(data.to_vec()) + } + MessageCallResult::Reverted(gas_left, data) => { + self.evm_gas_counter.set_gas_left(gas_left); + Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) + } + _ => unreachable!(), + } } /// Make an EVM transaction. Calls `contract_address` with `encoded_input`. Execution @@ -254,8 +311,20 @@ impl<'a> EvmContext<'a> { &Address::from(&args.address), &args.args, false, - ) - .map(|rd| rd.to_vec()); + &self.evm_gas_counter.gas_left(), + &self.fees_config.evm_config, + )?; + let result = match result { + MessageCallResult::Success(gas_left, data) => { + self.evm_gas_counter.set_gas_left(gas_left); + Ok(data.to_vec()) + } + MessageCallResult::Reverted(gas_left, data) => { + self.evm_gas_counter.set_gas_left(gas_left); + Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) + } + _ => unreachable!(), + }; // Need to subtract amount back, because if view call is called inside the transaction state will be applied. // The interpreter call is not committing changes, but `add_balance` did, so need to revert that. self.sub_balance(&sender, attached_amount)?; @@ -400,6 +469,27 @@ impl<'a> EvmContext<'a> { self.gas_counter.pay_action_accumulated(burn_gas, use_gas, ActionCosts::new_receipt) } + fn pay_gas_from_evm_gas(&mut self, op: EvmOpForGas) -> Result<()> { + let fee_cfg = &self.fees_config.evm_config; + let evm_gas = self.evm_gas_counter.used_gas.as_u64(); + self.gas_counter.inc_evm_gas_counter(evm_gas); + let gas = match op { + EvmOpForGas::Deploy(decoded_len) => { + // gas per byte is counting hex encoded contract size (solc output, 2x of decoded len) + (decoded_len as u64 * 2) * fee_cfg.deploy_cost_per_byte + + evm_gas * fee_cfg.deploy_cost_per_evm_gas + + fee_cfg.bootstrap_cost + } + EvmOpForGas::Funcall => { + evm_gas * fee_cfg.funcall_cost_per_evm_gas + + fee_cfg.funcall_cost_base + + fee_cfg.bootstrap_cost + } + EvmOpForGas::Other => fee_cfg.bootstrap_cost, + }; + self.gas_counter.pay_evm_gas(gas) + } + fn pay_gas_for_transfer(&mut self, account_id: &AccountId) -> Result<()> { if is_account_id_64_len_hex(&account_id) { self.gas_counter.pay_action_base( @@ -421,6 +511,45 @@ impl<'a> EvmContext<'a> { } } +fn max_evm_gas_from_near_gas( + near_gas: Gas, + evm_gas_config: &EvmCostConfig, + method_name: &str, + decoded_code_size: Option, +) -> Option { + match method_name { + "deploy_code" => { + if near_gas < evm_gas_config.bootstrap_cost { + return None; + } + Some( + ((near_gas + - evm_gas_config.bootstrap_cost + - evm_gas_config.deploy_cost_per_byte + * (2 * decoded_code_size.unwrap() as u64)) + / evm_gas_config.deploy_cost_per_evm_gas) + .into(), + ) + } + "call_function" => { + if near_gas < evm_gas_config.bootstrap_cost + evm_gas_config.funcall_cost_base { + return None; + } + Some( + ((near_gas - evm_gas_config.bootstrap_cost - evm_gas_config.funcall_cost_base) + / evm_gas_config.funcall_cost_per_evm_gas) + .into(), + ) + } + _ => { + if near_gas < evm_gas_config.bootstrap_cost { + return None; + } + Some(evm_gas_config.bootstrap_cost.into()) + } + } +} + pub fn run_evm( ext: &mut dyn External, chain_id: u128, @@ -437,6 +566,22 @@ pub fn run_evm( prepaid_gas: Gas, is_view: bool, ) -> (Option, Option) { + let evm_gas_result = max_evm_gas_from_near_gas( + prepaid_gas, + &fees_config.evm_config, + &method_name, + if &method_name == "deploy_code" { Some(args.len()) } else { None }, + ); + + if evm_gas_result.is_none() { + return ( + None, + Some(VMError::FunctionCallError(FunctionCallError::EvmError(EvmError::Revert( + "Not enough to run EVM".as_bytes().to_vec(), + )))), + ); + } + let evm_gas = evm_gas_result.unwrap(); let mut context = EvmContext::new( ext, chain_id, @@ -452,30 +597,50 @@ pub fn run_evm( storage_usage, prepaid_gas, is_view, + evm_gas, ); + let result = match method_name.as_str() { // Change the state methods. - "deploy_code" => context.deploy_code(args).map(|address| utils::address_to_vec(&address)), + "deploy_code" => context.deploy_code(args.clone()).map(|address| { + context.pay_gas_from_evm_gas(EvmOpForGas::Deploy(args.len())).unwrap(); + utils::address_to_vec(&address) + }), // TODO: remove this function name if no one is using it. - "call_function" => context.call_function(args), - "call" => context.call_function(args), - "meta_call" => context.meta_call_function(args), - "deposit" => context.deposit(args).map(|balance| utils::u256_to_arr(&balance).to_vec()), - "withdraw" => context.withdraw(args).map(|_| vec![]), - "transfer" => context.transfer(args).map(|_| vec![]), - "create" => context.create_evm(args).map(|_| vec![]), + "call_function" | "call" => { + let r = context.call_function(args.clone()); + context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); + r + } + "meta_call" => { + let r = context.meta_call_function(args.clone()); + context.pay_gas_from_evm_gas(EvmOpForGas::Other).unwrap(); + r + } + "deposit" => { + context.deposit(args.clone()).map(|balance| utils::u256_to_arr(&balance).to_vec()) + } + "withdraw" => context.withdraw(args.clone()).map(|_| vec![]), + "transfer" => context.transfer(args.clone()).map(|_| vec![]), + "create" => context.create_evm(args.clone()).map(|_| vec![]), // View methods. // TODO: remove this function name if no one is using it. - "view_function_call" => context.view_call_function(args), - "view" => context.view_call_function(args), - "get_code" => context.get_code(args), - "get_storage_at" => context.get_storage_at(args), - "get_nonce" => context.get_nonce(args).map(|nonce| utils::u256_to_arr(&nonce).to_vec()), + "view_function_call" | "view" => { + let r = context.view_call_function(args.clone()); + context.pay_gas_from_evm_gas(EvmOpForGas::Other).unwrap(); + r + } + "get_code" => context.get_code(args.clone()), + "get_storage_at" => context.get_storage_at(args.clone()), + "get_nonce" => { + context.get_nonce(args.clone()).map(|nonce| utils::u256_to_arr(&nonce).to_vec()) + } "get_balance" => { - context.get_balance(args).map(|balance| utils::u256_to_arr(&balance).to_vec()) + context.get_balance(args.clone()).map(|balance| utils::u256_to_arr(&balance).to_vec()) } _ => Err(VMLogicError::EvmError(EvmError::MethodNotFound)), }; + match result { Ok(value) => { let outcome = VMOutcome { @@ -531,6 +696,7 @@ mod tests { 0, 0, false, + 1_000_000_000.into(), ) } diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 144bd92cd06..409a6220330 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -3,16 +3,16 @@ use std::sync::Arc; use ethereum_types::{Address, H256, U256}; use evm::ActionParams; use keccak_hash::keccak; +use near_runtime_fees::EvmCostConfig; use parity_bytes::Bytes; use vm::{ CallType, ContractCreateResult, CreateContractAddress, EnvInfo, Error as VmError, MessageCallResult, Result as EvmResult, ReturnData, Schedule, TrapKind, }; -use near_vm_errors::{EvmError, VMLogicError}; - use crate::evm_state::{EvmState, SubState}; use crate::interpreter; + use crate::utils::format_log; // https://github.com/openethereum/openethereum/blob/77643c13e80ca09d9a6b10631034f5a1568ba6d3/ethcore/machine/src/externalities.rs @@ -25,6 +25,7 @@ pub struct NearExt<'a> { pub sub_state: &'a mut SubState<'a>, pub static_flag: bool, pub depth: usize, + pub evm_gas_config: &'a EvmCostConfig, } impl std::fmt::Debug for NearExt<'_> { @@ -46,6 +47,7 @@ impl<'a> NearExt<'a> { sub_state: &'a mut SubState<'a>, depth: usize, static_flag: bool, + evm_gas_config: &'a EvmCostConfig, ) -> Self { Self { info: Default::default(), @@ -56,6 +58,7 @@ impl<'a> NearExt<'a> { sub_state, static_flag, depth, + evm_gas_config, } } } @@ -125,7 +128,7 @@ impl<'a> vm::Ext for NearExt<'a> { fn create( &mut self, - _gas: &U256, + gas: &U256, value: &U256, code: &[u8], address_type: CreateContractAddress, @@ -136,7 +139,6 @@ impl<'a> vm::Ext for NearExt<'a> { } // TODO: better error propagation. - // TODO: gas metering. interpreter::deploy_code( self.sub_state, &self.origin, @@ -146,9 +148,9 @@ impl<'a> vm::Ext for NearExt<'a> { address_type, true, &code.to_vec(), + gas, + &self.evm_gas_config, ) - // TODO: gas usage. - .map(|result| ContractCreateResult::Created(result, 1_000_000_000.into())) .map_err(|_| TrapKind::Call(ActionParams::default())) } @@ -159,7 +161,7 @@ impl<'a> vm::Ext for NearExt<'a> { /// and true if subcall was successful. fn call( &mut self, - _gas: &U256, + gas: &U256, sender_address: &Address, receive_address: &Address, value: Option, @@ -174,7 +176,12 @@ impl<'a> vm::Ext for NearExt<'a> { // hijack builtins if crate::builtins::is_precompile(receive_address) { - return Ok(crate::builtins::process_precompile(receive_address, data)); + return Ok(crate::builtins::process_precompile( + receive_address, + data, + gas, + &self.evm_gas_config, + )); } let result = match call_type { @@ -191,6 +198,8 @@ impl<'a> vm::Ext for NearExt<'a> { receive_address, &data.to_vec(), true, // should_commit + gas, + &self.evm_gas_config, ), CallType::StaticCall => interpreter::static_call( self.sub_state, @@ -199,6 +208,8 @@ impl<'a> vm::Ext for NearExt<'a> { self.depth, receive_address, &data.to_vec(), + gas, + &self.evm_gas_config, ), CallType::CallCode => { // Call another contract using storage of the current contract. No longer used. @@ -212,29 +223,11 @@ impl<'a> vm::Ext for NearExt<'a> { receive_address, code_address, &data.to_vec(), + gas, + &self.evm_gas_config, ), }; - - let msg_call_result = match result { - // TODO: gas usage. - Ok(data) => MessageCallResult::Success(1_000_000_000.into(), data), - Err(err) => { - let message = match err { - VMLogicError::EvmError(EvmError::Revert(encoded_message)) => { - hex::decode(encoded_message).unwrap_or(vec![]) - } - // TODO(3455): Pass errors indirectly via state of the object. - _ => vec![], - }; - let message_len = message.len(); - // TODO: gas usage. - MessageCallResult::Reverted( - 1_000_000_000.into(), - ReturnData::new(message, 0, message_len), - ) - } - }; - Ok(msg_call_result) + result.map_err(|_| TrapKind::Call(ActionParams::default())) } /// Returns code at given address diff --git a/runtime/near-evm-runner/tests/build.sh b/runtime/near-evm-runner/tests/build.sh index 391db5242a6..f6245fa2712 100755 --- a/runtime/near-evm-runner/tests/build.sh +++ b/runtime/near-evm-runner/tests/build.sh @@ -6,6 +6,7 @@ contracts=( "Create2Factory" "SelfDestruct" "ConstructorRevert" + "PrecompiledFunction" ) truffle compile || exit 1 diff --git a/runtime/near-evm-runner/tests/build/BBronze.abi b/runtime/near-evm-runner/tests/build/BBronze.abi new file mode 100644 index 00000000000..ff6c870a05c --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BBronze.abi @@ -0,0 +1,17 @@ +[ + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/BBronze.bin b/runtime/near-evm-runner/tests/build/BBronze.bin new file mode 100644 index 00000000000..9bbf2865e61 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BBronze.bin @@ -0,0 +1 @@ +6080604052348015600f57600080fd5b5060ba8061001e6000396000f3fe6080604052348015600f57600080fd5b50600436106044577c010000000000000000000000000000000000000000000000000000000060003504639a86139b81146049575b600080fd5b604f6061565b60408051918252519081900360200190f35b7f42524f4e5a4500000000000000000000000000000000000000000000000000009056fea265627a7a72315820d02b5140da771a0eb87c9231627fadfdca36c5c04f502cc3fe1163438b04bda664736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/BColor.abi b/runtime/near-evm-runner/tests/build/BColor.abi new file mode 100644 index 00000000000..ff6c870a05c --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BColor.abi @@ -0,0 +1,17 @@ +[ + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/BConst.abi b/runtime/near-evm-runner/tests/build/BConst.abi new file mode 100644 index 00000000000..42a7386d836 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BConst.abi @@ -0,0 +1,257 @@ +[ + { + "constant": true, + "inputs": [], + "name": "BONE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "BPOW_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXIT_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "INIT_POOL_SUPPLY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_IN_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_OUT_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_TOTAL_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BALANCE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/BConst.bin b/runtime/near-evm-runner/tests/build/BConst.bin new file mode 100644 index 00000000000..df5ec05428b --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BConst.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061029c806100206000396000f3fe608060405234801561001057600080fd5b5060043610610108576000357c010000000000000000000000000000000000000000000000000000000090048063b0e0d136116100af578063b0e0d1361461015f578063b7b800a414610167578063ba019dab1461016f578063bc063e1a14610177578063bc694ea21461017f578063c36596a61461012f578063c6580d1214610187578063e4a28a521461010d578063ec0930211461018f57610108565b806309a3bbe41461010d578063189d00ca14610127578063218b53821461012f57806376c7a3c714610137578063867378c51461013f5780639381cd2b14610147578063992e2a921461014f5780639a86139b14610157575b600080fd5b610115610197565b60408051918252519081900360200190f35b6101156101a4565b6101156101b8565b6101156101c4565b6101156101d6565b6101156101ea565b6101156101f7565b610115610203565b610115610227565b61011561022c565b610115610231565b610115610236565b610115610246565b610115610252565b610115610257565b6802b5e3af16b188000081565b6402540be400670de0b6b3a76400005b0481565b670de0b6b3a764000081565b620f4240670de0b6b3a76400006101b4565b64e8d4a51000670de0b6b3a76400006101b4565b68056bc75e2d6310000081565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b600881565b600281565b600181565b600a670de0b6b3a76400006101b4565b671bc16d674ec7ffff81565b600081565b6002670de0b6b3a76400006101b456fea265627a7a72315820a3ed3e544d5a2480a4ca8e33cf23ff0c96b482b4cef52e564e7ba36b9ce3855064736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/BFactory.abi b/runtime/near-evm-runner/tests/build/BFactory.abi new file mode 100644 index 00000000000..2946beca8ae --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BFactory.abi @@ -0,0 +1,142 @@ +[ + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "blabs", + "type": "address" + } + ], + "name": "LOG_BLABS", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "LOG_NEW_POOL", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "b", + "type": "address" + } + ], + "name": "isBPool", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "newBPool", + "outputs": [ + { + "internalType": "contract BPool", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getBLabs", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "b", + "type": "address" + } + ], + "name": "setBLabs", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "contract BPool", + "name": "pool", + "type": "address" + } + ], + "name": "collect", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/BFactory.bin b/runtime/near-evm-runner/tests/build/BFactory.bin new file mode 100644 index 00000000000..c025ffa35ec --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BFactory.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5060018054600160a060020a03191633179055615fb1806100326000396000f3fe608060405234801561001057600080fd5b506004361061007e577c0100000000000000000000000000000000000000000000000000000000600035046306ec16f8811461008357806336ffb167146100ab5780639a86139b146100cf578063c2bb6dc2146100e9578063c6ce34fb14610123578063d556c5dc14610149575b600080fd5b6100a96004803603602081101561009957600080fd5b5035600160a060020a0316610151565b005b6100b361033e565b60408051600160a060020a039092168252519081900360200190f35b6100d761034d565b60408051918252519081900360200190f35b61010f600480360360208110156100ff57600080fd5b5035600160a060020a0316610371565b604080519115158252519081900360200190f35b6100a96004803603602081101561013957600080fd5b5035600160a060020a031661038f565b6100b3610456565b600154600160a060020a031633146101b3576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f4e4f545f424c41425300000000000000000000000000000000000000604482015290519081900360640190fd5b604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051600091600160a060020a038416916370a0823191602480820192602092909190829003018186803b15801561021657600080fd5b505afa15801561022a573d6000803e3d6000fd5b505050506040513d602081101561024057600080fd5b5051600154604080517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810184905290519293506000929185169163a9059cbb9160448082019260209290919082900301818787803b1580156102b657600080fd5b505af11580156102ca573d6000803e3d6000fd5b505050506040513d60208110156102e057600080fd5b5051905080610339576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f45524332305f4641494c454400000000000000000000000000000000604482015290519081900360640190fd5b505050565b600154600160a060020a031690565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b600160a060020a031660009081526020819052604090205460ff1690565b600154600160a060020a031633146103f1576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f4e4f545f424c41425300000000000000000000000000000000000000604482015290519081900360640190fd5b604051600160a060020a0382169033907ff586fa6ee1fc42f5b727f3b214ccbd0b6d7e698c45d49ba32f224fbb8670155d90600090a36001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b6000806040516104659061054f565b604051809103906000f080158015610481573d6000803e3d6000fd5b50600160a060020a038116600081815260208190526040808220805460ff1916600117905551929350909133917f8ccec77b0cb63ac2cafd0f5de8cdfadab91ce656d262240ba8a6343bccc5f94591a3604080517f92eefe9b0000000000000000000000000000000000000000000000000000000081523360048201529051600160a060020a038316916392eefe9b91602480830192600092919082900301818387803b15801561053157600080fd5b505af1158015610545573d6000803e3d6000fd5b5092935050505090565b615a208061055d8339019056fe60c0604052601360808190527f42616c616e63657220506f6f6c20546f6b656e0000000000000000000000000060a0908152620000409160039190620000f7565b506040805180820190915260038082527f425054000000000000000000000000000000000000000000000000000000000060209092019182526200008791600491620000f7565b506005805460ff19166012179055348015620000a257600080fd5b5060068054600580546201000060b060020a031916336201000081029190911790915564e8d4a51000600755600160a060020a03199091161760a060020a60ff02191690556008805460ff191690556200019c565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200013a57805160ff19168380011785556200016a565b828001600101855582156200016a579182015b828111156200016a5782518255916020019190600101906200014d565b50620001789291506200017c565b5090565b6200019991905b8082111562000178576000815560010162000183565b90565b61587480620001ac6000396000f3fe608060405234801561001057600080fd5b5060043610610378576000357c0100000000000000000000000000000000000000000000000000000000900480638d4e4083116101e7578063bc694ea211610122578063d73dd623116100c5578063d73dd62314610b7f578063dd62ed3e14610bab578063e4a28a521461047e578063e4e1e53814610bd9578063ec09302114610c0b578063f1b8a9b714610c13578063f8b2cb4f14610c39578063f8d6aed414610c5f578063fde924f714610c9a57610378565b8063bc694ea214610ad9578063be3bbd2e14610ae1578063c36596a6146104f2578063c6580d1214610b39578063cc77828d14610b41578063cd2ed8fb14610b49578063cf5e7bd314610b51578063d4cadf6814610b7757610378565b8063a221ee491161018a578063a221ee49146109a6578063a9059cbb146109db578063b02f0b7314610a07578063b0e0d13614610a7e578063b7b800a414610a86578063ba019dab14610a8e578063ba9530a614610a96578063bc063e1a14610ad157610378565b80638d4e40831461092a57806392eefe9b14610932578063936c3477146109585780639381cd2b14610960578063948d8ce61461096857806395d89b411461098e578063992e2a92146109965780639a86139b1461099e57610378565b806349b59552116102b757806376c7a3c71161025a57806376c7a3c7146107aa5780637c5e9ea4146107b25780638201aa3f1461080b57806382f652ad1461084b5780638656b65314610886578063867378c5146108c157806389298012146108c95780638c28cbe81461090457610378565b806349b595521461061b5780634bb278f31461063a5780634f69c0d4146106425780635c1bbaf7146106b95780635db34277146106f457806366188463146107265780636d06dfa01461075257806370a082311461078457610378565b8063218b53821161031f578063218b5382146104f257806323b872dd146104fa5780632f37b624146105305780633018205f14610556578063313ce5671461057a57806334e19907146105985780633fdddaa2146105b757806346ab38f1146105e957610378565b806302c967481461037d57806306fdde03146103c1578063095ea7b31461043e57806309a3bbe41461047e5780631446a7ff1461048657806315e84af9146104b457806318160ddd146104e2578063189d00ca146104ea575b600080fd5b6103af6004803603606081101561039357600080fd5b50600160a060020a038135169060208101359060400135610ca2565b60408051918252519081900360200190f35b6103c9610fef565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104035781810151838201526020016103eb565b50505050905090810190601f1680156104305780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61046a6004803603604081101561045457600080fd5b50600160a060020a038135169060200135611085565b604080519115158252519081900360200190f35b6103af6110da565b6103af6004803603604081101561049c57600080fd5b50600160a060020a03813581169160200135166110e7565b6103af600480360360408110156104ca57600080fd5b50600160a060020a0381358116916020013516611241565b6103af611392565b6103af611398565b6103af6113ac565b61046a6004803603606081101561051057600080fd5b50600160a060020a038135811691602081013590911690604001356113b8565b61046a6004803603602081101561054657600080fd5b5035600160a060020a031661151d565b61055e61153b565b60408051600160a060020a039092168252519081900360200190f35b61058261159c565b6040805160ff9092168252519081900360200190f35b6105b5600480360360208110156105ae57600080fd5b50356115a5565b005b6105b5600480360360608110156105cd57600080fd5b50600160a060020a0381351690602081013590604001356117c9565b6103af600480360360608110156105ff57600080fd5b50600160a060020a038135169060208101359060400135611c15565b6105b56004803603602081101561063157600080fd5b50351515611f01565b6105b5612092565b6105b56004803603604081101561065857600080fd5b8135919081019060408101602082013564010000000081111561067a57600080fd5b82018360208201111561068c57600080fd5b803590602001918460208302840111640100000000831117156106ae57600080fd5b5090925090506122a9565b6103af600480360360c08110156106cf57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135612590565b6103af6004803603606081101561070a57600080fd5b50600160a060020a038135169060208101359060400135612648565b61046a6004803603604081101561073c57600080fd5b50600160a060020a038135169060200135612919565b6103af6004803603606081101561076857600080fd5b50600160a060020a0381351690602081013590604001356129f1565b6103af6004803603602081101561079a57600080fd5b5035600160a060020a0316612cf0565b6103af612d0b565b6107f2600480360360a08110156107c857600080fd5b50600160a060020a0381358116916020810135916040820135169060608101359060800135612d1d565b6040805192835260208301919091528051918290030190f35b6107f2600480360360a081101561082157600080fd5b50600160a060020a038135811691602081013591604082013516906060810135906080013561320d565b6103af600480360360c081101561086157600080fd5b5080359060208101359060408101359060608101359060808101359060a001356136e4565b6103af600480360360c081101561089c57600080fd5b5080359060208101359060408101359060608101359060808101359060a001356137a3565b6103af613844565b6103af600480360360c08110156108df57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135613858565b6105b56004803603602081101561091a57600080fd5b5035600160a060020a0316613908565b61046a613ad9565b6105b56004803603602081101561094857600080fd5b5035600160a060020a0316613ae2565b6103af613c2c565b6103af613c84565b6103af6004803603602081101561097e57600080fd5b5035600160a060020a0316613c91565b6103c9613d5f565b6103af613dc0565b6103af613dcc565b6103af600480360360a08110156109bc57600080fd5b5080359060208101359060408101359060608101359060800135613df0565b61046a600480360360408110156109f157600080fd5b50600160a060020a038135169060200135613e55565b6105b560048036036040811015610a1d57600080fd5b81359190810190604081016020820135640100000000811115610a3f57600080fd5b820183602082011115610a5157600080fd5b80359060200191846020830284011164010000000083111715610a7357600080fd5b509092509050613e6b565b6103af61419f565b6103af6141a4565b6103af6141a9565b6103af600480360360c0811015610aac57600080fd5b5080359060208101359060408101359060608101359060808101359060a001356141ae565b6103af61422f565b6103af61423f565b610ae961424b565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610b25578181015183820152602001610b0d565b505050509050019250505060405180910390f35b6103af614343565b610ae9614348565b6103af614399565b6105b560048036036020811015610b6757600080fd5b5035600160a060020a031661439f565b6103af61472c565b61046a60048036036040811015610b9557600080fd5b50600160a060020a038135169060200135614784565b6103af60048036036040811015610bc157600080fd5b50600160a060020a0381358116916020013516614805565b6105b560048036036060811015610bef57600080fd5b50600160a060020a038135169060208101359060400135614830565b6103af614ab4565b6103af60048036036020811015610c2957600080fd5b5035600160a060020a0316614ac4565b6103af60048036036020811015610c4f57600080fd5b5035600160a060020a0316614ba4565b6103af600480360360c0811015610c7557600080fd5b5080359060208101359060408101359060608101359060808101359060a00135614c72565b61046a614cf5565b600033600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615610d53576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16610daa576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a602052604090205460ff16610e08576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a60205260409020600390810154610e3d91670de0b6b3a76400005b04600101614d05565b831115610e82576040805160e560020a62461bcd02815260206004820152601160248201526000805160206156e0833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a6020526040902060038101546002808301549054600b54600754610ebc949392919089906136e4565b915081610f01576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b82821115610f47576040805160e560020a62461bcd02815260206004820152600c60248201526000805160206156c0833981519152604482015290519081900360640190fd5b610f55816003015485614dee565b60038201556000610f668382614d05565b604080518781529051919250600160a060020a0388169133916000805160206157a0833981519152919081900360200190a3610fa23384614e5f565b610fb4610faf8483614dee565b614e6d565b600554610fd090620100009004600160a060020a031682614e79565b610fdb863387614e83565b50506005805461ff00191690559392505050565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561107b5780601f106110505761010080835404028352916020019161107b565b820191906000526020600020905b81548152906001019060200180831161105e57829003601f168201915b5050505050905090565b336000818152600160209081526040808320600160a060020a038716808552908352818420869055815186815291519394909390926000805160206157c0833981519152928290030190a35060015b92915050565b6802b5e3af16b188000081565b600554600090610100900460ff1615611138576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090205460ff16611196576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a602052604090205460ff166111f4576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a038084166000908152600a602052604080822092851682528120600380840154600280860154928401549084015493946112389492939290613df0565b95945050505050565b600554600090610100900460ff1615611292576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090205460ff166112f0576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a602052604090205460ff1661134e576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a038084166000908152600a602052604080822092851682529020600380830154600280850154928401549084015460075461123894929190613df0565b60025490565b6402540be400670de0b6b3a76400005b0481565b670de0b6b3a764000081565b600033600160a060020a03851614806113f45750600160a060020a03841660009081526001602090815260408083203384529091529020548211155b611448576040805160e560020a62461bcd02815260206004820152601560248201527f4552525f42544f4b454e5f4241445f43414c4c45520000000000000000000000604482015290519081900360640190fd5b611453848484614f78565b33600160a060020a038516148015906114915750600160a060020a038416600090815260016020908152604080832033845290915290205460001914155b1561151357600160a060020a03841660009081526001602090815260408083203384529091529020546114c49083614dee565b600160a060020a03858116600090815260016020908152604080832033808552908352928190208590558051948552519287169391926000805160206157c08339815191529281900390910190a35b5060019392505050565b600160a060020a03166000908152600a602052604090205460ff1690565b600554600090610100900460ff161561158c576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b50600654600160a060020a031690565b60055460ff1690565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615611654576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16156116ac576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b600654600160a060020a031633146116fc576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b64e8d4a51000811015611759576040805160e560020a62461bcd02815260206004820152600b60248201527f4552525f4d494e5f464545000000000000000000000000000000000000000000604482015290519081900360640190fd5b67016345785d8a00008111156117b9576040805160e560020a62461bcd02815260206004820152600b60248201527f4552525f4d41585f464545000000000000000000000000000000000000000000604482015290519081900360640190fd5b6007556005805461ff0019169055565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615611878576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560065433600160a060020a03909116146118d9576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090205460ff16611937576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b60085460ff1615611980576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b670de0b6b3a76400008110156119e0576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f4d494e5f574549474854000000000000000000000000000000000000604482015290519081900360640190fd5b6802b5e3af16b1880000811115611a41576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f4d41585f574549474854000000000000000000000000000000000000604482015290519081900360640190fd5b620f4240821015611a9c576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f4d494e5f42414c414e43450000000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090206002015480821115611b3f57611ad5600b54611ad08484614dee565b615082565b600b8190556802b5e3af16b18800001015611b3a576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f4d41585f544f54414c5f574549474854000000000000000000000000604482015290519081900360640190fd5b611b60565b80821015611b6057611b5c600b54611b578385614dee565b614dee565b600b555b600160a060020a0384166000908152600a602052604090206002810183905560030180549084905580841115611ba957611ba48533611b9f8785614dee565b6150df565b611c03565b80841015611c03576000611bbd8286614dee565b90506000611bcc826000614d05565b9050611be28733611bdd8585614dee565b614e83565b600554611c00908890620100009004600160a060020a031683614e83565b50505b50506005805461ff0019169055505050565b600033600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615611cc6576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16611d1d576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a602052604090205460ff16611d7b576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a6020526040902060038101546002808301549054600b54600754611db594939291908990613858565b915082821015611dfd576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615800833981519152604482015290519081900360640190fd5b600160a060020a0385166000908152600a60205260409020600390810154611e2d91670de0b6b3a7640000610e34565b821115611e72576040805160e560020a62461bcd02815260206004820152601160248201526000805160206156e0833981519152604482015290519081900360640190fd5b611e80816003015483614dee565b60038201556000611e918582614d05565b604080518581529051919250600160a060020a0388169133916000805160206157a0833981519152919081900360200190a3611ecd3386614e5f565b611eda610faf8683614dee565b600554611ef690620100009004600160a060020a031682614e79565b610fdb863385614e83565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615611fb0576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff1615612008576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b600654600160a060020a03163314612058576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b6006805491151560a060020a0274ff0000000000000000000000000000000000000000199092169190911790556005805461ff0019169055565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615612141576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560065433600160a060020a03909116146121a2576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b60085460ff16156121eb576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b60095460021115612246576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f4d494e5f544f4b454e53000000000000000000000000000000000000604482015290519081900360640190fd5b6008805460ff191660011790556006805474ff0000000000000000000000000000000000000000191660a060020a17905561228968056bc75e2d63100000615151565b61229c3368056bc75e2d63100000614e79565b6005805461ff0019169055565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615612358576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff166123af576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b60006123b9611392565b905060006123c7858361515a565b90508061240c576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b60005b60095481101561257c5760006009828154811061242857fe5b6000918252602080832090910154600160a060020a0316808352600a90915260408220600301549092509061245d8583614d05565b9050806124a2576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b8787858181106124ae57fe5b905060200201358111156124fa576040805160e560020a62461bcd02815260206004820152600c60248201526000805160206156c0833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a60205260409020600301546125209082615082565b600160a060020a0384166000818152600a60209081526040918290206003019390935580518481529051919233926000805160206157008339815191529281900390910190a36125718333836150df565b50505060010161240f565b5061258685615151565b611c033386614e79565b60008061259d878661515a565b905060006125ab8786615082565b905060006125b9828961515a565b905060006125cf670de0b6b3a76400008561515a565b905060006125dd8383615296565b905060006125eb828e614d05565b905060006125f9828f614dee565b90506000612618612612670de0b6b3a76400008a614dee565b8b614d05565b905061263582612630670de0b6b3a764000084614dee565b61515a565b9f9e505050505050505050505050505050565b600033600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff16156126f9576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16612750576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a602052604090205460ff166127ae576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a60205260409020600301546127e0906002670de0b6b3a76400005b04614d05565b831115612825576040805160e560020a62461bcd0281526020600482015260106024820152600080516020615740833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a6020526040902060038101546002808301549054600b5460075461285f949392919089906137a3565b9150828210156128a7576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615800833981519152604482015290519081900360640190fd5b6128b5816003015485615082565b6003820155604080518581529051600160a060020a0387169133916000805160206157008339815191529181900360200190a36128f182615151565b6128fb3383614e79565b6129068533866150df565b506005805461ff00191690559392505050565b336000908152600160209081526040808320600160a060020a03861684529091528120548083111561296e57336000908152600160209081526040808320600160a060020a038816845290915281205561299d565b6129788184614dee565b336000908152600160209081526040808320600160a060020a03891684529091529020555b336000818152600160209081526040808320600160a060020a0389168085529083529281902054815190815290519293926000805160206157c0833981519152929181900390910190a35060019392505050565b600033600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615612aa2576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16612af9576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a602052604090205460ff16612b57576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a6020526040902060038101546002808301549054600b54600754612b9194939291908990612590565b915081612bd6576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b82821115612c1c576040805160e560020a62461bcd02815260206004820152600c60248201526000805160206156c0833981519152604482015290519081900360640190fd5b600160a060020a0385166000908152600a6020526040902060030154612c4c906002670de0b6b3a76400006127da565b821115612c91576040805160e560020a62461bcd0281526020600482015260106024820152600080516020615740833981519152604482015290519081900360640190fd5b612c9f816003015483615082565b6003820155604080518381529051600160a060020a0387169133916000805160206157008339815191529181900360200190a3612cdb84615151565b612ce53385614e79565b6129068533846150df565b600160a060020a031660009081526020819052604090205490565b620f4240670de0b6b3a76400006113a8565b6040805160208082523690820181905260009283923392600160e060020a03198535169285929081908101848480828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615612dbd576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff001916610100179055600160a060020a0387166000908152600a602052604090205460ff16612e2a576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0385166000908152600a602052604090205460ff16612e88576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b60065460a060020a900460ff16612ee9576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f535741505f4e4f545f5055424c494300000000000000000000000000604482015290519081900360640190fd5b600160a060020a038088166000908152600a602052604080822092881682529020600380820154612f2291670de0b6b3a7640000610e34565b861115612f67576040805160e560020a62461bcd02815260206004820152601160248201526000805160206156e0833981519152604482015290519081900360640190fd5b6000612f888360030154846002015484600301548560020154600754613df0565b905085811115612fe2576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f4241445f4c494d49545f505249434500000000000000000000000000604482015290519081900360640190fd5b61300283600301548460020154846003015485600201548b600754614c72565b94508885111561304a576040805160e560020a62461bcd02815260206004820152600c60248201526000805160206156c0833981519152604482015290519081900360640190fd5b613058836003015486615082565b836003018190555061306e826003015488614dee565b600380840182905584015460028086015490850154600754613091949190613df0565b9350808410156130d9576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b85841115613131576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f4c494d49545f50524943450000000000000000000000000000000000604482015290519081900360640190fd5b61313b858861515a565b811115613180576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b87600160a060020a03168a600160a060020a031633600160a060020a03167f908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378888b604051808381526020018281526020019250505060405180910390a46131e88a33876150df565b6131f3883389614e83565b5050506005805461ff001916905590969095509350505050565b6040805160208082523690820181905260009283923392600160e060020a03198535169285929081908101848480828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff16156132ad576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff001916610100179055600160a060020a0387166000908152600a602052604090205460ff1661331a576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0385166000908152600a602052604090205460ff16613378576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b60065460a060020a900460ff166133d9576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f535741505f4e4f545f5055424c494300000000000000000000000000604482015290519081900360640190fd5b600160a060020a038088166000908152600a6020526040808220928816825290206003820154613413906002670de0b6b3a76400006127da565b881115613458576040805160e560020a62461bcd0281526020600482015260106024820152600080516020615740833981519152604482015290519081900360640190fd5b60006134798360030154846002015484600301548560020154600754613df0565b9050858111156134d3576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f4241445f4c494d49545f505249434500000000000000000000000000604482015290519081900360640190fd5b6134f383600301548460020154846003015485600201548d6007546141ae565b94508685101561353b576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615800833981519152604482015290519081900360640190fd5b61354983600301548a615082565b836003018190555061355f826003015486614dee565b600380840182905584015460028086015490850154600754613582949190613df0565b9350808410156135ca576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b85841115613622576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f4c494d49545f50524943450000000000000000000000000000000000604482015290519081900360640190fd5b61362c898661515a565b811115613671576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b87600160a060020a03168a600160a060020a031633600160a060020a03167f908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d433788c89604051808381526020018281526020019250505060405180910390a46136d98a338b6150df565b6131f3883387614e83565b6000806136f1878661515a565b90506000613707670de0b6b3a764000083614dee565b905060006137158286614d05565b9050600061372f87612630670de0b6b3a764000085614dee565b9050600061373d8c83614dee565b9050600061374b828e61515a565b905060006137598288615296565b90506000613767828e614d05565b905060006137758e83614dee565b905061378e81612630670de0b6b3a76400006000614dee565b99505050505050505050509695505050505050565b6000806137b0878661515a565b905060006137cf6137c9670de0b6b3a764000084614dee565b85614d05565b905060006137ee866137e9670de0b6b3a764000085614dee565b614d05565b905060006137fc8b83615082565b9050600061380a828d61515a565b905060006138188287615296565b90506000613826828d614d05565b9050613832818d614dee565b9e9d5050505050505050505050505050565b64e8d4a51000670de0b6b3a76400006113a8565b600080613865878661515a565b90506000613880856137e9670de0b6b3a76400006000614dee565b9050600061388e8883614dee565b9050600061389c828a61515a565b905060006138bb826138b6670de0b6b3a76400008861515a565b615296565b905060006138c9828e614d05565b905060006138d78e83614dee565b905060006138f0612612670de0b6b3a76400008a614dee565b9050612635826137e9670de0b6b3a764000084614dee565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff16156139b7576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff001916610100179055600160a060020a0381166000908152600a602052604090205460ff16613a24576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051600160a060020a038316916370a08231916024808301926020929190829003018186803b158015613a8357600080fd5b505afa158015613a97573d6000803e3d6000fd5b505050506040513d6020811015613aad57600080fd5b5051600160a060020a039091166000908152600a60205260409020600301556005805461ff0019169055565b60085460ff1690565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615613b91576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560065433600160a060020a0390911614613bf2576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03929092169190911790556005805461ff0019169055565b600554600090610100900460ff1615613c7d576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b50600b5490565b68056bc75e2d6310000081565b600554600090610100900460ff1615613ce2576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a602052604090205460ff16613d40576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b50600160a060020a03166000908152600a602052604090206002015490565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561107b5780601f106110505761010080835404028352916020019161107b565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b600080613dfd878761515a565b90506000613e0b868661515a565b90506000613e19838361515a565b90506000613e3b670de0b6b3a7640000612630670de0b6b3a764000089614dee565b9050613e478282614d05565b9a9950505050505050505050565b6000613e62338484614f78565b50600192915050565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615613f1a576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16613f71576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b6000613f7b611392565b90506000613f8a856000614d05565b90506000613f988683614dee565b90506000613fa6828561515a565b905080613feb576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b613ff53388614e5f565b60055461401190620100009004600160a060020a031684614e79565b61401a82614e6d565b60005b60095481101561418a5760006009828154811061403657fe5b6000918252602080832090910154600160a060020a0316808352600a90915260408220600301549092509061406b8583614d05565b9050806140b0576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b8989858181106140bc57fe5b90506020020135811015614108576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615800833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090206003015461412e9082614dee565b600160a060020a0384166000818152600a60209081526040918290206003019390935580518481529051919233926000805160206157a08339815191529281900390910190a361417f833383614e83565b50505060010161401d565b50506005805461ff0019169055505050505050565b600881565b600281565b600181565b6000806141bb878661515a565b905060006141d1670de0b6b3a764000085614dee565b90506141dd8582614d05565b905060006141ef8a6126308c85615082565b905060006141fd8285615296565b90506000614213670de0b6b3a764000083614dee565b905061421f8a82614d05565b9c9b505050505050505050505050565b600a670de0b6b3a76400006113a8565b671bc16d674ec7ffff81565b600554606090610100900460ff161561429c576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b60085460ff166142e4576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b600980548060200260200160405190810160405280929190818152602001828054801561107b57602002820191906000526020600020905b8154600160a060020a0316815260019091019060200180831161431c575050505050905090565b600081565b600554606090610100900460ff16156142e4576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b60095490565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff161561444e576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560065433600160a060020a03909116146144af576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b600160a060020a0381166000908152600a602052604090205460ff1661450d576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b60085460ff1615614556576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b600160a060020a0381166000908152600a60205260408120600301549061457d8282614d05565b600b54600160a060020a0385166000908152600a60205260409020600201549192506145a891614dee565b600b55600160a060020a0383166000908152600a60205260409020600101546009805460001981019190829081106145dc57fe5b60009182526020909120015460098054600160a060020a03909216918490811061460257fe5b9060005260206000200160006101000a815481600160a060020a030219169083600160a060020a0316021790555081600a60006009858154811061464257fe5b6000918252602080832090910154600160a060020a03168352820192909252604001902060010155600980548061467557fe5b600082815260208082206000199084018101805473ffffffffffffffffffffffffffffffffffffffff191690559092019092556040805160808101825283815280830184815281830185815260608301868152600160a060020a038c168752600a909552929094209051815460ff1916901515178155925160018401555160028301555160039091015561470e8533611bdd8787614dee565b600554611c03908690620100009004600160a060020a031685614e83565b600554600090610100900460ff161561477d576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b5060075490565b336000908152600160209081526040808320600160a060020a03861684529091528120546147b29083615082565b336000818152600160209081526040808320600160a060020a0389168085529083529281902085905580519485525191936000805160206157c0833981519152929081900390910190a350600192915050565b600160a060020a03918216600090815260016020908152604080832093909416825291909152205490565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600654600160a060020a031633146148e1576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090205460ff1615614952576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f49535f424f554e440000000000000000000000000000000000000000604482015290519081900360640190fd5b60085460ff161561499b576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b6009546008116149f5576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f4d41585f544f4b454e53000000000000000000000000000000000000604482015290519081900360640190fd5b604080516080810182526001808252600980546020808501918252600085870181815260608701828152600160a060020a038c16808452600a9094529782209651875460ff1916901515178755925186860155915160028601559451600390940193909355805491820181559091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af01805473ffffffffffffffffffffffffffffffffffffffff19169091179055614aaf8383836117c9565b505050565b6002670de0b6b3a76400006113a8565b600554600090610100900460ff1615614b15576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a602052604090205460ff16614b73576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a6020526040902060020154600b54614b9d90829061515a565b9392505050565b600554600090610100900460ff1615614bf5576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a602052604090205460ff16614c53576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b50600160a060020a03166000908152600a602052604090206003015490565b600080614c7f858861515a565b90506000614c8d8786614dee565b90506000614c9b888361515a565b90506000614ca98285615296565b9050614cbd81670de0b6b3a7640000614dee565b9050614cd1670de0b6b3a764000087614dee565b9450614ce6614ce08c83614d05565b8661515a565b9b9a5050505050505050505050565b60065460a060020a900460ff1690565b6000828202831580614d1f575082848281614d1c57fe5b04145b614d73576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6706f05b59d3b20000810181811015614dd6576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6000670de0b6b3a7640000825b049695505050505050565b6000806000614dfd85856153b9565b915091508015614e57576040805160e560020a62461bcd02815260206004820152601160248201527f4552525f5355425f554e444552464c4f57000000000000000000000000000000604482015290519081900360640190fd5b509392505050565b614e6982826153de565b5050565b614e76816153e9565b50565b614e6982826154b3565b604080517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a03848116600483015260248201849052915160009286169163a9059cbb91604480830192602092919082900301818787803b158015614eef57600080fd5b505af1158015614f03573d6000803e3d6000fd5b505050506040513d6020811015614f1957600080fd5b5051905080614f72576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f45524332305f46414c53450000000000000000000000000000000000604482015290519081900360640190fd5b50505050565b600160a060020a038316600090815260208190526040902054811115614fe8576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e53554646494349454e545f42414c000000000000000000000000604482015290519081900360640190fd5b600160a060020a03831660009081526020819052604090205461500b9082614dee565b600160a060020a03808516600090815260208190526040808220939093559084168152205461503a9082615082565b600160a060020a0380841660008181526020818152604091829020949094558051858152905191939287169260008051602061576083398151915292918290030190a3505050565b600082820183811015614b9d576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4144445f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b604080517f23b872dd000000000000000000000000000000000000000000000000000000008152600160a060020a0384811660048301523060248301526044820184905291516000928616916323b872dd91606480830192602092919082900301818787803b158015614eef57600080fd5b614e76816154be565b6000816151b1576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4449565f5a45524f0000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a764000083028315806151d95750670de0b6b3a76400008482816151d657fe5b04145b61522d576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b6002830481018181101561528b576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b6000848281614de357fe5b600060018310156152f1576040805160e560020a62461bcd02815260206004820152601560248201527f4552525f42504f575f424153455f544f4f5f4c4f570000000000000000000000604482015290519081900360640190fd5b671bc16d674ec7ffff831115615351576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f42504f575f424153455f544f4f5f4849474800000000000000000000604482015290519081900360640190fd5b600061535c83615521565b9050600061536a8483614dee565b905060006153808661537b8561553c565b61554a565b9050816153915792506110d4915050565b60006153a287846305f5e1006155a1565b90506153ae8282614d05565b979650505050505050565b6000808284106153cf57505080820360006153d7565b505081810360015b9250929050565b614e69823083614f78565b30600090815260208190526040902054811115615450576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e53554646494349454e545f42414c000000000000000000000000604482015290519081900360640190fd5b3060009081526020819052604090205461546a9082614dee565b306000908152602081905260409020556002546154879082614dee565b60025560408051828152905160009130916000805160206157608339815191529181900360200190a350565b614e69308383614f78565b306000908152602081905260409020546154d89082615082565b306000908152602081905260409020556002546154f59082615082565b60025560408051828152905130916000916000805160206157608339815191529181900360200190a350565b6000670de0b6b3a76400006155358361553c565b0292915050565b670de0b6b3a7640000900490565b6000806002830661556357670de0b6b3a7640000615565565b835b90506002830492505b8215614b9d5761557e8485614d05565b93506002830615615596576155938185614d05565b90505b60028304925061556e565b60008281806155b887670de0b6b3a76400006153b9565b9092509050670de0b6b3a764000080600060015b888410615670576000670de0b6b3a7640000820290506000806156008a6155fb85670de0b6b3a7640000614dee565b6153b9565b91509150615612876137e9848c614d05565b965061561e878461515a565b96508661562d57505050615670565b8715615637579315935b8015615641579315935b8415615658576156518688614dee565b9550615665565b6156628688615082565b95505b5050506001016155cc565b5090999850505050505050505056fe4552525f4e4f545f46494e414c495a45440000000000000000000000000000004552525f5245454e5452590000000000000000000000000000000000000000004552525f4c494d49545f494e00000000000000000000000000000000000000004552525f4d41585f4f55545f524154494f00000000000000000000000000000063982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a4552525f4e4f545f434f4e54524f4c4c455200000000000000000000000000004552525f4d41585f494e5f524154494f00000000000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef4552525f4e4f545f424f554e4400000000000000000000000000000000000000e74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9254552525f49535f46494e414c495a4544000000000000000000000000000000004552525f4c494d49545f4f5554000000000000000000000000000000000000004552525f4d4154485f415050524f580000000000000000000000000000000000a265627a7a72315820a6ed20be58469dda7b96f5cd85dbd70406a753a02b645704241ab59bf33344fe64736f6c634300050c0032a265627a7a723158201fb7c2c80fbc145fbafa4fbc21af09d0d3faf8acf13673c5517de0883d91e5f564736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/BMath.abi b/runtime/near-evm-runner/tests/build/BMath.abi new file mode 100644 index 00000000000..6df234eb16b --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BMath.abi @@ -0,0 +1,574 @@ +[ + { + "constant": true, + "inputs": [], + "name": "BONE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "BPOW_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXIT_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "INIT_POOL_SUPPLY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_IN_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_OUT_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_TOTAL_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BALANCE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcSpotPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "spotPrice", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcOutGivenIn", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcInGivenOut", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcPoolOutGivenSingleIn", + "outputs": [ + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcSingleInGivenPoolOut", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcSingleOutGivenPoolIn", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcPoolInGivenSingleOut", + "outputs": [ + { + "internalType": "uint256", + "name": "poolAmountIn", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/BMath.bin b/runtime/near-evm-runner/tests/build/BMath.bin new file mode 100644 index 00000000000..73ade7f2077 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BMath.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50610e77806100206000396000f3fe608060405234801561001057600080fd5b5060043610610175576000357c010000000000000000000000000000000000000000000000000000000090048063a221ee49116100e0578063bc694ea211610099578063bc694ea214610348578063c36596a61461019c578063c6580d1214610350578063e4a28a521461017a578063ec09302114610358578063f8d6aed41461036057610175565b8063a221ee49146102b8578063b0e0d136146102ed578063b7b800a4146102f5578063ba019dab146102fd578063ba9530a614610305578063bc063e1a1461034057610175565b80638656b653116101325780638656b65314610222578063867378c51461025d57806389298012146102655780639381cd2b146102a0578063992e2a92146102a85780639a86139b146102b057610175565b806309a3bbe41461017a578063189d00ca14610194578063218b53821461019c5780635c1bbaf7146101a457806376c7a3c7146101df57806382f652ad146101e7575b600080fd5b61018261039b565b60408051918252519081900360200190f35b6101826103a8565b6101826103bc565b610182600480360360c08110156101ba57600080fd5b5080359060208101359060408101359060608101359060808101359060a001356103c8565b610182610480565b610182600480360360c08110156101fd57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610492565b610182600480360360c081101561023857600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610551565b6101826105f2565b610182600480360360c081101561027b57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610606565b6101826106b6565b6101826106c3565b6101826106cf565b610182600480360360a08110156102ce57600080fd5b50803590602081013590604081013590606081013590608001356106f3565b610182610758565b61018261075d565b610182610762565b610182600480360360c081101561031b57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610767565b6101826107e8565b6101826107f8565b610182610804565b610182610809565b610182600480360360c081101561037657600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610819565b6802b5e3af16b188000081565b6402540be400670de0b6b3a76400005b0481565b670de0b6b3a764000081565b6000806103d5878661089c565b905060006103e387866109e5565b905060006103f1828961089c565b90506000610407670de0b6b3a76400008561089c565b905060006104158383610a49565b90506000610423828e610b6c565b90506000610431828f610c4e565b9050600061045061044a670de0b6b3a76400008a610c4e565b8b610b6c565b905061046d82610468670de0b6b3a764000084610c4e565b61089c565b9f9e505050505050505050505050505050565b620f4240670de0b6b3a76400006103b8565b60008061049f878661089c565b905060006104b5670de0b6b3a764000083610c4e565b905060006104c38286610b6c565b905060006104dd87610468670de0b6b3a764000085610c4e565b905060006104eb8c83610c4e565b905060006104f9828e61089c565b905060006105078288610a49565b90506000610515828e610b6c565b905060006105238e83610c4e565b905061053c81610468670de0b6b3a76400006000610c4e565b99505050505050505050509695505050505050565b60008061055e878661089c565b9050600061057d610577670de0b6b3a764000084610c4e565b85610b6c565b9050600061059c86610597670de0b6b3a764000085610c4e565b610b6c565b905060006105aa8b836109e5565b905060006105b8828d61089c565b905060006105c68287610a49565b905060006105d4828d610b6c565b90506105e0818d610c4e565b9e9d5050505050505050505050505050565b64e8d4a51000670de0b6b3a76400006103b8565b600080610613878661089c565b9050600061062e85610597670de0b6b3a76400006000610c4e565b9050600061063c8883610c4e565b9050600061064a828a61089c565b9050600061066982610664670de0b6b3a76400008861089c565b610a49565b90506000610677828e610b6c565b905060006106858e83610c4e565b9050600061069e61044a670de0b6b3a76400008a610c4e565b905061046d82610597670de0b6b3a764000084610c4e565b68056bc75e2d6310000081565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b600080610700878761089c565b9050600061070e868661089c565b9050600061071c838361089c565b9050600061073e670de0b6b3a7640000610468670de0b6b3a764000089610c4e565b905061074a8282610b6c565b9a9950505050505050505050565b600881565b600281565b600181565b600080610774878661089c565b9050600061078a670de0b6b3a764000085610c4e565b90506107968582610b6c565b905060006107a88a6104688c856109e5565b905060006107b68285610a49565b905060006107cc670de0b6b3a764000083610c4e565b90506107d88a82610b6c565b9c9b505050505050505050505050565b600a670de0b6b3a76400006103b8565b671bc16d674ec7ffff81565b600081565b6002670de0b6b3a76400006103b8565b600080610826858861089c565b905060006108348786610c4e565b90506000610842888361089c565b905060006108508285610a49565b905061086481670de0b6b3a7640000610c4e565b9050610878670de0b6b3a764000087610c4e565b945061088d6108878c83610b6c565b8661089c565b9b9a5050505050505050505050565b6000816108f3576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4449565f5a45524f0000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a7640000830283158061091b5750670de0b6b3a764000084828161091857fe5b04145b61096f576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b600283048101818110156109cd576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b60008482816109d857fe5b0493505050505b92915050565b600082820183811015610a42576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4144445f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b9392505050565b60006001831015610aa4576040805160e560020a62461bcd02815260206004820152601560248201527f4552525f42504f575f424153455f544f4f5f4c4f570000000000000000000000604482015290519081900360640190fd5b671bc16d674ec7ffff831115610b04576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f42504f575f424153455f544f4f5f4849474800000000000000000000604482015290519081900360640190fd5b6000610b0f83610cbf565b90506000610b1d8483610c4e565b90506000610b3386610b2e85610cda565b610ce8565b905081610b445792506109df915050565b6000610b5587846305f5e100610d3f565b9050610b618282610b6c565b979650505050505050565b6000828202831580610b86575082848281610b8357fe5b04145b610bda576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6706f05b59d3b20000810181811015610c3d576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6000670de0b6b3a7640000826109d8565b6000806000610c5d8585610e1d565b915091508015610cb7576040805160e560020a62461bcd02815260206004820152601160248201527f4552525f5355425f554e444552464c4f57000000000000000000000000000000604482015290519081900360640190fd5b509392505050565b6000670de0b6b3a7640000610cd383610cda565b0292915050565b670de0b6b3a7640000900490565b60008060028306610d0157670de0b6b3a7640000610d03565b835b90506002830492505b8215610a4257610d1c8485610b6c565b93506002830615610d3457610d318185610b6c565b90505b600283049250610d0c565b6000828180610d5687670de0b6b3a7640000610e1d565b9092509050670de0b6b3a764000080600060015b888410610e0e576000670de0b6b3a764000082029050600080610d9e8a610d9985670de0b6b3a7640000610c4e565b610e1d565b91509150610db087610597848c610b6c565b9650610dbc878461089c565b965086610dcb57505050610e0e565b8715610dd5579315935b8015610ddf579315935b8415610df657610def8688610c4e565b9550610e03565b610e0086886109e5565b95505b505050600101610d6a565b50909998505050505050505050565b600080828410610e335750508082036000610e3b565b505081810360015b925092905056fea265627a7a723158205ed1b22832c14cf9e2efe6ea235b597639d6738dd598d3ea8203c58103f244c964736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/BNum.abi b/runtime/near-evm-runner/tests/build/BNum.abi new file mode 100644 index 00000000000..42a7386d836 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BNum.abi @@ -0,0 +1,257 @@ +[ + { + "constant": true, + "inputs": [], + "name": "BONE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "BPOW_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXIT_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "INIT_POOL_SUPPLY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_IN_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_OUT_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_TOTAL_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BALANCE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/BNum.bin b/runtime/near-evm-runner/tests/build/BNum.bin new file mode 100644 index 00000000000..aac89837d18 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BNum.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061029c806100206000396000f3fe608060405234801561001057600080fd5b5060043610610108576000357c010000000000000000000000000000000000000000000000000000000090048063b0e0d136116100af578063b0e0d1361461015f578063b7b800a414610167578063ba019dab1461016f578063bc063e1a14610177578063bc694ea21461017f578063c36596a61461012f578063c6580d1214610187578063e4a28a521461010d578063ec0930211461018f57610108565b806309a3bbe41461010d578063189d00ca14610127578063218b53821461012f57806376c7a3c714610137578063867378c51461013f5780639381cd2b14610147578063992e2a921461014f5780639a86139b14610157575b600080fd5b610115610197565b60408051918252519081900360200190f35b6101156101a4565b6101156101b8565b6101156101c4565b6101156101d6565b6101156101ea565b6101156101f7565b610115610203565b610115610227565b61011561022c565b610115610231565b610115610236565b610115610246565b610115610252565b610115610257565b6802b5e3af16b188000081565b6402540be400670de0b6b3a76400005b0481565b670de0b6b3a764000081565b620f4240670de0b6b3a76400006101b4565b64e8d4a51000670de0b6b3a76400006101b4565b68056bc75e2d6310000081565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b600881565b600281565b600181565b600a670de0b6b3a76400006101b4565b671bc16d674ec7ffff81565b600081565b6002670de0b6b3a76400006101b456fea265627a7a7231582089365996d164956921d5302db8b5bd223216993fe8eda62ec774fd5ff6d7c3f164736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/BPool.abi b/runtime/near-evm-runner/tests/build/BPool.abi new file mode 100644 index 00000000000..10600139942 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BPool.abi @@ -0,0 +1,1630 @@ +[ + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": true, + "inputs": [ + { + "indexed": true, + "internalType": "bytes4", + "name": "sig", + "type": "bytes4" + }, + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "LOG_CALL", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenOut", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + } + ], + "name": "LOG_EXIT", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenIn", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + } + ], + "name": "LOG_JOIN", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenIn", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenOut", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + } + ], + "name": "LOG_SWAP", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "BONE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "BPOW_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXIT_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "INIT_POOL_SUPPLY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_IN_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_OUT_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_TOTAL_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BALANCE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "whom", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcInGivenOut", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcOutGivenIn", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcPoolInGivenSingleOut", + "outputs": [ + { + "internalType": "uint256", + "name": "poolAmountIn", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcPoolOutGivenSingleIn", + "outputs": [ + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcSingleInGivenPoolOut", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcSingleOutGivenPoolIn", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcSpotPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "spotPrice", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isPublicSwap", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "t", + "type": "address" + } + ], + "name": "isBound", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getNumTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getCurrentTokens", + "outputs": [ + { + "internalType": "address[]", + "name": "tokens", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getFinalTokens", + "outputs": [ + { + "internalType": "address[]", + "name": "tokens", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "getDenormalizedWeight", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getTotalDenormalizedWeight", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "getNormalizedWeight", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "getBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getSwapFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getController", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "setSwapFee", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "setController", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "bool", + "name": "public_", + "type": "bool" + } + ], + "name": "setPublicSwap", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "finalize", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "denorm", + "type": "uint256" + } + ], + "name": "bind", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "denorm", + "type": "uint256" + } + ], + "name": "rebind", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "unbind", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "gulp", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenOut", + "type": "address" + } + ], + "name": "getSpotPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "spotPrice", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenOut", + "type": "address" + } + ], + "name": "getSpotPriceSansFee", + "outputs": [ + { + "internalType": "uint256", + "name": "spotPrice", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "maxAmountsIn", + "type": "uint256[]" + } + ], + "name": "joinPool", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "poolAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + } + ], + "name": "exitPool", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPrice", + "type": "uint256" + } + ], + "name": "swapExactAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "spotPriceAfter", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPrice", + "type": "uint256" + } + ], + "name": "swapExactAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "spotPriceAfter", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minPoolAmountOut", + "type": "uint256" + } + ], + "name": "joinswapExternAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + } + ], + "name": "joinswapPoolAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "poolAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minAmountOut", + "type": "uint256" + } + ], + "name": "exitswapPoolAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPoolAmountIn", + "type": "uint256" + } + ], + "name": "exitswapExternAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "poolAmountIn", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/BPool.bin b/runtime/near-evm-runner/tests/build/BPool.bin new file mode 100644 index 00000000000..ed434055d39 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BPool.bin @@ -0,0 +1 @@ +60c0604052601360808190527f42616c616e63657220506f6f6c20546f6b656e0000000000000000000000000060a0908152620000409160039190620000f7565b506040805180820190915260038082527f425054000000000000000000000000000000000000000000000000000000000060209092019182526200008791600491620000f7565b506005805460ff19166012179055348015620000a257600080fd5b5060068054600580546201000060b060020a031916336201000081029190911790915564e8d4a51000600755600160a060020a03199091161760a060020a60ff02191690556008805460ff191690556200019c565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200013a57805160ff19168380011785556200016a565b828001600101855582156200016a579182015b828111156200016a5782518255916020019190600101906200014d565b50620001789291506200017c565b5090565b6200019991905b8082111562000178576000815560010162000183565b90565b61587480620001ac6000396000f3fe608060405234801561001057600080fd5b5060043610610378576000357c0100000000000000000000000000000000000000000000000000000000900480638d4e4083116101e7578063bc694ea211610122578063d73dd623116100c5578063d73dd62314610b7f578063dd62ed3e14610bab578063e4a28a521461047e578063e4e1e53814610bd9578063ec09302114610c0b578063f1b8a9b714610c13578063f8b2cb4f14610c39578063f8d6aed414610c5f578063fde924f714610c9a57610378565b8063bc694ea214610ad9578063be3bbd2e14610ae1578063c36596a6146104f2578063c6580d1214610b39578063cc77828d14610b41578063cd2ed8fb14610b49578063cf5e7bd314610b51578063d4cadf6814610b7757610378565b8063a221ee491161018a578063a221ee49146109a6578063a9059cbb146109db578063b02f0b7314610a07578063b0e0d13614610a7e578063b7b800a414610a86578063ba019dab14610a8e578063ba9530a614610a96578063bc063e1a14610ad157610378565b80638d4e40831461092a57806392eefe9b14610932578063936c3477146109585780639381cd2b14610960578063948d8ce61461096857806395d89b411461098e578063992e2a92146109965780639a86139b1461099e57610378565b806349b59552116102b757806376c7a3c71161025a57806376c7a3c7146107aa5780637c5e9ea4146107b25780638201aa3f1461080b57806382f652ad1461084b5780638656b65314610886578063867378c5146108c157806389298012146108c95780638c28cbe81461090457610378565b806349b595521461061b5780634bb278f31461063a5780634f69c0d4146106425780635c1bbaf7146106b95780635db34277146106f457806366188463146107265780636d06dfa01461075257806370a082311461078457610378565b8063218b53821161031f578063218b5382146104f257806323b872dd146104fa5780632f37b624146105305780633018205f14610556578063313ce5671461057a57806334e19907146105985780633fdddaa2146105b757806346ab38f1146105e957610378565b806302c967481461037d57806306fdde03146103c1578063095ea7b31461043e57806309a3bbe41461047e5780631446a7ff1461048657806315e84af9146104b457806318160ddd146104e2578063189d00ca146104ea575b600080fd5b6103af6004803603606081101561039357600080fd5b50600160a060020a038135169060208101359060400135610ca2565b60408051918252519081900360200190f35b6103c9610fef565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104035781810151838201526020016103eb565b50505050905090810190601f1680156104305780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61046a6004803603604081101561045457600080fd5b50600160a060020a038135169060200135611085565b604080519115158252519081900360200190f35b6103af6110da565b6103af6004803603604081101561049c57600080fd5b50600160a060020a03813581169160200135166110e7565b6103af600480360360408110156104ca57600080fd5b50600160a060020a0381358116916020013516611241565b6103af611392565b6103af611398565b6103af6113ac565b61046a6004803603606081101561051057600080fd5b50600160a060020a038135811691602081013590911690604001356113b8565b61046a6004803603602081101561054657600080fd5b5035600160a060020a031661151d565b61055e61153b565b60408051600160a060020a039092168252519081900360200190f35b61058261159c565b6040805160ff9092168252519081900360200190f35b6105b5600480360360208110156105ae57600080fd5b50356115a5565b005b6105b5600480360360608110156105cd57600080fd5b50600160a060020a0381351690602081013590604001356117c9565b6103af600480360360608110156105ff57600080fd5b50600160a060020a038135169060208101359060400135611c15565b6105b56004803603602081101561063157600080fd5b50351515611f01565b6105b5612092565b6105b56004803603604081101561065857600080fd5b8135919081019060408101602082013564010000000081111561067a57600080fd5b82018360208201111561068c57600080fd5b803590602001918460208302840111640100000000831117156106ae57600080fd5b5090925090506122a9565b6103af600480360360c08110156106cf57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135612590565b6103af6004803603606081101561070a57600080fd5b50600160a060020a038135169060208101359060400135612648565b61046a6004803603604081101561073c57600080fd5b50600160a060020a038135169060200135612919565b6103af6004803603606081101561076857600080fd5b50600160a060020a0381351690602081013590604001356129f1565b6103af6004803603602081101561079a57600080fd5b5035600160a060020a0316612cf0565b6103af612d0b565b6107f2600480360360a08110156107c857600080fd5b50600160a060020a0381358116916020810135916040820135169060608101359060800135612d1d565b6040805192835260208301919091528051918290030190f35b6107f2600480360360a081101561082157600080fd5b50600160a060020a038135811691602081013591604082013516906060810135906080013561320d565b6103af600480360360c081101561086157600080fd5b5080359060208101359060408101359060608101359060808101359060a001356136e4565b6103af600480360360c081101561089c57600080fd5b5080359060208101359060408101359060608101359060808101359060a001356137a3565b6103af613844565b6103af600480360360c08110156108df57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135613858565b6105b56004803603602081101561091a57600080fd5b5035600160a060020a0316613908565b61046a613ad9565b6105b56004803603602081101561094857600080fd5b5035600160a060020a0316613ae2565b6103af613c2c565b6103af613c84565b6103af6004803603602081101561097e57600080fd5b5035600160a060020a0316613c91565b6103c9613d5f565b6103af613dc0565b6103af613dcc565b6103af600480360360a08110156109bc57600080fd5b5080359060208101359060408101359060608101359060800135613df0565b61046a600480360360408110156109f157600080fd5b50600160a060020a038135169060200135613e55565b6105b560048036036040811015610a1d57600080fd5b81359190810190604081016020820135640100000000811115610a3f57600080fd5b820183602082011115610a5157600080fd5b80359060200191846020830284011164010000000083111715610a7357600080fd5b509092509050613e6b565b6103af61419f565b6103af6141a4565b6103af6141a9565b6103af600480360360c0811015610aac57600080fd5b5080359060208101359060408101359060608101359060808101359060a001356141ae565b6103af61422f565b6103af61423f565b610ae961424b565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610b25578181015183820152602001610b0d565b505050509050019250505060405180910390f35b6103af614343565b610ae9614348565b6103af614399565b6105b560048036036020811015610b6757600080fd5b5035600160a060020a031661439f565b6103af61472c565b61046a60048036036040811015610b9557600080fd5b50600160a060020a038135169060200135614784565b6103af60048036036040811015610bc157600080fd5b50600160a060020a0381358116916020013516614805565b6105b560048036036060811015610bef57600080fd5b50600160a060020a038135169060208101359060400135614830565b6103af614ab4565b6103af60048036036020811015610c2957600080fd5b5035600160a060020a0316614ac4565b6103af60048036036020811015610c4f57600080fd5b5035600160a060020a0316614ba4565b6103af600480360360c0811015610c7557600080fd5b5080359060208101359060408101359060608101359060808101359060a00135614c72565b61046a614cf5565b600033600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615610d53576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16610daa576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a602052604090205460ff16610e08576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a60205260409020600390810154610e3d91670de0b6b3a76400005b04600101614d05565b831115610e82576040805160e560020a62461bcd02815260206004820152601160248201526000805160206156e0833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a6020526040902060038101546002808301549054600b54600754610ebc949392919089906136e4565b915081610f01576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b82821115610f47576040805160e560020a62461bcd02815260206004820152600c60248201526000805160206156c0833981519152604482015290519081900360640190fd5b610f55816003015485614dee565b60038201556000610f668382614d05565b604080518781529051919250600160a060020a0388169133916000805160206157a0833981519152919081900360200190a3610fa23384614e5f565b610fb4610faf8483614dee565b614e6d565b600554610fd090620100009004600160a060020a031682614e79565b610fdb863387614e83565b50506005805461ff00191690559392505050565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561107b5780601f106110505761010080835404028352916020019161107b565b820191906000526020600020905b81548152906001019060200180831161105e57829003601f168201915b5050505050905090565b336000818152600160209081526040808320600160a060020a038716808552908352818420869055815186815291519394909390926000805160206157c0833981519152928290030190a35060015b92915050565b6802b5e3af16b188000081565b600554600090610100900460ff1615611138576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090205460ff16611196576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a602052604090205460ff166111f4576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a038084166000908152600a602052604080822092851682528120600380840154600280860154928401549084015493946112389492939290613df0565b95945050505050565b600554600090610100900460ff1615611292576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090205460ff166112f0576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a602052604090205460ff1661134e576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a038084166000908152600a602052604080822092851682529020600380830154600280850154928401549084015460075461123894929190613df0565b60025490565b6402540be400670de0b6b3a76400005b0481565b670de0b6b3a764000081565b600033600160a060020a03851614806113f45750600160a060020a03841660009081526001602090815260408083203384529091529020548211155b611448576040805160e560020a62461bcd02815260206004820152601560248201527f4552525f42544f4b454e5f4241445f43414c4c45520000000000000000000000604482015290519081900360640190fd5b611453848484614f78565b33600160a060020a038516148015906114915750600160a060020a038416600090815260016020908152604080832033845290915290205460001914155b1561151357600160a060020a03841660009081526001602090815260408083203384529091529020546114c49083614dee565b600160a060020a03858116600090815260016020908152604080832033808552908352928190208590558051948552519287169391926000805160206157c08339815191529281900390910190a35b5060019392505050565b600160a060020a03166000908152600a602052604090205460ff1690565b600554600090610100900460ff161561158c576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b50600654600160a060020a031690565b60055460ff1690565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615611654576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16156116ac576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b600654600160a060020a031633146116fc576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b64e8d4a51000811015611759576040805160e560020a62461bcd02815260206004820152600b60248201527f4552525f4d494e5f464545000000000000000000000000000000000000000000604482015290519081900360640190fd5b67016345785d8a00008111156117b9576040805160e560020a62461bcd02815260206004820152600b60248201527f4552525f4d41585f464545000000000000000000000000000000000000000000604482015290519081900360640190fd5b6007556005805461ff0019169055565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615611878576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560065433600160a060020a03909116146118d9576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090205460ff16611937576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b60085460ff1615611980576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b670de0b6b3a76400008110156119e0576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f4d494e5f574549474854000000000000000000000000000000000000604482015290519081900360640190fd5b6802b5e3af16b1880000811115611a41576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f4d41585f574549474854000000000000000000000000000000000000604482015290519081900360640190fd5b620f4240821015611a9c576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f4d494e5f42414c414e43450000000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090206002015480821115611b3f57611ad5600b54611ad08484614dee565b615082565b600b8190556802b5e3af16b18800001015611b3a576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f4d41585f544f54414c5f574549474854000000000000000000000000604482015290519081900360640190fd5b611b60565b80821015611b6057611b5c600b54611b578385614dee565b614dee565b600b555b600160a060020a0384166000908152600a602052604090206002810183905560030180549084905580841115611ba957611ba48533611b9f8785614dee565b6150df565b611c03565b80841015611c03576000611bbd8286614dee565b90506000611bcc826000614d05565b9050611be28733611bdd8585614dee565b614e83565b600554611c00908890620100009004600160a060020a031683614e83565b50505b50506005805461ff0019169055505050565b600033600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615611cc6576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16611d1d576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a602052604090205460ff16611d7b576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a6020526040902060038101546002808301549054600b54600754611db594939291908990613858565b915082821015611dfd576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615800833981519152604482015290519081900360640190fd5b600160a060020a0385166000908152600a60205260409020600390810154611e2d91670de0b6b3a7640000610e34565b821115611e72576040805160e560020a62461bcd02815260206004820152601160248201526000805160206156e0833981519152604482015290519081900360640190fd5b611e80816003015483614dee565b60038201556000611e918582614d05565b604080518581529051919250600160a060020a0388169133916000805160206157a0833981519152919081900360200190a3611ecd3386614e5f565b611eda610faf8683614dee565b600554611ef690620100009004600160a060020a031682614e79565b610fdb863385614e83565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615611fb0576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff1615612008576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b600654600160a060020a03163314612058576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b6006805491151560a060020a0274ff0000000000000000000000000000000000000000199092169190911790556005805461ff0019169055565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615612141576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560065433600160a060020a03909116146121a2576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b60085460ff16156121eb576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b60095460021115612246576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f4d494e5f544f4b454e53000000000000000000000000000000000000604482015290519081900360640190fd5b6008805460ff191660011790556006805474ff0000000000000000000000000000000000000000191660a060020a17905561228968056bc75e2d63100000615151565b61229c3368056bc75e2d63100000614e79565b6005805461ff0019169055565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615612358576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff166123af576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b60006123b9611392565b905060006123c7858361515a565b90508061240c576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b60005b60095481101561257c5760006009828154811061242857fe5b6000918252602080832090910154600160a060020a0316808352600a90915260408220600301549092509061245d8583614d05565b9050806124a2576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b8787858181106124ae57fe5b905060200201358111156124fa576040805160e560020a62461bcd02815260206004820152600c60248201526000805160206156c0833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a60205260409020600301546125209082615082565b600160a060020a0384166000818152600a60209081526040918290206003019390935580518481529051919233926000805160206157008339815191529281900390910190a36125718333836150df565b50505060010161240f565b5061258685615151565b611c033386614e79565b60008061259d878661515a565b905060006125ab8786615082565b905060006125b9828961515a565b905060006125cf670de0b6b3a76400008561515a565b905060006125dd8383615296565b905060006125eb828e614d05565b905060006125f9828f614dee565b90506000612618612612670de0b6b3a76400008a614dee565b8b614d05565b905061263582612630670de0b6b3a764000084614dee565b61515a565b9f9e505050505050505050505050505050565b600033600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff16156126f9576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16612750576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a602052604090205460ff166127ae576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a60205260409020600301546127e0906002670de0b6b3a76400005b04614d05565b831115612825576040805160e560020a62461bcd0281526020600482015260106024820152600080516020615740833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a6020526040902060038101546002808301549054600b5460075461285f949392919089906137a3565b9150828210156128a7576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615800833981519152604482015290519081900360640190fd5b6128b5816003015485615082565b6003820155604080518581529051600160a060020a0387169133916000805160206157008339815191529181900360200190a36128f182615151565b6128fb3383614e79565b6129068533866150df565b506005805461ff00191690559392505050565b336000908152600160209081526040808320600160a060020a03861684529091528120548083111561296e57336000908152600160209081526040808320600160a060020a038816845290915281205561299d565b6129788184614dee565b336000908152600160209081526040808320600160a060020a03891684529091529020555b336000818152600160209081526040808320600160a060020a0389168085529083529281902054815190815290519293926000805160206157c0833981519152929181900390910190a35060019392505050565b600033600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615612aa2576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16612af9576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a602052604090205460ff16612b57576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0384166000908152600a6020526040902060038101546002808301549054600b54600754612b9194939291908990612590565b915081612bd6576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b82821115612c1c576040805160e560020a62461bcd02815260206004820152600c60248201526000805160206156c0833981519152604482015290519081900360640190fd5b600160a060020a0385166000908152600a6020526040902060030154612c4c906002670de0b6b3a76400006127da565b821115612c91576040805160e560020a62461bcd0281526020600482015260106024820152600080516020615740833981519152604482015290519081900360640190fd5b612c9f816003015483615082565b6003820155604080518381529051600160a060020a0387169133916000805160206157008339815191529181900360200190a3612cdb84615151565b612ce53385614e79565b6129068533846150df565b600160a060020a031660009081526020819052604090205490565b620f4240670de0b6b3a76400006113a8565b6040805160208082523690820181905260009283923392600160e060020a03198535169285929081908101848480828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615612dbd576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff001916610100179055600160a060020a0387166000908152600a602052604090205460ff16612e2a576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0385166000908152600a602052604090205460ff16612e88576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b60065460a060020a900460ff16612ee9576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f535741505f4e4f545f5055424c494300000000000000000000000000604482015290519081900360640190fd5b600160a060020a038088166000908152600a602052604080822092881682529020600380820154612f2291670de0b6b3a7640000610e34565b861115612f67576040805160e560020a62461bcd02815260206004820152601160248201526000805160206156e0833981519152604482015290519081900360640190fd5b6000612f888360030154846002015484600301548560020154600754613df0565b905085811115612fe2576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f4241445f4c494d49545f505249434500000000000000000000000000604482015290519081900360640190fd5b61300283600301548460020154846003015485600201548b600754614c72565b94508885111561304a576040805160e560020a62461bcd02815260206004820152600c60248201526000805160206156c0833981519152604482015290519081900360640190fd5b613058836003015486615082565b836003018190555061306e826003015488614dee565b600380840182905584015460028086015490850154600754613091949190613df0565b9350808410156130d9576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b85841115613131576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f4c494d49545f50524943450000000000000000000000000000000000604482015290519081900360640190fd5b61313b858861515a565b811115613180576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b87600160a060020a03168a600160a060020a031633600160a060020a03167f908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378888b604051808381526020018281526020019250505060405180910390a46131e88a33876150df565b6131f3883389614e83565b5050506005805461ff001916905590969095509350505050565b6040805160208082523690820181905260009283923392600160e060020a03198535169285929081908101848480828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff16156132ad576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff001916610100179055600160a060020a0387166000908152600a602052604090205460ff1661331a576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0385166000908152600a602052604090205460ff16613378576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b60065460a060020a900460ff166133d9576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f535741505f4e4f545f5055424c494300000000000000000000000000604482015290519081900360640190fd5b600160a060020a038088166000908152600a6020526040808220928816825290206003820154613413906002670de0b6b3a76400006127da565b881115613458576040805160e560020a62461bcd0281526020600482015260106024820152600080516020615740833981519152604482015290519081900360640190fd5b60006134798360030154846002015484600301548560020154600754613df0565b9050858111156134d3576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f4241445f4c494d49545f505249434500000000000000000000000000604482015290519081900360640190fd5b6134f383600301548460020154846003015485600201548d6007546141ae565b94508685101561353b576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615800833981519152604482015290519081900360640190fd5b61354983600301548a615082565b836003018190555061355f826003015486614dee565b600380840182905584015460028086015490850154600754613582949190613df0565b9350808410156135ca576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b85841115613622576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f4c494d49545f50524943450000000000000000000000000000000000604482015290519081900360640190fd5b61362c898661515a565b811115613671576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b87600160a060020a03168a600160a060020a031633600160a060020a03167f908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d433788c89604051808381526020018281526020019250505060405180910390a46136d98a338b6150df565b6131f3883387614e83565b6000806136f1878661515a565b90506000613707670de0b6b3a764000083614dee565b905060006137158286614d05565b9050600061372f87612630670de0b6b3a764000085614dee565b9050600061373d8c83614dee565b9050600061374b828e61515a565b905060006137598288615296565b90506000613767828e614d05565b905060006137758e83614dee565b905061378e81612630670de0b6b3a76400006000614dee565b99505050505050505050509695505050505050565b6000806137b0878661515a565b905060006137cf6137c9670de0b6b3a764000084614dee565b85614d05565b905060006137ee866137e9670de0b6b3a764000085614dee565b614d05565b905060006137fc8b83615082565b9050600061380a828d61515a565b905060006138188287615296565b90506000613826828d614d05565b9050613832818d614dee565b9e9d5050505050505050505050505050565b64e8d4a51000670de0b6b3a76400006113a8565b600080613865878661515a565b90506000613880856137e9670de0b6b3a76400006000614dee565b9050600061388e8883614dee565b9050600061389c828a61515a565b905060006138bb826138b6670de0b6b3a76400008861515a565b615296565b905060006138c9828e614d05565b905060006138d78e83614dee565b905060006138f0612612670de0b6b3a76400008a614dee565b9050612635826137e9670de0b6b3a764000084614dee565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff16156139b7576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff001916610100179055600160a060020a0381166000908152600a602052604090205460ff16613a24576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051600160a060020a038316916370a08231916024808301926020929190829003018186803b158015613a8357600080fd5b505afa158015613a97573d6000803e3d6000fd5b505050506040513d6020811015613aad57600080fd5b5051600160a060020a039091166000908152600a60205260409020600301556005805461ff0019169055565b60085460ff1690565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615613b91576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560065433600160a060020a0390911614613bf2576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03929092169190911790556005805461ff0019169055565b600554600090610100900460ff1615613c7d576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b50600b5490565b68056bc75e2d6310000081565b600554600090610100900460ff1615613ce2576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a602052604090205460ff16613d40576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b50600160a060020a03166000908152600a602052604090206002015490565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561107b5780601f106110505761010080835404028352916020019161107b565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b600080613dfd878761515a565b90506000613e0b868661515a565b90506000613e19838361515a565b90506000613e3b670de0b6b3a7640000612630670de0b6b3a764000089614dee565b9050613e478282614d05565b9a9950505050505050505050565b6000613e62338484614f78565b50600192915050565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff1615613f1a576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560085460ff16613f71576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b6000613f7b611392565b90506000613f8a856000614d05565b90506000613f988683614dee565b90506000613fa6828561515a565b905080613feb576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b613ff53388614e5f565b60055461401190620100009004600160a060020a031684614e79565b61401a82614e6d565b60005b60095481101561418a5760006009828154811061403657fe5b6000918252602080832090910154600160a060020a0316808352600a90915260408220600301549092509061406b8583614d05565b9050806140b0576040805160e560020a62461bcd02815260206004820152600f6024820152600080516020615820833981519152604482015290519081900360640190fd5b8989858181106140bc57fe5b90506020020135811015614108576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615800833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090206003015461412e9082614dee565b600160a060020a0384166000818152600a60209081526040918290206003019390935580518481529051919233926000805160206157a08339815191529281900390910190a361417f833383614e83565b50505060010161401d565b50506005805461ff0019169055505050505050565b600881565b600281565b600181565b6000806141bb878661515a565b905060006141d1670de0b6b3a764000085614dee565b90506141dd8582614d05565b905060006141ef8a6126308c85615082565b905060006141fd8285615296565b90506000614213670de0b6b3a764000083614dee565b905061421f8a82614d05565b9c9b505050505050505050505050565b600a670de0b6b3a76400006113a8565b671bc16d674ec7ffff81565b600554606090610100900460ff161561429c576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b60085460ff166142e4576040805160e560020a62461bcd0281526020600482015260116024820152600080516020615680833981519152604482015290519081900360640190fd5b600980548060200260200160405190810160405280929190818152602001828054801561107b57602002820191906000526020600020905b8154600160a060020a0316815260019091019060200180831161431c575050505050905090565b600081565b600554606090610100900460ff16156142e4576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b60095490565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600554610100900460ff161561444e576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b6005805461ff00191661010017905560065433600160a060020a03909116146144af576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b600160a060020a0381166000908152600a602052604090205460ff1661450d576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b60085460ff1615614556576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b600160a060020a0381166000908152600a60205260408120600301549061457d8282614d05565b600b54600160a060020a0385166000908152600a60205260409020600201549192506145a891614dee565b600b55600160a060020a0383166000908152600a60205260409020600101546009805460001981019190829081106145dc57fe5b60009182526020909120015460098054600160a060020a03909216918490811061460257fe5b9060005260206000200160006101000a815481600160a060020a030219169083600160a060020a0316021790555081600a60006009858154811061464257fe5b6000918252602080832090910154600160a060020a03168352820192909252604001902060010155600980548061467557fe5b600082815260208082206000199084018101805473ffffffffffffffffffffffffffffffffffffffff191690559092019092556040805160808101825283815280830184815281830185815260608301868152600160a060020a038c168752600a909552929094209051815460ff1916901515178155925160018401555160028301555160039091015561470e8533611bdd8787614dee565b600554611c03908690620100009004600160a060020a031685614e83565b600554600090610100900460ff161561477d576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b5060075490565b336000908152600160209081526040808320600160a060020a03861684529091528120546147b29083615082565b336000818152600160209081526040808320600160a060020a0389168085529083529281902085905580519485525191936000805160206157c0833981519152929081900390910190a350600192915050565b600160a060020a03918216600090815260016020908152604080832093909416825291909152205490565b33600160a060020a0316600035600160e060020a031916600160e060020a03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2600654600160a060020a031633146148e1576040805160e560020a62461bcd0281526020600482015260126024820152600080516020615720833981519152604482015290519081900360640190fd5b600160a060020a0383166000908152600a602052604090205460ff1615614952576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f49535f424f554e440000000000000000000000000000000000000000604482015290519081900360640190fd5b60085460ff161561499b576040805160e560020a62461bcd02815260206004820152601060248201526000805160206157e0833981519152604482015290519081900360640190fd5b6009546008116149f5576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f4d41585f544f4b454e53000000000000000000000000000000000000604482015290519081900360640190fd5b604080516080810182526001808252600980546020808501918252600085870181815260608701828152600160a060020a038c16808452600a9094529782209651875460ff1916901515178755925186860155915160028601559451600390940193909355805491820181559091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af01805473ffffffffffffffffffffffffffffffffffffffff19169091179055614aaf8383836117c9565b505050565b6002670de0b6b3a76400006113a8565b600554600090610100900460ff1615614b15576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a602052604090205460ff16614b73576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a6020526040902060020154600b54614b9d90829061515a565b9392505050565b600554600090610100900460ff1615614bf5576040805160e560020a62461bcd02815260206004820152600b60248201526000805160206156a0833981519152604482015290519081900360640190fd5b600160a060020a0382166000908152600a602052604090205460ff16614c53576040805160e560020a62461bcd02815260206004820152600d6024820152600080516020615780833981519152604482015290519081900360640190fd5b50600160a060020a03166000908152600a602052604090206003015490565b600080614c7f858861515a565b90506000614c8d8786614dee565b90506000614c9b888361515a565b90506000614ca98285615296565b9050614cbd81670de0b6b3a7640000614dee565b9050614cd1670de0b6b3a764000087614dee565b9450614ce6614ce08c83614d05565b8661515a565b9b9a5050505050505050505050565b60065460a060020a900460ff1690565b6000828202831580614d1f575082848281614d1c57fe5b04145b614d73576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6706f05b59d3b20000810181811015614dd6576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6000670de0b6b3a7640000825b049695505050505050565b6000806000614dfd85856153b9565b915091508015614e57576040805160e560020a62461bcd02815260206004820152601160248201527f4552525f5355425f554e444552464c4f57000000000000000000000000000000604482015290519081900360640190fd5b509392505050565b614e6982826153de565b5050565b614e76816153e9565b50565b614e6982826154b3565b604080517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a03848116600483015260248201849052915160009286169163a9059cbb91604480830192602092919082900301818787803b158015614eef57600080fd5b505af1158015614f03573d6000803e3d6000fd5b505050506040513d6020811015614f1957600080fd5b5051905080614f72576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f45524332305f46414c53450000000000000000000000000000000000604482015290519081900360640190fd5b50505050565b600160a060020a038316600090815260208190526040902054811115614fe8576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e53554646494349454e545f42414c000000000000000000000000604482015290519081900360640190fd5b600160a060020a03831660009081526020819052604090205461500b9082614dee565b600160a060020a03808516600090815260208190526040808220939093559084168152205461503a9082615082565b600160a060020a0380841660008181526020818152604091829020949094558051858152905191939287169260008051602061576083398151915292918290030190a3505050565b600082820183811015614b9d576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4144445f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b604080517f23b872dd000000000000000000000000000000000000000000000000000000008152600160a060020a0384811660048301523060248301526044820184905291516000928616916323b872dd91606480830192602092919082900301818787803b158015614eef57600080fd5b614e76816154be565b6000816151b1576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4449565f5a45524f0000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a764000083028315806151d95750670de0b6b3a76400008482816151d657fe5b04145b61522d576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b6002830481018181101561528b576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b6000848281614de357fe5b600060018310156152f1576040805160e560020a62461bcd02815260206004820152601560248201527f4552525f42504f575f424153455f544f4f5f4c4f570000000000000000000000604482015290519081900360640190fd5b671bc16d674ec7ffff831115615351576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f42504f575f424153455f544f4f5f4849474800000000000000000000604482015290519081900360640190fd5b600061535c83615521565b9050600061536a8483614dee565b905060006153808661537b8561553c565b61554a565b9050816153915792506110d4915050565b60006153a287846305f5e1006155a1565b90506153ae8282614d05565b979650505050505050565b6000808284106153cf57505080820360006153d7565b505081810360015b9250929050565b614e69823083614f78565b30600090815260208190526040902054811115615450576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e53554646494349454e545f42414c000000000000000000000000604482015290519081900360640190fd5b3060009081526020819052604090205461546a9082614dee565b306000908152602081905260409020556002546154879082614dee565b60025560408051828152905160009130916000805160206157608339815191529181900360200190a350565b614e69308383614f78565b306000908152602081905260409020546154d89082615082565b306000908152602081905260409020556002546154f59082615082565b60025560408051828152905130916000916000805160206157608339815191529181900360200190a350565b6000670de0b6b3a76400006155358361553c565b0292915050565b670de0b6b3a7640000900490565b6000806002830661556357670de0b6b3a7640000615565565b835b90506002830492505b8215614b9d5761557e8485614d05565b93506002830615615596576155938185614d05565b90505b60028304925061556e565b60008281806155b887670de0b6b3a76400006153b9565b9092509050670de0b6b3a764000080600060015b888410615670576000670de0b6b3a7640000820290506000806156008a6155fb85670de0b6b3a7640000614dee565b6153b9565b91509150615612876137e9848c614d05565b965061561e878461515a565b96508661562d57505050615670565b8715615637579315935b8015615641579315935b8415615658576156518688614dee565b9550615665565b6156628688615082565b95505b5050506001016155cc565b5090999850505050505050505056fe4552525f4e4f545f46494e414c495a45440000000000000000000000000000004552525f5245454e5452590000000000000000000000000000000000000000004552525f4c494d49545f494e00000000000000000000000000000000000000004552525f4d41585f4f55545f524154494f00000000000000000000000000000063982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a4552525f4e4f545f434f4e54524f4c4c455200000000000000000000000000004552525f4d41585f494e5f524154494f00000000000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef4552525f4e4f545f424f554e4400000000000000000000000000000000000000e74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9254552525f49535f46494e414c495a4544000000000000000000000000000000004552525f4c494d49545f4f5554000000000000000000000000000000000000004552525f4d4154485f415050524f580000000000000000000000000000000000a265627a7a72315820a6ed20be58469dda7b96f5cd85dbd70406a753a02b645704241ab59bf33344fe64736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/BToken.abi b/runtime/near-evm-runner/tests/build/BToken.abi new file mode 100644 index 00000000000..bd685b01c12 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BToken.abi @@ -0,0 +1,549 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "BONE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "BPOW_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXIT_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "INIT_POOL_SUPPLY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_IN_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_OUT_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_TOTAL_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BALANCE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "whom", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/BToken.bin b/runtime/near-evm-runner/tests/build/BToken.bin new file mode 100644 index 00000000000..3126375860d --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BToken.bin @@ -0,0 +1 @@ +60c0604052601360808190527f42616c616e63657220506f6f6c20546f6b656e0000000000000000000000000060a090815261003e91600391906100a3565b506040805180820190915260038082527f42505400000000000000000000000000000000000000000000000000000000006020909201918252610083916004916100a3565b506005805460ff1916601217905534801561009d57600080fd5b5061013e565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e457805160ff1916838001178555610111565b82800160010185558215610111579182015b828111156101115782518255916020019190600101906100f6565b5061011d929150610121565b5090565b61013b91905b8082111561011d5760008155600101610127565b90565b610bd88061014d6000396000f3fe608060405234801561001057600080fd5b50600436106101a1576000357c010000000000000000000000000000000000000000000000000000000090048063992e2a92116100f6578063bc694ea2116100a4578063bc694ea2146103b7578063c36596a61461028d578063c6580d12146103bf578063d73dd623146103c7578063dd62ed3e146103f3578063e4a28a5214610263578063ec09302114610421576101a1565b8063992e2a921461035b5780639a86139b14610363578063a9059cbb1461036b578063b0e0d13614610397578063b7b800a41461039f578063ba019dab146103a7578063bc063e1a146103af576101a1565b8063313ce56711610153578063313ce567146102cb57806366188463146102e957806370a082311461031557806376c7a3c71461033b578063867378c5146103435780639381cd2b1461034b57806395d89b4114610353576101a1565b806306fdde03146101a6578063095ea7b31461022357806309a3bbe41461026357806318160ddd1461027d578063189d00ca14610285578063218b53821461028d57806323b872dd14610295575b600080fd5b6101ae610429565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101e85781810151838201526020016101d0565b50505050905090810190601f1680156102155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61024f6004803603604081101561023957600080fd5b50600160a060020a0381351690602001356104bf565b604080519115158252519081900360200190f35b61026b610513565b60408051918252519081900360200190f35b61026b610520565b61026b610526565b61026b61053a565b61024f600480360360608110156102ab57600080fd5b50600160a060020a03813581169160208101359091169060400135610546565b6102d36106ab565b6040805160ff9092168252519081900360200190f35b61024f600480360360408110156102ff57600080fd5b50600160a060020a0381351690602001356106b4565b61026b6004803603602081101561032b57600080fd5b5035600160a060020a031661078c565b61026b6107a7565b61026b6107b9565b61026b6107cd565b6101ae6107da565b61026b61083b565b61026b610847565b61024f6004803603604081101561038157600080fd5b50600160a060020a03813516906020013561086b565b61026b610881565b61026b610886565b61026b61088b565b61026b610890565b61026b6108a0565b61026b6108ac565b61024f600480360360408110156103dd57600080fd5b50600160a060020a0381351690602001356108b1565b61026b6004803603604081101561040957600080fd5b50600160a060020a0381358116916020013516610932565b61026b61095d565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104b55780601f1061048a576101008083540402835291602001916104b5565b820191906000526020600020905b81548152906001019060200180831161049857829003601f168201915b5050505050905090565b336000818152600160209081526040808320600160a060020a03871680855290835281842086905581518681529151939490939092600080516020610b84833981519152928290030190a350600192915050565b6802b5e3af16b188000081565b60025490565b6402540be400670de0b6b3a76400005b0481565b670de0b6b3a764000081565b600033600160a060020a03851614806105825750600160a060020a03841660009081526001602090815260408083203384529091529020548211155b6105d6576040805160e560020a62461bcd02815260206004820152601560248201527f4552525f42544f4b454e5f4241445f43414c4c45520000000000000000000000604482015290519081900360640190fd5b6105e184848461096d565b33600160a060020a0385161480159061061f5750600160a060020a038416600090815260016020908152604080832033845290915290205460001914155b156106a157600160a060020a03841660009081526001602090815260408083203384529091529020546106529083610a89565b600160a060020a0385811660009081526001602090815260408083203380855290835292819020859055805194855251928716939192600080516020610b848339815191529281900390910190a35b5060019392505050565b60055460ff1690565b336000908152600160209081526040808320600160a060020a03861684529091528120548083111561070957336000908152600160209081526040808320600160a060020a0388168452909152812055610738565b6107138184610a89565b336000908152600160209081526040808320600160a060020a03891684529091529020555b336000818152600160209081526040808320600160a060020a038916808552908352928190205481519081529051929392600080516020610b84833981519152929181900390910190a35060019392505050565b600160a060020a031660009081526020819052604090205490565b620f4240670de0b6b3a7640000610536565b64e8d4a51000670de0b6b3a7640000610536565b68056bc75e2d6310000081565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104b55780601f1061048a576101008083540402835291602001916104b5565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b600061087833848461096d565b50600192915050565b600881565b600281565b600181565b600a670de0b6b3a7640000610536565b671bc16d674ec7ffff81565b600081565b336000908152600160209081526040808320600160a060020a03861684529091528120546108df9083610afa565b336000818152600160209081526040808320600160a060020a038916808552908352928190208590558051948552519193600080516020610b84833981519152929081900390910190a350600192915050565b600160a060020a03918216600090815260016020908152604080832093909416825291909152205490565b6002670de0b6b3a7640000610536565b600160a060020a0383166000908152602081905260409020548111156109dd576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e53554646494349454e545f42414c000000000000000000000000604482015290519081900360640190fd5b600160a060020a038316600090815260208190526040902054610a009082610a89565b600160a060020a038085166000908152602081905260408082209390935590841681522054610a2f9082610afa565b600160a060020a038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6000806000610a988585610b5e565b915091508015610af2576040805160e560020a62461bcd02815260206004820152601160248201527f4552525f5355425f554e444552464c4f57000000000000000000000000000000604482015290519081900360640190fd5b509392505050565b600082820183811015610b57576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4144445f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b9392505050565b600080828410610b745750508082036000610b7c565b505081810360015b925092905056fe8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a265627a7a72315820a87af892d69e40e2c034544393d3427651f6eae9f394257394f44f1bd9738fdf64736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/BTokenBase.abi b/runtime/near-evm-runner/tests/build/BTokenBase.abi new file mode 100644 index 00000000000..96908e29e8b --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BTokenBase.abi @@ -0,0 +1,307 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "BONE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "BPOW_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXIT_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "INIT_POOL_SUPPLY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_IN_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_OUT_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_TOTAL_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BALANCE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/BTokenBase.bin b/runtime/near-evm-runner/tests/build/BTokenBase.bin new file mode 100644 index 00000000000..ff5c54e21c4 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/BTokenBase.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061029c806100206000396000f3fe608060405234801561001057600080fd5b5060043610610108576000357c010000000000000000000000000000000000000000000000000000000090048063b0e0d136116100af578063b0e0d1361461015f578063b7b800a414610167578063ba019dab1461016f578063bc063e1a14610177578063bc694ea21461017f578063c36596a61461012f578063c6580d1214610187578063e4a28a521461010d578063ec0930211461018f57610108565b806309a3bbe41461010d578063189d00ca14610127578063218b53821461012f57806376c7a3c714610137578063867378c51461013f5780639381cd2b14610147578063992e2a921461014f5780639a86139b14610157575b600080fd5b610115610197565b60408051918252519081900360200190f35b6101156101a4565b6101156101b8565b6101156101c4565b6101156101d6565b6101156101ea565b6101156101f7565b610115610203565b610115610227565b61011561022c565b610115610231565b610115610236565b610115610246565b610115610252565b610115610257565b6802b5e3af16b188000081565b6402540be400670de0b6b3a76400005b0481565b670de0b6b3a764000081565b620f4240670de0b6b3a76400006101b4565b64e8d4a51000670de0b6b3a76400006101b4565b68056bc75e2d6310000081565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b600881565b600281565b600181565b600a670de0b6b3a76400006101b4565b671bc16d674ec7ffff81565b600081565b6002670de0b6b3a76400006101b456fea265627a7a7231582008760bf61cf90a4adde4f0558f43bdcd8f3e5cdf97aca2d1957bb4fef5289a1764736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/ConstructorRevert.bin b/runtime/near-evm-runner/tests/build/ConstructorRevert.bin deleted file mode 100644 index eba8500764a..00000000000 --- a/runtime/near-evm-runner/tests/build/ConstructorRevert.bin +++ /dev/null @@ -1 +0,0 @@ -6080604052348015600f57600080fd5b5060056004146086576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f4572726f72204465706c6f79696e6720436f6e7472616374000000000000000081525060200191505060405180910390fd5b603e8060936000396000f3fe6080604052600080fdfea265627a7a723158203667e47f55606e5f72d16e0d9a81ed4435273fcfa1ee79bf9545dc524d930d2f64736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/Create2Factory.bin b/runtime/near-evm-runner/tests/build/Create2Factory.bin index da4baf5279f..5c18234a6ab 100644 --- a/runtime/near-evm-runner/tests/build/Create2Factory.bin +++ b/runtime/near-evm-runner/tests/build/Create2Factory.bin @@ -1 +1 @@ -608060405234801561001057600080fd5b50610758806100206000396000f3fe6080604052600436106100295760003560e01c80639f45e8151461002b578063cdcb760a14610108575b005b6100ee6004803603604081101561004157600080fd5b81019080803590602001909291908035906020019064010000000081111561006857600080fd5b82018360208201111561007a57600080fd5b8035906020019184600183028401116401000000008311171561009c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061021a565b604051808215151515815260200191505060405180910390f35b34801561011457600080fd5b506101d86004803603604081101561012b57600080fd5b81019080803590602001909291908035906020019064010000000081111561015257600080fd5b82018360208201111561016457600080fd5b8035906020019184600183028401116401000000008311171561018657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506106c7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60008061022784846106c7565b905060008190508073ffffffffffffffffffffffffffffffffffffffff1663eef4c90f60056040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561028257600080fd5b505af1158015610296573d6000803e3d6000fd5b5050505060058173ffffffffffffffffffffffffffffffffffffffff16636e4d2a346040518163ffffffff1660e01b815260040160206040518083038186803b1580156102e257600080fd5b505afa1580156102f6573d6000803e3d6000fd5b505050506040513d602081101561030c57600080fd5b810190808051906020019092919050505014610390576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f7072652d6465737472756374696f6e2077726f6e672075696e7400000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663d37c6c9e6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156103d857600080fd5b505af11580156103ec573d6000803e3d6000fd5b5050505060606103fb826106db565b90506000815114610474576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f706f73742d6465737472756374696f6e20636f6465206c656e6774680000000081525060200191505060405180910390fd5b61047e86866106c7565b5060008273ffffffffffffffffffffffffffffffffffffffff16636e4d2a346040518163ffffffff1660e01b815260040160206040518083038186803b1580156104c757600080fd5b505afa1580156104db573d6000803e3d6000fd5b505050506040513d60208110156104f157600080fd5b810190808051906020019092919050505014610575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f706f73742d6465737472756374696f6e2077726f6e672075696e74000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663eef4c90f60036040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156105c957600080fd5b505af11580156105dd573d6000803e3d6000fd5b5050505060038273ffffffffffffffffffffffffffffffffffffffff16636e4d2a346040518163ffffffff1660e01b815260040160206040518083038186803b15801561062957600080fd5b505afa15801561063d573d6000803e3d6000fd5b505050506040513d602081101561065357600080fd5b8101908080519060200190929190505050146106ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806107026022913960400191505060405180910390fd5b6001935050505092915050565b6000828251602084016000f5905092915050565b60606040519050813b8082526020820181600082863c818352818101604052505091905056fe706f73742d6465737472756374696f6e2073746f7265642077726f6e672075696e74a265627a7a7231582057b6addf30c31c49aa94429f78664940ffa8f1922153be7c94c853fa4932031c64736f6c63430005100032 \ No newline at end of file +608060405234801561001057600080fd5b50610758806100206000396000f3fe6080604052600436106100295760003560e01c80639f45e8151461002b578063cdcb760a14610108575b005b6100ee6004803603604081101561004157600080fd5b81019080803590602001909291908035906020019064010000000081111561006857600080fd5b82018360208201111561007a57600080fd5b8035906020019184600183028401116401000000008311171561009c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061021a565b604051808215151515815260200191505060405180910390f35b34801561011457600080fd5b506101d86004803603604081101561012b57600080fd5b81019080803590602001909291908035906020019064010000000081111561015257600080fd5b82018360208201111561016457600080fd5b8035906020019184600183028401116401000000008311171561018657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506106c7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60008061022784846106c7565b905060008190508073ffffffffffffffffffffffffffffffffffffffff1663eef4c90f60056040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561028257600080fd5b505af1158015610296573d6000803e3d6000fd5b5050505060058173ffffffffffffffffffffffffffffffffffffffff16636e4d2a346040518163ffffffff1660e01b815260040160206040518083038186803b1580156102e257600080fd5b505afa1580156102f6573d6000803e3d6000fd5b505050506040513d602081101561030c57600080fd5b810190808051906020019092919050505014610390576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f7072652d6465737472756374696f6e2077726f6e672075696e7400000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663d37c6c9e6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156103d857600080fd5b505af11580156103ec573d6000803e3d6000fd5b5050505060606103fb826106db565b90506000815114610474576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f706f73742d6465737472756374696f6e20636f6465206c656e6774680000000081525060200191505060405180910390fd5b61047e86866106c7565b5060008273ffffffffffffffffffffffffffffffffffffffff16636e4d2a346040518163ffffffff1660e01b815260040160206040518083038186803b1580156104c757600080fd5b505afa1580156104db573d6000803e3d6000fd5b505050506040513d60208110156104f157600080fd5b810190808051906020019092919050505014610575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f706f73742d6465737472756374696f6e2077726f6e672075696e74000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663eef4c90f60036040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156105c957600080fd5b505af11580156105dd573d6000803e3d6000fd5b5050505060038273ffffffffffffffffffffffffffffffffffffffff16636e4d2a346040518163ffffffff1660e01b815260040160206040518083038186803b15801561062957600080fd5b505afa15801561063d573d6000803e3d6000fd5b505050506040513d602081101561065357600080fd5b8101908080519060200190929190505050146106ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806107026022913960400191505060405180910390fd5b6001935050505092915050565b6000828251602084016000f5905092915050565b60606040519050813b8082526020820181600082863c818352818101604052505091905056fe706f73742d6465737472756374696f6e2073746f7265642077726f6e672075696e74a265627a7a72315820e8aa482dbb1ad5a50769172bb326b40795aaa96e6340d1443c2ce7fdf22f071564736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/IERC20.abi b/runtime/near-evm-runner/tests/build/IERC20.abi new file mode 100644 index 00000000000..a8a6512c554 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/IERC20.abi @@ -0,0 +1,197 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "whom", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/Migrations.abi b/runtime/near-evm-runner/tests/build/Migrations.abi new file mode 100644 index 00000000000..bc177e8cb7a --- /dev/null +++ b/runtime/near-evm-runner/tests/build/Migrations.abi @@ -0,0 +1,68 @@ +[ + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "constant": true, + "inputs": [], + "name": "lastCompletedMigration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "completed", + "type": "uint256" + } + ], + "name": "setCompleted", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "new_address", + "type": "address" + } + ], + "name": "upgrade", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/Migrations.bin b/runtime/near-evm-runner/tests/build/Migrations.bin new file mode 100644 index 00000000000..30bf5398e99 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/Migrations.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5060008054600160a060020a031916331790556101b9806100326000396000f3fe608060405234801561001057600080fd5b506004361061004f5760e060020a60003504630900f01081146100545780638da5cb5b1461007c578063fbdbad3c146100a0578063fdacd576146100ba575b600080fd5b61007a6004803603602081101561006a57600080fd5b5035600160a060020a03166100d7565b005b610084610157565b60408051600160a060020a039092168252519081900360200190f35b6100a8610166565b60408051918252519081900360200190f35b61007a600480360360208110156100d057600080fd5b503561016c565b600054600160a060020a031633141561015457600081905080600160a060020a031663fdacd5766001546040518263ffffffff1660e060020a02815260040180828152602001915050600060405180830381600087803b15801561013a57600080fd5b505af115801561014e573d6000803e3d6000fd5b50505050505b50565b600054600160a060020a031681565b60015481565b600054600160a060020a03163314156101545760015556fea265627a7a7231582023ed50b526b6a1b0948c964d1041e7f84e7a132d4284b38755f775875359435d64736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/PrecompiledFunction.abi b/runtime/near-evm-runner/tests/build/PrecompiledFunction.abi new file mode 100644 index 00000000000..98369784154 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/PrecompiledFunction.abi @@ -0,0 +1,204 @@ +[ + { + "inputs": [], + "payable": true, + "stateMutability": "payable", + "type": "constructor" + }, + { + "constant": true, + "inputs": [], + "name": "noop", + "outputs": [], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "testSha256", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "testSha256_100bytes", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "testEcrecover", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "testRipemd160", + "outputs": [ + { + "internalType": "bytes20", + "name": "", + "type": "bytes20" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "testRipemd160_1kb", + "outputs": [ + { + "internalType": "bytes20", + "name": "", + "type": "bytes20" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "identity", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "test_identity", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "test_identity_100bytes", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "base", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "e", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "m", + "type": "uint256" + } + ], + "name": "modexp", + "outputs": [ + { + "internalType": "uint256", + "name": "o", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "testModExp", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "testBn128Add", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/PrecompiledFunction.bin b/runtime/near-evm-runner/tests/build/PrecompiledFunction.bin new file mode 100644 index 00000000000..198e45d143f --- /dev/null +++ b/runtime/near-evm-runner/tests/build/PrecompiledFunction.bin @@ -0,0 +1 @@ +6080604052610c2c806100136000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063840f612011610071578063840f61201461026d5780638a6fa9da146103a1578063a449e8eb146103bf578063a7d4bbe6146103dd578063b7a0961a14610433578063e96cc75c1461046f576100b4565b806304e87187146100b9578063080e99331461013c5780631d82afc71461015a578063494236eb146101dd57806351163670146102195780635dfc2e4a14610263575b600080fd5b6100c161048d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101015780820151818401526020810190506100e6565b50505050905090810190601f16801561012e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101446104b5565b6040518082815260200191505060405180910390f35b610162610512565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101a2578082015181840152602081019050610187565b50505050905090810190601f1680156101cf5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101e5610531565b60405180826bffffffffffffffffffffffff19166bffffffffffffffffffffffff1916815260200191505060405180910390f35b610221610574565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61026b610640565b005b6103266004803603602081101561028357600080fd5b81019080803590602001906401000000008111156102a057600080fd5b8201836020820111156102b257600080fd5b803590602001918460018302840111640100000000831117156102d457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610642565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561036657808201518184015260208101905061034b565b50505050905090810190601f1680156103935780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103a961069e565b6040518082815260200191505060405180910390f35b6103c76106a3565b6040518082815260200191505060405180910390f35b61041d600480360360608110156103f357600080fd5b810190808035906020019092919080359060200190929190803590602001909291905050506106f8565b6040518082815260200191505060405180910390f35b61043b610743565b60405180826bffffffffffffffffffffffff19166bffffffffffffffffffffffff1916815260200191505060405180910390f35b61047761077c565b6040518082815260200191505060405180910390f35b60606104b06040518060a0016040528060658152602001610b9360659139610642565b905090565b600060026040518080610b93606591396065019050602060405180830381855afa1580156104e7573d6000803e3d6000fd5b5050506040513d60208110156104fc57600080fd5b8101908080519060200190929190505050905090565b606061052c60405180602001604052806000815250610642565b905090565b6000600360405180806107936104009139610400019050602060405180830381855afa158015610565573d6000803e3d6000fd5b5050506040515160601b905090565b60006001601b6040516000815260200160405260405180807f11111111111111111111111111111111111111111111111111111111111111118152506020018260ff168152602001807fb9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b698815250602001807f12ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb6447448152506020019150506020604051602081039080840390855afa158015610631573d6000803e3d6000fd5b50505060206040510351905090565b565b60608082516040519080825280601f01601f1916602001820160405280156106795781602001600182028038833980820191505090505b509050825180602083018260208701600060045af161069457fe5b5080915050919050565b600090565b60006002604051806000019050602060405180830381855afa1580156106cd573d6000803e3d6000fd5b5050506040513d60208110156106e257600080fd5b8101908080519060200190929190505050905090565b600060405160208152602080820152602060408201528460608201528360808201528260a082015260208160c08360056107d05a03fa61073757600080fd5b80519150509392505050565b60006003604051806000019050602060405180830381855afa15801561076d573d6000803e3d6000fd5b5050506040515160601b905090565b600061078d61303960ad60656106f8565b90509056fe6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f7071727374757677a265627a7a723158205d2c2b792d903870209e310c124cea57de9949e98fa1104d789ef0f5fea175cd64736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/SelfDestruct.bin b/runtime/near-evm-runner/tests/build/SelfDestruct.bin index fdf024159ad..176353f70ea 100644 --- a/runtime/near-evm-runner/tests/build/SelfDestruct.bin +++ b/runtime/near-evm-runner/tests/build/SelfDestruct.bin @@ -1 +1 @@ -608060405234801561001057600080fd5b506101fc806100206000396000f3fe60806040526004361061004a5760003560e01c80636e4d2a341461004c5780638f63640e14610077578063d37c6c9e146100ce578063eef4c90f146100e5578063f2c4da9314610120575b005b34801561005857600080fd5b50610061610137565b6040518082815260200191505060405180910390f35b34801561008357600080fd5b5061008c61013d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156100da57600080fd5b506100e3610162565b005b3480156100f157600080fd5b5061011e6004803603602081101561010857600080fd5b810190808035906020019092919050505061017b565b005b34801561012c57600080fd5b50610135610185565b005b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b8060018190555050565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555056fea265627a7a7231582049134aca36ca008aa7d94838f31a297f561997c03ec02dedcb7b63aa26289cd664736f6c63430005100032 \ No newline at end of file +608060405234801561001057600080fd5b506101fc806100206000396000f3fe60806040526004361061004a5760003560e01c80636e4d2a341461004c5780638f63640e14610077578063d37c6c9e146100ce578063eef4c90f146100e5578063f2c4da9314610120575b005b34801561005857600080fd5b50610061610137565b6040518082815260200191505060405180910390f35b34801561008357600080fd5b5061008c61013d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156100da57600080fd5b506100e3610162565b005b3480156100f157600080fd5b5061011e6004803603602081101561010857600080fd5b810190808035906020019092919050505061017b565b005b34801561012c57600080fd5b50610135610185565b005b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b8060018190555050565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555056fea265627a7a72315820bc2518d7325b1a42a627271a1c315221090ec42188a01825fcea78176392f4c164736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/SolTests.bin b/runtime/near-evm-runner/tests/build/SolTests.bin index 186505b4e7f..b7bacad4583 100644 --- a/runtime/near-evm-runner/tests/build/SolTests.bin +++ b/runtime/near-evm-runner/tests/build/SolTests.bin @@ -1 +1 @@ -6080604052610a87806100136000396000f3fe6080604052600436106100705760003560e01c8063299fb0431161004e578063299fb043146101af5780632ccb1b30146101c65780639d9f9a6e14610235578063b69ef8a81461028657610070565b80630a84cba514610072578063111e0b12146100e757806314d54f541461015c575b005b61009e6004803603602081101561008857600080fd5b81019080803590602001909291905050506102b1565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b610113600480360360208110156100fd57600080fd5b8101908080359060200190929190505050610390565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561016857600080fd5b506101956004803603602081101561017f57600080fd5b81019080803590602001909291905050506103dc565b604051808215151515815260200191505060405180910390f35b3480156101bb57600080fd5b506101c461041e565b005b3480156101d257600080fd5b5061021f600480360360408110156101e957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610756565b6040518082815260200191505060405180910390f35b61023d6107af565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561029257600080fd5b5061029b610810565b6040518082815260200191505060405180910390f35b6000806000836040516102c390610818565b80828152602001915050604051809103906000f0801580156102e9573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610332573d6000803e3d6000fd5b508073ffffffffffffffffffffffffffffffffffffffff167fa53ffc4fb91f5ca8287e168fc73db3b0b384a6ca275650f885a1740ef7a0bc1c346040518082815260200191505060405180910390a280348191509250925050915091565b600080600034846040516103a390610818565b808281526020019150506040518091039082f0801580156103c8573d6000803e3d6000fd5b509050905080348191509250925050915091565b60007f379340f64b65a8890c7ea4f6d86d2359beaf41080f36a7ea64b78a2c06eee3f0826040518082815260200191505060405180910390a160019050919050565b7fe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556002604051806000019050602060405180830381855afa158015610467573d6000803e3d6000fd5b5050506040513d602081101561047c57600080fd5b810190808051906020019092919050505014610500576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f7368613220646967657374206d69736d6174636800000000000000000000000081525060200191505060405180910390fd5b7f9c1185a5c5e9fc54612808977ee8f548b2258d310000000000000000000000006003604051806000019050602060405180830381855afa158015610549573d6000803e3d6000fd5b5050506040515160601b6bffffffffffffffffffffffff1916146105d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f726d6431363020646967657374206d69736d617463680000000000000000000081525060200191505060405180910390fd5b60006001601b6040516000815260200160405260405180807f11111111111111111111111111111111111111111111111111111111111111118152506020018260ff168152602001807fb9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b698815250602001807f12ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb6447448152506020019150506020604051602081039080840390855afa158015610692573d6000803e3d6000fd5b505050602060405103519050731563915e194d8cfba1943570603f7606a311550873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610753576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f65637265636f766572206d69736d61746368000000000000000000000000000081525060200191505060405180910390fd5b50565b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561079e573d6000803e3d6000fd5b506107a7610810565b905092915050565b6000803373ffffffffffffffffffffffffffffffffffffffff166108fc600234816107d657fe5b049081150290604051600060405180830381858888f19350505050158015610802573d6000803e3d6000fd5b503334819150915091509091565b600047905090565b61022d806108268339019056fe6080604052600660005560405161022d38038061022d8339818101604052602081101561002b57600080fd5b810190808051906020019092919050505080600081905550506101da806100536000396000f3fe60806040526004361061003f5760003560e01c80632ccb1b301461004157806339c117a4146100b0578063b69ef8a8146100df578063e6a899b61461010a575b005b34801561004d57600080fd5b5061009a6004803603604081101561006457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610135565b6040518082815260200191505060405180910390f35b3480156100bc57600080fd5b506100c561018e565b604051808215151515815260200191505060405180910390f35b3480156100eb57600080fd5b506100f4610197565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b5061011f61019f565b6040518082815260200191505060405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561017d573d6000803e3d6000fd5b50610186610197565b905092915050565b60006001905090565b600047905090565b6000548156fea265627a7a72315820bc102b3933ad6112eb436087a67714bf08814e4c202d3118307a3e280f47b6cb64736f6c63430005100032a265627a7a72315820fe8c0773a06b1128d9c03d755c55071d775ebea7ee4959a672d257e75225a51064736f6c63430005100032 \ No newline at end of file +6080604052610a87806100136000396000f3fe6080604052600436106100705760003560e01c8063299fb0431161004e578063299fb043146101af5780632ccb1b30146101c65780639d9f9a6e14610235578063b69ef8a81461028657610070565b80630a84cba514610072578063111e0b12146100e757806314d54f541461015c575b005b61009e6004803603602081101561008857600080fd5b81019080803590602001909291905050506102b1565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b610113600480360360208110156100fd57600080fd5b8101908080359060200190929190505050610390565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561016857600080fd5b506101956004803603602081101561017f57600080fd5b81019080803590602001909291905050506103dc565b604051808215151515815260200191505060405180910390f35b3480156101bb57600080fd5b506101c461041e565b005b3480156101d257600080fd5b5061021f600480360360408110156101e957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610756565b6040518082815260200191505060405180910390f35b61023d6107af565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561029257600080fd5b5061029b610810565b6040518082815260200191505060405180910390f35b6000806000836040516102c390610818565b80828152602001915050604051809103906000f0801580156102e9573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610332573d6000803e3d6000fd5b508073ffffffffffffffffffffffffffffffffffffffff167fa53ffc4fb91f5ca8287e168fc73db3b0b384a6ca275650f885a1740ef7a0bc1c346040518082815260200191505060405180910390a280348191509250925050915091565b600080600034846040516103a390610818565b808281526020019150506040518091039082f0801580156103c8573d6000803e3d6000fd5b509050905080348191509250925050915091565b60007f379340f64b65a8890c7ea4f6d86d2359beaf41080f36a7ea64b78a2c06eee3f0826040518082815260200191505060405180910390a160019050919050565b7fe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556002604051806000019050602060405180830381855afa158015610467573d6000803e3d6000fd5b5050506040513d602081101561047c57600080fd5b810190808051906020019092919050505014610500576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f7368613220646967657374206d69736d6174636800000000000000000000000081525060200191505060405180910390fd5b7f9c1185a5c5e9fc54612808977ee8f548b2258d310000000000000000000000006003604051806000019050602060405180830381855afa158015610549573d6000803e3d6000fd5b5050506040515160601b6bffffffffffffffffffffffff1916146105d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f726d6431363020646967657374206d69736d617463680000000000000000000081525060200191505060405180910390fd5b60006001601b6040516000815260200160405260405180807f11111111111111111111111111111111111111111111111111111111111111118152506020018260ff168152602001807fb9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b698815250602001807f12ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb6447448152506020019150506020604051602081039080840390855afa158015610692573d6000803e3d6000fd5b505050602060405103519050731563915e194d8cfba1943570603f7606a311550873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610753576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f65637265636f766572206d69736d61746368000000000000000000000000000081525060200191505060405180910390fd5b50565b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561079e573d6000803e3d6000fd5b506107a7610810565b905092915050565b6000803373ffffffffffffffffffffffffffffffffffffffff166108fc600234816107d657fe5b049081150290604051600060405180830381858888f19350505050158015610802573d6000803e3d6000fd5b503334819150915091509091565b600047905090565b61022d806108268339019056fe6080604052600660005560405161022d38038061022d8339818101604052602081101561002b57600080fd5b810190808051906020019092919050505080600081905550506101da806100536000396000f3fe60806040526004361061003f5760003560e01c80632ccb1b301461004157806339c117a4146100b0578063b69ef8a8146100df578063e6a899b61461010a575b005b34801561004d57600080fd5b5061009a6004803603604081101561006457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610135565b6040518082815260200191505060405180910390f35b3480156100bc57600080fd5b506100c561018e565b604051808215151515815260200191505060405180910390f35b3480156100eb57600080fd5b506100f4610197565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b5061011f61019f565b6040518082815260200191505060405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561017d573d6000803e3d6000fd5b50610186610197565b905092915050565b60006001905090565b600047905090565b6000548156fea265627a7a72315820e36da559b208b35510871048d70a0d6e8f4b25035fff6508b43b8eb718e4959e64736f6c63430005100032a265627a7a72315820d93d617e67411c892e102bf050987a9d89de3c461d600c727f04c59dc88f078864736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/SubContract.bin b/runtime/near-evm-runner/tests/build/SubContract.bin deleted file mode 100644 index 54225e72d6b..00000000000 --- a/runtime/near-evm-runner/tests/build/SubContract.bin +++ /dev/null @@ -1 +0,0 @@ -6080604052600660005560405161022d38038061022d8339818101604052602081101561002b57600080fd5b810190808051906020019092919050505080600081905550506101da806100536000396000f3fe60806040526004361061003f5760003560e01c80632ccb1b301461004157806339c117a4146100b0578063b69ef8a8146100df578063e6a899b61461010a575b005b34801561004d57600080fd5b5061009a6004803603604081101561006457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610135565b6040518082815260200191505060405180910390f35b3480156100bc57600080fd5b506100c561018e565b604051808215151515815260200191505060405180910390f35b3480156100eb57600080fd5b506100f4610197565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b5061011f61019f565b6040518082815260200191505060405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561017d573d6000803e3d6000fd5b50610186610197565b905092915050565b60006001905090565b600047905090565b6000548156fea265627a7a72315820bc102b3933ad6112eb436087a67714bf08814e4c202d3118307a3e280f47b6cb64736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/TBPoolJoinExit.abi b/runtime/near-evm-runner/tests/build/TBPoolJoinExit.abi new file mode 100644 index 00000000000..8a33cf7ccaf --- /dev/null +++ b/runtime/near-evm-runner/tests/build/TBPoolJoinExit.abi @@ -0,0 +1,302 @@ +[ + { + "constant": true, + "inputs": [], + "name": "BONE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "BPOW_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXIT_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "INIT_POOL_SUPPLY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_IN_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_OUT_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_TOTAL_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BALANCE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "echidna_no_bug_found", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_records_t_balance", + "type": "uint256" + } + ], + "name": "joinAndExitPool", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/TBPoolJoinExit.bin b/runtime/near-evm-runner/tests/build/TBPoolJoinExit.bin new file mode 100644 index 00000000000..268dfee4a38 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/TBPoolJoinExit.bin @@ -0,0 +1 @@ +60806040526000805460ff1916600117905534801561001d57600080fd5b506108298061002d6000396000f3fe608060405234801561001057600080fd5b506004361061012e576000357c0100000000000000000000000000000000000000000000000000000000900480639a86139b116100ca578063bc694ea21161008e578063bc694ea2146101f2578063c36596a614610171578063c6580d12146101fa578063e4a28a5214610133578063ec093021146102025761012e565b80639a86139b146101ca578063b0e0d136146101d2578063b7b800a4146101da578063ba019dab146101e2578063bc063e1a146101ea5761012e565b806309a3bbe4146101335780631819aa421461014d578063189d00ca14610169578063218b5382146101715780632370e3a41461017957806376c7a3c7146101aa578063867378c5146101b25780639381cd2b146101ba578063992e2a92146101c2575b600080fd5b61013b61020a565b60408051918252519081900360200190f35b610155610217565b604080519115158252519081900360200190f35b61013b610220565b61013b610234565b6101a86004803603608081101561018f57600080fd5b5080359060208101359060408101359060600135610240565b005b61013b610317565b61013b610329565b61013b61033d565b61013b61034a565b61013b610356565b61013b61037a565b61013b61037f565b61013b610384565b61013b610389565b61013b610399565b61013b6103a5565b61013b6103aa565b6802b5e3af16b188000081565b60005460ff1681565b6402540be400670de0b6b3a76400005b0481565b670de0b6b3a764000081565b600061024d8584846103ba565b905068056bc75e2d6310000083111561026557600080fd5b670de0b6b3a764000083101561027a57600080fd5b678ac7230489e8000082111561028f57600080fd5b620f424082101561029f57600080fd5b6102a98386610436565b92506102b58282610436565b9150600081116102c457600080fd5b838310156102d157600080fd5b60006102de85858561049a565b9050808310156102ed57600080fd5b8486116102f957600080fd5b81811461030557600080fd5b50506000805460ff1916905550505050565b620f4240670de0b6b3a7640000610230565b64e8d4a51000670de0b6b3a7640000610230565b68056bc75e2d6310000081565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b600881565b600281565b600181565b600a670de0b6b3a7640000610230565b671bc16d674ec7ffff81565b600081565b6002670de0b6b3a7640000610230565b6000806103c78585610535565b90508061041e576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f4d4154485f415050524f580000000000000000000000000000000000604482015290519081900360640190fd5b82600061042b838361067c565b979650505050505050565b600082820183811015610493576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4144445f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b9392505050565b6000806104a885600061067c565b905060006104b6868361075e565b905060006104c48287610535565b90508061051b576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f4d4154485f415050524f580000000000000000000000000000000000604482015290519081900360640190fd5b846000610528838361067c565b9998505050505050505050565b60008161058c576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4449565f5a45524f0000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a764000083028315806105b45750670de0b6b3a76400008482816105b157fe5b04145b610608576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b60028304810181811015610666576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b600084828161067157fe5b049695505050505050565b600082820283158061069657508284828161069357fe5b04145b6106ea576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6706f05b59d3b2000081018181101561074d576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6000670de0b6b3a764000082610671565b600080600061076d85856107cf565b9150915080156107c7576040805160e560020a62461bcd02815260206004820152601160248201527f4552525f5355425f554e444552464c4f57000000000000000000000000000000604482015290519081900360640190fd5b509392505050565b6000808284106107e557505080820360006107ed565b505081810360015b925092905056fea265627a7a723158201790844e1e2552cec4a67cc6ca52dd783178e8f791461ba35e1a0422e236dca664736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/TBPoolJoinExitNoFee.abi b/runtime/near-evm-runner/tests/build/TBPoolJoinExitNoFee.abi new file mode 100644 index 00000000000..f47c54d1493 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/TBPoolJoinExitNoFee.abi @@ -0,0 +1,302 @@ +[ + { + "constant": true, + "inputs": [], + "name": "BONE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "BPOW_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXIT_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "INIT_POOL_SUPPLY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_IN_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_OUT_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_TOTAL_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BALANCE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "echidna_no_bug_found", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_records_t_balance", + "type": "uint256" + } + ], + "name": "joinAndExitNoFeePool", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/TBPoolJoinExitNoFee.bin b/runtime/near-evm-runner/tests/build/TBPoolJoinExitNoFee.bin new file mode 100644 index 00000000000..a42713dc1ac --- /dev/null +++ b/runtime/near-evm-runner/tests/build/TBPoolJoinExitNoFee.bin @@ -0,0 +1 @@ +60806040526000805460ff1916600117905534801561001d57600080fd5b506106f88061002d6000396000f3fe608060405234801561001057600080fd5b506004361061012e576000357c010000000000000000000000000000000000000000000000000000000090048063b0e0d136116100ca578063c36596a61161008e578063c36596a614610171578063c6580d12146101c9578063e15c7d42146101d1578063e4a28a5214610133578063ec093021146102025761012e565b8063b0e0d136146101a1578063b7b800a4146101a9578063ba019dab146101b1578063bc063e1a146101b9578063bc694ea2146101c15761012e565b806309a3bbe4146101335780631819aa421461014d578063189d00ca14610169578063218b53821461017157806376c7a3c714610179578063867378c5146101815780639381cd2b14610189578063992e2a92146101915780639a86139b14610199575b600080fd5b61013b61020a565b60408051918252519081900360200190f35b610155610217565b604080519115158252519081900360200190f35b61013b610220565b61013b610234565b61013b610240565b61013b610252565b61013b610266565b61013b610273565b61013b61027f565b61013b6102a3565b61013b6102a8565b61013b6102ad565b61013b6102b2565b61013b6102c2565b61013b6102ce565b610200600480360360808110156101e757600080fd5b50803590602081013590604081013590606001356102d3565b005b61013b6103aa565b6802b5e3af16b188000081565b60005460ff1681565b6402540be400670de0b6b3a76400005b0481565b670de0b6b3a764000081565b620f4240670de0b6b3a7640000610230565b64e8d4a51000670de0b6b3a7640000610230565b68056bc75e2d6310000081565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b600881565b600281565b600181565b600a670de0b6b3a7640000610230565b671bc16d674ec7ffff81565b600081565b60006102e08584846103ba565b905068056bc75e2d631000008311156102f857600080fd5b670de0b6b3a764000083101561030d57600080fd5b678ac7230489e8000082111561032257600080fd5b620f424082101561033257600080fd5b61033c8386610436565b92506103488282610436565b91506000811161035757600080fd5b8383101561036457600080fd5b60006103718585856103ba565b90508083101561038057600080fd5b84861161038c57600080fd5b81811461039857600080fd5b50506000805460ff1916905550505050565b6002670de0b6b3a7640000610230565b6000806103c7858561049a565b90508061041e576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f4d4154485f415050524f580000000000000000000000000000000000604482015290519081900360640190fd5b82600061042b83836105e1565b979650505050505050565b600082820183811015610493576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4144445f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b9392505050565b6000816104f1576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4449565f5a45524f0000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a764000083028315806105195750670de0b6b3a764000084828161051657fe5b04145b61056d576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b600283048101818110156105cb576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b60008482816105d657fe5b049695505050505050565b60008282028315806105fb5750828482816105f857fe5b04145b61064f576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6706f05b59d3b200008101818110156106b2576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6000670de0b6b3a7640000826105d656fea265627a7a72315820ed2924388694d36bdbe4d7941a0e87d38ab5eeb0b511a244b36f45486e75febf64736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/TBPoolJoinPool.abi b/runtime/near-evm-runner/tests/build/TBPoolJoinPool.abi new file mode 100644 index 00000000000..6f3372807ae --- /dev/null +++ b/runtime/near-evm-runner/tests/build/TBPoolJoinPool.abi @@ -0,0 +1,303 @@ +[ + { + "constant": true, + "inputs": [], + "name": "BONE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "BPOW_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXIT_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "INIT_POOL_SUPPLY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_IN_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_OUT_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_TOTAL_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BALANCE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "echidna_no_bug_found", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_records_t_balance", + "type": "uint256" + } + ], + "name": "joinPool", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/TBPoolJoinPool.bin b/runtime/near-evm-runner/tests/build/TBPoolJoinPool.bin new file mode 100644 index 00000000000..65ea9d6ab16 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/TBPoolJoinPool.bin @@ -0,0 +1 @@ +60806040526000805460ff1916600117905534801561001d57600080fd5b506106298061002d6000396000f3fe608060405234801561001057600080fd5b506004361061012e576000357c0100000000000000000000000000000000000000000000000000000000900480639a86139b116100ca578063bc694ea21161008e578063bc694ea2146101ea578063c36596a614610171578063c6580d12146101f2578063e4a28a5214610133578063ec093021146101fa5761012e565b80639a86139b146101c2578063b0e0d136146101ca578063b7b800a4146101d2578063ba019dab146101da578063bc063e1a146101e25761012e565b806309a3bbe4146101335780631819aa421461014d578063189d00ca14610169578063218b5382146101715780632e6884451461017957806376c7a3c7146101a2578063867378c5146101aa5780639381cd2b146101b2578063992e2a92146101ba575b600080fd5b61013b610202565b60408051918252519081900360200190f35b61015561020f565b604080519115158252519081900360200190f35b61013b610218565b61013b61022c565b61013b6004803603606081101561018f57600080fd5b5080359060208101359060400135610238565b61013b610328565b61013b61033a565b61013b61034e565b61013b61035b565b61013b610367565b61013b61038b565b61013b610390565b61013b610395565b61013b61039a565b61013b6103aa565b61013b6103b6565b61013b6103bb565b6802b5e3af16b188000081565b60005460ff1681565b6402540be400670de0b6b3a76400005b0481565b670de0b6b3a764000081565b600068056bc75e2d6310000083111561025057600080fd5b670de0b6b3a764000083101561026557600080fd5b678ac7230489e8000082111561027a57600080fd5b620f424082101561028a57600080fd5b600061029685856103cb565b9050806102ed576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f4d4154485f415050524f580000000000000000000000000000000000604482015290519081900360640190fd5b8260006102fa8383610512565b90506000871161030957600080fd5b801561031457600080fd5b50506000805460ff19169055509392505050565b620f4240670de0b6b3a7640000610228565b64e8d4a51000670de0b6b3a7640000610228565b68056bc75e2d6310000081565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b600881565b600281565b600181565b600a670de0b6b3a7640000610228565b671bc16d674ec7ffff81565b600081565b6002670de0b6b3a7640000610228565b600081610422576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4449565f5a45524f0000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a7640000830283158061044a5750670de0b6b3a764000084828161044757fe5b04145b61049e576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b600283048101818110156104fc576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b600084828161050757fe5b049695505050505050565b600082820283158061052c57508284828161052957fe5b04145b610580576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6706f05b59d3b200008101818110156105e3576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6000670de0b6b3a76400008261050756fea265627a7a72315820f0f26278e3fc3369c41e852dd72450e07aafa81526408f333ccee8c0e34ee4c364736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/TMath.abi b/runtime/near-evm-runner/tests/build/TMath.abi new file mode 100644 index 00000000000..14a08506688 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/TMath.abi @@ -0,0 +1,834 @@ +[ + { + "constant": true, + "inputs": [], + "name": "BONE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "BPOW_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXIT_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "INIT_POOL_SUPPLY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_IN_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_OUT_RATIO", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_TOTAL_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BALANCE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BOUND_TOKENS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_BPOW_BASE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MIN_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcInGivenOut", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcOutGivenIn", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcPoolInGivenSingleOut", + "outputs": [ + { + "internalType": "uint256", + "name": "poolAmountIn", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcPoolOutGivenSingleIn", + "outputs": [ + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcSingleInGivenPoolOut", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountIn", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "poolAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcSingleOutGivenPoolIn", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenAmountOut", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "tokenBalanceIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenBalanceOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenWeightOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFee", + "type": "uint256" + } + ], + "name": "calcSpotPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "spotPrice", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getColor", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + } + ], + "name": "calc_btoi", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + } + ], + "name": "calc_bfloor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "b", + "type": "uint256" + } + ], + "name": "calc_badd", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "b", + "type": "uint256" + } + ], + "name": "calc_bsub", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "b", + "type": "uint256" + } + ], + "name": "calc_bsubSign", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "b", + "type": "uint256" + } + ], + "name": "calc_bmul", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "b", + "type": "uint256" + } + ], + "name": "calc_bdiv", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "n", + "type": "uint256" + } + ], + "name": "calc_bpowi", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "base", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exp", + "type": "uint256" + } + ], + "name": "calc_bpow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "base", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "precision", + "type": "uint256" + } + ], + "name": "calc_bpowApprox", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/TMath.bin b/runtime/near-evm-runner/tests/build/TMath.bin new file mode 100644 index 00000000000..4a14f446467 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/TMath.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506110df806100206000396000f3fe608060405234801561001057600080fd5b50600436106101e3576000357c010000000000000000000000000000000000000000000000000000000090048063b0e0d13611610117578063c36596a6116100ba578063c36596a614610250578063c6580d12146104a9578063c6b3199d146104b1578063cd094b14146104ce578063e4a28a52146101e8578063ec093021146104f1578063f5f5b148146104f9578063f760324b1461051c578063f8d6aed41461053f576101e3565b8063b0e0d136146103ed578063b58d3e70146103f5578063b65fcf4014610412578063b7b800a41461044e578063ba019dab14610456578063ba9530a61461045e578063bc063e1a14610499578063bc694ea2146104a1576101e3565b806382f652ad1161018a57806382f652ad146102c45780638656b653146102ff578063867378c51461033a578063872289ab1461034257806389298012146103655780639381cd2b146103a0578063992e2a92146103a85780639a86139b146103b0578063a221ee49146103b8576101e3565b806309a3bbe4146101e8578063189d00ca146102025780631bcaf56f1461020a5780631fdee4071461022d578063218b53821461025057806331124372146102585780635c1bbaf71461028157806376c7a3c7146102bc575b600080fd5b6101f061057a565b60408051918252519081900360200190f35b6101f0610587565b6101f06004803603604081101561022057600080fd5b508035906020013561059b565b6101f06004803603604081101561024357600080fd5b50803590602001356105b0565b6101f06105bc565b6101f06004803603606081101561026e57600080fd5b50803590602081013590604001356105c8565b6101f0600480360360c081101561029757600080fd5b5080359060208101359060408101359060608101359060808101359060a001356105dd565b6101f0610695565b6101f0600480360360c08110156102da57600080fd5b5080359060208101359060408101359060608101359060808101359060a001356106a7565b6101f0600480360360c081101561031557600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610766565b6101f0610807565b6101f06004803603604081101561035857600080fd5b508035906020013561081b565b6101f0600480360360c081101561037b57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610827565b6101f06108d7565b6101f06108e4565b6101f06108f0565b6101f0600480360360a08110156103ce57600080fd5b5080359060208101359060408101359060608101359060800135610914565b6101f0610979565b6101f06004803603602081101561040b57600080fd5b503561097e565b6104356004803603604081101561042857600080fd5b5080359060200135610989565b6040805192835290151560208301528051918290030190f35b6101f06109a2565b6101f06109a7565b6101f0600480360360c081101561047457600080fd5b5080359060208101359060408101359060608101359060808101359060a001356109ac565b6101f0610a2d565b6101f0610a3d565b6101f0610a49565b6101f0600480360360208110156104c757600080fd5b5035610a4e565b6101f0600480360360408110156104e457600080fd5b5080359060200135610a59565b6101f0610a65565b6101f06004803603604081101561050f57600080fd5b5080359060200135610a75565b6101f06004803603604081101561053257600080fd5b5080359060200135610a81565b6101f0600480360360c081101561055557600080fd5b5080359060208101359060408101359060608101359060808101359060a00135610a8d565b6802b5e3af16b188000081565b6402540be400670de0b6b3a76400005b0481565b60006105a78383610b10565b90505b92915050565b60006105a78383610b81565b670de0b6b3a764000081565b60006105d5848484610cc8565b949350505050565b6000806105ea8786610b81565b905060006105f88786610da6565b905060006106068289610b81565b9050600061061c670de0b6b3a764000085610b81565b9050600061062a8383610e03565b90506000610638828e610f26565b90506000610646828f610b10565b9050600061066561065f670de0b6b3a76400008a610b10565b8b610f26565b90506106828261067d670de0b6b3a764000084610b10565b610b81565b9f9e505050505050505050505050505050565b620f4240670de0b6b3a7640000610597565b6000806106b48786610b81565b905060006106ca670de0b6b3a764000083610b10565b905060006106d88286610f26565b905060006106f28761067d670de0b6b3a764000085610b10565b905060006107008c83610b10565b9050600061070e828e610b81565b9050600061071c8288610e03565b9050600061072a828e610f26565b905060006107388e83610b10565b90506107518161067d670de0b6b3a76400006000610b10565b99505050505050505050509695505050505050565b6000806107738786610b81565b9050600061079261078c670de0b6b3a764000084610b10565b85610f26565b905060006107b1866107ac670de0b6b3a764000085610b10565b610f26565b905060006107bf8b83610da6565b905060006107cd828d610b81565b905060006107db8287610e03565b905060006107e9828d610f26565b90506107f5818d610b10565b9e9d5050505050505050505050505050565b64e8d4a51000670de0b6b3a7640000610597565b60006105a78383610da6565b6000806108348786610b81565b9050600061084f856107ac670de0b6b3a76400006000610b10565b9050600061085d8883610b10565b9050600061086b828a610b81565b9050600061088a82610885670de0b6b3a764000088610b81565b610e03565b90506000610898828e610f26565b905060006108a68e83610b10565b905060006108bf61065f670de0b6b3a76400008a610b10565b9050610682826107ac670de0b6b3a764000084610b10565b68056bc75e2d6310000081565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b6000806109218787610b81565b9050600061092f8686610b81565b9050600061093d8383610b81565b9050600061095f670de0b6b3a764000061067d670de0b6b3a764000089610b10565b905061096b8282610f26565b9a9950505050505050505050565b600881565b60006105aa82611008565b6000806109968484611023565b915091505b9250929050565b600281565b600181565b6000806109b98786610b81565b905060006109cf670de0b6b3a764000085610b10565b90506109db8582610f26565b905060006109ed8a61067d8c85610da6565b905060006109fb8285610e03565b90506000610a11670de0b6b3a764000083610b10565b9050610a1d8a82610f26565b9c9b505050505050505050505050565b600a670de0b6b3a7640000610597565b671bc16d674ec7ffff81565b600081565b60006105aa82611045565b60006105a78383610f26565b6002670de0b6b3a7640000610597565b60006105a78383610e03565b60006105a78383611053565b600080610a9a8588610b81565b90506000610aa88786610b10565b90506000610ab68883610b81565b90506000610ac48285610e03565b9050610ad881670de0b6b3a7640000610b10565b9050610aec670de0b6b3a764000087610b10565b9450610b01610afb8c83610f26565b86610b81565b9b9a5050505050505050505050565b6000806000610b1f8585611023565b915091508015610b79576040805160e560020a62461bcd02815260206004820152601160248201527f4552525f5355425f554e444552464c4f57000000000000000000000000000000604482015290519081900360640190fd5b509392505050565b600081610bd8576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4449565f5a45524f0000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a76400008302831580610c005750670de0b6b3a7640000848281610bfd57fe5b04145b610c54576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b60028304810181811015610cb2576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4449565f494e5445524e414c00000000000000000000000000000000604482015290519081900360640190fd5b6000848281610cbd57fe5b049695505050505050565b6000828180610cdf87670de0b6b3a7640000611023565b9092509050670de0b6b3a764000080600060015b888410610d97576000670de0b6b3a764000082029050600080610d278a610d2285670de0b6b3a7640000610b10565b611023565b91509150610d39876107ac848c610f26565b9650610d458784610b81565b965086610d5457505050610d97565b8715610d5e579315935b8015610d68579315935b8415610d7f57610d788688610b10565b9550610d8c565b610d898688610da6565b95505b505050600101610cf3565b50909998505050505050505050565b6000828201838110156105a7576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4144445f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b60006001831015610e5e576040805160e560020a62461bcd02815260206004820152601560248201527f4552525f42504f575f424153455f544f4f5f4c4f570000000000000000000000604482015290519081900360640190fd5b671bc16d674ec7ffff831115610ebe576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f42504f575f424153455f544f4f5f4849474800000000000000000000604482015290519081900360640190fd5b6000610ec983611008565b90506000610ed78483610b10565b90506000610eed86610ee885611045565b611053565b905081610efe5792506105aa915050565b6000610f0f87846305f5e100610cc8565b9050610f1b8282610f26565b979650505050505050565b6000828202831580610f40575082848281610f3d57fe5b04145b610f94576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6706f05b59d3b20000810181811015610ff7576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f4d554c5f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b6000670de0b6b3a764000082610cbd565b6000670de0b6b3a764000061101c83611045565b0292915050565b600080828410611039575050808203600061099b565b5050818103600161099b565b670de0b6b3a7640000900490565b6000806002830661106c57670de0b6b3a764000061106e565b835b90506002830492505b82156105a7576110878485610f26565b9350600283061561109f5761109c8185610f26565b90505b60028304925061107756fea265627a7a72315820ba5c88696fa9a89794667fd441404d301fffcf81987230fc5eda2a8253a37e0a64736f6c634300050c0032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/build/TToken.abi b/runtime/near-evm-runner/tests/build/TToken.abi new file mode 100644 index 00000000000..12a64cc0432 --- /dev/null +++ b/runtime/near-evm-runner/tests/build/TToken.abi @@ -0,0 +1,311 @@ +[ + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "whom", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amt", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/zombieAttack.bin b/runtime/near-evm-runner/tests/build/zombieAttack.bin index 3e21cb25c22..dd6826bc417 100644 --- a/runtime/near-evm-runner/tests/build/zombieAttack.bin +++ b/runtime/near-evm-runner/tests/build/zombieAttack.bin @@ -1 +1 @@ -60606040526010600155600154600a0a6002556201518060035566038d7ea4c6800060085560006009556046600a55336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506119d28061007d6000396000f3006060604052600436106100d0576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630ce90ec2146100d557806317a7f4cc146100ed5780632052465e146101195780633ccfd60b1461021d5780634412e10414610232578063528b7b8f146102c05780635f4623f1146103235780635faf28801461035c5780637bff0a01146103885780638da5cb5b146103e5578063c39cbef11461043a578063ccf670f814610471578063e1fa763814610494578063f2fde38b146104c0575b600080fd5b6100eb60048080359060200190919050506104f9565b005b34156100f857600080fd5b6101176004808035906020019091908035906020019091905050610565565b005b341561012457600080fd5b61013a60048080359060200190919050506106d2565b60405180806020018781526020018663ffffffff1663ffffffff1681526020018563ffffffff1663ffffffff1681526020018461ffff1661ffff1681526020018361ffff1661ffff1681526020018281038252888181546001816001161561010002031660029004815260200191508054600181600116156101000203166002900480156102095780601f106101de57610100808354040283529160200191610209565b820191906000526020600020905b8154815290600101906020018083116101ec57829003601f168201915b505097505050505050505060405180910390f35b341561022857600080fd5b610230610758565b005b341561023d57600080fd5b610269600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061082d565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156102ac578082015181840152602081019050610291565b505050509050019250505060405180910390f35b34156102cb57600080fd5b6102e1600480803590602001909190505061095b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561032e57600080fd5b61035a600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061098e565b005b341561036757600080fd5b6103866004808035906020019091908035906020019091905050610a2d565b005b341561039357600080fd5b6103e3600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610b0f565b005b34156103f057600080fd5b6103f8610b88565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561044557600080fd5b61046f60048080359060200190919080359060200190820180359060200191909192905050610bad565b005b341561047c57600080fd5b6104926004808035906020019091905050610c9b565b005b341561049f57600080fd5b6104be6004808035906020019091908035906020019091905050610d00565b005b34156104cb57600080fd5b6104f7600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610f93565b005b6008543414151561050957600080fd5b60048181548110151561051857fe5b9060005260206000209060030201600201600081819054906101000a900463ffffffff168092919060010191906101000a81548163ffffffff021916908363ffffffff1602179055505050565b6000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e98b7f4d83600060405161014001526040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018082815260200191505061014060405180830381600087803b151561060257600080fd5b6102c65a03f1151561061357600080fd5b50505060405180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519050909192939495969798509091929394959697509091929394959650909192939495509091929394509091929350909192509091509050809150506106cd83826040805190810160405280600581526020017f6b697474790000000000000000000000000000000000000000000000000000008152506110e8565b505050565b6004818154811015156106e157fe5b906000526020600020906003020160009150905080600001908060010154908060020160009054906101000a900463ffffffff16908060020160049054906101000a900463ffffffff16908060020160089054906101000a900461ffff169080600201600a9054906101000a900461ffff16905086565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156107b357600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050151561082b57600080fd5b565b610835611764565b61083d611764565b600080600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460405180591061088d5750595b9080825280602002602001820160405250925060009150600090505b600480549050811015610950578473ffffffffffffffffffffffffffffffffffffffff166005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156109435780838381518110151561092c57fe5b906020019060200201818152505081806001019250505b80806001019150506108a9565b829350505050919050565b60056020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156109e957600080fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60148281600482815481101515610a4057fe5b906000526020600020906003020160020160009054906101000a900463ffffffff1663ffffffff1610151515610a7557600080fd5b836005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610ae357600080fd5b83600486815481101515610af357fe5b9060005260206000209060030201600101819055505050505050565b600080600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054141515610b5e57600080fd5b610b67826112bd565b9050606481811515610b7557fe5b0681039050610b84828261133f565b5050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60028381600482815481101515610bc057fe5b906000526020600020906003020160020160009054906101000a900463ffffffff1663ffffffff1610151515610bf557600080fd5b846005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610c6357600080fd5b8484600488815481101515610c7457fe5b90600052602060002090600302016000019190610c92929190611778565b50505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610cf657600080fd5b8060088190555050565b6000806000846005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d7357600080fd5b600486815481101515610d8257fe5b90600052602060002090600302019350600485815481101515610da157fe5b90600052602060002090600302019250610dbb606461160e565b9150600a5482111515610ef157610df260018560020160089054906101000a900461ffff1661ffff166116a590919063ffffffff16565b8460020160086101000a81548161ffff021916908361ffff160217905550610e3e60018560020160009054906101000a900463ffffffff1663ffffffff166116cb90919063ffffffff16565b8460020160006101000a81548163ffffffff021916908363ffffffff160217905550610e8a600184600201600a9054906101000a900461ffff1661ffff166116a590919063ffffffff16565b83600201600a6101000a81548161ffff021916908361ffff160217905550610eec8684600101546040805190810160405280600681526020017f7a6f6d62696500000000000000000000000000000000000000000000000000008152506110e8565b610f8b565b610f1b600185600201600a9054906101000a900461ffff1661ffff166116a590919063ffffffff16565b84600201600a6101000a81548161ffff021916908361ffff160217905550610f6360018460020160089054906101000a900461ffff1661ffff166116a590919063ffffffff16565b8360020160086101000a81548161ffff021916908361ffff160217905550610f8a846116f5565b5b505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610fee57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561102a57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600080846005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561115957600080fd5b60048681548110151561116857fe5b906000526020600020906003020192506111818361171f565b151561118c57600080fd5b6002548581151561119957fe5b0694506002858460010154018115156111ae57fe5b04915060405180807f6b697474790000000000000000000000000000000000000000000000000000008152506005019050604051809103902060001916846040518082805190602001908083835b60208310151561122157805182526020820191506020810190506020830392506111fc565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916141561126d57606360648381151561126657fe5b0683030191505b6112ac6040805190810160405280600681526020017f4e6f4e616d6500000000000000000000000000000000000000000000000000008152508361133f565b6112b5836116f5565b505050505050565b600080826040518082805190602001908083835b6020831015156112f657805182526020820191506020810190506020830392506112d1565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206001900490506002548181151561133657fe5b06915050919050565b600060016004805480600101828161135791906117f8565b9160005260206000209060030201600060c060405190810160405280888152602001878152602001600163ffffffff168152602001600354420163ffffffff168152602001600061ffff168152602001600061ffff16815250909190915060008201518160000190805190602001906113d192919061182a565b506020820151816001015560408201518160020160006101000a81548163ffffffff021916908363ffffffff16021790555060608201518160020160046101000a81548163ffffffff021916908363ffffffff16021790555060808201518160020160086101000a81548161ffff021916908361ffff16021790555060a082015181600201600a6101000a81548161ffff021916908361ffff1602179055505050039050336005600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061151a6001600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461174690919063ffffffff16565b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f88f026aacbbecc90c18411df4b1185fd8d9be2470f1962f192bf84a27d0704b78184846040518084815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156115cd5780820151818401526020810190506115b2565b50505050905090810190601f1680156115fa5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1505050565b6000611626600160095461174690919063ffffffff16565b600981905550814233600954604051808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401828152602001935050505060405180910390206001900481151561169d57fe5b069050919050565b60008082840190508361ffff168161ffff16101515156116c157fe5b8091505092915050565b60008082840190508363ffffffff168163ffffffff16101515156116eb57fe5b8091505092915050565b60035442018160020160046101000a81548163ffffffff021916908363ffffffff16021790555050565b6000428260020160049054906101000a900463ffffffff1663ffffffff1611159050919050565b600080828401905083811015151561175a57fe5b8091505092915050565b602060405190810160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106117b957803560ff19168380011785556117e7565b828001600101855582156117e7579182015b828111156117e65782358255916020019190600101906117cb565b5b5090506117f491906118aa565b5090565b8154818355818115116118255760030281600302836000526020600020918201910161182491906118cf565b5b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061186b57805160ff1916838001178555611899565b82800160010185558215611899579182015b8281111561189857825182559160200191906001019061187d565b5b5090506118a691906118aa565b5090565b6118cc91905b808211156118c85760008160009055506001016118b0565b5090565b90565b61195b91905b8082111561195757600080820160006118ee919061195e565b60018201600090556002820160006101000a81549063ffffffff02191690556002820160046101000a81549063ffffffff02191690556002820160086101000a81549061ffff021916905560028201600a6101000a81549061ffff0219169055506003016118d5565b5090565b90565b50805460018160011615610100020316600290046000825580601f1061198457506119a3565b601f0160209004906000526020600020908101906119a291906118aa565b5b505600a165627a7a72305820132b51da42f560f7184ac5aae47f26c9658881610ed4c49b0c5c00f7456864e60029 \ No newline at end of file +6080604052610a87806100136000396000f3fe6080604052600436106100705760003560e01c8063299fb0431161004e578063299fb043146101af5780632ccb1b30146101c65780639d9f9a6e14610235578063b69ef8a81461028657610070565b80630a84cba514610072578063111e0b12146100e757806314d54f541461015c575b005b61009e6004803603602081101561008857600080fd5b81019080803590602001909291905050506102b1565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b610113600480360360208110156100fd57600080fd5b8101908080359060200190929190505050610390565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561016857600080fd5b506101956004803603602081101561017f57600080fd5b81019080803590602001909291905050506103dc565b604051808215151515815260200191505060405180910390f35b3480156101bb57600080fd5b506101c461041e565b005b3480156101d257600080fd5b5061021f600480360360408110156101e957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610756565b6040518082815260200191505060405180910390f35b61023d6107af565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561029257600080fd5b5061029b610810565b6040518082815260200191505060405180910390f35b6000806000836040516102c390610818565b80828152602001915050604051809103906000f0801580156102e9573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610332573d6000803e3d6000fd5b508073ffffffffffffffffffffffffffffffffffffffff167fa53ffc4fb91f5ca8287e168fc73db3b0b384a6ca275650f885a1740ef7a0bc1c346040518082815260200191505060405180910390a280348191509250925050915091565b600080600034846040516103a390610818565b808281526020019150506040518091039082f0801580156103c8573d6000803e3d6000fd5b509050905080348191509250925050915091565b60007f379340f64b65a8890c7ea4f6d86d2359beaf41080f36a7ea64b78a2c06eee3f0826040518082815260200191505060405180910390a160019050919050565b7fe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556002604051806000019050602060405180830381855afa158015610467573d6000803e3d6000fd5b5050506040513d602081101561047c57600080fd5b810190808051906020019092919050505014610500576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f7368613220646967657374206d69736d6174636800000000000000000000000081525060200191505060405180910390fd5b7f9c1185a5c5e9fc54612808977ee8f548b2258d310000000000000000000000006003604051806000019050602060405180830381855afa158015610549573d6000803e3d6000fd5b5050506040515160601b6bffffffffffffffffffffffff1916146105d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f726d6431363020646967657374206d69736d617463680000000000000000000081525060200191505060405180910390fd5b60006001601b6040516000815260200160405260405180807f11111111111111111111111111111111111111111111111111111111111111118152506020018260ff168152602001807fb9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b698815250602001807f12ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb6447448152506020019150506020604051602081039080840390855afa158015610692573d6000803e3d6000fd5b505050602060405103519050731563915e194d8cfba1943570603f7606a311550873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610753576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f65637265636f766572206d69736d61746368000000000000000000000000000081525060200191505060405180910390fd5b50565b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561079e573d6000803e3d6000fd5b506107a7610810565b905092915050565b6000803373ffffffffffffffffffffffffffffffffffffffff166108fc600234816107d657fe5b049081150290604051600060405180830381858888f19350505050158015610802573d6000803e3d6000fd5b503334819150915091509091565b600047905090565b61022d806108268339019056fe6080604052600660005560405161022d38038061022d8339818101604052602081101561002b57600080fd5b810190808051906020019092919050505080600081905550506101da806100536000396000f3fe60806040526004361061003f5760003560e01c80632ccb1b301461004157806339c117a4146100b0578063b69ef8a8146100df578063e6a899b61461010a575b005b34801561004d57600080fd5b5061009a6004803603604081101561006457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610135565b6040518082815260200191505060405180910390f35b3480156100bc57600080fd5b506100c561018e565b604051808215151515815260200191505060405180910390f35b3480156100eb57600080fd5b506100f4610197565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b5061011f61019f565b6040518082815260200191505060405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561017d573d6000803e3d6000fd5b50610186610197565b905092915050565b60006001905090565b600047905090565b6000548156fea265627a7a72315820f6f44f505670bac22a9333cd975c317fbaa88dc23152a224b1341fc02dd8764264736f6c63430005100032a265627a7a723158205890404b6d6a9f080f4d5156523ec567b299609c5d3e45e4baf5c0ee35c7a68764736f6c63430005100032 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/contracts/SolTests.sol b/runtime/near-evm-runner/tests/contracts/SolTests.sol index 0e6973c4e46..cda1f28a318 100644 --- a/runtime/near-evm-runner/tests/contracts/SolTests.sol +++ b/runtime/near-evm-runner/tests/contracts/SolTests.sol @@ -78,3 +78,83 @@ contract SubContract is ExposesBalance { function () external payable {} } + +contract PrecompiledFunction { + constructor() public payable {} + + function noop() public pure { + + } + + function testSha256() public pure returns (bytes32) { + return sha256(""); + } + + function testSha256_100bytes() public pure returns (bytes32) { + return sha256("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw"); + } + + function testEcrecover() public pure returns (address) { + return ecrecover( + hex"1111111111111111111111111111111111111111111111111111111111111111", + 27, + hex"b9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b698", // r + hex"12ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb644744" // s + ); + } + + function testRipemd160() public pure returns (bytes20) { + return ripemd160(""); + } + + function testRipemd160_1kb() public pure returns (bytes20) { + return ripemd160("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij"); + } + + function identity(bytes memory data) public returns (bytes memory) { + bytes memory ret = new bytes(data.length); + assembly { + let len := mload(data) + if iszero(call(gas, 0x04, 0, add(data, 0x20), len, add(ret,0x20), len)) { + invalid() + } + } + + return ret; + } + + function test_identity() public returns (bytes memory) { + return identity(""); + } + + function test_identity_100bytes() public returns (bytes memory) { + return identity("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw"); + } + + function modexp(uint base, uint e, uint m) public view returns (uint o) { + assembly { + // define pointer + let p := mload(0x40) + // store data assembly-favouring ways + mstore(p, 0x20) // Length of Base + mstore(add(p, 0x20), 0x20) // Length of Exponent + mstore(add(p, 0x40), 0x20) // Length of Modulus + mstore(add(p, 0x60), base) // Base + mstore(add(p, 0x80), e) // Exponent + mstore(add(p, 0xa0), m) // Modulus + if iszero(staticcall(sub(gas, 2000), 0x05, p, 0xc0, p, 0x20)) { + revert(0, 0) + } + // data + o := mload(p) + } + } + + function testModExp() public view returns (uint) { + return modexp(12345, 173, 101); + } + + function testBn128Add() public pure returns (uint) { + + } +} \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index 30789eb9971..d25d7ce3aab 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -42,9 +42,15 @@ pub fn create_context<'a>( 0, 10u64.pow(14), false, + 1_000_000_000.into(), ) } +#[cfg(test)] +pub fn show_evm_gas_used(context: &EvmContext) { + println!("Accumulated EVM gas used: {}", &context.evm_gas_counter.used_gas); +} + /// Linter is suboptimal, because doesn't see that this is used in standard_ops.rs. #[allow(dead_code)] pub fn public_key_to_address(public_key: PublicKey) -> Address { diff --git a/runtime/near-runtime-fees/src/lib.rs b/runtime/near-runtime-fees/src/lib.rs index f357c2d3456..8d004a87c05 100644 --- a/runtime/near-runtime-fees/src/lib.rs +++ b/runtime/near-runtime-fees/src/lib.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; pub type Balance = u128; pub type Gas = u64; +pub type EvmGas = u64; /// The amount is 1000 * 10e24 = 1000 NEAR. const EVM_DEPOSIT: Balance = 1_000_000_000_000_000_000_000_000_000; @@ -72,6 +73,10 @@ pub struct RuntimeFeesConfig { /// Pessimistic gas price inflation ratio. pub pessimistic_gas_price_inflation_ratio: Rational, + /// Describes cost of running method of evm, include deploy code and call contract function + pub evm_config: EvmCostConfig, + + /// New EVM deposit. /// Fee to create new EVM account. #[serde(with = "u128_dec_format", default = "default_evm_deposit")] pub evm_deposit: Balance, @@ -147,6 +152,27 @@ pub struct StorageUsageConfig { pub num_extra_bytes_record: u64, } +/// Describe cost of evm +#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)] +pub struct EvmCostConfig { + /// Base cost of instantiate an evm instance for any evm operation + pub bootstrap_cost: Gas, + /// For every unit of gas used by evm in deploy evm contract, equivalent near gas cost + pub deploy_cost_per_evm_gas: Gas, + /// For every byte of evm contract, result near gas cost + pub deploy_cost_per_byte: Gas, + /// For bootstrapped evm, base cost to invoke a contract function + pub funcall_cost_base: Gas, + /// For every unit of gas used by evm in funcall, equivalent near gas cost + pub funcall_cost_per_evm_gas: Gas, + /// Evm precompiled function costs, note cost is in evm gas unit. + pub ecrecover_cost: EvmGas, + pub sha256_cost: EvmGas, + pub ripemd160_cost: EvmGas, + pub identity_cost: EvmGas, + pub modexp_cost: EvmGas, +} + impl Default for RuntimeFeesConfig { fn default() -> Self { #[allow(clippy::unreadable_literal)] @@ -240,6 +266,21 @@ impl Default for RuntimeFeesConfig { }, burnt_gas_reward: Rational::new(3, 10), pessimistic_gas_price_inflation_ratio: Rational::new(103, 100), + evm_config: EvmCostConfig { + // Got inside emu-cost docker, numbers differ slightly in different runs: + // cd /host/nearcore/runtime/near-evm-runner/tests + // ../../runtime-params-estimator/emu-cost/counter_plugin/qemu-x86_64 -cpu Westmere-v1 -plugin file=../../runtime-params-estimator/emu-cost/counter_plugin/libcounter.so ../../../target/release/runtime-params-estimator --home /tmp/data --accounts-num 200000 --iters 1 --warmup-iters 1 --evm-only + bootstrap_cost: 373945633846, + deploy_cost_per_evm_gas: 3004467, + deploy_cost_per_byte: 2732257, + funcall_cost_base: 300126401250, + funcall_cost_per_evm_gas: 116076934, + ecrecover_cost: 2418, + sha256_cost: 56, + ripemd160_cost: 52, + identity_cost: 115, + modexp_cost: 90, + }, evm_deposit: EVM_DEPOSIT, } } @@ -276,6 +317,18 @@ impl RuntimeFeesConfig { }, burnt_gas_reward: Rational::from_integer(0), pessimistic_gas_price_inflation_ratio: Rational::from_integer(0), + evm_config: EvmCostConfig { + bootstrap_cost: 0, + deploy_cost_per_evm_gas: 0, + deploy_cost_per_byte: 0, + funcall_cost_base: 0, + funcall_cost_per_evm_gas: 0, + ecrecover_cost: 0, + sha256_cost: 0, + ripemd160_cost: 0, + identity_cost: 0, + modexp_cost: 0, + }, evm_deposit: 0, } } diff --git a/runtime/near-vm-errors/Cargo.toml b/runtime/near-vm-errors/Cargo.toml index 3bdefd976e1..483461ddc98 100644 --- a/runtime/near-vm-errors/Cargo.toml +++ b/runtime/near-vm-errors/Cargo.toml @@ -20,5 +20,7 @@ borsh = "0.7.1" near-rpc-error-macro = { path = "../../tools/rpctypegen/macro", version = "0.1.0" } +ethereum-types = "0.6.0" + [features] dump_errors_schema = ["near-rpc-error-macro/dump_errors_schema"] diff --git a/runtime/near-vm-logic/src/gas_counter.rs b/runtime/near-vm-logic/src/gas_counter.rs index 7a99702f271..557f7dcf7a0 100644 --- a/runtime/near-vm-logic/src/gas_counter.rs +++ b/runtime/near-vm-logic/src/gas_counter.rs @@ -1,12 +1,24 @@ use crate::config::{ActionCosts, ExtCosts, ExtCostsConfig}; use crate::types::{Gas, ProfileData}; use crate::{HostError, VMLogicError}; -use near_runtime_fees::Fee; +use near_runtime_fees::{EvmGas, Fee}; #[cfg(feature = "costs_counting")] thread_local! { pub static EXT_COSTS_COUNTER: std::cell::RefCell> = Default::default(); + + pub static EVM_GAS_COUNTER: std::cell::RefCell = Default::default(); +} + +#[cfg(feature = "costs_counting")] +pub fn reset_evm_gas_counter() -> u64 { + let mut ret = 0; + EVM_GAS_COUNTER.with(|f| { + ret = *f.borrow(); + *f.borrow_mut() = 0; + }); + ret } type Result = ::std::result::Result; @@ -26,6 +38,13 @@ pub struct GasCounter { profile: Option, } +use std::fmt; +impl fmt::Debug for GasCounter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("").finish() + } +} + impl GasCounter { pub fn new( ext_costs_config: ExtCostsConfig, @@ -73,6 +92,18 @@ impl GasCounter { } } + #[cfg(feature = "costs_counting")] + #[inline] + pub fn inc_evm_gas_counter(&mut self, value: EvmGas) { + EVM_GAS_COUNTER.with(|f| { + *f.borrow_mut() += value; + }) + } + + #[cfg(not(feature = "costs_counting"))] + #[inline] + pub fn inc_evm_gas_counter(&mut self, _value: EvmGas) {} + #[cfg(feature = "costs_counting")] #[inline] fn inc_ext_costs_counter(&mut self, cost: ExtCosts, value: u64) { @@ -117,6 +148,10 @@ impl GasCounter { self.deduct_gas(value, value) } + pub fn pay_evm_gas(&mut self, value: u64) -> Result<()> { + self.deduct_gas(value, value) + } + /// A helper function to pay per byte gas pub fn pay_per_byte(&mut self, cost: ExtCosts, num_bytes: u64) -> Result<()> { let use_gas = num_bytes diff --git a/runtime/near-vm-runner/Cargo.toml b/runtime/near-vm-runner/Cargo.toml index fe54ea0bf1c..768697b6274 100644 --- a/runtime/near-vm-runner/Cargo.toml +++ b/runtime/near-vm-runner/Cargo.toml @@ -23,6 +23,7 @@ anyhow = { version = "1.0.19", optional = true } near-runtime-fees = { path="../near-runtime-fees", version = "2.2.0" } near-vm-logic = { path="../near-vm-logic", version = "2.2.0", default-features = false, features = []} near-vm-errors = { path = "../near-vm-errors", version = "2.2.0" } +near-evm-runner = { path = "../near-evm-runner", version = "2.2.0"} [dev-dependencies] assert_matches = "1.3" diff --git a/runtime/runtime-params-estimator/Cargo.toml b/runtime/runtime-params-estimator/Cargo.toml index 9c002b643ef..88cf5b86a17 100644 --- a/runtime/runtime-params-estimator/Cargo.toml +++ b/runtime/runtime-params-estimator/Cargo.toml @@ -22,13 +22,23 @@ near-runtime-fees = { path = "../../runtime/near-runtime-fees" } near-crypto = { path = "../../core/crypto" } near-vm-logic = {path = "../../runtime/near-vm-logic" , features = ["costs_counting"]} near-vm-runner = {path = "../../runtime/near-vm-runner" , features = ["costs_counting", "no_cache", "no_cpu_compatibility_checks", "wasmtime_vm" ]} -node-runtime = { path = "../../runtime/runtime" , features = ["costs_counting", "no_cache"]} +node-runtime = { path = "../../runtime/runtime" , features = ["costs_counting", "no_cache", "protocol_feature_evm"]} near-store = { path = "../../core/store", features = ["no_cache", "single_thread_rocksdb"]} -near-primitives = { path = "../../core/primitives" } +near-primitives = { path = "../../core/primitives", features = ["protocol_feature_evm", "protocol_feature_forward_chunk_parts", "nightly_protocol"] } +testlib = { path = "../../test-utils/testlib" } +state-viewer = { path = "../../test-utils/state-viewer" } neard = { path = "../../neard" } rocksdb = { git = "https://github.com/nearprotocol/rust-rocksdb", branch="disable-thread" } glob = "0.3.0" walrus = "0.18.0" +near-evm-runner = { path = "../../runtime/near-evm-runner", features = ["costs_counting"] } +hex = "0.4" +ethabi = "8.0.0" +ethabi-contract = "8.0.0" +ethabi-derive = "8.0.0" +ethereum-types = "0.6.0" +lazy-static-include = "2.2.2" +num-traits = "0.2.12" [features] default = [] diff --git a/runtime/runtime-params-estimator/src/cases.rs b/runtime/runtime-params-estimator/src/cases.rs index 12f759db827..b8670b5d2d3 100644 --- a/runtime/runtime-params-estimator/src/cases.rs +++ b/runtime/runtime-params-estimator/src/cases.rs @@ -1,4 +1,5 @@ use num_rational::Ratio; +use num_traits::cast::FromPrimitive; use rand::seq::SliceRandom; use rand::{Rng, SeedableRng}; use std::cell::RefCell; @@ -20,7 +21,9 @@ use crate::stats::Measurements; use crate::testbed::RuntimeTestbed; use crate::testbed_runners::GasMetric; use crate::testbed_runners::{get_account_id, measure_actions, measure_transactions, Config}; -use crate::vm_estimator::{cost_per_op, cost_to_compile, load_and_compile}; +use crate::vm_estimator::{ + cost_of_evm, cost_per_op, cost_to_compile, load_and_compile, near_cost_to_evm_gas, +}; use near_runtime_fees::{ AccessKeyCreationConfig, ActionCreationConfig, DataReceiptCreationConfig, Fee, RuntimeFeesConfig, @@ -146,9 +149,11 @@ pub enum Metric { data_receipt_10b_1000, data_receipt_100kib_1000, cpu_ram_soak_test, + + deploy_evm_contract, } -pub fn run(mut config: Config, only_compile: bool) -> RuntimeConfig { +pub fn run(mut config: Config, only_compile: bool, only_evm: bool) -> RuntimeConfig { let mut m = Measurements::new(config.metric); if only_compile { let (contract_compile_cost, contract_compile_base_cost) = @@ -159,6 +164,67 @@ pub fn run(mut config: Config, only_compile: bool) -> RuntimeConfig { contract_byte_cost, ratio_to_gas(config.metric, contract_compile_base_cost) ); + process::exit(0); + } else if only_evm { + config.block_sizes = vec![100]; + let cost = cost_of_evm(&config, true); + println!( + "EVM base deploy (and init evm instance) cost: {}, deploy cost per EVM gas: {}, deploy cost per byte: {}", + ratio_to_gas(config.metric, Ratio::::from_f64(cost.deploy_cost.2).unwrap()), + ratio_to_gas(config.metric, Ratio::::from_f64(cost.deploy_cost.0).unwrap()), + ratio_to_gas(config.metric, Ratio::::from_f64(cost.deploy_cost.1).unwrap()), + ); + println!( + "EVM base function call cost: {}, function call cost per EVM gas: {}", + ratio_to_gas(config.metric, cost.funcall_cost.1), + ratio_to_gas(config.metric, cost.funcall_cost.0), + ); + println!("EVM precompiled function evm gas:"); + println!( + "ecrecover: {}", + near_cost_to_evm_gas(cost.funcall_cost, cost.precompiled_function_cost.ec_recover_cost) + ); + println!( + "sha256: {}", + near_cost_to_evm_gas(cost.funcall_cost, cost.precompiled_function_cost.sha256_cost) + ); + println!( + "sha256 per byte: {}", + near_cost_to_evm_gas( + cost.funcall_cost, + cost.precompiled_function_cost.sha256_cost_per_byte + ) + ); + println!( + "ripemd160: {}", + near_cost_to_evm_gas(cost.funcall_cost, cost.precompiled_function_cost.ripemd160_cost) + ); + println!( + "ripemd160 per byte: {}", + near_cost_to_evm_gas( + cost.funcall_cost, + cost.precompiled_function_cost.ripemd160_cost_per_byte + ) + ); + println!( + "identity: {}", + near_cost_to_evm_gas(cost.funcall_cost, cost.precompiled_function_cost.identity_cost) + ); + println!( + "identity per byte: {}", + near_cost_to_evm_gas( + cost.funcall_cost, + cost.precompiled_function_cost.identity_cost_per_byte + ) + ); + println!( + "modexp: {}", + near_cost_to_evm_gas( + cost.funcall_cost, + cost.precompiled_function_cost.modexp_impl_cost + ) + ); + process::exit(0); } config.block_sizes = vec![100]; diff --git a/runtime/runtime-params-estimator/src/main.rs b/runtime/runtime-params-estimator/src/main.rs index 4ff7df436d2..0d5d3aa60e6 100644 --- a/runtime/runtime-params-estimator/src/main.rs +++ b/runtime/runtime-params-estimator/src/main.rs @@ -71,6 +71,7 @@ fn main() { .long("transaction") .help("Disables transaction measurements"), ) + .arg(Arg::with_name("evm-only").long("evm-only").help("only test evm related cost")) .get_matches(); let state_dump_path = matches.value_of("home").unwrap().to_string(); @@ -102,6 +103,7 @@ fn main() { disable_measure_transaction, }, matches.is_present("compile-only"), + matches.is_present("evm-only"), ); println!("Generated RuntimeConfig:"); diff --git a/runtime/runtime-params-estimator/src/testbed.rs b/runtime/runtime-params-estimator/src/testbed.rs index 784231e63a0..b3c65d16b36 100644 --- a/runtime/runtime-params-estimator/src/testbed.rs +++ b/runtime/runtime-params-estimator/src/testbed.rs @@ -4,6 +4,7 @@ use std::path::Path; use borsh::BorshDeserialize; +use near_chain_configs::Genesis; use near_primitives::receipt::Receipt; use near_primitives::test_utils::MockEpochInfoProvider; use near_primitives::transaction::{ExecutionStatus, SignedTransaction}; @@ -23,9 +24,10 @@ pub struct RuntimeTestbed { /// Directory where we temporarily keep the storage. #[allow(dead_code)] workdir: tempfile::TempDir, - tries: ShardTries, - root: MerkleHash, - runtime: Runtime, + pub tries: ShardTries, + pub root: MerkleHash, + pub runtime: Runtime, + pub genesis: Genesis, prev_receipts: Vec, apply_state: ApplyState, epoch_info_provider: MockEpochInfoProvider, @@ -39,6 +41,7 @@ impl RuntimeTestbed { let store = create_store(&get_store_path(workdir.path())); let tries = ShardTries::new(store.clone(), 1); + let genesis = Genesis::from_file(dump_dir.join("genesis.json")); let mut state_file = dump_dir.to_path_buf(); state_file.push(STATE_DUMP_FILE); store.load_from_file(ColState, state_file.as_path()).expect("Failed to read state dump"); @@ -98,6 +101,7 @@ impl RuntimeTestbed { prev_receipts, apply_state, epoch_info_provider: MockEpochInfoProvider::default(), + genesis, } } diff --git a/runtime/runtime-params-estimator/src/testbed_runners.rs b/runtime/runtime-params-estimator/src/testbed_runners.rs index 67fa26e2afc..c4c40958cf7 100644 --- a/runtime/runtime-params-estimator/src/testbed_runners.rs +++ b/runtime/runtime-params-estimator/src/testbed_runners.rs @@ -18,7 +18,7 @@ pub fn get_account_id(account_index: usize) -> String { } /// Total number of transactions that we need to prepare. -fn total_transactions(config: &Config) -> usize { +pub fn total_transactions(config: &Config) -> usize { config.block_sizes.iter().sum::() * config.iter_per_block } diff --git a/runtime/runtime-params-estimator/src/vm_estimator.rs b/runtime/runtime-params-estimator/src/vm_estimator.rs index 80aacbcd422..75e6dbc3233 100644 --- a/runtime/runtime-params-estimator/src/vm_estimator.rs +++ b/runtime/runtime-params-estimator/src/vm_estimator.rs @@ -1,19 +1,42 @@ +use crate::testbed::RuntimeTestbed; use crate::testbed_runners::end_count; +use crate::testbed_runners::get_account_id; use crate::testbed_runners::start_count; +use crate::testbed_runners::total_transactions; +use crate::testbed_runners::Config; use crate::testbed_runners::GasMetric; +use ethabi_contract::use_contract; +use ethereum_types::H160; use glob::glob; +use indicatif::{ProgressBar, ProgressStyle}; +use lazy_static_include::lazy_static_include_str; +use near_crypto::{InMemorySigner, KeyType}; +use near_evm_runner::utils::encode_call_function_args; +use near_evm_runner::EvmContext; +use near_primitives::hash::CryptoHash; +use near_primitives::transaction::{Action, FunctionCallAction, SignedTransaction}; use near_primitives::version::PROTOCOL_VERSION; use near_runtime_fees::RuntimeFeesConfig; +use near_vm_logic::gas_counter::reset_evm_gas_counter; use near_vm_logic::mocks::mock_external::MockedExternal; use near_vm_logic::{VMConfig, VMContext, VMKind, VMOutcome}; use near_vm_runner::{compile_module, prepare, VMError}; use num_rational::Ratio; +use num_traits::cast::ToPrimitive; +use rand::Rng; +use rocksdb::Env; use std::collections::hash_map::DefaultHasher; +use std::collections::{HashMap, HashSet}; +use std::convert::TryFrom; use std::fs; +use std::sync::{Arc, Mutex, RwLock}; use std::{ hash::{Hash, Hasher}, + path::Path, path::PathBuf, }; +use testlib::node::{Node, RuntimeNode}; +use testlib::user::runtime_user::MockClient; use walrus::{Module, Result}; const CURRENT_ACCOUNT_ID: &str = "alice"; @@ -135,11 +158,570 @@ pub fn load_and_compile( } } +#[derive(Debug)] +pub struct EvmCost { + pub evm_gas: u64, + pub size: u64, + pub cost: Ratio, +} + +fn testbed_for_evm( + state_dump_path: &str, + accounts: usize, +) -> (Arc>, Arc>>) { + let path = PathBuf::from(state_dump_path); + let testbed = Arc::new(Mutex::new(RuntimeTestbed::from_state_dump(&path))); + let mut nonces: HashMap = HashMap::new(); + let bar = ProgressBar::new(accounts as _); + println!("Prepare a testbed of {} accounts all having a deployed evm contract", accounts); + bar.set_style(ProgressStyle::default_bar().template( + "[elapsed {elapsed_precise} remaining {eta_precise}] Evm contracts {bar} {pos:>7}/{len:7} {msg}", + )); + let mut env = Env::default().unwrap(); + env.set_background_threads(4); + for account_idx in 0..accounts { + let account_id = get_account_id(account_idx); + let signer = InMemorySigner::from_seed(&account_id, KeyType::ED25519, &account_id); + let code = hex::decode(&TEST).unwrap(); + let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); + + let block: Vec<_> = vec![SignedTransaction::from_actions( + nonce as u64, + account_id.clone(), + "evm".to_owned(), + &signer, + vec![Action::FunctionCall(FunctionCallAction { + method_name: "deploy_code".to_string(), + args: code, + gas: 10u64.pow(18), + deposit: 0, + })], + CryptoHash::default(), + )]; + let mut testbed = testbed.lock().unwrap(); + testbed.process_block(&block, false); + testbed.process_blocks_until_no_receipts(false); + bar.inc(1); + } + bar.finish(); + reset_evm_gas_counter(); + env.set_background_threads(0); + (testbed, Arc::new(Mutex::new(nonces))) +} + +fn deploy_evm_contract( + code: &[u8], + config: &Config, + testbed: Arc>, + nonces: Arc>>, +) -> Option { + let path = PathBuf::from(config.state_dump_path.as_str()); + println!("{:?}. Preparing testbed. Loading state.", config.metric); + let allow_failures = false; + let mut nonces = nonces.lock().unwrap(); + let mut accounts_deployed = HashSet::new(); + + let mut f = || { + let account_idx = loop { + let x = rand::thread_rng().gen::() % config.active_accounts; + if accounts_deployed.contains(&x) { + continue; + } + break x; + }; + accounts_deployed.insert(account_idx); + let account_id = get_account_id(account_idx); + let signer = InMemorySigner::from_seed(&account_id, KeyType::ED25519, &account_id); + + let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); + SignedTransaction::from_actions( + nonce as u64, + account_id.clone(), + "evm".to_owned(), + &signer, + vec![Action::FunctionCall(FunctionCallAction { + method_name: "deploy_code".to_string(), + args: hex::decode(code).unwrap(), + gas: 10u64.pow(18), + deposit: 0, + })], + CryptoHash::default(), + ) + }; + + for _ in 0..config.warmup_iters_per_block { + for block_size in config.block_sizes.clone() { + let block: Vec<_> = (0..block_size).map(|_| f()).collect(); + let mut testbed = testbed.lock().unwrap(); + testbed.process_block(&block, allow_failures); + testbed.process_blocks_until_no_receipts(allow_failures); + } + } + reset_evm_gas_counter(); + let mut evm_gas = 0; + let mut total_cost = 0; + for _ in 0..config.iter_per_block { + for block_size in config.block_sizes.clone() { + let block: Vec<_> = (0..block_size).map(|_| f()).collect(); + let mut testbed = testbed.lock().unwrap(); + testbed.process_block(&block, allow_failures); + // process_block create action receipt for FunctionCall Action, not count as gas used in evm. + // In real node, action receipt cost is deducted in validate_tx -> tx_cost so should only count + // and deduct evm execution cost + let start = start_count(config.metric); + testbed.process_blocks_until_no_receipts(allow_failures); + let cost = end_count(config.metric, &start); + total_cost += cost; + evm_gas += reset_evm_gas_counter(); + } + } + + let counts = total_transactions(config) as u64; + evm_gas /= counts; + + Some(EvmCost { evm_gas, size: code.len() as u64, cost: Ratio::new(total_cost, counts) }) +} + +fn load_and_deploy_evm_contract( + path: &PathBuf, + config: &Config, + testbed: Arc>, + nonces: Arc>>, +) -> Option { + match fs::read(path) { + Ok(code) => deploy_evm_contract(&code, config, testbed, nonces), + _ => None, + } +} + #[cfg(feature = "lightbeam")] const USING_LIGHTBEAM: bool = true; #[cfg(not(feature = "lightbeam"))] const USING_LIGHTBEAM: bool = false; +type Coef = (Ratio, Ratio); + +type Coef2D = (f64, f64, f64); + +pub struct EvmPrecompiledFunctionCost { + pub ec_recover_cost: Ratio, + pub sha256_cost: Ratio, + pub sha256_cost_per_byte: Ratio, + pub ripemd160_cost: Ratio, + pub ripemd160_cost_per_byte: Ratio, + pub identity_cost: Ratio, + pub identity_cost_per_byte: Ratio, + pub modexp_impl_cost: Ratio, + // pub bn128AddImplCost: Ratio, + // pub bn128MulImplCost: Ratio, + // pub bn128PairingImplCost: Ratio, + // pub blake2FImplCost: Ratio, + // pub lastPrecompileCost: Ratio, +} + +pub struct EvmCostCoef { + pub deploy_cost: Coef2D, + pub funcall_cost: Coef, + pub precompiled_function_cost: EvmPrecompiledFunctionCost, +} + +pub fn measure_evm_deploy( + config: &Config, + verbose: bool, + testbed: Arc>, + nonces: Arc>>, +) -> Coef2D { + let globbed_files = glob("./**/*.bin").expect("Failed to read glob pattern for bin files"); + let paths = globbed_files + .filter_map(|x| match x { + Ok(p) => Some(p), + _ => None, + }) + .collect::>(); + + let measurements = paths + .iter() + .filter(|path| fs::metadata(path).is_ok()) + .map(|path| { + if verbose { + print!("Testing {}: ", path.display()); + }; + // Evm counted gas already count on size of the contract, therefore we look for cost = m*evm_gas + b. + if let Some(EvmCost { evm_gas, size, cost }) = + load_and_deploy_evm_contract(path, config, testbed.clone(), nonces.clone()) + { + if verbose { + println!("({}, {}, {}),", evm_gas, size, cost); + }; + Some(EvmCost { evm_gas, size, cost }) + } else { + if verbose { + println!("FAILED") + }; + None + } + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .collect::>(); + measurements_to_coef_2d(measurements, true) +} + +use_contract!(soltest, "../near-evm-runner/tests/build/SolTests.abi"); +use_contract!(precompiled_function, "../near-evm-runner/tests/build/PrecompiledFunction.abi"); + +lazy_static_include_str!(TEST, "../near-evm-runner/tests/build/SolTests.bin"); +lazy_static_include_str!( + PRECOMPILED_TEST, + "../near-evm-runner/tests/build/PrecompiledFunction.bin" +); + +const CHAIN_ID: u128 = 0x99; + +pub fn create_evm_context<'a>( + external: &'a mut MockedExternal, + vm_config: &'a VMConfig, + fees_config: &'a RuntimeFeesConfig, + account_id: String, + attached_deposit: u128, +) -> EvmContext<'a> { + EvmContext::new( + external, + CHAIN_ID, + vm_config, + fees_config, + 1000, + account_id.to_string(), + account_id.to_string(), + account_id.to_string(), + attached_deposit, + 0, + 10u64.pow(14), + false, + 100_000_000.into(), + ) +} + +pub fn measure_evm_funcall( + config: &Config, + verbose: bool, + testbed: Arc>, + nonces: Arc>>, +) -> Coef { + let measurements = vec![ + measure_evm_function( + config, + verbose, + |sol_test_addr| { + vec![sol_test_addr, soltest::functions::deploy_new_guy::call(8).0].concat() + }, + "deploy_new_guy(8)", + testbed.clone(), + nonces.clone(), + ), + measure_evm_function( + config, + verbose, + |sol_test_addr| { + vec![sol_test_addr, soltest::functions::pay_new_guy::call(8).0].concat() + }, + "pay_new_guy(8)", + testbed.clone(), + nonces.clone(), + ), + measure_evm_function( + config, + verbose, + |sol_test_addr| { + vec![sol_test_addr, soltest::functions::return_some_funds::call().0].concat() + }, + "return_some_funds()", + testbed.clone(), + nonces.clone(), + ), + measure_evm_function( + config, + verbose, + |sol_test_addr| vec![sol_test_addr, soltest::functions::emit_it::call(8).0].concat(), + "emit_it(8)", + testbed.clone(), + nonces.clone(), + ), + ]; + println!("{:?}", measurements); + measurements_to_coef(measurements, true) +} + +pub fn measure_evm_precompile_function( + config: &Config, + verbose: bool, + context: &mut EvmContext, + args: Vec, + test_name: &str, +) -> EvmCost { + // adding action receipt etc is too big compare too evm precompile function itself and cause the error is bigger + // than evm precompile function cost, so measure this cost in evm context level to be precise + let gas_metric = config.metric; + let start = start_count(gas_metric); + let mut evm_gas = 0; + for i in 0..NUM_ITERATIONS { + if i == 0 { + evm_gas = context.evm_gas_counter.used_gas.as_u64(); + } else if i == 1 { + evm_gas = context.evm_gas_counter.used_gas.as_u64() - evm_gas; + } + let _ = context.call_function(args.clone()).unwrap(); + } + let end = end_count(gas_metric, &start); + let cost = Ratio::new(end, NUM_ITERATIONS); + if verbose { + println!("Testing call {}: ({}, {})", test_name, evm_gas, cost); + } + EvmCost { size: 0, evm_gas, cost } +} + +pub fn measure_evm_function) -> Vec + Copy>( + config: &Config, + verbose: bool, + args_encoder: F, + test_name: &str, + testbed: Arc>, + nonces: Arc>>, +) -> EvmCost { + let path = PathBuf::from(config.state_dump_path.as_str()); + println!("{:?}. Preparing testbed. Loading state.", config.metric); + let allow_failures = false; + let mut nonces = nonces.lock().unwrap(); + let mut accounts_deployed = HashSet::new(); + let code = hex::decode(&TEST).unwrap(); + + let mut f = || { + let account_idx = loop { + let x = rand::thread_rng().gen::() % config.active_accounts; + if accounts_deployed.contains(&x) { + continue; + } + break x; + }; + accounts_deployed.insert(account_idx); + let account_id = get_account_id(account_idx); + let signer = InMemorySigner::from_seed(&account_id, KeyType::ED25519, &account_id); + + let mut testbed = testbed.lock().unwrap(); + let runtime_node = RuntimeNode { + signer: Arc::new(signer.clone()), + client: Arc::new(RwLock::new(MockClient { + runtime: testbed.runtime, + runtime_config: testbed.genesis.config.runtime_config.clone(), + tries: testbed.tries.clone(), + state_root: testbed.root, + epoch_length: testbed.genesis.config.epoch_length, + })), + genesis: testbed.genesis.clone(), + }; + let node_user = runtime_node.user(); + let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); + let addr = node_user + .function_call( + account_id.clone(), + "evm".to_string(), + "deploy_code", + code.clone(), + 10u64.pow(14), + 10, + ) + .unwrap() + .status + .as_success_decoded() + .unwrap(); + + testbed.tries = runtime_node.client.read().unwrap().tries.clone(); + testbed.root = runtime_node.client.read().unwrap().state_root; + testbed.runtime = runtime_node.client.read().unwrap().runtime; + + let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); + SignedTransaction::from_actions( + nonce as u64, + account_id.clone(), + "evm".to_owned(), + &signer, + vec![Action::FunctionCall(FunctionCallAction { + method_name: "call_function".to_string(), + args: args_encoder(addr), + gas: 10u64.pow(18), + deposit: 0, + })], + CryptoHash::default(), + ) + }; + + for _ in 0..config.warmup_iters_per_block { + for block_size in config.block_sizes.clone() { + let block: Vec<_> = (0..block_size).map(|_| f()).collect(); + let mut testbed = testbed.lock().unwrap(); + testbed.process_block(&block, allow_failures); + testbed.process_blocks_until_no_receipts(allow_failures); + } + } + reset_evm_gas_counter(); + let mut evm_gas = 0; + let mut total_cost = 0; + for _ in 0..config.iter_per_block { + for block_size in config.block_sizes.clone() { + let block: Vec<_> = (0..block_size).map(|_| f()).collect(); + let mut testbed = testbed.lock().unwrap(); + testbed.process_block(&block, allow_failures); + let start = start_count(config.metric); + testbed.process_blocks_until_no_receipts(allow_failures); + let cost = end_count(config.metric, &start); + total_cost += cost; + evm_gas += reset_evm_gas_counter(); + } + } + + let counts = total_transactions(config) as u64; + evm_gas /= counts; + + let cost = Ratio::new(total_cost, counts); + if verbose { + println!("Testing call {}: ({}, {})", test_name, evm_gas, cost); + } + EvmCost { evm_gas, size: 0, cost } +} + +pub fn measure_evm_precompiled(config: &Config, verbose: bool) -> EvmPrecompiledFunctionCost { + let mut fake_external = MockedExternal::new(); + let vm_config = VMConfig::default(); + let fees = RuntimeFeesConfig::default(); + + let mut context = + create_evm_context(&mut fake_external, &vm_config, &fees, "alice".to_string(), 0); + let precompiled_function_addr = + context.deploy_code(hex::decode(&PRECOMPILED_TEST).unwrap()).unwrap(); + + let measurements = vec![ + measure_evm_precompile_function( + config, + verbose, + &mut context, + encode_call_function_args( + precompiled_function_addr, + precompiled_function::functions::noop::call().0, + ), + "noop()", + ), + measure_evm_precompile_function( + config, + verbose, + &mut context, + encode_call_function_args( + precompiled_function_addr, + precompiled_function::functions::test_ecrecover::call().0, + ), + "test_ecrecover()", + ), + measure_evm_precompile_function( + config, + verbose, + &mut context, + encode_call_function_args( + precompiled_function_addr, + precompiled_function::functions::test_sha256::call().0, + ), + "test_sha256()", + ), + measure_evm_precompile_function( + config, + verbose, + &mut context, + encode_call_function_args( + precompiled_function_addr, + precompiled_function::functions::test_sha256_100bytes::call().0, + ), + "test_sha256_100bytes()", + ), + measure_evm_precompile_function( + config, + verbose, + &mut context, + encode_call_function_args( + precompiled_function_addr, + precompiled_function::functions::test_ripemd160::call().0, + ), + "test_ripemd160()", + ), + measure_evm_precompile_function( + config, + verbose, + &mut context, + encode_call_function_args( + precompiled_function_addr, + precompiled_function::functions::test_ripemd160_1kb::call().0, + ), + "test_ripemd160_1kb()", + ), + measure_evm_precompile_function( + config, + verbose, + &mut context, + encode_call_function_args( + precompiled_function_addr, + precompiled_function::functions::test_identity::call().0, + ), + "test_identity()", + ), + measure_evm_precompile_function( + config, + verbose, + &mut context, + encode_call_function_args( + precompiled_function_addr, + precompiled_function::functions::test_identity_100bytes::call().0, + ), + "test_identity_100bytes()", + ), + measure_evm_precompile_function( + config, + verbose, + &mut context, + encode_call_function_args( + precompiled_function_addr, + precompiled_function::functions::test_mod_exp::call().0, + ), + "test_mod_exp()", + ), + ]; + + println!("measurements: {:?}", measurements); + let r = EvmPrecompiledFunctionCost { + ec_recover_cost: measurements[1].cost - measurements[0].cost, + sha256_cost: measurements[2].cost - measurements[0].cost, + sha256_cost_per_byte: (measurements[3].cost - measurements[2].cost) / 100, + ripemd160_cost: measurements[4].cost - measurements[0].cost, + ripemd160_cost_per_byte: (measurements[5].cost - measurements[4].cost) / 1024, + identity_cost: measurements[6].cost - measurements[0].cost, + identity_cost_per_byte: (measurements[7].cost - measurements[6].cost) / 100, + modexp_impl_cost: measurements[8].cost - measurements[0].cost, + }; + println!("sha256_cost_per_byte {}", r.sha256_cost_per_byte); + r +} + +pub fn near_cost_to_evm_gas(funcall_cost: Coef, cost: Ratio) -> u64 { + return u64::try_from((cost / funcall_cost.0).to_integer()).unwrap(); +} + +/// Cost of all evm related +pub fn cost_of_evm(config: &Config, verbose: bool) -> EvmCostCoef { + let (testbed, nonces) = testbed_for_evm(&config.state_dump_path, config.active_accounts); + let evm_cost_config = EvmCostCoef { + deploy_cost: measure_evm_deploy(config, verbose, testbed.clone(), nonces.clone()), + funcall_cost: measure_evm_funcall(config, verbose, testbed.clone(), nonces.clone()), + precompiled_function_cost: measure_evm_precompiled(config, verbose), + }; + evm_cost_config +} + /// Cost of the compile contract with vm_kind pub fn cost_to_compile( gas_metric: GasMetric, @@ -175,7 +757,7 @@ pub fn cost_to_compile( .filter(|path| fs::metadata(path).is_ok()) .map(|path| { if verbose { - print!("Testing {}: ", path.display()); + print!("Testing deploy {}: ", path.display()); }; if let Some((size, cost)) = load_and_compile(path, gas_metric, vm_kind) { if verbose { @@ -200,6 +782,77 @@ pub fn cost_to_compile( (m, b) } +fn dot(v1: &Vec, v2: &Vec) -> f64 { + let mut ret = 0.0; + for (i, u) in v1.iter().enumerate() { + ret += u * v2[i]; + } + ret +} + +struct Matrix2x2 { + a: f64, + b: f64, + c: f64, + d: f64, +} + +fn inverse2x2(m: Matrix2x2) -> Matrix2x2 { + let Matrix2x2 { a, b, c, d } = m; + let delta = a * d - b * c; + Matrix2x2 { a: d / delta, b: -b / delta, c: -c / delta, d: a / delta } +} + +fn normalize(v: &Vec) -> (Vec, f64) { + let mean = v.iter().sum::() / (v.len() as f64); + // default sklearn LinearRegression only normalize mean to 0, but not normalize stddev to 1, and that gives a very good result. + + let v: Vec<_> = v.iter().map(|x| (*x - mean)).collect(); + (v, mean) +} + +fn measurements_to_coef_2d(measurements: Vec, verbose: bool) -> Coef2D { + let v1: Vec<_> = measurements.iter().map(|m| m.evm_gas as f64).collect(); + let (v1, _) = normalize(&v1); + let v2: Vec<_> = measurements.iter().map(|m| m.size as f64).collect(); + let (v2, _) = normalize(&v2); + let a = dot(&v1, &v1); + let b = dot(&v1, &v2); + let c = dot(&v2, &v1); + let d = dot(&v2, &v2); + + let xt_x_inverse = inverse2x2(Matrix2x2 { a, b, c, d }); + + let y: Vec<_> = measurements.iter().map(|m| m.cost.to_f64().unwrap()).collect(); + let xt_y1 = dot(&v1, &y); + let xt_y2 = dot(&v2, &y); + + let beta1 = (xt_x_inverse.a * xt_y1 + xt_x_inverse.b * xt_y2); + let beta2 = (xt_x_inverse.c * xt_y1 + xt_x_inverse.d * xt_y2); + + let delta: Vec<_> = measurements + .iter() + .map(|m| m.cost.to_f64().unwrap() - (m.evm_gas as f64) * beta1 - (m.size as f64) * beta2) + .collect(); + let r = (beta1, beta2, delta.iter().sum::() / delta.len() as f64); + println!("evm calc data {:?}", r); + println!("delta: {:?}", delta); + r +} + +fn measurements_to_coef(measurements: Vec, verbose: bool) -> Coef { + let ratio = Ratio::new(0 as u64, 1); + let base = Ratio::new(u64::MAX, 1); + let b = measurements.iter().fold(base, |b, EvmCost { evm_gas: _, size: _, cost }| b.min(*cost)); + let m = measurements + .iter() + .fold(ratio, |r, EvmCost { evm_gas, size: _, cost }| r.max((*cost - b) / evm_gas)); + if verbose { + println!("raw data: ({},{})", m, b); + } + (m, b) +} + fn delete_all_data(wasm_bin: &mut Vec) -> Result<&Vec> { let m = &mut Module::from_buffer(wasm_bin)?; for id in get_ids(m.data.iter().map(|t| t.id())) { diff --git a/runtime/runtime/Cargo.toml b/runtime/runtime/Cargo.toml index fa5d1e22564..8b0e57cd6e2 100644 --- a/runtime/runtime/Cargo.toml +++ b/runtime/runtime/Cargo.toml @@ -36,6 +36,7 @@ near-vm-errors = { path = "../../runtime/near-vm-errors" } [features] default = [] dump_errors_schema = ["near-vm-errors/dump_errors_schema"] +protocol_feature_evm = ["near-primitives/protocol_feature_evm"] # Use this feature to enable counting of fees and costs applied. costs_counting = ["near-vm-logic/costs_counting", "near-vm-runner/costs_counting"] diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs index eeea07e71ab..7a68cfc6d96 100644 --- a/runtime/runtime/src/lib.rs +++ b/runtime/runtime/src/lib.rs @@ -195,6 +195,7 @@ impl Default for ActionResult { } } +#[derive(Copy, Clone)] pub struct Runtime {} impl Runtime { @@ -303,6 +304,7 @@ impl Runtime { actions: &[Action], epoch_info_provider: &dyn EpochInfoProvider, ) -> Result { + // println!("enter apply_action"); let mut result = ActionResult::default(); let exec_fees = exec_fee( &apply_state.config.transaction_costs, diff --git a/runtime/runtime/tests/runtime_group_tools/random_config.rs b/runtime/runtime/tests/runtime_group_tools/random_config.rs index 2ca9be698a9..e0ba6b09af3 100644 --- a/runtime/runtime/tests/runtime_group_tools/random_config.rs +++ b/runtime/runtime/tests/runtime_group_tools/random_config.rs @@ -1,5 +1,5 @@ use near_runtime_fees::{ - AccessKeyCreationConfig, ActionCreationConfig, DataReceiptCreationConfig, Fee, + AccessKeyCreationConfig, ActionCreationConfig, DataReceiptCreationConfig, EvmCostConfig, Fee, RuntimeFeesConfig, StorageUsageConfig, }; use node_runtime::config::RuntimeConfig; @@ -46,6 +46,18 @@ pub fn random_config() -> RuntimeConfig { (101 + rng.next_u32() % 10).try_into().unwrap(), 100, ), + evm_config: EvmCostConfig { + bootstrap_cost: rng.next_u64() % 1000, + deploy_cost_per_evm_gas: rng.next_u64() % 1000, + deploy_cost_per_byte: rng.next_u64() % 1000, + funcall_cost_base: rng.next_u64() % 1000, + funcall_cost_per_evm_gas: rng.next_u64() % 1000, + ecrecover_cost: rng.next_u64() % 1000, + sha256_cost: rng.next_u64() % 1000, + ripemd160_cost: rng.next_u64() % 1000, + identity_cost: rng.next_u64() % 1000, + modexp_cost: rng.next_u64() % 1000, + }, evm_deposit: (rng.next_u64() % 10000) as u128 * 10u128.pow(23), }, ..Default::default() diff --git a/test-utils/state-viewer/src/lib.rs b/test-utils/state-viewer/src/lib.rs new file mode 100644 index 00000000000..c54d8b02d76 --- /dev/null +++ b/test-utils/state-viewer/src/lib.rs @@ -0,0 +1,2 @@ +mod state_dump; +pub use crate::state_dump::state_dump; From f8cdfa34bcdae4b86948e1fe7fc78b92c552d03a Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Mon, 2 Nov 2020 17:01:54 -0800 Subject: [PATCH 49/82] fix bug when not compile with all features --- core/primitives/src/version.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/primitives/src/version.rs b/core/primitives/src/version.rs index 922fdee71ff..3dc648f75fa 100644 --- a/core/primitives/src/version.rs +++ b/core/primitives/src/version.rs @@ -108,9 +108,12 @@ lazy_static! { let nightly_protocol_features_to_version_mapping: HashMap< ProtocolFeature, ProtocolVersion, - > = vec![(ProtocolFeature::ForwardChunkParts, 41), (ProtocolFeature::EVM, 41)] - .into_iter() - .collect(); + > = vec![ + #[cfg(feature = "protocol_feature_forward_chunk_parts")] + (ProtocolFeature::ForwardChunkParts, 41), + #[cfg(feature = "protocol_feature_evm")] + (ProtocolFeature::EVM, 41), + ].into_iter().collect(); for (stable_protocol_feature, stable_protocol_version) in STABLE_PROTOCOL_FEATURES_TO_VERSION_MAPPING.iter() { From 878fb1e24f06419af311de77e88c130e8c35309a Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Thu, 5 Nov 2020 09:23:02 -0800 Subject: [PATCH 50/82] Fix view gas cost and debug test --- Cargo.toml | 1 + runtime/near-evm-runner/src/lib.rs | 1 + runtime/runtime/src/state_viewer.rs | 2 +- test-utils/testlib/src/standard_test_cases.rs | 9 +++++++-- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5c37117cfd0..b178f3dba29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,3 +110,4 @@ rosetta_rpc = ["neard/rosetta_rpc"] protocol_feature_forward_chunk_parts = ["neard/protocol_feature_forward_chunk_parts"] nightly_protocol = [] nightly_protocol_features = ["nightly_protocol", "neard/nightly_protocol_features"] +protocol_feature_evm = ["neard/protocol_feature_evm"] diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 13b5ccd8296..c4dc72ebcd5 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -302,6 +302,7 @@ impl<'a> EvmContext<'a> { let sender = Address::from(&args.sender); let attached_amount = U256::from(args.amount); self.add_balance(&sender, attached_amount)?; + // TODO: Verify we don't keep the balance in case `call` returns `Err` let result = interpreter::call( self, &sender, diff --git a/runtime/runtime/src/state_viewer.rs b/runtime/runtime/src/state_viewer.rs index 80e52988c51..d640e0e9bdf 100644 --- a/runtime/runtime/src/state_viewer.rs +++ b/runtime/runtime/src/state_viewer.rs @@ -152,7 +152,7 @@ impl TrieViewer { let function_call = FunctionCallAction { method_name: method_name.to_string(), args: args.to_vec(), - gas: 0, + gas: config.wasm_config.limit_config.max_gas_burnt_view, deposit: 0, }; let (outcome, err) = execute_function_call( diff --git a/test-utils/testlib/src/standard_test_cases.rs b/test-utils/testlib/src/standard_test_cases.rs index 52776d0088e..d0d082dbb86 100644 --- a/test-utils/testlib/src/standard_test_cases.rs +++ b/test-utils/testlib/src/standard_test_cases.rs @@ -24,7 +24,7 @@ use crate::fees_utils::FeeHelper; use crate::node::Node; use crate::runtime_utils::{alice_account, bob_account, eve_dot_alice_account, evm_account}; use crate::user::User; -use near_evm_runner::utils::near_account_id_to_evm_address; +use near_evm_runner::utils::{address_to_vec, near_account_id_to_evm_address, u256_to_arr}; /// The amount to send with function call. const FUNCTION_CALL_AMOUNT: Balance = TESTING_INIT_BALANCE / 10; @@ -1294,6 +1294,9 @@ pub fn test_evm_deploy_call(node: impl Node) { .as_success_decoded() .unwrap(); + let result = node_user.view_call(&evm_account(), "get_balance", &contract_id).unwrap(); + assert_eq!(result.result, u256_to_arr(&U256::from(10)).to_vec()); + let (input, _decoder) = cryptozombies::functions::create_random_zombie::call("test"); let args = vec![contract_id.clone(), input].concat(); assert_eq!( @@ -1306,11 +1309,13 @@ pub fn test_evm_deploy_call(node: impl Node) { Vec::::new() ); + let alice = + address_to_vec(&near_evm_runner::utils::near_account_id_to_evm_address(&alice_account())); let (input, _decoder) = cryptozombies::functions::get_zombies_by_owner::call( near_evm_runner::utils::near_account_id_to_evm_address(&alice_account()), ); // sender, to, attached amount, args - let args = vec![contract_id.clone(), contract_id.clone(), vec![0u8; 32], input].concat(); + let args = vec![alice.clone(), contract_id.clone(), vec![0u8; 32], input].concat(); let bytes = node_user .function_call(alice_account(), evm_account(), "view", args.clone(), 10u64.pow(14), 0) .unwrap() From c78ba7c57b007cd3796bdce16267029b542b0e93 Mon Sep 17 00:00:00 2001 From: Arto Bendiken Date: Fri, 6 Nov 2020 01:40:50 +0200 Subject: [PATCH 51/82] Upgrade to OpenEthereum 2.6.8 (Istanbul support) (#3558) As the next step in #3506, and following up from #3542, upgrade OpenEthereum from [2.6.2](https://github.com/openethereum/openethereum/releases/tag/v2.6.2) (Aug 2019) to [2.6.8](https://github.com/openethereum/openethereum/releases/tag/v2.6.8) (Dec 2019), the last release in the 2.6.x series. This brings us up to par on the [Istanbul](https://eth.wiki/en/roadmap/istanbul) hard fork, which incorporated many EIPs, changing gas metering and adding a new precompile as well as two new opcodes: - [EIP-152: Add BLAKE2 compression function `F` precompile](https://eips.ethereum.org/EIPS/eip-152) - [EIP-1108: Reduce alt_bn128 precompile gas costs](https://eips.ethereum.org/EIPS/eip-1108) - [EIP-1344: ChainID opcode](https://eips.ethereum.org/EIPS/eip-1344) (includes a new opcode: `CHAINID`) - [EIP-1884: Repricing for trie-size-dependent opcodes](https://eips.ethereum.org/EIPS/eip-1884) (includes a new opcode: `SELFBALANCE`) - [EIP-2028: Transaction data gas cost reduction](https://eips.ethereum.org/EIPS/eip-2028) - [EIP-2200: Structured Definitions for Net Gas Metering](https://eips.ethereum.org/EIPS/eip-2200) This PR includes an implementation of the `CHAINID` opcode. (The `SELFBALANCE` opcode doesn't need anything from our runtime.) The upstream changelog for 2.6.8 is at: https://github.com/openethereum/openethereum/blob/v2.6.8/CHANGELOG.md The upstream diff from 2.6.2 to 2.6.8 is at: https://github.com/openethereum/openethereum/compare/v2.6.2...v2.6.8 --- Cargo.lock | 41 +++++++++++++++++----- runtime/near-evm-runner/Cargo.toml | 4 +-- runtime/near-evm-runner/src/interpreter.rs | 14 ++++++++ runtime/near-evm-runner/src/lib.rs | 6 ++++ runtime/near-evm-runner/src/near_ext.rs | 15 ++++++++ 5 files changed, 70 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0473e2440ea..887b6e70a1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1500,19 +1500,18 @@ dependencies = [ [[package]] name = "ethjson" version = "0.1.0" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" dependencies = [ "ethereum-types", "rustc-hex 1.0.0", "serde", - "serde_derive", "serde_json", ] [[package]] name = "evm" version = "0.1.0" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" dependencies = [ "bit-set", "ethereum-types", @@ -1522,7 +1521,7 @@ dependencies = [ "memory-cache", "parity-bytes", "parity-util-mem", - "parking_lot 0.7.1", + "parking_lot 0.9.0", "vm", ] @@ -2366,7 +2365,7 @@ dependencies = [ [[package]] name = "keccak-hasher" version = "0.1.1" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" dependencies = [ "ethereum-types", "hash-db", @@ -2648,7 +2647,7 @@ dependencies = [ [[package]] name = "memory-cache" version = "0.1.0" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" dependencies = [ "lru-cache", "parity-util-mem", @@ -3764,6 +3763,17 @@ dependencies = [ "parking_lot_core 0.4.0", ] +[[package]] +name = "parking_lot" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +dependencies = [ + "lock_api 0.3.4", + "parking_lot_core 0.6.2", + "rustc_version", +] + [[package]] name = "parking_lot" version = "0.10.2" @@ -3798,6 +3808,21 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "parking_lot_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +dependencies = [ + "cfg-if", + "cloudabi 0.0.3", + "libc", + "redox_syscall", + "rustc_version", + "smallvec 0.6.13", + "winapi 0.3.8", +] + [[package]] name = "parking_lot_core" version = "0.7.2" @@ -3830,7 +3855,7 @@ dependencies = [ [[package]] name = "patricia-trie-ethereum" version = "0.1.0" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" dependencies = [ "elastic-array 0.10.3", "ethereum-types", @@ -5656,7 +5681,7 @@ checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" [[package]] name = "vm" version = "0.1.0" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.2#25936ae0f6d48f5ac6fb93cd467c15f4f8a631c2" +source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" dependencies = [ "ethereum-types", "ethjson", diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 604fad9eb2d..b8a93874762 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -24,8 +24,8 @@ keccak-hash = "0.2.0" ripemd160 = "0.9.0" libsecp256k1 = "0.3.5" -evm = { git = "https://github.com/openethereum/openethereum", rev = "v2.6.2" } -vm = { git = "https://github.com/openethereum/openethereum", rev = "v2.6.2" } +evm = { git = "https://github.com/openethereum/openethereum", rev = "v2.6.8" } +vm = { git = "https://github.com/openethereum/openethereum", rev = "v2.6.8" } bn = { git = "https://github.com/paritytech/bn", default-features = false } parity-bytes = "0.1.0" ethereum-types = "0.6.0" diff --git a/runtime/near-evm-runner/src/interpreter.rs b/runtime/near-evm-runner/src/interpreter.rs index f767cf85e55..554a0599acc 100644 --- a/runtime/near-evm-runner/src/interpreter.rs +++ b/runtime/near-evm-runner/src/interpreter.rs @@ -26,6 +26,7 @@ pub fn deploy_code( code: &[u8], gas: &U256, evm_gas_config: &EvmCostConfig, + chain_id: u128, ) -> Result { let mut nonce = U256::zero(); if address_type == CreateContractAddress::FromSenderAndNonce { @@ -49,6 +50,7 @@ pub fn deploy_code( code, gas, evm_gas_config, + chain_id, )?; // Apply known gas amount changes (all reverts are NeedsReturn) @@ -82,6 +84,7 @@ pub fn _create( code: &[u8], gas: &U256, evm_gas_config: &EvmCostConfig, + chain_id: u128, ) -> Result<(ExecTrapResult, Option)> { let mut store = StateStore::default(); let mut sub_state = SubState::new(sender, &mut store, state); @@ -110,6 +113,7 @@ pub fn _create( call_stack_depth + 1, false, evm_gas_config, + chain_id, ); ext.info.gas_limit = U256::from(gas); ext.schedule = Schedule::new_constantinople(); @@ -133,6 +137,7 @@ pub fn call( should_commit: bool, gas: &U256, evm_gas_config: &EvmCostConfig, + chain_id: u128, ) -> Result { run_and_commit_if_success( state, @@ -148,6 +153,7 @@ pub fn call( should_commit, gas, evm_gas_config, + chain_id, ) } @@ -161,6 +167,7 @@ pub fn delegate_call( input: &[u8], gas: &U256, evm_gas_config: &EvmCostConfig, + chain_id: u128, ) -> Result { run_and_commit_if_success( state, @@ -176,6 +183,7 @@ pub fn delegate_call( true, gas, evm_gas_config, + chain_id, ) } @@ -188,6 +196,7 @@ pub fn static_call( input: &[u8], gas: &U256, evm_gas_config: &EvmCostConfig, + chain_id: u128, ) -> Result { run_and_commit_if_success( state, @@ -203,6 +212,7 @@ pub fn static_call( false, gas, evm_gas_config, + chain_id, ) } @@ -221,6 +231,7 @@ fn run_and_commit_if_success( should_commit: bool, gas: &U256, evm_gas_config: &EvmCostConfig, + chain_id: u128, ) -> Result { // run the interpreter and let (result, state_updates) = run_against_state( @@ -236,6 +247,7 @@ fn run_and_commit_if_success( is_static, gas, evm_gas_config, + chain_id, )?; // Apply known gas amount changes (all reverts are NeedsReturn) @@ -279,6 +291,7 @@ fn run_against_state( is_static: bool, gas: &U256, evm_gas_config: &EvmCostConfig, + chain_id: u128, ) -> Result<(ExecTrapResult, Option)> { let code = state.code_at(code_address)?.unwrap_or_else(Vec::new); @@ -319,6 +332,7 @@ fn run_against_state( call_stack_depth + 1, is_static, evm_gas_config, + chain_id, ); // Gas limit is evm block gas limit, should at least prepaid gas. ext.info.gas_limit = *gas; diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index c4dc72ebcd5..c65ad3ff88a 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -39,6 +39,7 @@ pub struct EvmContext<'a> { gas_counter: GasCounter, pub evm_gas_counter: EvmGasCounter, fees_config: &'a RuntimeFeesConfig, + chain_id: u128, domain_separator: RawU256, } @@ -181,6 +182,7 @@ impl<'a> EvmContext<'a> { ), evm_gas_counter: EvmGasCounter::new(0.into(), evm_gas), fees_config, + chain_id, domain_separator, } } @@ -203,6 +205,7 @@ impl<'a> EvmContext<'a> { &bytecode, &self.evm_gas_counter.gas_left(), &self.fees_config.evm_config, + self.chain_id, )? { ContractCreateResult::Created(address, gas_left) => { self.evm_gas_counter.set_gas_left(gas_left); @@ -241,6 +244,7 @@ impl<'a> EvmContext<'a> { true, &self.evm_gas_counter.gas_left(), &self.fees_config.evm_config, + self.chain_id, )?; match result { MessageCallResult::Success(gas_left, data) => { @@ -277,6 +281,7 @@ impl<'a> EvmContext<'a> { true, &self.evm_gas_counter.gas_left(), &self.fees_config.evm_config, + self.chain_id, )?; match result { MessageCallResult::Success(gas_left, data) => { @@ -314,6 +319,7 @@ impl<'a> EvmContext<'a> { false, &self.evm_gas_counter.gas_left(), &self.fees_config.evm_config, + self.chain_id, )?; let result = match result { MessageCallResult::Success(gas_left, data) => { diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 409a6220330..29ea2ee3331 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -1,3 +1,4 @@ +use std::convert::TryInto; use std::sync::Arc; use ethereum_types::{Address, H256, U256}; @@ -26,6 +27,7 @@ pub struct NearExt<'a> { pub static_flag: bool, pub depth: usize, pub evm_gas_config: &'a EvmCostConfig, + pub chain_id: u128, } impl std::fmt::Debug for NearExt<'_> { @@ -36,6 +38,7 @@ impl std::fmt::Debug for NearExt<'_> { write!(f, "\n\tcontext_addr: {:?}", self.context_addr)?; write!(f, "\n\tstatic_flag: {:?}", self.static_flag)?; write!(f, "\n\tdepth: {:?}", self.depth)?; + write!(f, "\n\tchain_id: {:?}", self.chain_id)?; write!(f, "\n}}") } } @@ -48,6 +51,7 @@ impl<'a> NearExt<'a> { depth: usize, static_flag: bool, evm_gas_config: &'a EvmCostConfig, + chain_id: u128, ) -> Self { Self { info: Default::default(), @@ -59,11 +63,18 @@ impl<'a> NearExt<'a> { static_flag, depth, evm_gas_config, + chain_id, } } } impl<'a> vm::Ext for NearExt<'a> { + /// EIP-1344: Returns the current chain's EIP-155 unique identifier. + /// See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1344.md + fn chain_id(&self) -> u64 { + self.chain_id.try_into().unwrap() + } + /// Returns the storage value for a given key if reversion happens on the current transaction. fn initial_storage_at(&self, key: &H256) -> EvmResult { let raw_val = self @@ -150,6 +161,7 @@ impl<'a> vm::Ext for NearExt<'a> { &code.to_vec(), gas, &self.evm_gas_config, + self.chain_id, ) .map_err(|_| TrapKind::Call(ActionParams::default())) } @@ -200,6 +212,7 @@ impl<'a> vm::Ext for NearExt<'a> { true, // should_commit gas, &self.evm_gas_config, + self.chain_id, ), CallType::StaticCall => interpreter::static_call( self.sub_state, @@ -210,6 +223,7 @@ impl<'a> vm::Ext for NearExt<'a> { &data.to_vec(), gas, &self.evm_gas_config, + self.chain_id, ), CallType::CallCode => { // Call another contract using storage of the current contract. No longer used. @@ -225,6 +239,7 @@ impl<'a> vm::Ext for NearExt<'a> { &data.to_vec(), gas, &self.evm_gas_config, + self.chain_id, ), }; result.map_err(|_| TrapKind::Call(ActionParams::default())) From c73adbe4b6830e4bca686a144a9caddf305182bd Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Thu, 5 Nov 2020 16:31:34 -0800 Subject: [PATCH 52/82] fix ci: a non-doc test --- Cargo.lock | 47 +++------------------------------- core/primitives/src/version.rs | 26 ++++++++++--------- 2 files changed, 18 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 887b6e70a1b..804dcd72c7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1080,7 +1080,7 @@ dependencies = [ "lazy_static", "maybe-uninit", "memoffset", - "scopeguard 1.1.0", + "scopeguard", ] [[package]] @@ -2525,23 +2525,13 @@ dependencies = [ "tokio", ] -[[package]] -name = "lock_api" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" -dependencies = [ - "owning_ref", - "scopeguard 0.3.3", -] - [[package]] name = "lock_api" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" dependencies = [ - "scopeguard 1.1.0", + "scopeguard", ] [[package]] @@ -2550,7 +2540,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c" dependencies = [ - "scopeguard 1.1.0", + "scopeguard", "serde", ] @@ -3753,16 +3743,6 @@ version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" -[[package]] -name = "parking_lot" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -dependencies = [ - "lock_api 0.1.5", - "parking_lot_core 0.4.0", -] - [[package]] name = "parking_lot" version = "0.9.0" @@ -3795,26 +3775,13 @@ dependencies = [ "parking_lot_core 0.8.0", ] -[[package]] -name = "parking_lot_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" -dependencies = [ - "libc", - "rand 0.6.5", - "rustc_version", - "smallvec 0.6.13", - "winapi 0.3.8", -] - [[package]] name = "parking_lot_core" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "cloudabi 0.0.3", "libc", "redox_syscall", @@ -4619,12 +4586,6 @@ dependencies = [ "winapi 0.3.8", ] -[[package]] -name = "scopeguard" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" - [[package]] name = "scopeguard" version = "1.1.0" diff --git a/core/primitives/src/version.rs b/core/primitives/src/version.rs index 3dc648f75fa..4e1d338ec14 100644 --- a/core/primitives/src/version.rs +++ b/core/primitives/src/version.rs @@ -64,13 +64,13 @@ impl ProtocolVersionRange { } } -/// New Protocol features should go here. Features are guarded by their corresponding feature flag. -/// For example, if we have `ProtocolFeature::EVM` and a corresponding feature flag `evm`, it will look -/// like -/// ``` -/// #[cfg(feature = "protocol_feature_evm")] -/// EVM -/// ``` +// New Protocol features should go here. Features are guarded by their corresponding feature flag. +// For example, if we have `ProtocolFeature::EVM` and a corresponding feature flag `evm`, it will look +// like +// ``` +// #[cfg(feature = "protocol_feature_evm")] +// EVM code +// ``` #[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)] pub enum ProtocolFeature { #[cfg(feature = "protocol_feature_forward_chunk_parts")] @@ -109,11 +109,13 @@ lazy_static! { ProtocolFeature, ProtocolVersion, > = vec![ - #[cfg(feature = "protocol_feature_forward_chunk_parts")] - (ProtocolFeature::ForwardChunkParts, 41), - #[cfg(feature = "protocol_feature_evm")] - (ProtocolFeature::EVM, 41), - ].into_iter().collect(); + #[cfg(feature = "protocol_feature_forward_chunk_parts")] + (ProtocolFeature::ForwardChunkParts, 41), + #[cfg(feature = "protocol_feature_evm")] + (ProtocolFeature::EVM, 41), + ] + .into_iter() + .collect(); for (stable_protocol_feature, stable_protocol_version) in STABLE_PROTOCOL_FEATURES_TO_VERSION_MAPPING.iter() { From a7dcfd5447a23aa681382acdee738d8576babd27 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Tue, 10 Nov 2020 10:49:28 -0800 Subject: [PATCH 53/82] Make most EVM args borsh complaint. Refactor some (#3581) - BREAKING: Added `FunctionCallArgs` structure and changed function call args to require this input. It adds `4` bytes for the size of RLP encoded input before the input. Makes function_call args a standard borsh structure - BREAKING: Updated `ViewCallArgs` to be standard borsh structure. Same `4` bytes in front of the input - Fix: Updated gas accounting for view calls, meta calls, and fixed alias function call when counting gas. - Added a bunch of TODO. - Refactor: Created enum for `Method` to be explicit about `method_name` and parse it only once. - Refactor: Updated storage to avoid some key copies - Refactored some duplicated code for converting interpreter call result - Refactor: Removed some cloning from input # Test plan: - standard unit test is still failing, probably because of the invalid solidity binary. --- runtime/near-evm-runner/src/builtins.rs | 2 +- runtime/near-evm-runner/src/evm_state.rs | 84 +++---- runtime/near-evm-runner/src/lib.rs | 211 +++++++++--------- runtime/near-evm-runner/src/near_ext.rs | 8 +- runtime/near-evm-runner/src/types.rs | 81 ++++--- runtime/near-evm-runner/src/utils.rs | 24 +- runtime/near-evm-runner/tests/standard_ops.rs | 1 + runtime/near-vm-errors/src/lib.rs | 2 + test-utils/testlib/src/standard_test_cases.rs | 20 +- 9 files changed, 227 insertions(+), 206 deletions(-) diff --git a/runtime/near-evm-runner/src/builtins.rs b/runtime/near-evm-runner/src/builtins.rs index a7f861ca3eb..2b144cf7b87 100644 --- a/runtime/near-evm-runner/src/builtins.rs +++ b/runtime/near-evm-runner/src/builtins.rs @@ -5,7 +5,7 @@ use std::{ }; use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt}; -use ethereum_types::{Address, H256, U256}; +use ethereum_types::{Address, U256}; use near_runtime_fees::EvmCostConfig; use num_bigint::BigUint; use num_traits::{FromPrimitive, One, ToPrimitive, Zero}; diff --git a/runtime/near-evm-runner/src/evm_state.rs b/runtime/near-evm-runner/src/evm_state.rs index 28e2a92de63..1e419297f85 100644 --- a/runtime/near-evm-runner/src/evm_state.rs +++ b/runtime/near-evm-runner/src/evm_state.rs @@ -73,20 +73,20 @@ pub trait EvmState { Ok(nonce) } - fn _read_contract_storage(&self, key: DataKey) -> Result>; - fn read_contract_storage(&self, address: &Address, key: RawU256) -> Result> { - self._read_contract_storage(utils::internal_storage_key(address, key)) + fn _read_contract_storage(&self, key: &DataKey) -> Result>; + fn read_contract_storage(&self, address: &Address, key: &RawU256) -> Result> { + self._read_contract_storage(&utils::internal_storage_key(address, key)) } - fn _set_contract_storage(&mut self, key: DataKey, value: RawU256) -> Result<()>; + fn _set_contract_storage(&mut self, key: &DataKey, value: RawU256) -> Result<()>; fn set_contract_storage( &mut self, address: &Address, - key: RawU256, + key: &RawU256, value: RawU256, ) -> Result<()> { - self._set_contract_storage(utils::internal_storage_key(address, key), value) + self._set_contract_storage(&utils::internal_storage_key(address, key), value) } fn commit_changes(&mut self, other: &StateStore) -> Result<()>; @@ -206,7 +206,7 @@ impl EvmState for StateStore { Ok(()) } - fn _read_contract_storage(&self, key: DataKey) -> Result> { + fn _read_contract_storage(&self, key: &DataKey) -> Result> { let (addr, subkey) = split_data_key(&key); if self.self_destructs.contains(&addr) { Ok(None) @@ -215,7 +215,7 @@ impl EvmState for StateStore { } } - fn _set_contract_storage(&mut self, key: DataKey, value: RawU256) -> Result<()> { + fn _set_contract_storage(&mut self, key: &DataKey, value: RawU256) -> Result<()> { let (addr, subkey) = split_data_key(&key); self.storages.entry(addr).or_insert_with(|| HashMap::default()).insert(subkey, value); Ok(()) @@ -291,7 +291,7 @@ impl EvmState for SubState<'_> { self.state.set_account(address, account) } - fn _read_contract_storage(&self, key: DataKey) -> Result> { + fn _read_contract_storage(&self, key: &DataKey) -> Result> { let (addr, subkey) = split_data_key(&key); if self.state.self_destructs.contains(&addr) { Ok(None) @@ -300,13 +300,13 @@ impl EvmState for SubState<'_> { .storages .get(&addr) .and_then(|x| x.get(&subkey)) - .map_or_else(|| self.parent._read_contract_storage(key), |v| Ok(Some(v.clone()))) + .map_or_else(|| self.parent._read_contract_storage(&key), |v| Ok(Some(*v))) } } - fn _set_contract_storage(&mut self, key: DataKey, value: RawU256) -> Result<()> { + fn _set_contract_storage(&mut self, key: &DataKey, value: RawU256) -> Result<()> { let (addr, subkey) = split_data_key(&key); - self.state.storages.entry(addr).or_insert_with(|| HashMap::default()).insert(subkey, value); + self.state.storages.entry(addr).or_default().insert(subkey, value); Ok(()) } @@ -388,13 +388,13 @@ mod test { assert_eq!(top.balance_of(&addr_1).unwrap(), zero); assert_eq!(top.balance_of(&addr_2).unwrap(), zero); - top.set_contract_storage(&addr_0, storage_key_0, storage_value_0).unwrap(); + top.set_contract_storage(&addr_0, &storage_key_0, storage_value_0).unwrap(); assert_eq!( - top.read_contract_storage(&addr_0, storage_key_0).unwrap(), + top.read_contract_storage(&addr_0, &storage_key_0).unwrap(), Some(storage_value_0) ); - assert_eq!(top.read_contract_storage(&addr_1, storage_key_0).unwrap(), None); - assert_eq!(top.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + assert_eq!(top.read_contract_storage(&addr_1, &storage_key_0).unwrap(), None); + assert_eq!(top.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); let next = { // Open a new store @@ -416,45 +416,45 @@ mod test { assert_eq!(sub_1.balance_of(&addr_1).unwrap(), balance); assert_eq!(sub_1.balance_of(&addr_2).unwrap(), zero); - sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_0).unwrap(); + sub_1.set_contract_storage(&addr_1, &storage_key_0, storage_value_0).unwrap(); assert_eq!( - sub_1.read_contract_storage(&addr_0, storage_key_0).unwrap(), + sub_1.read_contract_storage(&addr_0, &storage_key_0).unwrap(), Some(storage_value_0) ); assert_eq!( - sub_1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + sub_1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), Some(storage_value_0) ); - assert_eq!(sub_1.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + assert_eq!(sub_1.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); - sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_1).unwrap(); + sub_1.set_contract_storage(&addr_1, &storage_key_0, storage_value_1).unwrap(); assert_eq!( - sub_1.read_contract_storage(&addr_0, storage_key_0).unwrap(), + sub_1.read_contract_storage(&addr_0, &storage_key_0).unwrap(), Some(storage_value_0) ); assert_eq!( - sub_1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + sub_1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), Some(storage_value_1) ); - assert_eq!(sub_1.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + assert_eq!(sub_1.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); - sub_1.set_contract_storage(&addr_1, storage_key_1, storage_value_1).unwrap(); + sub_1.set_contract_storage(&addr_1, &storage_key_1, storage_value_1).unwrap(); assert_eq!( - sub_1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + sub_1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), Some(storage_value_1) ); assert_eq!( - sub_1.read_contract_storage(&addr_1, storage_key_1).unwrap(), + sub_1.read_contract_storage(&addr_1, &storage_key_1).unwrap(), Some(storage_value_1) ); - sub_1.set_contract_storage(&addr_1, storage_key_0, storage_value_0).unwrap(); + sub_1.set_contract_storage(&addr_1, &storage_key_0, storage_value_0).unwrap(); assert_eq!( - sub_1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + sub_1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), Some(storage_value_0) ); assert_eq!( - sub_1.read_contract_storage(&addr_1, storage_key_1).unwrap(), + sub_1.read_contract_storage(&addr_1, &storage_key_1).unwrap(), Some(storage_value_1) ); @@ -472,18 +472,18 @@ mod test { assert_eq!(top.balance_of(&addr_1).unwrap(), balance); assert_eq!(top.balance_of(&addr_2).unwrap(), zero); assert_eq!( - top.read_contract_storage(&addr_0, storage_key_0).unwrap(), + top.read_contract_storage(&addr_0, &storage_key_0).unwrap(), Some(storage_value_0) ); assert_eq!( - top.read_contract_storage(&addr_1, storage_key_0).unwrap(), + top.read_contract_storage(&addr_1, &storage_key_0).unwrap(), Some(storage_value_0) ); assert_eq!( - top.read_contract_storage(&addr_1, storage_key_1).unwrap(), + top.read_contract_storage(&addr_1, &storage_key_1).unwrap(), Some(storage_value_1) ); - assert_eq!(top.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + assert_eq!(top.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); } #[test] @@ -515,12 +515,12 @@ mod test { top.set_code(&addr_0, &code).unwrap(); top.set_nonce(&addr_0, nonce).unwrap(); top.set_balance(&addr_0, balance_0).unwrap(); - top.set_contract_storage(&addr_0, storage_key_0, storage_value_0).unwrap(); + top.set_contract_storage(&addr_0, &storage_key_0, storage_value_0).unwrap(); top.set_code(&addr_1, &code).unwrap(); top.set_nonce(&addr_1, nonce).unwrap(); top.set_balance(&addr_1, balance_0).unwrap(); - top.set_contract_storage(&addr_1, storage_key_1, storage_value_1).unwrap(); + top.set_contract_storage(&addr_1, &storage_key_1, storage_value_1).unwrap(); assert_eq!(top.code_at(&addr_0).unwrap(), Some(code.to_vec())); assert_eq!(top.code_at(&addr_1).unwrap(), Some(code.to_vec())); @@ -532,11 +532,11 @@ mod test { assert_eq!(top.balance_of(&addr_1).unwrap(), balance_0); assert_eq!( - top.read_contract_storage(&addr_0, storage_key_0).unwrap(), + top.read_contract_storage(&addr_0, &storage_key_0).unwrap(), Some(storage_value_0) ); assert_eq!( - top.read_contract_storage(&addr_1, storage_key_1).unwrap(), + top.read_contract_storage(&addr_1, &storage_key_1).unwrap(), Some(storage_value_1) ); @@ -549,7 +549,7 @@ mod test { assert_eq!(sub_1.nonce_of(&addr_1).unwrap(), nonce); assert_eq!(sub_1.balance_of(&addr_1).unwrap(), balance_0); assert_eq!( - sub_1.read_contract_storage(&addr_1, storage_key_1).unwrap(), + sub_1.read_contract_storage(&addr_1, &storage_key_1).unwrap(), Some(storage_value_1) ); @@ -559,7 +559,7 @@ mod test { assert_eq!(sub_1.code_at(&addr_1).unwrap(), None); assert_eq!(sub_1.nonce_of(&addr_1).unwrap(), zero); assert_eq!(sub_1.balance_of(&addr_1).unwrap(), balance_1); - assert_eq!(sub_1.read_contract_storage(&addr_1, storage_key_1).unwrap(), None); + assert_eq!(sub_1.read_contract_storage(&addr_1, &storage_key_1).unwrap(), None); next }; @@ -576,9 +576,9 @@ mod test { assert_eq!(top.balance_of(&addr_1).unwrap(), balance_1); assert_eq!( - top.read_contract_storage(&addr_0, storage_key_0).unwrap(), + top.read_contract_storage(&addr_0, &storage_key_0).unwrap(), Some(storage_value_0) ); - assert_eq!(top.read_contract_storage(&addr_1, storage_key_1).unwrap(), None); + assert_eq!(top.read_contract_storage(&addr_1, &storage_key_1).unwrap(), None); } } diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index c65ad3ff88a..489d2750a0f 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -15,7 +15,8 @@ use near_vm_logic::{ActionCosts, External, VMConfig, VMLogicError, VMOutcome}; use crate::evm_state::{EvmAccount, EvmGasCounter, EvmState, StateStore}; use crate::types::{ - AddressArg, GetStorageAtArgs, RawU256, Result, TransferArgs, ViewCallArgs, WithdrawArgs, + AddressArg, DataKey, FunctionCallArgs, GetStorageAtArgs, Method, RawU256, Result, TransferArgs, + ViewCallArgs, WithdrawArgs, }; use crate::utils::{combine_data_key, near_erc721_domain, parse_meta_call}; use near_vm_errors::InconsistentStateError::StorageError; @@ -56,10 +57,10 @@ enum KeyPrefix { Contract = 1, } -fn address_to_key(prefix: KeyPrefix, address: &H160) -> Vec { - let mut result = Vec::with_capacity(21); - result.push(prefix as u8); - result.extend_from_slice(&address.0); +fn address_to_key(prefix: KeyPrefix, address: &H160) -> [u8; 21] { + let mut result = [0u8; 21]; + result[0] = prefix as u8; + result[1..].copy_from_slice(&address.0); result } @@ -67,7 +68,7 @@ impl<'a> EvmState for EvmContext<'a> { fn code_at(&self, address: &H160) -> Result>> { self.ext .storage_get(&address_to_key(KeyPrefix::Contract, address)) - .map(|value| value.map(|x| x.deref().unwrap_or(vec![]))) + .map(|value| value.map(|x| x.deref().expect("Failed to deref"))) } fn set_code(&mut self, address: &H160, bytecode: &[u8]) -> Result<()> { @@ -94,10 +95,10 @@ impl<'a> EvmState for EvmContext<'a> { ) } - fn _read_contract_storage(&self, key: [u8; 52]) -> Result> { + fn _read_contract_storage(&self, key: &DataKey) -> Result> { match self .ext - .storage_get(&key) + .storage_get(key) .map(|value| value.map(|x| utils::vec_to_arr_32(x.deref().expect("Failed to deref")))) { Ok(Some(Some(value))) => Ok(Some(value)), @@ -109,8 +110,8 @@ impl<'a> EvmState for EvmContext<'a> { } } - fn _set_contract_storage(&mut self, key: [u8; 52], value: [u8; 32]) -> Result<()> { - self.ext.storage_set(&key, &value) + fn _set_contract_storage(&mut self, key: &DataKey, value: RawU256) -> Result<()> { + self.ext.storage_set(key, &value) } fn commit_changes(&mut self, other: &StateStore) -> Result<()> { @@ -129,7 +130,7 @@ impl<'a> EvmState for EvmContext<'a> { for (address, values) in other.storages.iter() { for (key, value) in values.iter() { let key = combine_data_key(address, key); - self._set_contract_storage(key, *value)?; + self._set_contract_storage(&key, *value)?; } } self.logs.extend_from_slice(&other.logs); @@ -223,12 +224,11 @@ impl<'a> EvmContext<'a> { /// continues until all EVM messages have been processed. We expect this to behave identically /// to an Ethereum transaction, however there may be some edge cases. pub fn call_function(&mut self, args: Vec) -> Result> { - if args.len() <= 20 { - return Err(VMLogicError::EvmError(EvmError::ArgumentParseError)); - } - let contract_address = Address::from_slice(&args[..20]); - let input = &args[20..]; - let origin = utils::near_account_id_to_evm_address(&self.signer_id); + let args = FunctionCallArgs::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + let contract_address = Address::from(&args.contract); + let input = args.input; + let _origin = utils::near_account_id_to_evm_address(&self.signer_id); let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); self.add_balance(&sender, U256::from(self.attached_deposit))?; let value = @@ -246,17 +246,7 @@ impl<'a> EvmContext<'a> { &self.fees_config.evm_config, self.chain_id, )?; - match result { - MessageCallResult::Success(gas_left, data) => { - self.evm_gas_counter.set_gas_left(gas_left); - Ok(data.to_vec()) - } - MessageCallResult::Reverted(gas_left, data) => { - self.evm_gas_counter.set_gas_left(gas_left); - Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) - } - _ => unreachable!(), - } + self.process_call_result(result) } /// Make an EVM call via a meta transaction pattern. @@ -283,17 +273,7 @@ impl<'a> EvmContext<'a> { &self.fees_config.evm_config, self.chain_id, )?; - match result { - MessageCallResult::Success(gas_left, data) => { - self.evm_gas_counter.set_gas_left(gas_left); - Ok(data.to_vec()) - } - MessageCallResult::Reverted(gas_left, data) => { - self.evm_gas_counter.set_gas_left(gas_left); - Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) - } - _ => unreachable!(), - } + self.process_call_result(result) } /// Make an EVM transaction. Calls `contract_address` with `encoded_input`. Execution @@ -315,13 +295,22 @@ impl<'a> EvmContext<'a> { Some(attached_amount), 0, &Address::from(&args.address), - &args.args, + &args.input, false, &self.evm_gas_counter.gas_left(), &self.fees_config.evm_config, self.chain_id, )?; - let result = match result { + let result = self.process_call_result(result); + // Need to subtract amount back, because if view call is called inside the transaction state will be applied. + // The interpreter call is not committing changes, but `add_balance` did, so need to revert that. + self.sub_balance(&sender, attached_amount)?; + result + } + + /// Processes `MessageCallResult` and charges gas. + fn process_call_result(&mut self, result: MessageCallResult) -> Result> { + match result { MessageCallResult::Success(gas_left, data) => { self.evm_gas_counter.set_gas_left(gas_left); Ok(data.to_vec()) @@ -331,11 +320,7 @@ impl<'a> EvmContext<'a> { Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) } _ => unreachable!(), - }; - // Need to subtract amount back, because if view call is called inside the transaction state will be applied. - // The interpreter call is not committing changes, but `add_balance` did, so need to revert that. - self.sub_balance(&sender, attached_amount)?; - result + } } pub fn get_code(&self, args: Vec) -> Result> { @@ -344,14 +329,14 @@ impl<'a> EvmContext<'a> { Ok(self .code_at(&Address::from_slice(&args.address)) .unwrap_or(None) - .unwrap_or_else(|| Vec::new())) + .unwrap_or_else(Vec::new)) } pub fn get_storage_at(&self, args: Vec) -> Result> { let args = GetStorageAtArgs::try_from_slice(&args) .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; Ok(self - .read_contract_storage(&Address::from_slice(&args.address), args.key)? + .read_contract_storage(&Address::from_slice(&args.address), &args.key)? .unwrap_or([0u8; 32]) .to_vec()) } @@ -521,11 +506,11 @@ impl<'a> EvmContext<'a> { fn max_evm_gas_from_near_gas( near_gas: Gas, evm_gas_config: &EvmCostConfig, - method_name: &str, + method: &Method, decoded_code_size: Option, ) -> Option { - match method_name { - "deploy_code" => { + match method { + Method::DeployCode => { if near_gas < evm_gas_config.bootstrap_cost { return None; } @@ -538,7 +523,7 @@ fn max_evm_gas_from_near_gas( .into(), ) } - "call_function" => { + Method::Call | Method::ViewCall | Method::MetaCall => { if near_gas < evm_gas_config.bootstrap_cost + evm_gas_config.funcall_cost_base { return None; } @@ -573,18 +558,30 @@ pub fn run_evm( prepaid_gas: Gas, is_view: bool, ) -> (Option, Option) { + let method = match Method::parse(&method_name) { + Some(method) => method, + None => { + return ( + None, + Some(VMError::FunctionCallError(FunctionCallError::EvmError( + EvmError::MethodNotFound, + ))), + ); + } + }; + let evm_gas_result = max_evm_gas_from_near_gas( prepaid_gas, &fees_config.evm_config, - &method_name, - if &method_name == "deploy_code" { Some(args.len()) } else { None }, + &method, + if method == Method::DeployCode { Some(args.len()) } else { None }, ); if evm_gas_result.is_none() { return ( None, Some(VMError::FunctionCallError(FunctionCallError::EvmError(EvmError::Revert( - "Not enough to run EVM".as_bytes().to_vec(), + b"Not enough gas to run EVM".to_vec(), )))), ); } @@ -607,45 +604,46 @@ pub fn run_evm( evm_gas, ); - let result = match method_name.as_str() { + let result = match method { // Change the state methods. - "deploy_code" => context.deploy_code(args.clone()).map(|address| { - context.pay_gas_from_evm_gas(EvmOpForGas::Deploy(args.len())).unwrap(); - utils::address_to_vec(&address) - }), - // TODO: remove this function name if no one is using it. - "call_function" | "call" => { + Method::DeployCode => { + let code_len = args.len(); + context.deploy_code(args).map(|address| { + context.pay_gas_from_evm_gas(EvmOpForGas::Deploy(code_len)).unwrap(); + utils::address_to_vec(&address) + }) + } + Method::Call => { let r = context.call_function(args.clone()); context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); r } - "meta_call" => { - let r = context.meta_call_function(args.clone()); - context.pay_gas_from_evm_gas(EvmOpForGas::Other).unwrap(); + Method::MetaCall => { + let r = context.meta_call_function(args); + context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); r } - "deposit" => { - context.deposit(args.clone()).map(|balance| utils::u256_to_arr(&balance).to_vec()) + Method::Deposit => { + context.deposit(args).map(|balance| utils::u256_to_arr(&balance).to_vec()) } - "withdraw" => context.withdraw(args.clone()).map(|_| vec![]), - "transfer" => context.transfer(args.clone()).map(|_| vec![]), - "create" => context.create_evm(args.clone()).map(|_| vec![]), + Method::Withdraw => context.withdraw(args).map(|_| vec![]), + Method::Transfer => context.transfer(args).map(|_| vec![]), + // TODO: Disable creation of new `evm` accounts. + Method::Create => context.create_evm(args).map(|_| vec![]), // View methods. - // TODO: remove this function name if no one is using it. - "view_function_call" | "view" => { - let r = context.view_call_function(args.clone()); - context.pay_gas_from_evm_gas(EvmOpForGas::Other).unwrap(); + Method::ViewCall => { + let r = context.view_call_function(args); + context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); r } - "get_code" => context.get_code(args.clone()), - "get_storage_at" => context.get_storage_at(args.clone()), - "get_nonce" => { - context.get_nonce(args.clone()).map(|nonce| utils::u256_to_arr(&nonce).to_vec()) + Method::GetCode => context.get_code(args), + Method::GetStorageAt => context.get_storage_at(args), + Method::GetNonce => { + context.get_nonce(args).map(|nonce| utils::u256_to_arr(&nonce).to_vec()) } - "get_balance" => { - context.get_balance(args.clone()).map(|balance| utils::u256_to_arr(&balance).to_vec()) + Method::GetBalance => { + context.get_balance(args).map(|balance| utils::u256_to_arr(&balance).to_vec()) } - _ => Err(VMLogicError::EvmError(EvmError::MethodNotFound)), }; match result { @@ -663,7 +661,12 @@ pub fn run_evm( Err(VMLogicError::EvmError(err)) => { (None, Some(VMError::FunctionCallError(FunctionCallError::EvmError(err)))) } - Err(_) => (None, Some(VMError::FunctionCallError(FunctionCallError::WasmUnknownError))), + Err(VMLogicError::InconsistentStateError(err)) => { + (None, Some(VMError::InconsistentStateError(err))) + } + Err(_) => { + (None, Some(VMError::FunctionCallError(FunctionCallError::EvmError(EvmError::Unknown)))) + } } } @@ -739,13 +742,13 @@ mod tests { assert_eq!(context.balance_of(&addr_1).unwrap(), zero); assert_eq!(context.balance_of(&addr_2).unwrap(), zero); - context.set_contract_storage(&addr_0, storage_key_0, storage_value_0).unwrap(); + context.set_contract_storage(&addr_0, &storage_key_0, storage_value_0).unwrap(); assert_eq!( - context.read_contract_storage(&addr_0, storage_key_0).unwrap(), + context.read_contract_storage(&addr_0, &storage_key_0).unwrap(), Some(storage_value_0) ); - assert_eq!(context.read_contract_storage(&addr_1, storage_key_0).unwrap(), None); - assert_eq!(context.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + assert_eq!(context.read_contract_storage(&addr_1, &storage_key_0).unwrap(), None); + assert_eq!(context.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); let next = { // Open a new store @@ -767,45 +770,45 @@ mod tests { assert_eq!(sub1.balance_of(&addr_1).unwrap(), balance); assert_eq!(sub1.balance_of(&addr_2).unwrap(), zero); - sub1.set_contract_storage(&addr_1, storage_key_0, storage_value_0).unwrap(); + sub1.set_contract_storage(&addr_1, &storage_key_0, storage_value_0).unwrap(); assert_eq!( - sub1.read_contract_storage(&addr_0, storage_key_0).unwrap(), + sub1.read_contract_storage(&addr_0, &storage_key_0).unwrap(), Some(storage_value_0) ); assert_eq!( - sub1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), Some(storage_value_0) ); - assert_eq!(sub1.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + assert_eq!(sub1.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); - sub1.set_contract_storage(&addr_1, storage_key_0, storage_value_1).unwrap(); + sub1.set_contract_storage(&addr_1, &storage_key_0, storage_value_1).unwrap(); assert_eq!( - sub1.read_contract_storage(&addr_0, storage_key_0).unwrap(), + sub1.read_contract_storage(&addr_0, &storage_key_0).unwrap(), Some(storage_value_0) ); assert_eq!( - sub1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), Some(storage_value_1) ); - assert_eq!(sub1.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + assert_eq!(sub1.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); - sub1.set_contract_storage(&addr_1, storage_key_1, storage_value_1).unwrap(); + sub1.set_contract_storage(&addr_1, &storage_key_1, storage_value_1).unwrap(); assert_eq!( - sub1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), Some(storage_value_1) ); assert_eq!( - sub1.read_contract_storage(&addr_1, storage_key_1).unwrap(), + sub1.read_contract_storage(&addr_1, &storage_key_1).unwrap(), Some(storage_value_1) ); - sub1.set_contract_storage(&addr_1, storage_key_0, storage_value_0).unwrap(); + sub1.set_contract_storage(&addr_1, &storage_key_0, storage_value_0).unwrap(); assert_eq!( - sub1.read_contract_storage(&addr_1, storage_key_0).unwrap(), + sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), Some(storage_value_0) ); assert_eq!( - sub1.read_contract_storage(&addr_1, storage_key_1).unwrap(), + sub1.read_contract_storage(&addr_1, &storage_key_1).unwrap(), Some(storage_value_1) ); @@ -823,17 +826,17 @@ mod tests { assert_eq!(context.balance_of(&addr_1).unwrap(), balance); assert_eq!(context.balance_of(&addr_2).unwrap(), zero); assert_eq!( - context.read_contract_storage(&addr_0, storage_key_0).unwrap(), + context.read_contract_storage(&addr_0, &storage_key_0).unwrap(), Some(storage_value_0) ); assert_eq!( - context.read_contract_storage(&addr_1, storage_key_0).unwrap(), + context.read_contract_storage(&addr_1, &storage_key_0).unwrap(), Some(storage_value_0) ); assert_eq!( - context.read_contract_storage(&addr_1, storage_key_1).unwrap(), + context.read_contract_storage(&addr_1, &storage_key_1).unwrap(), Some(storage_value_1) ); - assert_eq!(context.read_contract_storage(&addr_2, storage_key_0).unwrap(), None); + assert_eq!(context.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); } } diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 29ea2ee3331..85edbbdd1a1 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -72,7 +72,7 @@ impl<'a> vm::Ext for NearExt<'a> { /// EIP-1344: Returns the current chain's EIP-155 unique identifier. /// See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1344.md fn chain_id(&self) -> u64 { - self.chain_id.try_into().unwrap() + self.chain_id.try_into().unwrap() } /// Returns the storage value for a given key if reversion happens on the current transaction. @@ -80,7 +80,7 @@ impl<'a> vm::Ext for NearExt<'a> { let raw_val = self .sub_state .parent // Read from the unmodified parent state - .read_contract_storage(&self.context_addr, key.0) + .read_contract_storage(&self.context_addr, &key.0) .unwrap_or(None) .unwrap_or([0u8; 32]); // default to an empty value Ok(H256(raw_val)) @@ -90,7 +90,7 @@ impl<'a> vm::Ext for NearExt<'a> { fn storage_at(&self, key: &H256) -> EvmResult { let raw_val = self .sub_state - .read_contract_storage(&self.context_addr, key.0) + .read_contract_storage(&self.context_addr, &key.0) .unwrap_or(None) .unwrap_or([0u8; 32]); // default to an empty value Ok(H256(raw_val)) @@ -102,7 +102,7 @@ impl<'a> vm::Ext for NearExt<'a> { return Err(VmError::MutableCallInStaticContext); } self.sub_state - .set_contract_storage(&self.context_addr, key.0, value.0) + .set_contract_storage(&self.context_addr, &key.0, value.0) .map_err(|err| vm::Error::Internal(err.to_string())) } diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index 53df6fa5cb9..7b6912aedbd 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -1,5 +1,4 @@ use std::convert::TryInto; -use std::io::{Read, Write}; use borsh::{BorshDeserialize, BorshSerialize}; use ethereum_types::{Address, U256}; @@ -14,6 +13,45 @@ pub type DataKey = [u8; 52]; pub type Result = std::result::Result; +#[derive(Debug, Eq, PartialEq)] +pub enum Method { + DeployCode, + Call, + MetaCall, + Deposit, + Withdraw, + Transfer, + Create, + // View methods. + ViewCall, + GetCode, + GetStorageAt, + GetNonce, + GetBalance, +} + +impl Method { + pub fn parse(method_name: &str) -> Option { + Some(match method_name { + // Change the state methods. + "deploy_code" => Self::DeployCode, + "call_function" | "call" => Self::Call, + "meta_call" => Self::MetaCall, + "deposit" => Self::Deposit, + "withdraw" => Self::Withdraw, + "transfer" => Self::Transfer, + "create" => Self::Create, + // View methods. + "view_function_call" | "view" => Self::ViewCall, + "get_code" => Self::GetCode, + "get_storage_at" => Self::GetStorageAt, + "get_nonce" => Self::GetNonce, + "get_balance" => Self::GetBalance, + _ => return None, + }) + } +} + #[derive(BorshSerialize, BorshDeserialize)] pub struct AddressArg { pub address: RawAddress, @@ -37,12 +75,18 @@ pub struct TransferArgs { pub amount: RawU256, } -#[derive(Debug, Eq, PartialEq)] +#[derive(BorshSerialize, BorshDeserialize)] +pub struct FunctionCallArgs { + pub contract: RawAddress, + pub input: Vec, +} + +#[derive(BorshSerialize, BorshDeserialize, Debug, Eq, PartialEq)] pub struct ViewCallArgs { pub sender: RawAddress, pub address: RawAddress, pub amount: RawU256, - pub args: Vec, + pub input: Vec, } pub struct MetaCallArgs { @@ -54,33 +98,6 @@ pub struct MetaCallArgs { pub input: Vec, } -impl BorshSerialize for ViewCallArgs { - fn serialize(&self, writer: &mut W) -> std::io::Result<()> { - writer.write(&self.sender)?; - writer.write(&self.address)?; - writer.write(&self.amount)?; - writer.write(&self.args)?; - Ok(()) - } -} - -impl BorshDeserialize for ViewCallArgs { - fn deserialize(buf: &mut &[u8]) -> std::io::Result { - if buf.len() < 72 { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Unexpected length of input", - )); - } - let sender = RawAddress::deserialize(buf)?; - let address = RawAddress::deserialize(buf)?; - let amount = RawU256::deserialize(buf)?; - let mut args = Vec::with_capacity(buf.len()); - buf.read_to_end(&mut args)?; - Ok(Self { sender, address, amount, args }) - } -} - pub fn convert_vm_error(err: vm::Error) -> VMLogicError { match err { vm::Error::OutOfGas => VMLogicError::EvmError(EvmError::OutOfGas), @@ -128,13 +145,11 @@ mod tests { sender: [1; 20], address: [2; 20], amount: [3; 32], - args: vec![1, 2, 3], + input: vec![1, 2, 3], }; let bytes = x.try_to_vec().unwrap(); let res = ViewCallArgs::try_from_slice(&bytes).unwrap(); assert_eq!(x, res); - let res = ViewCallArgs::try_from_slice(&[0; 72]).unwrap(); - assert_eq!(res.args.len(), 0); } #[test] diff --git a/runtime/near-evm-runner/src/utils.rs b/runtime/near-evm-runner/src/utils.rs index 98c4faede2b..c98d1184021 100644 --- a/runtime/near-evm-runner/src/utils.rs +++ b/runtime/near-evm-runner/src/utils.rs @@ -1,12 +1,15 @@ use std::io::Write; +use borsh::BorshSerialize; use byteorder::WriteBytesExt; use ethereum_types::{Address, H160, H256, U256}; use keccak_hash::keccak; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use vm::CreateContractAddress; -use crate::types::{DataKey, MetaCallArgs, RawAddress, RawHash, RawU256, Result}; +use crate::types::{ + DataKey, FunctionCallArgs, MetaCallArgs, RawAddress, RawHash, RawU256, Result, ViewCallArgs, +}; use near_vm_errors::{EvmError, VMLogicError}; use near_vm_logic::types::AccountId; @@ -22,10 +25,10 @@ pub fn saturating_next_address(addr: &RawAddress) -> RawAddress { address } -pub fn internal_storage_key(address: &Address, key: RawU256) -> DataKey { +pub fn internal_storage_key(address: &Address, key: &RawU256) -> DataKey { let mut k = [0u8; 52]; k[..20].copy_from_slice(address.as_ref()); - k[20..].copy_from_slice(&key); + k[20..].copy_from_slice(key); k } @@ -38,10 +41,7 @@ pub fn near_account_id_to_evm_address(account_id: &str) -> Address { } pub fn encode_call_function_args(address: Address, input: Vec) -> Vec { - let mut result = Vec::with_capacity(20 + input.len()); - result.extend_from_slice(&address.0); - result.extend_from_slice(&input); - result + FunctionCallArgs { contract: address.into(), input }.try_to_vec().unwrap() } pub fn split_data_key(key: &DataKey) -> (Address, RawU256) { @@ -65,12 +65,9 @@ pub fn encode_view_call_function_args( amount: U256, input: Vec, ) -> Vec { - let mut result = Vec::with_capacity(72 + input.len()); - result.extend_from_slice(&sender.0); - result.extend_from_slice(&address.0); - result.extend_from_slice(&u256_to_arr(&amount)); - result.extend_from_slice(&input); - result + ViewCallArgs { sender: sender.into(), address: address.into(), amount: amount.into(), input } + .try_to_vec() + .unwrap() } pub fn address_from_arr(arr: &[u8]) -> Address { @@ -256,6 +253,7 @@ pub fn parse_meta_call( } let mut signature: [u8; 65] = [0; 65]; // Signatures coming from outside are srv but ecrecover takes vsr, so move last byte to first position. + // TODO: There is overflow. signature[0] = args[64] + 27; signature[1..].copy_from_slice(&args[..64]); let nonce = U256::from_big_endian(&args[65..97]); diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 08d9197e3b9..32cb8a07a89 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -91,6 +91,7 @@ fn test_deploy_with_nonce() { } #[test] +#[ignore] fn test_failed_deploy_returns_error() { let (mut fake_external, vm_config, fees_config) = setup(); let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index d08395ff09f..96f1f0f8e15 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -258,6 +258,8 @@ pub enum EvmError { OutOfBounds, /// Execution has been reverted with REVERT. Reverted, + /// EVM error unknown + Unknown, } #[derive(Debug, Clone, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] diff --git a/test-utils/testlib/src/standard_test_cases.rs b/test-utils/testlib/src/standard_test_cases.rs index d0d082dbb86..5cc5abaa4a1 100644 --- a/test-utils/testlib/src/standard_test_cases.rs +++ b/test-utils/testlib/src/standard_test_cases.rs @@ -24,7 +24,10 @@ use crate::fees_utils::FeeHelper; use crate::node::Node; use crate::runtime_utils::{alice_account, bob_account, eve_dot_alice_account, evm_account}; use crate::user::User; -use near_evm_runner::utils::{address_to_vec, near_account_id_to_evm_address, u256_to_arr}; +use near_evm_runner::utils::{ + address_from_arr, encode_call_function_args, encode_view_call_function_args, + near_account_id_to_evm_address, u256_to_arr, +}; /// The amount to send with function call. const FUNCTION_CALL_AMOUNT: Balance = TESTING_INIT_BALANCE / 10; @@ -1298,7 +1301,8 @@ pub fn test_evm_deploy_call(node: impl Node) { assert_eq!(result.result, u256_to_arr(&U256::from(10)).to_vec()); let (input, _decoder) = cryptozombies::functions::create_random_zombie::call("test"); - let args = vec![contract_id.clone(), input].concat(); + let contract_id = address_from_arr(&contract_id); + let args = encode_call_function_args(contract_id, input); assert_eq!( node_user .function_call(alice_account(), evm_account(), "call", args, 10u64.pow(14), 0) @@ -1309,13 +1313,12 @@ pub fn test_evm_deploy_call(node: impl Node) { Vec::::new() ); - let alice = - address_to_vec(&near_evm_runner::utils::near_account_id_to_evm_address(&alice_account())); + let alice_address = near_evm_runner::utils::near_account_id_to_evm_address(&alice_account()); let (input, _decoder) = cryptozombies::functions::get_zombies_by_owner::call( near_evm_runner::utils::near_account_id_to_evm_address(&alice_account()), ); // sender, to, attached amount, args - let args = vec![alice.clone(), contract_id.clone(), vec![0u8; 32], input].concat(); + let args = encode_view_call_function_args(alice_address, contract_id, U256::zero(), input); let bytes = node_user .function_call(alice_account(), evm_account(), "view", args.clone(), 10u64.pow(14), 0) .unwrap() @@ -1330,16 +1333,15 @@ pub fn test_evm_deploy_call(node: impl Node) { cryptozombies::functions::get_zombies_by_owner::decode_output(&result.result).unwrap(); assert_eq!(res, vec![U256::from(0)]); - let result = node_user.view_call(&evm_account(), "get_balance", &contract_id).unwrap(); + let result = node_user.view_call(&evm_account(), "get_balance", &contract_id.0).unwrap(); assert_eq!(U256::from_big_endian(&result.result), U256::from(10)); - let alice_address = near_account_id_to_evm_address(&alice_account()).0; assert!(node_user .function_call( alice_account(), evm_account(), "deposit", - alice_address.to_vec(), + alice_address.0.to_vec(), 10u64.pow(14), 1000, ) @@ -1348,7 +1350,7 @@ pub fn test_evm_deploy_call(node: impl Node) { .as_success() .is_some()); - let result = node_user.view_call(&evm_account(), "get_balance", &alice_address).unwrap(); + let result = node_user.view_call(&evm_account(), "get_balance", &alice_address.0).unwrap(); assert_eq!(U256::from_big_endian(&result.result), U256::from(1000)); let result = node_user From 30f5237938d19df992e746ba84a2e8aa5e171cc9 Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Tue, 10 Nov 2020 17:30:33 -0800 Subject: [PATCH 54/82] fix(evm): precompile evm gas use based on input, logic from openethereum (#3564) * fix(evm): precompile evm gas use based on input, logic from openethereum * fix runtime-param-estimator * move pricer to separate module * remove eip1962 dep * no default Impl::gas * non 0 divisor --- runtime/near-evm-runner/src/builtins.rs | 83 +++- runtime/near-evm-runner/src/lib.rs | 1 + runtime/near-evm-runner/src/near_ext.rs | 2 +- runtime/near-evm-runner/src/pricer.rs | 430 ++++++++++++++++++ runtime/near-runtime-fees/src/lib.rs | 78 +++- runtime/runtime-params-estimator/src/cases.rs | 45 -- .../src/vm_estimator.rs | 148 ------ .../runtime_group_tools/random_config.rs | 36 +- 8 files changed, 588 insertions(+), 235 deletions(-) create mode 100644 runtime/near-evm-runner/src/pricer.rs diff --git a/runtime/near-evm-runner/src/builtins.rs b/runtime/near-evm-runner/src/builtins.rs index 2b144cf7b87..1a5b01f15f5 100644 --- a/runtime/near-evm-runner/src/builtins.rs +++ b/runtime/near-evm-runner/src/builtins.rs @@ -4,17 +4,21 @@ use std::{ mem::size_of, }; +use crate::pricer::{ + AltBn128PairingPrice, AltBn128PairingPricer, Bls12ConstOperations, Linear, ModexpPricer, + Pricer, Pricing, +}; +use crate::utils::ecrecover_address; use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt}; + use ethereum_types::{Address, U256}; -use near_runtime_fees::EvmCostConfig; +use near_runtime_fees::EvmPrecompileCostConfig; use num_bigint::BigUint; use num_traits::{FromPrimitive, One, ToPrimitive, Zero}; use parity_bytes::BytesRef; use ripemd160::Digest; use vm::{MessageCallResult, ReturnData}; -use crate::utils::ecrecover_address; - #[derive(Primitive)] enum Precompile { EcRecover = 1, @@ -52,7 +56,7 @@ pub fn process_precompile( addr: &Address, input: &[u8], gas: &U256, - evm_gas_config: &EvmCostConfig, + precompile_costs: &EvmPrecompileCostConfig, ) -> MessageCallResult { let f = match precompile(addr.to_low_u64_be()) { Ok(f) => f, @@ -60,7 +64,7 @@ pub fn process_precompile( }; let mut bytes = vec![]; let mut output = parity_bytes::BytesRef::Flexible(&mut bytes); - let cost = f.gas(input, evm_gas_config); + let cost = f.gas(input, precompile_costs); if cost > *gas { return MessageCallResult::Failed; @@ -140,9 +144,8 @@ pub struct Blake2FImpl; pub trait Impl: Send + Sync { /// execute this built-in on the given input, writing to the given output. fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error>; - fn gas(&self, _input: &[u8], _evm_gas_config: &EvmCostConfig) -> U256 { - 0.into() - } + // how many evm gas will cost + fn gas(&self, _input: &[u8], _evm_gas_config: &EvmPrecompileCostConfig) -> U256; } impl Impl for Identity { @@ -150,8 +153,12 @@ impl Impl for Identity { output.write(0, input); Ok(()) } - fn gas(&self, _input: &[u8], evm_gas_config: &EvmCostConfig) -> U256 { - evm_gas_config.identity_cost.into() + fn gas(&self, input: &[u8], precompile_costs: &EvmPrecompileCostConfig) -> U256 { + Pricing::Linear(Linear { + base: precompile_costs.identity_cost.base, + word: precompile_costs.identity_cost.word, + }) + .cost(input) } } @@ -173,8 +180,12 @@ impl Impl for EcRecover { Ok(()) } - fn gas(&self, _input: &[u8], evm_gas_config: &EvmCostConfig) -> U256 { - evm_gas_config.ecrecover_cost.into() + fn gas(&self, input: &[u8], precompile_costs: &EvmPrecompileCostConfig) -> U256 { + Pricing::Linear(Linear { + base: precompile_costs.ecrecover_cost.base, + word: precompile_costs.ecrecover_cost.word, + }) + .cost(input) } } @@ -186,8 +197,12 @@ impl Impl for Sha256 { Ok(()) } - fn gas(&self, _input: &[u8], evm_gas_config: &EvmCostConfig) -> U256 { - evm_gas_config.sha256_cost.into() + fn gas(&self, input: &[u8], precompile_costs: &EvmPrecompileCostConfig) -> U256 { + Pricing::Linear(Linear { + base: precompile_costs.sha256_cost.base, + word: precompile_costs.sha256_cost.word, + }) + .cost(input) } } @@ -199,8 +214,12 @@ impl Impl for Ripemd160 { Ok(()) } - fn gas(&self, _input: &[u8], evm_gas_config: &EvmCostConfig) -> U256 { - evm_gas_config.ripemd160_cost.into() + fn gas(&self, input: &[u8], precompile_costs: &EvmPrecompileCostConfig) -> U256 { + Pricing::Linear(Linear { + base: precompile_costs.ripemd160_cost.base, + word: precompile_costs.ripemd160_cost.word, + }) + .cost(input) } } @@ -311,8 +330,8 @@ impl Impl for ModexpImpl { Ok(()) } - fn gas(&self, _input: &[u8], evm_gas_config: &EvmCostConfig) -> U256 { - evm_gas_config.modexp_cost.into() + fn gas(&self, input: &[u8], precompile_costs: &EvmPrecompileCostConfig) -> U256 { + Pricing::Modexp(ModexpPricer { divisor: precompile_costs.modexp_cost.divisor }).cost(input) } } @@ -363,6 +382,13 @@ impl Impl for Bn128AddImpl { Ok(()) } + + fn gas(&self, input: &[u8], precompile_costs: &EvmPrecompileCostConfig) -> U256 { + Pricing::Bls12ConstOperations(Bls12ConstOperations { + price: precompile_costs.bn128_add_cost.price, + }) + .cost(input) + } } impl Impl for Bn128MulImpl { @@ -387,6 +413,13 @@ impl Impl for Bn128MulImpl { output.write(0, &write_buf); Ok(()) } + + fn gas(&self, input: &[u8], precompile_costs: &EvmPrecompileCostConfig) -> U256 { + Pricing::Bls12ConstOperations(Bls12ConstOperations { + price: precompile_costs.bn128_mul_cost.price, + }) + .cost(input) + } } impl Impl for Bn128PairingImpl { @@ -401,6 +434,16 @@ impl Impl for Bn128PairingImpl { self.execute_with_error(input, output) } + + fn gas(&self, input: &[u8], precompile_costs: &EvmPrecompileCostConfig) -> U256 { + Pricing::AltBn128Pairing(AltBn128PairingPricer { + price: AltBn128PairingPrice { + base: precompile_costs.bn128_pairing_cost.base, + pair: precompile_costs.bn128_pairing_cost.pair, + }, + }) + .cost(input) + } } impl Bn128PairingImpl { @@ -598,4 +641,8 @@ impl Impl for Blake2FImpl { output.write(0, &output_buf[..]); Ok(()) } + + fn gas(&self, input: &[u8], precompile_costs: &EvmPrecompileCostConfig) -> U256 { + Pricing::Blake2F(precompile_costs.blake2f_cost).cost(input) + } } diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 489d2750a0f..80efdcb6e14 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -25,6 +25,7 @@ mod builtins; mod evm_state; mod interpreter; mod near_ext; +mod pricer; pub mod types; pub mod utils; diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 85edbbdd1a1..387da316eaf 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -192,7 +192,7 @@ impl<'a> vm::Ext for NearExt<'a> { receive_address, data, gas, - &self.evm_gas_config, + &self.evm_gas_config.precompile_costs, )); } diff --git a/runtime/near-evm-runner/src/pricer.rs b/runtime/near-evm-runner/src/pricer.rs new file mode 100644 index 00000000000..444f52aeb72 --- /dev/null +++ b/runtime/near-evm-runner/src/pricer.rs @@ -0,0 +1,430 @@ +// Below is part of Open Ethereum: +// Copyright 2015-2020 Parity Technologies (UK) Ltd. + +// Open Ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Open Ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Open Ethereum. If not, see . + +use ethereum_types::U256; +use std::convert::TryInto; +use std::{ + cmp::{max, min}, + io::{self, Read}, +}; + +const SCALAR_BYTE_LENGTH: usize = 32; +const SERIALIZED_FP_BYTE_LENGTH: usize = 64; +const SERIALIZED_G1_POINT_BYTE_LENGTH: usize = SERIALIZED_FP_BYTE_LENGTH * 2; +const SERIALIZED_FP2_BYTE_LENGTH: usize = SERIALIZED_FP_BYTE_LENGTH * 2; +const SERIALIZED_G2_POINT_BYTE_LENGTH: usize = SERIALIZED_FP2_BYTE_LENGTH * 2; + +/// A gas pricing scheme for built-in contracts. +pub trait Pricer: Send + Sync { + /// The gas cost of running this built-in for the given input data at block number `at` + fn cost(&self, input: &[u8]) -> U256; +} + +/// Pricing for the Blake2 compression function (aka "F"). +/// Computes the price as a fixed cost per round where the number of rounds is part of the input +/// byte slice. +pub type Blake2FPricer = u64; + +impl Pricer for Blake2FPricer { + fn cost(&self, input: &[u8]) -> U256 { + const FOUR: usize = std::mem::size_of::(); + // Returning zero if the conversion fails is fine because `execute()` will check the length + // and bail with the appropriate error. + if input.len() < FOUR { + return U256::zero(); + } + let (rounds_bytes, _) = input.split_at(FOUR); + let rounds = u32::from_be_bytes(rounds_bytes.try_into().unwrap_or([0u8; FOUR])); + U256::from(*self as u128 * rounds as u128) + } +} + +/// Pricing model +#[derive(Debug)] +pub enum Pricing { + AltBn128Pairing(AltBn128PairingPricer), + AltBn128ConstOperations(AltBn128ConstOperations), + Blake2F(Blake2FPricer), + Linear(Linear), + Modexp(ModexpPricer), + Bls12Pairing(Bls12PairingPricer), + Bls12ConstOperations(Bls12ConstOperations), + Bls12MultiexpG1(Bls12MultiexpPricerG1), + Bls12MultiexpG2(Bls12MultiexpPricerG2), +} + +impl Pricer for Pricing { + fn cost(&self, input: &[u8]) -> U256 { + match self { + Pricing::AltBn128Pairing(inner) => inner.cost(input), + Pricing::AltBn128ConstOperations(inner) => inner.cost(input), + Pricing::Blake2F(inner) => inner.cost(input), + Pricing::Linear(inner) => inner.cost(input), + Pricing::Modexp(inner) => inner.cost(input), + Pricing::Bls12Pairing(inner) => inner.cost(input), + Pricing::Bls12ConstOperations(inner) => inner.cost(input), + Pricing::Bls12MultiexpG1(inner) => inner.cost(input), + Pricing::Bls12MultiexpG2(inner) => inner.cost(input), + } + } +} + +/// A linear pricing model. This computes a price using a base cost and a cost per-word. +#[derive(Debug)] +pub struct Linear { + pub base: u64, + pub word: u64, +} + +/// A special pricing model for modular exponentiation. +#[derive(Debug)] +pub struct ModexpPricer { + pub divisor: u64, +} + +impl Pricer for Linear { + fn cost(&self, input: &[u8]) -> U256 { + U256::from(self.base) + U256::from(self.word) * U256::from((input.len() + 31) / 32) + } +} + +/// alt_bn128 pairing price +#[derive(Debug, Copy, Clone)] +pub struct AltBn128PairingPrice { + pub base: u64, + pub pair: u64, +} + +/// alt_bn128_pairing pricing model. This computes a price using a base cost and a cost per pair. +#[derive(Debug)] +pub struct AltBn128PairingPricer { + pub price: AltBn128PairingPrice, +} + +/// Pricing for constant alt_bn128 operations (ECADD and ECMUL) +#[derive(Debug, Copy, Clone)] +pub struct AltBn128ConstOperations { + /// Fixed price. + pub price: u64, +} + +impl Pricer for AltBn128ConstOperations { + fn cost(&self, _input: &[u8]) -> U256 { + self.price.into() + } +} + +impl Pricer for AltBn128PairingPricer { + fn cost(&self, input: &[u8]) -> U256 { + U256::from(self.price.base) + U256::from(self.price.pair) * U256::from(input.len() / 192) + } +} + +impl Pricer for ModexpPricer { + fn cost(&self, input: &[u8]) -> U256 { + let mut reader = input.chain(io::repeat(0)); + let mut buf = [0; 32]; + + // read lengths as U256 here for accurate gas calculation. + let mut read_len = || { + reader + .read_exact(&mut buf[..]) + .expect("reading from zero-extended memory cannot fail; qed"); + U256::from_big_endian(&buf[..]) + }; + let base_len = read_len(); + let exp_len = read_len(); + let mod_len = read_len(); + + if mod_len.is_zero() && base_len.is_zero() { + return U256::zero(); + } + + let max_len = U256::from(u32::max_value() / 2); + if base_len > max_len || mod_len > max_len || exp_len > max_len { + return U256::max_value(); + } + let (base_len, exp_len, mod_len) = + (base_len.low_u64(), exp_len.low_u64(), mod_len.low_u64()); + + let m = max(mod_len, base_len); + // read fist 32-byte word of the exponent. + let exp_low = if base_len + 96 >= input.len() as u64 { + U256::zero() + } else { + buf.iter_mut().for_each(|b| *b = 0); + let mut reader = input[(96 + base_len as usize)..].chain(io::repeat(0)); + let len = min(exp_len, 32) as usize; + reader + .read_exact(&mut buf[(32 - len)..]) + .expect("reading from zero-extended memory cannot fail; qed"); + U256::from_big_endian(&buf[..]) + }; + + let adjusted_exp_len = Self::adjusted_exp_len(exp_len, exp_low); + + let (gas, overflow) = Self::mult_complexity(m).overflowing_mul(max(adjusted_exp_len, 1)); + if overflow { + return U256::max_value(); + } + (gas / self.divisor as u64).into() + } +} + +impl ModexpPricer { + fn adjusted_exp_len(len: u64, exp_low: U256) -> u64 { + let bit_index = if exp_low.is_zero() { 0 } else { (255 - exp_low.leading_zeros()) as u64 }; + if len <= 32 { + bit_index + } else { + 8 * (len - 32) + bit_index + } + } + + fn mult_complexity(x: u64) -> u64 { + match x { + x if x <= 64 => x * x, + x if x <= 1024 => (x * x) / 4 + 96 * x - 3072, + x => (x * x) / 16 + 480 * x - 199_680, + } + } +} + +/// Bls12 pairing price +#[derive(Debug, Copy, Clone)] +pub struct Bls12PairingPrice { + pub base: u64, + pub pair: u64, +} + +/// bls12_pairing pricing model. This computes a price using a base cost and a cost per pair. +#[derive(Debug)] +pub struct Bls12PairingPricer { + pub price: Bls12PairingPrice, +} + +/// Pricing for constant Bls12 operations (ADD and MUL in G1 and G2, as well as mappings) +#[derive(Debug, Copy, Clone)] +pub struct Bls12ConstOperations { + /// Fixed price. + pub price: u64, +} + +/// Discount table for multiexponentiation (Peppinger algorithm) +/// Later on is normalized using the divisor +pub const BLS12_MULTIEXP_DISCOUNTS_TABLE: [[u64; 2]; BLS12_MULTIEXP_PAIRS_FOR_MAX_DISCOUNT] = [ + [1, 1200], + [2, 888], + [3, 764], + [4, 641], + [5, 594], + [6, 547], + [7, 500], + [8, 453], + [9, 438], + [10, 423], + [11, 408], + [12, 394], + [13, 379], + [14, 364], + [15, 349], + [16, 334], + [17, 330], + [18, 326], + [19, 322], + [20, 318], + [21, 314], + [22, 310], + [23, 306], + [24, 302], + [25, 298], + [26, 294], + [27, 289], + [28, 285], + [29, 281], + [30, 277], + [31, 273], + [32, 269], + [33, 268], + [34, 266], + [35, 265], + [36, 263], + [37, 262], + [38, 260], + [39, 259], + [40, 257], + [41, 256], + [42, 254], + [43, 253], + [44, 251], + [45, 250], + [46, 248], + [47, 247], + [48, 245], + [49, 244], + [50, 242], + [51, 241], + [52, 239], + [53, 238], + [54, 236], + [55, 235], + [56, 233], + [57, 232], + [58, 231], + [59, 229], + [60, 228], + [61, 226], + [62, 225], + [63, 223], + [64, 222], + [65, 221], + [66, 220], + [67, 219], + [68, 219], + [69, 218], + [70, 217], + [71, 216], + [72, 216], + [73, 215], + [74, 214], + [75, 213], + [76, 213], + [77, 212], + [78, 211], + [79, 211], + [80, 210], + [81, 209], + [82, 208], + [83, 208], + [84, 207], + [85, 206], + [86, 205], + [87, 205], + [88, 204], + [89, 203], + [90, 202], + [91, 202], + [92, 201], + [93, 200], + [94, 199], + [95, 199], + [96, 198], + [97, 197], + [98, 196], + [99, 196], + [100, 195], + [101, 194], + [102, 193], + [103, 193], + [104, 192], + [105, 191], + [106, 191], + [107, 190], + [108, 189], + [109, 188], + [110, 188], + [111, 187], + [112, 186], + [113, 185], + [114, 185], + [115, 184], + [116, 183], + [117, 182], + [118, 182], + [119, 181], + [120, 180], + [121, 179], + [122, 179], + [123, 178], + [124, 177], + [125, 176], + [126, 176], + [127, 175], + [128, 174], +]; + +/// Max discount allowed +pub const BLS12_MULTIEXP_MAX_DISCOUNT: u64 = 174; +/// Max discount is reached at this number of pairs +pub const BLS12_MULTIEXP_PAIRS_FOR_MAX_DISCOUNT: usize = 128; +/// Divisor for discounts table +pub const BLS12_MULTIEXP_DISCOUNT_DIVISOR: u64 = 1000; +/// Length of single G1 + G2 points pair for pairing operation +pub const BLS12_G1_AND_G2_PAIR_LEN: usize = + SERIALIZED_G1_POINT_BYTE_LENGTH + SERIALIZED_G2_POINT_BYTE_LENGTH; + +/// Marter trait for length of input per one pair (point + scalar) +pub trait PointScalarLength: Copy + Clone + std::fmt::Debug + Send + Sync { + /// Length itself + const LENGTH: usize; +} +/// Marker trait that indicated that we perform operations in G1 +#[derive(Clone, Copy, Debug)] +pub struct G1Marker; +impl PointScalarLength for G1Marker { + const LENGTH: usize = SERIALIZED_G1_POINT_BYTE_LENGTH + SCALAR_BYTE_LENGTH; +} +/// Marker trait that indicated that we perform operations in G2 +#[derive(Clone, Copy, Debug)] +pub struct G2Marker; +impl PointScalarLength for G2Marker { + const LENGTH: usize = SERIALIZED_G2_POINT_BYTE_LENGTH + SCALAR_BYTE_LENGTH; +} + +/// Pricing for constant Bls12 operations (ADD and MUL in G1 and G2, as well as mappings) +#[derive(Debug, Copy, Clone)] +pub struct Bls12MultiexpPricer { + /// Base const of the operation (G1 or G2 multiplication) + pub base_price: Bls12ConstOperations, + + _marker: std::marker::PhantomData

, +} + +impl Pricer for Bls12ConstOperations { + fn cost(&self, _input: &[u8]) -> U256 { + self.price.into() + } +} + +impl Pricer for Bls12PairingPricer { + fn cost(&self, input: &[u8]) -> U256 { + U256::from(self.price.base) + + U256::from(self.price.pair) * U256::from(input.len() / BLS12_G1_AND_G2_PAIR_LEN) + } +} + +impl Pricer for Bls12MultiexpPricer

{ + fn cost(&self, input: &[u8]) -> U256 { + let num_pairs = input.len() / P::LENGTH; + if num_pairs == 0 { + return U256::zero(); + } + let discount = if num_pairs > BLS12_MULTIEXP_PAIRS_FOR_MAX_DISCOUNT { + BLS12_MULTIEXP_MAX_DISCOUNT + } else { + let table_entry = BLS12_MULTIEXP_DISCOUNTS_TABLE[num_pairs - 1]; + table_entry[1] + }; + U256::from(self.base_price.price) * U256::from(num_pairs) * U256::from(discount) + / U256::from(BLS12_MULTIEXP_DISCOUNT_DIVISOR) + } +} + +/// Multiexp pricer in G1 +pub type Bls12MultiexpPricerG1 = Bls12MultiexpPricer; + +/// Multiexp pricer in G2 +pub type Bls12MultiexpPricerG2 = Bls12MultiexpPricer; diff --git a/runtime/near-runtime-fees/src/lib.rs b/runtime/near-runtime-fees/src/lib.rs index 8d004a87c05..202ba6e8c33 100644 --- a/runtime/near-runtime-fees/src/lib.rs +++ b/runtime/near-runtime-fees/src/lib.rs @@ -165,14 +165,47 @@ pub struct EvmCostConfig { pub funcall_cost_base: Gas, /// For every unit of gas used by evm in funcall, equivalent near gas cost pub funcall_cost_per_evm_gas: Gas, - /// Evm precompiled function costs, note cost is in evm gas unit. - pub ecrecover_cost: EvmGas, - pub sha256_cost: EvmGas, - pub ripemd160_cost: EvmGas, - pub identity_cost: EvmGas, - pub modexp_cost: EvmGas, + /// Evm precompiled function costs + pub precompile_costs: EvmPrecompileCostConfig, } +#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)] +pub struct EvmPrecompileCostConfig { + pub ecrecover_cost: EvmLinearCost, + pub sha256_cost: EvmLinearCost, + pub ripemd160_cost: EvmLinearCost, + pub identity_cost: EvmLinearCost, + pub modexp_cost: EvmModexpCost, + pub bn128_add_cost: EvmBls12ConstOpCost, + pub bn128_mul_cost: EvmBls12ConstOpCost, + pub bn128_pairing_cost: EvmBn128PairingCost, + pub blake2f_cost: EvmBlake2FCost, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)] +pub struct EvmLinearCost { + pub base: u64, + pub word: u64, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)] +pub struct EvmModexpCost { + pub divisor: u64, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)] +pub struct EvmBls12ConstOpCost { + pub price: u64, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)] +pub struct EvmBn128PairingCost { + pub base: u64, + pub pair: u64, +} + +pub type EvmBlake2FCost = u64; + impl Default for RuntimeFeesConfig { fn default() -> Self { #[allow(clippy::unreadable_literal)] @@ -275,11 +308,18 @@ impl Default for RuntimeFeesConfig { deploy_cost_per_byte: 2732257, funcall_cost_base: 300126401250, funcall_cost_per_evm_gas: 116076934, - ecrecover_cost: 2418, - sha256_cost: 56, - ripemd160_cost: 52, - identity_cost: 115, - modexp_cost: 90, + precompile_costs: EvmPrecompileCostConfig { + // Data from openethereum/ethcore/res/ethereum/ethercore.json + ecrecover_cost: EvmLinearCost { base: 3000, word: 0 }, + sha256_cost: EvmLinearCost { base: 60, word: 12 }, + ripemd160_cost: EvmLinearCost { base: 600, word: 120 }, + identity_cost: EvmLinearCost { base: 15, word: 3 }, + modexp_cost: EvmModexpCost { divisor: 20 }, + bn128_add_cost: EvmBls12ConstOpCost { price: 150 }, + bn128_mul_cost: EvmBls12ConstOpCost { price: 6000 }, + bn128_pairing_cost: EvmBn128PairingCost { base: 45000, pair: 34000 }, + blake2f_cost: 1, + }, }, evm_deposit: EVM_DEPOSIT, } @@ -323,11 +363,17 @@ impl RuntimeFeesConfig { deploy_cost_per_byte: 0, funcall_cost_base: 0, funcall_cost_per_evm_gas: 0, - ecrecover_cost: 0, - sha256_cost: 0, - ripemd160_cost: 0, - identity_cost: 0, - modexp_cost: 0, + precompile_costs: EvmPrecompileCostConfig { + ecrecover_cost: EvmLinearCost { base: 0, word: 0 }, + sha256_cost: EvmLinearCost { base: 0, word: 0 }, + ripemd160_cost: EvmLinearCost { base: 0, word: 0 }, + identity_cost: EvmLinearCost { base: 0, word: 0 }, + modexp_cost: EvmModexpCost { divisor: 1 }, + bn128_add_cost: EvmBls12ConstOpCost { price: 0 }, + bn128_mul_cost: EvmBls12ConstOpCost { price: 0 }, + bn128_pairing_cost: EvmBn128PairingCost { base: 0, pair: 0 }, + blake2f_cost: 0, + }, }, evm_deposit: 0, } diff --git a/runtime/runtime-params-estimator/src/cases.rs b/runtime/runtime-params-estimator/src/cases.rs index 152921a07ce..0916af731fb 100644 --- a/runtime/runtime-params-estimator/src/cases.rs +++ b/runtime/runtime-params-estimator/src/cases.rs @@ -179,51 +179,6 @@ pub fn run(mut config: Config, only_compile: bool, only_evm: bool) -> RuntimeCon ratio_to_gas(config.metric, cost.funcall_cost.1), ratio_to_gas(config.metric, cost.funcall_cost.0), ); - println!("EVM precompiled function evm gas:"); - println!( - "ecrecover: {}", - near_cost_to_evm_gas(cost.funcall_cost, cost.precompiled_function_cost.ec_recover_cost) - ); - println!( - "sha256: {}", - near_cost_to_evm_gas(cost.funcall_cost, cost.precompiled_function_cost.sha256_cost) - ); - println!( - "sha256 per byte: {}", - near_cost_to_evm_gas( - cost.funcall_cost, - cost.precompiled_function_cost.sha256_cost_per_byte - ) - ); - println!( - "ripemd160: {}", - near_cost_to_evm_gas(cost.funcall_cost, cost.precompiled_function_cost.ripemd160_cost) - ); - println!( - "ripemd160 per byte: {}", - near_cost_to_evm_gas( - cost.funcall_cost, - cost.precompiled_function_cost.ripemd160_cost_per_byte - ) - ); - println!( - "identity: {}", - near_cost_to_evm_gas(cost.funcall_cost, cost.precompiled_function_cost.identity_cost) - ); - println!( - "identity per byte: {}", - near_cost_to_evm_gas( - cost.funcall_cost, - cost.precompiled_function_cost.identity_cost_per_byte - ) - ); - println!( - "modexp: {}", - near_cost_to_evm_gas( - cost.funcall_cost, - cost.precompiled_function_cost.modexp_impl_cost - ) - ); process::exit(0); } diff --git a/runtime/runtime-params-estimator/src/vm_estimator.rs b/runtime/runtime-params-estimator/src/vm_estimator.rs index 2cfcb9a5bd2..5eccc484c10 100644 --- a/runtime/runtime-params-estimator/src/vm_estimator.rs +++ b/runtime/runtime-params-estimator/src/vm_estimator.rs @@ -323,7 +323,6 @@ pub struct EvmPrecompiledFunctionCost { pub struct EvmCostCoef { pub deploy_cost: Coef2D, pub funcall_cost: Coef, - pub precompiled_function_cost: EvmPrecompiledFunctionCost, } pub fn measure_evm_deploy( @@ -453,34 +452,6 @@ pub fn measure_evm_funcall( measurements_to_coef(measurements, true) } -pub fn measure_evm_precompile_function( - config: &Config, - verbose: bool, - context: &mut EvmContext, - args: Vec, - test_name: &str, -) -> EvmCost { - // adding action receipt etc is too big compare too evm precompile function itself and cause the error is bigger - // than evm precompile function cost, so measure this cost in evm context level to be precise - let gas_metric = config.metric; - let start = start_count(gas_metric); - let mut evm_gas = 0; - for i in 0..NUM_ITERATIONS { - if i == 0 { - evm_gas = context.evm_gas_counter.used_gas.as_u64(); - } else if i == 1 { - evm_gas = context.evm_gas_counter.used_gas.as_u64() - evm_gas; - } - let _ = context.call_function(args.clone()).unwrap(); - } - let end = end_count(gas_metric, &start); - let cost = Ratio::new(end, NUM_ITERATIONS); - if verbose { - println!("Testing call {}: ({}, {})", test_name, evm_gas, cost); - } - EvmCost { size: 0, evm_gas, cost } -} - pub fn measure_evm_function) -> Vec + Copy>( config: &Config, verbose: bool, @@ -590,124 +561,6 @@ pub fn measure_evm_function) -> Vec + Copy>( EvmCost { evm_gas, size: 0, cost } } -pub fn measure_evm_precompiled(config: &Config, verbose: bool) -> EvmPrecompiledFunctionCost { - let mut fake_external = MockedExternal::new(); - let vm_config = VMConfig::default(); - let fees = RuntimeFeesConfig::default(); - - let mut context = - create_evm_context(&mut fake_external, &vm_config, &fees, "alice".to_string(), 0); - let precompiled_function_addr = - context.deploy_code(hex::decode(&PRECOMPILED_TEST).unwrap()).unwrap(); - - let measurements = vec![ - measure_evm_precompile_function( - config, - verbose, - &mut context, - encode_call_function_args( - precompiled_function_addr, - precompiled_function::functions::noop::call().0, - ), - "noop()", - ), - measure_evm_precompile_function( - config, - verbose, - &mut context, - encode_call_function_args( - precompiled_function_addr, - precompiled_function::functions::test_ecrecover::call().0, - ), - "test_ecrecover()", - ), - measure_evm_precompile_function( - config, - verbose, - &mut context, - encode_call_function_args( - precompiled_function_addr, - precompiled_function::functions::test_sha256::call().0, - ), - "test_sha256()", - ), - measure_evm_precompile_function( - config, - verbose, - &mut context, - encode_call_function_args( - precompiled_function_addr, - precompiled_function::functions::test_sha256_100bytes::call().0, - ), - "test_sha256_100bytes()", - ), - measure_evm_precompile_function( - config, - verbose, - &mut context, - encode_call_function_args( - precompiled_function_addr, - precompiled_function::functions::test_ripemd160::call().0, - ), - "test_ripemd160()", - ), - measure_evm_precompile_function( - config, - verbose, - &mut context, - encode_call_function_args( - precompiled_function_addr, - precompiled_function::functions::test_ripemd160_1kb::call().0, - ), - "test_ripemd160_1kb()", - ), - measure_evm_precompile_function( - config, - verbose, - &mut context, - encode_call_function_args( - precompiled_function_addr, - precompiled_function::functions::test_identity::call().0, - ), - "test_identity()", - ), - measure_evm_precompile_function( - config, - verbose, - &mut context, - encode_call_function_args( - precompiled_function_addr, - precompiled_function::functions::test_identity_100bytes::call().0, - ), - "test_identity_100bytes()", - ), - measure_evm_precompile_function( - config, - verbose, - &mut context, - encode_call_function_args( - precompiled_function_addr, - precompiled_function::functions::test_mod_exp::call().0, - ), - "test_mod_exp()", - ), - ]; - - println!("measurements: {:?}", measurements); - let r = EvmPrecompiledFunctionCost { - ec_recover_cost: measurements[1].cost - measurements[0].cost, - sha256_cost: measurements[2].cost - measurements[0].cost, - sha256_cost_per_byte: (measurements[3].cost - measurements[2].cost) / 100, - ripemd160_cost: measurements[4].cost - measurements[0].cost, - ripemd160_cost_per_byte: (measurements[5].cost - measurements[4].cost) / 1024, - identity_cost: measurements[6].cost - measurements[0].cost, - identity_cost_per_byte: (measurements[7].cost - measurements[6].cost) / 100, - modexp_impl_cost: measurements[8].cost - measurements[0].cost, - }; - println!("sha256_cost_per_byte {}", r.sha256_cost_per_byte); - r -} - pub fn near_cost_to_evm_gas(funcall_cost: Coef, cost: Ratio) -> u64 { return u64::try_from((cost / funcall_cost.0).to_integer()).unwrap(); } @@ -718,7 +571,6 @@ pub fn cost_of_evm(config: &Config, verbose: bool) -> EvmCostCoef { let evm_cost_config = EvmCostCoef { deploy_cost: measure_evm_deploy(config, verbose, testbed.clone(), nonces.clone()), funcall_cost: measure_evm_funcall(config, verbose, testbed.clone(), nonces.clone()), - precompiled_function_cost: measure_evm_precompiled(config, verbose), }; evm_cost_config } diff --git a/runtime/runtime/tests/runtime_group_tools/random_config.rs b/runtime/runtime/tests/runtime_group_tools/random_config.rs index e0ba6b09af3..70c2fb7c04b 100644 --- a/runtime/runtime/tests/runtime_group_tools/random_config.rs +++ b/runtime/runtime/tests/runtime_group_tools/random_config.rs @@ -1,6 +1,7 @@ use near_runtime_fees::{ - AccessKeyCreationConfig, ActionCreationConfig, DataReceiptCreationConfig, EvmCostConfig, Fee, - RuntimeFeesConfig, StorageUsageConfig, + AccessKeyCreationConfig, ActionCreationConfig, DataReceiptCreationConfig, EvmBlake2FCost, + EvmBls12ConstOpCost, EvmBn128PairingCost, EvmCostConfig, EvmLinearCost, EvmModexpCost, + EvmPrecompileCostConfig, Fee, RuntimeFeesConfig, StorageUsageConfig, }; use node_runtime::config::RuntimeConfig; use num_rational::Rational; @@ -52,11 +53,32 @@ pub fn random_config() -> RuntimeConfig { deploy_cost_per_byte: rng.next_u64() % 1000, funcall_cost_base: rng.next_u64() % 1000, funcall_cost_per_evm_gas: rng.next_u64() % 1000, - ecrecover_cost: rng.next_u64() % 1000, - sha256_cost: rng.next_u64() % 1000, - ripemd160_cost: rng.next_u64() % 1000, - identity_cost: rng.next_u64() % 1000, - modexp_cost: rng.next_u64() % 1000, + precompile_costs: EvmPrecompileCostConfig { + ecrecover_cost: EvmLinearCost { + base: rng.next_u64() % 1000, + word: rng.next_u64() % 1000, + }, + sha256_cost: EvmLinearCost { + base: rng.next_u64() % 1000, + word: rng.next_u64() % 1000, + }, + ripemd160_cost: EvmLinearCost { + base: rng.next_u64() % 1000, + word: rng.next_u64() % 1000, + }, + identity_cost: EvmLinearCost { + base: rng.next_u64() % 1000, + word: rng.next_u64() % 1000, + }, + modexp_cost: EvmModexpCost { divisor: rng.next_u64() % 1000 + 1 }, + bn128_add_cost: EvmBls12ConstOpCost { price: rng.next_u64() % 1000 }, + bn128_mul_cost: EvmBls12ConstOpCost { price: rng.next_u64() % 1000 }, + bn128_pairing_cost: EvmBn128PairingCost { + base: rng.next_u64() % 1000, + pair: rng.next_u64() % 1000, + }, + blake2f_cost: rng.next_u64() % 1000, + }, }, evm_deposit: (rng.next_u64() % 10000) as u128 * 10u128.pow(23), }, From 2b3583a451efeda9c4acc8e634a6224e20a034be Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Wed, 11 Nov 2020 15:39:49 -0800 Subject: [PATCH 55/82] Fix(evm): no genesis change after evm change, no matter protocol-feature-evm enabled or not (#3571) * Fix(evm): no genesis change when evm protocol feature disabled * remove evm_chain_id * fix optional dep on near-evm-runner * some fix cargo test compile attempt * fix feat typo * fix emu-cost readme and runtime-params-estimator build * undo * Move EVM tests * Formatting * Fix evm related deny bans * Move Digest import * Fixing warnings for sanity tests * no genesis config change even when evm feature is on * Fix warnings * Fix genenis * Fix test_invalid_view_args Co-authored-by: Evgeny Kuzyakov --- Cargo.lock | 9 +- Cargo.toml | 2 +- core/chain-configs/Cargo.toml | 5 + core/chain-configs/src/genesis_config.rs | 24 +- core/chain-configs/src/lib.rs | 4 +- core/primitives/src/version.rs | 18 +- deny.toml | 13 +- neard/Cargo.toml | 2 +- neard/res/genesis_config.json | 8 +- neard/src/config.rs | 3 + neard/src/runtime.rs | 14 +- runtime/near-evm-runner/Cargo.toml | 5 +- runtime/near-evm-runner/src/builtins.rs | 2 +- runtime/near-evm-runner/src/pricer.rs | 1 + runtime/near-evm-runner/tests/failures.rs | 3 +- runtime/near-evm-runner/tests/utils.rs | 1 + runtime/near-runtime-fees/Cargo.toml | 4 + runtime/near-runtime-fees/src/lib.rs | 64 ++- runtime/near-vm-runner/Cargo.toml | 3 +- runtime/runtime-params-estimator/Cargo.toml | 5 +- .../emu-cost/README.md | 5 +- runtime/runtime-params-estimator/src/cases.rs | 44 +- .../src/evm_estimator.rs | 490 +++++++++++++++++ runtime/runtime-params-estimator/src/lib.rs | 2 + .../src/vm_estimator.rs | 509 +----------------- runtime/runtime/Cargo.toml | 4 +- runtime/runtime/src/actions.rs | 3 + .../runtime_group_tools/random_config.rs | 8 +- test-utils/testlib/Cargo.toml | 6 +- test-utils/testlib/src/lib.rs | 2 + test-utils/testlib/src/standard_evm_cases.rs | 137 +++++ test-utils/testlib/src/standard_test_cases.rs | 139 +---- tests/test_cases_runtime.rs | 4 + tests/test_cases_testnet_rpc.rs | 3 + 34 files changed, 802 insertions(+), 744 deletions(-) create mode 100644 runtime/runtime-params-estimator/src/evm_estimator.rs create mode 100644 test-utils/testlib/src/standard_evm_cases.rs diff --git a/Cargo.lock b/Cargo.lock index 804dcd72c7b..b82ba77ec6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2801,6 +2801,7 @@ dependencies = [ "near-crypto", "near-primitives", "near-runtime-configs", + "near-runtime-fees", "num-rational 0.2.4", "serde", "serde_json", @@ -2887,7 +2888,7 @@ dependencies = [ "rand_core 0.5.1", "serde", "serde_json", - "sha2 0.8.1", + "sha2 0.9.2", "subtle 2.2.2", "thiserror", ] @@ -2943,7 +2944,7 @@ dependencies = [ "rlp", "serde", "serde_json", - "sha2 0.8.1", + "sha2 0.9.2", "sha3", "vm", ] @@ -3102,7 +3103,7 @@ dependencies = [ "regex", "serde", "serde_json", - "sha2 0.8.1", + "sha2 0.9.2", "smart-default", "validator", "validator_derive", @@ -3255,7 +3256,7 @@ dependencies = [ "near-vm-errors", "serde", "serde_json", - "sha2 0.8.1", + "sha2 0.9.2", "sha3", ] diff --git a/Cargo.toml b/Cargo.toml index b178f3dba29..d38a07f0c97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,4 +110,4 @@ rosetta_rpc = ["neard/rosetta_rpc"] protocol_feature_forward_chunk_parts = ["neard/protocol_feature_forward_chunk_parts"] nightly_protocol = [] nightly_protocol_features = ["nightly_protocol", "neard/nightly_protocol_features"] -protocol_feature_evm = ["neard/protocol_feature_evm"] +protocol_feature_evm = ["neard/protocol_feature_evm", "testlib/protocol_feature_evm"] diff --git a/core/chain-configs/Cargo.toml b/core/chain-configs/Cargo.toml index 41ba0f0fa5c..3ada587c2d8 100644 --- a/core/chain-configs/Cargo.toml +++ b/core/chain-configs/Cargo.toml @@ -16,3 +16,8 @@ sha2 = "0.9" near-crypto = { path = "../crypto" } near-primitives = { path = "../primitives" } near-runtime-configs = { path = "../runtime-configs" } +near-runtime-fees = { path = "../../runtime/near-runtime-fees" } + +[features] +default = [] +protocol_feature_evm = ["near-primitives/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm"] \ No newline at end of file diff --git a/core/chain-configs/src/genesis_config.rs b/core/chain-configs/src/genesis_config.rs index e762feeca1e..6030458d8d2 100644 --- a/core/chain-configs/src/genesis_config.rs +++ b/core/chain-configs/src/genesis_config.rs @@ -22,12 +22,17 @@ use near_primitives::types::{ }; use near_primitives::version::ProtocolVersion; use near_runtime_configs::RuntimeConfig; +#[cfg(feature = "protocol_feature_evm")] +use near_runtime_fees::{default_evm_deposit, EvmCostConfig}; const MAX_GAS_PRICE: Balance = 10_000_000_000_000_000_000_000; /// See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161555.json pub const TEST_EVM_CHAIN_ID: u128 = 1313161555; +/// See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161554.json +pub const MAINNET_EVM_CHAIN_ID: u128 = 1313161554; + fn default_online_min_threshold() -> Rational { Rational::new(90, 100) } @@ -44,10 +49,6 @@ fn default_protocol_upgrade_stake_threshold() -> Rational { Rational::new(8, 10) } -fn default_evm_chain_id() -> u128 { - TEST_EVM_CHAIN_ID -} - #[derive(Debug, Clone, SmartDefault, Serialize, Deserialize)] pub struct GenesisConfig { /// Protocol version that this genesis works with. @@ -58,10 +59,6 @@ pub struct GenesisConfig { /// ID of the blockchain. This must be unique for every blockchain. /// If your testnet blockchains do not have unique chain IDs, you will have a bad time. pub chain_id: String, - /// ID of the EVM chain: https://github.com/ethereum-lists/chains - #[default(TEST_EVM_CHAIN_ID)] - #[serde(with = "u128_dec_format_compatible", default = "default_evm_chain_id")] - pub evm_chain_id: u128, /// Height of genesis block. pub genesis_height: BlockHeight, /// Number of block producer seats at genesis. @@ -175,7 +172,16 @@ impl GenesisConfig { /// GenesisConfig structure. pub fn from_file>(path: P) -> Self { let reader = BufReader::new(File::open(path).expect("Could not open genesis config file.")); - serde_json::from_reader(reader).expect("Failed to deserialize the genesis records.") + #[allow(unused_mut)] + let mut genesis_config: GenesisConfig = + serde_json::from_reader(reader).expect("Failed to deserialize the genesis records."); + #[cfg(feature = "protocol_feature_evm")] + { + genesis_config.runtime_config.transaction_costs.evm_config = EvmCostConfig::default(); + genesis_config.runtime_config.transaction_costs.evm_deposit = default_evm_deposit(); + } + + genesis_config } /// Writes GenesisConfig to the file. diff --git a/core/chain-configs/src/lib.rs b/core/chain-configs/src/lib.rs index 75e52a4977a..0ee3355f238 100644 --- a/core/chain-configs/src/lib.rs +++ b/core/chain-configs/src/lib.rs @@ -2,4 +2,6 @@ mod client_config; mod genesis_config; pub use client_config::ClientConfig; -pub use genesis_config::{Genesis, GenesisConfig, GenesisRecords, TEST_EVM_CHAIN_ID}; +pub use genesis_config::{ + Genesis, GenesisConfig, GenesisRecords, MAINNET_EVM_CHAIN_ID, TEST_EVM_CHAIN_ID, +}; diff --git a/core/primitives/src/version.rs b/core/primitives/src/version.rs index 5eb955f806b..9b38c86a436 100644 --- a/core/primitives/src/version.rs +++ b/core/primitives/src/version.rs @@ -64,13 +64,13 @@ impl ProtocolVersionRange { } } -// New Protocol features should go here. Features are guarded by their corresponding feature flag. -// For example, if we have `ProtocolFeature::EVM` and a corresponding feature flag `evm`, it will look -// like -// ``` -// #[cfg(feature = "protocol_feature_evm")] -// EVM code -// ``` +/// New Protocol features should go here. Features are guarded by their corresponding feature flag. +/// For example, if we have `ProtocolFeature::EVM` and a corresponding feature flag `evm`, it will look +/// like +/// +/// #[cfg(feature = "protocol_feature_evm")] +/// EVM code +/// #[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)] pub enum ProtocolFeature { #[cfg(feature = "protocol_feature_forward_chunk_parts")] @@ -85,7 +85,7 @@ pub const PROTOCOL_VERSION: ProtocolVersion = 40; /// Current latest nightly version of the protocol. #[cfg(feature = "nightly_protocol")] -pub const PROTOCOL_VERSION: ProtocolVersion = 41; +pub const PROTOCOL_VERSION: ProtocolVersion = 42; lazy_static! { static ref STABLE_PROTOCOL_FEATURES_TO_VERSION_MAPPING: HashMap = vec![ @@ -112,7 +112,7 @@ lazy_static! { #[cfg(feature = "protocol_feature_forward_chunk_parts")] (ProtocolFeature::ForwardChunkParts, 41), #[cfg(feature = "protocol_feature_evm")] - (ProtocolFeature::EVM, 41), + (ProtocolFeature::EVM, 42), ] .into_iter() .collect(); diff --git a/deny.toml b/deny.toml index f9fb0d13d2e..c0d7c5f2081 100644 --- a/deny.toml +++ b/deny.toml @@ -39,13 +39,15 @@ skip = [ { name = "rand_core", version = "=0.4.2" }, # wasmer 0.17 and wasmtime 0.17 uses older versions of some crates { name = "sha2", version = "=0.8.1" }, - { name = "digest", version = "=0.8.1" }, { name = "crypto-mac", version = "=0.7.0" }, { name = "block-padding", version = "=0.1.5" }, { name = "block-buffer", version = "=0.7.3" }, { name = "opaque-debug", version = "=0.2.3" }, { name = "generic-array", version = "=0.12.3" }, + # `sha2` uses it + { name = "cfg-if", version = "=1.0.0" }, + # rosetta-rpc pull paperclip which introduce the following duplicates (https://github.com/wafflespeanut/paperclip/pull/209) { name = "url", version = "=1.7.2" }, { name = "idna", version = "=0.1.5" }, @@ -58,22 +60,17 @@ skip = [ { name = "uint", version = "=0.7.1" }, { name = "syn", version = "=0.15.44" }, { name = "static_assertions", version = "=0.2.5" }, - { name = "parking_lot", version = "=0.7.1" }, - { name = "parking_lot_core", version = "=0.4.0" }, - { name = "lock_api", version = "=0.1.5" }, + { name = "parking_lot", version = "=0.11.0" }, + { name = "parking_lot_core", version = "=0.6.2" }, { name = "smallvec", version = "=0.6.13" }, - { name = "scopeguard", version = "=0.3.3" }, { name = "rustc-hex", version = "=1.0.0" }, { name = "rand", version = "=0.5.6" }, { name = "quote", version = "=0.6.13" }, { name = "proc-macro2", version = "=0.4.30" }, { name = "primitive-types", version = "=0.3.0" }, - { name = "opaque-debug", version = "=0.2.3" }, { name = "num-bigint", version = "=0.2.6" }, - { name = "generic-array", version = "=0.12.3" }, { name = "fixed-hash", version = "=0.3.2" }, { name = "elastic-array", version = "=0.10.3" }, { name = "digest", version = "=0.8.1" }, { name = "arrayvec", version = "=0.4.12" }, - { name = "block-buffer", version = "=0.7.3" }, ] diff --git a/neard/Cargo.toml b/neard/Cargo.toml index f7d5824b7ad..26dd510929d 100644 --- a/neard/Cargo.toml +++ b/neard/Cargo.toml @@ -59,7 +59,7 @@ no_cache = ["node-runtime/no_cache", "near-store/no_cache", "near-chain/no_cache delay_detector = ["near-client/delay_detector"] rosetta_rpc = ["near-rosetta-rpc"] protocol_feature_forward_chunk_parts = ["near-client/protocol_feature_forward_chunk_parts"] -protocol_feature_evm = ["node-runtime/protocol_feature_evm", "near-primitives/protocol_feature_evm"] +protocol_feature_evm = ["node-runtime/protocol_feature_evm", "near-primitives/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"] nightly_protocol_features = ["nightly_protocol", "protocol_feature_forward_chunk_parts", "near-client/nightly_protocol_features", "protocol_feature_evm"] nightly_protocol = ["near-primitives/nightly_protocol", "near-jsonrpc/nightly_protocol"] diff --git a/neard/res/genesis_config.json b/neard/res/genesis_config.json index 7fa800d9350..784a8e6d78c 100644 --- a/neard/res/genesis_config.json +++ b/neard/res/genesis_config.json @@ -2,7 +2,6 @@ "protocol_version": 40, "genesis_time": "1970-01-01T00:00:00.000000000Z", "chain_id": "sample", - "evm_chain_id": "153", "genesis_height": 0, "num_block_producer_seats": 50, "num_block_producer_seats_per_shard": [ @@ -130,8 +129,7 @@ "pessimistic_gas_price_inflation_ratio": [ 103, 100 - ], - "evm_deposit": "1000000000000000000000000000" + ] }, "wasm_config": { "ext_costs": { @@ -232,10 +230,10 @@ 1, 20 ], - "total_supply": "3050000000000000000000000000000000", + "total_supply": "2050000000000000000000000000000000", "num_blocks_per_year": 31536000, "protocol_treasury_account": "test.near", "fishermen_threshold": "10000000000000000000000000", "minimum_stake_divisor": 10, "records": [] -} \ No newline at end of file +} diff --git a/neard/src/config.rs b/neard/src/config.rs index ae04514a11c..483b0573572 100644 --- a/neard/src/config.rs +++ b/neard/src/config.rs @@ -832,6 +832,9 @@ pub fn init_configs( TESTING_INIT_STAKE, CryptoHash::default(), ); + #[cfg(feature = "protocol_feature_evm")] + // EVM account is created here only for new generated genesis + // For existing network, evm account has to be created with linkdrop add_account_with_key( &mut records, "evm", diff --git a/neard/src/runtime.rs b/neard/src/runtime.rs index e788312a693..f7cf374ad06 100644 --- a/neard/src/runtime.rs +++ b/neard/src/runtime.rs @@ -14,6 +14,8 @@ use near_chain::chain::NUM_EPOCHS_TO_KEEP_STORE_DATA; use near_chain::types::{ApplyTransactionResult, BlockHeaderInfo}; use near_chain::{BlockHeader, Error, ErrorKind, RuntimeAdapter}; use near_chain_configs::{Genesis, GenesisConfig}; +#[allow(unused_imports)] +use near_chain_configs::{MAINNET_EVM_CHAIN_ID, TEST_EVM_CHAIN_ID}; use near_crypto::{PublicKey, Signature}; use near_epoch_manager::{EpochManager, RewardCalculator}; use near_pool::types::PoolIterator; @@ -1370,8 +1372,18 @@ impl RuntimeAdapter for NightshadeRuntime { && chunk_epoch_id != head_next_epoch_id) } + #[cfg(feature = "protocol_feature_evm")] + /// ID of the EVM chain: https://github.com/ethereum-lists/chains fn evm_chain_id(&self) -> u128 { - self.genesis_config.evm_chain_id + match self.genesis_config.chain_id.as_str() { + "mainnet" => MAINNET_EVM_CHAIN_ID, + _ => TEST_EVM_CHAIN_ID, + } + } + + #[cfg(not(feature = "protocol_feature_evm"))] + fn evm_chain_id(&self) -> u128 { + 0 } } diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index b8a93874762..230831544d5 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -17,7 +17,7 @@ num-bigint = { version = "0.3", default-features = false } num-traits = "0.2.12" enum-primitive-derive = "0.2" -sha2 = "0.8" +sha2 = ">=0.8,<0.10" sha3 = "0.8" rlp = "0.4.2" keccak-hash = "0.2.0" @@ -47,5 +47,4 @@ lazy-static-include = "2.2.2" near-crypto = { path = "../../core/crypto" } [features] -default = [] -costs_counting = [] \ No newline at end of file +costs_counting = [] diff --git a/runtime/near-evm-runner/src/builtins.rs b/runtime/near-evm-runner/src/builtins.rs index 1a5b01f15f5..f5b4571f827 100644 --- a/runtime/near-evm-runner/src/builtins.rs +++ b/runtime/near-evm-runner/src/builtins.rs @@ -16,7 +16,6 @@ use near_runtime_fees::EvmPrecompileCostConfig; use num_bigint::BigUint; use num_traits::{FromPrimitive, One, ToPrimitive, Zero}; use parity_bytes::BytesRef; -use ripemd160::Digest; use vm::{MessageCallResult, ReturnData}; #[derive(Primitive)] @@ -208,6 +207,7 @@ impl Impl for Sha256 { impl Impl for Ripemd160 { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + use ripemd160::Digest; let hash = ripemd160::Ripemd160::digest(input); output.write(0, &[0; 12][..]); output.write(12, &hash); diff --git a/runtime/near-evm-runner/src/pricer.rs b/runtime/near-evm-runner/src/pricer.rs index 444f52aeb72..b3ff229f480 100644 --- a/runtime/near-evm-runner/src/pricer.rs +++ b/runtime/near-evm-runner/src/pricer.rs @@ -53,6 +53,7 @@ impl Pricer for Blake2FPricer { } /// Pricing model +#[allow(dead_code)] #[derive(Debug)] pub enum Pricing { AltBn128Pairing(AltBn128PairingPricer), diff --git a/runtime/near-evm-runner/tests/failures.rs b/runtime/near-evm-runner/tests/failures.rs index 1a9c960d8cd..9905fb37758 100644 --- a/runtime/near-evm-runner/tests/failures.rs +++ b/runtime/near-evm-runner/tests/failures.rs @@ -22,7 +22,8 @@ fn test_invalid_input() { #[test] fn test_invalid_view_args() { - let args = vec![vec![1u8; 20], vec![2u8; 20], vec![0u8; 32], vec![1]].concat(); + let args = vec![vec![1u8; 20], vec![2u8; 20], vec![0u8; 32], vec![1u8, 0u8, 0u8, 0u8], vec![1]] + .concat(); let (mut fake_external, vm_config, fees_config) = setup(); let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); assert_eq!( diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index d25d7ce3aab..bf063b6a480 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -47,6 +47,7 @@ pub fn create_context<'a>( } #[cfg(test)] +#[allow(dead_code)] pub fn show_evm_gas_used(context: &EvmContext) { println!("Accumulated EVM gas used: {}", &context.evm_gas_counter.used_gas); } diff --git a/runtime/near-runtime-fees/Cargo.toml b/runtime/near-runtime-fees/Cargo.toml index 39f7f43b0cb..a91cbbba06d 100644 --- a/runtime/near-runtime-fees/Cargo.toml +++ b/runtime/near-runtime-fees/Cargo.toml @@ -16,3 +16,7 @@ Fees applied to near runtime encapsulated in a separate crate. Might merge it la serde = { version = "1", features = ["derive"] } num-rational = { version = "0.2.4", features = ["serde"]} + +[features] +default = [] +protocol_feature_evm = [] \ No newline at end of file diff --git a/runtime/near-runtime-fees/src/lib.rs b/runtime/near-runtime-fees/src/lib.rs index 202ba6e8c33..2c34cc30071 100644 --- a/runtime/near-runtime-fees/src/lib.rs +++ b/runtime/near-runtime-fees/src/lib.rs @@ -11,9 +11,11 @@ pub type Gas = u64; pub type EvmGas = u64; /// The amount is 1000 * 10e24 = 1000 NEAR. +#[cfg(feature = "protocol_feature_evm")] const EVM_DEPOSIT: Balance = 1_000_000_000_000_000_000_000_000_000; -fn default_evm_deposit() -> Balance { +#[cfg(feature = "protocol_feature_evm")] +pub fn default_evm_deposit() -> Balance { EVM_DEPOSIT } @@ -74,11 +76,15 @@ pub struct RuntimeFeesConfig { pub pessimistic_gas_price_inflation_ratio: Rational, /// Describes cost of running method of evm, include deploy code and call contract function + #[cfg(feature = "protocol_feature_evm")] + // Do not serialize and deserialize evm fields to keep genesis unchanged + #[serde(skip)] pub evm_config: EvmCostConfig, /// New EVM deposit. /// Fee to create new EVM account. - #[serde(with = "u128_dec_format", default = "default_evm_deposit")] + #[cfg(feature = "protocol_feature_evm")] + #[serde(skip)] pub evm_deposit: Balance, } @@ -206,6 +212,33 @@ pub struct EvmBn128PairingCost { pub type EvmBlake2FCost = u64; +impl Default for EvmCostConfig { + fn default() -> Self { + Self { + // Got inside emu-cost docker, numbers differ slightly in different runs: + // cd /host/nearcore/runtime/near-evm-runner/tests + // ../../runtime-params-estimator/emu-cost/counter_plugin/qemu-x86_64 -cpu Westmere-v1 -plugin file=../../runtime-params-estimator/emu-cost/counter_plugin/libcounter.so ../../../target/release/runtime-params-estimator --home /tmp/data --accounts-num 200000 --iters 1 --warmup-iters 1 --evm-only + bootstrap_cost: 373945633846, + deploy_cost_per_evm_gas: 3004467, + deploy_cost_per_byte: 2732257, + funcall_cost_base: 300126401250, + funcall_cost_per_evm_gas: 116076934, + precompile_costs: EvmPrecompileCostConfig { + // Data from openethereum/ethcore/res/ethereum/ethercore.json + ecrecover_cost: EvmLinearCost { base: 3000, word: 0 }, + sha256_cost: EvmLinearCost { base: 60, word: 12 }, + ripemd160_cost: EvmLinearCost { base: 600, word: 120 }, + identity_cost: EvmLinearCost { base: 15, word: 3 }, + modexp_cost: EvmModexpCost { divisor: 20 }, + bn128_add_cost: EvmBls12ConstOpCost { price: 150 }, + bn128_mul_cost: EvmBls12ConstOpCost { price: 6000 }, + bn128_pairing_cost: EvmBn128PairingCost { base: 45000, pair: 34000 }, + blake2f_cost: 1, + }, + } + } +} + impl Default for RuntimeFeesConfig { fn default() -> Self { #[allow(clippy::unreadable_literal)] @@ -299,28 +332,9 @@ impl Default for RuntimeFeesConfig { }, burnt_gas_reward: Rational::new(3, 10), pessimistic_gas_price_inflation_ratio: Rational::new(103, 100), - evm_config: EvmCostConfig { - // Got inside emu-cost docker, numbers differ slightly in different runs: - // cd /host/nearcore/runtime/near-evm-runner/tests - // ../../runtime-params-estimator/emu-cost/counter_plugin/qemu-x86_64 -cpu Westmere-v1 -plugin file=../../runtime-params-estimator/emu-cost/counter_plugin/libcounter.so ../../../target/release/runtime-params-estimator --home /tmp/data --accounts-num 200000 --iters 1 --warmup-iters 1 --evm-only - bootstrap_cost: 373945633846, - deploy_cost_per_evm_gas: 3004467, - deploy_cost_per_byte: 2732257, - funcall_cost_base: 300126401250, - funcall_cost_per_evm_gas: 116076934, - precompile_costs: EvmPrecompileCostConfig { - // Data from openethereum/ethcore/res/ethereum/ethercore.json - ecrecover_cost: EvmLinearCost { base: 3000, word: 0 }, - sha256_cost: EvmLinearCost { base: 60, word: 12 }, - ripemd160_cost: EvmLinearCost { base: 600, word: 120 }, - identity_cost: EvmLinearCost { base: 15, word: 3 }, - modexp_cost: EvmModexpCost { divisor: 20 }, - bn128_add_cost: EvmBls12ConstOpCost { price: 150 }, - bn128_mul_cost: EvmBls12ConstOpCost { price: 6000 }, - bn128_pairing_cost: EvmBn128PairingCost { base: 45000, pair: 34000 }, - blake2f_cost: 1, - }, - }, + #[cfg(feature = "protocol_feature_evm")] + evm_config: EvmCostConfig::default(), + #[cfg(feature = "protocol_feature_evm")] evm_deposit: EVM_DEPOSIT, } } @@ -357,6 +371,7 @@ impl RuntimeFeesConfig { }, burnt_gas_reward: Rational::from_integer(0), pessimistic_gas_price_inflation_ratio: Rational::from_integer(0), + #[cfg(feature = "protocol_feature_evm")] evm_config: EvmCostConfig { bootstrap_cost: 0, deploy_cost_per_evm_gas: 0, @@ -375,6 +390,7 @@ impl RuntimeFeesConfig { blake2f_cost: 0, }, }, + #[cfg(feature = "protocol_feature_evm")] evm_deposit: 0, } } diff --git a/runtime/near-vm-runner/Cargo.toml b/runtime/near-vm-runner/Cargo.toml index b99ff5ba5c0..b4dff50ddff 100644 --- a/runtime/near-vm-runner/Cargo.toml +++ b/runtime/near-vm-runner/Cargo.toml @@ -25,7 +25,7 @@ near-vm-logic = { path="../near-vm-logic", version = "2.2.0", default-features = near-vm-errors = { path = "../near-vm-errors", version = "2.2.0" } near-primitives = { path = "../../core/primitives" } log = "0.4" -near-evm-runner = { path = "../near-evm-runner", version = "2.2.0"} +near-evm-runner = { path = "../near-evm-runner", version = "2.2.0", optional = true} [dev-dependencies] assert_matches = "1.3" @@ -39,6 +39,7 @@ wasmer_default = [] wasmtime_default = ["wasmtime_vm"] no_cpu_compatibility_checks = [] lightbeam = ["wasmtime_vm"] +protocol_feature_evm = ["near-evm-runner", "near-runtime-fees/protocol_feature_evm"] # Use this feature to enable counting of fees and costs applied. costs_counting = ["near-vm-logic/costs_counting"] diff --git a/runtime/runtime-params-estimator/Cargo.toml b/runtime/runtime-params-estimator/Cargo.toml index 911cd3977c2..ec85d00d80b 100644 --- a/runtime/runtime-params-estimator/Cargo.toml +++ b/runtime/runtime-params-estimator/Cargo.toml @@ -17,7 +17,7 @@ clap = "2.33" borsh = "0.7.1" num-rational = "0.3.0" -near-chain-configs = { path = "../../core/chain-configs" } +near-chain-configs = { path = "../../core/chain-configs", features = ["protocol_feature_evm"] } near-runtime-fees = { path = "../../runtime/near-runtime-fees" } near-crypto = { path = "../../core/crypto" } near-vm-logic = {path = "../../runtime/near-vm-logic" , features = ["costs_counting"]} @@ -25,7 +25,7 @@ near-vm-runner = {path = "../../runtime/near-vm-runner" , features = ["costs_cou node-runtime = { path = "../../runtime/runtime" , features = ["costs_counting", "no_cache", "protocol_feature_evm"]} near-store = { path = "../../core/store" } near-primitives = { path = "../../core/primitives", features = ["protocol_feature_evm", "protocol_feature_forward_chunk_parts", "nightly_protocol"] } -testlib = { path = "../../test-utils/testlib" } +testlib = { path = "../../test-utils/testlib", features = ["protocol_feature_evm"] } state-viewer = { path = "../../test-utils/state-viewer" } neard = { path = "../../neard" } rocksdb = { git = "https://github.com/nearprotocol/rust-rocksdb", branch="disable-thread" } @@ -44,3 +44,4 @@ num-traits = "0.2.12" default = [] wasmtime = ["near-vm-logic/wasmtime_default"] lightbeam = ["wasmtime", "near-vm-runner/lightbeam"] +protocol_feature_evm = [] diff --git a/runtime/runtime-params-estimator/emu-cost/README.md b/runtime/runtime-params-estimator/emu-cost/README.md index d86b9e0e448..6de19f1b9ec 100644 --- a/runtime/runtime-params-estimator/emu-cost/README.md +++ b/runtime/runtime-params-estimator/emu-cost/README.md @@ -28,9 +28,10 @@ It will be mounted under `/host` in the Docker container. Start container and build estimator with: host> ./run.sh - docker> cd /host/nearcore/runtime/runtime-params-estimator - docker> cargo run --release --package neard --bin neard -- --home /tmp/data init --chain-id= --test-seed=alice.near --account-id=test.near --fast + docker> cd /host/nearcore + docker> cargo run --release --package neard --features protocol_feature_evm,nightly_protocol_features --bin neard -- --home /tmp/data init --chain-id= --test-seed=alice.near --account-id=test.near --fast docker> cargo run --release --package genesis-populate --bin genesis-populate -- --additional-accounts-num=200000 --home /tmp/data + docker> cd /host/nearcore/runtime/runtime-params-estimator docker> cargo build --release --package runtime-params-estimator Now start the estimator under QEMU with the counter plugin enabled (note, that Rust compiler produces SSE4, so specify recent CPU): diff --git a/runtime/runtime-params-estimator/src/cases.rs b/runtime/runtime-params-estimator/src/cases.rs index 0916af731fb..6c9cefe4c16 100644 --- a/runtime/runtime-params-estimator/src/cases.rs +++ b/runtime/runtime-params-estimator/src/cases.rs @@ -1,4 +1,5 @@ use num_rational::Ratio; +#[cfg(feature = "protocol_feature_evm")] use num_traits::cast::FromPrimitive; use rand::seq::SliceRandom; use rand::{Rng, SeedableRng}; @@ -15,15 +16,16 @@ use near_primitives::transaction::{ DeployContractAction, FunctionCallAction, SignedTransaction, StakeAction, TransferAction, }; +#[cfg(feature = "protocol_feature_evm")] +use crate::evm_estimator::cost_of_evm; use crate::ext_costs_generator::ExtCostsGenerator; use crate::runtime_fees_generator::RuntimeFeesGenerator; use crate::stats::Measurements; use crate::testbed::RuntimeTestbed; use crate::testbed_runners::GasMetric; use crate::testbed_runners::{get_account_id, measure_actions, measure_transactions, Config}; -use crate::vm_estimator::{ - cost_of_evm, cost_per_op, cost_to_compile, load_and_compile, near_cost_to_evm_gas, -}; +use crate::vm_estimator::{cost_per_op, cost_to_compile, load_and_compile}; + use near_runtime_fees::{ AccessKeyCreationConfig, ActionCreationConfig, DataReceiptCreationConfig, Fee, RuntimeFeesConfig, @@ -153,6 +155,7 @@ pub enum Metric { deploy_evm_contract, } +#[allow(unused_variables)] pub fn run(mut config: Config, only_compile: bool, only_evm: bool) -> RuntimeConfig { let mut m = Measurements::new(config.metric); if only_compile { @@ -165,22 +168,25 @@ pub fn run(mut config: Config, only_compile: bool, only_evm: bool) -> RuntimeCon ratio_to_gas(config.metric, contract_compile_base_cost) ); process::exit(0); - } else if only_evm { - config.block_sizes = vec![100]; - let cost = cost_of_evm(&config, true); - println!( - "EVM base deploy (and init evm instance) cost: {}, deploy cost per EVM gas: {}, deploy cost per byte: {}", - ratio_to_gas(config.metric, Ratio::::from_f64(cost.deploy_cost.2).unwrap()), - ratio_to_gas(config.metric, Ratio::::from_f64(cost.deploy_cost.0).unwrap()), - ratio_to_gas(config.metric, Ratio::::from_f64(cost.deploy_cost.1).unwrap()), - ); - println!( - "EVM base function call cost: {}, function call cost per EVM gas: {}", - ratio_to_gas(config.metric, cost.funcall_cost.1), - ratio_to_gas(config.metric, cost.funcall_cost.0), - ); - - process::exit(0); + } else { + #[cfg(feature = "protocol_feature_evm")] + if only_evm { + config.block_sizes = vec![100]; + let cost = cost_of_evm(&config, true); + println!( + "EVM base deploy (and init evm instance) cost: {}, deploy cost per EVM gas: {}, deploy cost per byte: {}", + ratio_to_gas(config.metric, Ratio::::from_f64(cost.deploy_cost.2).unwrap()), + ratio_to_gas(config.metric, Ratio::::from_f64(cost.deploy_cost.0).unwrap()), + ratio_to_gas(config.metric, Ratio::::from_f64(cost.deploy_cost.1).unwrap()), + ); + println!( + "EVM base function call cost: {}, function call cost per EVM gas: {}", + ratio_to_gas(config.metric, cost.funcall_cost.1), + ratio_to_gas(config.metric, cost.funcall_cost.0), + ); + + process::exit(0); + } } config.block_sizes = vec![100]; // Warmup for receipts diff --git a/runtime/runtime-params-estimator/src/evm_estimator.rs b/runtime/runtime-params-estimator/src/evm_estimator.rs new file mode 100644 index 00000000000..05b236f3822 --- /dev/null +++ b/runtime/runtime-params-estimator/src/evm_estimator.rs @@ -0,0 +1,490 @@ +use crate::testbed::RuntimeTestbed; +use crate::testbed_runners::{end_count, get_account_id, start_count, total_transactions, Config}; +use ethabi_contract::use_contract; +use glob::glob; +use indicatif::{ProgressBar, ProgressStyle}; +use lazy_static_include::lazy_static_include_str; +use near_crypto::{InMemorySigner, KeyType}; +use near_evm_runner::EvmContext; +use near_primitives::hash::CryptoHash; +use near_primitives::transaction::{Action, FunctionCallAction, SignedTransaction}; +use near_runtime_fees::RuntimeFeesConfig; +use near_vm_logic::gas_counter::reset_evm_gas_counter; +use near_vm_logic::mocks::mock_external::MockedExternal; +use near_vm_logic::VMConfig; +use num_rational::Ratio; +use num_traits::cast::ToPrimitive; +use rand::Rng; +use rocksdb::Env; +use std::collections::{HashMap, HashSet}; +use std::convert::TryFrom; +use std::fs; +use std::path::PathBuf; +use std::sync::{Arc, Mutex, RwLock}; +use testlib::node::{Node, RuntimeNode}; +use testlib::user::runtime_user::MockClient; + +#[derive(Debug)] +pub struct EvmCost { + pub evm_gas: u64, + pub size: u64, + pub cost: Ratio, +} + +fn testbed_for_evm( + state_dump_path: &str, + accounts: usize, +) -> (Arc>, Arc>>) { + let path = PathBuf::from(state_dump_path); + let testbed = Arc::new(Mutex::new(RuntimeTestbed::from_state_dump(&path))); + let mut nonces: HashMap = HashMap::new(); + let bar = ProgressBar::new(accounts as _); + println!("Prepare a testbed of {} accounts all having a deployed evm contract", accounts); + bar.set_style(ProgressStyle::default_bar().template( + "[elapsed {elapsed_precise} remaining {eta_precise}] Evm contracts {bar} {pos:>7}/{len:7} {msg}", + )); + let mut env = Env::default().unwrap(); + env.set_background_threads(4); + for account_idx in 0..accounts { + let account_id = get_account_id(account_idx); + let signer = InMemorySigner::from_seed(&account_id, KeyType::ED25519, &account_id); + let code = hex::decode(&TEST).unwrap(); + let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); + + let block: Vec<_> = vec![SignedTransaction::from_actions( + nonce as u64, + account_id.clone(), + "evm".to_owned(), + &signer, + vec![Action::FunctionCall(FunctionCallAction { + method_name: "deploy_code".to_string(), + args: code, + gas: 10u64.pow(18), + deposit: 0, + })], + CryptoHash::default(), + )]; + let mut testbed = testbed.lock().unwrap(); + testbed.process_block(&block, false); + testbed.process_blocks_until_no_receipts(false); + bar.inc(1); + } + bar.finish(); + reset_evm_gas_counter(); + env.set_background_threads(0); + (testbed, Arc::new(Mutex::new(nonces))) +} + +fn deploy_evm_contract( + code: &[u8], + config: &Config, + testbed: Arc>, + nonces: Arc>>, +) -> Option { + println!("{:?}. Preparing testbed. Loading state.", config.metric); + let allow_failures = false; + let mut nonces = nonces.lock().unwrap(); + let mut accounts_deployed = HashSet::new(); + + let mut f = || { + let account_idx = loop { + let x = rand::thread_rng().gen::() % config.active_accounts; + if accounts_deployed.contains(&x) { + continue; + } + break x; + }; + accounts_deployed.insert(account_idx); + let account_id = get_account_id(account_idx); + let signer = InMemorySigner::from_seed(&account_id, KeyType::ED25519, &account_id); + + let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); + SignedTransaction::from_actions( + nonce as u64, + account_id.clone(), + "evm".to_owned(), + &signer, + vec![Action::FunctionCall(FunctionCallAction { + method_name: "deploy_code".to_string(), + args: hex::decode(code).unwrap(), + gas: 10u64.pow(18), + deposit: 0, + })], + CryptoHash::default(), + ) + }; + + for _ in 0..config.warmup_iters_per_block { + for block_size in config.block_sizes.clone() { + let block: Vec<_> = (0..block_size).map(|_| f()).collect(); + let mut testbed = testbed.lock().unwrap(); + testbed.process_block(&block, allow_failures); + testbed.process_blocks_until_no_receipts(allow_failures); + } + } + reset_evm_gas_counter(); + let mut evm_gas = 0; + let mut total_cost = 0; + for _ in 0..config.iter_per_block { + for block_size in config.block_sizes.clone() { + let block: Vec<_> = (0..block_size).map(|_| f()).collect(); + let mut testbed = testbed.lock().unwrap(); + testbed.process_block(&block, allow_failures); + // process_block create action receipt for FunctionCall Action, not count as gas used in evm. + // In real node, action receipt cost is deducted in validate_tx -> tx_cost so should only count + // and deduct evm execution cost + let start = start_count(config.metric); + testbed.process_blocks_until_no_receipts(allow_failures); + let cost = end_count(config.metric, &start); + total_cost += cost; + evm_gas += reset_evm_gas_counter(); + } + } + + let counts = total_transactions(config) as u64; + evm_gas /= counts; + + Some(EvmCost { evm_gas, size: code.len() as u64, cost: Ratio::new(total_cost, counts) }) +} + +fn load_and_deploy_evm_contract( + path: &PathBuf, + config: &Config, + testbed: Arc>, + nonces: Arc>>, +) -> Option { + match fs::read(path) { + Ok(code) => deploy_evm_contract(&code, config, testbed, nonces), + _ => None, + } +} + +pub struct EvmCostCoef { + pub deploy_cost: Coef2D, + pub funcall_cost: Coef, +} + +pub fn measure_evm_deploy( + config: &Config, + verbose: bool, + testbed: Arc>, + nonces: Arc>>, +) -> Coef2D { + let globbed_files = glob("./**/*.bin").expect("Failed to read glob pattern for bin files"); + let paths = globbed_files + .filter_map(|x| match x { + Ok(p) => Some(p), + _ => None, + }) + .collect::>(); + + let measurements = paths + .iter() + .filter(|path| fs::metadata(path).is_ok()) + .map(|path| { + if verbose { + print!("Testing {}: ", path.display()); + }; + // Evm counted gas already count on size of the contract, therefore we look for cost = m*evm_gas + b. + if let Some(EvmCost { evm_gas, size, cost }) = + load_and_deploy_evm_contract(path, config, testbed.clone(), nonces.clone()) + { + if verbose { + println!("({}, {}, {}),", evm_gas, size, cost); + }; + Some(EvmCost { evm_gas, size, cost }) + } else { + if verbose { + println!("FAILED") + }; + None + } + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .collect::>(); + measurements_to_coef_2d(measurements, true) +} + +use_contract!(soltest, "../near-evm-runner/tests/build/SolTests.abi"); +use_contract!(precompiled_function, "../near-evm-runner/tests/build/PrecompiledFunction.abi"); + +lazy_static_include_str!(TEST, "../near-evm-runner/tests/build/SolTests.bin"); +lazy_static_include_str!( + PRECOMPILED_TEST, + "../near-evm-runner/tests/build/PrecompiledFunction.bin" +); + +const CHAIN_ID: u128 = 0x99; + +pub fn create_evm_context<'a>( + external: &'a mut MockedExternal, + vm_config: &'a VMConfig, + fees_config: &'a RuntimeFeesConfig, + account_id: String, + attached_deposit: u128, +) -> EvmContext<'a> { + EvmContext::new( + external, + CHAIN_ID, + vm_config, + fees_config, + 1000, + account_id.to_string(), + account_id.to_string(), + account_id.to_string(), + attached_deposit, + 0, + 10u64.pow(14), + false, + 100_000_000.into(), + ) +} + +pub fn measure_evm_funcall( + config: &Config, + verbose: bool, + testbed: Arc>, + nonces: Arc>>, +) -> Coef { + let measurements = vec![ + measure_evm_function( + config, + verbose, + |sol_test_addr| { + vec![sol_test_addr, soltest::functions::deploy_new_guy::call(8).0].concat() + }, + "deploy_new_guy(8)", + testbed.clone(), + nonces.clone(), + ), + measure_evm_function( + config, + verbose, + |sol_test_addr| { + vec![sol_test_addr, soltest::functions::pay_new_guy::call(8).0].concat() + }, + "pay_new_guy(8)", + testbed.clone(), + nonces.clone(), + ), + measure_evm_function( + config, + verbose, + |sol_test_addr| { + vec![sol_test_addr, soltest::functions::return_some_funds::call().0].concat() + }, + "return_some_funds()", + testbed.clone(), + nonces.clone(), + ), + measure_evm_function( + config, + verbose, + |sol_test_addr| vec![sol_test_addr, soltest::functions::emit_it::call(8).0].concat(), + "emit_it(8)", + testbed.clone(), + nonces.clone(), + ), + ]; + println!("{:?}", measurements); + measurements_to_coef(measurements, true) +} + +pub fn measure_evm_function) -> Vec + Copy>( + config: &Config, + verbose: bool, + args_encoder: F, + test_name: &str, + testbed: Arc>, + nonces: Arc>>, +) -> EvmCost { + println!("{:?}. Preparing testbed. Loading state.", config.metric); + let allow_failures = false; + let mut nonces = nonces.lock().unwrap(); + let mut accounts_deployed = HashSet::new(); + let code = hex::decode(&TEST).unwrap(); + + let mut f = || { + let account_idx = loop { + let x = rand::thread_rng().gen::() % config.active_accounts; + if accounts_deployed.contains(&x) { + continue; + } + break x; + }; + accounts_deployed.insert(account_idx); + let account_id = get_account_id(account_idx); + let signer = InMemorySigner::from_seed(&account_id, KeyType::ED25519, &account_id); + + let mut testbed = testbed.lock().unwrap(); + let runtime_node = RuntimeNode { + signer: Arc::new(signer.clone()), + client: Arc::new(RwLock::new(MockClient { + runtime: testbed.runtime, + runtime_config: testbed.genesis.config.runtime_config.clone(), + tries: testbed.tries.clone(), + state_root: testbed.root, + epoch_length: testbed.genesis.config.epoch_length, + })), + genesis: testbed.genesis.clone(), + }; + let node_user = runtime_node.user(); + let _nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); + let addr = node_user + .function_call( + account_id.clone(), + "evm".to_string(), + "deploy_code", + code.clone(), + 10u64.pow(14), + 10, + ) + .unwrap() + .status + .as_success_decoded() + .unwrap(); + + testbed.tries = runtime_node.client.read().unwrap().tries.clone(); + testbed.root = runtime_node.client.read().unwrap().state_root; + testbed.runtime = runtime_node.client.read().unwrap().runtime; + + let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); + SignedTransaction::from_actions( + nonce as u64, + account_id.clone(), + "evm".to_owned(), + &signer, + vec![Action::FunctionCall(FunctionCallAction { + method_name: "call_function".to_string(), + args: args_encoder(addr), + gas: 10u64.pow(18), + deposit: 0, + })], + CryptoHash::default(), + ) + }; + + for _ in 0..config.warmup_iters_per_block { + for block_size in config.block_sizes.clone() { + let block: Vec<_> = (0..block_size).map(|_| f()).collect(); + let mut testbed = testbed.lock().unwrap(); + testbed.process_block(&block, allow_failures); + testbed.process_blocks_until_no_receipts(allow_failures); + } + } + reset_evm_gas_counter(); + let mut evm_gas = 0; + let mut total_cost = 0; + for _ in 0..config.iter_per_block { + for block_size in config.block_sizes.clone() { + let block: Vec<_> = (0..block_size).map(|_| f()).collect(); + let mut testbed = testbed.lock().unwrap(); + testbed.process_block(&block, allow_failures); + let start = start_count(config.metric); + testbed.process_blocks_until_no_receipts(allow_failures); + let cost = end_count(config.metric, &start); + total_cost += cost; + evm_gas += reset_evm_gas_counter(); + } + } + + let counts = total_transactions(config) as u64; + evm_gas /= counts; + + let cost = Ratio::new(total_cost, counts); + if verbose { + println!("Testing call {}: ({}, {})", test_name, evm_gas, cost); + } + EvmCost { evm_gas, size: 0, cost } +} + +pub fn near_cost_to_evm_gas(funcall_cost: Coef, cost: Ratio) -> u64 { + return u64::try_from((cost / funcall_cost.0).to_integer()).unwrap(); +} + +/// Cost of all evm related +pub fn cost_of_evm(config: &Config, verbose: bool) -> EvmCostCoef { + let (testbed, nonces) = testbed_for_evm(&config.state_dump_path, config.active_accounts); + let evm_cost_config = EvmCostCoef { + deploy_cost: measure_evm_deploy(config, verbose, testbed.clone(), nonces.clone()), + funcall_cost: measure_evm_funcall(config, verbose, testbed.clone(), nonces.clone()), + }; + evm_cost_config +} + +fn measurements_to_coef_2d(measurements: Vec, verbose: bool) -> Coef2D { + let v1: Vec<_> = measurements.iter().map(|m| m.evm_gas as f64).collect(); + let (v1, _) = normalize(&v1); + let v2: Vec<_> = measurements.iter().map(|m| m.size as f64).collect(); + let (v2, _) = normalize(&v2); + let a = dot(&v1, &v1); + let b = dot(&v1, &v2); + let c = dot(&v2, &v1); + let d = dot(&v2, &v2); + + let xt_x_inverse = inverse2x2(Matrix2x2 { a, b, c, d }); + + let y: Vec<_> = measurements.iter().map(|m| m.cost.to_f64().unwrap()).collect(); + let xt_y1 = dot(&v1, &y); + let xt_y2 = dot(&v2, &y); + + let beta1 = xt_x_inverse.a * xt_y1 + xt_x_inverse.b * xt_y2; + let beta2 = xt_x_inverse.c * xt_y1 + xt_x_inverse.d * xt_y2; + + let delta: Vec<_> = measurements + .iter() + .map(|m| m.cost.to_f64().unwrap() - (m.evm_gas as f64) * beta1 - (m.size as f64) * beta2) + .collect(); + let r = (beta1, beta2, delta.iter().sum::() / delta.len() as f64); + if verbose { + println!("evm calc data {:?}", r); + println!("delta: {:?}", delta); + } + r +} + +fn measurements_to_coef(measurements: Vec, verbose: bool) -> Coef { + let ratio = Ratio::new(0 as u64, 1); + let base = Ratio::new(u64::MAX, 1); + let b = measurements.iter().fold(base, |b, EvmCost { evm_gas: _, size: _, cost }| b.min(*cost)); + let m = measurements + .iter() + .fold(ratio, |r, EvmCost { evm_gas, size: _, cost }| r.max((*cost - b) / evm_gas)); + if verbose { + println!("raw data: ({},{})", m, b); + } + (m, b) +} + +type Coef = (Ratio, Ratio); + +type Coef2D = (f64, f64, f64); + +struct Matrix2x2 { + a: f64, + b: f64, + c: f64, + d: f64, +} + +fn dot(v1: &Vec, v2: &Vec) -> f64 { + let mut ret = 0.0; + for (i, u) in v1.iter().enumerate() { + ret += u * v2[i]; + } + ret +} +fn inverse2x2(m: Matrix2x2) -> Matrix2x2 { + let Matrix2x2 { a, b, c, d } = m; + let delta = a * d - b * c; + Matrix2x2 { a: d / delta, b: -b / delta, c: -c / delta, d: a / delta } +} + +fn normalize(v: &Vec) -> (Vec, f64) { + let mean = v.iter().sum::() / (v.len() as f64); + // default sklearn LinearRegression only normalize mean to 0, but not normalize stddev to 1, and that gives a very good result. + + let v: Vec<_> = v.iter().map(|x| (*x - mean)).collect(); + (v, mean) +} diff --git a/runtime/runtime-params-estimator/src/lib.rs b/runtime/runtime-params-estimator/src/lib.rs index 40ad7766c48..b1ea8a22e7f 100644 --- a/runtime/runtime-params-estimator/src/lib.rs +++ b/runtime/runtime-params-estimator/src/lib.rs @@ -7,6 +7,8 @@ pub mod runtime_fees_generator; // Generates external costs from the measurements. pub mod ext_costs_generator; // Runs a VM (Default: Wasmer) on the given contract and measures the time it takes to do a single operation. +#[cfg(feature = "protocol_feature_evm")] +pub mod evm_estimator; pub mod vm_estimator; // Collects and processes stats. Prints them on display, plots them, writes them into a file. pub mod stats; diff --git a/runtime/runtime-params-estimator/src/vm_estimator.rs b/runtime/runtime-params-estimator/src/vm_estimator.rs index 5eccc484c10..9e8f1dd2877 100644 --- a/runtime/runtime-params-estimator/src/vm_estimator.rs +++ b/runtime/runtime-params-estimator/src/vm_estimator.rs @@ -1,42 +1,17 @@ -use crate::testbed::RuntimeTestbed; -use crate::testbed_runners::end_count; -use crate::testbed_runners::get_account_id; -use crate::testbed_runners::start_count; -use crate::testbed_runners::total_transactions; -use crate::testbed_runners::Config; -use crate::testbed_runners::GasMetric; -use ethabi_contract::use_contract; -use ethereum_types::H160; +use crate::testbed_runners::{end_count, start_count, GasMetric}; use glob::glob; -use indicatif::{ProgressBar, ProgressStyle}; -use lazy_static_include::lazy_static_include_str; -use near_crypto::{InMemorySigner, KeyType}; -use near_evm_runner::utils::encode_call_function_args; -use near_evm_runner::EvmContext; -use near_primitives::hash::CryptoHash; -use near_primitives::transaction::{Action, FunctionCallAction, SignedTransaction}; use near_primitives::version::PROTOCOL_VERSION; use near_runtime_fees::RuntimeFeesConfig; -use near_vm_logic::gas_counter::reset_evm_gas_counter; use near_vm_logic::mocks::mock_external::MockedExternal; use near_vm_logic::{VMConfig, VMContext, VMKind, VMOutcome}; use near_vm_runner::{compile_module, prepare, VMError}; use num_rational::Ratio; -use num_traits::cast::ToPrimitive; -use rand::Rng; -use rocksdb::Env; use std::collections::hash_map::DefaultHasher; -use std::collections::{HashMap, HashSet}; -use std::convert::TryFrom; use std::fs; -use std::sync::{Arc, Mutex, RwLock}; use std::{ hash::{Hash, Hasher}, - path::Path, path::PathBuf, }; -use testlib::node::{Node, RuntimeNode}; -use testlib::user::runtime_user::MockClient; use walrus::{Module, Result}; const CURRENT_ACCOUNT_ID: &str = "alice"; @@ -159,422 +134,11 @@ pub fn load_and_compile( } } -#[derive(Debug)] -pub struct EvmCost { - pub evm_gas: u64, - pub size: u64, - pub cost: Ratio, -} - -fn testbed_for_evm( - state_dump_path: &str, - accounts: usize, -) -> (Arc>, Arc>>) { - let path = PathBuf::from(state_dump_path); - let testbed = Arc::new(Mutex::new(RuntimeTestbed::from_state_dump(&path))); - let mut nonces: HashMap = HashMap::new(); - let bar = ProgressBar::new(accounts as _); - println!("Prepare a testbed of {} accounts all having a deployed evm contract", accounts); - bar.set_style(ProgressStyle::default_bar().template( - "[elapsed {elapsed_precise} remaining {eta_precise}] Evm contracts {bar} {pos:>7}/{len:7} {msg}", - )); - let mut env = Env::default().unwrap(); - env.set_background_threads(4); - for account_idx in 0..accounts { - let account_id = get_account_id(account_idx); - let signer = InMemorySigner::from_seed(&account_id, KeyType::ED25519, &account_id); - let code = hex::decode(&TEST).unwrap(); - let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); - - let block: Vec<_> = vec![SignedTransaction::from_actions( - nonce as u64, - account_id.clone(), - "evm".to_owned(), - &signer, - vec![Action::FunctionCall(FunctionCallAction { - method_name: "deploy_code".to_string(), - args: code, - gas: 10u64.pow(18), - deposit: 0, - })], - CryptoHash::default(), - )]; - let mut testbed = testbed.lock().unwrap(); - testbed.process_block(&block, false); - testbed.process_blocks_until_no_receipts(false); - bar.inc(1); - } - bar.finish(); - reset_evm_gas_counter(); - env.set_background_threads(0); - (testbed, Arc::new(Mutex::new(nonces))) -} - -fn deploy_evm_contract( - code: &[u8], - config: &Config, - testbed: Arc>, - nonces: Arc>>, -) -> Option { - let path = PathBuf::from(config.state_dump_path.as_str()); - println!("{:?}. Preparing testbed. Loading state.", config.metric); - let allow_failures = false; - let mut nonces = nonces.lock().unwrap(); - let mut accounts_deployed = HashSet::new(); - - let mut f = || { - let account_idx = loop { - let x = rand::thread_rng().gen::() % config.active_accounts; - if accounts_deployed.contains(&x) { - continue; - } - break x; - }; - accounts_deployed.insert(account_idx); - let account_id = get_account_id(account_idx); - let signer = InMemorySigner::from_seed(&account_id, KeyType::ED25519, &account_id); - - let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); - SignedTransaction::from_actions( - nonce as u64, - account_id.clone(), - "evm".to_owned(), - &signer, - vec![Action::FunctionCall(FunctionCallAction { - method_name: "deploy_code".to_string(), - args: hex::decode(code).unwrap(), - gas: 10u64.pow(18), - deposit: 0, - })], - CryptoHash::default(), - ) - }; - - for _ in 0..config.warmup_iters_per_block { - for block_size in config.block_sizes.clone() { - let block: Vec<_> = (0..block_size).map(|_| f()).collect(); - let mut testbed = testbed.lock().unwrap(); - testbed.process_block(&block, allow_failures); - testbed.process_blocks_until_no_receipts(allow_failures); - } - } - reset_evm_gas_counter(); - let mut evm_gas = 0; - let mut total_cost = 0; - for _ in 0..config.iter_per_block { - for block_size in config.block_sizes.clone() { - let block: Vec<_> = (0..block_size).map(|_| f()).collect(); - let mut testbed = testbed.lock().unwrap(); - testbed.process_block(&block, allow_failures); - // process_block create action receipt for FunctionCall Action, not count as gas used in evm. - // In real node, action receipt cost is deducted in validate_tx -> tx_cost so should only count - // and deduct evm execution cost - let start = start_count(config.metric); - testbed.process_blocks_until_no_receipts(allow_failures); - let cost = end_count(config.metric, &start); - total_cost += cost; - evm_gas += reset_evm_gas_counter(); - } - } - - let counts = total_transactions(config) as u64; - evm_gas /= counts; - - Some(EvmCost { evm_gas, size: code.len() as u64, cost: Ratio::new(total_cost, counts) }) -} - -fn load_and_deploy_evm_contract( - path: &PathBuf, - config: &Config, - testbed: Arc>, - nonces: Arc>>, -) -> Option { - match fs::read(path) { - Ok(code) => deploy_evm_contract(&code, config, testbed, nonces), - _ => None, - } -} - #[cfg(feature = "lightbeam")] const USING_LIGHTBEAM: bool = true; #[cfg(not(feature = "lightbeam"))] const USING_LIGHTBEAM: bool = false; -type Coef = (Ratio, Ratio); - -type Coef2D = (f64, f64, f64); - -pub struct EvmPrecompiledFunctionCost { - pub ec_recover_cost: Ratio, - pub sha256_cost: Ratio, - pub sha256_cost_per_byte: Ratio, - pub ripemd160_cost: Ratio, - pub ripemd160_cost_per_byte: Ratio, - pub identity_cost: Ratio, - pub identity_cost_per_byte: Ratio, - pub modexp_impl_cost: Ratio, - // pub bn128AddImplCost: Ratio, - // pub bn128MulImplCost: Ratio, - // pub bn128PairingImplCost: Ratio, - // pub blake2FImplCost: Ratio, - // pub lastPrecompileCost: Ratio, -} - -pub struct EvmCostCoef { - pub deploy_cost: Coef2D, - pub funcall_cost: Coef, -} - -pub fn measure_evm_deploy( - config: &Config, - verbose: bool, - testbed: Arc>, - nonces: Arc>>, -) -> Coef2D { - let globbed_files = glob("./**/*.bin").expect("Failed to read glob pattern for bin files"); - let paths = globbed_files - .filter_map(|x| match x { - Ok(p) => Some(p), - _ => None, - }) - .collect::>(); - - let measurements = paths - .iter() - .filter(|path| fs::metadata(path).is_ok()) - .map(|path| { - if verbose { - print!("Testing {}: ", path.display()); - }; - // Evm counted gas already count on size of the contract, therefore we look for cost = m*evm_gas + b. - if let Some(EvmCost { evm_gas, size, cost }) = - load_and_deploy_evm_contract(path, config, testbed.clone(), nonces.clone()) - { - if verbose { - println!("({}, {}, {}),", evm_gas, size, cost); - }; - Some(EvmCost { evm_gas, size, cost }) - } else { - if verbose { - println!("FAILED") - }; - None - } - }) - .filter(|x| x.is_some()) - .map(|x| x.unwrap()) - .collect::>(); - measurements_to_coef_2d(measurements, true) -} - -use_contract!(soltest, "../near-evm-runner/tests/build/SolTests.abi"); -use_contract!(precompiled_function, "../near-evm-runner/tests/build/PrecompiledFunction.abi"); - -lazy_static_include_str!(TEST, "../near-evm-runner/tests/build/SolTests.bin"); -lazy_static_include_str!( - PRECOMPILED_TEST, - "../near-evm-runner/tests/build/PrecompiledFunction.bin" -); - -const CHAIN_ID: u128 = 0x99; - -pub fn create_evm_context<'a>( - external: &'a mut MockedExternal, - vm_config: &'a VMConfig, - fees_config: &'a RuntimeFeesConfig, - account_id: String, - attached_deposit: u128, -) -> EvmContext<'a> { - EvmContext::new( - external, - CHAIN_ID, - vm_config, - fees_config, - 1000, - account_id.to_string(), - account_id.to_string(), - account_id.to_string(), - attached_deposit, - 0, - 10u64.pow(14), - false, - 100_000_000.into(), - ) -} - -pub fn measure_evm_funcall( - config: &Config, - verbose: bool, - testbed: Arc>, - nonces: Arc>>, -) -> Coef { - let measurements = vec![ - measure_evm_function( - config, - verbose, - |sol_test_addr| { - vec![sol_test_addr, soltest::functions::deploy_new_guy::call(8).0].concat() - }, - "deploy_new_guy(8)", - testbed.clone(), - nonces.clone(), - ), - measure_evm_function( - config, - verbose, - |sol_test_addr| { - vec![sol_test_addr, soltest::functions::pay_new_guy::call(8).0].concat() - }, - "pay_new_guy(8)", - testbed.clone(), - nonces.clone(), - ), - measure_evm_function( - config, - verbose, - |sol_test_addr| { - vec![sol_test_addr, soltest::functions::return_some_funds::call().0].concat() - }, - "return_some_funds()", - testbed.clone(), - nonces.clone(), - ), - measure_evm_function( - config, - verbose, - |sol_test_addr| vec![sol_test_addr, soltest::functions::emit_it::call(8).0].concat(), - "emit_it(8)", - testbed.clone(), - nonces.clone(), - ), - ]; - println!("{:?}", measurements); - measurements_to_coef(measurements, true) -} - -pub fn measure_evm_function) -> Vec + Copy>( - config: &Config, - verbose: bool, - args_encoder: F, - test_name: &str, - testbed: Arc>, - nonces: Arc>>, -) -> EvmCost { - let path = PathBuf::from(config.state_dump_path.as_str()); - println!("{:?}. Preparing testbed. Loading state.", config.metric); - let allow_failures = false; - let mut nonces = nonces.lock().unwrap(); - let mut accounts_deployed = HashSet::new(); - let code = hex::decode(&TEST).unwrap(); - - let mut f = || { - let account_idx = loop { - let x = rand::thread_rng().gen::() % config.active_accounts; - if accounts_deployed.contains(&x) { - continue; - } - break x; - }; - accounts_deployed.insert(account_idx); - let account_id = get_account_id(account_idx); - let signer = InMemorySigner::from_seed(&account_id, KeyType::ED25519, &account_id); - - let mut testbed = testbed.lock().unwrap(); - let runtime_node = RuntimeNode { - signer: Arc::new(signer.clone()), - client: Arc::new(RwLock::new(MockClient { - runtime: testbed.runtime, - runtime_config: testbed.genesis.config.runtime_config.clone(), - tries: testbed.tries.clone(), - state_root: testbed.root, - epoch_length: testbed.genesis.config.epoch_length, - })), - genesis: testbed.genesis.clone(), - }; - let node_user = runtime_node.user(); - let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); - let addr = node_user - .function_call( - account_id.clone(), - "evm".to_string(), - "deploy_code", - code.clone(), - 10u64.pow(14), - 10, - ) - .unwrap() - .status - .as_success_decoded() - .unwrap(); - - testbed.tries = runtime_node.client.read().unwrap().tries.clone(); - testbed.root = runtime_node.client.read().unwrap().state_root; - testbed.runtime = runtime_node.client.read().unwrap().runtime; - - let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); - SignedTransaction::from_actions( - nonce as u64, - account_id.clone(), - "evm".to_owned(), - &signer, - vec![Action::FunctionCall(FunctionCallAction { - method_name: "call_function".to_string(), - args: args_encoder(addr), - gas: 10u64.pow(18), - deposit: 0, - })], - CryptoHash::default(), - ) - }; - - for _ in 0..config.warmup_iters_per_block { - for block_size in config.block_sizes.clone() { - let block: Vec<_> = (0..block_size).map(|_| f()).collect(); - let mut testbed = testbed.lock().unwrap(); - testbed.process_block(&block, allow_failures); - testbed.process_blocks_until_no_receipts(allow_failures); - } - } - reset_evm_gas_counter(); - let mut evm_gas = 0; - let mut total_cost = 0; - for _ in 0..config.iter_per_block { - for block_size in config.block_sizes.clone() { - let block: Vec<_> = (0..block_size).map(|_| f()).collect(); - let mut testbed = testbed.lock().unwrap(); - testbed.process_block(&block, allow_failures); - let start = start_count(config.metric); - testbed.process_blocks_until_no_receipts(allow_failures); - let cost = end_count(config.metric, &start); - total_cost += cost; - evm_gas += reset_evm_gas_counter(); - } - } - - let counts = total_transactions(config) as u64; - evm_gas /= counts; - - let cost = Ratio::new(total_cost, counts); - if verbose { - println!("Testing call {}: ({}, {})", test_name, evm_gas, cost); - } - EvmCost { evm_gas, size: 0, cost } -} - -pub fn near_cost_to_evm_gas(funcall_cost: Coef, cost: Ratio) -> u64 { - return u64::try_from((cost / funcall_cost.0).to_integer()).unwrap(); -} - -/// Cost of all evm related -pub fn cost_of_evm(config: &Config, verbose: bool) -> EvmCostCoef { - let (testbed, nonces) = testbed_for_evm(&config.state_dump_path, config.active_accounts); - let evm_cost_config = EvmCostCoef { - deploy_cost: measure_evm_deploy(config, verbose, testbed.clone(), nonces.clone()), - funcall_cost: measure_evm_funcall(config, verbose, testbed.clone(), nonces.clone()), - }; - evm_cost_config -} - /// Cost of the compile contract with vm_kind pub fn cost_to_compile( gas_metric: GasMetric, @@ -635,77 +199,6 @@ pub fn cost_to_compile( (m, b) } -fn dot(v1: &Vec, v2: &Vec) -> f64 { - let mut ret = 0.0; - for (i, u) in v1.iter().enumerate() { - ret += u * v2[i]; - } - ret -} - -struct Matrix2x2 { - a: f64, - b: f64, - c: f64, - d: f64, -} - -fn inverse2x2(m: Matrix2x2) -> Matrix2x2 { - let Matrix2x2 { a, b, c, d } = m; - let delta = a * d - b * c; - Matrix2x2 { a: d / delta, b: -b / delta, c: -c / delta, d: a / delta } -} - -fn normalize(v: &Vec) -> (Vec, f64) { - let mean = v.iter().sum::() / (v.len() as f64); - // default sklearn LinearRegression only normalize mean to 0, but not normalize stddev to 1, and that gives a very good result. - - let v: Vec<_> = v.iter().map(|x| (*x - mean)).collect(); - (v, mean) -} - -fn measurements_to_coef_2d(measurements: Vec, verbose: bool) -> Coef2D { - let v1: Vec<_> = measurements.iter().map(|m| m.evm_gas as f64).collect(); - let (v1, _) = normalize(&v1); - let v2: Vec<_> = measurements.iter().map(|m| m.size as f64).collect(); - let (v2, _) = normalize(&v2); - let a = dot(&v1, &v1); - let b = dot(&v1, &v2); - let c = dot(&v2, &v1); - let d = dot(&v2, &v2); - - let xt_x_inverse = inverse2x2(Matrix2x2 { a, b, c, d }); - - let y: Vec<_> = measurements.iter().map(|m| m.cost.to_f64().unwrap()).collect(); - let xt_y1 = dot(&v1, &y); - let xt_y2 = dot(&v2, &y); - - let beta1 = (xt_x_inverse.a * xt_y1 + xt_x_inverse.b * xt_y2); - let beta2 = (xt_x_inverse.c * xt_y1 + xt_x_inverse.d * xt_y2); - - let delta: Vec<_> = measurements - .iter() - .map(|m| m.cost.to_f64().unwrap() - (m.evm_gas as f64) * beta1 - (m.size as f64) * beta2) - .collect(); - let r = (beta1, beta2, delta.iter().sum::() / delta.len() as f64); - println!("evm calc data {:?}", r); - println!("delta: {:?}", delta); - r -} - -fn measurements_to_coef(measurements: Vec, verbose: bool) -> Coef { - let ratio = Ratio::new(0 as u64, 1); - let base = Ratio::new(u64::MAX, 1); - let b = measurements.iter().fold(base, |b, EvmCost { evm_gas: _, size: _, cost }| b.min(*cost)); - let m = measurements - .iter() - .fold(ratio, |r, EvmCost { evm_gas, size: _, cost }| r.max((*cost - b) / evm_gas)); - if verbose { - println!("raw data: ({},{})", m, b); - } - (m, b) -} - fn delete_all_data(wasm_bin: &mut Vec) -> Result<&Vec> { let m = &mut Module::from_buffer(wasm_bin)?; for id in get_ids(m.data.iter().map(|t| t.id())) { diff --git a/runtime/runtime/Cargo.toml b/runtime/runtime/Cargo.toml index 5e3e8c6a319..9f2daf5f41c 100644 --- a/runtime/runtime/Cargo.toml +++ b/runtime/runtime/Cargo.toml @@ -29,13 +29,13 @@ near-runtime-fees = { path = "../../runtime/near-runtime-fees" } near-runtime-utils = { path = "../../runtime/near-runtime-utils" } near-vm-logic = { path = "../../runtime/near-vm-logic" } near-vm-runner = { path = "../../runtime/near-vm-runner" } -near-evm-runner = { path = "../../runtime/near-evm-runner" } near-vm-errors = { path = "../../runtime/near-vm-errors" } +near-evm-runner = { path = "../../runtime/near-evm-runner", optional = true } [features] default = [] dump_errors_schema = ["near-vm-errors/dump_errors_schema"] -protocol_feature_evm = ["near-primitives/protocol_feature_evm"] +protocol_feature_evm = ["near-primitives/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm", "near-vm-runner/protocol_feature_evm", "near-evm-runner"] # Use this feature to enable counting of fees and costs applied. costs_counting = ["near-vm-logic/costs_counting", "near-vm-runner/costs_counting"] diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index e68b25401cc..73efbb6886a 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -53,6 +53,9 @@ pub(crate) fn execute_function_call( if checked_feature!("protocol_feature_evm", EVM, runtime_ext.protocol_version()) && is_account_evm(&account_id) { + #[cfg(not(feature = "protocol_feature_evm"))] + unreachable!(); + #[cfg(feature = "protocol_feature_evm")] near_evm_runner::run_evm( runtime_ext, apply_state.evm_chain_id, diff --git a/runtime/runtime/tests/runtime_group_tools/random_config.rs b/runtime/runtime/tests/runtime_group_tools/random_config.rs index 70c2fb7c04b..5f260210aeb 100644 --- a/runtime/runtime/tests/runtime_group_tools/random_config.rs +++ b/runtime/runtime/tests/runtime_group_tools/random_config.rs @@ -1,7 +1,7 @@ use near_runtime_fees::{ - AccessKeyCreationConfig, ActionCreationConfig, DataReceiptCreationConfig, EvmBlake2FCost, - EvmBls12ConstOpCost, EvmBn128PairingCost, EvmCostConfig, EvmLinearCost, EvmModexpCost, - EvmPrecompileCostConfig, Fee, RuntimeFeesConfig, StorageUsageConfig, + AccessKeyCreationConfig, ActionCreationConfig, DataReceiptCreationConfig, EvmBls12ConstOpCost, + EvmBn128PairingCost, EvmCostConfig, EvmLinearCost, EvmModexpCost, EvmPrecompileCostConfig, Fee, + RuntimeFeesConfig, StorageUsageConfig, }; use node_runtime::config::RuntimeConfig; use num_rational::Rational; @@ -47,6 +47,7 @@ pub fn random_config() -> RuntimeConfig { (101 + rng.next_u32() % 10).try_into().unwrap(), 100, ), + #[cfg(feature = "protocol_feature_evm")] evm_config: EvmCostConfig { bootstrap_cost: rng.next_u64() % 1000, deploy_cost_per_evm_gas: rng.next_u64() % 1000, @@ -80,6 +81,7 @@ pub fn random_config() -> RuntimeConfig { blake2f_cost: rng.next_u64() % 1000, }, }, + #[cfg(feature = "protocol_feature_evm")] evm_deposit: (rng.next_u64() % 10000) as u128 * 10u128.pow(23), }, ..Default::default() diff --git a/test-utils/testlib/Cargo.toml b/test-utils/testlib/Cargo.toml index d34b121f020..a0731ff277a 100644 --- a/test-utils/testlib/Cargo.toml +++ b/test-utils/testlib/Cargo.toml @@ -34,7 +34,6 @@ near-primitives = { path = "../../core/primitives" } near-store = { path = "../../core/store" } node-runtime = { path = "../../runtime/runtime" } near-vm-errors = { path = "../../runtime/near-vm-errors" } -near-evm-runner = { path = "../../runtime/near-evm-runner" } near-chain = { path = "../../chain/chain" } near-client = { path = "../../chain/client" } near-jsonrpc = { path = "../../chain/jsonrpc" } @@ -42,3 +41,8 @@ near-network = { path = "../../chain/network" } near-jsonrpc-client = { path = "../../chain/jsonrpc/client" } near-runtime-fees = { path = "../../runtime/near-runtime-fees" } neard = { path = "../../neard" } +near-evm-runner = { path = "../../runtime/near-evm-runner", optional = true } + +[features] +default = [] +protocol_feature_evm = ["near-evm-runner", "node-runtime/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"] diff --git a/test-utils/testlib/src/lib.rs b/test-utils/testlib/src/lib.rs index 1a45479c004..e05d4fc5bd2 100644 --- a/test-utils/testlib/src/lib.rs +++ b/test-utils/testlib/src/lib.rs @@ -18,6 +18,8 @@ pub mod actix_utils; pub mod fees_utils; pub mod node; pub mod runtime_utils; +#[cfg(feature = "protocol_feature_evm")] +pub mod standard_evm_cases; pub mod standard_test_cases; pub mod test_helpers; pub mod user; diff --git a/test-utils/testlib/src/standard_evm_cases.rs b/test-utils/testlib/src/standard_evm_cases.rs new file mode 100644 index 00000000000..dd4100ff9a1 --- /dev/null +++ b/test-utils/testlib/src/standard_evm_cases.rs @@ -0,0 +1,137 @@ +use crate::node::Node; +use crate::runtime_utils::{alice_account, evm_account}; +use borsh::BorshSerialize; +use ethabi_contract::use_contract; +use ethereum_types::U256; +use near_evm_runner::types::WithdrawArgs; +use near_evm_runner::utils::{ + address_from_arr, encode_call_function_args, encode_view_call_function_args, u256_to_arr, +}; + +use_contract!(cryptozombies, "../../runtime/near-evm-runner/tests/build/zombieAttack.abi"); + +pub fn test_evm_deploy_call(node: impl Node) { + let node_user = node.user(); + let bytes = hex::decode( + include_bytes!("../../../runtime/near-evm-runner/tests/build/zombieAttack.bin").to_vec(), + ) + .unwrap(); + let contract_id = node_user + .function_call(alice_account(), evm_account(), "deploy_code", bytes, 10u64.pow(14), 10) + .unwrap() + .status + .as_success_decoded() + .unwrap(); + + let result = node_user.view_call(&evm_account(), "get_balance", &contract_id).unwrap(); + assert_eq!(result.result, u256_to_arr(&U256::from(10)).to_vec()); + + let (input, _decoder) = cryptozombies::functions::create_random_zombie::call("test"); + let contract_id = address_from_arr(&contract_id); + let args = encode_call_function_args(contract_id, input); + assert_eq!( + node_user + .function_call(alice_account(), evm_account(), "call", args, 10u64.pow(14), 0) + .unwrap() + .status + .as_success_decoded() + .unwrap(), + Vec::::new() + ); + + let alice_address = near_evm_runner::utils::near_account_id_to_evm_address(&alice_account()); + let (input, _decoder) = cryptozombies::functions::get_zombies_by_owner::call( + near_evm_runner::utils::near_account_id_to_evm_address(&alice_account()), + ); + // sender, to, attached amount, args + let args = encode_view_call_function_args(alice_address, contract_id, U256::zero(), input); + let bytes = node_user + .function_call(alice_account(), evm_account(), "view", args.clone(), 10u64.pow(14), 0) + .unwrap() + .status + .as_success_decoded() + .unwrap(); + let res = cryptozombies::functions::get_zombies_by_owner::decode_output(&bytes).unwrap(); + assert_eq!(res, vec![U256::from(0)]); + + let result = node_user.view_call(&evm_account(), "view", &args).unwrap(); + let res = + cryptozombies::functions::get_zombies_by_owner::decode_output(&result.result).unwrap(); + assert_eq!(res, vec![U256::from(0)]); + + let result = node_user.view_call(&evm_account(), "get_balance", &contract_id.0).unwrap(); + assert_eq!(U256::from_big_endian(&result.result), U256::from(10)); + + assert!(node_user + .function_call( + alice_account(), + evm_account(), + "deposit", + alice_address.0.to_vec(), + 10u64.pow(14), + 1000, + ) + .unwrap() + .status + .as_success() + .is_some()); + + let result = node_user.view_call(&evm_account(), "get_balance", &alice_address.0).unwrap(); + assert_eq!(U256::from_big_endian(&result.result), U256::from(1000)); + + let result = node_user + .function_call( + alice_account(), + evm_account(), + "withdraw", + WithdrawArgs { account_id: alice_account(), amount: U256::from(10).into() } + .try_to_vec() + .unwrap(), + 10u64.pow(14), + 0, + ) + .unwrap() + .status + .as_success_decoded() + .unwrap(); + assert_eq!(result.len(), 0); +} + +pub fn test_sub_evm(node: impl Node) { + let node_user = node.user(); + assert_eq!( + node_user.view_account(&"sub.evm".to_string()).unwrap_err().to_string(), + "account sub.evm does not exist while viewing" + ); + assert_eq!( + node_user + .function_call( + alice_account(), + evm_account(), + "create", + b"sub.evm".to_vec(), + 10u64.pow(14), + 0, + ) + .unwrap() + .status + .as_failure() + .unwrap() + .to_string(), + "Action #0: EVM: InsufficientDeposit" + ); + node_user + .function_call( + alice_account(), + evm_account(), + "create", + b"sub.evm".to_vec(), + 10u64.pow(14), + 10u128.pow(27), + ) + .unwrap() + .status + .as_success() + .unwrap(); + assert_eq!(node_user.view_account(&"sub.evm".to_string()).unwrap().amount, 10u128.pow(27)); +} diff --git a/test-utils/testlib/src/standard_test_cases.rs b/test-utils/testlib/src/standard_test_cases.rs index 5cc5abaa4a1..ed14f1c8485 100644 --- a/test-utils/testlib/src/standard_test_cases.rs +++ b/test-utils/testlib/src/standard_test_cases.rs @@ -1,12 +1,7 @@ use std::sync::Arc; -use borsh::BorshSerialize; -use ethabi_contract::use_contract; -use ethereum_types::U256; - use assert_matches::assert_matches; use near_crypto::{InMemorySigner, KeyType}; -use near_evm_runner::types::WithdrawArgs; use near_jsonrpc::ServerError; use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermission}; use near_primitives::errors::{ @@ -22,12 +17,8 @@ use neard::config::{NEAR_BASE, TESTING_INIT_BALANCE, TESTING_INIT_STAKE}; use crate::fees_utils::FeeHelper; use crate::node::Node; -use crate::runtime_utils::{alice_account, bob_account, eve_dot_alice_account, evm_account}; +use crate::runtime_utils::{alice_account, bob_account, eve_dot_alice_account}; use crate::user::User; -use near_evm_runner::utils::{ - address_from_arr, encode_call_function_args, encode_view_call_function_args, - near_account_id_to_evm_address, u256_to_arr, -}; /// The amount to send with function call. const FUNCTION_CALL_AMOUNT: Balance = TESTING_INIT_BALANCE / 10; @@ -1281,131 +1272,3 @@ pub fn test_smart_contract_free(node: impl Node) { let new_root = node_user.get_state_root(); assert_ne!(root, new_root); } - -use_contract!(cryptozombies, "../../runtime/near-evm-runner/tests/build/zombieAttack.abi"); - -pub fn test_evm_deploy_call(node: impl Node) { - let node_user = node.user(); - let bytes = hex::decode( - include_bytes!("../../../runtime/near-evm-runner/tests/build/zombieAttack.bin").to_vec(), - ) - .unwrap(); - let contract_id = node_user - .function_call(alice_account(), evm_account(), "deploy_code", bytes, 10u64.pow(14), 10) - .unwrap() - .status - .as_success_decoded() - .unwrap(); - - let result = node_user.view_call(&evm_account(), "get_balance", &contract_id).unwrap(); - assert_eq!(result.result, u256_to_arr(&U256::from(10)).to_vec()); - - let (input, _decoder) = cryptozombies::functions::create_random_zombie::call("test"); - let contract_id = address_from_arr(&contract_id); - let args = encode_call_function_args(contract_id, input); - assert_eq!( - node_user - .function_call(alice_account(), evm_account(), "call", args, 10u64.pow(14), 0) - .unwrap() - .status - .as_success_decoded() - .unwrap(), - Vec::::new() - ); - - let alice_address = near_evm_runner::utils::near_account_id_to_evm_address(&alice_account()); - let (input, _decoder) = cryptozombies::functions::get_zombies_by_owner::call( - near_evm_runner::utils::near_account_id_to_evm_address(&alice_account()), - ); - // sender, to, attached amount, args - let args = encode_view_call_function_args(alice_address, contract_id, U256::zero(), input); - let bytes = node_user - .function_call(alice_account(), evm_account(), "view", args.clone(), 10u64.pow(14), 0) - .unwrap() - .status - .as_success_decoded() - .unwrap(); - let res = cryptozombies::functions::get_zombies_by_owner::decode_output(&bytes).unwrap(); - assert_eq!(res, vec![U256::from(0)]); - - let result = node_user.view_call(&evm_account(), "view", &args).unwrap(); - let res = - cryptozombies::functions::get_zombies_by_owner::decode_output(&result.result).unwrap(); - assert_eq!(res, vec![U256::from(0)]); - - let result = node_user.view_call(&evm_account(), "get_balance", &contract_id.0).unwrap(); - assert_eq!(U256::from_big_endian(&result.result), U256::from(10)); - - assert!(node_user - .function_call( - alice_account(), - evm_account(), - "deposit", - alice_address.0.to_vec(), - 10u64.pow(14), - 1000, - ) - .unwrap() - .status - .as_success() - .is_some()); - - let result = node_user.view_call(&evm_account(), "get_balance", &alice_address.0).unwrap(); - assert_eq!(U256::from_big_endian(&result.result), U256::from(1000)); - - let result = node_user - .function_call( - alice_account(), - evm_account(), - "withdraw", - WithdrawArgs { account_id: alice_account(), amount: U256::from(10).into() } - .try_to_vec() - .unwrap(), - 10u64.pow(14), - 0, - ) - .unwrap() - .status - .as_success_decoded() - .unwrap(); - assert_eq!(result.len(), 0); -} - -pub fn test_sub_evm(node: impl Node) { - let node_user = node.user(); - assert_eq!( - node_user.view_account(&"sub.evm".to_string()).unwrap_err().to_string(), - "account sub.evm does not exist while viewing" - ); - assert_eq!( - node_user - .function_call( - alice_account(), - evm_account(), - "create", - b"sub.evm".to_vec(), - 10u64.pow(14), - 0, - ) - .unwrap() - .status - .as_failure() - .unwrap() - .to_string(), - "Action #0: EVM: InsufficientDeposit" - ); - node_user - .function_call( - alice_account(), - evm_account(), - "create", - b"sub.evm".to_vec(), - 10u64.pow(14), - 10u128.pow(27), - ) - .unwrap() - .status - .as_success() - .unwrap(); - assert_eq!(node_user.view_account(&"sub.evm".to_string()).unwrap().amount, 10u128.pow(27)); -} diff --git a/tests/test_cases_runtime.rs b/tests/test_cases_runtime.rs index 98e835153f1..52aecb235f8 100644 --- a/tests/test_cases_runtime.rs +++ b/tests/test_cases_runtime.rs @@ -5,6 +5,8 @@ mod test { use neard::config::{GenesisExt, TESTING_INIT_BALANCE}; use testlib::node::RuntimeNode; use testlib::runtime_utils::{add_test_contract, alice_account, bob_account}; + #[cfg(feature = "protocol_feature_evm")] + use testlib::standard_evm_cases::*; use testlib::standard_test_cases::*; fn create_runtime_node() -> RuntimeNode { @@ -304,12 +306,14 @@ mod test { test_smart_contract_free(node); } + #[cfg(feature = "protocol_feature_evm")] #[test] fn test_evm_deploy_call_runtime() { let node = create_runtime_node(); test_evm_deploy_call(node); } + #[cfg(feature = "protocol_feature_evm")] #[test] fn test_sub_evm_runtime() { let node = create_runtime_node(); diff --git a/tests/test_cases_testnet_rpc.rs b/tests/test_cases_testnet_rpc.rs index 2ca9ac33e1a..f81aca2cc93 100644 --- a/tests/test_cases_testnet_rpc.rs +++ b/tests/test_cases_testnet_rpc.rs @@ -9,6 +9,8 @@ mod test { use near_logger_utils::init_test_module_logger; use testlib::node::{create_nodes_from_seeds, Node, NodeConfig, ThreadNode}; use testlib::runtime_utils::alice_account; + #[cfg(feature = "protocol_feature_evm")] + use testlib::standard_evm_cases::*; use testlib::standard_test_cases::*; use testlib::test_helpers::heavy_test; @@ -197,6 +199,7 @@ mod test { run_testnet_test!(test_access_key_smart_contract); } + #[cfg(feature = "protocol_feature_evm")] #[test] fn test_evm_deploy_call_testnet() { run_testnet_test!(test_evm_deploy_call); From 8a451400f6d00d97fdb8d360ee1b92453150b896 Mon Sep 17 00:00:00 2001 From: Arto Bendiken Date: Thu, 12 Nov 2020 22:51:23 +0200 Subject: [PATCH 56/82] Upgrade OpenEthereum from 2.6.8 to 2.7.2. (#3506) (#3595) As the next step in #3506, and following up from #3542 and #3558, upgrade Parity Ethereum (now OpenEthereum) from [2.6.8] (Dec 2019) to [2.7.2] (Feb 2020), the last release in the 2.x series. This harmonizes our dependency graph with upstream, fixing numerous build errors from the upgrade and eliminating multiple versions of the same crates. This concerns the [bn], [ethabi], [ethabi-contract], [ethabi-derive], [ethereum-types], [keccak-hash], [primitive-types], and [uint] crates as well as their transitive dependencies and their interdependencies. The [near/bn] fork exists to upgrade [bn]'s [rand] dependency. That's necessary because of a particularly complex dependency issue (https://github.com/rust-random/rand/issues/645) in old versions of rand. We will eliminate the fork going forward once upstream upgrades their dependency (I will open a pull request for them). The upstream changelog for 2.7.2 is at: https://github.com/openethereum/openethereum/blob/v2.7.2/CHANGELOG.md The upstream diff from 2.6.8 to 2.7.2 is at: https://github.com/openethereum/openethereum/compare/v2.6.8...v2.7.2 [2.6.8]: https://github.com/openethereum/openethereum/releases/tag/v2.6.8 [2.7.2]: https://github.com/openethereum/openethereum/releases/tag/v2.7.2 [near/bn]: https://github.com/near/bn [bn]: https://crates.io/crates/bn [ethabi]: https://crates.io/crates/ethabi [ethabi-contract]: https://crates.io/crates/ethabi-contract [ethabi-derive]: https://crates.io/crates/ethabi-derive [ethereum-types]: https://crates.io/crates/ethereum-types [keccak-hash]: https://crates.io/crates/keccak-hash [primitive-types]: https://crates.io/crates/primitive-types [rand]: https://crates.io/crates/rand [uint]: https://crates.io/crates/uint --- Cargo.lock | 239 +++++++++----------- chain/epoch_manager/Cargo.toml | 2 +- core/primitives/Cargo.toml | 2 +- deny.toml | 36 +-- runtime/near-evm-runner/Cargo.toml | 16 +- runtime/near-evm-runner/src/interpreter.rs | 20 +- runtime/near-evm-runner/src/near_ext.rs | 17 +- runtime/near-vm-errors/Cargo.toml | 2 +- runtime/runtime-params-estimator/Cargo.toml | 8 +- runtime/runtime/Cargo.toml | 2 +- test-utils/testlib/Cargo.toml | 8 +- 11 files changed, 165 insertions(+), 187 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b82ba77ec6c..bd8b0a85371 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -355,15 +355,6 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] - [[package]] name = "arrayvec" version = "0.5.1" @@ -529,6 +520,16 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitvec" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium", +] + [[package]] name = "blake2" version = "0.9.1" @@ -547,7 +548,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" dependencies = [ "arrayref", - "arrayvec 0.5.1", + "arrayvec", "constant_time_eq", ] @@ -558,7 +559,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "423897d97e11b810c9da22458400b28ec866991c711409073662eb34dc44bfff" dependencies = [ "arrayref", - "arrayvec 0.5.1", + "arrayvec", "cc", "cfg-if 0.1.10", "constant_time_eq", @@ -599,13 +600,14 @@ dependencies = [ [[package]] name = "bn" version = "0.4.4" -source = "git+https://github.com/paritytech/bn#635c4cdd560bc0c8b262e6bf809dc709da8bcd7e" +source = "git+https://github.com/near/bn?branch=upgrade-rand#43953916ed1a314b78320771734f36af77993dd9" dependencies = [ "byteorder", "crunchy", "lazy_static", - "rand 0.5.6", + "rand 0.6.5", "rustc-hex 2.1.0", + "rustc-serialize", ] [[package]] @@ -694,6 +696,12 @@ version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" +[[package]] +name = "byte-slice-cast" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" + [[package]] name = "byte-tools" version = "0.3.1" @@ -859,15 +867,6 @@ dependencies = [ "syn 1.0.38", ] -[[package]] -name = "clear_on_drop" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" -dependencies = [ - "cc", -] - [[package]] name = "cloudabi" version = "0.0.3" @@ -1438,9 +1437,9 @@ dependencies = [ [[package]] name = "ethabi" -version = "8.0.1" +version = "9.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebdeeea85a6d217b9fcc862906d7e283c047e04114165c433756baf5dce00a6c" +checksum = "965126c64662832991f5a748893577630b558e47fa94e7f35aefcd20d737cef7" dependencies = [ "error-chain", "ethereum-types", @@ -1453,15 +1452,15 @@ dependencies = [ [[package]] name = "ethabi-contract" -version = "8.0.1" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d6314f57a5451692753696f40903bacf870adf65d452911ab6b15bf6be41f8" +checksum = "cf407dce0290374bfbb1528493bc14320e663f75856b73a5b76262d8e2cec3c9" [[package]] name = "ethabi-derive" -version = "8.0.0" +version = "9.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65cdef3199bf5d1821dc53b5ab992f853a13b2e28d7a63983095d9d61fae58d3" +checksum = "bd0753d4f9e1dba99450da5f2400b20527702ae8ce0309a5f7c239d305539884" dependencies = [ "ethabi", "heck", @@ -1472,35 +1471,35 @@ dependencies = [ [[package]] name = "ethbloom" -version = "0.6.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3932e82d64d347a045208924002930dc105a138995ccdc1479d0f05f0359f17c" +checksum = "32cfe1c169414b709cf28aa30c74060bdb830a03a8ba473314d079ac79d80a5f" dependencies = [ "crunchy", - "fixed-hash 0.3.2", + "fixed-hash", "impl-rlp", - "impl-serde", + "impl-serde 0.2.3", "tiny-keccak", ] [[package]] name = "ethereum-types" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62d1bc682337e2c5ec98930853674dd2b4bd5d0d246933a9e98e5280f7c76c5f" +checksum = "ba744248e3553a393143d5ebb68939fc3a4ec0c22a269682535f5ffe7fed728c" dependencies = [ "ethbloom", - "fixed-hash 0.3.2", + "fixed-hash", "impl-rlp", - "impl-serde", - "primitive-types 0.3.0", - "uint 0.7.1", + "impl-serde 0.2.3", + "primitive-types", + "uint", ] [[package]] name = "ethjson" version = "0.1.0" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" +source = "git+https://github.com/openethereum/openethereum?rev=v2.7.2#2662d1925ec794f3ad7c5759b2412ff5128d259b" dependencies = [ "ethereum-types", "rustc-hex 1.0.0", @@ -1511,7 +1510,7 @@ dependencies = [ [[package]] name = "evm" version = "0.1.0" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" +source = "git+https://github.com/openethereum/openethereum?rev=v2.7.2#2662d1925ec794f3ad7c5759b2412ff5128d259b" dependencies = [ "bit-set", "ethereum-types", @@ -1586,24 +1585,14 @@ dependencies = [ [[package]] name = "fixed-hash" -version = "0.3.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1a683d1234507e4f3bf2736eeddf0de1dc65996dc0164d57eba0a74bcf29489" +checksum = "3367952ceb191f4ab95dd5685dc163ac539e36202f9fcfd0cb22f9f9c542fefc" dependencies = [ "byteorder", - "heapsize", - "rand 0.5.6", + "rand 0.7.3", "rustc-hex 2.1.0", - "static_assertions 0.2.5", -] - -[[package]] -name = "fixed-hash" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32529fc42e86ec06e5047092082aab9ad459b070c5d2a76b14f4f5ce70bf2e84" -dependencies = [ - "static_assertions 1.1.0", + "static_assertions", ] [[package]] @@ -1855,7 +1844,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81dd6190aad0f05ddbbf3245c54ed14ca4aa6dd32f22312b70d8f168c3e3e633" dependencies = [ - "arrayvec 0.5.1", + "arrayvec", "byteorder", "fallible-iterator", "indexmap", @@ -1938,15 +1927,18 @@ dependencies = [ [[package]] name = "hash-db" -version = "0.12.4" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b3c95a428c86ed4633d83e07ef9e0a147a906da01e931f07e74a85bedce5a43" +checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" [[package]] -name = "hashmap_core" -version = "0.1.11" +name = "hashbrown" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6852e5a86250521973b0c1d39677166d8a9c0047c908d7e04f1aa04177973c" +checksum = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" +dependencies = [ + "autocfg 0.1.7", +] [[package]] name = "heapsize" @@ -2157,11 +2149,11 @@ checksum = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d" [[package]] name = "impl-codec" -version = "0.2.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2050d823639fbeae26b2b5ba09aca8907793117324858070ade0673c49f793b" +checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" dependencies = [ - "parity-codec", + "parity-scale-codec", ] [[package]] @@ -2182,6 +2174,15 @@ dependencies = [ "serde", ] +[[package]] +name = "impl-serde" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f" +dependencies = [ + "serde", +] + [[package]] name = "indexer-example" version = "0.1.0" @@ -2354,18 +2355,18 @@ checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" [[package]] name = "keccak-hash" -version = "0.2.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e8ee697b9aa6dcc34d7657565fa5052763a1627a5b59e4c3c0ae3ed0d70a65" +checksum = "4f0e55d8f242fdc281c21c4cd70960a25db6dd17cc6232d8b38b564b5b18c784" dependencies = [ - "primitive-types 0.3.0", + "primitive-types", "tiny-keccak", ] [[package]] name = "keccak-hasher" version = "0.1.1" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" +source = "git+https://github.com/openethereum/openethereum?rev=v2.7.2#2662d1925ec794f3ad7c5759b2412ff5128d259b" dependencies = [ "ethereum-types", "hash-db", @@ -2637,7 +2638,7 @@ dependencies = [ [[package]] name = "memory-cache" version = "0.1.0" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" +source = "git+https://github.com/openethereum/openethereum?rev=v2.7.2#2662d1925ec794f3ad7c5759b2412ff5128d259b" dependencies = [ "lru-cache", "parity-util-mem", @@ -2905,7 +2906,7 @@ dependencies = [ "near-primitives", "near-store", "num-rational 0.2.4", - "primitive-types 0.7.0", + "primitive-types", "rand 0.6.5", "rand 0.7.3", "serde", @@ -3097,7 +3098,7 @@ dependencies = [ "near-rpc-error-macro", "near-vm-errors", "num-rational 0.2.4", - "primitive-types 0.7.0", + "primitive-types", "rand 0.7.3", "reed-solomon-erasure", "regex", @@ -3429,12 +3430,6 @@ dependencies = [ "testlib", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "nom" version = "5.1.1" @@ -3702,12 +3697,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b56e3a2420138bdb970f84dfb9c774aea80fa0e7371549eedec0d80c209c67" [[package]] -name = "parity-codec" -version = "3.5.4" +name = "parity-scale-codec" +version = "1.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b9df1283109f542d8852cd6b30e9341acc2137481eb6157d2e62af68b0afec9" +checksum = "7c740e5fbcb6847058b40ac7e5574766c6388f585e184d769910fe0d3a2ca861" dependencies = [ - "arrayvec 0.4.12", + "arrayvec", + "bitvec", + "byte-slice-cast", "serde", ] @@ -3717,7 +3714,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fca4f82fccae37e8bbdaeb949a4a218a1bbc485d11598f193d2a908042e5fc1" dependencies = [ - "arrayvec 0.5.1", + "arrayvec", "cc", "cfg-if 0.1.10", "rand 0.7.3", @@ -3725,16 +3722,15 @@ dependencies = [ [[package]] name = "parity-util-mem" -version = "0.1.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e80f22052161e0cb55cb5a8a75890420c525031f95c9d262dbb0434aa85dc1" +checksum = "8174d85e62c4d615fddd1ef67966bdc5757528891d0742f15b131ad04667b3f9" dependencies = [ "cfg-if 0.1.10", - "clear_on_drop", - "elastic-array 0.11.0", "ethereum-types", "malloc_size_of_derive", - "parking_lot 0.11.0", + "parking_lot 0.9.0", + "smallvec 1.4.0", "winapi 0.3.8", ] @@ -3823,7 +3819,7 @@ dependencies = [ [[package]] name = "patricia-trie-ethereum" version = "0.1.0" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" +source = "git+https://github.com/openethereum/openethereum?rev=v2.7.2#2662d1925ec794f3ad7c5759b2412ff5128d259b" dependencies = [ "elastic-array 0.10.3", "ethereum-types", @@ -3913,25 +3909,15 @@ checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" [[package]] name = "primitive-types" -version = "0.3.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2288eb2a39386c4bc817974cc413afe173010dc80e470fcb1e9a35580869f024" +checksum = "e4336f4f5d5524fa60bcbd6fe626f9223d8142a50e7053e979acdf0da41ab975" dependencies = [ - "fixed-hash 0.3.2", + "fixed-hash", "impl-codec", "impl-rlp", - "impl-serde", - "uint 0.7.1", -] - -[[package]] -name = "primitive-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5e4b9943a2da369aec5e96f7c10ebc74fcf434d39590d974b0a3460e6f67fbb" -dependencies = [ - "fixed-hash 0.6.0", - "uint 0.8.2", + "impl-serde 0.3.1", + "uint", ] [[package]] @@ -4070,17 +4056,10 @@ dependencies = [ ] [[package]] -name = "rand" -version = "0.5.6" +name = "radium" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -dependencies = [ - "cloudabi 0.0.3", - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "winapi 0.3.8", -] +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" [[package]] name = "rand" @@ -4549,6 +4528,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + [[package]] name = "rustc_version" version = "0.2.3" @@ -4902,12 +4887,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "static_assertions" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" - [[package]] name = "static_assertions" version = "1.1.0" @@ -5400,15 +5379,15 @@ checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" [[package]] name = "trie-db" -version = "0.12.4" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae063390324bfcf36c7e8e4fb1f85f6f0fb5dd04e1cd282581eb7b8b34b32de7" +checksum = "191fda5d0106f3ed35a8c6875428b213e15c516e48129cc263dd7ad16e9a665f" dependencies = [ - "elastic-array 0.10.3", "hash-db", - "hashmap_core", + "hashbrown", "log", "rand 0.6.5", + "smallvec 1.4.0", ] [[package]] @@ -5471,18 +5450,6 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" -[[package]] -name = "uint" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2143cded94692b156c356508d92888acc824db5bffc0b4089732264c6fcf86d4" -dependencies = [ - "byteorder", - "crunchy", - "heapsize", - "rustc-hex 2.1.0", -] - [[package]] name = "uint" version = "0.8.2" @@ -5492,7 +5459,7 @@ dependencies = [ "byteorder", "crunchy", "rustc-hex 2.1.0", - "static_assertions 1.1.0", + "static_assertions", ] [[package]] @@ -5643,7 +5610,7 @@ checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" [[package]] name = "vm" version = "0.1.0" -source = "git+https://github.com/openethereum/openethereum?rev=v2.6.8#9bf6ed8450ec2eb61f14b362574c453ed68bd761" +source = "git+https://github.com/openethereum/openethereum?rev=v2.7.2#2662d1925ec794f3ad7c5759b2412ff5128d259b" dependencies = [ "ethereum-types", "ethjson", diff --git a/chain/epoch_manager/Cargo.toml b/chain/epoch_manager/Cargo.toml index 7a8239131d4..59e29a3bf57 100644 --- a/chain/epoch_manager/Cargo.toml +++ b/chain/epoch_manager/Cargo.toml @@ -15,7 +15,7 @@ rand = "0.7" serde = { version = "1", features = [ "derive" ] } serde_json = "1" smart-default = "0.6" -primitive-types = { version = "0.7", default-features = false } +primitive-types = "0.6" num-rational = "0.2.4" near-crypto = { path = "../../core/crypto" } diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index f80aa8372a5..6b4d6385c83 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -23,7 +23,7 @@ reed-solomon-erasure = "4" jemallocator = { version = "0.3", optional = true } hex = "0.4" num-rational = "0.2.4" -primitive-types = { version = "0.7", default-features = false } +primitive-types = "0.6" lazy_static = "1.4" borsh = "0.7.1" diff --git a/deny.toml b/deny.toml index c0d7c5f2081..30bc2d2f426 100644 --- a/deny.toml +++ b/deny.toml @@ -7,7 +7,19 @@ targets = [ [bans] multiple-versions = "deny" deny = [ + # See: https://github.com/rust-random/rand/issues/645 + { name = "rand", version = "<0.6" }, + + # See: https://github.com/near/nearcore/pull/3595 + { name = "ethabi", version = "<9.0.1" }, + { name = "ethabi-contract", version = "<9.0.0" }, + { name = "ethabi-derive", version = "<9.0.1" }, + { name = "ethereum-types", version = "<0.8.0" }, + { name = "keccak-hash", version = "<0.4.1" }, + { name = "primitive-types", version = "<0.6.2" }, + { name = "uint", version = "<0.8.2" }, ] + skip = [ # actix 0.9.0 still uses it { name = "tokio-util", version = "=0.2.0" }, @@ -56,21 +68,17 @@ skip = [ # evm support has some legacy. Updating it fails at this point. # to fully update, need to fork half of parity libraries, as they stopped development. - { name = "unicode-xid", version = "=0.1.0" }, - { name = "uint", version = "=0.7.1" }, - { name = "syn", version = "=0.15.44" }, - { name = "static_assertions", version = "=0.2.5" }, + # See: https://github.com/near/nearcore/issues/3506 + { name = "digest", version = "=0.8.1" }, + { name = "elastic-array", version = "=0.10.3" }, + { name = "impl-serde", version = "=0.2.3" }, + { name = "num-bigint", version = "=0.2.6" }, { name = "parking_lot", version = "=0.11.0" }, { name = "parking_lot_core", version = "=0.6.2" }, - { name = "smallvec", version = "=0.6.13" }, - { name = "rustc-hex", version = "=1.0.0" }, - { name = "rand", version = "=0.5.6" }, - { name = "quote", version = "=0.6.13" }, { name = "proc-macro2", version = "=0.4.30" }, - { name = "primitive-types", version = "=0.3.0" }, - { name = "num-bigint", version = "=0.2.6" }, - { name = "fixed-hash", version = "=0.3.2" }, - { name = "elastic-array", version = "=0.10.3" }, - { name = "digest", version = "=0.8.1" }, - { name = "arrayvec", version = "=0.4.12" }, + { name = "quote", version = "=0.6.13" }, + { name = "rustc-hex", version = "=1.0.0" }, + { name = "smallvec", version = "=0.6.13" }, + { name = "syn", version = "=0.15.44" }, + { name = "unicode-xid", version = "=0.1.0" }, ] diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 230831544d5..e556c32c120 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -20,15 +20,15 @@ enum-primitive-derive = "0.2" sha2 = ">=0.8,<0.10" sha3 = "0.8" rlp = "0.4.2" -keccak-hash = "0.2.0" +keccak-hash = "0.4.1" ripemd160 = "0.9.0" libsecp256k1 = "0.3.5" -evm = { git = "https://github.com/openethereum/openethereum", rev = "v2.6.8" } -vm = { git = "https://github.com/openethereum/openethereum", rev = "v2.6.8" } -bn = { git = "https://github.com/paritytech/bn", default-features = false } +evm = { git = "https://github.com/openethereum/openethereum", rev = "v2.7.2" } +vm = { git = "https://github.com/openethereum/openethereum", rev = "v2.7.2" } +bn = { git = "https://github.com/near/bn", branch = "upgrade-rand", rev = "43953916ed1a314b78320771734f36af77993dd9" } parity-bytes = "0.1.0" -ethereum-types = "0.6.0" +ethereum-types = "0.8.0" near-vm-logic = { path = "../near-vm-logic" } near-vm-errors = { path = "../near-vm-errors" } @@ -38,9 +38,9 @@ near-runtime-fees = { path = "../near-runtime-fees" } derivative = "2.1.1" [dev-dependencies] -ethabi = "8.0.0" -ethabi-contract = "8.0.0" -ethabi-derive = "8.0.0" +ethabi = "9.0.1" +ethabi-contract = "9.0.0" +ethabi-derive = "9.0.1" lazy_static = "1.4" lazy-static-include = "2.2.2" diff --git a/runtime/near-evm-runner/src/interpreter.rs b/runtime/near-evm-runner/src/interpreter.rs index 554a0599acc..c0bb2262ed4 100644 --- a/runtime/near-evm-runner/src/interpreter.rs +++ b/runtime/near-evm-runner/src/interpreter.rs @@ -4,7 +4,7 @@ use ethereum_types::{Address, U256}; use evm::{CreateContractAddress, Factory}; use near_runtime_fees::EvmCostConfig; use vm::{ - ActionParams, ActionValue, CallType, ContractCreateResult, ExecTrapResult, Ext, GasLeft, + ActionParams, ActionType, ActionValue, ContractCreateResult, ExecTrapResult, Ext, GasLeft, MessageCallResult, ParamsType, ReturnData, Schedule, }; @@ -91,6 +91,8 @@ pub fn _create( let params = ActionParams { code_address: *address, + code_hash: None, + code_version: U256::zero(), address: *address, sender: *sender, origin: *origin, @@ -98,9 +100,8 @@ pub fn _create( gas_price: 1.into(), value: ActionValue::Transfer(value), code: Some(Arc::new(code.to_vec())), - code_hash: None, data: None, - call_type: CallType::None, + action_type: ActionType::Create, params_type: vm::ParamsType::Embedded, }; @@ -145,7 +146,7 @@ pub fn call( sender, value, call_stack_depth, - CallType::Call, + ActionType::Call, contract_address, contract_address, input, @@ -175,7 +176,7 @@ pub fn delegate_call( sender, None, call_stack_depth, - CallType::DelegateCall, + ActionType::DelegateCall, context, delegee, input, @@ -204,7 +205,7 @@ pub fn static_call( sender, None, call_stack_depth, - CallType::StaticCall, + ActionType::StaticCall, contract_address, contract_address, input, @@ -223,7 +224,7 @@ fn run_and_commit_if_success( sender: &Address, value: Option, call_stack_depth: usize, - call_type: CallType, + call_type: ActionType, state_address: &Address, code_address: &Address, input: &[u8], @@ -284,7 +285,7 @@ fn run_against_state( sender: &Address, value: Option, call_stack_depth: usize, - call_type: CallType, + call_type: ActionType, state_address: &Address, code_address: &Address, input: &[u8], @@ -307,6 +308,7 @@ fn run_against_state( let mut params = ActionParams { code_address: *code_address, code_hash: None, + code_version: U256::zero(), address: *state_address, sender: *sender, origin: *origin, @@ -315,7 +317,7 @@ fn run_against_state( value: ActionValue::Apparent(0.into()), code: Some(Arc::new(code)), data: Some(input.to_vec()), - call_type, + action_type: call_type, params_type: ParamsType::Separate, }; diff --git a/runtime/near-evm-runner/src/near_ext.rs b/runtime/near-evm-runner/src/near_ext.rs index 387da316eaf..64d725f7a1c 100644 --- a/runtime/near-evm-runner/src/near_ext.rs +++ b/runtime/near-evm-runner/src/near_ext.rs @@ -7,7 +7,7 @@ use keccak_hash::keccak; use near_runtime_fees::EvmCostConfig; use parity_bytes::Bytes; use vm::{ - CallType, ContractCreateResult, CreateContractAddress, EnvInfo, Error as VmError, + ActionType, ContractCreateResult, CreateContractAddress, EnvInfo, Error as VmError, MessageCallResult, Result as EvmResult, ReturnData, Schedule, TrapKind, }; @@ -142,6 +142,7 @@ impl<'a> vm::Ext for NearExt<'a> { gas: &U256, value: &U256, code: &[u8], + _parent_version: &U256, address_type: CreateContractAddress, _trap: bool, ) -> Result { @@ -179,10 +180,10 @@ impl<'a> vm::Ext for NearExt<'a> { value: Option, data: &[u8], code_address: &Address, - call_type: CallType, + call_type: ActionType, _trap: bool, ) -> Result { - if self.is_static() && call_type != CallType::StaticCall { + if self.is_static() && call_type != ActionType::StaticCall { panic!("MutableCallInStaticContext") } @@ -197,11 +198,11 @@ impl<'a> vm::Ext for NearExt<'a> { } let result = match call_type { - CallType::None => { + ActionType::Create | ActionType::Create2 => { // Is not used. return Err(TrapKind::Call(ActionParams::default())); } - CallType::Call => interpreter::call( + ActionType::Call => interpreter::call( self.sub_state, &self.origin, sender_address, @@ -214,7 +215,7 @@ impl<'a> vm::Ext for NearExt<'a> { &self.evm_gas_config, self.chain_id, ), - CallType::StaticCall => interpreter::static_call( + ActionType::StaticCall => interpreter::static_call( self.sub_state, &self.origin, sender_address, @@ -225,11 +226,11 @@ impl<'a> vm::Ext for NearExt<'a> { &self.evm_gas_config, self.chain_id, ), - CallType::CallCode => { + ActionType::CallCode => { // Call another contract using storage of the current contract. No longer used. return Err(TrapKind::Call(ActionParams::default())); } - CallType::DelegateCall => interpreter::delegate_call( + ActionType::DelegateCall => interpreter::delegate_call( self.sub_state, &self.origin, sender_address, diff --git a/runtime/near-vm-errors/Cargo.toml b/runtime/near-vm-errors/Cargo.toml index 483461ddc98..c443b25dfbd 100644 --- a/runtime/near-vm-errors/Cargo.toml +++ b/runtime/near-vm-errors/Cargo.toml @@ -20,7 +20,7 @@ borsh = "0.7.1" near-rpc-error-macro = { path = "../../tools/rpctypegen/macro", version = "0.1.0" } -ethereum-types = "0.6.0" +ethereum-types = "0.8.0" [features] dump_errors_schema = ["near-rpc-error-macro/dump_errors_schema"] diff --git a/runtime/runtime-params-estimator/Cargo.toml b/runtime/runtime-params-estimator/Cargo.toml index ec85d00d80b..a7ebdced9bf 100644 --- a/runtime/runtime-params-estimator/Cargo.toml +++ b/runtime/runtime-params-estimator/Cargo.toml @@ -33,10 +33,10 @@ glob = "0.3.0" walrus = "0.18.0" near-evm-runner = { path = "../../runtime/near-evm-runner", features = ["costs_counting"] } hex = "0.4" -ethabi = "8.0.0" -ethabi-contract = "8.0.0" -ethabi-derive = "8.0.0" -ethereum-types = "0.6.0" +ethabi = "9.0.1" +ethabi-contract = "9.0.0" +ethabi-derive = "9.0.1" +ethereum-types = "0.8.0" lazy-static-include = "2.2.2" num-traits = "0.2.12" diff --git a/runtime/runtime/Cargo.toml b/runtime/runtime/Cargo.toml index 9f2daf5f41c..36253d3587d 100644 --- a/runtime/runtime/Cargo.toml +++ b/runtime/runtime/Cargo.toml @@ -16,7 +16,7 @@ num-rational = "0.2.4" num-bigint = "0.2.6" num-traits = "0.2.11" hex = "0.4.2" -ethereum-types = "0.6.0" +ethereum-types = "0.8.0" borsh = "0.7.1" diff --git a/test-utils/testlib/Cargo.toml b/test-utils/testlib/Cargo.toml index a0731ff277a..08eb4d95a27 100644 --- a/test-utils/testlib/Cargo.toml +++ b/test-utils/testlib/Cargo.toml @@ -20,10 +20,10 @@ tempfile = "3" assert_matches = "1.3" num-rational = "0.2.4" hex = "0.4" -ethabi = "8.0.0" -ethabi-contract = "8.0.0" -ethabi-derive = "8.0.0" -ethereum-types = "0.6.0" +ethabi = "9.0.1" +ethabi-contract = "9.0.0" +ethabi-derive = "9.0.1" +ethereum-types = "0.8.0" borsh = "0.7.1" From 739636ca6a02b8341a7642a087a4bbe5b9b00414 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Mon, 16 Nov 2020 12:48:24 -0800 Subject: [PATCH 57/82] Remove branch --- Cargo.lock | 2 +- runtime/near-evm-runner/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd8b0a85371..606e62d136c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -600,7 +600,7 @@ dependencies = [ [[package]] name = "bn" version = "0.4.4" -source = "git+https://github.com/near/bn?branch=upgrade-rand#43953916ed1a314b78320771734f36af77993dd9" +source = "git+https://github.com/near/bn?rev=43953916ed1a314b78320771734f36af77993dd9#43953916ed1a314b78320771734f36af77993dd9" dependencies = [ "byteorder", "crunchy", diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index e556c32c120..6ed803a4d63 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -26,7 +26,7 @@ libsecp256k1 = "0.3.5" evm = { git = "https://github.com/openethereum/openethereum", rev = "v2.7.2" } vm = { git = "https://github.com/openethereum/openethereum", rev = "v2.7.2" } -bn = { git = "https://github.com/near/bn", branch = "upgrade-rand", rev = "43953916ed1a314b78320771734f36af77993dd9" } +bn = { git = "https://github.com/near/bn", rev = "43953916ed1a314b78320771734f36af77993dd9" } parity-bytes = "0.1.0" ethereum-types = "0.8.0" From 60fb45cab62b97d21676c77a9a64d6c863d95d2f Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Tue, 17 Nov 2020 09:03:43 -0800 Subject: [PATCH 58/82] Try removing evm-runner from workspace --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d38a07f0c97..5ae62de871c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ members = [ "runtime/near-vm-logic", "runtime/near-vm-runner", "runtime/near-vm-runner-standalone", - "runtime/near-evm-runner", "runtime/runtime-params-estimator", "chain/chain", "chain/chunks", From 47db54a435c7b372ba56e656bf73197a503ca75f Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Tue, 17 Nov 2020 09:20:27 -0800 Subject: [PATCH 59/82] Removing param estimator --- Cargo.lock | 150 +++++------------------------------------------------ Cargo.toml | 3 +- 2 files changed, 15 insertions(+), 138 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 606e62d136c..24841e41cc3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1811,7 +1811,7 @@ dependencies = [ "borsh", "byteorder", "clap 2.33.0", - "indicatif 0.13.0", + "indicatif", "near-chain", "near-chain-configs", "near-client", @@ -1886,15 +1886,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -[[package]] -name = "gnuplot" -version = "0.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de437277a7ec10de5f34e3147c7da4c6d8b279c5d8ae1e33e842fd9432bb0f3" -dependencies = [ - "byteorder", -] - [[package]] name = "goblin" version = "0.1.3" @@ -2113,12 +2104,6 @@ dependencies = [ "tokio-tls", ] -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - [[package]] name = "idna" version = "0.1.5" @@ -2220,18 +2205,6 @@ dependencies = [ "regex", ] -[[package]] -name = "indicatif" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7baab56125e25686df467fe470785512329883aab42696d661247aca2a2896e4" -dependencies = [ - "console", - "lazy_static", - "number_prefix", - "regex", -] - [[package]] name = "insta" version = "1.0.0" @@ -2425,12 +2398,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" -[[package]] -name = "leb128" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" - [[package]] name = "libc" version = "0.2.71" @@ -2783,7 +2750,7 @@ dependencies = [ "near-pool", "near-primitives", "near-store", - "num-rational 0.2.4", + "num-rational", "rand 0.7.3", "rocksdb", "serde", @@ -2803,7 +2770,7 @@ dependencies = [ "near-primitives", "near-runtime-configs", "near-runtime-fees", - "num-rational 0.2.4", + "num-rational", "serde", "serde_json", "sha2 0.9.2", @@ -2858,7 +2825,7 @@ dependencies = [ "near-store", "near-telemetry", "neard", - "num-rational 0.2.4", + "num-rational", "rand 0.7.3", "reed-solomon-erasure", "rocksdb", @@ -2905,7 +2872,7 @@ dependencies = [ "near-crypto", "near-primitives", "near-store", - "num-rational 0.2.4", + "num-rational", "primitive-types", "rand 0.6.5", "rand 0.7.3", @@ -3097,7 +3064,7 @@ dependencies = [ "near-crypto", "near-rpc-error-macro", "near-vm-errors", - "num-rational 0.2.4", + "num-rational", "primitive-types", "rand 0.7.3", "reed-solomon-erasure", @@ -3173,7 +3140,7 @@ dependencies = [ name = "near-runtime-fees" version = "2.2.0" dependencies = [ - "num-rational 0.2.4", + "num-rational", "serde", ] @@ -3292,7 +3259,7 @@ dependencies = [ "near-runtime-fees", "near-vm-logic", "near-vm-runner", - "num-rational 0.2.4", + "num-rational", "serde", "serde_json", "strum", @@ -3357,7 +3324,7 @@ dependencies = [ "near-store", "near-telemetry", "node-runtime", - "num-rational 0.2.4", + "num-rational", "openssl-probe", "rand 0.7.3", "rocksdb", @@ -3403,7 +3370,7 @@ dependencies = [ "byteorder", "ethereum-types", "hex", - "indicatif 0.13.0", + "indicatif", "lazy_static", "log", "near-chain-configs", @@ -3419,7 +3386,7 @@ dependencies = [ "near-vm-logic", "near-vm-runner", "num-bigint 0.2.6", - "num-rational 0.2.4", + "num-rational", "num-traits", "rand 0.7.3", "rayon", @@ -3494,18 +3461,6 @@ dependencies = [ "serde", ] -[[package]] -name = "num-rational" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5b4d7360f362cfb50dde8143501e6940b22f644be75a4cc90b2d81968908138" -dependencies = [ - "autocfg 1.0.0", - "num-bigint 0.3.0", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.12" @@ -4076,7 +4031,7 @@ dependencies = [ "rand_jitter", "rand_os", "rand_pcg", - "rand_xorshift 0.1.1", + "rand_xorshift", "winapi 0.3.8", ] @@ -4208,15 +4163,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "rand_xorshift" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "raw-cpuid" version = "7.0.3" @@ -4454,44 +4400,6 @@ dependencies = [ "librocksdb-sys", ] -[[package]] -name = "runtime-params-estimator" -version = "2.2.0" -dependencies = [ - "borsh", - "clap 2.33.0", - "csv", - "ethabi", - "ethabi-contract", - "ethabi-derive", - "ethereum-types", - "glob 0.3.0", - "gnuplot", - "hex", - "indicatif 0.15.0", - "lazy-static-include", - "near-chain-configs", - "near-crypto", - "near-evm-runner", - "near-primitives", - "near-runtime-fees", - "near-store", - "near-vm-logic", - "near-vm-runner", - "neard", - "node-runtime", - "num-rational 0.3.0", - "num-traits", - "rand 0.7.3", - "rand_xorshift 0.2.0", - "rocksdb", - "serde_json", - "state-viewer", - "tempfile", - "testlib", - "walrus", -] - [[package]] name = "rust-argon2" version = "0.7.0" @@ -5118,7 +5026,7 @@ dependencies = [ "near-vm-errors", "neard", "node-runtime", - "num-rational 0.2.4", + "num-rational", "rand 0.7.3", "serde_json", "tempfile", @@ -5649,32 +5557,6 @@ dependencies = [ "glob 0.2.11", ] -[[package]] -name = "walrus" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d470d0583e65f4cab21a1ff3c1ba3dd23ae49e68f516f0afceaeb001b32af39" -dependencies = [ - "anyhow", - "id-arena", - "leb128", - "log", - "walrus-macro", - "wasmparser 0.59.0", -] - -[[package]] -name = "walrus-macro" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c2bb690b44cb1b0fdcc54d4998d21f8bdaf706b93775425e440b174f39ad16" -dependencies = [ - "heck", - "proc-macro2 1.0.20", - "quote 1.0.3", - "syn 1.0.38", -] - [[package]] name = "want" version = "0.3.0" @@ -5833,12 +5715,6 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" -[[package]] -name = "wasmparser" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a950e6a618f62147fd514ff445b2a0b53120d382751960797f85f058c7eda9b9" - [[package]] name = "wasmtime" version = "0.17.0" diff --git a/Cargo.toml b/Cargo.toml index 5ae62de871c..a3a31effb1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,8 @@ members = [ "runtime/near-vm-logic", "runtime/near-vm-runner", "runtime/near-vm-runner-standalone", - "runtime/runtime-params-estimator", + # "runtime/near-evm-runner", + # "runtime/runtime-params-estimator", "chain/chain", "chain/chunks", "chain/epoch_manager", From d63c4f0fc8e924cae3180a4659553d81f5d532c3 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Tue, 17 Nov 2020 11:47:08 -0800 Subject: [PATCH 60/82] Add missing feature dependency --- runtime/near-evm-runner/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 6ed803a4d63..8cf243b698a 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -33,7 +33,7 @@ ethereum-types = "0.8.0" near-vm-logic = { path = "../near-vm-logic" } near-vm-errors = { path = "../near-vm-errors" } near-runtime-utils = { path = "../near-runtime-utils" } -near-runtime-fees = { path = "../near-runtime-fees" } +near-runtime-fees = { path = "../near-runtime-fees", features = ["protocol_feature_evm"] } derivative = "2.1.1" From 7bf555b9e6b0b0ff8fa8b9d2a6b8f6c7abca1f08 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Tue, 17 Nov 2020 13:23:09 -0800 Subject: [PATCH 61/82] Move EVM members to exclude --- Cargo.lock | 23 ----------------------- Cargo.toml | 3 +-- test-utils/testlib/Cargo.toml | 2 +- 3 files changed, 2 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24841e41cc3..ab3c12a164f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2372,17 +2372,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -[[package]] -name = "lazy-static-include" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10200e516c7a80a6dcfb1cdc23cd01ca0d8e97df71e9c5aa6d116302b89a928" -dependencies = [ - "lazy_static", - "starts-ends-with-caseless", - "syn 1.0.38", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -2890,17 +2879,11 @@ dependencies = [ "byteorder", "derivative", "enum-primitive-derive", - "ethabi", - "ethabi-contract", - "ethabi-derive", "ethereum-types", "evm", "hex", "keccak-hash", - "lazy-static-include", - "lazy_static", "libsecp256k1", - "near-crypto", "near-runtime-fees", "near-runtime-utils", "near-vm-errors", @@ -4769,12 +4752,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -[[package]] -name = "starts-ends-with-caseless" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1c13a0dff1a602924cf45fcb409855d46a5fd470a15b76ddcb61be675296d3" - [[package]] name = "state-viewer" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index a3a31effb1e..f16e387e232 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,6 @@ members = [ "runtime/near-vm-logic", "runtime/near-vm-runner", "runtime/near-vm-runner-standalone", - # "runtime/near-evm-runner", - # "runtime/runtime-params-estimator", "chain/chain", "chain/chunks", "chain/epoch_manager", @@ -46,6 +44,7 @@ members = [ "tools/indexer/example", "tools/delay_detector" ] +exclude = ["runtime/near-evm-runner", "runtime/runtime-params-estimator"] [dependencies] # pins this version to fix https://github.com/actix/actix-net/issues/129 diff --git a/test-utils/testlib/Cargo.toml b/test-utils/testlib/Cargo.toml index 08eb4d95a27..5dfdd770fe2 100644 --- a/test-utils/testlib/Cargo.toml +++ b/test-utils/testlib/Cargo.toml @@ -45,4 +45,4 @@ near-evm-runner = { path = "../../runtime/near-evm-runner", optional = true } [features] default = [] -protocol_feature_evm = ["near-evm-runner", "node-runtime/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"] +protocol_feature_evm = ["near-evm-runner", "near-primitives/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm", "neard/protocol_feature_evm", "node-runtime/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"] From de07bde068b8fa07e3d15a98852d1b686f5b5170 Mon Sep 17 00:00:00 2001 From: Arto Bendiken Date: Tue, 17 Nov 2020 23:31:45 +0200 Subject: [PATCH 62/82] Fix the CryptoZombies test. (#3611) (#3624) This fixes #3611. The regression was due to an invalid `zombieAttack.bin` imported in e350e29 (#3299). Hereby reverted to the original from cc4ec1f. Additionally, this also removes an annoying build warning inadvertently introduced in 8a45140 (#3595). --- runtime/near-evm-runner/tests/build/zombieAttack.bin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/near-evm-runner/tests/build/zombieAttack.bin b/runtime/near-evm-runner/tests/build/zombieAttack.bin index dd6826bc417..3e21cb25c22 100644 --- a/runtime/near-evm-runner/tests/build/zombieAttack.bin +++ b/runtime/near-evm-runner/tests/build/zombieAttack.bin @@ -1 +1 @@ -6080604052610a87806100136000396000f3fe6080604052600436106100705760003560e01c8063299fb0431161004e578063299fb043146101af5780632ccb1b30146101c65780639d9f9a6e14610235578063b69ef8a81461028657610070565b80630a84cba514610072578063111e0b12146100e757806314d54f541461015c575b005b61009e6004803603602081101561008857600080fd5b81019080803590602001909291905050506102b1565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b610113600480360360208110156100fd57600080fd5b8101908080359060200190929190505050610390565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561016857600080fd5b506101956004803603602081101561017f57600080fd5b81019080803590602001909291905050506103dc565b604051808215151515815260200191505060405180910390f35b3480156101bb57600080fd5b506101c461041e565b005b3480156101d257600080fd5b5061021f600480360360408110156101e957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610756565b6040518082815260200191505060405180910390f35b61023d6107af565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561029257600080fd5b5061029b610810565b6040518082815260200191505060405180910390f35b6000806000836040516102c390610818565b80828152602001915050604051809103906000f0801580156102e9573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610332573d6000803e3d6000fd5b508073ffffffffffffffffffffffffffffffffffffffff167fa53ffc4fb91f5ca8287e168fc73db3b0b384a6ca275650f885a1740ef7a0bc1c346040518082815260200191505060405180910390a280348191509250925050915091565b600080600034846040516103a390610818565b808281526020019150506040518091039082f0801580156103c8573d6000803e3d6000fd5b509050905080348191509250925050915091565b60007f379340f64b65a8890c7ea4f6d86d2359beaf41080f36a7ea64b78a2c06eee3f0826040518082815260200191505060405180910390a160019050919050565b7fe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556002604051806000019050602060405180830381855afa158015610467573d6000803e3d6000fd5b5050506040513d602081101561047c57600080fd5b810190808051906020019092919050505014610500576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f7368613220646967657374206d69736d6174636800000000000000000000000081525060200191505060405180910390fd5b7f9c1185a5c5e9fc54612808977ee8f548b2258d310000000000000000000000006003604051806000019050602060405180830381855afa158015610549573d6000803e3d6000fd5b5050506040515160601b6bffffffffffffffffffffffff1916146105d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f726d6431363020646967657374206d69736d617463680000000000000000000081525060200191505060405180910390fd5b60006001601b6040516000815260200160405260405180807f11111111111111111111111111111111111111111111111111111111111111118152506020018260ff168152602001807fb9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b698815250602001807f12ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb6447448152506020019150506020604051602081039080840390855afa158015610692573d6000803e3d6000fd5b505050602060405103519050731563915e194d8cfba1943570603f7606a311550873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610753576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f65637265636f766572206d69736d61746368000000000000000000000000000081525060200191505060405180910390fd5b50565b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561079e573d6000803e3d6000fd5b506107a7610810565b905092915050565b6000803373ffffffffffffffffffffffffffffffffffffffff166108fc600234816107d657fe5b049081150290604051600060405180830381858888f19350505050158015610802573d6000803e3d6000fd5b503334819150915091509091565b600047905090565b61022d806108268339019056fe6080604052600660005560405161022d38038061022d8339818101604052602081101561002b57600080fd5b810190808051906020019092919050505080600081905550506101da806100536000396000f3fe60806040526004361061003f5760003560e01c80632ccb1b301461004157806339c117a4146100b0578063b69ef8a8146100df578063e6a899b61461010a575b005b34801561004d57600080fd5b5061009a6004803603604081101561006457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610135565b6040518082815260200191505060405180910390f35b3480156100bc57600080fd5b506100c561018e565b604051808215151515815260200191505060405180910390f35b3480156100eb57600080fd5b506100f4610197565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b5061011f61019f565b6040518082815260200191505060405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015801561017d573d6000803e3d6000fd5b50610186610197565b905092915050565b60006001905090565b600047905090565b6000548156fea265627a7a72315820f6f44f505670bac22a9333cd975c317fbaa88dc23152a224b1341fc02dd8764264736f6c63430005100032a265627a7a723158205890404b6d6a9f080f4d5156523ec567b299609c5d3e45e4baf5c0ee35c7a68764736f6c63430005100032 \ No newline at end of file +60606040526010600155600154600a0a6002556201518060035566038d7ea4c6800060085560006009556046600a55336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506119d28061007d6000396000f3006060604052600436106100d0576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630ce90ec2146100d557806317a7f4cc146100ed5780632052465e146101195780633ccfd60b1461021d5780634412e10414610232578063528b7b8f146102c05780635f4623f1146103235780635faf28801461035c5780637bff0a01146103885780638da5cb5b146103e5578063c39cbef11461043a578063ccf670f814610471578063e1fa763814610494578063f2fde38b146104c0575b600080fd5b6100eb60048080359060200190919050506104f9565b005b34156100f857600080fd5b6101176004808035906020019091908035906020019091905050610565565b005b341561012457600080fd5b61013a60048080359060200190919050506106d2565b60405180806020018781526020018663ffffffff1663ffffffff1681526020018563ffffffff1663ffffffff1681526020018461ffff1661ffff1681526020018361ffff1661ffff1681526020018281038252888181546001816001161561010002031660029004815260200191508054600181600116156101000203166002900480156102095780601f106101de57610100808354040283529160200191610209565b820191906000526020600020905b8154815290600101906020018083116101ec57829003601f168201915b505097505050505050505060405180910390f35b341561022857600080fd5b610230610758565b005b341561023d57600080fd5b610269600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061082d565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156102ac578082015181840152602081019050610291565b505050509050019250505060405180910390f35b34156102cb57600080fd5b6102e1600480803590602001909190505061095b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561032e57600080fd5b61035a600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061098e565b005b341561036757600080fd5b6103866004808035906020019091908035906020019091905050610a2d565b005b341561039357600080fd5b6103e3600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610b0f565b005b34156103f057600080fd5b6103f8610b88565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561044557600080fd5b61046f60048080359060200190919080359060200190820180359060200191909192905050610bad565b005b341561047c57600080fd5b6104926004808035906020019091905050610c9b565b005b341561049f57600080fd5b6104be6004808035906020019091908035906020019091905050610d00565b005b34156104cb57600080fd5b6104f7600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610f93565b005b6008543414151561050957600080fd5b60048181548110151561051857fe5b9060005260206000209060030201600201600081819054906101000a900463ffffffff168092919060010191906101000a81548163ffffffff021916908363ffffffff1602179055505050565b6000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e98b7f4d83600060405161014001526040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018082815260200191505061014060405180830381600087803b151561060257600080fd5b6102c65a03f1151561061357600080fd5b50505060405180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519050909192939495969798509091929394959697509091929394959650909192939495509091929394509091929350909192509091509050809150506106cd83826040805190810160405280600581526020017f6b697474790000000000000000000000000000000000000000000000000000008152506110e8565b505050565b6004818154811015156106e157fe5b906000526020600020906003020160009150905080600001908060010154908060020160009054906101000a900463ffffffff16908060020160049054906101000a900463ffffffff16908060020160089054906101000a900461ffff169080600201600a9054906101000a900461ffff16905086565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156107b357600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050151561082b57600080fd5b565b610835611764565b61083d611764565b600080600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460405180591061088d5750595b9080825280602002602001820160405250925060009150600090505b600480549050811015610950578473ffffffffffffffffffffffffffffffffffffffff166005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156109435780838381518110151561092c57fe5b906020019060200201818152505081806001019250505b80806001019150506108a9565b829350505050919050565b60056020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156109e957600080fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60148281600482815481101515610a4057fe5b906000526020600020906003020160020160009054906101000a900463ffffffff1663ffffffff1610151515610a7557600080fd5b836005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610ae357600080fd5b83600486815481101515610af357fe5b9060005260206000209060030201600101819055505050505050565b600080600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054141515610b5e57600080fd5b610b67826112bd565b9050606481811515610b7557fe5b0681039050610b84828261133f565b5050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60028381600482815481101515610bc057fe5b906000526020600020906003020160020160009054906101000a900463ffffffff1663ffffffff1610151515610bf557600080fd5b846005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610c6357600080fd5b8484600488815481101515610c7457fe5b90600052602060002090600302016000019190610c92929190611778565b50505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610cf657600080fd5b8060088190555050565b6000806000846005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d7357600080fd5b600486815481101515610d8257fe5b90600052602060002090600302019350600485815481101515610da157fe5b90600052602060002090600302019250610dbb606461160e565b9150600a5482111515610ef157610df260018560020160089054906101000a900461ffff1661ffff166116a590919063ffffffff16565b8460020160086101000a81548161ffff021916908361ffff160217905550610e3e60018560020160009054906101000a900463ffffffff1663ffffffff166116cb90919063ffffffff16565b8460020160006101000a81548163ffffffff021916908363ffffffff160217905550610e8a600184600201600a9054906101000a900461ffff1661ffff166116a590919063ffffffff16565b83600201600a6101000a81548161ffff021916908361ffff160217905550610eec8684600101546040805190810160405280600681526020017f7a6f6d62696500000000000000000000000000000000000000000000000000008152506110e8565b610f8b565b610f1b600185600201600a9054906101000a900461ffff1661ffff166116a590919063ffffffff16565b84600201600a6101000a81548161ffff021916908361ffff160217905550610f6360018460020160089054906101000a900461ffff1661ffff166116a590919063ffffffff16565b8360020160086101000a81548161ffff021916908361ffff160217905550610f8a846116f5565b5b505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610fee57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561102a57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600080846005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561115957600080fd5b60048681548110151561116857fe5b906000526020600020906003020192506111818361171f565b151561118c57600080fd5b6002548581151561119957fe5b0694506002858460010154018115156111ae57fe5b04915060405180807f6b697474790000000000000000000000000000000000000000000000000000008152506005019050604051809103902060001916846040518082805190602001908083835b60208310151561122157805182526020820191506020810190506020830392506111fc565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916141561126d57606360648381151561126657fe5b0683030191505b6112ac6040805190810160405280600681526020017f4e6f4e616d6500000000000000000000000000000000000000000000000000008152508361133f565b6112b5836116f5565b505050505050565b600080826040518082805190602001908083835b6020831015156112f657805182526020820191506020810190506020830392506112d1565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206001900490506002548181151561133657fe5b06915050919050565b600060016004805480600101828161135791906117f8565b9160005260206000209060030201600060c060405190810160405280888152602001878152602001600163ffffffff168152602001600354420163ffffffff168152602001600061ffff168152602001600061ffff16815250909190915060008201518160000190805190602001906113d192919061182a565b506020820151816001015560408201518160020160006101000a81548163ffffffff021916908363ffffffff16021790555060608201518160020160046101000a81548163ffffffff021916908363ffffffff16021790555060808201518160020160086101000a81548161ffff021916908361ffff16021790555060a082015181600201600a6101000a81548161ffff021916908361ffff1602179055505050039050336005600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061151a6001600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461174690919063ffffffff16565b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f88f026aacbbecc90c18411df4b1185fd8d9be2470f1962f192bf84a27d0704b78184846040518084815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156115cd5780820151818401526020810190506115b2565b50505050905090810190601f1680156115fa5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1505050565b6000611626600160095461174690919063ffffffff16565b600981905550814233600954604051808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401828152602001935050505060405180910390206001900481151561169d57fe5b069050919050565b60008082840190508361ffff168161ffff16101515156116c157fe5b8091505092915050565b60008082840190508363ffffffff168163ffffffff16101515156116eb57fe5b8091505092915050565b60035442018160020160046101000a81548163ffffffff021916908363ffffffff16021790555050565b6000428260020160049054906101000a900463ffffffff1663ffffffff1611159050919050565b600080828401905083811015151561175a57fe5b8091505092915050565b602060405190810160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106117b957803560ff19168380011785556117e7565b828001600101855582156117e7579182015b828111156117e65782358255916020019190600101906117cb565b5b5090506117f491906118aa565b5090565b8154818355818115116118255760030281600302836000526020600020918201910161182491906118cf565b5b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061186b57805160ff1916838001178555611899565b82800160010185558215611899579182015b8281111561189857825182559160200191906001019061187d565b5b5090506118a691906118aa565b5090565b6118cc91905b808211156118c85760008160009055506001016118b0565b5090565b90565b61195b91905b8082111561195757600080820160006118ee919061195e565b60018201600090556002820160006101000a81549063ffffffff02191690556002820160046101000a81549063ffffffff02191690556002820160086101000a81549061ffff021916905560028201600a6101000a81549061ffff0219169055506003016118d5565b5090565b90565b50805460018160011615610100020316600290046000825580601f1061198457506119a3565b601f0160209004906000526020600020908101906119a291906118aa565b5b505600a165627a7a72305820132b51da42f560f7184ac5aae47f26c9658881610ed4c49b0c5c00f7456864e60029 \ No newline at end of file From 2475a28d7b77764557eed1c0ff318832c918fad8 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Tue, 17 Nov 2020 15:41:15 -0800 Subject: [PATCH 63/82] Cleaning up features --- Cargo.toml | 2 +- chain/chunks/Cargo.toml | 2 -- chain/client/Cargo.toml | 2 -- chain/jsonrpc/Cargo.toml | 2 +- chain/network/Cargo.toml | 4 +--- core/primitives/Cargo.toml | 3 +-- neard/Cargo.toml | 6 +++--- 7 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f16e387e232..a9082e3f91e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,6 +107,6 @@ metric_recorder = ["neard/metric_recorder"] delay_detector = ["neard/delay_detector"] rosetta_rpc = ["neard/rosetta_rpc"] protocol_feature_forward_chunk_parts = ["neard/protocol_feature_forward_chunk_parts"] -nightly_protocol = [] +nightly_protocol = ["near-primitives/nightly_protocol", "near-jsonrpc/nightly_protocol"] nightly_protocol_features = ["nightly_protocol", "neard/nightly_protocol_features"] protocol_feature_evm = ["neard/protocol_feature_evm", "testlib/protocol_feature_evm"] diff --git a/chain/chunks/Cargo.toml b/chain/chunks/Cargo.toml index f6508935384..6af66720ef4 100644 --- a/chain/chunks/Cargo.toml +++ b/chain/chunks/Cargo.toml @@ -29,5 +29,3 @@ near-logger-utils = { path = "../../test-utils/logger" } byzantine_asserts = ["near-chain/byzantine_asserts"] expensive_tests = [] protocol_feature_forward_chunk_parts = ["near-primitives/protocol_feature_forward_chunk_parts", "near-network/protocol_feature_forward_chunk_parts"] -nightly_protocol_features = ["nightly_protocol", "protocol_feature_forward_chunk_parts", "near-primitives/nightly_protocol_features"] -nightly_protocol = ["near-primitives/nightly_protocol"] diff --git a/chain/client/Cargo.toml b/chain/client/Cargo.toml index 053f35ec437..30c41ceb5d1 100644 --- a/chain/client/Cargo.toml +++ b/chain/client/Cargo.toml @@ -50,5 +50,3 @@ adversarial = ["near-network/adversarial", "near-chain/adversarial"] metric_recorder = [] delay_detector = ["near-chain/delay_detector", "near-network/delay_detector", "delay-detector"] protocol_feature_forward_chunk_parts = ["near-primitives/protocol_feature_forward_chunk_parts", "near-network/protocol_feature_forward_chunk_parts", "near-chunks/protocol_feature_forward_chunk_parts"] -nightly_protocol = [] -nightly_protocol_features = ["nightly_protocol", "protocol_feature_forward_chunk_parts"] diff --git a/chain/jsonrpc/Cargo.toml b/chain/jsonrpc/Cargo.toml index e2a1bc07095..edec01a4716 100644 --- a/chain/jsonrpc/Cargo.toml +++ b/chain/jsonrpc/Cargo.toml @@ -33,4 +33,4 @@ near-logger-utils = { path = "../../test-utils/logger" } [features] dump_errors_schema = ["near-rpc-error-macro/dump_errors_schema"] adversarial = [] -nightly_protocol = [] +nightly_protocol = ["near-primitives/nightly_protocol"] diff --git a/chain/network/Cargo.toml b/chain/network/Cargo.toml index fb5da80e0ae..3c3b6fb753d 100644 --- a/chain/network/Cargo.toml +++ b/chain/network/Cargo.toml @@ -44,9 +44,7 @@ near-telemetry = { path = "../telemetry" } adversarial = [] metric_recorder = [] delay_detector = ["delay-detector"] -protocol_feature_forward_chunk_parts = [] -nightly_protocol_features = ["nightly_protocol", "protocol_feature_forward_chunk_parts"] -nightly_protocol = [] +protocol_feature_forward_chunk_parts = ["near-primitives/protocol_feature_forward_chunk_parts"] [[bench]] name = "graph" diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index 6b4d6385c83..aadbce23673 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -35,9 +35,8 @@ near-rpc-error-macro = { path = "../../tools/rpctypegen/macro" } [features] default = ["jemallocator"] dump_errors_schema = ["near-rpc-error-macro/dump_errors_schema"] -protocol_feature_forward_chunk_parts = [] +protocol_feature_forward_chunk_parts = ["nightly_protocol"] protocol_feature_evm = [] -nightly_protocol_features = ["nightly_protocol", "protocol_feature_forward_chunk_parts"] nightly_protocol = [] diff --git a/neard/Cargo.toml b/neard/Cargo.toml index 26dd510929d..315bd61568e 100644 --- a/neard/Cargo.toml +++ b/neard/Cargo.toml @@ -58,9 +58,9 @@ metric_recorder = ["near-network/metric_recorder", "near-client/metric_recorder" no_cache = ["node-runtime/no_cache", "near-store/no_cache", "near-chain/no_cache"] delay_detector = ["near-client/delay_detector"] rosetta_rpc = ["near-rosetta-rpc"] -protocol_feature_forward_chunk_parts = ["near-client/protocol_feature_forward_chunk_parts"] -protocol_feature_evm = ["node-runtime/protocol_feature_evm", "near-primitives/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"] -nightly_protocol_features = ["nightly_protocol", "protocol_feature_forward_chunk_parts", "near-client/nightly_protocol_features", "protocol_feature_evm"] +protocol_feature_forward_chunk_parts = ["near-primitives/protocol_feature_forward_chunk_parts", "near-client/protocol_feature_forward_chunk_parts", "near-chunks/protocol_feature_forward_chunk_parts", "near-network/protocol_feature_forward_chunk_parts"] +protocol_feature_evm = ["near-primitives/protocol_feature_evm", "node-runtime/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"] +nightly_protocol_features = ["nightly_protocol", "protocol_feature_forward_chunk_parts", "protocol_feature_evm"] nightly_protocol = ["near-primitives/nightly_protocol", "near-jsonrpc/nightly_protocol"] [[bin]] From b92f5f7ecb5cbb0085de90cd4043cc22139271ed Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Tue, 17 Nov 2020 17:27:31 -0800 Subject: [PATCH 64/82] Fix nightly version check --- core/primitives/src/version.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/primitives/src/version.rs b/core/primitives/src/version.rs index d8575d0bb54..4bfd2b07eeb 100644 --- a/core/primitives/src/version.rs +++ b/core/primitives/src/version.rs @@ -125,7 +125,7 @@ macro_rules! checked_feature { #[cfg(feature = $feature_name)] let is_feature_enabled = near_primitives::version::PROTOCOL_FEATURES_TO_VERSION_MAPPING [&near_primitives::version::ProtocolFeature::$feature] - >= $current_protocol_version; + <= $current_protocol_version; #[cfg(not(feature = $feature_name))] let is_feature_enabled = { // Workaround unused variable warning From f3892c4d56f9b9afffd89b01276b810464308e4c Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Wed, 18 Nov 2020 11:11:10 -0800 Subject: [PATCH 65/82] Re-enable members --- Cargo.lock | 173 +++++++++++++++++++++++++++++++++++++++++++++++++---- Cargo.toml | 7 ++- 2 files changed, 164 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab3c12a164f..df662ebe255 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1811,7 +1811,7 @@ dependencies = [ "borsh", "byteorder", "clap 2.33.0", - "indicatif", + "indicatif 0.13.0", "near-chain", "near-chain-configs", "near-client", @@ -1886,6 +1886,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +[[package]] +name = "gnuplot" +version = "0.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de437277a7ec10de5f34e3147c7da4c6d8b279c5d8ae1e33e842fd9432bb0f3" +dependencies = [ + "byteorder", +] + [[package]] name = "goblin" version = "0.1.3" @@ -2104,6 +2113,12 @@ dependencies = [ "tokio-tls", ] +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + [[package]] name = "idna" version = "0.1.5" @@ -2205,6 +2220,18 @@ dependencies = [ "regex", ] +[[package]] +name = "indicatif" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7baab56125e25686df467fe470785512329883aab42696d661247aca2a2896e4" +dependencies = [ + "console", + "lazy_static", + "number_prefix", + "regex", +] + [[package]] name = "insta" version = "1.0.0" @@ -2372,6 +2399,17 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" +[[package]] +name = "lazy-static-include" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10200e516c7a80a6dcfb1cdc23cd01ca0d8e97df71e9c5aa6d116302b89a928" +dependencies = [ + "lazy_static", + "starts-ends-with-caseless", + "syn 1.0.38", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -2387,6 +2425,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" +[[package]] +name = "leb128" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" + [[package]] name = "libc" version = "0.2.71" @@ -2739,7 +2783,7 @@ dependencies = [ "near-pool", "near-primitives", "near-store", - "num-rational", + "num-rational 0.2.4", "rand 0.7.3", "rocksdb", "serde", @@ -2759,7 +2803,7 @@ dependencies = [ "near-primitives", "near-runtime-configs", "near-runtime-fees", - "num-rational", + "num-rational 0.2.4", "serde", "serde_json", "sha2 0.9.2", @@ -2814,7 +2858,7 @@ dependencies = [ "near-store", "near-telemetry", "neard", - "num-rational", + "num-rational 0.2.4", "rand 0.7.3", "reed-solomon-erasure", "rocksdb", @@ -2861,7 +2905,7 @@ dependencies = [ "near-crypto", "near-primitives", "near-store", - "num-rational", + "num-rational 0.2.4", "primitive-types", "rand 0.6.5", "rand 0.7.3", @@ -2879,11 +2923,17 @@ dependencies = [ "byteorder", "derivative", "enum-primitive-derive", + "ethabi", + "ethabi-contract", + "ethabi-derive", "ethereum-types", "evm", "hex", "keccak-hash", + "lazy-static-include", + "lazy_static", "libsecp256k1", + "near-crypto", "near-runtime-fees", "near-runtime-utils", "near-vm-errors", @@ -3047,7 +3097,7 @@ dependencies = [ "near-crypto", "near-rpc-error-macro", "near-vm-errors", - "num-rational", + "num-rational 0.2.4", "primitive-types", "rand 0.7.3", "reed-solomon-erasure", @@ -3123,7 +3173,7 @@ dependencies = [ name = "near-runtime-fees" version = "2.2.0" dependencies = [ - "num-rational", + "num-rational 0.2.4", "serde", ] @@ -3242,7 +3292,7 @@ dependencies = [ "near-runtime-fees", "near-vm-logic", "near-vm-runner", - "num-rational", + "num-rational 0.2.4", "serde", "serde_json", "strum", @@ -3307,7 +3357,7 @@ dependencies = [ "near-store", "near-telemetry", "node-runtime", - "num-rational", + "num-rational 0.2.4", "openssl-probe", "rand 0.7.3", "rocksdb", @@ -3353,7 +3403,7 @@ dependencies = [ "byteorder", "ethereum-types", "hex", - "indicatif", + "indicatif 0.13.0", "lazy_static", "log", "near-chain-configs", @@ -3369,7 +3419,7 @@ dependencies = [ "near-vm-logic", "near-vm-runner", "num-bigint 0.2.6", - "num-rational", + "num-rational 0.2.4", "num-traits", "rand 0.7.3", "rayon", @@ -3444,6 +3494,18 @@ dependencies = [ "serde", ] +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg 1.0.0", + "num-bigint 0.3.0", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.12" @@ -4014,7 +4076,7 @@ dependencies = [ "rand_jitter", "rand_os", "rand_pcg", - "rand_xorshift", + "rand_xorshift 0.1.1", "winapi 0.3.8", ] @@ -4146,6 +4208,15 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "rand_xorshift" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" +dependencies = [ + "rand_core 0.5.1", +] + [[package]] name = "raw-cpuid" version = "7.0.3" @@ -4383,6 +4454,44 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "runtime-params-estimator" +version = "2.2.0" +dependencies = [ + "borsh", + "clap 2.33.0", + "csv", + "ethabi", + "ethabi-contract", + "ethabi-derive", + "ethereum-types", + "glob 0.3.0", + "gnuplot", + "hex", + "indicatif 0.15.0", + "lazy-static-include", + "near-chain-configs", + "near-crypto", + "near-evm-runner", + "near-primitives", + "near-runtime-fees", + "near-store", + "near-vm-logic", + "near-vm-runner", + "neard", + "node-runtime", + "num-rational 0.3.2", + "num-traits", + "rand 0.7.3", + "rand_xorshift 0.2.0", + "rocksdb", + "serde_json", + "state-viewer", + "tempfile", + "testlib", + "walrus", +] + [[package]] name = "rust-argon2" version = "0.7.0" @@ -4752,6 +4861,12 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +[[package]] +name = "starts-ends-with-caseless" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1c13a0dff1a602924cf45fcb409855d46a5fd470a15b76ddcb61be675296d3" + [[package]] name = "state-viewer" version = "0.1.0" @@ -5003,7 +5118,7 @@ dependencies = [ "near-vm-errors", "neard", "node-runtime", - "num-rational", + "num-rational 0.2.4", "rand 0.7.3", "serde_json", "tempfile", @@ -5534,6 +5649,32 @@ dependencies = [ "glob 0.2.11", ] +[[package]] +name = "walrus" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d470d0583e65f4cab21a1ff3c1ba3dd23ae49e68f516f0afceaeb001b32af39" +dependencies = [ + "anyhow", + "id-arena", + "leb128", + "log", + "walrus-macro", + "wasmparser 0.59.0", +] + +[[package]] +name = "walrus-macro" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c2bb690b44cb1b0fdcc54d4998d21f8bdaf706b93775425e440b174f39ad16" +dependencies = [ + "heck", + "proc-macro2 1.0.20", + "quote 1.0.3", + "syn 1.0.38", +] + [[package]] name = "want" version = "0.3.0" @@ -5692,6 +5833,12 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" +[[package]] +name = "wasmparser" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a950e6a618f62147fd514ff445b2a0b53120d382751960797f85f058c7eda9b9" + [[package]] name = "wasmtime" version = "0.17.0" diff --git a/Cargo.toml b/Cargo.toml index a9082e3f91e..d349c234f2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,12 +13,14 @@ members = [ "core/store", "core/metrics", "utils/actix", - "runtime/runtime", - "runtime/runtime-standalone", + "runtime/near-evm-runner", "runtime/near-runtime-fees", "runtime/near-vm-logic", "runtime/near-vm-runner", "runtime/near-vm-runner-standalone", + "runtime/runtime", + "runtime/runtime-standalone", + "runtime/runtime-params-estimator", "chain/chain", "chain/chunks", "chain/epoch_manager", @@ -44,7 +46,6 @@ members = [ "tools/indexer/example", "tools/delay_detector" ] -exclude = ["runtime/near-evm-runner", "runtime/runtime-params-estimator"] [dependencies] # pins this version to fix https://github.com/actix/actix-net/issues/129 From 77c763000018db1d1c73cd2ec76c1eda28dc45ae Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Wed, 18 Nov 2020 15:04:31 -0800 Subject: [PATCH 66/82] Fix near-evm-runner depdendency leak --- runtime/near-evm-runner/Cargo.toml | 3 +- runtime/near-evm-runner/src/lib.rs | 847 +----------------- runtime/near-evm-runner/src/runner.rs | 835 +++++++++++++++++ runtime/near-evm-runner/tests/failures.rs | 65 +- runtime/near-evm-runner/tests/standard_ops.rs | 597 ++++++------ runtime/near-evm-runner/tests/utils.rs | 195 ++-- runtime/near-vm-runner/Cargo.toml | 2 +- runtime/runtime-params-estimator/Cargo.toml | 12 +- runtime/runtime/Cargo.toml | 4 +- test-utils/testlib/Cargo.toml | 2 +- 10 files changed, 1302 insertions(+), 1260 deletions(-) create mode 100644 runtime/near-evm-runner/src/runner.rs diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 8cf243b698a..fe199755425 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -33,7 +33,7 @@ ethereum-types = "0.8.0" near-vm-logic = { path = "../near-vm-logic" } near-vm-errors = { path = "../near-vm-errors" } near-runtime-utils = { path = "../near-runtime-utils" } -near-runtime-fees = { path = "../near-runtime-fees", features = ["protocol_feature_evm"] } +near-runtime-fees = { path = "../near-runtime-fees" } derivative = "2.1.1" @@ -48,3 +48,4 @@ near-crypto = { path = "../../core/crypto" } [features] costs_counting = [] +protocol_feature_evm = ["near-runtime-fees/protocol_feature_evm"] diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 80efdcb6e14..0dd3cca5de7 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -1,843 +1,18 @@ -#[macro_use] -extern crate enum_primitive_derive; - -use borsh::{BorshDeserialize, BorshSerialize}; -use ethereum_types::{Address, H160, U256}; -use evm::CreateContractAddress; -use vm::{ContractCreateResult, MessageCallResult}; - -use near_runtime_fees::{EvmCostConfig, RuntimeFeesConfig}; -use near_runtime_utils::{is_account_id_64_len_hex, is_valid_sub_account_id}; -use near_vm_errors::{EvmError, FunctionCallError, VMError}; -use near_vm_logic::gas_counter::GasCounter; -use near_vm_logic::types::{AccountId, Balance, Gas, ReturnData, StorageUsage}; -use near_vm_logic::{ActionCosts, External, VMConfig, VMLogicError, VMOutcome}; - -use crate::evm_state::{EvmAccount, EvmGasCounter, EvmState, StateStore}; -use crate::types::{ - AddressArg, DataKey, FunctionCallArgs, GetStorageAtArgs, Method, RawU256, Result, TransferArgs, - ViewCallArgs, WithdrawArgs, -}; -use crate::utils::{combine_data_key, near_erc721_domain, parse_meta_call}; -use near_vm_errors::InconsistentStateError::StorageError; - +#[cfg(feature = "protocol_feature_evm")] mod builtins; +#[cfg(feature = "protocol_feature_evm")] mod evm_state; +#[cfg(feature = "protocol_feature_evm")] mod interpreter; +#[cfg(feature = "protocol_feature_evm")] mod near_ext; +#[cfg(feature = "protocol_feature_evm")] mod pricer; +#[cfg(feature = "protocol_feature_evm")] +mod runner; +#[cfg(feature = "protocol_feature_evm")] pub mod types; +#[cfg(feature = "protocol_feature_evm")] pub mod utils; - -pub struct EvmContext<'a> { - ext: &'a mut dyn External, - account_id: AccountId, - signer_id: AccountId, - predecessor_id: AccountId, - current_amount: Balance, - pub attached_deposit: Balance, - storage_usage: StorageUsage, - pub logs: Vec, - gas_counter: GasCounter, - pub evm_gas_counter: EvmGasCounter, - fees_config: &'a RuntimeFeesConfig, - chain_id: u128, - domain_separator: RawU256, -} - -// Different kind of evm operations that result in different gas calculation -pub enum EvmOpForGas { - // size of deployed evm contract after it's decoded from hex (0.5x) - Deploy(usize), - Funcall, - Other, -} - -enum KeyPrefix { - Account = 0, - Contract = 1, -} - -fn address_to_key(prefix: KeyPrefix, address: &H160) -> [u8; 21] { - let mut result = [0u8; 21]; - result[0] = prefix as u8; - result[1..].copy_from_slice(&address.0); - result -} - -impl<'a> EvmState for EvmContext<'a> { - fn code_at(&self, address: &H160) -> Result>> { - self.ext - .storage_get(&address_to_key(KeyPrefix::Contract, address)) - .map(|value| value.map(|x| x.deref().expect("Failed to deref"))) - } - - fn set_code(&mut self, address: &H160, bytecode: &[u8]) -> Result<()> { - self.ext.storage_set(&address_to_key(KeyPrefix::Contract, address), bytecode) - } - - fn get_account(&self, address: &Address) -> Result> { - match self.ext.storage_get(&address_to_key(KeyPrefix::Account, address)).map(|value| { - value.map(|x| EvmAccount::try_from_slice(&x.deref().expect("Failed to deref"))) - }) { - Ok(Some(Ok(value))) => Ok(Some(value)), - Ok(None) => Ok(None), - Ok(Some(Err(_))) => Err(VMLogicError::InconsistentStateError(StorageError( - "Failed to deserialize".to_string(), - ))), - Err(e) => Err(e), - } - } - - fn set_account(&mut self, address: &Address, account: &EvmAccount) -> Result<()> { - self.ext.storage_set( - &address_to_key(KeyPrefix::Account, address), - &account.try_to_vec().expect("Failed to serialize"), - ) - } - - fn _read_contract_storage(&self, key: &DataKey) -> Result> { - match self - .ext - .storage_get(key) - .map(|value| value.map(|x| utils::vec_to_arr_32(x.deref().expect("Failed to deref")))) - { - Ok(Some(Some(value))) => Ok(Some(value)), - Ok(Some(None)) => Err(VMLogicError::InconsistentStateError(StorageError( - "Must be 32 bytes".to_string(), - ))), - Ok(None) => Ok(None), - Err(err) => Err(err), - } - } - - fn _set_contract_storage(&mut self, key: &DataKey, value: RawU256) -> Result<()> { - self.ext.storage_set(key, &value) - } - - fn commit_changes(&mut self, other: &StateStore) -> Result<()> { - for address in other.self_destructs.iter() { - self.clear_contract_info(address)?; - } - for address in other.recreated.iter() { - self.clear_contract_info(address)?; - } - for (address, code) in other.code.iter() { - self.set_code(address, code)?; - } - for (address, account) in other.accounts.iter() { - self.set_account(address, account)?; - } - for (address, values) in other.storages.iter() { - for (key, value) in values.iter() { - let key = combine_data_key(address, key); - self._set_contract_storage(&key, *value)?; - } - } - self.logs.extend_from_slice(&other.logs); - Ok(()) - } - - fn recreate(&mut self, _address: Address) { - unreachable!() - } -} - -impl<'a> EvmContext<'a> { - pub fn new( - ext: &'a mut dyn External, - chain_id: u128, - config: &'a VMConfig, - fees_config: &'a RuntimeFeesConfig, - current_amount: Balance, - account_id: AccountId, - signer_id: AccountId, - predecessor_id: AccountId, - attached_deposit: Balance, - storage_usage: StorageUsage, - prepaid_gas: Gas, - is_view: bool, - evm_gas: U256, - ) -> Self { - let max_gas_burnt = if is_view { - config.limit_config.max_gas_burnt_view - } else { - config.limit_config.max_gas_burnt - }; - // TODO: pass chain id from ??? genesis / config. - let domain_separator = near_erc721_domain(U256::from(chain_id)); - Self { - ext, - account_id, - signer_id, - predecessor_id, - current_amount, - attached_deposit, - storage_usage, - logs: Vec::default(), - gas_counter: GasCounter::new( - config.ext_costs.clone(), - max_gas_burnt, - prepaid_gas, - is_view, - None, - ), - evm_gas_counter: EvmGasCounter::new(0.into(), evm_gas), - fees_config, - chain_id, - domain_separator, - } - } - - fn clear_contract_info(&mut self, other: &Address) -> Result<()> { - self.ext.storage_remove_subtree(&other.0) - } - - pub fn deploy_code(&mut self, bytecode: Vec) -> Result

{ - let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); - self.add_balance(&sender, U256::from(self.attached_deposit))?; - match interpreter::deploy_code( - self, - &sender, - &sender, - U256::from(self.attached_deposit), - 0, - CreateContractAddress::FromSenderAndNonce, - false, - &bytecode, - &self.evm_gas_counter.gas_left(), - &self.fees_config.evm_config, - self.chain_id, - )? { - ContractCreateResult::Created(address, gas_left) => { - self.evm_gas_counter.set_gas_left(gas_left); - Ok(address) - } - ContractCreateResult::Reverted(gas_left, return_data) => { - self.evm_gas_counter.set_gas_left(gas_left); - Err(VMLogicError::EvmError(EvmError::DeployFail(return_data.to_vec()))) - } - _ => unreachable!(), - } - } - - /// Make an EVM transaction. Calls `contract_address` with RLP encoded `input`. Execution - /// continues until all EVM messages have been processed. We expect this to behave identically - /// to an Ethereum transaction, however there may be some edge cases. - pub fn call_function(&mut self, args: Vec) -> Result> { - let args = FunctionCallArgs::try_from_slice(&args) - .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; - let contract_address = Address::from(&args.contract); - let input = args.input; - let _origin = utils::near_account_id_to_evm_address(&self.signer_id); - let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); - self.add_balance(&sender, U256::from(self.attached_deposit))?; - let value = - if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; - let result = interpreter::call( - self, - &sender, - &sender, - value, - 0, - &contract_address, - &input, - true, - &self.evm_gas_counter.gas_left(), - &self.fees_config.evm_config, - self.chain_id, - )?; - self.process_call_result(result) - } - - /// Make an EVM call via a meta transaction pattern. - /// Specifically, providing signature and NEAREvm message that determines which contract and arguments to be called. - /// See `parse_meta_call` for arguments format. - pub fn meta_call_function(&mut self, args: Vec) -> Result> { - let meta_call_args = parse_meta_call(&self.domain_separator, &self.account_id, args)?; - if self.next_nonce(&meta_call_args.sender)? != meta_call_args.nonce { - return Err(VMLogicError::EvmError(EvmError::InvalidNonce)); - } - self.add_balance(&meta_call_args.sender, U256::from(self.attached_deposit))?; - let value = - if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; - let result = interpreter::call( - self, - &meta_call_args.sender, - &meta_call_args.sender, - value, - 0, - &meta_call_args.contract_address, - &meta_call_args.input, - true, - &self.evm_gas_counter.gas_left(), - &self.fees_config.evm_config, - self.chain_id, - )?; - self.process_call_result(result) - } - - /// Make an EVM transaction. Calls `contract_address` with `encoded_input`. Execution - /// continues until all EVM messages have been processed. We expect this to behave identically - /// to an Ethereum transaction, however there may be some edge cases. - /// - /// This function serves the eth_call functionality, and will NOT apply state changes. - pub fn view_call_function(&mut self, args: Vec) -> Result> { - let args = ViewCallArgs::try_from_slice(&args) - .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; - let sender = Address::from(&args.sender); - let attached_amount = U256::from(args.amount); - self.add_balance(&sender, attached_amount)?; - // TODO: Verify we don't keep the balance in case `call` returns `Err` - let result = interpreter::call( - self, - &sender, - &sender, - Some(attached_amount), - 0, - &Address::from(&args.address), - &args.input, - false, - &self.evm_gas_counter.gas_left(), - &self.fees_config.evm_config, - self.chain_id, - )?; - let result = self.process_call_result(result); - // Need to subtract amount back, because if view call is called inside the transaction state will be applied. - // The interpreter call is not committing changes, but `add_balance` did, so need to revert that. - self.sub_balance(&sender, attached_amount)?; - result - } - - /// Processes `MessageCallResult` and charges gas. - fn process_call_result(&mut self, result: MessageCallResult) -> Result> { - match result { - MessageCallResult::Success(gas_left, data) => { - self.evm_gas_counter.set_gas_left(gas_left); - Ok(data.to_vec()) - } - MessageCallResult::Reverted(gas_left, data) => { - self.evm_gas_counter.set_gas_left(gas_left); - Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) - } - _ => unreachable!(), - } - } - - pub fn get_code(&self, args: Vec) -> Result> { - let args = AddressArg::try_from_slice(&args) - .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; - Ok(self - .code_at(&Address::from_slice(&args.address)) - .unwrap_or(None) - .unwrap_or_else(Vec::new)) - } - - pub fn get_storage_at(&self, args: Vec) -> Result> { - let args = GetStorageAtArgs::try_from_slice(&args) - .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; - Ok(self - .read_contract_storage(&Address::from_slice(&args.address), &args.key)? - .unwrap_or([0u8; 32]) - .to_vec()) - } - - pub fn get_balance(&self, args: Vec) -> Result { - let args = AddressArg::try_from_slice(&args) - .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; - self.balance_of(&Address::from_slice(&args.address)) - } - - pub fn get_nonce(&self, args: Vec) -> Result { - let args = AddressArg::try_from_slice(&args) - .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; - self.nonce_of(&Address::from_slice(&args.address)) - } - - pub fn deposit(&mut self, args: Vec) -> Result { - let args = AddressArg::try_from_slice(&args) - .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; - if self.attached_deposit == 0 { - return Err(VMLogicError::EvmError(EvmError::MissingDeposit)); - } - let address = Address::from_slice(&args.address); - self.add_balance(&address, U256::from(self.attached_deposit))?; - self.balance_of(&address) - } - - pub fn withdraw(&mut self, args: Vec) -> Result<()> { - let args = WithdrawArgs::try_from_slice(&args) - .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; - if args.account_id == self.account_id { - return Err(VMLogicError::EvmError(EvmError::FailSelfWithdraw)); - } - let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); - let amount = U256::from(args.amount); - if amount > self.balance_of(&sender)? { - return Err(VMLogicError::EvmError(EvmError::InsufficientFunds)); - } - self.sub_balance(&sender, amount)?; - let receipt_index = self.ext.create_receipt(vec![], args.account_id.clone())?; - // We use low_u128, because NEAR native currency fits into u128. - let amount = amount.low_u128(); - self.current_amount = self - .current_amount - .checked_sub(amount) - .ok_or_else(|| VMLogicError::EvmError(EvmError::InsufficientFunds))?; - self.pay_gas_for_new_receipt(false, &[])?; - self.pay_gas_for_transfer(&args.account_id)?; - self.ext.append_action_transfer(receipt_index, amount) - } - - /// Transfer tokens from sender to given EVM address. - pub fn transfer(&mut self, args: Vec) -> Result<()> { - let args = TransferArgs::try_from_slice(&args) - .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; - let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); - let amount = U256::from(args.amount); - if amount > self.balance_of(&sender)? { - return Err(VMLogicError::EvmError(EvmError::InsufficientFunds)); - } - self.transfer_balance(&sender, &Address::from(args.address), amount) - } - - /// Creates new EVM under given sub account and sends attached balance to it. - /// If account id given is not a valid subaccount of the current account, will return InvalidSubAccount. - /// If balance attached was not enough, will return InsufficientDeposit. - pub fn create_evm(&mut self, args: Vec) -> Result<()> { - let new_account_id = std::str::from_utf8(&args) - .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))? - .to_string(); - if !is_valid_sub_account_id(&self.account_id, &new_account_id) { - return Err(VMLogicError::EvmError(EvmError::InvalidSubAccount)); - } - if self.attached_deposit < self.fees_config.evm_deposit { - return Err(VMLogicError::EvmError(EvmError::InsufficientDeposit)); - } - self.current_amount = self - .current_amount - .checked_sub(self.attached_deposit) - .ok_or_else(|| VMLogicError::EvmError(EvmError::InsufficientFunds))?; - let receipt_index = self.ext.create_receipt(vec![], new_account_id.clone())?; - self.pay_gas_for_new_receipt(false, &[])?; - self.gas_counter.pay_action_base( - &self.fees_config.action_creation_config.create_account_cost, - false, - ActionCosts::create_account, - )?; - self.ext.append_action_create_account(receipt_index)?; - self.pay_gas_for_transfer(&new_account_id)?; - self.ext.append_action_transfer(receipt_index, self.attached_deposit) - } - - /// A helper function to pay gas fee for creating a new receipt without actions. - /// # Args: - /// * `sir`: whether contract call is addressed to itself; - /// * `data_dependencies`: other contracts that this execution will be waiting on (or rather - /// their data receipts), where bool indicates whether this is sender=receiver communication. - /// - /// # Cost - /// - /// This is a convenience function that encapsulates several costs: - /// `burnt_gas := dispatch cost of the receipt + base dispatch cost cost of the data receipt` - /// `used_gas := burnt_gas + exec cost of the receipt + base exec cost cost of the data receipt` - /// Notice that we prepay all base cost upon the creation of the data dependency, we are going to - /// pay for the content transmitted through the dependency upon the actual creation of the - /// DataReceipt. - fn pay_gas_for_new_receipt(&mut self, sir: bool, data_dependencies: &[bool]) -> Result<()> { - let fees_config_cfg = &self.fees_config; - let mut burn_gas = fees_config_cfg.action_receipt_creation_config.send_fee(sir); - let mut use_gas = fees_config_cfg.action_receipt_creation_config.exec_fee(); - for dep in data_dependencies { - // Both creation and execution for data receipts are considered burnt gas. - burn_gas = burn_gas - .checked_add(fees_config_cfg.data_receipt_creation_config.base_cost.send_fee(*dep)) - .ok_or(VMLogicError::EvmError(EvmError::IntegerOverflow))? - .checked_add(fees_config_cfg.data_receipt_creation_config.base_cost.exec_fee()) - .ok_or(VMLogicError::EvmError(EvmError::IntegerOverflow))?; - } - use_gas = use_gas - .checked_add(burn_gas) - .ok_or(VMLogicError::EvmError(EvmError::IntegerOverflow))?; - self.gas_counter.pay_action_accumulated(burn_gas, use_gas, ActionCosts::new_receipt) - } - - fn pay_gas_from_evm_gas(&mut self, op: EvmOpForGas) -> Result<()> { - let fee_cfg = &self.fees_config.evm_config; - let evm_gas = self.evm_gas_counter.used_gas.as_u64(); - self.gas_counter.inc_evm_gas_counter(evm_gas); - let gas = match op { - EvmOpForGas::Deploy(decoded_len) => { - // gas per byte is counting hex encoded contract size (solc output, 2x of decoded len) - (decoded_len as u64 * 2) * fee_cfg.deploy_cost_per_byte - + evm_gas * fee_cfg.deploy_cost_per_evm_gas - + fee_cfg.bootstrap_cost - } - EvmOpForGas::Funcall => { - evm_gas * fee_cfg.funcall_cost_per_evm_gas - + fee_cfg.funcall_cost_base - + fee_cfg.bootstrap_cost - } - EvmOpForGas::Other => fee_cfg.bootstrap_cost, - }; - self.gas_counter.pay_evm_gas(gas) - } - - fn pay_gas_for_transfer(&mut self, account_id: &AccountId) -> Result<()> { - if is_account_id_64_len_hex(&account_id) { - self.gas_counter.pay_action_base( - &self.fees_config.action_creation_config.create_account_cost, - false, - ActionCosts::transfer, - )?; - self.gas_counter.pay_action_base( - &self.fees_config.action_creation_config.add_key_cost.full_access_cost, - false, - ActionCosts::transfer, - )?; - } - self.gas_counter.pay_action_base( - &self.fees_config.action_creation_config.transfer_cost, - false, - ActionCosts::transfer, - ) - } -} - -fn max_evm_gas_from_near_gas( - near_gas: Gas, - evm_gas_config: &EvmCostConfig, - method: &Method, - decoded_code_size: Option, -) -> Option { - match method { - Method::DeployCode => { - if near_gas < evm_gas_config.bootstrap_cost { - return None; - } - Some( - ((near_gas - - evm_gas_config.bootstrap_cost - - evm_gas_config.deploy_cost_per_byte - * (2 * decoded_code_size.unwrap() as u64)) - / evm_gas_config.deploy_cost_per_evm_gas) - .into(), - ) - } - Method::Call | Method::ViewCall | Method::MetaCall => { - if near_gas < evm_gas_config.bootstrap_cost + evm_gas_config.funcall_cost_base { - return None; - } - Some( - ((near_gas - evm_gas_config.bootstrap_cost - evm_gas_config.funcall_cost_base) - / evm_gas_config.funcall_cost_per_evm_gas) - .into(), - ) - } - _ => { - if near_gas < evm_gas_config.bootstrap_cost { - return None; - } - Some(evm_gas_config.bootstrap_cost.into()) - } - } -} - -pub fn run_evm( - ext: &mut dyn External, - chain_id: u128, - config: &VMConfig, - fees_config: &RuntimeFeesConfig, - account_id: &AccountId, - signer_id: &AccountId, - predecessor_id: &AccountId, - amount: Balance, - attached_deposit: Balance, - storage_usage: StorageUsage, - method_name: String, - args: Vec, - prepaid_gas: Gas, - is_view: bool, -) -> (Option, Option) { - let method = match Method::parse(&method_name) { - Some(method) => method, - None => { - return ( - None, - Some(VMError::FunctionCallError(FunctionCallError::EvmError( - EvmError::MethodNotFound, - ))), - ); - } - }; - - let evm_gas_result = max_evm_gas_from_near_gas( - prepaid_gas, - &fees_config.evm_config, - &method, - if method == Method::DeployCode { Some(args.len()) } else { None }, - ); - - if evm_gas_result.is_none() { - return ( - None, - Some(VMError::FunctionCallError(FunctionCallError::EvmError(EvmError::Revert( - b"Not enough gas to run EVM".to_vec(), - )))), - ); - } - let evm_gas = evm_gas_result.unwrap(); - let mut context = EvmContext::new( - ext, - chain_id, - config, - fees_config, - // This is total amount of all $NEAR inside this EVM. - // Should already validate that will not overflow external to this call. - amount.checked_add(attached_deposit).unwrap_or(amount), - account_id.clone(), - signer_id.clone(), - predecessor_id.clone(), - attached_deposit, - storage_usage, - prepaid_gas, - is_view, - evm_gas, - ); - - let result = match method { - // Change the state methods. - Method::DeployCode => { - let code_len = args.len(); - context.deploy_code(args).map(|address| { - context.pay_gas_from_evm_gas(EvmOpForGas::Deploy(code_len)).unwrap(); - utils::address_to_vec(&address) - }) - } - Method::Call => { - let r = context.call_function(args.clone()); - context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); - r - } - Method::MetaCall => { - let r = context.meta_call_function(args); - context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); - r - } - Method::Deposit => { - context.deposit(args).map(|balance| utils::u256_to_arr(&balance).to_vec()) - } - Method::Withdraw => context.withdraw(args).map(|_| vec![]), - Method::Transfer => context.transfer(args).map(|_| vec![]), - // TODO: Disable creation of new `evm` accounts. - Method::Create => context.create_evm(args).map(|_| vec![]), - // View methods. - Method::ViewCall => { - let r = context.view_call_function(args); - context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); - r - } - Method::GetCode => context.get_code(args), - Method::GetStorageAt => context.get_storage_at(args), - Method::GetNonce => { - context.get_nonce(args).map(|nonce| utils::u256_to_arr(&nonce).to_vec()) - } - Method::GetBalance => { - context.get_balance(args).map(|balance| utils::u256_to_arr(&balance).to_vec()) - } - }; - - match result { - Ok(value) => { - let outcome = VMOutcome { - balance: context.current_amount, - storage_usage: context.storage_usage, - return_data: ReturnData::Value(value), - burnt_gas: context.gas_counter.burnt_gas(), - used_gas: context.gas_counter.used_gas(), - logs: context.logs, - }; - (Some(outcome), None) - } - Err(VMLogicError::EvmError(err)) => { - (None, Some(VMError::FunctionCallError(FunctionCallError::EvmError(err)))) - } - Err(VMLogicError::InconsistentStateError(err)) => { - (None, Some(VMError::InconsistentStateError(err))) - } - Err(_) => { - (None, Some(VMError::FunctionCallError(FunctionCallError::EvmError(EvmError::Unknown)))) - } - } -} - -#[cfg(test)] -mod tests { - use near_vm_logic::mocks::mock_external::MockedExternal; - - use crate::evm_state::SubState; - - use super::*; - - const CHAIN_ID: u128 = 0x99; - - fn setup() -> (MockedExternal, VMConfig, RuntimeFeesConfig) { - let vm_config = VMConfig::default(); - let fees_config = RuntimeFeesConfig::default(); - let fake_external = MockedExternal::new(); - (fake_external, vm_config, fees_config) - } - - fn create_context<'a>( - external: &'a mut MockedExternal, - vm_config: &'a VMConfig, - fees_config: &'a RuntimeFeesConfig, - account_id: &str, - ) -> EvmContext<'a> { - EvmContext::new( - external, - CHAIN_ID, - vm_config, - fees_config, - 0, - "evm".to_string(), - account_id.to_string(), - account_id.to_string(), - 0, - 0, - 0, - false, - 1_000_000_000.into(), - ) - } - - #[test] - fn state_management() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = create_context(&mut fake_external, &vm_config, &fees_config, "alice"); - let addr_0 = Address::repeat_byte(0); - let addr_1 = Address::repeat_byte(1); - let addr_2 = Address::repeat_byte(2); - - let zero = U256::zero(); - let code: [u8; 3] = [0, 1, 2]; - let nonce = U256::from_dec_str("103030303").unwrap(); - let balance = U256::from_dec_str("3838209").unwrap(); - let storage_key_0 = [4u8; 32]; - let storage_key_1 = [5u8; 32]; - let storage_value_0 = [6u8; 32]; - let storage_value_1 = [7u8; 32]; - - context.set_code(&addr_0, &code).unwrap(); - assert_eq!(context.code_at(&addr_0).unwrap(), Some(code.to_vec())); - assert_eq!(context.code_at(&addr_1).unwrap(), None); - assert_eq!(context.code_at(&addr_2).unwrap(), None); - - context.set_nonce(&addr_0, nonce).unwrap(); - assert_eq!(context.nonce_of(&addr_0).unwrap(), nonce); - assert_eq!(context.nonce_of(&addr_1).unwrap(), zero); - assert_eq!(context.nonce_of(&addr_2).unwrap(), zero); - - context.set_balance(&addr_0, balance).unwrap(); - assert_eq!(context.balance_of(&addr_0).unwrap(), balance); - assert_eq!(context.balance_of(&addr_1).unwrap(), zero); - assert_eq!(context.balance_of(&addr_2).unwrap(), zero); - - context.set_contract_storage(&addr_0, &storage_key_0, storage_value_0).unwrap(); - assert_eq!( - context.read_contract_storage(&addr_0, &storage_key_0).unwrap(), - Some(storage_value_0) - ); - assert_eq!(context.read_contract_storage(&addr_1, &storage_key_0).unwrap(), None); - assert_eq!(context.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); - - let next = { - // Open a new store - let mut next = StateStore::default(); - let mut sub1 = SubState::new(&addr_0, &mut next, &context); - - sub1.set_code(&addr_1, &code).unwrap(); - assert_eq!(sub1.code_at(&addr_0).unwrap(), Some(code.to_vec())); - assert_eq!(sub1.code_at(&addr_1).unwrap(), Some(code.to_vec())); - assert_eq!(sub1.code_at(&addr_2).unwrap(), None); - - sub1.set_nonce(&addr_1, nonce).unwrap(); - assert_eq!(sub1.nonce_of(&addr_0).unwrap(), nonce); - assert_eq!(sub1.nonce_of(&addr_1).unwrap(), nonce); - assert_eq!(sub1.nonce_of(&addr_2).unwrap(), zero); - - sub1.set_balance(&addr_1, balance).unwrap(); - assert_eq!(sub1.balance_of(&addr_0).unwrap(), balance); - assert_eq!(sub1.balance_of(&addr_1).unwrap(), balance); - assert_eq!(sub1.balance_of(&addr_2).unwrap(), zero); - - sub1.set_contract_storage(&addr_1, &storage_key_0, storage_value_0).unwrap(); - assert_eq!( - sub1.read_contract_storage(&addr_0, &storage_key_0).unwrap(), - Some(storage_value_0) - ); - assert_eq!( - sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), - Some(storage_value_0) - ); - assert_eq!(sub1.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); - - sub1.set_contract_storage(&addr_1, &storage_key_0, storage_value_1).unwrap(); - assert_eq!( - sub1.read_contract_storage(&addr_0, &storage_key_0).unwrap(), - Some(storage_value_0) - ); - assert_eq!( - sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), - Some(storage_value_1) - ); - assert_eq!(sub1.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); - - sub1.set_contract_storage(&addr_1, &storage_key_1, storage_value_1).unwrap(); - assert_eq!( - sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), - Some(storage_value_1) - ); - assert_eq!( - sub1.read_contract_storage(&addr_1, &storage_key_1).unwrap(), - Some(storage_value_1) - ); - - sub1.set_contract_storage(&addr_1, &storage_key_0, storage_value_0).unwrap(); - assert_eq!( - sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), - Some(storage_value_0) - ); - assert_eq!( - sub1.read_contract_storage(&addr_1, &storage_key_1).unwrap(), - Some(storage_value_1) - ); - - next - }; - - context.commit_changes(&next).unwrap(); - assert_eq!(context.code_at(&addr_0).unwrap(), Some(code.to_vec())); - assert_eq!(context.code_at(&addr_1).unwrap(), Some(code.to_vec())); - assert_eq!(context.code_at(&addr_2).unwrap(), None); - assert_eq!(context.nonce_of(&addr_0).unwrap(), nonce); - assert_eq!(context.nonce_of(&addr_1).unwrap(), nonce); - assert_eq!(context.nonce_of(&addr_2).unwrap(), zero); - assert_eq!(context.balance_of(&addr_0).unwrap(), balance); - assert_eq!(context.balance_of(&addr_1).unwrap(), balance); - assert_eq!(context.balance_of(&addr_2).unwrap(), zero); - assert_eq!( - context.read_contract_storage(&addr_0, &storage_key_0).unwrap(), - Some(storage_value_0) - ); - assert_eq!( - context.read_contract_storage(&addr_1, &storage_key_0).unwrap(), - Some(storage_value_0) - ); - assert_eq!( - context.read_contract_storage(&addr_1, &storage_key_1).unwrap(), - Some(storage_value_1) - ); - assert_eq!(context.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); - } -} +#[cfg(feature = "protocol_feature_evm")] +use runner::*; diff --git a/runtime/near-evm-runner/src/runner.rs b/runtime/near-evm-runner/src/runner.rs new file mode 100644 index 00000000000..15c62d89cdc --- /dev/null +++ b/runtime/near-evm-runner/src/runner.rs @@ -0,0 +1,835 @@ +#[macro_use] +extern crate enum_primitive_derive; + +use borsh::{BorshDeserialize, BorshSerialize}; +use ethereum_types::{Address, H160, U256}; +use evm::CreateContractAddress; +use vm::{ContractCreateResult, MessageCallResult}; + +use near_runtime_fees::{EvmCostConfig, RuntimeFeesConfig}; +use near_runtime_utils::{is_account_id_64_len_hex, is_valid_sub_account_id}; +use near_vm_errors::{EvmError, FunctionCallError, VMError}; +use near_vm_logic::gas_counter::GasCounter; +use near_vm_logic::types::{AccountId, Balance, Gas, ReturnData, StorageUsage}; +use near_vm_logic::{ActionCosts, External, VMConfig, VMLogicError, VMOutcome}; + +use crate::evm_state::{EvmAccount, EvmGasCounter, EvmState, StateStore}; +use crate::types::{ + AddressArg, DataKey, FunctionCallArgs, GetStorageAtArgs, Method, RawU256, Result, TransferArgs, + ViewCallArgs, WithdrawArgs, +}; +use crate::utils::{combine_data_key, near_erc721_domain, parse_meta_call}; +use near_vm_errors::InconsistentStateError::StorageError; + +pub struct EvmContext<'a> { + ext: &'a mut dyn External, + account_id: AccountId, + signer_id: AccountId, + predecessor_id: AccountId, + current_amount: Balance, + pub attached_deposit: Balance, + storage_usage: StorageUsage, + pub logs: Vec, + gas_counter: GasCounter, + pub evm_gas_counter: EvmGasCounter, + fees_config: &'a RuntimeFeesConfig, + chain_id: u128, + domain_separator: RawU256, +} + +// Different kind of evm operations that result in different gas calculation +pub enum EvmOpForGas { + // size of deployed evm contract after it's decoded from hex (0.5x) + Deploy(usize), + Funcall, + Other, +} + +enum KeyPrefix { + Account = 0, + Contract = 1, +} + +fn address_to_key(prefix: KeyPrefix, address: &H160) -> [u8; 21] { + let mut result = [0u8; 21]; + result[0] = prefix as u8; + result[1..].copy_from_slice(&address.0); + result +} + +impl<'a> EvmState for EvmContext<'a> { + fn code_at(&self, address: &H160) -> Result>> { + self.ext + .storage_get(&address_to_key(KeyPrefix::Contract, address)) + .map(|value| value.map(|x| x.deref().expect("Failed to deref"))) + } + + fn set_code(&mut self, address: &H160, bytecode: &[u8]) -> Result<()> { + self.ext.storage_set(&address_to_key(KeyPrefix::Contract, address), bytecode) + } + + fn get_account(&self, address: &Address) -> Result> { + match self.ext.storage_get(&address_to_key(KeyPrefix::Account, address)).map(|value| { + value.map(|x| EvmAccount::try_from_slice(&x.deref().expect("Failed to deref"))) + }) { + Ok(Some(Ok(value))) => Ok(Some(value)), + Ok(None) => Ok(None), + Ok(Some(Err(_))) => Err(VMLogicError::InconsistentStateError(StorageError( + "Failed to deserialize".to_string(), + ))), + Err(e) => Err(e), + } + } + + fn set_account(&mut self, address: &Address, account: &EvmAccount) -> Result<()> { + self.ext.storage_set( + &address_to_key(KeyPrefix::Account, address), + &account.try_to_vec().expect("Failed to serialize"), + ) + } + + fn _read_contract_storage(&self, key: &DataKey) -> Result> { + match self + .ext + .storage_get(key) + .map(|value| value.map(|x| utils::vec_to_arr_32(x.deref().expect("Failed to deref")))) + { + Ok(Some(Some(value))) => Ok(Some(value)), + Ok(Some(None)) => Err(VMLogicError::InconsistentStateError(StorageError( + "Must be 32 bytes".to_string(), + ))), + Ok(None) => Ok(None), + Err(err) => Err(err), + } + } + + fn _set_contract_storage(&mut self, key: &DataKey, value: RawU256) -> Result<()> { + self.ext.storage_set(key, &value) + } + + fn commit_changes(&mut self, other: &StateStore) -> Result<()> { + for address in other.self_destructs.iter() { + self.clear_contract_info(address)?; + } + for address in other.recreated.iter() { + self.clear_contract_info(address)?; + } + for (address, code) in other.code.iter() { + self.set_code(address, code)?; + } + for (address, account) in other.accounts.iter() { + self.set_account(address, account)?; + } + for (address, values) in other.storages.iter() { + for (key, value) in values.iter() { + let key = combine_data_key(address, key); + self._set_contract_storage(&key, *value)?; + } + } + self.logs.extend_from_slice(&other.logs); + Ok(()) + } + + fn recreate(&mut self, _address: Address) { + unreachable!() + } +} + +impl<'a> EvmContext<'a> { + pub fn new( + ext: &'a mut dyn External, + chain_id: u128, + config: &'a VMConfig, + fees_config: &'a RuntimeFeesConfig, + current_amount: Balance, + account_id: AccountId, + signer_id: AccountId, + predecessor_id: AccountId, + attached_deposit: Balance, + storage_usage: StorageUsage, + prepaid_gas: Gas, + is_view: bool, + evm_gas: U256, + ) -> Self { + let max_gas_burnt = if is_view { + config.limit_config.max_gas_burnt_view + } else { + config.limit_config.max_gas_burnt + }; + // TODO: pass chain id from ??? genesis / config. + let domain_separator = near_erc721_domain(U256::from(chain_id)); + Self { + ext, + account_id, + signer_id, + predecessor_id, + current_amount, + attached_deposit, + storage_usage, + logs: Vec::default(), + gas_counter: GasCounter::new( + config.ext_costs.clone(), + max_gas_burnt, + prepaid_gas, + is_view, + None, + ), + evm_gas_counter: EvmGasCounter::new(0.into(), evm_gas), + fees_config, + chain_id, + domain_separator, + } + } + + fn clear_contract_info(&mut self, other: &Address) -> Result<()> { + self.ext.storage_remove_subtree(&other.0) + } + + pub fn deploy_code(&mut self, bytecode: Vec) -> Result
{ + let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); + self.add_balance(&sender, U256::from(self.attached_deposit))?; + match interpreter::deploy_code( + self, + &sender, + &sender, + U256::from(self.attached_deposit), + 0, + CreateContractAddress::FromSenderAndNonce, + false, + &bytecode, + &self.evm_gas_counter.gas_left(), + &self.fees_config.evm_config, + self.chain_id, + )? { + ContractCreateResult::Created(address, gas_left) => { + self.evm_gas_counter.set_gas_left(gas_left); + Ok(address) + } + ContractCreateResult::Reverted(gas_left, return_data) => { + self.evm_gas_counter.set_gas_left(gas_left); + Err(VMLogicError::EvmError(EvmError::DeployFail(return_data.to_vec()))) + } + _ => unreachable!(), + } + } + + /// Make an EVM transaction. Calls `contract_address` with RLP encoded `input`. Execution + /// continues until all EVM messages have been processed. We expect this to behave identically + /// to an Ethereum transaction, however there may be some edge cases. + pub fn call_function(&mut self, args: Vec) -> Result> { + let args = FunctionCallArgs::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + let contract_address = Address::from(&args.contract); + let input = args.input; + let _origin = utils::near_account_id_to_evm_address(&self.signer_id); + let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); + self.add_balance(&sender, U256::from(self.attached_deposit))?; + let value = + if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; + let result = interpreter::call( + self, + &sender, + &sender, + value, + 0, + &contract_address, + &input, + true, + &self.evm_gas_counter.gas_left(), + &self.fees_config.evm_config, + self.chain_id, + )?; + self.process_call_result(result) + } + + /// Make an EVM call via a meta transaction pattern. + /// Specifically, providing signature and NEAREvm message that determines which contract and arguments to be called. + /// See `parse_meta_call` for arguments format. + pub fn meta_call_function(&mut self, args: Vec) -> Result> { + let meta_call_args = parse_meta_call(&self.domain_separator, &self.account_id, args)?; + if self.next_nonce(&meta_call_args.sender)? != meta_call_args.nonce { + return Err(VMLogicError::EvmError(EvmError::InvalidNonce)); + } + self.add_balance(&meta_call_args.sender, U256::from(self.attached_deposit))?; + let value = + if self.attached_deposit == 0 { None } else { Some(U256::from(self.attached_deposit)) }; + let result = interpreter::call( + self, + &meta_call_args.sender, + &meta_call_args.sender, + value, + 0, + &meta_call_args.contract_address, + &meta_call_args.input, + true, + &self.evm_gas_counter.gas_left(), + &self.fees_config.evm_config, + self.chain_id, + )?; + self.process_call_result(result) + } + + /// Make an EVM transaction. Calls `contract_address` with `encoded_input`. Execution + /// continues until all EVM messages have been processed. We expect this to behave identically + /// to an Ethereum transaction, however there may be some edge cases. + /// + /// This function serves the eth_call functionality, and will NOT apply state changes. + pub fn view_call_function(&mut self, args: Vec) -> Result> { + let args = ViewCallArgs::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + let sender = Address::from(&args.sender); + let attached_amount = U256::from(args.amount); + self.add_balance(&sender, attached_amount)?; + // TODO: Verify we don't keep the balance in case `call` returns `Err` + let result = interpreter::call( + self, + &sender, + &sender, + Some(attached_amount), + 0, + &Address::from(&args.address), + &args.input, + false, + &self.evm_gas_counter.gas_left(), + &self.fees_config.evm_config, + self.chain_id, + )?; + let result = self.process_call_result(result); + // Need to subtract amount back, because if view call is called inside the transaction state will be applied. + // The interpreter call is not committing changes, but `add_balance` did, so need to revert that. + self.sub_balance(&sender, attached_amount)?; + result + } + + /// Processes `MessageCallResult` and charges gas. + fn process_call_result(&mut self, result: MessageCallResult) -> Result> { + match result { + MessageCallResult::Success(gas_left, data) => { + self.evm_gas_counter.set_gas_left(gas_left); + Ok(data.to_vec()) + } + MessageCallResult::Reverted(gas_left, data) => { + self.evm_gas_counter.set_gas_left(gas_left); + Err(VMLogicError::EvmError(EvmError::Revert(data.to_vec()))) + } + _ => unreachable!(), + } + } + + pub fn get_code(&self, args: Vec) -> Result> { + let args = AddressArg::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + Ok(self + .code_at(&Address::from_slice(&args.address)) + .unwrap_or(None) + .unwrap_or_else(Vec::new)) + } + + pub fn get_storage_at(&self, args: Vec) -> Result> { + let args = GetStorageAtArgs::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + Ok(self + .read_contract_storage(&Address::from_slice(&args.address), &args.key)? + .unwrap_or([0u8; 32]) + .to_vec()) + } + + pub fn get_balance(&self, args: Vec) -> Result { + let args = AddressArg::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + self.balance_of(&Address::from_slice(&args.address)) + } + + pub fn get_nonce(&self, args: Vec) -> Result { + let args = AddressArg::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + self.nonce_of(&Address::from_slice(&args.address)) + } + + pub fn deposit(&mut self, args: Vec) -> Result { + let args = AddressArg::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + if self.attached_deposit == 0 { + return Err(VMLogicError::EvmError(EvmError::MissingDeposit)); + } + let address = Address::from_slice(&args.address); + self.add_balance(&address, U256::from(self.attached_deposit))?; + self.balance_of(&address) + } + + pub fn withdraw(&mut self, args: Vec) -> Result<()> { + let args = WithdrawArgs::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + if args.account_id == self.account_id { + return Err(VMLogicError::EvmError(EvmError::FailSelfWithdraw)); + } + let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); + let amount = U256::from(args.amount); + if amount > self.balance_of(&sender)? { + return Err(VMLogicError::EvmError(EvmError::InsufficientFunds)); + } + self.sub_balance(&sender, amount)?; + let receipt_index = self.ext.create_receipt(vec![], args.account_id.clone())?; + // We use low_u128, because NEAR native currency fits into u128. + let amount = amount.low_u128(); + self.current_amount = self + .current_amount + .checked_sub(amount) + .ok_or_else(|| VMLogicError::EvmError(EvmError::InsufficientFunds))?; + self.pay_gas_for_new_receipt(false, &[])?; + self.pay_gas_for_transfer(&args.account_id)?; + self.ext.append_action_transfer(receipt_index, amount) + } + + /// Transfer tokens from sender to given EVM address. + pub fn transfer(&mut self, args: Vec) -> Result<()> { + let args = TransferArgs::try_from_slice(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))?; + let sender = utils::near_account_id_to_evm_address(&self.predecessor_id); + let amount = U256::from(args.amount); + if amount > self.balance_of(&sender)? { + return Err(VMLogicError::EvmError(EvmError::InsufficientFunds)); + } + self.transfer_balance(&sender, &Address::from(args.address), amount) + } + + /// Creates new EVM under given sub account and sends attached balance to it. + /// If account id given is not a valid subaccount of the current account, will return InvalidSubAccount. + /// If balance attached was not enough, will return InsufficientDeposit. + pub fn create_evm(&mut self, args: Vec) -> Result<()> { + let new_account_id = std::str::from_utf8(&args) + .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))? + .to_string(); + if !is_valid_sub_account_id(&self.account_id, &new_account_id) { + return Err(VMLogicError::EvmError(EvmError::InvalidSubAccount)); + } + if self.attached_deposit < self.fees_config.evm_deposit { + return Err(VMLogicError::EvmError(EvmError::InsufficientDeposit)); + } + self.current_amount = self + .current_amount + .checked_sub(self.attached_deposit) + .ok_or_else(|| VMLogicError::EvmError(EvmError::InsufficientFunds))?; + let receipt_index = self.ext.create_receipt(vec![], new_account_id.clone())?; + self.pay_gas_for_new_receipt(false, &[])?; + self.gas_counter.pay_action_base( + &self.fees_config.action_creation_config.create_account_cost, + false, + ActionCosts::create_account, + )?; + self.ext.append_action_create_account(receipt_index)?; + self.pay_gas_for_transfer(&new_account_id)?; + self.ext.append_action_transfer(receipt_index, self.attached_deposit) + } + + /// A helper function to pay gas fee for creating a new receipt without actions. + /// # Args: + /// * `sir`: whether contract call is addressed to itself; + /// * `data_dependencies`: other contracts that this execution will be waiting on (or rather + /// their data receipts), where bool indicates whether this is sender=receiver communication. + /// + /// # Cost + /// + /// This is a convenience function that encapsulates several costs: + /// `burnt_gas := dispatch cost of the receipt + base dispatch cost cost of the data receipt` + /// `used_gas := burnt_gas + exec cost of the receipt + base exec cost cost of the data receipt` + /// Notice that we prepay all base cost upon the creation of the data dependency, we are going to + /// pay for the content transmitted through the dependency upon the actual creation of the + /// DataReceipt. + fn pay_gas_for_new_receipt(&mut self, sir: bool, data_dependencies: &[bool]) -> Result<()> { + let fees_config_cfg = &self.fees_config; + let mut burn_gas = fees_config_cfg.action_receipt_creation_config.send_fee(sir); + let mut use_gas = fees_config_cfg.action_receipt_creation_config.exec_fee(); + for dep in data_dependencies { + // Both creation and execution for data receipts are considered burnt gas. + burn_gas = burn_gas + .checked_add(fees_config_cfg.data_receipt_creation_config.base_cost.send_fee(*dep)) + .ok_or(VMLogicError::EvmError(EvmError::IntegerOverflow))? + .checked_add(fees_config_cfg.data_receipt_creation_config.base_cost.exec_fee()) + .ok_or(VMLogicError::EvmError(EvmError::IntegerOverflow))?; + } + use_gas = use_gas + .checked_add(burn_gas) + .ok_or(VMLogicError::EvmError(EvmError::IntegerOverflow))?; + self.gas_counter.pay_action_accumulated(burn_gas, use_gas, ActionCosts::new_receipt) + } + + fn pay_gas_from_evm_gas(&mut self, op: EvmOpForGas) -> Result<()> { + let fee_cfg = &self.fees_config.evm_config; + let evm_gas = self.evm_gas_counter.used_gas.as_u64(); + self.gas_counter.inc_evm_gas_counter(evm_gas); + let gas = match op { + EvmOpForGas::Deploy(decoded_len) => { + // gas per byte is counting hex encoded contract size (solc output, 2x of decoded len) + (decoded_len as u64 * 2) * fee_cfg.deploy_cost_per_byte + + evm_gas * fee_cfg.deploy_cost_per_evm_gas + + fee_cfg.bootstrap_cost + } + EvmOpForGas::Funcall => { + evm_gas * fee_cfg.funcall_cost_per_evm_gas + + fee_cfg.funcall_cost_base + + fee_cfg.bootstrap_cost + } + EvmOpForGas::Other => fee_cfg.bootstrap_cost, + }; + self.gas_counter.pay_evm_gas(gas) + } + + fn pay_gas_for_transfer(&mut self, account_id: &AccountId) -> Result<()> { + if is_account_id_64_len_hex(&account_id) { + self.gas_counter.pay_action_base( + &self.fees_config.action_creation_config.create_account_cost, + false, + ActionCosts::transfer, + )?; + self.gas_counter.pay_action_base( + &self.fees_config.action_creation_config.add_key_cost.full_access_cost, + false, + ActionCosts::transfer, + )?; + } + self.gas_counter.pay_action_base( + &self.fees_config.action_creation_config.transfer_cost, + false, + ActionCosts::transfer, + ) + } +} + +fn max_evm_gas_from_near_gas( + near_gas: Gas, + evm_gas_config: &EvmCostConfig, + method: &Method, + decoded_code_size: Option, +) -> Option { + match method { + Method::DeployCode => { + if near_gas < evm_gas_config.bootstrap_cost { + return None; + } + Some( + ((near_gas + - evm_gas_config.bootstrap_cost + - evm_gas_config.deploy_cost_per_byte + * (2 * decoded_code_size.unwrap() as u64)) + / evm_gas_config.deploy_cost_per_evm_gas) + .into(), + ) + } + Method::Call | Method::ViewCall | Method::MetaCall => { + if near_gas < evm_gas_config.bootstrap_cost + evm_gas_config.funcall_cost_base { + return None; + } + Some( + ((near_gas - evm_gas_config.bootstrap_cost - evm_gas_config.funcall_cost_base) + / evm_gas_config.funcall_cost_per_evm_gas) + .into(), + ) + } + _ => { + if near_gas < evm_gas_config.bootstrap_cost { + return None; + } + Some(evm_gas_config.bootstrap_cost.into()) + } + } +} + +pub fn run_evm( + ext: &mut dyn External, + chain_id: u128, + config: &VMConfig, + fees_config: &RuntimeFeesConfig, + account_id: &AccountId, + signer_id: &AccountId, + predecessor_id: &AccountId, + amount: Balance, + attached_deposit: Balance, + storage_usage: StorageUsage, + method_name: String, + args: Vec, + prepaid_gas: Gas, + is_view: bool, +) -> (Option, Option) { + let method = match Method::parse(&method_name) { + Some(method) => method, + None => { + return ( + None, + Some(VMError::FunctionCallError(FunctionCallError::EvmError( + EvmError::MethodNotFound, + ))), + ); + } + }; + + let evm_gas_result = max_evm_gas_from_near_gas( + prepaid_gas, + &fees_config.evm_config, + &method, + if method == Method::DeployCode { Some(args.len()) } else { None }, + ); + + if evm_gas_result.is_none() { + return ( + None, + Some(VMError::FunctionCallError(FunctionCallError::EvmError(EvmError::Revert( + b"Not enough gas to run EVM".to_vec(), + )))), + ); + } + let evm_gas = evm_gas_result.unwrap(); + let mut context = EvmContext::new( + ext, + chain_id, + config, + fees_config, + // This is total amount of all $NEAR inside this EVM. + // Should already validate that will not overflow external to this call. + amount.checked_add(attached_deposit).unwrap_or(amount), + account_id.clone(), + signer_id.clone(), + predecessor_id.clone(), + attached_deposit, + storage_usage, + prepaid_gas, + is_view, + evm_gas, + ); + + let result = match method { + // Change the state methods. + Method::DeployCode => { + let code_len = args.len(); + context.deploy_code(args).map(|address| { + context.pay_gas_from_evm_gas(EvmOpForGas::Deploy(code_len)).unwrap(); + utils::address_to_vec(&address) + }) + } + Method::Call => { + let r = context.call_function(args.clone()); + context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); + r + } + Method::MetaCall => { + let r = context.meta_call_function(args); + context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); + r + } + Method::Deposit => { + context.deposit(args).map(|balance| utils::u256_to_arr(&balance).to_vec()) + } + Method::Withdraw => context.withdraw(args).map(|_| vec![]), + Method::Transfer => context.transfer(args).map(|_| vec![]), + // TODO: Disable creation of new `evm` accounts. + Method::Create => context.create_evm(args).map(|_| vec![]), + // View methods. + Method::ViewCall => { + let r = context.view_call_function(args); + context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); + r + } + Method::GetCode => context.get_code(args), + Method::GetStorageAt => context.get_storage_at(args), + Method::GetNonce => { + context.get_nonce(args).map(|nonce| utils::u256_to_arr(&nonce).to_vec()) + } + Method::GetBalance => { + context.get_balance(args).map(|balance| utils::u256_to_arr(&balance).to_vec()) + } + }; + + match result { + Ok(value) => { + let outcome = VMOutcome { + balance: context.current_amount, + storage_usage: context.storage_usage, + return_data: ReturnData::Value(value), + burnt_gas: context.gas_counter.burnt_gas(), + used_gas: context.gas_counter.used_gas(), + logs: context.logs, + }; + (Some(outcome), None) + } + Err(VMLogicError::EvmError(err)) => { + (None, Some(VMError::FunctionCallError(FunctionCallError::EvmError(err)))) + } + Err(VMLogicError::InconsistentStateError(err)) => { + (None, Some(VMError::InconsistentStateError(err))) + } + Err(_) => { + (None, Some(VMError::FunctionCallError(FunctionCallError::EvmError(EvmError::Unknown)))) + } + } +} + +#[cfg(test)] +mod tests { + use near_vm_logic::mocks::mock_external::MockedExternal; + + use crate::evm_state::SubState; + + use super::*; + + const CHAIN_ID: u128 = 0x99; + + fn setup() -> (MockedExternal, VMConfig, RuntimeFeesConfig) { + let vm_config = VMConfig::default(); + let fees_config = RuntimeFeesConfig::default(); + let fake_external = MockedExternal::new(); + (fake_external, vm_config, fees_config) + } + + fn create_context<'a>( + external: &'a mut MockedExternal, + vm_config: &'a VMConfig, + fees_config: &'a RuntimeFeesConfig, + account_id: &str, + ) -> EvmContext<'a> { + EvmContext::new( + external, + CHAIN_ID, + vm_config, + fees_config, + 0, + "evm".to_string(), + account_id.to_string(), + account_id.to_string(), + 0, + 0, + 0, + false, + 1_000_000_000.into(), + ) + } + + #[test] + fn state_management() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, "alice"); + let addr_0 = Address::repeat_byte(0); + let addr_1 = Address::repeat_byte(1); + let addr_2 = Address::repeat_byte(2); + + let zero = U256::zero(); + let code: [u8; 3] = [0, 1, 2]; + let nonce = U256::from_dec_str("103030303").unwrap(); + let balance = U256::from_dec_str("3838209").unwrap(); + let storage_key_0 = [4u8; 32]; + let storage_key_1 = [5u8; 32]; + let storage_value_0 = [6u8; 32]; + let storage_value_1 = [7u8; 32]; + + context.set_code(&addr_0, &code).unwrap(); + assert_eq!(context.code_at(&addr_0).unwrap(), Some(code.to_vec())); + assert_eq!(context.code_at(&addr_1).unwrap(), None); + assert_eq!(context.code_at(&addr_2).unwrap(), None); + + context.set_nonce(&addr_0, nonce).unwrap(); + assert_eq!(context.nonce_of(&addr_0).unwrap(), nonce); + assert_eq!(context.nonce_of(&addr_1).unwrap(), zero); + assert_eq!(context.nonce_of(&addr_2).unwrap(), zero); + + context.set_balance(&addr_0, balance).unwrap(); + assert_eq!(context.balance_of(&addr_0).unwrap(), balance); + assert_eq!(context.balance_of(&addr_1).unwrap(), zero); + assert_eq!(context.balance_of(&addr_2).unwrap(), zero); + + context.set_contract_storage(&addr_0, &storage_key_0, storage_value_0).unwrap(); + assert_eq!( + context.read_contract_storage(&addr_0, &storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!(context.read_contract_storage(&addr_1, &storage_key_0).unwrap(), None); + assert_eq!(context.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); + + let next = { + // Open a new store + let mut next = StateStore::default(); + let mut sub1 = SubState::new(&addr_0, &mut next, &context); + + sub1.set_code(&addr_1, &code).unwrap(); + assert_eq!(sub1.code_at(&addr_0).unwrap(), Some(code.to_vec())); + assert_eq!(sub1.code_at(&addr_1).unwrap(), Some(code.to_vec())); + assert_eq!(sub1.code_at(&addr_2).unwrap(), None); + + sub1.set_nonce(&addr_1, nonce).unwrap(); + assert_eq!(sub1.nonce_of(&addr_0).unwrap(), nonce); + assert_eq!(sub1.nonce_of(&addr_1).unwrap(), nonce); + assert_eq!(sub1.nonce_of(&addr_2).unwrap(), zero); + + sub1.set_balance(&addr_1, balance).unwrap(); + assert_eq!(sub1.balance_of(&addr_0).unwrap(), balance); + assert_eq!(sub1.balance_of(&addr_1).unwrap(), balance); + assert_eq!(sub1.balance_of(&addr_2).unwrap(), zero); + + sub1.set_contract_storage(&addr_1, &storage_key_0, storage_value_0).unwrap(); + assert_eq!( + sub1.read_contract_storage(&addr_0, &storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!(sub1.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); + + sub1.set_contract_storage(&addr_1, &storage_key_0, storage_value_1).unwrap(); + assert_eq!( + sub1.read_contract_storage(&addr_0, &storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), + Some(storage_value_1) + ); + assert_eq!(sub1.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); + + sub1.set_contract_storage(&addr_1, &storage_key_1, storage_value_1).unwrap(); + assert_eq!( + sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), + Some(storage_value_1) + ); + assert_eq!( + sub1.read_contract_storage(&addr_1, &storage_key_1).unwrap(), + Some(storage_value_1) + ); + + sub1.set_contract_storage(&addr_1, &storage_key_0, storage_value_0).unwrap(); + assert_eq!( + sub1.read_contract_storage(&addr_1, &storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + sub1.read_contract_storage(&addr_1, &storage_key_1).unwrap(), + Some(storage_value_1) + ); + + next + }; + + context.commit_changes(&next).unwrap(); + assert_eq!(context.code_at(&addr_0).unwrap(), Some(code.to_vec())); + assert_eq!(context.code_at(&addr_1).unwrap(), Some(code.to_vec())); + assert_eq!(context.code_at(&addr_2).unwrap(), None); + assert_eq!(context.nonce_of(&addr_0).unwrap(), nonce); + assert_eq!(context.nonce_of(&addr_1).unwrap(), nonce); + assert_eq!(context.nonce_of(&addr_2).unwrap(), zero); + assert_eq!(context.balance_of(&addr_0).unwrap(), balance); + assert_eq!(context.balance_of(&addr_1).unwrap(), balance); + assert_eq!(context.balance_of(&addr_2).unwrap(), zero); + assert_eq!( + context.read_contract_storage(&addr_0, &storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + context.read_contract_storage(&addr_1, &storage_key_0).unwrap(), + Some(storage_value_0) + ); + assert_eq!( + context.read_contract_storage(&addr_1, &storage_key_1).unwrap(), + Some(storage_value_1) + ); + assert_eq!(context.read_contract_storage(&addr_2, &storage_key_0).unwrap(), None); + } +} diff --git a/runtime/near-evm-runner/tests/failures.rs b/runtime/near-evm-runner/tests/failures.rs index 9905fb37758..de8faaf8975 100644 --- a/runtime/near-evm-runner/tests/failures.rs +++ b/runtime/near-evm-runner/tests/failures.rs @@ -1,33 +1,40 @@ -use crate::utils::{accounts, create_context, setup}; +#[cfg(feature = "protocol_feature_evm")] +#[cfg(tests)] +mod tests { + use crate::utils::{accounts, create_context, setup}; -mod utils; + mod utils; -/// Test various invalid inputs to function calls. -#[test] -fn test_invalid_input() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 10); - assert!(context.get_nonce(vec![]).is_err()); - assert!(context.get_balance(vec![]).is_err()); - assert!(context.get_code(vec![]).is_err()); - assert!(context.get_storage_at(vec![]).is_err()); - assert!(context.view_call_function(vec![]).is_err()); - assert!(context.view_call_function(vec![0u8; 20]).is_err()); - assert!(context.call_function(vec![]).is_err()); - assert!(context.call_function(vec![0u8; 20]).is_err()); - assert!(context.deposit(vec![]).is_err()); - assert!(context.withdraw(vec![]).is_err()); - assert!(context.transfer(vec![]).is_err()); -} + /// Test various invalid inputs to function calls. + #[test] + fn test_invalid_input() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 10); + assert!(context.get_nonce(vec![]).is_err()); + assert!(context.get_balance(vec![]).is_err()); + assert!(context.get_code(vec![]).is_err()); + assert!(context.get_storage_at(vec![]).is_err()); + assert!(context.view_call_function(vec![]).is_err()); + assert!(context.view_call_function(vec![0u8; 20]).is_err()); + assert!(context.call_function(vec![]).is_err()); + assert!(context.call_function(vec![0u8; 20]).is_err()); + assert!(context.deposit(vec![]).is_err()); + assert!(context.withdraw(vec![]).is_err()); + assert!(context.transfer(vec![]).is_err()); + } -#[test] -fn test_invalid_view_args() { - let args = vec![vec![1u8; 20], vec![2u8; 20], vec![0u8; 32], vec![1u8, 0u8, 0u8, 0u8], vec![1]] - .concat(); - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - assert_eq!( - context.view_call_function(args).unwrap_err().to_string(), - "EvmError(ContractNotFound)" - ); + #[test] + fn test_invalid_view_args() { + let args = + vec![vec![1u8; 20], vec![2u8; 20], vec![0u8; 32], vec![1u8, 0u8, 0u8, 0u8], vec![1]] + .concat(); + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + assert_eq!( + context.view_call_function(args).unwrap_err().to_string(), + "EvmError(ContractNotFound)" + ); + } } diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 32cb8a07a89..69d0e0d5d20 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -1,309 +1,330 @@ -#[macro_use] -extern crate lazy_static_include; - -use borsh::BorshSerialize; -use ethabi_contract::use_contract; -use ethereum_types::{Address, H256, U256}; - -use near_crypto::{InMemorySigner, KeyType}; -use near_evm_runner::types::{TransferArgs, WithdrawArgs}; -use near_evm_runner::utils::{ - address_from_arr, address_to_vec, encode_call_function_args, encode_view_call_function_args, - near_account_id_to_evm_address, near_erc721_domain, parse_meta_call, u256_to_arr, -}; -use near_runtime_fees::RuntimeFeesConfig; -use near_vm_errors::{EvmError, VMLogicError}; -use near_vm_logic::mocks::mock_external::MockedExternal; -use near_vm_logic::VMConfig; - -use crate::utils::{ - accounts, create_context, encode_meta_call_function_args, public_key_to_address, setup, - CHAIN_ID, -}; -use parity_bytes::ToPretty; - -mod utils; - -use_contract!(soltest, "tests/build/SolTests.abi"); -use_contract!(subcontract, "tests/build/SubContract.abi"); -use_contract!(create2factory, "tests/build/Create2Factory.abi"); -use_contract!(selfdestruct, "tests/build/SelfDestruct.abi"); - -lazy_static_include_str!(TEST, "tests/build/SolTests.bin"); -lazy_static_include_str!(FACTORY_TEST, "tests/build/Create2Factory.bin"); -lazy_static_include_str!(DESTRUCT_TEST, "tests/build/SelfDestruct.bin"); -lazy_static_include_str!(CONSTRUCTOR_TEST, "tests/build/ConstructorRevert.bin"); - -#[test] -fn test_funds_transfers() { - let (mut fake_external, vm_config, fees_config) = setup(); - let context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - assert_eq!( - context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), - U256::from(0) - ); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - assert_eq!( - context.deposit(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), - U256::from(100) - ); - let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - context - .transfer( - TransferArgs { - address: near_account_id_to_evm_address(&accounts(2)).0, - amount: u256_to_arr(&U256::from(50)), - } - .try_to_vec() - .unwrap(), - ) - .unwrap(); - assert_eq!( - context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))).unwrap(), - U256::from(50) - ); - let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(2), 0); - context - .withdraw( - WithdrawArgs { account_id: accounts(2), amount: u256_to_arr(&U256::from(50)) } +#[cfg(feature = "protocol_feature_evm")] +#[cfg(tests)] +mod tests { + #[macro_use] + extern crate lazy_static_include; + + use borsh::BorshSerialize; + use ethabi_contract::use_contract; + use ethereum_types::{Address, H256, U256}; + + use near_crypto::{InMemorySigner, KeyType}; + use near_evm_runner::types::{TransferArgs, WithdrawArgs}; + use near_evm_runner::utils::{ + address_from_arr, address_to_vec, encode_call_function_args, + encode_view_call_function_args, near_account_id_to_evm_address, near_erc721_domain, + parse_meta_call, u256_to_arr, + }; + use near_runtime_fees::RuntimeFeesConfig; + use near_vm_errors::{EvmError, VMLogicError}; + use near_vm_logic::mocks::mock_external::MockedExternal; + use near_vm_logic::VMConfig; + + use crate::utils::{ + accounts, create_context, encode_meta_call_function_args, public_key_to_address, setup, + CHAIN_ID, + }; + use parity_bytes::ToPretty; + + mod utils; + + use_contract!(soltest, "tests/build/SolTests.abi"); + use_contract!(subcontract, "tests/build/SubContract.abi"); + use_contract!(create2factory, "tests/build/Create2Factory.abi"); + use_contract!(selfdestruct, "tests/build/SelfDestruct.abi"); + + lazy_static_include_str!(TEST, "tests/build/SolTests.bin"); + lazy_static_include_str!(FACTORY_TEST, "tests/build/Create2Factory.bin"); + lazy_static_include_str!(DESTRUCT_TEST, "tests/build/SelfDestruct.bin"); + lazy_static_include_str!(CONSTRUCTOR_TEST, "tests/build/ConstructorRevert.bin"); + + #[test] + fn test_funds_transfers() { + let (mut fake_external, vm_config, fees_config) = setup(); + let context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + assert_eq!( + context + .get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))) + .unwrap(), + U256::from(0) + ); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + assert_eq!( + context.deposit(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), + U256::from(100) + ); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + context + .transfer( + TransferArgs { + address: near_account_id_to_evm_address(&accounts(2)).0, + amount: u256_to_arr(&U256::from(50)), + } .try_to_vec() .unwrap(), - ) - .unwrap(); - assert_eq!( - context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))).unwrap(), - U256::from(0) - ); -} - -#[test] -fn test_deploy_with_nonce() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - let address = near_account_id_to_evm_address(&accounts(1)); - assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(0)); - let address1 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); - assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(1)); - let address2 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); - assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(2)); - assert_ne!(address1, address2); -} + ) + .unwrap(); + assert_eq!( + context + .get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))) + .unwrap(), + U256::from(50) + ); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(2), 0); + context + .withdraw( + WithdrawArgs { account_id: accounts(2), amount: u256_to_arr(&U256::from(50)) } + .try_to_vec() + .unwrap(), + ) + .unwrap(); + assert_eq!( + context + .get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))) + .unwrap(), + U256::from(0) + ); + } -#[test] -#[ignore] -fn test_failed_deploy_returns_error() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - if let Err(VMLogicError::EvmError(EvmError::DeployFail(_))) = - context.deploy_code(hex::decode(&CONSTRUCTOR_TEST).unwrap()) - { - } else { - panic!("Should fail"); + #[test] + fn test_deploy_with_nonce() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let address = near_account_id_to_evm_address(&accounts(1)); + assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(0)); + let address1 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(1)); + let address2 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(2)); + assert_ne!(address1, address2); } -} -#[test] -fn test_internal_create() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); - assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); - - // This should increment the nonce of the deploying contract - let (input, _) = soltest::functions::deploy_new_guy::call(8); - let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); - assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(1)); - - let sub_addr = address_from_arr(&raw[12..32]); - let (new_input, _) = subcontract::functions::a_number::call(); - let new_raw = context.call_function(encode_call_function_args(sub_addr, new_input)).unwrap(); - let output = subcontract::functions::a_number::decode_output(&new_raw).unwrap(); - assert_eq!(output, U256::from(8)); -} + #[test] + #[ignore] + fn test_failed_deploy_returns_error() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + if let Err(VMLogicError::EvmError(EvmError::DeployFail(_))) = + context.deploy_code(hex::decode(&CONSTRUCTOR_TEST).unwrap()) + { + } else { + panic!("Should fail"); + } + } -#[test] -fn test_precompiles() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); - - let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - let (input, _) = soltest::functions::precompile_test::call(); - let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); - assert_eq!(raw.len(), 0); -} + #[test] + fn test_internal_create() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); + + // This should increment the nonce of the deploying contract + let (input, _) = soltest::functions::deploy_new_guy::call(8); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(1)); + + let sub_addr = address_from_arr(&raw[12..32]); + let (new_input, _) = subcontract::functions::a_number::call(); + let new_raw = + context.call_function(encode_call_function_args(sub_addr, new_input)).unwrap(); + let output = subcontract::functions::a_number::decode_output(&new_raw).unwrap(); + assert_eq!(output, U256::from(8)); + } -fn setup_and_deploy_test() -> (MockedExternal, Address, VMConfig, RuntimeFeesConfig) { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); - assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); - (fake_external, test_addr, vm_config, fees_config) -} + #[test] + fn test_precompiles() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let (input, _) = soltest::functions::precompile_test::call(); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + assert_eq!(raw.len(), 0); + } -#[test] -fn test_deploy_and_transfer() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - - // This should increment the nonce of the deploying contract. - // There is 100 attached to this that should be passed through. - let (input, _) = soltest::functions::deploy_new_guy::call(8); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); - assert!(context.logs.len() > 0); - - // The sub_addr should have been transferred 100 yoctoN. - let sub_addr = raw[12..32].to_vec(); - assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); - assert_eq!(context.get_balance(sub_addr).unwrap(), U256::from(100)); -} + fn setup_and_deploy_test() -> (MockedExternal, Address, VMConfig, RuntimeFeesConfig) { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); + (fake_external, test_addr, vm_config, fees_config) + } -#[test] -fn test_deploy_with_value() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - - // This should increment the nonce of the deploying contract - // There is 100 attached to this that should be passed through - let (input, _) = soltest::functions::pay_new_guy::call(8); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); - - // The sub_addr should have been transferred 100 tokens. - let sub_addr = raw[12..32].to_vec(); - assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); - assert_eq!(context.get_balance(sub_addr).unwrap(), U256::from(100)); -} + #[test] + fn test_deploy_and_transfer() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + + // This should increment the nonce of the deploying contract. + // There is 100 attached to this that should be passed through. + let (input, _) = soltest::functions::deploy_new_guy::call(8); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + assert!(context.logs.len() > 0); + + // The sub_addr should have been transferred 100 yoctoN. + let sub_addr = raw[12..32].to_vec(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); + assert_eq!(context.get_balance(sub_addr).unwrap(), U256::from(100)); + } -#[test] -fn test_contract_to_eoa_transfer() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + #[test] + fn test_deploy_with_value() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + + // This should increment the nonce of the deploying contract + // There is 100 attached to this that should be passed through + let (input, _) = soltest::functions::pay_new_guy::call(8); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + + // The sub_addr should have been transferred 100 tokens. + let sub_addr = raw[12..32].to_vec(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); + assert_eq!(context.get_balance(sub_addr).unwrap(), U256::from(100)); + } - let (input, _) = soltest::functions::return_some_funds::call(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + #[test] + fn test_contract_to_eoa_transfer() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - let sender_addr = raw[12..32].to_vec(); - assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); - assert_eq!(context.get_balance(sender_addr).unwrap(), U256::from(50)); -} + let (input, _) = soltest::functions::return_some_funds::call(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); -#[test] -fn test_get_code() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - let context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let sender_addr = raw[12..32].to_vec(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); + assert_eq!(context.get_balance(sender_addr).unwrap(), U256::from(50)); + } - assert!(context.get_code(test_addr.0.to_vec()).unwrap().len() > 1500); // contract code should roughly be over length 1500 - assert_eq!(context.get_code(vec![0u8; 20]).unwrap().len(), 0); -} + #[test] + fn test_get_code() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + let context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); -#[test] -fn test_view_call() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + assert!(context.get_code(test_addr.0.to_vec()).unwrap().len() > 1500); // contract code should roughly be over length 1500 + assert_eq!(context.get_code(vec![0u8; 20]).unwrap().len(), 0); + } - // This should NOT increment the nonce of the deploying contract - // And NO CODE should be deployed - let (input, _) = soltest::functions::deploy_new_guy::call(8); - let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - let raw = context - .view_call_function(encode_view_call_function_args( - test_addr, - test_addr, - U256::from(0), - input, - )) - .unwrap(); - assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); + #[test] + fn test_view_call() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + + // This should NOT increment the nonce of the deploying contract + // And NO CODE should be deployed + let (input, _) = soltest::functions::deploy_new_guy::call(8); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let raw = context + .view_call_function(encode_view_call_function_args( + test_addr, + test_addr, + U256::from(0), + input, + )) + .unwrap(); + assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); + + let sub_addr = raw[12..32].to_vec(); + assert_eq!(context.get_code(sub_addr).unwrap().len(), 0); + + let (input, _) = soltest::functions::return_some_funds::call(); + let raw = context + .view_call_function(encode_view_call_function_args( + test_addr, + test_addr, + U256::from(10u128.pow(27)), + input, + )) + .unwrap(); + assert_eq!(raw[12..32], test_addr.0); + } - let sub_addr = raw[12..32].to_vec(); - assert_eq!(context.get_code(sub_addr).unwrap().len(), 0); + #[test] + fn test_solidity_accurate_storage_on_selfdestruct() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + assert_eq!( + context.deposit(near_account_id_to_evm_address(&accounts(1)).0.to_vec()).unwrap(), + U256::from(100) + ); + + // Deploy CREATE2 Factory + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let factory_addr = context.deploy_code(hex::decode(&FACTORY_TEST).unwrap()).unwrap(); + + // Deploy + SelfDestruct in one transaction + let salt = H256([0u8; 32]); + let destruct_code = hex::decode(&DESTRUCT_TEST).unwrap(); + let input = + create2factory::functions::test_double_deploy::call(salt, destruct_code.clone()).0; + let raw = context.call_function(encode_call_function_args(factory_addr, input)).unwrap(); + assert!(create2factory::functions::test_double_deploy::decode_output(&raw).unwrap()); + } - let (input, _) = soltest::functions::return_some_funds::call(); - let raw = context - .view_call_function(encode_view_call_function_args( - test_addr, + #[test] + fn test_meta_call() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + let signer = InMemorySigner::from_random("doesnt".to_string(), KeyType::SECP256K1); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let meta_tx = encode_meta_call_function_args( + &signer, + CHAIN_ID, + U256::from(0), + U256::from(0), + Address::from_slice(&[0u8; 20]), test_addr, - U256::from(10u128.pow(27)), - input, - )) - .unwrap(); - assert_eq!(raw[12..32], test_addr.0); -} - -#[test] -fn test_solidity_accurate_storage_on_selfdestruct() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - assert_eq!( - context.deposit(near_account_id_to_evm_address(&accounts(1)).0.to_vec()).unwrap(), - U256::from(100) - ); - - // Deploy CREATE2 Factory - let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - let factory_addr = context.deploy_code(hex::decode(&FACTORY_TEST).unwrap()).unwrap(); - - // Deploy + SelfDestruct in one transaction - let salt = H256([0u8; 32]); - let destruct_code = hex::decode(&DESTRUCT_TEST).unwrap(); - let input = create2factory::functions::test_double_deploy::call(salt, destruct_code.clone()).0; - let raw = context.call_function(encode_call_function_args(factory_addr, input)).unwrap(); - assert!(create2factory::functions::test_double_deploy::decode_output(&raw).unwrap()); -} - -#[test] -fn test_meta_call() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - let signer = InMemorySigner::from_random("doesnt".to_string(), KeyType::SECP256K1); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let meta_tx = encode_meta_call_function_args( - &signer, - CHAIN_ID, - U256::from(0), - U256::from(0), - Address::from_slice(&[0u8; 20]), - test_addr, - "returnSomeFunds()", - vec![], - ); - let _ = context.meta_call_function(meta_tx.clone()).unwrap(); - let signer_addr = public_key_to_address(signer.public_key); - assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); - assert_eq!(context.get_balance(signer_addr.0.to_vec()).unwrap(), U256::from(50)); - assert_eq!( - context.meta_call_function(meta_tx).unwrap_err().to_string(), - "EvmError(InvalidNonce)" - ); -} + "returnSomeFunds()", + vec![], + ); + let _ = context.meta_call_function(meta_tx.clone()).unwrap(); + let signer_addr = public_key_to_address(signer.public_key); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); + assert_eq!(context.get_balance(signer_addr.0.to_vec()).unwrap(), U256::from(50)); + assert_eq!( + context.meta_call_function(meta_tx).unwrap_err().to_string(), + "EvmError(InvalidNonce)" + ); + } -#[test] -#[ignore] -fn test_meta_call_sig_recover() { - let meta_tx = [ - // signature: 65 bytes - hex::decode("1cb6f28f29524cf3ae5ce49f364b5ad798af5dd8ec3563744dc62792735ce5e222285df1e91c416e430d0a38ea3b51d6677e337e1b0684d7618f5a00a26a2ee21c").unwrap(), - // nonce: 14 - u256_to_arr(&U256::from(14)).to_vec(), - // fee amount: 6 - u256_to_arr(&U256::from(6)).to_vec(), - // fee token: 0x0 - vec![0; 20], - // contract: address, - hex::decode("Ed2a1b3Fa739DAbBf8c07a059dE1333D20e8b482").unwrap(), - // contract method: length 1 byte + bytes for the name. - vec![14], - b"adopt(uint256)".to_vec(), - // arguments - u256_to_arr(&U256::from(9)).to_vec(), - ].concat(); - let domain_separator = near_erc721_domain(U256::from(CHAIN_ID)); - let result = parse_meta_call(&domain_separator, &"evm".to_string(), meta_tx).unwrap(); - assert_eq!(result.sender.to_hex(), "2941022347348828A24a5ff33c775D67691681e9"); + #[test] + #[ignore] + fn test_meta_call_sig_recover() { + let meta_tx = [ + // signature: 65 bytes + hex::decode("1cb6f28f29524cf3ae5ce49f364b5ad798af5dd8ec3563744dc62792735ce5e222285df1e91c416e430d0a38ea3b51d6677e337e1b0684d7618f5a00a26a2ee21c").unwrap(), + // nonce: 14 + u256_to_arr(&U256::from(14)).to_vec(), + // fee amount: 6 + u256_to_arr(&U256::from(6)).to_vec(), + // fee token: 0x0 + vec![0; 20], + // contract: address, + hex::decode("Ed2a1b3Fa739DAbBf8c07a059dE1333D20e8b482").unwrap(), + // contract method: length 1 byte + bytes for the name. + vec![14], + b"adopt(uint256)".to_vec(), + // arguments + u256_to_arr(&U256::from(9)).to_vec(), + ].concat(); + let domain_separator = near_erc721_domain(U256::from(CHAIN_ID)); + let result = parse_meta_call(&domain_separator, &"evm".to_string(), meta_tx).unwrap(); + assert_eq!(result.sender.to_hex(), "2941022347348828A24a5ff33c775D67691681e9"); + } } diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index bf063b6a480..b37e6666eb9 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -1,107 +1,110 @@ -use ethereum_types::{Address, U256}; -use keccak_hash::keccak; -use near_crypto::{PublicKey, Signature, Signer}; -use near_evm_runner::utils::{near_erc721_domain, prepare_meta_call_args, u256_to_arr}; -use near_evm_runner::EvmContext; -use near_runtime_fees::RuntimeFeesConfig; -use near_vm_logic::mocks::mock_external::MockedExternal; -use near_vm_logic::types::Balance; -use near_vm_logic::VMConfig; +#[cfg(feature = "protocol_feature_evm")] +mod utils { + use ethereum_types::{Address, U256}; + use keccak_hash::keccak; + use near_crypto::{PublicKey, Signature, Signer}; + use near_evm_runner::utils::{near_erc721_domain, prepare_meta_call_args, u256_to_arr}; + use near_evm_runner::EvmContext; + use near_runtime_fees::RuntimeFeesConfig; + use near_vm_logic::mocks::mock_external::MockedExternal; + use near_vm_logic::types::Balance; + use near_vm_logic::VMConfig; -/// See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161555.json -pub const CHAIN_ID: u128 = 1313161555; + /// See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161555.json + pub const CHAIN_ID: u128 = 1313161555; -pub fn accounts(num: usize) -> String { - ["evm", "alice", "bob", "chad"][num].to_string() -} + pub fn accounts(num: usize) -> String { + ["evm", "alice", "bob", "chad"][num].to_string() + } -pub fn setup() -> (MockedExternal, VMConfig, RuntimeFeesConfig) { - let vm_config = VMConfig::default(); - let fees_config = RuntimeFeesConfig::default(); - let fake_external = MockedExternal::new(); - (fake_external, vm_config, fees_config) -} + pub fn setup() -> (MockedExternal, VMConfig, RuntimeFeesConfig) { + let vm_config = VMConfig::default(); + let fees_config = RuntimeFeesConfig::default(); + let fake_external = MockedExternal::new(); + (fake_external, vm_config, fees_config) + } -pub fn create_context<'a>( - external: &'a mut MockedExternal, - vm_config: &'a VMConfig, - fees_config: &'a RuntimeFeesConfig, - account_id: String, - attached_deposit: Balance, -) -> EvmContext<'a> { - EvmContext::new( - external, - CHAIN_ID, - vm_config, - fees_config, - 1000, - "evm".to_string(), - account_id.to_string(), - account_id.to_string(), - attached_deposit, - 0, - 10u64.pow(14), - false, - 1_000_000_000.into(), - ) -} + pub fn create_context<'a>( + external: &'a mut MockedExternal, + vm_config: &'a VMConfig, + fees_config: &'a RuntimeFeesConfig, + account_id: String, + attached_deposit: Balance, + ) -> EvmContext<'a> { + EvmContext::new( + external, + CHAIN_ID, + vm_config, + fees_config, + 1000, + "evm".to_string(), + account_id.to_string(), + account_id.to_string(), + attached_deposit, + 0, + 10u64.pow(14), + false, + 1_000_000_000.into(), + ) + } -#[cfg(test)] -#[allow(dead_code)] -pub fn show_evm_gas_used(context: &EvmContext) { - println!("Accumulated EVM gas used: {}", &context.evm_gas_counter.used_gas); -} + #[cfg(test)] + #[allow(dead_code)] + pub fn show_evm_gas_used(context: &EvmContext) { + println!("Accumulated EVM gas used: {}", &context.evm_gas_counter.used_gas); + } -/// Linter is suboptimal, because doesn't see that this is used in standard_ops.rs. -#[allow(dead_code)] -pub fn public_key_to_address(public_key: PublicKey) -> Address { - match public_key { - PublicKey::ED25519(_) => panic!("Wrong PublicKey"), - PublicKey::SECP256K1(pubkey) => { - let pk: [u8; 64] = pubkey.into(); - let bytes = keccak(&pk.to_vec()); - let mut result = Address::zero(); - result.as_bytes_mut().copy_from_slice(&bytes[12..]); - result + /// Linter is suboptimal, because doesn't see that this is used in standard_ops.rs. + #[allow(dead_code)] + pub fn public_key_to_address(public_key: PublicKey) -> Address { + match public_key { + PublicKey::ED25519(_) => panic!("Wrong PublicKey"), + PublicKey::SECP256K1(pubkey) => { + let pk: [u8; 64] = pubkey.into(); + let bytes = keccak(&pk.to_vec()); + let mut result = Address::zero(); + result.as_bytes_mut().copy_from_slice(&bytes[12..]); + result + } } } -} -/// Linter is suboptimal, because doesn't see that this is used in standard_ops.rs. -#[allow(dead_code)] -pub fn encode_meta_call_function_args( - signer: &dyn Signer, - chain_id: u128, - nonce: U256, - fee_amount: U256, - fee_token: Address, - address: Address, - method_name: &str, - args: Vec, -) -> Vec { - let domain_separator = near_erc721_domain(U256::from(chain_id)); - let msg = prepare_meta_call_args( - &domain_separator, - &"evm".to_string(), - nonce, - fee_amount, - fee_token, - address, - method_name, - &args, - ); - match signer.sign(&msg) { - Signature::ED25519(_) => panic!("Wrong Signer"), - Signature::SECP256K1(sig) => [ - Into::<[u8; 65]>::into(sig).to_vec(), - u256_to_arr(&nonce).to_vec(), - u256_to_arr(&fee_amount).to_vec(), - fee_token.0.to_vec(), - address.0.to_vec(), - vec![method_name.len() as u8], - method_name.as_bytes().to_vec(), - args, - ] - .concat(), + /// Linter is suboptimal, because doesn't see that this is used in standard_ops.rs. + #[allow(dead_code)] + pub fn encode_meta_call_function_args( + signer: &dyn Signer, + chain_id: u128, + nonce: U256, + fee_amount: U256, + fee_token: Address, + address: Address, + method_name: &str, + args: Vec, + ) -> Vec { + let domain_separator = near_erc721_domain(U256::from(chain_id)); + let msg = prepare_meta_call_args( + &domain_separator, + &"evm".to_string(), + nonce, + fee_amount, + fee_token, + address, + method_name, + &args, + ); + match signer.sign(&msg) { + Signature::ED25519(_) => panic!("Wrong Signer"), + Signature::SECP256K1(sig) => [ + Into::<[u8; 65]>::into(sig).to_vec(), + u256_to_arr(&nonce).to_vec(), + u256_to_arr(&fee_amount).to_vec(), + fee_token.0.to_vec(), + address.0.to_vec(), + vec![method_name.len() as u8], + method_name.as_bytes().to_vec(), + args, + ] + .concat(), + } } } diff --git a/runtime/near-vm-runner/Cargo.toml b/runtime/near-vm-runner/Cargo.toml index b4dff50ddff..1ad276e732e 100644 --- a/runtime/near-vm-runner/Cargo.toml +++ b/runtime/near-vm-runner/Cargo.toml @@ -39,7 +39,7 @@ wasmer_default = [] wasmtime_default = ["wasmtime_vm"] no_cpu_compatibility_checks = [] lightbeam = ["wasmtime_vm"] -protocol_feature_evm = ["near-evm-runner", "near-runtime-fees/protocol_feature_evm"] +protocol_feature_evm = ["near-runtime-fees/protocol_feature_evm", "near-evm-runner/protocol_feature_evm"] # Use this feature to enable counting of fees and costs applied. costs_counting = ["near-vm-logic/costs_counting"] diff --git a/runtime/runtime-params-estimator/Cargo.toml b/runtime/runtime-params-estimator/Cargo.toml index a7ebdced9bf..f27a021cae0 100644 --- a/runtime/runtime-params-estimator/Cargo.toml +++ b/runtime/runtime-params-estimator/Cargo.toml @@ -17,21 +17,21 @@ clap = "2.33" borsh = "0.7.1" num-rational = "0.3.0" -near-chain-configs = { path = "../../core/chain-configs", features = ["protocol_feature_evm"] } +near-chain-configs = { path = "../../core/chain-configs" } near-runtime-fees = { path = "../../runtime/near-runtime-fees" } near-crypto = { path = "../../core/crypto" } near-vm-logic = {path = "../../runtime/near-vm-logic" , features = ["costs_counting"]} near-vm-runner = {path = "../../runtime/near-vm-runner" , features = ["costs_counting", "no_cache", "no_cpu_compatibility_checks", "wasmtime_vm" ]} -node-runtime = { path = "../../runtime/runtime" , features = ["costs_counting", "no_cache", "protocol_feature_evm"]} +node-runtime = { path = "../../runtime/runtime" , features = ["costs_counting", "no_cache"]} near-store = { path = "../../core/store" } -near-primitives = { path = "../../core/primitives", features = ["protocol_feature_evm", "protocol_feature_forward_chunk_parts", "nightly_protocol"] } -testlib = { path = "../../test-utils/testlib", features = ["protocol_feature_evm"] } +near-primitives = { path = "../../core/primitives" } +testlib = { path = "../../test-utils/testlib" } state-viewer = { path = "../../test-utils/state-viewer" } neard = { path = "../../neard" } rocksdb = { git = "https://github.com/nearprotocol/rust-rocksdb", branch="disable-thread" } glob = "0.3.0" walrus = "0.18.0" -near-evm-runner = { path = "../../runtime/near-evm-runner", features = ["costs_counting"] } +near-evm-runner = { path = "../../runtime/near-evm-runner", features = ["costs_counting"], optional = true } hex = "0.4" ethabi = "9.0.1" ethabi-contract = "9.0.0" @@ -44,4 +44,4 @@ num-traits = "0.2.12" default = [] wasmtime = ["near-vm-logic/wasmtime_default"] lightbeam = ["wasmtime", "near-vm-runner/lightbeam"] -protocol_feature_evm = [] +protocol_feature_evm = ["near-evm-runner/protocol_feature_evm", "near-vm-runner/protocol_feature_evm", "near-chain-configs/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm", "node-runtime/protocol_feature_evm", "near-primitives/protocol_feature_evm", "testlib/protocol_feature_evm"] diff --git a/runtime/runtime/Cargo.toml b/runtime/runtime/Cargo.toml index 36253d3587d..d7eab039359 100644 --- a/runtime/runtime/Cargo.toml +++ b/runtime/runtime/Cargo.toml @@ -35,7 +35,7 @@ near-evm-runner = { path = "../../runtime/near-evm-runner", optional = true } [features] default = [] dump_errors_schema = ["near-vm-errors/dump_errors_schema"] -protocol_feature_evm = ["near-primitives/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm", "near-vm-runner/protocol_feature_evm", "near-evm-runner"] +protocol_feature_evm = ["near-evm-runner/protocol_feature_evm", "near-primitives/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm", "near-vm-runner/protocol_feature_evm", "testlib/protocol_feature_evm"] # Use this feature to enable counting of fees and costs applied. costs_counting = ["near-vm-logic/costs_counting", "near-vm-runner/costs_counting"] @@ -52,4 +52,4 @@ rayon = "^1.1" assert_matches = "1.3" testlib = { path = "../../test-utils/testlib" } -near-chain-configs = { path = "../../core/chain-configs" } \ No newline at end of file +near-chain-configs = { path = "../../core/chain-configs" } diff --git a/test-utils/testlib/Cargo.toml b/test-utils/testlib/Cargo.toml index 5dfdd770fe2..7ebadec7176 100644 --- a/test-utils/testlib/Cargo.toml +++ b/test-utils/testlib/Cargo.toml @@ -45,4 +45,4 @@ near-evm-runner = { path = "../../runtime/near-evm-runner", optional = true } [features] default = [] -protocol_feature_evm = ["near-evm-runner", "near-primitives/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm", "neard/protocol_feature_evm", "node-runtime/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"] +protocol_feature_evm = ["near-evm-runner/protocol_feature_evm", "near-primitives/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm", "neard/protocol_feature_evm", "node-runtime/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"] From c36f45e0ea06274c55d261e08e953783d8737c25 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Wed, 18 Nov 2020 15:48:50 -0800 Subject: [PATCH 67/82] Fix evm runner --- runtime/near-evm-runner/src/lib.rs | 5 ++++- runtime/near-evm-runner/src/runner.rs | 6 ++---- runtime/runtime/Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/runtime/near-evm-runner/src/lib.rs b/runtime/near-evm-runner/src/lib.rs index 0dd3cca5de7..e9ab8dc02e6 100644 --- a/runtime/near-evm-runner/src/lib.rs +++ b/runtime/near-evm-runner/src/lib.rs @@ -1,4 +1,7 @@ #[cfg(feature = "protocol_feature_evm")] +#[macro_use] +extern crate enum_primitive_derive; +#[cfg(feature = "protocol_feature_evm")] mod builtins; #[cfg(feature = "protocol_feature_evm")] mod evm_state; @@ -15,4 +18,4 @@ pub mod types; #[cfg(feature = "protocol_feature_evm")] pub mod utils; #[cfg(feature = "protocol_feature_evm")] -use runner::*; +pub use runner::*; diff --git a/runtime/near-evm-runner/src/runner.rs b/runtime/near-evm-runner/src/runner.rs index 15c62d89cdc..8e0d4906c8a 100644 --- a/runtime/near-evm-runner/src/runner.rs +++ b/runtime/near-evm-runner/src/runner.rs @@ -1,6 +1,3 @@ -#[macro_use] -extern crate enum_primitive_derive; - use borsh::{BorshDeserialize, BorshSerialize}; use ethereum_types::{Address, H160, U256}; use evm::CreateContractAddress; @@ -14,11 +11,12 @@ use near_vm_logic::types::{AccountId, Balance, Gas, ReturnData, StorageUsage}; use near_vm_logic::{ActionCosts, External, VMConfig, VMLogicError, VMOutcome}; use crate::evm_state::{EvmAccount, EvmGasCounter, EvmState, StateStore}; +use crate::interpreter; use crate::types::{ AddressArg, DataKey, FunctionCallArgs, GetStorageAtArgs, Method, RawU256, Result, TransferArgs, ViewCallArgs, WithdrawArgs, }; -use crate::utils::{combine_data_key, near_erc721_domain, parse_meta_call}; +use crate::utils::{self, combine_data_key, near_erc721_domain, parse_meta_call}; use near_vm_errors::InconsistentStateError::StorageError; pub struct EvmContext<'a> { diff --git a/runtime/runtime/Cargo.toml b/runtime/runtime/Cargo.toml index d7eab039359..40501450e8b 100644 --- a/runtime/runtime/Cargo.toml +++ b/runtime/runtime/Cargo.toml @@ -35,7 +35,7 @@ near-evm-runner = { path = "../../runtime/near-evm-runner", optional = true } [features] default = [] dump_errors_schema = ["near-vm-errors/dump_errors_schema"] -protocol_feature_evm = ["near-evm-runner/protocol_feature_evm", "near-primitives/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm", "near-vm-runner/protocol_feature_evm", "testlib/protocol_feature_evm"] +protocol_feature_evm = ["near-evm-runner/protocol_feature_evm", "near-primitives/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm", "near-vm-runner/protocol_feature_evm"] # Use this feature to enable counting of fees and costs applied. costs_counting = ["near-vm-logic/costs_counting", "near-vm-runner/costs_counting"] From c16db53759d197b9741800aeae9f450b9c555b0a Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Wed, 18 Nov 2020 16:02:10 -0800 Subject: [PATCH 68/82] Fix evm-runner tests --- runtime/near-evm-runner/tests/failures.rs | 2 - runtime/near-evm-runner/tests/standard_ops.rs | 2 - runtime/near-evm-runner/tests/utils.rs | 195 +++++++++--------- 3 files changed, 96 insertions(+), 103 deletions(-) diff --git a/runtime/near-evm-runner/tests/failures.rs b/runtime/near-evm-runner/tests/failures.rs index de8faaf8975..3828353b1c0 100644 --- a/runtime/near-evm-runner/tests/failures.rs +++ b/runtime/near-evm-runner/tests/failures.rs @@ -3,8 +3,6 @@ mod tests { use crate::utils::{accounts, create_context, setup}; - mod utils; - /// Test various invalid inputs to function calls. #[test] fn test_invalid_input() { diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 69d0e0d5d20..91b9d16cdb3 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -26,8 +26,6 @@ mod tests { }; use parity_bytes::ToPretty; - mod utils; - use_contract!(soltest, "tests/build/SolTests.abi"); use_contract!(subcontract, "tests/build/SubContract.abi"); use_contract!(create2factory, "tests/build/Create2Factory.abi"); diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils.rs index b37e6666eb9..bf063b6a480 100644 --- a/runtime/near-evm-runner/tests/utils.rs +++ b/runtime/near-evm-runner/tests/utils.rs @@ -1,110 +1,107 @@ -#[cfg(feature = "protocol_feature_evm")] -mod utils { - use ethereum_types::{Address, U256}; - use keccak_hash::keccak; - use near_crypto::{PublicKey, Signature, Signer}; - use near_evm_runner::utils::{near_erc721_domain, prepare_meta_call_args, u256_to_arr}; - use near_evm_runner::EvmContext; - use near_runtime_fees::RuntimeFeesConfig; - use near_vm_logic::mocks::mock_external::MockedExternal; - use near_vm_logic::types::Balance; - use near_vm_logic::VMConfig; +use ethereum_types::{Address, U256}; +use keccak_hash::keccak; +use near_crypto::{PublicKey, Signature, Signer}; +use near_evm_runner::utils::{near_erc721_domain, prepare_meta_call_args, u256_to_arr}; +use near_evm_runner::EvmContext; +use near_runtime_fees::RuntimeFeesConfig; +use near_vm_logic::mocks::mock_external::MockedExternal; +use near_vm_logic::types::Balance; +use near_vm_logic::VMConfig; - /// See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161555.json - pub const CHAIN_ID: u128 = 1313161555; +/// See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161555.json +pub const CHAIN_ID: u128 = 1313161555; - pub fn accounts(num: usize) -> String { - ["evm", "alice", "bob", "chad"][num].to_string() - } +pub fn accounts(num: usize) -> String { + ["evm", "alice", "bob", "chad"][num].to_string() +} - pub fn setup() -> (MockedExternal, VMConfig, RuntimeFeesConfig) { - let vm_config = VMConfig::default(); - let fees_config = RuntimeFeesConfig::default(); - let fake_external = MockedExternal::new(); - (fake_external, vm_config, fees_config) - } +pub fn setup() -> (MockedExternal, VMConfig, RuntimeFeesConfig) { + let vm_config = VMConfig::default(); + let fees_config = RuntimeFeesConfig::default(); + let fake_external = MockedExternal::new(); + (fake_external, vm_config, fees_config) +} - pub fn create_context<'a>( - external: &'a mut MockedExternal, - vm_config: &'a VMConfig, - fees_config: &'a RuntimeFeesConfig, - account_id: String, - attached_deposit: Balance, - ) -> EvmContext<'a> { - EvmContext::new( - external, - CHAIN_ID, - vm_config, - fees_config, - 1000, - "evm".to_string(), - account_id.to_string(), - account_id.to_string(), - attached_deposit, - 0, - 10u64.pow(14), - false, - 1_000_000_000.into(), - ) - } +pub fn create_context<'a>( + external: &'a mut MockedExternal, + vm_config: &'a VMConfig, + fees_config: &'a RuntimeFeesConfig, + account_id: String, + attached_deposit: Balance, +) -> EvmContext<'a> { + EvmContext::new( + external, + CHAIN_ID, + vm_config, + fees_config, + 1000, + "evm".to_string(), + account_id.to_string(), + account_id.to_string(), + attached_deposit, + 0, + 10u64.pow(14), + false, + 1_000_000_000.into(), + ) +} - #[cfg(test)] - #[allow(dead_code)] - pub fn show_evm_gas_used(context: &EvmContext) { - println!("Accumulated EVM gas used: {}", &context.evm_gas_counter.used_gas); - } +#[cfg(test)] +#[allow(dead_code)] +pub fn show_evm_gas_used(context: &EvmContext) { + println!("Accumulated EVM gas used: {}", &context.evm_gas_counter.used_gas); +} - /// Linter is suboptimal, because doesn't see that this is used in standard_ops.rs. - #[allow(dead_code)] - pub fn public_key_to_address(public_key: PublicKey) -> Address { - match public_key { - PublicKey::ED25519(_) => panic!("Wrong PublicKey"), - PublicKey::SECP256K1(pubkey) => { - let pk: [u8; 64] = pubkey.into(); - let bytes = keccak(&pk.to_vec()); - let mut result = Address::zero(); - result.as_bytes_mut().copy_from_slice(&bytes[12..]); - result - } +/// Linter is suboptimal, because doesn't see that this is used in standard_ops.rs. +#[allow(dead_code)] +pub fn public_key_to_address(public_key: PublicKey) -> Address { + match public_key { + PublicKey::ED25519(_) => panic!("Wrong PublicKey"), + PublicKey::SECP256K1(pubkey) => { + let pk: [u8; 64] = pubkey.into(); + let bytes = keccak(&pk.to_vec()); + let mut result = Address::zero(); + result.as_bytes_mut().copy_from_slice(&bytes[12..]); + result } } +} - /// Linter is suboptimal, because doesn't see that this is used in standard_ops.rs. - #[allow(dead_code)] - pub fn encode_meta_call_function_args( - signer: &dyn Signer, - chain_id: u128, - nonce: U256, - fee_amount: U256, - fee_token: Address, - address: Address, - method_name: &str, - args: Vec, - ) -> Vec { - let domain_separator = near_erc721_domain(U256::from(chain_id)); - let msg = prepare_meta_call_args( - &domain_separator, - &"evm".to_string(), - nonce, - fee_amount, - fee_token, - address, - method_name, - &args, - ); - match signer.sign(&msg) { - Signature::ED25519(_) => panic!("Wrong Signer"), - Signature::SECP256K1(sig) => [ - Into::<[u8; 65]>::into(sig).to_vec(), - u256_to_arr(&nonce).to_vec(), - u256_to_arr(&fee_amount).to_vec(), - fee_token.0.to_vec(), - address.0.to_vec(), - vec![method_name.len() as u8], - method_name.as_bytes().to_vec(), - args, - ] - .concat(), - } +/// Linter is suboptimal, because doesn't see that this is used in standard_ops.rs. +#[allow(dead_code)] +pub fn encode_meta_call_function_args( + signer: &dyn Signer, + chain_id: u128, + nonce: U256, + fee_amount: U256, + fee_token: Address, + address: Address, + method_name: &str, + args: Vec, +) -> Vec { + let domain_separator = near_erc721_domain(U256::from(chain_id)); + let msg = prepare_meta_call_args( + &domain_separator, + &"evm".to_string(), + nonce, + fee_amount, + fee_token, + address, + method_name, + &args, + ); + match signer.sign(&msg) { + Signature::ED25519(_) => panic!("Wrong Signer"), + Signature::SECP256K1(sig) => [ + Into::<[u8; 65]>::into(sig).to_vec(), + u256_to_arr(&nonce).to_vec(), + u256_to_arr(&fee_amount).to_vec(), + fee_token.0.to_vec(), + address.0.to_vec(), + vec![method_name.len() as u8], + method_name.as_bytes().to_vec(), + args, + ] + .concat(), } } From 4871332133384e2a486ca0226a9494a9883b15ce Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Wed, 18 Nov 2020 16:43:13 -0800 Subject: [PATCH 69/82] Addressing feature/non-feature shit --- chain/chunks/src/lib.rs | 9 +- runtime/near-evm-runner/Cargo.toml | 10 + runtime/near-evm-runner/tests/failures.rs | 65 +- runtime/near-evm-runner/tests/standard_ops.rs | 563 +++++++++--------- .../tests/{utils.rs => utils/mod.rs} | 0 .../runtime_group_tools/random_config.rs | 8 +- 6 files changed, 321 insertions(+), 334 deletions(-) rename runtime/near-evm-runner/tests/{utils.rs => utils/mod.rs} (100%) diff --git a/chain/chunks/src/lib.rs b/chain/chunks/src/lib.rs index a994239cc4e..e486aa54986 100644 --- a/chain/chunks/src/lib.rs +++ b/chain/chunks/src/lib.rs @@ -1699,17 +1699,14 @@ impl ShardsManager { #[cfg(test)] mod test { - use crate::test_utils::{ChunkForwardingTestFixture, SealsManagerTestFixture}; - use crate::{ - ChunkRequestInfo, ProcessPartialEncodedChunkResult, Seal, SealsManager, ShardsManager, - CHUNK_REQUEST_RETRY_MS, NUM_PARTS_REQUESTED_IN_SEAL, - }; + use super::*; + use crate::test_utils::*; use near_chain::test_utils::KeyValueRuntime; use near_network::test_utils::MockNetworkAdapter; #[cfg(feature = "protocol_feature_forward_chunk_parts")] use near_network::types::PartialEncodedChunkForwardMsg; use near_primitives::hash::{hash, CryptoHash}; - use near_primitives::sharding::{ChunkHash, PartialEncodedChunkV2}; + #[cfg(feature = "protocol_feature_forward_chunk_parts")] use near_primitives::version::PROTOCOL_VERSION; use near_store::test_utils::create_test_store; use std::sync::Arc; diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index fe199755425..fcff990ef54 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -49,3 +49,13 @@ near-crypto = { path = "../../core/crypto" } [features] costs_counting = [] protocol_feature_evm = ["near-runtime-fees/protocol_feature_evm"] + +[[test]] +name = "failures" +path = "tests/failures.rs" +required-features = ["protocol_feature_evm"] + +[[test]] +name = "standard_ops" +path = "tests/standard_ops.rs" +required-features = ["protocol_feature_evm"] diff --git a/runtime/near-evm-runner/tests/failures.rs b/runtime/near-evm-runner/tests/failures.rs index 3828353b1c0..eedcaa79357 100644 --- a/runtime/near-evm-runner/tests/failures.rs +++ b/runtime/near-evm-runner/tests/failures.rs @@ -1,38 +1,33 @@ -#[cfg(feature = "protocol_feature_evm")] -#[cfg(tests)] -mod tests { - use crate::utils::{accounts, create_context, setup}; +mod utils; - /// Test various invalid inputs to function calls. - #[test] - fn test_invalid_input() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 10); - assert!(context.get_nonce(vec![]).is_err()); - assert!(context.get_balance(vec![]).is_err()); - assert!(context.get_code(vec![]).is_err()); - assert!(context.get_storage_at(vec![]).is_err()); - assert!(context.view_call_function(vec![]).is_err()); - assert!(context.view_call_function(vec![0u8; 20]).is_err()); - assert!(context.call_function(vec![]).is_err()); - assert!(context.call_function(vec![0u8; 20]).is_err()); - assert!(context.deposit(vec![]).is_err()); - assert!(context.withdraw(vec![]).is_err()); - assert!(context.transfer(vec![]).is_err()); - } +use crate::utils::{accounts, create_context, setup}; - #[test] - fn test_invalid_view_args() { - let args = - vec![vec![1u8; 20], vec![2u8; 20], vec![0u8; 32], vec![1u8, 0u8, 0u8, 0u8], vec![1]] - .concat(); - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - assert_eq!( - context.view_call_function(args).unwrap_err().to_string(), - "EvmError(ContractNotFound)" - ); - } +/// Test various invalid inputs to function calls. +#[test] +fn test_invalid_input() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 10); + assert!(context.get_nonce(vec![]).is_err()); + assert!(context.get_balance(vec![]).is_err()); + assert!(context.get_code(vec![]).is_err()); + assert!(context.get_storage_at(vec![]).is_err()); + assert!(context.view_call_function(vec![]).is_err()); + assert!(context.view_call_function(vec![0u8; 20]).is_err()); + assert!(context.call_function(vec![]).is_err()); + assert!(context.call_function(vec![0u8; 20]).is_err()); + assert!(context.deposit(vec![]).is_err()); + assert!(context.withdraw(vec![]).is_err()); + assert!(context.transfer(vec![]).is_err()); +} + +#[test] +fn test_invalid_view_args() { + let args = vec![vec![1u8; 20], vec![2u8; 20], vec![0u8; 32], vec![1u8, 0u8, 0u8, 0u8], vec![1]] + .concat(); + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + assert_eq!( + context.view_call_function(args).unwrap_err().to_string(), + "EvmError(ContractNotFound)" + ); } diff --git a/runtime/near-evm-runner/tests/standard_ops.rs b/runtime/near-evm-runner/tests/standard_ops.rs index 91b9d16cdb3..28620069af1 100644 --- a/runtime/near-evm-runner/tests/standard_ops.rs +++ b/runtime/near-evm-runner/tests/standard_ops.rs @@ -1,310 +1,292 @@ -#[cfg(feature = "protocol_feature_evm")] -#[cfg(tests)] -mod tests { - #[macro_use] - extern crate lazy_static_include; - - use borsh::BorshSerialize; - use ethabi_contract::use_contract; - use ethereum_types::{Address, H256, U256}; - - use near_crypto::{InMemorySigner, KeyType}; - use near_evm_runner::types::{TransferArgs, WithdrawArgs}; - use near_evm_runner::utils::{ - address_from_arr, address_to_vec, encode_call_function_args, - encode_view_call_function_args, near_account_id_to_evm_address, near_erc721_domain, - parse_meta_call, u256_to_arr, - }; - use near_runtime_fees::RuntimeFeesConfig; - use near_vm_errors::{EvmError, VMLogicError}; - use near_vm_logic::mocks::mock_external::MockedExternal; - use near_vm_logic::VMConfig; - - use crate::utils::{ - accounts, create_context, encode_meta_call_function_args, public_key_to_address, setup, - CHAIN_ID, - }; - use parity_bytes::ToPretty; - - use_contract!(soltest, "tests/build/SolTests.abi"); - use_contract!(subcontract, "tests/build/SubContract.abi"); - use_contract!(create2factory, "tests/build/Create2Factory.abi"); - use_contract!(selfdestruct, "tests/build/SelfDestruct.abi"); - - lazy_static_include_str!(TEST, "tests/build/SolTests.bin"); - lazy_static_include_str!(FACTORY_TEST, "tests/build/Create2Factory.bin"); - lazy_static_include_str!(DESTRUCT_TEST, "tests/build/SelfDestruct.bin"); - lazy_static_include_str!(CONSTRUCTOR_TEST, "tests/build/ConstructorRevert.bin"); - - #[test] - fn test_funds_transfers() { - let (mut fake_external, vm_config, fees_config) = setup(); - let context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - assert_eq!( - context - .get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))) - .unwrap(), - U256::from(0) - ); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - assert_eq!( - context.deposit(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), - U256::from(100) - ); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - context - .transfer( - TransferArgs { - address: near_account_id_to_evm_address(&accounts(2)).0, - amount: u256_to_arr(&U256::from(50)), - } +#[macro_use] +extern crate lazy_static_include; + +use borsh::BorshSerialize; +use ethabi_contract::use_contract; +use ethereum_types::{Address, H256, U256}; + +use near_crypto::{InMemorySigner, KeyType}; +use near_evm_runner::types::{TransferArgs, WithdrawArgs}; +use near_evm_runner::utils::{ + address_from_arr, address_to_vec, encode_call_function_args, encode_view_call_function_args, + near_account_id_to_evm_address, near_erc721_domain, parse_meta_call, u256_to_arr, +}; +use near_runtime_fees::RuntimeFeesConfig; +use near_vm_errors::{EvmError, VMLogicError}; +use near_vm_logic::mocks::mock_external::MockedExternal; +use near_vm_logic::VMConfig; + +use crate::utils::{ + accounts, create_context, encode_meta_call_function_args, public_key_to_address, setup, + CHAIN_ID, +}; +mod utils; + +use parity_bytes::ToPretty; + +use_contract!(soltest, "tests/build/SolTests.abi"); +use_contract!(subcontract, "tests/build/SubContract.abi"); +use_contract!(create2factory, "tests/build/Create2Factory.abi"); +use_contract!(selfdestruct, "tests/build/SelfDestruct.abi"); + +lazy_static_include_str!(TEST, "tests/build/SolTests.bin"); +lazy_static_include_str!(FACTORY_TEST, "tests/build/Create2Factory.bin"); +lazy_static_include_str!(DESTRUCT_TEST, "tests/build/SelfDestruct.bin"); +lazy_static_include_str!(CONSTRUCTOR_TEST, "tests/build/ConstructorRevert.bin"); + +#[test] +fn test_funds_transfers() { + let (mut fake_external, vm_config, fees_config) = setup(); + let context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + assert_eq!( + context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), + U256::from(0) + ); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + assert_eq!( + context.deposit(address_to_vec(&near_account_id_to_evm_address(&accounts(1)))).unwrap(), + U256::from(100) + ); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + context + .transfer( + TransferArgs { + address: near_account_id_to_evm_address(&accounts(2)).0, + amount: u256_to_arr(&U256::from(50)), + } + .try_to_vec() + .unwrap(), + ) + .unwrap(); + assert_eq!( + context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))).unwrap(), + U256::from(50) + ); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(2), 0); + context + .withdraw( + WithdrawArgs { account_id: accounts(2), amount: u256_to_arr(&U256::from(50)) } .try_to_vec() .unwrap(), - ) - .unwrap(); - assert_eq!( - context - .get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))) - .unwrap(), - U256::from(50) - ); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(2), 0); - context - .withdraw( - WithdrawArgs { account_id: accounts(2), amount: u256_to_arr(&U256::from(50)) } - .try_to_vec() - .unwrap(), - ) - .unwrap(); - assert_eq!( - context - .get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))) - .unwrap(), - U256::from(0) - ); - } - - #[test] - fn test_deploy_with_nonce() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - let address = near_account_id_to_evm_address(&accounts(1)); - assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(0)); - let address1 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); - assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(1)); - let address2 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); - assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(2)); - assert_ne!(address1, address2); - } + ) + .unwrap(); + assert_eq!( + context.get_balance(address_to_vec(&near_account_id_to_evm_address(&accounts(2)))).unwrap(), + U256::from(0) + ); +} - #[test] - #[ignore] - fn test_failed_deploy_returns_error() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - if let Err(VMLogicError::EvmError(EvmError::DeployFail(_))) = - context.deploy_code(hex::decode(&CONSTRUCTOR_TEST).unwrap()) - { - } else { - panic!("Should fail"); - } - } +#[test] +fn test_deploy_with_nonce() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let address = near_account_id_to_evm_address(&accounts(1)); + assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(0)); + let address1 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(1)); + let address2 = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_nonce(address.0.to_vec()).unwrap(), U256::from(2)); + assert_ne!(address1, address2); +} - #[test] - fn test_internal_create() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); - assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); - - // This should increment the nonce of the deploying contract - let (input, _) = soltest::functions::deploy_new_guy::call(8); - let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); - assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(1)); - - let sub_addr = address_from_arr(&raw[12..32]); - let (new_input, _) = subcontract::functions::a_number::call(); - let new_raw = - context.call_function(encode_call_function_args(sub_addr, new_input)).unwrap(); - let output = subcontract::functions::a_number::decode_output(&new_raw).unwrap(); - assert_eq!(output, U256::from(8)); +#[test] +#[ignore] +fn test_failed_deploy_returns_error() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + if let Err(VMLogicError::EvmError(EvmError::DeployFail(_))) = + context.deploy_code(hex::decode(&CONSTRUCTOR_TEST).unwrap()) + { + } else { + panic!("Should fail"); } +} - #[test] - fn test_precompiles() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); - - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - let (input, _) = soltest::functions::precompile_test::call(); - let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); - assert_eq!(raw.len(), 0); - } +#[test] +fn test_internal_create() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); + + // This should increment the nonce of the deploying contract + let (input, _) = soltest::functions::deploy_new_guy::call(8); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(1)); + + let sub_addr = address_from_arr(&raw[12..32]); + let (new_input, _) = subcontract::functions::a_number::call(); + let new_raw = context.call_function(encode_call_function_args(sub_addr, new_input)).unwrap(); + let output = subcontract::functions::a_number::decode_output(&new_raw).unwrap(); + assert_eq!(output, U256::from(8)); +} - fn setup_and_deploy_test() -> (MockedExternal, Address, VMConfig, RuntimeFeesConfig) { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); - assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); - (fake_external, test_addr, vm_config, fees_config) - } +#[test] +fn test_precompiles() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let (input, _) = soltest::functions::precompile_test::call(); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + assert_eq!(raw.len(), 0); +} - #[test] - fn test_deploy_and_transfer() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - - // This should increment the nonce of the deploying contract. - // There is 100 attached to this that should be passed through. - let (input, _) = soltest::functions::deploy_new_guy::call(8); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); - assert!(context.logs.len() > 0); - - // The sub_addr should have been transferred 100 yoctoN. - let sub_addr = raw[12..32].to_vec(); - assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); - assert_eq!(context.get_balance(sub_addr).unwrap(), U256::from(100)); - } +fn setup_and_deploy_test() -> (MockedExternal, Address, VMConfig, RuntimeFeesConfig) { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let test_addr = context.deploy_code(hex::decode(&TEST).unwrap()).unwrap(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); + (fake_external, test_addr, vm_config, fees_config) +} - #[test] - fn test_deploy_with_value() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - - // This should increment the nonce of the deploying contract - // There is 100 attached to this that should be passed through - let (input, _) = soltest::functions::pay_new_guy::call(8); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); - - // The sub_addr should have been transferred 100 tokens. - let sub_addr = raw[12..32].to_vec(); - assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); - assert_eq!(context.get_balance(sub_addr).unwrap(), U256::from(100)); - } +#[test] +fn test_deploy_and_transfer() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + + // This should increment the nonce of the deploying contract. + // There is 100 attached to this that should be passed through. + let (input, _) = soltest::functions::deploy_new_guy::call(8); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + assert!(context.logs.len() > 0); + + // The sub_addr should have been transferred 100 yoctoN. + let sub_addr = raw[12..32].to_vec(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); + assert_eq!(context.get_balance(sub_addr).unwrap(), U256::from(100)); +} - #[test] - fn test_contract_to_eoa_transfer() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); +#[test] +fn test_deploy_with_value() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + + // This should increment the nonce of the deploying contract + // There is 100 attached to this that should be passed through + let (input, _) = soltest::functions::pay_new_guy::call(8); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); + + // The sub_addr should have been transferred 100 tokens. + let sub_addr = raw[12..32].to_vec(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(100)); + assert_eq!(context.get_balance(sub_addr).unwrap(), U256::from(100)); +} - let (input, _) = soltest::functions::return_some_funds::call(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); +#[test] +fn test_contract_to_eoa_transfer() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - let sender_addr = raw[12..32].to_vec(); - assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); - assert_eq!(context.get_balance(sender_addr).unwrap(), U256::from(50)); - } + let (input, _) = soltest::functions::return_some_funds::call(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let raw = context.call_function(encode_call_function_args(test_addr, input)).unwrap(); - #[test] - fn test_get_code() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - let context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let sender_addr = raw[12..32].to_vec(); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); + assert_eq!(context.get_balance(sender_addr).unwrap(), U256::from(50)); +} - assert!(context.get_code(test_addr.0.to_vec()).unwrap().len() > 1500); // contract code should roughly be over length 1500 - assert_eq!(context.get_code(vec![0u8; 20]).unwrap().len(), 0); - } +#[test] +fn test_get_code() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + let context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - #[test] - fn test_view_call() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - - // This should NOT increment the nonce of the deploying contract - // And NO CODE should be deployed - let (input, _) = soltest::functions::deploy_new_guy::call(8); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - let raw = context - .view_call_function(encode_view_call_function_args( - test_addr, - test_addr, - U256::from(0), - input, - )) - .unwrap(); - assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); - - let sub_addr = raw[12..32].to_vec(); - assert_eq!(context.get_code(sub_addr).unwrap().len(), 0); - - let (input, _) = soltest::functions::return_some_funds::call(); - let raw = context - .view_call_function(encode_view_call_function_args( - test_addr, - test_addr, - U256::from(10u128.pow(27)), - input, - )) - .unwrap(); - assert_eq!(raw[12..32], test_addr.0); - } + assert!(context.get_code(test_addr.0.to_vec()).unwrap().len() > 1500); // contract code should roughly be over length 1500 + assert_eq!(context.get_code(vec![0u8; 20]).unwrap().len(), 0); +} - #[test] - fn test_solidity_accurate_storage_on_selfdestruct() { - let (mut fake_external, vm_config, fees_config) = setup(); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - assert_eq!( - context.deposit(near_account_id_to_evm_address(&accounts(1)).0.to_vec()).unwrap(), - U256::from(100) - ); - - // Deploy CREATE2 Factory - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); - let factory_addr = context.deploy_code(hex::decode(&FACTORY_TEST).unwrap()).unwrap(); - - // Deploy + SelfDestruct in one transaction - let salt = H256([0u8; 32]); - let destruct_code = hex::decode(&DESTRUCT_TEST).unwrap(); - let input = - create2factory::functions::test_double_deploy::call(salt, destruct_code.clone()).0; - let raw = context.call_function(encode_call_function_args(factory_addr, input)).unwrap(); - assert!(create2factory::functions::test_double_deploy::decode_output(&raw).unwrap()); - } +#[test] +fn test_view_call() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - #[test] - fn test_meta_call() { - let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); - let signer = InMemorySigner::from_random("doesnt".to_string(), KeyType::SECP256K1); - let mut context = - create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); - let meta_tx = encode_meta_call_function_args( - &signer, - CHAIN_ID, - U256::from(0), + // This should NOT increment the nonce of the deploying contract + // And NO CODE should be deployed + let (input, _) = soltest::functions::deploy_new_guy::call(8); + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let raw = context + .view_call_function(encode_view_call_function_args( + test_addr, + test_addr, U256::from(0), - Address::from_slice(&[0u8; 20]), + input, + )) + .unwrap(); + assert_eq!(context.get_nonce(test_addr.0.to_vec()).unwrap(), U256::from(0)); + + let sub_addr = raw[12..32].to_vec(); + assert_eq!(context.get_code(sub_addr).unwrap().len(), 0); + + let (input, _) = soltest::functions::return_some_funds::call(); + let raw = context + .view_call_function(encode_view_call_function_args( test_addr, - "returnSomeFunds()", - vec![], - ); - let _ = context.meta_call_function(meta_tx.clone()).unwrap(); - let signer_addr = public_key_to_address(signer.public_key); - assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); - assert_eq!(context.get_balance(signer_addr.0.to_vec()).unwrap(), U256::from(50)); - assert_eq!( - context.meta_call_function(meta_tx).unwrap_err().to_string(), - "EvmError(InvalidNonce)" - ); - } + test_addr, + U256::from(10u128.pow(27)), + input, + )) + .unwrap(); + assert_eq!(raw[12..32], test_addr.0); +} + +#[test] +fn test_solidity_accurate_storage_on_selfdestruct() { + let (mut fake_external, vm_config, fees_config) = setup(); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + assert_eq!( + context.deposit(near_account_id_to_evm_address(&accounts(1)).0.to_vec()).unwrap(), + U256::from(100) + ); + + // Deploy CREATE2 Factory + let mut context = create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 0); + let factory_addr = context.deploy_code(hex::decode(&FACTORY_TEST).unwrap()).unwrap(); + + // Deploy + SelfDestruct in one transaction + let salt = H256([0u8; 32]); + let destruct_code = hex::decode(&DESTRUCT_TEST).unwrap(); + let input = create2factory::functions::test_double_deploy::call(salt, destruct_code.clone()).0; + let raw = context.call_function(encode_call_function_args(factory_addr, input)).unwrap(); + assert!(create2factory::functions::test_double_deploy::decode_output(&raw).unwrap()); +} - #[test] - #[ignore] - fn test_meta_call_sig_recover() { - let meta_tx = [ +#[test] +fn test_meta_call() { + let (mut fake_external, test_addr, vm_config, fees_config) = setup_and_deploy_test(); + let signer = InMemorySigner::from_random("doesnt".to_string(), KeyType::SECP256K1); + let mut context = + create_context(&mut fake_external, &vm_config, &fees_config, accounts(1), 100); + let meta_tx = encode_meta_call_function_args( + &signer, + CHAIN_ID, + U256::from(0), + U256::from(0), + Address::from_slice(&[0u8; 20]), + test_addr, + "returnSomeFunds()", + vec![], + ); + let _ = context.meta_call_function(meta_tx.clone()).unwrap(); + let signer_addr = public_key_to_address(signer.public_key); + assert_eq!(context.get_balance(test_addr.0.to_vec()).unwrap(), U256::from(150)); + assert_eq!(context.get_balance(signer_addr.0.to_vec()).unwrap(), U256::from(50)); + assert_eq!( + context.meta_call_function(meta_tx).unwrap_err().to_string(), + "EvmError(InvalidNonce)" + ); +} + +#[test] +#[ignore] +fn test_meta_call_sig_recover() { + let meta_tx = [ // signature: 65 bytes hex::decode("1cb6f28f29524cf3ae5ce49f364b5ad798af5dd8ec3563744dc62792735ce5e222285df1e91c416e430d0a38ea3b51d6677e337e1b0684d7618f5a00a26a2ee21c").unwrap(), // nonce: 14 @@ -321,8 +303,7 @@ mod tests { // arguments u256_to_arr(&U256::from(9)).to_vec(), ].concat(); - let domain_separator = near_erc721_domain(U256::from(CHAIN_ID)); - let result = parse_meta_call(&domain_separator, &"evm".to_string(), meta_tx).unwrap(); - assert_eq!(result.sender.to_hex(), "2941022347348828A24a5ff33c775D67691681e9"); - } + let domain_separator = near_erc721_domain(U256::from(CHAIN_ID)); + let result = parse_meta_call(&domain_separator, &"evm".to_string(), meta_tx).unwrap(); + assert_eq!(result.sender.to_hex(), "2941022347348828A24a5ff33c775D67691681e9"); } diff --git a/runtime/near-evm-runner/tests/utils.rs b/runtime/near-evm-runner/tests/utils/mod.rs similarity index 100% rename from runtime/near-evm-runner/tests/utils.rs rename to runtime/near-evm-runner/tests/utils/mod.rs diff --git a/runtime/runtime/tests/runtime_group_tools/random_config.rs b/runtime/runtime/tests/runtime_group_tools/random_config.rs index 5f260210aeb..4e4353bd088 100644 --- a/runtime/runtime/tests/runtime_group_tools/random_config.rs +++ b/runtime/runtime/tests/runtime_group_tools/random_config.rs @@ -1,8 +1,12 @@ use near_runtime_fees::{ - AccessKeyCreationConfig, ActionCreationConfig, DataReceiptCreationConfig, EvmBls12ConstOpCost, - EvmBn128PairingCost, EvmCostConfig, EvmLinearCost, EvmModexpCost, EvmPrecompileCostConfig, Fee, + AccessKeyCreationConfig, ActionCreationConfig, DataReceiptCreationConfig, Fee, RuntimeFeesConfig, StorageUsageConfig, }; +#[cfg(feature = "protocol_feature_evm")] +use near_runtime_fees::{ + EvmBls12ConstOpCost, EvmBn128PairingCost, EvmCostConfig, EvmLinearCost, EvmModexpCost, + EvmPrecompileCostConfig, +}; use node_runtime::config::RuntimeConfig; use num_rational::Rational; use rand::{thread_rng, RngCore}; From b174d8cb42e49385e7eec409bae938c72edb116f Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Thu, 19 Nov 2020 14:25:45 -0800 Subject: [PATCH 70/82] Remove multiple EVM accounts. Disable meta-tx --- runtime/near-evm-runner/src/runner.rs | 34 +---------------- runtime/near-evm-runner/src/types.rs | 5 +-- runtime/near-runtime-utils/src/lib.rs | 2 +- test-utils/testlib/src/standard_evm_cases.rs | 39 -------------------- tests/test_cases_runtime.rs | 7 ---- 5 files changed, 5 insertions(+), 82 deletions(-) diff --git a/runtime/near-evm-runner/src/runner.rs b/runtime/near-evm-runner/src/runner.rs index 8e0d4906c8a..5bfdf267c65 100644 --- a/runtime/near-evm-runner/src/runner.rs +++ b/runtime/near-evm-runner/src/runner.rs @@ -4,7 +4,7 @@ use evm::CreateContractAddress; use vm::{ContractCreateResult, MessageCallResult}; use near_runtime_fees::{EvmCostConfig, RuntimeFeesConfig}; -use near_runtime_utils::{is_account_id_64_len_hex, is_valid_sub_account_id}; +use near_runtime_utils::is_account_id_64_len_hex; use near_vm_errors::{EvmError, FunctionCallError, VMError}; use near_vm_logic::gas_counter::GasCounter; use near_vm_logic::types::{AccountId, Balance, Gas, ReturnData, StorageUsage}; @@ -391,35 +391,6 @@ impl<'a> EvmContext<'a> { self.transfer_balance(&sender, &Address::from(args.address), amount) } - /// Creates new EVM under given sub account and sends attached balance to it. - /// If account id given is not a valid subaccount of the current account, will return InvalidSubAccount. - /// If balance attached was not enough, will return InsufficientDeposit. - pub fn create_evm(&mut self, args: Vec) -> Result<()> { - let new_account_id = std::str::from_utf8(&args) - .map_err(|_| VMLogicError::EvmError(EvmError::ArgumentParseError))? - .to_string(); - if !is_valid_sub_account_id(&self.account_id, &new_account_id) { - return Err(VMLogicError::EvmError(EvmError::InvalidSubAccount)); - } - if self.attached_deposit < self.fees_config.evm_deposit { - return Err(VMLogicError::EvmError(EvmError::InsufficientDeposit)); - } - self.current_amount = self - .current_amount - .checked_sub(self.attached_deposit) - .ok_or_else(|| VMLogicError::EvmError(EvmError::InsufficientFunds))?; - let receipt_index = self.ext.create_receipt(vec![], new_account_id.clone())?; - self.pay_gas_for_new_receipt(false, &[])?; - self.gas_counter.pay_action_base( - &self.fees_config.action_creation_config.create_account_cost, - false, - ActionCosts::create_account, - )?; - self.ext.append_action_create_account(receipt_index)?; - self.pay_gas_for_transfer(&new_account_id)?; - self.ext.append_action_transfer(receipt_index, self.attached_deposit) - } - /// A helper function to pay gas fee for creating a new receipt without actions. /// # Args: /// * `sir`: whether contract call is addressed to itself; @@ -609,6 +580,7 @@ pub fn run_evm( context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); r } + // TODO: MetaCalls are currently disabled Method::MetaCall => { let r = context.meta_call_function(args); context.pay_gas_from_evm_gas(EvmOpForGas::Funcall).unwrap(); @@ -619,8 +591,6 @@ pub fn run_evm( } Method::Withdraw => context.withdraw(args).map(|_| vec![]), Method::Transfer => context.transfer(args).map(|_| vec![]), - // TODO: Disable creation of new `evm` accounts. - Method::Create => context.create_evm(args).map(|_| vec![]), // View methods. Method::ViewCall => { let r = context.view_call_function(args); diff --git a/runtime/near-evm-runner/src/types.rs b/runtime/near-evm-runner/src/types.rs index 7b6912aedbd..04dc7b16db8 100644 --- a/runtime/near-evm-runner/src/types.rs +++ b/runtime/near-evm-runner/src/types.rs @@ -21,7 +21,6 @@ pub enum Method { Deposit, Withdraw, Transfer, - Create, // View methods. ViewCall, GetCode, @@ -36,11 +35,11 @@ impl Method { // Change the state methods. "deploy_code" => Self::DeployCode, "call_function" | "call" => Self::Call, - "meta_call" => Self::MetaCall, + // TODO: Meta calls are temporary disabled. + // "meta_call" => Self::MetaCall, "deposit" => Self::Deposit, "withdraw" => Self::Withdraw, "transfer" => Self::Transfer, - "create" => Self::Create, // View methods. "view_function_call" | "view" => Self::ViewCall, "get_code" => Self::GetCode, diff --git a/runtime/near-runtime-utils/src/lib.rs b/runtime/near-runtime-utils/src/lib.rs index 2d80ed0d5bf..9298cb35e25 100644 --- a/runtime/near-runtime-utils/src/lib.rs +++ b/runtime/near-runtime-utils/src/lib.rs @@ -68,7 +68,7 @@ pub fn is_account_id_64_len_hex(account_id: &str) -> bool { /// Returns true if the account ID is suppose to be EVM machine. pub fn is_account_evm(account_id: &str) -> bool { - account_id == "evm" || account_id.ends_with(".evm") + account_id == "evm" } #[cfg(test)] diff --git a/test-utils/testlib/src/standard_evm_cases.rs b/test-utils/testlib/src/standard_evm_cases.rs index dd4100ff9a1..02bf257e3ec 100644 --- a/test-utils/testlib/src/standard_evm_cases.rs +++ b/test-utils/testlib/src/standard_evm_cases.rs @@ -96,42 +96,3 @@ pub fn test_evm_deploy_call(node: impl Node) { .unwrap(); assert_eq!(result.len(), 0); } - -pub fn test_sub_evm(node: impl Node) { - let node_user = node.user(); - assert_eq!( - node_user.view_account(&"sub.evm".to_string()).unwrap_err().to_string(), - "account sub.evm does not exist while viewing" - ); - assert_eq!( - node_user - .function_call( - alice_account(), - evm_account(), - "create", - b"sub.evm".to_vec(), - 10u64.pow(14), - 0, - ) - .unwrap() - .status - .as_failure() - .unwrap() - .to_string(), - "Action #0: EVM: InsufficientDeposit" - ); - node_user - .function_call( - alice_account(), - evm_account(), - "create", - b"sub.evm".to_vec(), - 10u64.pow(14), - 10u128.pow(27), - ) - .unwrap() - .status - .as_success() - .unwrap(); - assert_eq!(node_user.view_account(&"sub.evm".to_string()).unwrap().amount, 10u128.pow(27)); -} diff --git a/tests/test_cases_runtime.rs b/tests/test_cases_runtime.rs index 52aecb235f8..139290b4413 100644 --- a/tests/test_cases_runtime.rs +++ b/tests/test_cases_runtime.rs @@ -312,11 +312,4 @@ mod test { let node = create_runtime_node(); test_evm_deploy_call(node); } - - #[cfg(feature = "protocol_feature_evm")] - #[test] - fn test_sub_evm_runtime() { - let node = create_runtime_node(); - test_sub_evm(node); - } } From 14fccf1837642e6ca9fb094a6813a581708af707 Mon Sep 17 00:00:00 2001 From: Arto Bendiken Date: Wed, 25 Nov 2020 19:22:13 +0200 Subject: [PATCH 71/82] Added test cases for standard EVM precompiles. (#3628) (#3633) The tests can be run with: ```bash cargo test --package nearcore --test test_cases_runtime test::test_evm_call_standard_precompiles_runtime --features protocol_feature_evm,nightly_protocol_features -- --exact ``` --- .../tests/build/StandardPrecompiles.abi | 137 +++++++++++ .../tests/build/StandardPrecompiles.bin | 1 + .../tests/contracts/StandardPrecompiles.sol | 222 ++++++++++++++++++ test-utils/testlib/src/standard_evm_cases.rs | 34 ++- tests/test_cases_runtime.rs | 9 + 5 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 runtime/near-evm-runner/tests/build/StandardPrecompiles.abi create mode 100644 runtime/near-evm-runner/tests/build/StandardPrecompiles.bin create mode 100644 runtime/near-evm-runner/tests/contracts/StandardPrecompiles.sol diff --git a/runtime/near-evm-runner/tests/build/StandardPrecompiles.abi b/runtime/near-evm-runner/tests/build/StandardPrecompiles.abi new file mode 100644 index 00000000000..b67026e373c --- /dev/null +++ b/runtime/near-evm-runner/tests/build/StandardPrecompiles.abi @@ -0,0 +1,137 @@ +[ + { + "inputs" : [], + "type" : "constructor", + "stateMutability" : "payable" + }, + { + "type" : "function", + "inputs" : [], + "name" : "test_all", + "stateMutability" : "view", + "outputs" : [ + { + "type" : "bool", + "internalType" : "bool", + "name" : "" + } + ] + }, + { + "outputs" : [ + { + "type" : "bool", + "internalType" : "bool", + "name" : "" + } + ], + "stateMutability" : "view", + "name" : "test_blake2f", + "inputs" : [], + "type" : "function" + }, + { + "inputs" : [], + "type" : "function", + "stateMutability" : "view", + "name" : "test_ecadd", + "outputs" : [ + { + "name" : "", + "internalType" : "bool", + "type" : "bool" + } + ] + }, + { + "inputs" : [], + "type" : "function", + "stateMutability" : "view", + "name" : "test_ecmul", + "outputs" : [ + { + "internalType" : "bool", + "type" : "bool", + "name" : "" + } + ] + }, + { + "type" : "function", + "inputs" : [], + "name" : "test_ecpair", + "stateMutability" : "view", + "outputs" : [ + { + "type" : "bool", + "internalType" : "bool", + "name" : "" + } + ] + }, + { + "type" : "function", + "inputs" : [], + "outputs" : [ + { + "internalType" : "bool", + "type" : "bool", + "name" : "" + } + ], + "stateMutability" : "pure", + "name" : "test_ecrecover" + }, + { + "inputs" : [], + "type" : "function", + "outputs" : [ + { + "name" : "", + "type" : "bool", + "internalType" : "bool" + } + ], + "name" : "test_identity", + "stateMutability" : "view" + }, + { + "outputs" : [ + { + "type" : "bool", + "internalType" : "bool", + "name" : "" + } + ], + "stateMutability" : "view", + "name" : "test_modexp", + "inputs" : [], + "type" : "function" + }, + { + "stateMutability" : "pure", + "name" : "test_ripemd160", + "outputs" : [ + { + "type" : "bool", + "internalType" : "bool", + "name" : "" + } + ], + "inputs" : [], + "type" : "function" + }, + { + "stateMutability" : "pure", + "name" : "test_sha256", + "outputs" : [ + { + "type" : "bool", + "internalType" : "bool", + "name" : "" + } + ], + "inputs" : [], + "type" : "function" + } +] diff --git a/runtime/near-evm-runner/tests/build/StandardPrecompiles.bin b/runtime/near-evm-runner/tests/build/StandardPrecompiles.bin new file mode 100644 index 00000000000..0648ee6a8cd --- /dev/null +++ b/runtime/near-evm-runner/tests/build/StandardPrecompiles.bin @@ -0,0 +1 @@ +60806040526113b5806100136000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c8063aefff86311610066578063aefff86314610143578063d06d2a3114610163578063d7d4430414610183578063da726c1b146101a3578063ff71b530146101c35761009e565b8063166f2a2f146100a35780631d82afc7146100c35780633ae57cb6146100e357806341d5e54514610103578063a7465fca14610123575b600080fd5b6100ab6101e3565b60405180821515815260200191505060405180910390f35b6100cb610303565b60405180821515815260200191505060405180910390f35b6100eb61035e565b60405180821515815260200191505060405180910390f35b61010b6103d5565b60405180821515815260200191505060405180910390f35b61012b6104b9565b60405180821515815260200191505060405180910390f35b61014b61090c565b60405180821515815260200191505060405180910390f35b61016b61097b565b60405180821515815260200191505060405180910390f35b61018b6109e2565b60405180821515815260200191505060405180910390f35b6101ab610a4c565b60405180821515815260200191505060405180910390f35b6101cb610caf565b60405180821515815260200191505060405180910390f35b60006101ed611136565b6102857f18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc960001b7f063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f3726660001b7f07c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed60001b7f06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d760001b610ce5565b90507f2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee20283970360001b816000600281106102b857fe5b60200201511480156102fd57507f301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c91560001b816001600281106102f657fe5b6020020151145b91505090565b600060606040518060400160405280602081526020017f11111111111111111111111111111111111111111111111111111111111111118152509050808051906020012061035082610d40565b805190602001201491505090565b60007fe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556002604051806000019050602060405180830381855afa1580156103a9573d6000803e3d6000fd5b5050506040513d60208110156103be57600080fd5b810190808051906020019092919050505014905090565b60006103df611136565b61043b7f2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb760001b7f21611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb20460001b6711138ce750fa15c260001b610dc0565b90507f070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c60001b8160006002811061046e57fe5b60200201511480156104b357507f031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc60001b816001600281106104ac57fe5b6020020151145b91505090565b60006104c361090c565b610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f6572726f6e656f75732065637265636f76657220707265636f6d70696c65000081525060200191505060405180910390fd5b61053d61035e565b6105af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f6572726f6e656f75732073686132353620707265636f6d70696c65000000000081525060200191505060405180910390fd5b6105b76109e2565b610629576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f6572726f6e656f757320726970656d6431363020707265636f6d70696c65000081525060200191505060405180910390fd5b610631610303565b6106a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f6572726f6e656f7573206964656e7469747920707265636f6d70696c6500000081525060200191505060405180910390fd5b6106ab61097b565b61071d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f6572726f6e656f7573206d6f6465787020707265636f6d70696c65000000000081525060200191505060405180910390fd5b6107256101e3565b610797576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f6572726f6e656f757320656361646420707265636f6d70696c6500000000000081525060200191505060405180910390fd5b61079f6103d5565b610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f6572726f6e656f75732065636d756c20707265636f6d70696c6500000000000081525060200191505060405180910390fd5b610819610caf565b61088b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f6572726f6e656f75732065637061697220707265636f6d70696c65000000000081525060200191505060405180910390fd5b610893610a4c565b610905576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f6572726f6e656f757320626c616b65326620707265636f6d70696c650000000081525060200191505060405180910390fd5b6001905090565b6000807f11111111111111111111111111111111111111111111111111111111111111119050606060405180608001604052806041815260200161133f6041913990506000731563915e194d8cfba1943570603f7606a31155089050610973838383610e14565b935050505090565b6000806003905060007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e905060007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f905060016109d9848484610e6e565b14935050505090565b60007f9c1185a5c5e9fc54612808977ee8f548b2258d310000000000000000000000006003604051806000019050602060405180830381855afa158015610a2d573d6000803e3d6000fd5b5050506040515160601b6bffffffffffffffffffffffff191614905090565b600080600c9050610a5b611136565b7f48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa581600060028110610a8957fe5b6020020181815250507fd182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b81600160028110610ac057fe5b602002018181525050610ad1611158565b7f616263000000000000000000000000000000000000000000000000000000000081600060048110610aff57fe5b602002018181525050600081600160048110610b1757fe5b602002018181525050600081600260048110610b2f57fe5b602002018181525050600081600360048110610b4757fe5b602002018181525050610b5861117a565b7f030000000000000000000000000000000000000000000000000000000000000081600060028110610b8657fe5b602002019077ffffffffffffffffffffffffffffffffffffffffffffffff1916908177ffffffffffffffffffffffffffffffffffffffffffffffff191681525050600081600160028110610bd657fe5b602002019077ffffffffffffffffffffffffffffffffffffffffffffffff1916908177ffffffffffffffffffffffffffffffffffffffffffffffff191681525050600060019050610c25611136565b610c328686868686610ec1565b90507fba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d181600060028110610c6257fe5b6020020151148015610ca457507f7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd400992381600160028110610c9d57fe5b6020020151145b965050505050505090565b600080610cd6604051806101a0016040528061018081526020016111bf6101809139611039565b9050600160001b811491505090565b610ced611136565b610cf5611158565b604051806080016040528087815260200186815260200185815260200184815250905060408260808360065afa8060008114610d3057610d35565b600080fd5b505050949350505050565b606080825167ffffffffffffffff81118015610d5b57600080fd5b506040519080825280601f01601f191660200182016040528015610d8e5781602001600182028036833780820191505090505b50905082518060208301826020870160045afa8060008114610daf57610db4565b600080fd5b50505080915050919050565b610dc8611136565b610dd061119c565b604051806060016040528086815260200185815260200184815250905060408260608360075afa8060008114610e0557610e0a565b600080fd5b5050509392505050565b6000806000610e238686611086565b8092508193505050818015610e6357508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b925050509392505050565b600060405160208152602080820152602060408201528460608201528360808201528260a082015260208160c08360055afa8060008114610eb25782519350610eb7565b600080fd5b5050509392505050565b610ec9611136565b610ed1611136565b60608787600060028110610ee157fe5b602002015188600160028110610ef357fe5b602002015188600060048110610f0557fe5b602002015189600160048110610f1757fe5b60200201518a600260048110610f2957fe5b60200201518b600360048110610f3b57fe5b60200201518b600060028110610f4d57fe5b60200201518c600160028110610f5f57fe5b60200201518c604051602001808b63ffffffff1660e01b81526004018a81526020018981526020018881526020018781526020018681526020018581526020018477ffffffffffffffffffffffffffffffffffffffffffffffff191681526008018377ffffffffffffffffffffffffffffffffffffffffffffffff1916815260080182151560f81b81526001019a5050505050505050505050604051602081830303815290604052905060408260d56020840160095afa806000811461102457611029565b600080fd5b5050819250505095945050505050565b60008082519050600060c0828161104c57fe5b061461105757600080fd5b604051602081836020870160085afa8060008114611078578251945061107d565b600080fd5b50505050919050565b600080604183511461109e576000809150915061112f565b60008060006020860151925060408601519150606086015160001a9050600060018883868660405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015611117573d6000803e3d6000fd5b50505060206040510351905060018195509550505050505b9250929050565b6040518060400160405280600290602082028036833780820191505090505090565b6040518060800160405280600490602082028036833780820191505090505090565b6040518060400160405280600290602082028036833780820191505090505090565b604051806060016040528060039060208202803683378082019150509050509056fe1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daab9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b69812ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb6447441ba26469706673582212203acf67adc69694b9cae057a502d5c1741f3f0e71a7bd73034e88327c199996da64736f6c63430007030033 \ No newline at end of file diff --git a/runtime/near-evm-runner/tests/contracts/StandardPrecompiles.sol b/runtime/near-evm-runner/tests/contracts/StandardPrecompiles.sol new file mode 100644 index 00000000000..dbfac7b4395 --- /dev/null +++ b/runtime/near-evm-runner/tests/contracts/StandardPrecompiles.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.7.0; + +//import "hardhat/console.sol"; + +contract StandardPrecompiles { + constructor() payable { + //console.log("Deploying StandardPrecompiles"); + } + + function test_all() public view returns(bool) { + require(test_ecrecover(), "erroneous ecrecover precompile"); + require(test_sha256(), "erroneous sha256 precompile"); + require(test_ripemd160(), "erroneous ripemd160 precompile"); + require(test_identity(), "erroneous identity precompile"); + require(test_modexp(), "erroneous modexp precompile"); + require(test_ecadd(), "erroneous ecadd precompile"); + require(test_ecmul(), "erroneous ecmul precompile"); + require(test_ecpair(), "erroneous ecpair precompile"); + require(test_blake2f(), "erroneous blake2f precompile"); + return true; + } + + // See: https://docs.soliditylang.org/en/develop/units-and-global-variables.html#mathematical-and-cryptographic-functions + // See: https://etherscan.io/address/0x0000000000000000000000000000000000000001 + function test_ecrecover() public pure returns(bool) { + bytes32 hash = hex"1111111111111111111111111111111111111111111111111111111111111111"; + bytes memory sig = hex"b9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b69812ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb6447441b"; + address signer = 0x1563915e194D8CfBA1943570603F7606A3115508; + return ecverify(hash, sig, signer); + } + + // See: https://docs.soliditylang.org/en/develop/units-and-global-variables.html#mathematical-and-cryptographic-functions + // See: https://etherscan.io/address/0x0000000000000000000000000000000000000002 + function test_sha256() public pure returns(bool) { + return sha256("") == hex"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + } + + // See: https://docs.soliditylang.org/en/develop/units-and-global-variables.html#mathematical-and-cryptographic-functions + // See: https://etherscan.io/address/0x0000000000000000000000000000000000000003 + function test_ripemd160() public pure returns(bool) { + return ripemd160("") == hex"9c1185a5c5e9fc54612808977ee8f548b2258d31"; + } + + // See: https://etherscan.io/address/0x0000000000000000000000000000000000000004 + function test_identity() public view returns(bool) { + bytes memory data = hex"1111111111111111111111111111111111111111111111111111111111111111"; + return keccak256(datacopy(data)) == keccak256(data); + } + + // See: https://eips.ethereum.org/EIPS/eip-198 + // See: https://etherscan.io/address/0x0000000000000000000000000000000000000005 + function test_modexp() public view returns(bool) { + uint256 base = 3; + uint256 exponent = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e; + uint256 modulus = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f; + return modexp(base, exponent, modulus) == 1; + } + + // See: https://eips.ethereum.org/EIPS/eip-196 + // See: https://etherscan.io/address/0x0000000000000000000000000000000000000006 + function test_ecadd() public view returns(bool) { + // alt_bn128_add_chfast1: + bytes32[2] memory result; + result = ecadd( + 0x18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9, + 0x063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266, + 0x07c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed, + 0x06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7 + ); + return result[0] == 0x2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703 && result[1] == 0x301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915; + } + + // See: https://eips.ethereum.org/EIPS/eip-196 + // See: https://etherscan.io/address/0x0000000000000000000000000000000000000007 + function test_ecmul() public view returns(bool) { + // alt_bn128_mul_chfast1: + bytes32[2] memory result; + result = ecmul( + 0x2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb7, + 0x21611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204, + 0x00000000000000000000000000000000000000000000000011138ce750fa15c2 + ); + return result[0] == 0x070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c && result[1] == 0x031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc; + } + + // See: https://eips.ethereum.org/EIPS/eip-197 + // See: https://etherscan.io/address/0x0000000000000000000000000000000000000008 + function test_ecpair() public view returns(bool) { + // alt_bn128_pairing_jeff1: + bytes32 result = ecpair(hex"1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa"); + return result == 0x0000000000000000000000000000000000000000000000000000000000000001; + } + + // See: https://eips.ethereum.org/EIPS/eip-152 + // See: https://etherscan.io/address/0x0000000000000000000000000000000000000009 + function test_blake2f() public view returns(bool) { + uint32 rounds = 12; + bytes32[2] memory h; + h[0] = hex"48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5"; + h[1] = hex"d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b"; + bytes32[4] memory m; + m[0] = hex"6162630000000000000000000000000000000000000000000000000000000000"; + m[1] = hex"0000000000000000000000000000000000000000000000000000000000000000"; + m[2] = hex"0000000000000000000000000000000000000000000000000000000000000000"; + m[3] = hex"0000000000000000000000000000000000000000000000000000000000000000"; + bytes8[2] memory t; + t[0] = hex"03000000"; + t[1] = hex"00000000"; + bool f = true; + bytes32[2] memory result = blake2f(rounds, h, m, t, f); + return result[0] == hex"ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1" && result[1] == hex"7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"; + } + + function ecverify(bytes32 hash, bytes memory sig, address signer) private pure returns (bool) { + bool ok; + address addr; + (ok, addr) = ecrecovery(hash, sig); + return ok && addr == signer; + } + + function ecrecovery(bytes32 hash, bytes memory sig) private pure returns (bool, address) { + if (sig.length != 65) + return (false, address(0)); + + bytes32 r; + bytes32 s; + uint8 v; + assembly { + r := mload(add(sig, 32)) + s := mload(add(sig, 64)) + v := byte(0, mload(add(sig, 96))) + } + + address addr = ecrecover(hash, v, r, s); + return (true, addr); + } + + function datacopy(bytes memory input) private view returns (bytes memory) { + bytes memory output = new bytes(input.length); + assembly { + let len := mload(input) + let ok := staticcall(gas(), 0x04, add(input, 32), len, add(output, 32), len) + switch ok + case 0 { + revert(0, 0) + } + } + return output; + } + + function modexp(uint256 base, uint256 exponent, uint256 modulus) private view returns (uint256 output) { + assembly { + let ptr := mload(0x40) + mstore(ptr, 32) + mstore(add(ptr, 0x20), 32) + mstore(add(ptr, 0x40), 32) + mstore(add(ptr, 0x60), base) + mstore(add(ptr, 0x80), exponent) + mstore(add(ptr, 0xA0), modulus) + let ok := staticcall(gas(), 0x05, ptr, 0xC0, ptr, 0x20) + switch ok + case 0 { + revert(0, 0) + } + default { + output := mload(ptr) + } + } + } + + function ecadd(bytes32 ax, bytes32 ay, bytes32 bx, bytes32 by) private view returns (bytes32[2] memory output) { + bytes32[4] memory input = [ax, ay, bx, by]; + assembly { + let ok := staticcall(gas(), 0x06, input, 0x80, output, 0x40) + switch ok + case 0 { + revert(0, 0) + } + } + } + + function ecmul(bytes32 x, bytes32 y, bytes32 scalar) private view returns (bytes32[2] memory output) { + bytes32[3] memory input = [x, y, scalar]; + assembly { + let ok := staticcall(gas(), 0x07, input, 0x60, output, 0x40) + switch ok + case 0 { + revert(0, 0) + } + } + } + + function ecpair(bytes memory input) private view returns (bytes32 output) { + uint256 len = input.length; + require(len % 192 == 0); + assembly { + let ptr := mload(0x40) + let ok := staticcall(gas(), 0x08, add(input, 32), len, ptr, 0x20) + switch ok + case 0 { + revert(0, 0) + } + default { + output := mload(ptr) + } + } + } + + function blake2f(uint32 rounds, bytes32[2] memory h, bytes32[4] memory m, bytes8[2] memory t, bool f) private view returns (bytes32[2] memory) { + bytes32[2] memory output; + bytes memory args = abi.encodePacked(rounds, h[0], h[1], m[0], m[1], m[2], m[3], t[0], t[1], f); + assembly { + let ok := staticcall(gas(), 0x09, add(args, 32), 0xD5, output, 0x40) + switch ok + case 0 { + revert(0, 0) + } + } + return output; + } +} diff --git a/test-utils/testlib/src/standard_evm_cases.rs b/test-utils/testlib/src/standard_evm_cases.rs index 02bf257e3ec..2371fc89056 100644 --- a/test-utils/testlib/src/standard_evm_cases.rs +++ b/test-utils/testlib/src/standard_evm_cases.rs @@ -9,6 +9,7 @@ use near_evm_runner::utils::{ }; use_contract!(cryptozombies, "../../runtime/near-evm-runner/tests/build/zombieAttack.abi"); +use_contract!(precompiles, "../../runtime/near-evm-runner/tests/build/StandardPrecompiles.abi"); pub fn test_evm_deploy_call(node: impl Node) { let node_user = node.user(); @@ -26,8 +27,9 @@ pub fn test_evm_deploy_call(node: impl Node) { let result = node_user.view_call(&evm_account(), "get_balance", &contract_id).unwrap(); assert_eq!(result.result, u256_to_arr(&U256::from(10)).to_vec()); - let (input, _decoder) = cryptozombies::functions::create_random_zombie::call("test"); let contract_id = address_from_arr(&contract_id); + + let (input, _decoder) = cryptozombies::functions::create_random_zombie::call("test"); let args = encode_call_function_args(contract_id, input); assert_eq!( node_user @@ -96,3 +98,33 @@ pub fn test_evm_deploy_call(node: impl Node) { .unwrap(); assert_eq!(result.len(), 0); } + +pub fn test_evm_call_standard_precompiles(node: impl Node) { + let node_user = node.user(); + let bytes = hex::decode( + include_bytes!("../../../runtime/near-evm-runner/tests/build/StandardPrecompiles.bin") + .to_vec(), + ) + .unwrap(); + + let contract_id = node_user + .function_call(alice_account(), evm_account(), "deploy_code", bytes, 10u64.pow(14), 0) + .unwrap() + .status + .as_success_decoded() + .unwrap(); + let contract_id = address_from_arr(&contract_id); + + let alice_address = near_evm_runner::utils::near_account_id_to_evm_address(&alice_account()); + + let (input, _decoder) = precompiles::functions::test_all::call(); + let args = encode_view_call_function_args(alice_address, contract_id, U256::zero(), input); + let bytes = node_user + .function_call(alice_account(), evm_account(), "view", args.clone(), 10u64.pow(14), 0) + .unwrap() + .status + .as_success_decoded() + .unwrap(); + let res = precompiles::functions::test_all::decode_output(&bytes).unwrap(); + assert_eq!(res, true); +} diff --git a/tests/test_cases_runtime.rs b/tests/test_cases_runtime.rs index 139290b4413..c1305c4d3f0 100644 --- a/tests/test_cases_runtime.rs +++ b/tests/test_cases_runtime.rs @@ -306,10 +306,19 @@ mod test { test_smart_contract_free(node); } + // cargo test --package nearcore --test test_cases_runtime test::test_evm_deploy_call_runtime --features protocol_feature_evm,nightly_protocol_features -- --exact --nocapture #[cfg(feature = "protocol_feature_evm")] #[test] fn test_evm_deploy_call_runtime() { let node = create_runtime_node(); test_evm_deploy_call(node); } + + // cargo test --package nearcore --test test_cases_runtime test::test_evm_call_standard_precompiles_runtime --features protocol_feature_evm,nightly_protocol_features -- --exact --nocapture + #[cfg(feature = "protocol_feature_evm")] + #[test] + fn test_evm_call_standard_precompiles_runtime() { + let node = create_runtime_node(); + test_evm_call_standard_precompiles(node); + } } From 084aa481de4a75cf077c5bc62691a8c237030b36 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Mon, 30 Nov 2020 09:56:00 -0800 Subject: [PATCH 72/82] Disable primitive-types no-default --- core/primitives/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index 8b49ec26511..9563cd95d7e 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -24,7 +24,7 @@ reed-solomon-erasure = "4" jemallocator = { version = "0.3", optional = true } hex = "0.4" num-rational = "0.2.4" -primitive-types = { version = "0.7", default-features = false } +primitive-types = "0.7" borsh = "0.7.1" From b07d0dc91ed26ea370bc658253e208915dfb1460 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Mon, 30 Nov 2020 10:21:15 -0800 Subject: [PATCH 73/82] Add some to duplicates to ignore --- Cargo.lock | 2 +- chain/epoch_manager/Cargo.toml | 2 +- deny.toml | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 17bfb27a861..a1e2a21221c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2920,7 +2920,7 @@ dependencies = [ "near-primitives", "near-store", "num-rational 0.2.4", - "primitive-types 0.6.2", + "primitive-types 0.7.2", "rand 0.6.5", "rand 0.7.3", "serde", diff --git a/chain/epoch_manager/Cargo.toml b/chain/epoch_manager/Cargo.toml index 6e21f16ec7f..43887f343f7 100644 --- a/chain/epoch_manager/Cargo.toml +++ b/chain/epoch_manager/Cargo.toml @@ -15,7 +15,7 @@ rand = "0.7" serde = { version = "1", features = [ "derive" ] } serde_json = "1" smart-default = "0.6" -primitive-types = "0.6" +primitive-types = "0.7" num-rational = "0.2.4" chrono = { version = "0.4.4", optional = true} diff --git a/deny.toml b/deny.toml index 30bc2d2f426..ee2ec3f8b8a 100644 --- a/deny.toml +++ b/deny.toml @@ -81,4 +81,6 @@ skip = [ { name = "smallvec", version = "=0.6.13" }, { name = "syn", version = "=0.15.44" }, { name = "unicode-xid", version = "=0.1.0" }, + { name = "primitive-types", version = "=0.6.2" }, + { name = "fixed-hash", version = "=0.5.2" }, ] From 8c06f9a44af12d1bb29764b254638b5fee046176 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Mon, 30 Nov 2020 10:38:00 -0800 Subject: [PATCH 74/82] Bump sha --- runtime/near-evm-runner/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index fcff990ef54..fb0731d2686 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -18,7 +18,7 @@ num-traits = "0.2.12" enum-primitive-derive = "0.2" sha2 = ">=0.8,<0.10" -sha3 = "0.8" +sha3 = ">=0.8,<0.10" rlp = "0.4.2" keccak-hash = "0.4.1" ripemd160 = "0.9.0" From 7fdef601716c417c7546ca040aa4fad494fd4230 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Mon, 30 Nov 2020 12:01:49 -0800 Subject: [PATCH 75/82] Remove Unknown EVMError. Fix sha3 --- Cargo.lock | 17 ++--------------- runtime/near-evm-runner/Cargo.toml | 2 +- runtime/near-evm-runner/src/runner.rs | 5 +++-- runtime/near-vm-errors/src/lib.rs | 2 -- 4 files changed, 6 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1e2a21221c..abf3b1c7cef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2960,7 +2960,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.9.1", - "sha3 0.8.2", + "sha3", "vm", ] @@ -3272,7 +3272,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.9.1", - "sha3 0.9.1", + "sha3", ] [[package]] @@ -4787,19 +4787,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "sha3" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -dependencies = [ - "block-buffer 0.7.3", - "byte-tools", - "digest 0.8.1", - "keccak", - "opaque-debug 0.2.3", -] - [[package]] name = "sha3" version = "0.9.1" diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index fb0731d2686..9b229e9462d 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -18,7 +18,7 @@ num-traits = "0.2.12" enum-primitive-derive = "0.2" sha2 = ">=0.8,<0.10" -sha3 = ">=0.8,<0.10" +sha3 = "0.9" rlp = "0.4.2" keccak-hash = "0.4.1" ripemd160 = "0.9.0" diff --git a/runtime/near-evm-runner/src/runner.rs b/runtime/near-evm-runner/src/runner.rs index 5bfdf267c65..5b0a7826064 100644 --- a/runtime/near-evm-runner/src/runner.rs +++ b/runtime/near-evm-runner/src/runner.rs @@ -625,9 +625,10 @@ pub fn run_evm( Err(VMLogicError::InconsistentStateError(err)) => { (None, Some(VMError::InconsistentStateError(err))) } - Err(_) => { - (None, Some(VMError::FunctionCallError(FunctionCallError::EvmError(EvmError::Unknown)))) + Err(VMLogicError::HostError(_)) => { + unreachable!("EVM runner shouldn't get Wasm Errors"); } + Err(VMLogicError::ExternalError(err)) => (None, Some(VMError::ExternalError(err))), } } diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index 96f1f0f8e15..d08395ff09f 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -258,8 +258,6 @@ pub enum EvmError { OutOfBounds, /// Execution has been reverted with REVERT. Reverted, - /// EVM error unknown - Unknown, } #[derive(Debug, Clone, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] From 031949628a31bdd61f8fdd282ab43d1e01d79ef4 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Mon, 30 Nov 2020 15:18:53 -0800 Subject: [PATCH 76/82] Wrap evm_chain_id with feature flag --- Cargo.lock | 2 ++ Cargo.toml | 6 ++++-- chain/chain/Cargo.toml | 1 + chain/chain/src/test_utils.rs | 1 + chain/chain/src/types.rs | 1 + core/chain-configs/src/genesis_config.rs | 2 ++ core/chain-configs/src/lib.rs | 6 +++--- core/primitives/src/views.rs | 1 + neard/Cargo.toml | 2 +- neard/src/config.rs | 1 + neard/src/runtime.rs | 16 +++++++--------- runtime/near-vm-errors/src/lib.rs | 5 +++-- runtime/near-vm-runner/src/wasmer_runner.rs | 4 +--- .../src/evm_estimator.rs | 5 +++-- runtime/runtime-params-estimator/src/testbed.rs | 1 + runtime/runtime-standalone/Cargo.toml | 1 + runtime/runtime-standalone/src/lib.rs | 2 ++ runtime/runtime/src/adapter.rs | 2 +- runtime/runtime/src/lib.rs | 3 ++- runtime/runtime/src/state_viewer.rs | 7 +++++++ runtime/runtime/tests/runtime_group_tools/mod.rs | 1 + test-utils/testlib/Cargo.toml | 2 +- test-utils/testlib/src/user/runtime_user.rs | 6 +++++- 23 files changed, 52 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index abf3b1c7cef..02d5231669e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3328,11 +3328,13 @@ dependencies = [ "near-logger-utils", "near-network", "near-primitives", + "near-runtime-standalone", "near-store", "neard", "node-runtime", "openssl-probe", "rand 0.7.3", + "runtime-params-estimator", "serde_json", "testlib", ] diff --git a/Cargo.toml b/Cargo.toml index d349c234f2b..0476d7a9fdf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,6 +66,8 @@ near-chain-configs = { path = "./core/chain-configs" } near-crypto = { path = "./core/crypto" } near-primitives = { path = "./core/primitives" } near-store = { path = "./core/store" } +near-runtime-standalone = { path = "./runtime/runtime-standalone" } +runtime-params-estimator = { path = "./runtime/runtime-params-estimator" } node-runtime = { path = "./runtime/runtime" } @@ -109,5 +111,5 @@ delay_detector = ["neard/delay_detector"] rosetta_rpc = ["neard/rosetta_rpc"] protocol_feature_forward_chunk_parts = ["neard/protocol_feature_forward_chunk_parts"] nightly_protocol = ["near-primitives/nightly_protocol", "near-jsonrpc/nightly_protocol"] -nightly_protocol_features = ["nightly_protocol", "neard/nightly_protocol_features"] -protocol_feature_evm = ["neard/protocol_feature_evm", "testlib/protocol_feature_evm"] +nightly_protocol_features = ["nightly_protocol", "neard/nightly_protocol_features", "protocol_feature_evm"] +protocol_feature_evm = ["neard/protocol_feature_evm", "testlib/protocol_feature_evm", "near-runtime-standalone/protocol_feature_evm", "runtime-params-estimator/protocol_feature_evm"] diff --git a/chain/chain/Cargo.toml b/chain/chain/Cargo.toml index 0287e8cd7d5..240f3c81c72 100644 --- a/chain/chain/Cargo.toml +++ b/chain/chain/Cargo.toml @@ -41,6 +41,7 @@ expensive_tests = [] adversarial = [] delay_detector = ["delay-detector"] no_cache = ["near-store/no_cache"] +protocol_feature_evm = ["near-primitives/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"] protocol_feature_rectify_inflation = [] nightly_protocol_features = ["nightly_protocol", "protocol_feature_rectify_inflation"] nightly_protocol = [] diff --git a/chain/chain/src/test_utils.rs b/chain/chain/src/test_utils.rs index cae2c7cc5aa..935a3fc69ad 100644 --- a/chain/chain/src/test_utils.rs +++ b/chain/chain/src/test_utils.rs @@ -960,6 +960,7 @@ impl RuntimeAdapter for KeyValueRuntime { Err(ErrorKind::NotAValidator.into()) } + #[cfg(feature = "protocol_feature_evm")] fn evm_chain_id(&self) -> u128 { // See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161555.json 1313161555 diff --git a/chain/chain/src/types.rs b/chain/chain/src/types.rs index be21df64944..91995b0a4f6 100644 --- a/chain/chain/src/types.rs +++ b/chain/chain/src/types.rs @@ -586,6 +586,7 @@ pub trait RuntimeAdapter: Send + Sync { header_head: &CryptoHash, ) -> Result; + #[cfg(feature = "protocol_feature_evm")] fn evm_chain_id(&self) -> u128; /// Build receipts hashes. diff --git a/core/chain-configs/src/genesis_config.rs b/core/chain-configs/src/genesis_config.rs index 6030458d8d2..d34da88f941 100644 --- a/core/chain-configs/src/genesis_config.rs +++ b/core/chain-configs/src/genesis_config.rs @@ -27,9 +27,11 @@ use near_runtime_fees::{default_evm_deposit, EvmCostConfig}; const MAX_GAS_PRICE: Balance = 10_000_000_000_000_000_000_000; +#[cfg(feature = "protocol_feature_evm")] /// See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161555.json pub const TEST_EVM_CHAIN_ID: u128 = 1313161555; +#[cfg(feature = "protocol_feature_evm")] /// See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161554.json pub const MAINNET_EVM_CHAIN_ID: u128 = 1313161554; diff --git a/core/chain-configs/src/lib.rs b/core/chain-configs/src/lib.rs index 5135966fa0b..776568dc291 100644 --- a/core/chain-configs/src/lib.rs +++ b/core/chain-configs/src/lib.rs @@ -2,6 +2,6 @@ mod client_config; mod genesis_config; pub use client_config::{ClientConfig, LogSummaryStyle}; -pub use genesis_config::{ - Genesis, GenesisConfig, GenesisRecords, MAINNET_EVM_CHAIN_ID, TEST_EVM_CHAIN_ID, -}; +pub use genesis_config::{Genesis, GenesisConfig, GenesisRecords}; +#[cfg(feature = "protocol_feature_evm")] +pub use genesis_config::{MAINNET_EVM_CHAIN_ID, TEST_EVM_CHAIN_ID}; diff --git a/core/primitives/src/views.rs b/core/primitives/src/views.rs index ec8b158e49e..37c7701846f 100644 --- a/core/primitives/src/views.rs +++ b/core/primitives/src/views.rs @@ -76,6 +76,7 @@ pub struct ViewApplyState { /// Cache for compiled contracts. pub cache: Option>, /// EVM chain ID + #[cfg(feature = "protocol_feature_evm")] pub evm_chain_id: u128, } diff --git a/neard/Cargo.toml b/neard/Cargo.toml index d1226cb646f..c17783e6f18 100644 --- a/neard/Cargo.toml +++ b/neard/Cargo.toml @@ -61,7 +61,7 @@ delay_detector = ["near-client/delay_detector"] rosetta_rpc = ["near-rosetta-rpc"] protocol_feature_forward_chunk_parts = ["near-client/protocol_feature_forward_chunk_parts"] protocol_feature_rectify_inflation = ["near-epoch-manager/protocol_feature_rectify_inflation"] -protocol_feature_evm = ["near-primitives/protocol_feature_evm", "node-runtime/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"] +protocol_feature_evm = ["near-primitives/protocol_feature_evm", "node-runtime/protocol_feature_evm", "near-chain-configs/protocol_feature_evm", "near-chain/protocol_feature_evm"] nightly_protocol_features = ["nightly_protocol", "near-primitives/nightly_protocol_features", "near-client/nightly_protocol_features", "near-epoch-manager/nightly_protocol_features", "near-store/nightly_protocol_features", "protocol_feature_forward_chunk_parts", "protocol_feature_rectify_inflation", "protocol_feature_evm"] nightly_protocol = ["near-primitives/nightly_protocol", "near-jsonrpc/nightly_protocol"] diff --git a/neard/src/config.rs b/neard/src/config.rs index af94ee28257..5b64895c137 100644 --- a/neard/src/config.rs +++ b/neard/src/config.rs @@ -129,6 +129,7 @@ pub const MINIMUM_STAKE_DIVISOR: u64 = 10; /// Number of epochs before protocol upgrade. pub const PROTOCOL_UPGRADE_NUM_EPOCHS: EpochHeight = 2; +#[cfg(feature = "protocol_feature_evm")] pub const TEST_EVM_CHAIN_ID: u128 = 0x99; pub const CONFIG_FILENAME: &str = "config.json"; diff --git a/neard/src/runtime.rs b/neard/src/runtime.rs index c23e900fe3d..04c9bcc5829 100644 --- a/neard/src/runtime.rs +++ b/neard/src/runtime.rs @@ -14,7 +14,7 @@ use near_chain::chain::NUM_EPOCHS_TO_KEEP_STORE_DATA; use near_chain::types::{ApplyTransactionResult, BlockHeaderInfo}; use near_chain::{BlockHeader, Error, ErrorKind, RuntimeAdapter}; use near_chain_configs::{Genesis, GenesisConfig}; -#[allow(unused_imports)] +#[cfg(feature = "protocol_feature_evm")] use near_chain_configs::{MAINNET_EVM_CHAIN_ID, TEST_EVM_CHAIN_ID}; use near_crypto::{PublicKey, Signature}; use near_epoch_manager::{EpochManager, RewardCalculator}; @@ -454,6 +454,7 @@ impl NightshadeRuntime { current_protocol_version, ), cache: Some(Arc::new(StoreCompiledContractCache { store: self.store.clone() })), + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: self.evm_chain_id(), }; @@ -1160,6 +1161,7 @@ impl RuntimeAdapter for NightshadeRuntime { &mut logs, &self.epoch_manager, current_protocol_version, + #[cfg(feature = "protocol_feature_evm")] self.evm_chain_id(), ) { Ok(result) => Ok(QueryResponse { @@ -1256,8 +1258,8 @@ impl RuntimeAdapter for NightshadeRuntime { Ok(partial_state) => partial_state, Err(e) => { error!(target: "runtime", - "Can't get_trie_nodes_for_part for {:?}, part_id {:?}, num_parts {:?}, {:?}", - state_root, part_id, num_parts, e + "Can't get_trie_nodes_for_part for {:?}, part_id {:?}, num_parts {:?}, {:?}", + state_root, part_id, num_parts, e ); return Err(e.to_string().into()); } @@ -1387,11 +1389,6 @@ impl RuntimeAdapter for NightshadeRuntime { _ => TEST_EVM_CHAIN_ID, } } - - #[cfg(not(feature = "protocol_feature_evm"))] - fn evm_chain_id(&self) -> u128 { - 0 - } } impl node_runtime::adapter::ViewRuntimeAdapter for NightshadeRuntime { @@ -1420,7 +1417,7 @@ impl node_runtime::adapter::ViewRuntimeAdapter for NightshadeRuntime { logs: &mut Vec, epoch_info_provider: &dyn EpochInfoProvider, current_protocol_version: ProtocolVersion, - evm_chain_id: u128, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: u128, ) -> Result, Box> { let state_update = self.get_tries().new_trie_update_view(shard_id, state_root); let view_state = ViewApplyState { @@ -1431,6 +1428,7 @@ impl node_runtime::adapter::ViewRuntimeAdapter for NightshadeRuntime { block_timestamp, current_protocol_version, cache: Some(Arc::new(StoreCompiledContractCache { store: self.tries.get_store() })), + #[cfg(feature = "protocol_feature_evm")] evm_chain_id, }; self.trie_viewer.call_function( diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index d08395ff09f..bed8ead86f6 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -184,7 +184,7 @@ pub enum HostError { Deprecated { method_name: String }, } -/// Errors specifically from EVM pre-compile. +/// Errors specifically from native EVM. #[derive(Debug, Clone, Eq, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] pub enum EvmError { /// Contract not found. @@ -262,12 +262,13 @@ pub enum EvmError { #[derive(Debug, Clone, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)] pub enum VMLogicError { + /// Errors coming from native Wasm VM. HostError(HostError), /// Serialized external error from External trait implementation. ExternalError(Vec), /// An error that is caused by an operation on an inconsistent state. InconsistentStateError(InconsistentStateError), - /// An error coming from EVM precompile. + /// An error coming from native EVM. EvmError(EvmError), } diff --git a/runtime/near-vm-runner/src/wasmer_runner.rs b/runtime/near-vm-runner/src/wasmer_runner.rs index 9f5808c202f..9047ab2b480 100644 --- a/runtime/near-vm-runner/src/wasmer_runner.rs +++ b/runtime/near-vm-runner/src/wasmer_runner.rs @@ -161,9 +161,7 @@ impl IntoVMError for wasmer_runtime::error::RuntimeError { VMLogicError::InconsistentStateError(e) => { VMError::InconsistentStateError(e.clone()) } - VMLogicError::EvmError(e) => { - VMError::FunctionCallError(FunctionCallError::EvmError(e.clone())) - } + VMLogicError::EvmError(_) => unreachable!("Wasm can't return EVM error"), } } else { panic!( diff --git a/runtime/runtime-params-estimator/src/evm_estimator.rs b/runtime/runtime-params-estimator/src/evm_estimator.rs index 05b236f3822..4860f07cb9e 100644 --- a/runtime/runtime-params-estimator/src/evm_estimator.rs +++ b/runtime/runtime-params-estimator/src/evm_estimator.rs @@ -12,6 +12,7 @@ use near_runtime_fees::RuntimeFeesConfig; use near_vm_logic::gas_counter::reset_evm_gas_counter; use near_vm_logic::mocks::mock_external::MockedExternal; use near_vm_logic::VMConfig; +use node_runtime::Runtime; use num_rational::Ratio; use num_traits::cast::ToPrimitive; use rand::Rng; @@ -321,7 +322,7 @@ pub fn measure_evm_function) -> Vec + Copy>( let runtime_node = RuntimeNode { signer: Arc::new(signer.clone()), client: Arc::new(RwLock::new(MockClient { - runtime: testbed.runtime, + runtime: Runtime::new(), runtime_config: testbed.genesis.config.runtime_config.clone(), tries: testbed.tries.clone(), state_root: testbed.root, @@ -347,7 +348,7 @@ pub fn measure_evm_function) -> Vec + Copy>( testbed.tries = runtime_node.client.read().unwrap().tries.clone(); testbed.root = runtime_node.client.read().unwrap().state_root; - testbed.runtime = runtime_node.client.read().unwrap().runtime; + testbed.runtime = Runtime::new(); let nonce = *nonces.entry(account_idx).and_modify(|x| *x += 1).or_insert(1); SignedTransaction::from_actions( diff --git a/runtime/runtime-params-estimator/src/testbed.rs b/runtime/runtime-params-estimator/src/testbed.rs index d967cd3beab..4766b2c4a37 100644 --- a/runtime/runtime-params-estimator/src/testbed.rs +++ b/runtime/runtime-params-estimator/src/testbed.rs @@ -92,6 +92,7 @@ impl RuntimeTestbed { current_protocol_version: PROTOCOL_VERSION, config: Arc::new(runtime_config), cache: Some(Arc::new(StoreCompiledContractCache { store: tries.get_store() })), + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: near_chain_configs::TEST_EVM_CHAIN_ID, }; Self { diff --git a/runtime/runtime-standalone/Cargo.toml b/runtime/runtime-standalone/Cargo.toml index dbc3001a825..f265f1abed5 100644 --- a/runtime/runtime-standalone/Cargo.toml +++ b/runtime/runtime-standalone/Cargo.toml @@ -15,4 +15,5 @@ node-runtime = { path = "../runtime" } [features] default = [] +protocol_feature_evm = ["near-primitives/protocol_feature_evm", "node-runtime/protocol_feature_evm"] no_cache = ["near-store/no_cache", "node-runtime/no_cache"] diff --git a/runtime/runtime-standalone/src/lib.rs b/runtime/runtime-standalone/src/lib.rs index 32f05558837..c53018786a7 100644 --- a/runtime/runtime-standalone/src/lib.rs +++ b/runtime/runtime-standalone/src/lib.rs @@ -232,6 +232,7 @@ impl RuntimeStandalone { config: self.runtime_config.clone(), // TODO: shall we use compiled contracts cache in standalone runtime? cache: None, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: CHAIN_ID, }; @@ -315,6 +316,7 @@ impl RuntimeStandalone { block_timestamp: self.cur_block.block_timestamp, current_protocol_version: PROTOCOL_VERSION, cache: Some(Arc::new(StoreCompiledContractCache { store: self.tries.get_store() })), + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: CHAIN_ID, }; let mut logs = vec![]; diff --git a/runtime/runtime/src/adapter.rs b/runtime/runtime/src/adapter.rs index 3922f1272ab..eb3f4af4808 100644 --- a/runtime/runtime/src/adapter.rs +++ b/runtime/runtime/src/adapter.rs @@ -31,7 +31,7 @@ pub trait ViewRuntimeAdapter { logs: &mut Vec, epoch_info_provider: &dyn EpochInfoProvider, current_protocol_version: ProtocolVersion, - evm_chain_id: u128, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: u128, ) -> Result, Box>; fn view_access_key( diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs index ef9ab53ec97..8bd9e119aac 100644 --- a/runtime/runtime/src/lib.rs +++ b/runtime/runtime/src/lib.rs @@ -90,6 +90,7 @@ pub struct ApplyState { /// Cache for compiled contracts. pub cache: Option>, /// Ethereum chain id. + #[cfg(feature = "protocol_feature_evm")] pub evm_chain_id: u128, } @@ -198,7 +199,6 @@ impl Default for ActionResult { } } -#[derive(Copy, Clone)] pub struct Runtime {} impl Runtime { @@ -1540,6 +1540,7 @@ mod tests { current_protocol_version: PROTOCOL_VERSION, config: Arc::new(RuntimeConfig::default()), cache: Some(Arc::new(StoreCompiledContractCache { store: tries.get_store() })), + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: near_chain_configs::TEST_EVM_CHAIN_ID, }; diff --git a/runtime/runtime/src/state_viewer.rs b/runtime/runtime/src/state_viewer.rs index 389b1a319ce..69c1f95dd74 100644 --- a/runtime/runtime/src/state_viewer.rs +++ b/runtime/runtime/src/state_viewer.rs @@ -131,6 +131,7 @@ impl TrieViewer { current_protocol_version: view_state.current_protocol_version, config: config.clone(), cache: view_state.cache, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: view_state.evm_chain_id, }; let action_receipt = ActionReceipt { @@ -189,6 +190,7 @@ impl TrieViewer { mod tests { use super::*; + #[cfg(feature = "protocol_feature_evm")] use near_chain_configs::TEST_EVM_CHAIN_ID; use near_primitives::test_utils::MockEpochInfoProvider; use near_primitives::trie_key::TrieKey; @@ -211,6 +213,7 @@ mod tests { block_timestamp: 1, current_protocol_version: PROTOCOL_VERSION, cache: None, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: TEST_EVM_CHAIN_ID, }; let result = viewer.call_function( @@ -239,6 +242,7 @@ mod tests { block_timestamp: 1, current_protocol_version: PROTOCOL_VERSION, cache: None, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: TEST_EVM_CHAIN_ID, }; let result = viewer.call_function( @@ -271,6 +275,7 @@ mod tests { block_timestamp: 1, current_protocol_version: PROTOCOL_VERSION, cache: None, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: 0x99, }; let result = viewer.call_function( @@ -302,6 +307,7 @@ mod tests { block_timestamp: 1, current_protocol_version: PROTOCOL_VERSION, cache: None, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: 0x99, }; let view_call_result = viewer.call_function( @@ -384,6 +390,7 @@ mod tests { block_timestamp: 1, current_protocol_version: PROTOCOL_VERSION, cache: None, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: 0x99, }; let mut logs = vec![]; diff --git a/runtime/runtime/tests/runtime_group_tools/mod.rs b/runtime/runtime/tests/runtime_group_tools/mod.rs index 20628825fe7..07943794eac 100644 --- a/runtime/runtime/tests/runtime_group_tools/mod.rs +++ b/runtime/runtime/tests/runtime_group_tools/mod.rs @@ -68,6 +68,7 @@ impl StandaloneRuntime { current_protocol_version: PROTOCOL_VERSION, config: Arc::new(runtime_config), cache: None, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: near_chain_configs::TEST_EVM_CHAIN_ID, }; diff --git a/test-utils/testlib/Cargo.toml b/test-utils/testlib/Cargo.toml index 7ebadec7176..9bbedf73d0f 100644 --- a/test-utils/testlib/Cargo.toml +++ b/test-utils/testlib/Cargo.toml @@ -45,4 +45,4 @@ near-evm-runner = { path = "../../runtime/near-evm-runner", optional = true } [features] default = [] -protocol_feature_evm = ["near-evm-runner/protocol_feature_evm", "near-primitives/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm", "neard/protocol_feature_evm", "node-runtime/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"] +protocol_feature_evm = ["near-evm-runner/protocol_feature_evm", "near-primitives/protocol_feature_evm", "near-runtime-fees/protocol_feature_evm", "neard/protocol_feature_evm", "node-runtime/protocol_feature_evm", "near-chain-configs/protocol_feature_evm", "near-chain/protocol_feature_evm"] diff --git a/test-utils/testlib/src/user/runtime_user.rs b/test-utils/testlib/src/user/runtime_user.rs index c2c368d4de7..4dab5de80a9 100644 --- a/test-utils/testlib/src/user/runtime_user.rs +++ b/test-utils/testlib/src/user/runtime_user.rs @@ -17,7 +17,9 @@ use near_primitives::views::{ FinalExecutionStatus, ViewApplyState, ViewStateResult, }; use near_store::{ShardTries, TrieUpdate}; -use neard::config::{MIN_GAS_PRICE, TEST_EVM_CHAIN_ID}; +use neard::config::MIN_GAS_PRICE; +#[cfg(feature = "protocol_feature_evm")] +use neard::config::TEST_EVM_CHAIN_ID; use node_runtime::config::RuntimeConfig; use node_runtime::state_viewer::TrieViewer; use node_runtime::{ApplyState, Runtime}; @@ -136,6 +138,7 @@ impl RuntimeUser { current_protocol_version: PROTOCOL_VERSION, config: self.runtime_config.clone(), cache: None, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: TEST_EVM_CHAIN_ID, } } @@ -233,6 +236,7 @@ impl User for RuntimeUser { block_timestamp: apply_state.block_timestamp, current_protocol_version: PROTOCOL_VERSION, cache: apply_state.cache, + #[cfg(feature = "protocol_feature_evm")] evm_chain_id: TEST_EVM_CHAIN_ID, }; result.result = self From 4a8dbeeee051fb703c878845c00e7b821ffdb8ff Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Mon, 30 Nov 2020 16:06:20 -0800 Subject: [PATCH 77/82] Fix new param estimator denies --- deny.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/deny.toml b/deny.toml index ee2ec3f8b8a..b0ad139e573 100644 --- a/deny.toml +++ b/deny.toml @@ -83,4 +83,10 @@ skip = [ { name = "unicode-xid", version = "=0.1.0" }, { name = "primitive-types", version = "=0.6.2" }, { name = "fixed-hash", version = "=0.5.2" }, + + # param estimator uses newer imports, but it's not part of neard + { name = "indicatif", version = "=0.15.0" }, + { name = "num-rational", version = "=0.3.0" }, + { name = "rand_xorshift", version = "=0.2.0" }, + { name = "wasmparser", version = "=0.59.0" }, ] From fea688a8ca54c25a1f6241674b19ab3796299434 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Wed, 2 Dec 2020 10:31:56 -0800 Subject: [PATCH 78/82] Address comments --- runtime/near-evm-runner/Cargo.toml | 2 +- runtime/near-evm-runner/src/pricer.rs | 3 +++ runtime/near-runtime-fees/src/lib.rs | 1 + runtime/near-vm-logic/Cargo.toml | 2 ++ runtime/near-vm-logic/src/gas_counter.rs | 11 +++++++---- runtime/near-vm-runner/src/wasmtime_runner.rs | 4 +--- runtime/runtime-standalone/src/lib.rs | 1 + 7 files changed, 16 insertions(+), 8 deletions(-) diff --git a/runtime/near-evm-runner/Cargo.toml b/runtime/near-evm-runner/Cargo.toml index 9b229e9462d..48254ace63f 100644 --- a/runtime/near-evm-runner/Cargo.toml +++ b/runtime/near-evm-runner/Cargo.toml @@ -48,7 +48,7 @@ near-crypto = { path = "../../core/crypto" } [features] costs_counting = [] -protocol_feature_evm = ["near-runtime-fees/protocol_feature_evm"] +protocol_feature_evm = ["near-runtime-fees/protocol_feature_evm", "near-vm-logic/protocol_feature_evm"] [[test]] name = "failures" diff --git a/runtime/near-evm-runner/src/pricer.rs b/runtime/near-evm-runner/src/pricer.rs index b3ff229f480..ff8640e274d 100644 --- a/runtime/near-evm-runner/src/pricer.rs +++ b/runtime/near-evm-runner/src/pricer.rs @@ -1,6 +1,9 @@ // Below is part of Open Ethereum: // Copyright 2015-2020 Parity Technologies (UK) Ltd. +// Source Reference +// https://github.com/openethereum/openethereum/blob/116554961c24b1c7de6cd15738a391720ae3fe56/ethcore/builtin/src/lib.rs#L159 + // Open Ethereum is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or diff --git a/runtime/near-runtime-fees/src/lib.rs b/runtime/near-runtime-fees/src/lib.rs index 2c34cc30071..896034d23ae 100644 --- a/runtime/near-runtime-fees/src/lib.rs +++ b/runtime/near-runtime-fees/src/lib.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; pub type Balance = u128; pub type Gas = u64; +#[cfg(feature = "protocol_feature_evm")] pub type EvmGas = u64; /// The amount is 1000 * 10e24 = 1000 NEAR. diff --git a/runtime/near-vm-logic/Cargo.toml b/runtime/near-vm-logic/Cargo.toml index 8aba801f3d7..8e3a897a678 100644 --- a/runtime/near-vm-logic/Cargo.toml +++ b/runtime/near-vm-logic/Cargo.toml @@ -30,8 +30,10 @@ serde_json = {version= "1", features= ["preserve_order"]} [features] default = ["costs_counting"] +protocol_feature_evm = ["near-runtime-fees/protocol_feature_evm"] wasmtime_default = [] + # Use this feature to enable counting of fees and costs applied. costs_counting = [] diff --git a/runtime/near-vm-logic/src/gas_counter.rs b/runtime/near-vm-logic/src/gas_counter.rs index 557f7dcf7a0..d114b5ea2ba 100644 --- a/runtime/near-vm-logic/src/gas_counter.rs +++ b/runtime/near-vm-logic/src/gas_counter.rs @@ -1,17 +1,20 @@ use crate::config::{ActionCosts, ExtCosts, ExtCostsConfig}; use crate::types::{Gas, ProfileData}; use crate::{HostError, VMLogicError}; -use near_runtime_fees::{EvmGas, Fee}; +#[cfg(feature = "protocol_feature_evm")] +use near_runtime_fees::EvmGas; +use near_runtime_fees::Fee; #[cfg(feature = "costs_counting")] thread_local! { pub static EXT_COSTS_COUNTER: std::cell::RefCell> = Default::default(); + #[cfg(feature = "protocol_feature_evm")] pub static EVM_GAS_COUNTER: std::cell::RefCell = Default::default(); } -#[cfg(feature = "costs_counting")] +#[cfg(all(feature = "costs_counting", feature = "protocol_feature_evm"))] pub fn reset_evm_gas_counter() -> u64 { let mut ret = 0; EVM_GAS_COUNTER.with(|f| { @@ -92,7 +95,7 @@ impl GasCounter { } } - #[cfg(feature = "costs_counting")] + #[cfg(all(feature = "costs_counting", feature = "protocol_feature_evm"))] #[inline] pub fn inc_evm_gas_counter(&mut self, value: EvmGas) { EVM_GAS_COUNTER.with(|f| { @@ -100,7 +103,7 @@ impl GasCounter { }) } - #[cfg(not(feature = "costs_counting"))] + #[cfg(all(not(feature = "costs_counting"), feature = "protocol_feature_evm"))] #[inline] pub fn inc_evm_gas_counter(&mut self, _value: EvmGas) {} diff --git a/runtime/near-vm-runner/src/wasmtime_runner.rs b/runtime/near-vm-runner/src/wasmtime_runner.rs index f74169bb5e6..a28286ebedb 100644 --- a/runtime/near-vm-runner/src/wasmtime_runner.rs +++ b/runtime/near-vm-runner/src/wasmtime_runner.rs @@ -79,9 +79,7 @@ pub mod wasmtime_runner { Some(VMLogicError::InconsistentStateError(e)) => { VMError::InconsistentStateError(e.clone()) } - Some(VMLogicError::EvmError(e)) => { - VMError::FunctionCallError(FunctionCallError::EvmError(e.clone())) - } + Some(VMLogicError::EvmError(_)) => unreachable!("Wasm can't return EVM error"), None => panic!("Error is not properly set"), } } else { diff --git a/runtime/runtime-standalone/src/lib.rs b/runtime/runtime-standalone/src/lib.rs index c53018786a7..c6e30a697a5 100644 --- a/runtime/runtime-standalone/src/lib.rs +++ b/runtime/runtime-standalone/src/lib.rs @@ -26,6 +26,7 @@ use node_runtime::{state_viewer::TrieViewer, ApplyState, Runtime}; const DEFAULT_EPOCH_LENGTH: u64 = 3; +#[cfg(feature = "protocol_feature_evm")] /// See https://github.com/ethereum-lists/chains/blob/master/_data/chains/1313161555.json const CHAIN_ID: u128 = 1313161555; From bb7b838dd2d13e6f4c60a298f5c1ece3b28cc6dc Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Wed, 2 Dec 2020 10:49:03 -0800 Subject: [PATCH 79/82] Use default --- core/chain-configs/src/genesis_config.rs | 11 +---------- runtime/near-runtime-fees/Cargo.toml | 2 +- runtime/near-runtime-fees/src/lib.rs | 8 -------- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/core/chain-configs/src/genesis_config.rs b/core/chain-configs/src/genesis_config.rs index d34da88f941..806f752f281 100644 --- a/core/chain-configs/src/genesis_config.rs +++ b/core/chain-configs/src/genesis_config.rs @@ -22,8 +22,6 @@ use near_primitives::types::{ }; use near_primitives::version::ProtocolVersion; use near_runtime_configs::RuntimeConfig; -#[cfg(feature = "protocol_feature_evm")] -use near_runtime_fees::{default_evm_deposit, EvmCostConfig}; const MAX_GAS_PRICE: Balance = 10_000_000_000_000_000_000_000; @@ -174,15 +172,8 @@ impl GenesisConfig { /// GenesisConfig structure. pub fn from_file>(path: P) -> Self { let reader = BufReader::new(File::open(path).expect("Could not open genesis config file.")); - #[allow(unused_mut)] - let mut genesis_config: GenesisConfig = + let genesis_config: GenesisConfig = serde_json::from_reader(reader).expect("Failed to deserialize the genesis records."); - #[cfg(feature = "protocol_feature_evm")] - { - genesis_config.runtime_config.transaction_costs.evm_config = EvmCostConfig::default(); - genesis_config.runtime_config.transaction_costs.evm_deposit = default_evm_deposit(); - } - genesis_config } diff --git a/runtime/near-runtime-fees/Cargo.toml b/runtime/near-runtime-fees/Cargo.toml index a91cbbba06d..e5e235043f6 100644 --- a/runtime/near-runtime-fees/Cargo.toml +++ b/runtime/near-runtime-fees/Cargo.toml @@ -19,4 +19,4 @@ num-rational = { version = "0.2.4", features = ["serde"]} [features] default = [] -protocol_feature_evm = [] \ No newline at end of file +protocol_feature_evm = [] diff --git a/runtime/near-runtime-fees/src/lib.rs b/runtime/near-runtime-fees/src/lib.rs index 896034d23ae..1635911d2d1 100644 --- a/runtime/near-runtime-fees/src/lib.rs +++ b/runtime/near-runtime-fees/src/lib.rs @@ -15,11 +15,6 @@ pub type EvmGas = u64; #[cfg(feature = "protocol_feature_evm")] const EVM_DEPOSIT: Balance = 1_000_000_000_000_000_000_000_000_000; -#[cfg(feature = "protocol_feature_evm")] -pub fn default_evm_deposit() -> Balance { - EVM_DEPOSIT -} - /// Costs associated with an object that can only be sent over the network (and executed /// by the receiver). /// NOTE: `send_sir` or `send_not_sir` fees are usually burned when the item is being created. @@ -78,14 +73,11 @@ pub struct RuntimeFeesConfig { /// Describes cost of running method of evm, include deploy code and call contract function #[cfg(feature = "protocol_feature_evm")] - // Do not serialize and deserialize evm fields to keep genesis unchanged - #[serde(skip)] pub evm_config: EvmCostConfig, /// New EVM deposit. /// Fee to create new EVM account. #[cfg(feature = "protocol_feature_evm")] - #[serde(skip)] pub evm_deposit: Balance, } From d6aff1d2e2f4f9df59c60012d9addb5d8710779c Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Wed, 2 Dec 2020 11:01:44 -0800 Subject: [PATCH 80/82] Switch early reverted to out of gas --- runtime/near-evm-runner/src/runner.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/runtime/near-evm-runner/src/runner.rs b/runtime/near-evm-runner/src/runner.rs index 5b0a7826064..4f6e5ba13ec 100644 --- a/runtime/near-evm-runner/src/runner.rs +++ b/runtime/near-evm-runner/src/runner.rs @@ -542,9 +542,7 @@ pub fn run_evm( if evm_gas_result.is_none() { return ( None, - Some(VMError::FunctionCallError(FunctionCallError::EvmError(EvmError::Revert( - b"Not enough gas to run EVM".to_vec(), - )))), + Some(VMError::FunctionCallError(FunctionCallError::EvmError(EvmError::OutOfGas))), ); } let evm_gas = evm_gas_result.unwrap(); From 60a2158da982fa4e5c6e91bb0bfffd28ee183714 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Wed, 2 Dec 2020 11:20:42 -0800 Subject: [PATCH 81/82] fix genesis --- runtime/near-runtime-fees/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/near-runtime-fees/src/lib.rs b/runtime/near-runtime-fees/src/lib.rs index 1635911d2d1..cf27f87eaff 100644 --- a/runtime/near-runtime-fees/src/lib.rs +++ b/runtime/near-runtime-fees/src/lib.rs @@ -51,6 +51,7 @@ impl Fee { } #[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)] +#[serde(default)] pub struct RuntimeFeesConfig { /// Describes the cost of creating an action receipt, `ActionReceipt`, excluding the actual cost /// of actions. From 317a2c831364d35f43eb2c615d4f532b7d9d2538 Mon Sep 17 00:00:00 2001 From: Evgeny Kuzyakov Date: Wed, 2 Dec 2020 14:10:50 -0800 Subject: [PATCH 82/82] Fix CI --- runtime/near-runtime-fees/src/lib.rs | 1 + runtime/runtime-params-estimator/src/cases.rs | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/runtime/near-runtime-fees/src/lib.rs b/runtime/near-runtime-fees/src/lib.rs index cf27f87eaff..94bb39f37cb 100644 --- a/runtime/near-runtime-fees/src/lib.rs +++ b/runtime/near-runtime-fees/src/lib.rs @@ -79,6 +79,7 @@ pub struct RuntimeFeesConfig { /// New EVM deposit. /// Fee to create new EVM account. #[cfg(feature = "protocol_feature_evm")] + #[serde(with = "u128_dec_format")] pub evm_deposit: Balance, } diff --git a/runtime/runtime-params-estimator/src/cases.rs b/runtime/runtime-params-estimator/src/cases.rs index 6c9cefe4c16..a199e7a477c 100644 --- a/runtime/runtime-params-estimator/src/cases.rs +++ b/runtime/runtime-params-estimator/src/cases.rs @@ -151,8 +151,6 @@ pub enum Metric { data_receipt_10b_1000, data_receipt_100kib_1000, cpu_ram_soak_test, - - deploy_evm_contract, } #[allow(unused_variables)]