Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ authors = ["Ethcore <admin@ethcore.io>"]
[dependencies]
log = "0.3"
env_logger = "0.3"
ethcore-util = "0.1.0"
ethcore-util = { path = "../ethcore-util" }
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we shouldn't hardcode paths. It's better to use .cargo/config and overwrite paths only locally.

eg.

> ls -a
.cargo ethcore ethcore-client ethcore-util

> cat .cargo/config
paths = ["/Users/marek/projects/ethcore/ethcore-util", "/Users/marek/projects/ethcore/ethcore"]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason that causes a trip to crates.io and recompilation on each cargo build. A considerable slowdown

rustc-serialize = "0.3"
flate2 = "0.2"
rocksdb = "0.2.1"
heapsize = "0.2.0"
rust-crypto = "0.2.34"

evmjit = { path = "rust-evmjit", optional = true }

Expand Down
34 changes: 34 additions & 0 deletions res/morden.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"engineName": "Ethash",
"params": {
"accountStartNonce": "0x0100000",
"frontierCompatibilityModeLimit": "0xfffa2990",
"maximumExtraDataSize": "0x20",
"tieBreakingGas": false,
"minGasLimit": "0x1388",
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar": "",
"networkID" : "0x2"
},
"genesis": {
"nonce": "0x00006d6f7264656e",
"difficulty": "0x20000",
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2fefd8"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
}
}
261 changes: 261 additions & 0 deletions src/builtin.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
use std::cmp::min;
use std::fmt;
use util::uint::*;
use util::hash::*;
use util::sha3::*;
use util::bytes::*;
use rustc_serialize::json::Json;
use std::io::Write;
use util::crypto::*;
use crypto::sha2::Sha256;
use crypto::ripemd160::Ripemd160;
use crypto::digest::Digest;

/// Definition of a contract whose implementation is built-in.
pub struct Builtin {
Expand All @@ -8,3 +19,253 @@ pub struct Builtin {
/// being placed into the second.
pub execute: Box<Fn(&[u8], &mut [u8])>,
}

impl fmt::Debug for Builtin {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<Builtin>")
}
}

impl Builtin {
/// Create a new object from components.
pub fn new(cost: Box<Fn(usize) -> U256>, execute: Box<Fn(&[u8], &mut [u8])>) -> Builtin {
Builtin {cost: cost, execute: execute}
}

/// Create a new object from a builtin-function name with a linear cost associated with input size.
pub fn from_named_linear(name: &str, base_cost: usize, word_cost: usize) -> Option<Builtin> {
new_builtin_exec(name).map(|b| {
let cost = Box::new(move|s: usize| -> U256 {
U256::from(base_cost) + U256::from(word_cost) * U256::from((s + 31) / 32)
});
Self::new(cost, b)
})
}

/// Create a builtin from JSON.
///
/// JSON must be of the form `{ "name": "identity", "linear": {"base": 10, "word": 20} }`.
pub fn from_json(json: &Json) -> Option<Builtin> {
// NICE: figure out a more convenient means of handing errors here.
if let Json::String(ref name) = json["name"] {
if let Json::Object(ref o) = json["linear"] {
if let Json::U64(ref word) = o["word"] {
if let Json::U64(ref base) = o["base"] {
return Self::from_named_linear(&name[..], *base as usize, *word as usize);
}
}
}
}
None
}
}

pub fn copy_to(src: &[u8], dest: &mut[u8]) {
// NICE: optimise
for i in 0..min(src.len(), dest.len()) {
dest[i] = src[i];
}
}

/// Create a new builtin executor according to `name`.
/// TODO: turn in to a factory with dynamic registration.
pub fn new_builtin_exec(name: &str) -> Option<Box<Fn(&[u8], &mut [u8])>> {
match name {
"identity" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
for i in 0..min(input.len(), output.len()) {
output[i] = input[i];
}
})),
"ecrecover" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
#[repr(packed)]
#[derive(Debug)]
struct InType {
hash: H256,
v: H256,
r: H256,
s: H256,
}
let mut it: InType = InType { hash: H256::new(), v: H256::new(), r: H256::new(), s: H256::new() };
it.copy_raw(input);
if it.v == H256::from(&U256::from(27)) || it.v == H256::from(&U256::from(28)) {
let s = Signature::from_rsv(&it.r, &it.s, it.v[31] - 27);
if is_valid(&s) {
match recover(&s, &it.hash) {
Ok(p) => {
let r = p.as_slice().sha3();
// NICE: optimise and separate out into populate-like function
for i in 0..min(32, output.len()) {
output[i] = if i < 12 {0} else {r[i]};
}
}
_ => {}
};
}
}
})),
"sha256" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
let mut sha = Sha256::new();
sha.input(input);
if output.len() >= 32 {
sha.result(output);
} else {
let mut ret = H256::new();
sha.result(ret.as_slice_mut());
copy_to(&ret, output);
}
})),
"ripemd160" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
let mut sha = Ripemd160::new();
sha.input(input);
let mut ret = H256::new();
sha.result(&mut ret.as_slice_mut()[12..32]);
copy_to(&ret, output);
})),
_ => None
}
}

#[test]
fn identity() {
let f = new_builtin_exec("identity").unwrap();
let i = [0u8, 1, 2, 3];

let mut o2 = [255u8; 2];
f(&i[..], &mut o2[..]);
assert_eq!(i[0..2], o2);

let mut o4 = [255u8; 4];
f(&i[..], &mut o4[..]);
assert_eq!(i, o4);

let mut o8 = [255u8; 8];
f(&i[..], &mut o8[..]);
assert_eq!(i, o8[..4]);
assert_eq!([255u8; 4], o8[4..]);
}

#[test]
fn sha256() {
use rustc_serialize::hex::FromHex;
let f = new_builtin_exec("sha256").unwrap();
let i = [0u8; 0];

let mut o = [255u8; 32];
f(&i[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").unwrap())[..]);

let mut o8 = [255u8; 8];
f(&i[..], &mut o8[..]);
assert_eq!(&o8[..], &(FromHex::from_hex("e3b0c44298fc1c14").unwrap())[..]);

let mut o34 = [255u8; 34];
f(&i[..], &mut o34[..]);
assert_eq!(&o34[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855ffff").unwrap())[..]);
}

#[test]
fn ripemd160() {
use rustc_serialize::hex::FromHex;
let f = new_builtin_exec("ripemd160").unwrap();
let i = [0u8; 0];

let mut o = [255u8; 32];
f(&i[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31").unwrap())[..]);

let mut o8 = [255u8; 8];
f(&i[..], &mut o8[..]);
assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);

let mut o34 = [255u8; 34];
f(&i[..], &mut o34[..]);
assert_eq!(&o34[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31ffff").unwrap())[..]);
}

#[test]
fn ecrecover() {
use rustc_serialize::hex::FromHex;
/*let k = KeyPair::from_secret(b"test".sha3()).unwrap();
let a: Address = From::from(k.public().sha3());
println!("Address: {}", a);
let m = b"hello world".sha3();
println!("Message: {}", m);
let s = k.sign(&m).unwrap();
println!("Signed: {}", s);*/

let f = new_builtin_exec("ecrecover").unwrap();
let i = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();

let mut o = [255u8; 32];
f(&i[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddb").unwrap())[..]);

let mut o8 = [255u8; 8];
f(&i[..], &mut o8[..]);
assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);

let mut o34 = [255u8; 34];
f(&i[..], &mut o34[..]);
assert_eq!(&o34[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddbffff").unwrap())[..]);

let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001a650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);

let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);

let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);

let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000001b").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);

let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);

// TODO: Should this (corrupted version of the above) fail rather than returning some address?
/* let i_bad = FromHex::from_hex("48173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
let mut o = [255u8; 32];
f(&i_bad[..], &mut o[..]);
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);*/
}

#[test]
fn from_named_linear() {
let b = Builtin::from_named_linear("identity", 10, 20).unwrap();
assert_eq!((*b.cost)(0), U256::from(10));
assert_eq!((*b.cost)(1), U256::from(30));
assert_eq!((*b.cost)(32), U256::from(30));
assert_eq!((*b.cost)(33), U256::from(50));

let i = [0u8, 1, 2, 3];
let mut o = [255u8; 4];
(*b.execute)(&i[..], &mut o[..]);
assert_eq!(i, o);
}

#[test]
fn from_json() {
let text = "{ \"name\": \"identity\", \"linear\": {\"base\": 10, \"word\": 20} }";
let json = Json::from_str(text).unwrap();
let b = Builtin::from_json(&json).unwrap();
assert_eq!((*b.cost)(0), U256::from(10));
assert_eq!((*b.cost)(1), U256::from(30));
assert_eq!((*b.cost)(32), U256::from(30));
assert_eq!((*b.cost)(33), U256::from(50));

let i = [0u8, 1, 2, 3];
let mut o = [255u8; 4];
(*b.execute)(&i[..], &mut o[..]);
assert_eq!(i, o);
}
2 changes: 1 addition & 1 deletion src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub trait Engine {
// TODO: consider including State in the params.
fn populate_from_parent(&self, _header: &mut Header, _parent: &Header) -> Result<(), EthcoreError> { Ok(()) }

// TODO: buildin contract routing - to do this properly, it will require removing the built-in configuration-reading logic
// TODO: builtin contract routing - to do this properly, it will require removing the built-in configuration-reading logic
// from Spec into here and removing the Spec::builtins field.
/* fn is_builtin(&self, a: Address) -> bool;
fn cost_of_builtin(&self, a: Address, in: &[u8]) -> bignum;
Expand Down
22 changes: 22 additions & 0 deletions src/ethash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use engine::Engine;
use spec::Spec;
use evm_schedule::EvmSchedule;
use env_info::EnvInfo;

/// Engine using Ethash proof-of-work consensus algorithm, suitable for Ethereum
/// mainnet chains in the Olympic, Frontier and Homestead eras.
pub struct Ethash {
spec: Spec,
}

impl Ethash {
pub fn new_boxed(spec: Spec) -> Box<Engine> {
Box::new(Ethash{spec: spec})
}
}

impl Engine for Ethash {
fn name(&self) -> &str { "Ethash" }
fn spec(&self) -> &Spec { &self.spec }
fn evm_schedule(&self, _env_info: &EnvInfo) -> EvmSchedule { EvmSchedule::new_frontier() }
}
2 changes: 1 addition & 1 deletion src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ impl Genesis {
// ethash specific fields
let mixhash = H256::from_str(&json["mixhash"].as_string().unwrap()[2..]).unwrap();
let nonce = H64::from_str(&json["nonce"].as_string().unwrap()[2..]).unwrap();
vec![mixhash.to_vec(), nonce.to_vec()]
vec![encode(&mixhash), encode(&nonce)]
}
};

Expand Down
Loading