From 5e34235a3645e7090c20e6804f5348098ba07074 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 22 Mar 2017 04:01:46 +0300 Subject: [PATCH 01/10] initial, fallable built-ins --- Cargo.lock | 18 ++++++ ethcore/Cargo.toml | 1 + ethcore/res/ethereum/foundation.json | 2 + ethcore/src/builtin.rs | 77 +++++++++++++++++++++++--- ethcore/src/evm/evm.rs | 9 +++ ethcore/src/executive.rs | 3 +- ethcore/src/lib.rs | 1 + ethcore/src/types/trace_types/error.rs | 7 ++- 8 files changed, 107 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e61658e16..42d6054e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,6 +175,21 @@ name = "bloomchain" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bn" +version = "0.4.2" +source = "git+https://github.com/paritytech/bn#78cf02fd7b35e4a2398fedd96f68c92953badea7" +dependencies = [ + "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byteorder" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.0.0" @@ -382,6 +397,7 @@ version = "1.7.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bn 0.4.2 (git+https://github.com/paritytech/bn)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2617,6 +2633,8 @@ dependencies = [ "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum blastfig 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09640e0509d97d5cdff03a9f5daf087a8e04c735c3b113a75139634a19cfc7b2" "checksum bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f421095d2a76fc24cd3fb3f912b90df06be7689912b1bdb423caefae59c258d" +"checksum bn 0.4.2 (git+https://github.com/paritytech/bn)" = "" +"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" "checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27" "checksum bytes 0.4.0-dev (git+https://github.com/carllerche/bytes)" = "" diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index d1c9d624b..c44e98763 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -45,6 +45,7 @@ ethcore-bloom-journal = { path = "../util/bloom" } hardware-wallet = { path = "../hw" } stats = { path = "../util/stats" } num = "0.1" +bn = { git = "https://github.com/paritytech/bn" } [dependencies.hyper] git = "https://github.com/ethcore/hyper" diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index 77b0d5533..1debff1d6 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -190,6 +190,8 @@ "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": "0x7fffffffffffff", "pricing": { "modexp": { "divisor": 20 } } } }, + "0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } }, + "0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } }, "3282791d6fd713f1e94f4bfd565eaa78b3a0599d": { "balance": "1337000000000000000000" }, diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index 9927435dd..7de9409a0 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -27,10 +27,19 @@ use util::{U256, H256, Uint, Hashable, BytesRef}; use ethkey::{Signature, recover as ec_recover}; use ethjson; +#[derive(Debug)] +pub struct Error(pub String); + +impl From<&'static str> for Error { + fn from(val: &'static str) -> Self { + Error(val.to_owned()) + } +} + /// 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); + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error>; } /// A gas pricing scheme for built-in contracts. @@ -102,7 +111,10 @@ impl Builtin { pub fn cost(&self, input: &[u8]) -> U256 { self.pricer.cost(input) } /// Simple forwarder for execute. - pub fn execute(&self, input: &[u8], output: &mut BytesRef) { self.native.execute(input, output) } + pub fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + self.native.execute(input, output); + Ok(()) + } /// Whether the builtin is activated at the given block number. pub fn is_active(&self, at: u64) -> bool { at >= self.activate_at } @@ -172,14 +184,21 @@ struct Ripemd160; #[derive(Debug)] struct ModexpImpl; +#[derive(Debug)] +struct Bn128AddImpl; + +#[derive(Debug)] +struct Bn128MulImpl; + impl Impl for Identity { - fn execute(&self, input: &[u8], output: &mut BytesRef) { + 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) { + fn execute(&self, i: &[u8], output: &mut BytesRef) -> Result<(), Error> { let len = min(i.len(), 128); let mut input = [0; 128]; @@ -192,7 +211,7 @@ impl Impl for EcRecover { let bit = match v[31] { 27 | 28 if &v.0[..31] == &[0; 31] => v[31] - 27, - _ => return, + _ => { return Ok(()); }, }; let s = Signature::from_rsv(&r, &s, bit); @@ -203,11 +222,13 @@ impl Impl for EcRecover { output.write(12, &r[12..r.len()]); } } + + Ok(()) } } impl Impl for Sha256 { - fn execute(&self, input: &[u8], output: &mut BytesRef) { + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { let mut sha = Sha256Digest::new(); sha.input(input); @@ -215,11 +236,13 @@ impl Impl for Sha256 { sha.result(&mut out); output.write(0, &out); + + Ok(()) } } impl Impl for Ripemd160 { - fn execute(&self, input: &[u8], output: &mut BytesRef) { + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { let mut sha = Ripemd160Digest::new(); sha.input(input); @@ -227,11 +250,13 @@ impl Impl for Ripemd160 { sha.result(&mut out[12..32]); output.write(0, &out); + + Ok(()) } } impl Impl for ModexpImpl { - fn execute(&self, input: &[u8], output: &mut BytesRef) { + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { let mut reader = input.chain(io::repeat(0)); let mut buf = [0; 32]; @@ -294,9 +319,43 @@ impl Impl for ModexpImpl { let res_start = mod_len - bytes.len(); output.write(res_start, &bytes); } + + Ok(()) } } +impl Impl for Bn128AddImpl { + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + use bn::{Fq, AffineG1, G1}; + + let mut buf = [0u8; 32]; + let mut next_coord = |reader: &mut io::Chain<&[u8], io::Repeat>| { + reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed"); + Fq::from_slice(&input[0..32]) + }; + + let mut padded_input = input.chain(io::repeat(0)); + + let p1x = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 x coordinate"))?; + let p1y = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 y coordinate"))?; + let p1: G1 = AffineG1::new(p1x, p1y).into(); + + let p2x = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p2 x coordinate"))?; + let p2y = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p2 y coordinate"))?; + let p2: G1 = AffineG1::new(p2x, p2y).into(); + + let sum = AffineG1::from_jacobian(p1 + p2).expect("Sum of two valid points is a valid point also; qed"); + + Ok(()) + } +} + +impl Impl for Bn128MulImpl { + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { + Ok(()) + } +} + #[cfg(test)] mod tests { use super::{Builtin, Linear, ethereum_builtin, Pricer, Modexp}; @@ -574,4 +633,4 @@ mod tests { b.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); assert_eq!(i, o); } -} +} \ No newline at end of file diff --git a/ethcore/src/evm/evm.rs b/ethcore/src/evm/evm.rs index 09a93f087..b561c271f 100644 --- a/ethcore/src/evm/evm.rs +++ b/ethcore/src/evm/evm.rs @@ -20,6 +20,7 @@ use std::{ops, cmp, fmt}; use util::{U128, U256, U512, Uint, trie}; use action_params::ActionParams; use evm::Ext; +use builtin; /// Evm errors. #[derive(Debug, Clone, PartialEq)] @@ -59,6 +60,7 @@ pub enum Error { /// What was the stack limit limit: usize }, + BuiltIn(String), /// Returned on evm internal error. Should never be ignored during development. /// Likely to cause consensus issues. Internal(String), @@ -70,6 +72,12 @@ impl From> for Error { } } +impl From for Error { + fn from(err: builtin::Error) -> Self { + Error::BuiltIn(err.0) + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::Error::*; @@ -79,6 +87,7 @@ impl fmt::Display for Error { BadInstruction { .. } => "Bad instruction", StackUnderflow { .. } => "Stack underflow", OutOfStack { .. } => "Out of stack", + BuiltIn { .. } => "Built-in failed", Internal(ref msg) => msg, }; message.fmt(f) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index cdae8a85f..4fdd9cbbd 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -276,7 +276,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let cost = builtin.cost(data); if cost <= params.gas { - builtin.execute(data, &mut output); + builtin.execute(data, &mut output)?; self.state.discard_checkpoint(); // trace only top level calls to builtins to avoid DDoS attacks @@ -497,6 +497,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { | Err(evm::Error::BadJumpDestination {..}) | Err(evm::Error::BadInstruction {.. }) | Err(evm::Error::StackUnderflow {..}) + | Err(evm::Error::BuiltIn {..}) | Err(evm::Error::OutOfStack {..}) => { self.state.revert_to_checkpoint(); }, diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 75c8a80e1..641b841f3 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -107,6 +107,7 @@ extern crate ethabi; extern crate hardware_wallet; extern crate stats; extern crate num; +extern crate bn; #[macro_use] extern crate log; diff --git a/ethcore/src/types/trace_types/error.rs b/ethcore/src/types/trace_types/error.rs index 33ccf2bb7..c36d86728 100644 --- a/ethcore/src/types/trace_types/error.rs +++ b/ethcore/src/types/trace_types/error.rs @@ -34,7 +34,9 @@ pub enum Error { /// `StackUnderflow` when there is not enough stack elements to execute instruction StackUnderflow, /// When execution would exceed defined Stack Limit - OutOfStack, + OutOfStack, + /// When builtin contract failed on input data + BuiltIn, /// Returned on evm internal error. Should never be ignored during development. /// Likely to cause consensus issues. Internal, @@ -48,6 +50,7 @@ impl<'a> From<&'a EvmError> for Error { EvmError::BadInstruction { .. } => Error::BadInstruction, EvmError::StackUnderflow { .. } => Error::StackUnderflow, EvmError::OutOfStack { .. } => Error::OutOfStack, + EvmError::BuiltIn { .. } => Error::OutOfStack, EvmError::Internal(_) => Error::Internal, } } @@ -68,6 +71,7 @@ impl fmt::Display for Error { BadInstruction => "Bad instruction", StackUnderflow => "Stack underflow", OutOfStack => "Out of stack", + BuiltIn => "Built-in failed", Internal => "Internal error", }; message.fmt(f) @@ -84,6 +88,7 @@ impl Encodable for Error { StackUnderflow => 3, OutOfStack => 4, Internal => 5, + BuiltIn => 6, }; s.append_internal(&value); From 3e7dc57289eedc59dc1e87c8e334b92a23c474a0 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 22 Mar 2017 15:41:32 +0300 Subject: [PATCH 02/10] some tests for simple cases --- Cargo.lock | 2 +- ethcore/src/builtin.rs | 81 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 42d6054e6..b92cbaed9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -178,7 +178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bn" version = "0.4.2" -source = "git+https://github.com/paritytech/bn#78cf02fd7b35e4a2398fedd96f68c92953badea7" +source = "git+https://github.com/paritytech/bn#7e513a84330f02603759e370f22af90c99e3e717" dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index 7de9409a0..112afbd97 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -112,7 +112,7 @@ impl Builtin { /// Simple forwarder for execute. pub fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { - self.native.execute(input, output); + self.native.execute(input, output)?; Ok(()) } @@ -157,6 +157,8 @@ fn ethereum_builtin(name: &str) -> Box { "sha256" => Box::new(Sha256) as Box, "ripemd160" => Box::new(Ripemd160) as Box, "modexp" => Box::new(ModexpImpl) as Box, + "alt_bn128_add" => Box::new(Bn128AddImpl) as Box, + "alt_bn128_mul" => Box::new(Bn128MulImpl) as Box, _ => panic!("invalid builtin name: {}", name), } } @@ -326,25 +328,39 @@ impl Impl for ModexpImpl { impl Impl for Bn128AddImpl { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { - use bn::{Fq, AffineG1, G1}; + use bn::{Fq, AffineG1, G1, Group}; let mut buf = [0u8; 32]; let mut next_coord = |reader: &mut io::Chain<&[u8], io::Repeat>| { reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed"); - Fq::from_slice(&input[0..32]) + Fq::from_slice(&buf[0..32]) }; let mut padded_input = input.chain(io::repeat(0)); - let p1x = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 x coordinate"))?; - let p1y = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 y coordinate"))?; - let p1: G1 = AffineG1::new(p1x, p1y).into(); + let px = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 x coordinate"))?; + let py = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 y coordinate"))?; + let p1: G1 = if px == Fq::zero() && py == Fq::zero() { + G1::zero() + } else { + AffineG1::new(px, py).map_err(|_| Error::from("Invalid curve point"))?.into() + }; - let p2x = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p2 x coordinate"))?; - let p2y = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p2 y coordinate"))?; - let p2: G1 = AffineG1::new(p2x, p2y).into(); + let px = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 x coordinate"))?; + let py = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 y coordinate"))?; + let p2: G1 = if px == Fq::zero() && py == Fq::zero() { + G1::zero() + } else { + AffineG1::new(px, py).map_err(|_| Error::from("Invalid curve point"))?.into() + }; - let sum = AffineG1::from_jacobian(p1 + p2).expect("Sum of two valid points is a valid point also; qed"); + 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]); + sum.y().to_big_endian(&mut write_buf[32..64]); + } + output.write(0, &write_buf); Ok(()) } @@ -572,6 +588,51 @@ mod tests { } } + #[test] + fn alt_bn128_add() { + use rustc_serialize::hex::FromHex; + + let f = Builtin { + pricer: Box::new(Linear { base: 0, word: 0 }), + native: ethereum_builtin("alt_bn128_add"), + activate_at: 0, + }; + + // zero-points additions + { + let input = FromHex::from_hex("\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000" + ).unwrap(); + + let mut output = vec![0u8; 64]; + let expected = FromHex::from_hex("\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000" + ).unwrap(); + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail"); + assert_eq!(output, expected); + } + + // should fail - point not on curve + { + let input = FromHex::from_hex("\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 1111111111111111111111111111111111111111111111111111111111111111" + ).unwrap(); + + let mut output = vec![0u8; 64]; + + let res = f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])); + assert!(res.is_err(), "There should be built-in error here"); + } + } + #[test] #[should_panic] fn from_unknown_linear() { From d1293d9fb0d306b7d0d86398f77d6af66f164098 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 22 Mar 2017 15:54:19 +0300 Subject: [PATCH 03/10] fix warnings --- ethcore/src/builtin.rs | 52 +++++++++++++++++++++--------------------- ethcore/src/evm/evm.rs | 1 + 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index 112afbd97..acc495085 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -357,8 +357,8 @@ impl Impl for Bn128AddImpl { 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]); - sum.y().to_big_endian(&mut write_buf[32..64]); + 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); @@ -385,15 +385,15 @@ mod tests { let i = [0u8, 1, 2, 3]; let mut o2 = [255u8; 2]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o2[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o2[..])).expect("Builtin should not fail"); assert_eq!(i[0..2], o2); let mut o4 = [255u8; 4]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o4[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o4[..])).expect("Builtin should not fail"); assert_eq!(i, o4); let mut o8 = [255u8; 8]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])).expect("Builtin should not fail"); assert_eq!(i, o8[..4]); assert_eq!([255u8; 4], o8[4..]); } @@ -406,19 +406,19 @@ mod tests { let i = [0u8; 0]; let mut o = [255u8; 32]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail"); assert_eq!(&o[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").unwrap())[..]); let mut o8 = [255u8; 8]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])).expect("Builtin should not fail"); assert_eq!(&o8[..], &(FromHex::from_hex("e3b0c44298fc1c14").unwrap())[..]); let mut o34 = [255u8; 34]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])).expect("Builtin should not fail"); assert_eq!(&o34[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855ffff").unwrap())[..]); let mut ov = vec![]; - f.execute(&i[..], &mut BytesRef::Flexible(&mut ov)); + f.execute(&i[..], &mut BytesRef::Flexible(&mut ov)).expect("Builtin should not fail"); assert_eq!(&ov[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").unwrap())[..]); } @@ -430,15 +430,15 @@ mod tests { let i = [0u8; 0]; let mut o = [255u8; 32]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail"); assert_eq!(&o[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31").unwrap())[..]); let mut o8 = [255u8; 8]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])).expect("Builtin should not fail"); assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]); let mut o34 = [255u8; 34]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])).expect("Builtin should not fail"); assert_eq!(&o34[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31ffff").unwrap())[..]); } @@ -458,40 +458,40 @@ mod tests { let i = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap(); let mut o = [255u8; 32]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail"); assert_eq!(&o[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddb").unwrap())[..]); let mut o8 = [255u8; 8]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])).expect("Builtin should not fail"); assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]); let mut o34 = [255u8; 34]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])); + f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])).expect("Builtin should not fail"); assert_eq!(&o34[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddbffff").unwrap())[..]); let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001a650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap(); let mut o = [255u8; 32]; - f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])); + f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail"); assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]); let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000").unwrap(); let mut o = [255u8; 32]; - f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])); + f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail"); assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]); let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b").unwrap(); let mut o = [255u8; 32]; - f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])); + f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail"); assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]); let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000001b").unwrap(); let mut o = [255u8; 32]; - f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])); + f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail"); assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]); let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(); let mut o = [255u8; 32]; - f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])); + f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail"); assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]); // TODO: Should this (corrupted version of the above) fail rather than returning some address? @@ -525,7 +525,7 @@ mod tests { let expected = FromHex::from_hex("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); let expected_cost = 1638; - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])); + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail"); assert_eq!(output, expected); assert_eq!(f.cost(&input[..]), expected_cost.into()); } @@ -544,7 +544,7 @@ mod tests { let expected = FromHex::from_hex("0000000000000000000000000000000000000000000000000000000000000000").unwrap(); let expected_cost = 1638; - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])); + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail"); assert_eq!(output, expected); assert_eq!(f.cost(&input[..]), expected_cost.into()); } @@ -564,7 +564,7 @@ mod tests { let expected = FromHex::from_hex("3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab").unwrap(); let expected_cost = 102; - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])); + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail"); assert_eq!(output, expected); assert_eq!(f.cost(&input[..]), expected_cost.into()); } @@ -582,7 +582,7 @@ mod tests { let mut output = vec![]; let expected_cost = 0; - f.execute(&input[..], &mut BytesRef::Flexible(&mut output)); + f.execute(&input[..], &mut BytesRef::Flexible(&mut output)).expect("Builtin should not fail"); assert_eq!(output.len(), 0); // shouldn't have written any output. assert_eq!(f.cost(&input[..]), expected_cost.into()); } @@ -669,7 +669,7 @@ mod tests { let i = [0u8, 1, 2, 3]; let mut o = [255u8; 4]; - b.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); + b.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail"); assert_eq!(i, o); } @@ -691,7 +691,7 @@ mod tests { let i = [0u8, 1, 2, 3]; let mut o = [255u8; 4]; - b.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); + b.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail"); assert_eq!(i, o); } } \ No newline at end of file diff --git a/ethcore/src/evm/evm.rs b/ethcore/src/evm/evm.rs index b561c271f..0e7a4d968 100644 --- a/ethcore/src/evm/evm.rs +++ b/ethcore/src/evm/evm.rs @@ -60,6 +60,7 @@ pub enum Error { /// What was the stack limit limit: usize }, + /// Built-in contract failed on given input BuiltIn(String), /// Returned on evm internal error. Should never be ignored during development. /// Likely to cause consensus issues. From 8a4537fc731c7eda1c92333c5a0d17359192d3fb Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 22 Mar 2017 16:31:43 +0300 Subject: [PATCH 04/10] no-input test --- ethcore/src/builtin.rs | 127 +++++++++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 23 deletions(-) diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index acc495085..a638d06d9 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -326,33 +326,40 @@ impl Impl for ModexpImpl { } } +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::{Fq, AffineG1, G1, Group}; + + 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 x 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 { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { - use bn::{Fq, AffineG1, G1, Group}; - - let mut buf = [0u8; 32]; - let mut next_coord = |reader: &mut io::Chain<&[u8], io::Repeat>| { - reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed"); - Fq::from_slice(&buf[0..32]) - }; + use bn::AffineG1; let mut padded_input = input.chain(io::repeat(0)); - - let px = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 x coordinate"))?; - let py = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 y coordinate"))?; - let p1: G1 = if px == Fq::zero() && py == Fq::zero() { - G1::zero() - } else { - AffineG1::new(px, py).map_err(|_| Error::from("Invalid curve point"))?.into() - }; - - let px = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 x coordinate"))?; - let py = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 y coordinate"))?; - let p2: G1 = if px == Fq::zero() && py == Fq::zero() { - G1::zero() - } else { - AffineG1::new(px, py).map_err(|_| Error::from("Invalid curve point"))?.into() - }; + 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) { @@ -368,6 +375,19 @@ impl Impl for Bn128AddImpl { impl Impl for Bn128MulImpl { 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(()) } } @@ -617,6 +637,22 @@ mod tests { assert_eq!(output, expected); } + + // no input, should not fail + { + let mut empty = [0u8; 0]; + let input = BytesRef::Fixed(&mut empty); + + let mut output = vec![0u8; 64]; + let expected = FromHex::from_hex("\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000" + ).unwrap(); + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail"); + assert_eq!(output, expected); + } + // should fail - point not on curve { let input = FromHex::from_hex("\ @@ -633,6 +669,51 @@ mod tests { } } + + #[test] + fn alt_bn128_mul() { + use rustc_serialize::hex::FromHex; + + let f = Builtin { + pricer: Box::new(Linear { base: 0, word: 0 }), + native: ethereum_builtin("alt_bn128_mul"), + activate_at: 0, + }; + + // zero-point multiplication + { + let input = FromHex::from_hex("\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0200000000000000000000000000000000000000000000000000000000000000" + ).unwrap(); + + let mut output = vec![0u8; 64]; + let expected = FromHex::from_hex("\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000" + ).unwrap(); + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail"); + assert_eq!(output, expected); + } + + // should fail - point not on curve + { + let input = FromHex::from_hex("\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 0f00000000000000000000000000000000000000000000000000000000000000" + ).unwrap(); + + let mut output = vec![0u8; 64]; + + let res = f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])); + assert!(res.is_err(), "There should be built-in error here"); + } + } + + #[test] #[should_panic] fn from_unknown_linear() { From 436ae1333cbccc6cfcd4facc07ac5ba4c3769bb3 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 22 Mar 2017 16:40:44 +0300 Subject: [PATCH 05/10] trace mapping fix --- ethcore/src/types/trace_types/error.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethcore/src/types/trace_types/error.rs b/ethcore/src/types/trace_types/error.rs index c36d86728..184ab962f 100644 --- a/ethcore/src/types/trace_types/error.rs +++ b/ethcore/src/types/trace_types/error.rs @@ -50,7 +50,7 @@ impl<'a> From<&'a EvmError> for Error { EvmError::BadInstruction { .. } => Error::BadInstruction, EvmError::StackUnderflow { .. } => Error::StackUnderflow, EvmError::OutOfStack { .. } => Error::OutOfStack, - EvmError::BuiltIn { .. } => Error::OutOfStack, + EvmError::BuiltIn { .. } => Error::BuiltIn, EvmError::Internal(_) => Error::Internal, } } @@ -106,6 +106,7 @@ impl Decodable for Error { 3 => Ok(StackUnderflow), 4 => Ok(OutOfStack), 5 => Ok(Internal), + 6 => Ok(BuiltIn), _ => Err(DecoderError::Custom("Invalid error type")), } } From 9d23101c9a6b19c5ad2a50b308e39b4a369da4bc Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 22 Mar 2017 17:43:19 +0300 Subject: [PATCH 06/10] update for rv --- ethcore/src/builtin.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index a638d06d9..f65759f72 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -112,8 +112,7 @@ impl Builtin { /// Simple forwarder for execute. pub fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { - self.native.execute(input, output)?; - Ok(()) + self.native.execute(input, output) } /// Whether the builtin is activated at the given block number. @@ -354,6 +353,7 @@ fn read_point(reader: &mut io::Chain<&[u8], io::Repeat>) -> Result<::bn::G1, Err } 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; @@ -374,6 +374,7 @@ impl Impl for Bn128AddImpl { } 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; From 2de67538a25d870d7d51fa33e8758fc146d7baf2 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 22 Mar 2017 18:07:41 +0300 Subject: [PATCH 07/10] updating deps --- Cargo.lock | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b92cbaed9..2b59df5e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,19 +177,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bn" -version = "0.4.2" -source = "git+https://github.com/paritytech/bn#7e513a84330f02603759e370f22af90c99e3e717" +version = "0.4.3" +source = "git+https://github.com/paritytech/bn#59d848e642ad1ff0d60e39348576a6f11ee123b8" dependencies = [ - "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "byteorder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "1.0.0" @@ -397,7 +392,7 @@ version = "1.7.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bn 0.4.2 (git+https://github.com/paritytech/bn)", + "bn 0.4.3 (git+https://github.com/paritytech/bn)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2633,8 +2628,7 @@ dependencies = [ "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum blastfig 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09640e0509d97d5cdff03a9f5daf087a8e04c735c3b113a75139634a19cfc7b2" "checksum bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f421095d2a76fc24cd3fb3f912b90df06be7689912b1bdb423caefae59c258d" -"checksum bn 0.4.2 (git+https://github.com/paritytech/bn)" = "" -"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" +"checksum bn 0.4.3 (git+https://github.com/paritytech/bn)" = "" "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" "checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27" "checksum bytes 0.4.0-dev (git+https://github.com/carllerche/bytes)" = "" From 434ed1b91c7735a93bb3fd7591e93810ce5eea1a Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 24 Mar 2017 15:35:00 +0300 Subject: [PATCH 08/10] remove alt_ --- ethcore/res/ethereum/foundation.json | 4 ++-- ethcore/src/builtin.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index 1debff1d6..54f10b70c 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -190,8 +190,8 @@ "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": "0x7fffffffffffff", "pricing": { "modexp": { "divisor": 20 } } } }, - "0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } }, - "0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } }, + "0000000000000000000000000000000000000006": { "builtin": { "name": "bn128_add", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } }, + "0000000000000000000000000000000000000007": { "builtin": { "name": "bn128_mul", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } }, "3282791d6fd713f1e94f4bfd565eaa78b3a0599d": { "balance": "1337000000000000000000" }, diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index f65759f72..da0ee38e1 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -156,8 +156,8 @@ fn ethereum_builtin(name: &str) -> Box { "sha256" => Box::new(Sha256) as Box, "ripemd160" => Box::new(Ripemd160) as Box, "modexp" => Box::new(ModexpImpl) as Box, - "alt_bn128_add" => Box::new(Bn128AddImpl) as Box, - "alt_bn128_mul" => Box::new(Bn128MulImpl) as Box, + "bn128_add" => Box::new(Bn128AddImpl) as Box, + "bn128_mul" => Box::new(Bn128MulImpl) as Box, _ => panic!("invalid builtin name: {}", name), } } @@ -610,12 +610,12 @@ mod tests { } #[test] - fn alt_bn128_add() { + fn bn128_add() { use rustc_serialize::hex::FromHex; let f = Builtin { pricer: Box::new(Linear { base: 0, word: 0 }), - native: ethereum_builtin("alt_bn128_add"), + native: ethereum_builtin("bn128_add"), activate_at: 0, }; @@ -672,12 +672,12 @@ mod tests { #[test] - fn alt_bn128_mul() { + fn bn128_mul() { use rustc_serialize::hex::FromHex; let f = Builtin { pricer: Box::new(Linear { base: 0, word: 0 }), - native: ethereum_builtin("alt_bn128_mul"), + native: ethereum_builtin("bn128_mul"), activate_at: 0, }; From 34fb39da5b902cc645b7c5b0f3811e72bf8374b3 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 25 Mar 2017 23:30:11 +0300 Subject: [PATCH 09/10] avoid allocating string --- ethcore/src/builtin.rs | 4 ++-- ethcore/src/evm/evm.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index da0ee38e1..bdedd5739 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -28,11 +28,11 @@ use ethkey::{Signature, recover as ec_recover}; use ethjson; #[derive(Debug)] -pub struct Error(pub String); +pub struct Error(pub &'static str); impl From<&'static str> for Error { fn from(val: &'static str) -> Self { - Error(val.to_owned()) + Error(val) } } diff --git a/ethcore/src/evm/evm.rs b/ethcore/src/evm/evm.rs index 0e7a4d968..265b83559 100644 --- a/ethcore/src/evm/evm.rs +++ b/ethcore/src/evm/evm.rs @@ -61,7 +61,7 @@ pub enum Error { limit: usize }, /// Built-in contract failed on given input - BuiltIn(String), + BuiltIn(&'static str), /// Returned on evm internal error. Should never be ignored during development. /// Likely to cause consensus issues. Internal(String), From c313857485c7c51d12751fbab809a226e5dab747 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 27 Mar 2017 18:17:49 +0300 Subject: [PATCH 10/10] fix error handling --- ethcore/src/executive.rs | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 4fdd9cbbd..4183a5005 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -276,25 +276,31 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let cost = builtin.cost(data); if cost <= params.gas { - builtin.execute(data, &mut output)?; - self.state.discard_checkpoint(); + if let Err(e) = builtin.execute(data, &mut output) { + self.state.revert_to_checkpoint(); + let evm_err: evm::evm::Error = e.into(); + tracer.trace_failed_call(trace_info, vec![], evm_err.clone().into()); + Err(evm_err) + } else { + self.state.discard_checkpoint(); - // trace only top level calls to builtins to avoid DDoS attacks - if self.depth == 0 { - let mut trace_output = tracer.prepare_trace_output(); - if let Some(mut out) = trace_output.as_mut() { - *out = output.to_owned(); + // trace only top level calls to builtins to avoid DDoS attacks + if self.depth == 0 { + let mut trace_output = tracer.prepare_trace_output(); + if let Some(mut out) = trace_output.as_mut() { + *out = output.to_owned(); + } + + tracer.trace_call( + trace_info, + cost, + trace_output, + vec![] + ); } - tracer.trace_call( - trace_info, - cost, - trace_output, - vec![] - ); + Ok(params.gas - cost) } - - Ok(params.gas - cost) } else { // just drain the whole gas self.state.revert_to_checkpoint();