Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.

Commit 7cf9f0e

Browse files
author
Gav Wood
committed
Merge pull request #54 from gavofyork/gav
Spec with tested Morden genesis decoder and builtins.
2 parents d15d803 + 1c71640 commit 7cf9f0e

9 files changed

+486
-67
lines changed

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ authors = ["Ethcore <[email protected]>"]
99
[dependencies]
1010
log = "0.3"
1111
env_logger = "0.3"
12-
ethcore-util = "0.1.0"
12+
ethcore-util = { path = "../ethcore-util" }
1313
rustc-serialize = "0.3"
1414
flate2 = "0.2"
1515
rocksdb = "0.2.1"
1616
heapsize = "0.2.0"
17+
rust-crypto = "0.2.34"
1718

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

res/morden.json

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"engineName": "Ethash",
3+
"params": {
4+
"accountStartNonce": "0x0100000",
5+
"frontierCompatibilityModeLimit": "0xfffa2990",
6+
"maximumExtraDataSize": "0x20",
7+
"tieBreakingGas": false,
8+
"minGasLimit": "0x1388",
9+
"gasLimitBoundDivisor": "0x0400",
10+
"minimumDifficulty": "0x020000",
11+
"difficultyBoundDivisor": "0x0800",
12+
"durationLimit": "0x0d",
13+
"blockReward": "0x4563918244F40000",
14+
"registrar": "",
15+
"networkID" : "0x2"
16+
},
17+
"genesis": {
18+
"nonce": "0x00006d6f7264656e",
19+
"difficulty": "0x20000",
20+
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
21+
"author": "0x0000000000000000000000000000000000000000",
22+
"timestamp": "0x00",
23+
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
24+
"extraData": "0x",
25+
"gasLimit": "0x2fefd8"
26+
},
27+
"accounts": {
28+
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
29+
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
30+
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
31+
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
32+
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
33+
}
34+
}

src/builtin.rs

+261
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1+
use std::cmp::min;
2+
use std::fmt;
13
use util::uint::*;
4+
use util::hash::*;
5+
use util::sha3::*;
6+
use util::bytes::*;
7+
use rustc_serialize::json::Json;
8+
use std::io::Write;
9+
use util::crypto::*;
10+
use crypto::sha2::Sha256;
11+
use crypto::ripemd160::Ripemd160;
12+
use crypto::digest::Digest;
213

314
/// Definition of a contract whose implementation is built-in.
415
pub struct Builtin {
@@ -8,3 +19,253 @@ pub struct Builtin {
819
/// being placed into the second.
920
pub execute: Box<Fn(&[u8], &mut [u8])>,
1021
}
22+
23+
impl fmt::Debug for Builtin {
24+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25+
write!(f, "<Builtin>")
26+
}
27+
}
28+
29+
impl Builtin {
30+
/// Create a new object from components.
31+
pub fn new(cost: Box<Fn(usize) -> U256>, execute: Box<Fn(&[u8], &mut [u8])>) -> Builtin {
32+
Builtin {cost: cost, execute: execute}
33+
}
34+
35+
/// Create a new object from a builtin-function name with a linear cost associated with input size.
36+
pub fn from_named_linear(name: &str, base_cost: usize, word_cost: usize) -> Option<Builtin> {
37+
new_builtin_exec(name).map(|b| {
38+
let cost = Box::new(move|s: usize| -> U256 {
39+
U256::from(base_cost) + U256::from(word_cost) * U256::from((s + 31) / 32)
40+
});
41+
Self::new(cost, b)
42+
})
43+
}
44+
45+
/// Create a builtin from JSON.
46+
///
47+
/// JSON must be of the form `{ "name": "identity", "linear": {"base": 10, "word": 20} }`.
48+
pub fn from_json(json: &Json) -> Option<Builtin> {
49+
// NICE: figure out a more convenient means of handing errors here.
50+
if let Json::String(ref name) = json["name"] {
51+
if let Json::Object(ref o) = json["linear"] {
52+
if let Json::U64(ref word) = o["word"] {
53+
if let Json::U64(ref base) = o["base"] {
54+
return Self::from_named_linear(&name[..], *base as usize, *word as usize);
55+
}
56+
}
57+
}
58+
}
59+
None
60+
}
61+
}
62+
63+
pub fn copy_to(src: &[u8], dest: &mut[u8]) {
64+
// NICE: optimise
65+
for i in 0..min(src.len(), dest.len()) {
66+
dest[i] = src[i];
67+
}
68+
}
69+
70+
/// Create a new builtin executor according to `name`.
71+
/// TODO: turn in to a factory with dynamic registration.
72+
pub fn new_builtin_exec(name: &str) -> Option<Box<Fn(&[u8], &mut [u8])>> {
73+
match name {
74+
"identity" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
75+
for i in 0..min(input.len(), output.len()) {
76+
output[i] = input[i];
77+
}
78+
})),
79+
"ecrecover" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
80+
#[repr(packed)]
81+
#[derive(Debug)]
82+
struct InType {
83+
hash: H256,
84+
v: H256,
85+
r: H256,
86+
s: H256,
87+
}
88+
let mut it: InType = InType { hash: H256::new(), v: H256::new(), r: H256::new(), s: H256::new() };
89+
it.copy_raw(input);
90+
if it.v == H256::from(&U256::from(27)) || it.v == H256::from(&U256::from(28)) {
91+
let s = Signature::from_rsv(&it.r, &it.s, it.v[31] - 27);
92+
if is_valid(&s) {
93+
match recover(&s, &it.hash) {
94+
Ok(p) => {
95+
let r = p.as_slice().sha3();
96+
// NICE: optimise and separate out into populate-like function
97+
for i in 0..min(32, output.len()) {
98+
output[i] = if i < 12 {0} else {r[i]};
99+
}
100+
}
101+
_ => {}
102+
};
103+
}
104+
}
105+
})),
106+
"sha256" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
107+
let mut sha = Sha256::new();
108+
sha.input(input);
109+
if output.len() >= 32 {
110+
sha.result(output);
111+
} else {
112+
let mut ret = H256::new();
113+
sha.result(ret.as_slice_mut());
114+
copy_to(&ret, output);
115+
}
116+
})),
117+
"ripemd160" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
118+
let mut sha = Ripemd160::new();
119+
sha.input(input);
120+
let mut ret = H256::new();
121+
sha.result(&mut ret.as_slice_mut()[12..32]);
122+
copy_to(&ret, output);
123+
})),
124+
_ => None
125+
}
126+
}
127+
128+
#[test]
129+
fn identity() {
130+
let f = new_builtin_exec("identity").unwrap();
131+
let i = [0u8, 1, 2, 3];
132+
133+
let mut o2 = [255u8; 2];
134+
f(&i[..], &mut o2[..]);
135+
assert_eq!(i[0..2], o2);
136+
137+
let mut o4 = [255u8; 4];
138+
f(&i[..], &mut o4[..]);
139+
assert_eq!(i, o4);
140+
141+
let mut o8 = [255u8; 8];
142+
f(&i[..], &mut o8[..]);
143+
assert_eq!(i, o8[..4]);
144+
assert_eq!([255u8; 4], o8[4..]);
145+
}
146+
147+
#[test]
148+
fn sha256() {
149+
use rustc_serialize::hex::FromHex;
150+
let f = new_builtin_exec("sha256").unwrap();
151+
let i = [0u8; 0];
152+
153+
let mut o = [255u8; 32];
154+
f(&i[..], &mut o[..]);
155+
assert_eq!(&o[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").unwrap())[..]);
156+
157+
let mut o8 = [255u8; 8];
158+
f(&i[..], &mut o8[..]);
159+
assert_eq!(&o8[..], &(FromHex::from_hex("e3b0c44298fc1c14").unwrap())[..]);
160+
161+
let mut o34 = [255u8; 34];
162+
f(&i[..], &mut o34[..]);
163+
assert_eq!(&o34[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855ffff").unwrap())[..]);
164+
}
165+
166+
#[test]
167+
fn ripemd160() {
168+
use rustc_serialize::hex::FromHex;
169+
let f = new_builtin_exec("ripemd160").unwrap();
170+
let i = [0u8; 0];
171+
172+
let mut o = [255u8; 32];
173+
f(&i[..], &mut o[..]);
174+
assert_eq!(&o[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31").unwrap())[..]);
175+
176+
let mut o8 = [255u8; 8];
177+
f(&i[..], &mut o8[..]);
178+
assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);
179+
180+
let mut o34 = [255u8; 34];
181+
f(&i[..], &mut o34[..]);
182+
assert_eq!(&o34[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31ffff").unwrap())[..]);
183+
}
184+
185+
#[test]
186+
fn ecrecover() {
187+
use rustc_serialize::hex::FromHex;
188+
/*let k = KeyPair::from_secret(b"test".sha3()).unwrap();
189+
let a: Address = From::from(k.public().sha3());
190+
println!("Address: {}", a);
191+
let m = b"hello world".sha3();
192+
println!("Message: {}", m);
193+
let s = k.sign(&m).unwrap();
194+
println!("Signed: {}", s);*/
195+
196+
let f = new_builtin_exec("ecrecover").unwrap();
197+
let i = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
198+
199+
let mut o = [255u8; 32];
200+
f(&i[..], &mut o[..]);
201+
assert_eq!(&o[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddb").unwrap())[..]);
202+
203+
let mut o8 = [255u8; 8];
204+
f(&i[..], &mut o8[..]);
205+
assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);
206+
207+
let mut o34 = [255u8; 34];
208+
f(&i[..], &mut o34[..]);
209+
assert_eq!(&o34[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddbffff").unwrap())[..]);
210+
211+
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001a650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
212+
let mut o = [255u8; 32];
213+
f(&i_bad[..], &mut o[..]);
214+
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
215+
216+
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000").unwrap();
217+
let mut o = [255u8; 32];
218+
f(&i_bad[..], &mut o[..]);
219+
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
220+
221+
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b").unwrap();
222+
let mut o = [255u8; 32];
223+
f(&i_bad[..], &mut o[..]);
224+
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
225+
226+
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000001b").unwrap();
227+
let mut o = [255u8; 32];
228+
f(&i_bad[..], &mut o[..]);
229+
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
230+
231+
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
232+
let mut o = [255u8; 32];
233+
f(&i_bad[..], &mut o[..]);
234+
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
235+
236+
// TODO: Should this (corrupted version of the above) fail rather than returning some address?
237+
/* let i_bad = FromHex::from_hex("48173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
238+
let mut o = [255u8; 32];
239+
f(&i_bad[..], &mut o[..]);
240+
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);*/
241+
}
242+
243+
#[test]
244+
fn from_named_linear() {
245+
let b = Builtin::from_named_linear("identity", 10, 20).unwrap();
246+
assert_eq!((*b.cost)(0), U256::from(10));
247+
assert_eq!((*b.cost)(1), U256::from(30));
248+
assert_eq!((*b.cost)(32), U256::from(30));
249+
assert_eq!((*b.cost)(33), U256::from(50));
250+
251+
let i = [0u8, 1, 2, 3];
252+
let mut o = [255u8; 4];
253+
(*b.execute)(&i[..], &mut o[..]);
254+
assert_eq!(i, o);
255+
}
256+
257+
#[test]
258+
fn from_json() {
259+
let text = "{ \"name\": \"identity\", \"linear\": {\"base\": 10, \"word\": 20} }";
260+
let json = Json::from_str(text).unwrap();
261+
let b = Builtin::from_json(&json).unwrap();
262+
assert_eq!((*b.cost)(0), U256::from(10));
263+
assert_eq!((*b.cost)(1), U256::from(30));
264+
assert_eq!((*b.cost)(32), U256::from(30));
265+
assert_eq!((*b.cost)(33), U256::from(50));
266+
267+
let i = [0u8, 1, 2, 3];
268+
let mut o = [255u8; 4];
269+
(*b.execute)(&i[..], &mut o[..]);
270+
assert_eq!(i, o);
271+
}

src/engine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub trait Engine {
5757
// TODO: consider including State in the params.
5858
fn populate_from_parent(&self, _header: &mut Header, _parent: &Header) -> Result<(), EthcoreError> { Ok(()) }
5959

60-
// TODO: buildin contract routing - to do this properly, it will require removing the built-in configuration-reading logic
60+
// TODO: builtin contract routing - to do this properly, it will require removing the built-in configuration-reading logic
6161
// from Spec into here and removing the Spec::builtins field.
6262
/* fn is_builtin(&self, a: Address) -> bool;
6363
fn cost_of_builtin(&self, a: Address, in: &[u8]) -> bignum;

src/ethash.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use engine::Engine;
2+
use spec::Spec;
3+
use evm_schedule::EvmSchedule;
4+
use env_info::EnvInfo;
5+
6+
/// Engine using Ethash proof-of-work consensus algorithm, suitable for Ethereum
7+
/// mainnet chains in the Olympic, Frontier and Homestead eras.
8+
pub struct Ethash {
9+
spec: Spec,
10+
}
11+
12+
impl Ethash {
13+
pub fn new_boxed(spec: Spec) -> Box<Engine> {
14+
Box::new(Ethash{spec: spec})
15+
}
16+
}
17+
18+
impl Engine for Ethash {
19+
fn name(&self) -> &str { "Ethash" }
20+
fn spec(&self) -> &Spec { &self.spec }
21+
fn evm_schedule(&self, _env_info: &EnvInfo) -> EvmSchedule { EvmSchedule::new_frontier() }
22+
}

src/genesis.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ impl Genesis {
8989
// ethash specific fields
9090
let mixhash = H256::from_str(&json["mixhash"].as_string().unwrap()[2..]).unwrap();
9191
let nonce = H64::from_str(&json["nonce"].as_string().unwrap()[2..]).unwrap();
92-
vec![mixhash.to_vec(), nonce.to_vec()]
92+
vec![encode(&mixhash), encode(&nonce)]
9393
}
9494
};
9595

0 commit comments

Comments
 (0)