,
+ pub headers_raw: String,
+ pub body: String,
+}
+
+pub fn read_block(lines: &mut Lines, all: bool) -> String {
+ let mut block = String::new();
+ loop {
+ let line = lines.next();
+ match line {
+ None => break,
+ Some("") if !all => break,
+ Some(v) => {
+ block.push_str(v);
+ block.push_str("\n");
+ },
+ }
+ }
+ block
+}
+
+pub fn request(server: Server, request: &str) -> Response {
+ let mut req = TcpStream::connect(server.addr()).unwrap();
+ req.write_all(request.as_bytes()).unwrap();
+
+ let mut response = String::new();
+ req.read_to_string(&mut response).unwrap();
+
+ let mut lines = response.lines();
+ let status = lines.next().unwrap().to_owned();
+ let headers_raw = read_block(&mut lines, false);
+ let headers = headers_raw.split('\n').map(|v| v.to_owned()).collect();
+ let body = read_block(&mut lines, true);
+
+ Response {
+ status: status,
+ headers: headers,
+ headers_raw: headers_raw,
+ body: body,
+ }
+}
+
diff --git a/dapps/src/tests/mod.rs b/dapps/src/tests/mod.rs
new file mode 100644
index 000000000..8c5bf2283
--- /dev/null
+++ b/dapps/src/tests/mod.rs
@@ -0,0 +1,25 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity 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 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. If not, see .
+
+//! Dapps server test suite
+
+mod helpers;
+
+mod api;
+mod authorization;
+mod redirection;
+mod validation;
+
diff --git a/dapps/src/tests/redirection.rs b/dapps/src/tests/redirection.rs
new file mode 100644
index 000000000..53aa393e2
--- /dev/null
+++ b/dapps/src/tests/redirection.rs
@@ -0,0 +1,185 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity 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 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. If not, see .
+
+use tests::helpers::{serve, request};
+
+#[test]
+fn should_redirect_to_home() {
+ // given
+ let server = serve();
+
+ // when
+ let response = request(server,
+ "\
+ GET / HTTP/1.1\r\n\
+ Host: 127.0.0.1:8080\r\n\
+ Connection: close\r\n\
+ \r\n\
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 302 Found".to_owned());
+ assert_eq!(response.headers.get(0).unwrap(), "Location: /home/");
+}
+
+#[test]
+fn should_redirect_to_home_when_trailing_slash_is_missing() {
+ // given
+ let server = serve();
+
+ // when
+ let response = request(server,
+ "\
+ GET /app HTTP/1.1\r\n\
+ Host: 127.0.0.1:8080\r\n\
+ Connection: close\r\n\
+ \r\n\
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 302 Found".to_owned());
+ assert_eq!(response.headers.get(0).unwrap(), "Location: /home/");
+}
+
+#[test]
+fn should_redirect_to_home_on_invalid_dapp() {
+ // given
+ let server = serve();
+
+ // when
+ let response = request(server,
+ "\
+ GET /invaliddapp/ HTTP/1.1\r\n\
+ Host: 127.0.0.1:8080\r\n\
+ Connection: close\r\n\
+ \r\n\
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 302 Found".to_owned());
+ assert_eq!(response.headers.get(0).unwrap(), "Location: /home/");
+}
+
+#[test]
+fn should_redirect_to_home_on_invalid_dapp_with_domain() {
+ // given
+ let server = serve();
+
+ // when
+ let response = request(server,
+ "\
+ GET / HTTP/1.1\r\n\
+ Host: invaliddapp.parity\r\n\
+ Connection: close\r\n\
+ \r\n\
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 302 Found".to_owned());
+ assert_eq!(response.headers.get(0).unwrap(), "Location: http://home.parity/");
+}
+
+#[test]
+fn should_serve_rpc() {
+ // given
+ let server = serve();
+
+ // when
+ let response = request(server,
+ "\
+ POST / HTTP/1.1\r\n\
+ Host: 127.0.0.1:8080\r\n\
+ Connection: close\r\n\
+ Content-Type: application/json\r\n
+ \r\n\
+ {}
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned());
+ assert_eq!(response.body, format!("57\n{}\n0\n\n", r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error","data":null},"id":null}"#));
+}
+
+#[test]
+fn should_serve_rpc_at_slash_rpc() {
+ // given
+ let server = serve();
+
+ // when
+ let response = request(server,
+ "\
+ POST /rpc HTTP/1.1\r\n\
+ Host: 127.0.0.1:8080\r\n\
+ Connection: close\r\n\
+ Content-Type: application/json\r\n
+ \r\n\
+ {}
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned());
+ assert_eq!(response.body, format!("57\n{}\n0\n\n", r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error","data":null},"id":null}"#));
+}
+
+
+#[test]
+fn should_serve_proxy_pac() {
+ // given
+ let server = serve();
+
+ // when
+ let response = request(server,
+ "\
+ GET /proxy/proxy.pac HTTP/1.1\r\n\
+ Host: 127.0.0.1:8080\r\n\
+ Connection: close\r\n\
+ \r\n\
+ {}
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned());
+ assert_eq!(response.body, "86\n\nfunction FindProxyForURL(url, host) {\n\tif (shExpMatch(host, \"*.parity\"))\n\t{\n\t\treturn \"PROXY 127.0.0.1:8080\";\n\t}\n\n\treturn \"DIRECT\";\n}\n\n0\n\n".to_owned());
+}
+
+#[test]
+fn should_serve_utils() {
+ // given
+ let server = serve();
+
+ // when
+ let response = request(server,
+ "\
+ GET /parity-utils/inject.js HTTP/1.1\r\n\
+ Host: 127.0.0.1:8080\r\n\
+ Connection: close\r\n\
+ \r\n\
+ {}
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned());
+ assert_eq!(response.body.contains("function(){"), true);
+}
+
diff --git a/dapps/src/tests/validation.rs b/dapps/src/tests/validation.rs
new file mode 100644
index 000000000..b233a07d8
--- /dev/null
+++ b/dapps/src/tests/validation.rs
@@ -0,0 +1,79 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity 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 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. If not, see .
+
+use tests::helpers::{serve_hosts, request};
+
+#[test]
+fn should_reject_invalid_host() {
+ // given
+ let server = serve_hosts(Some(vec!["localhost:8080".into()]));
+
+ // when
+ let response = request(server,
+ "\
+ GET / HTTP/1.1\r\n\
+ Host: 127.0.0.1:8080\r\n\
+ Connection: close\r\n\
+ \r\n\
+ {}
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 403 Forbidden".to_owned());
+ assert_eq!(response.body, "85\n\n\t\tRequest with disallowed Host
header has been blocked.
\n\t\tCheck the URL in your browser address bar.
\n\t\t\n0\n\n".to_owned());
+}
+
+#[test]
+fn should_allow_valid_host() {
+ // given
+ let server = serve_hosts(Some(vec!["localhost:8080".into()]));
+
+ // when
+ let response = request(server,
+ "\
+ GET /home/ HTTP/1.1\r\n\
+ Host: localhost:8080\r\n\
+ Connection: close\r\n\
+ \r\n\
+ {}
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned());
+}
+
+#[test]
+fn should_serve_dapps_domains() {
+ // given
+ let server = serve_hosts(Some(vec!["localhost:8080".into()]));
+
+ // when
+ let response = request(server,
+ "\
+ GET / HTTP/1.1\r\n\
+ Host: home.parity\r\n\
+ Connection: close\r\n\
+ \r\n\
+ {}
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned());
+}
+
diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs
index cd02b9a1b..784e71dc0 100644
--- a/ethcore/src/block.rs
+++ b/ethcore/src/block.rs
@@ -245,11 +245,11 @@ impl<'x> OpenBlock<'x> {
last_hashes: last_hashes,
};
- r.block.base.header.parent_hash = parent.hash();
- r.block.base.header.number = parent.number + 1;
- r.block.base.header.author = author;
+ r.block.base.header.set_parent_hash(parent.hash());
+ r.block.base.header.set_number(parent.number() + 1);
+ r.block.base.header.set_author(author);
r.block.base.header.set_timestamp_now(parent.timestamp());
- r.block.base.header.extra_data = extra_data;
+ r.block.base.header.set_extra_data(extra_data);
r.block.base.header.note_dirty();
engine.populate_from_parent(&mut r.block.base.header, parent, gas_range_target.0, gas_range_target.1);
@@ -309,13 +309,13 @@ impl<'x> OpenBlock<'x> {
pub fn env_info(&self) -> EnvInfo {
// TODO: memoise.
EnvInfo {
- number: self.block.base.header.number,
- author: self.block.base.header.author.clone(),
- timestamp: self.block.base.header.timestamp,
- difficulty: self.block.base.header.difficulty.clone(),
+ number: self.block.base.header.number(),
+ author: self.block.base.header.author().clone(),
+ timestamp: self.block.base.header.timestamp(),
+ difficulty: self.block.base.header.difficulty().clone(),
last_hashes: self.last_hashes.clone(),
gas_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used),
- gas_limit: self.block.base.header.gas_limit.clone(),
+ gas_limit: self.block.base.header.gas_limit().clone(),
}
}
@@ -349,14 +349,13 @@ impl<'x> OpenBlock<'x> {
let unclosed_state = s.block.state.clone();
s.engine.on_close_block(&mut s.block);
- s.block.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|e| e.rlp_bytes().to_vec()).collect());
+ s.block.base.header.set_transactions_root(ordered_trie_root(s.block.base.transactions.iter().map(|e| e.rlp_bytes().to_vec()).collect()));
let uncle_bytes = s.block.base.uncles.iter().fold(RlpStream::new_list(s.block.base.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out();
- s.block.base.header.uncles_hash = uncle_bytes.sha3();
- s.block.base.header.state_root = s.block.state.root().clone();
- s.block.base.header.receipts_root = ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes().to_vec()).collect());
- s.block.base.header.log_bloom = s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b}); //TODO: use |= operator
- s.block.base.header.gas_used = s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used);
- s.block.base.header.note_dirty();
+ s.block.base.header.set_uncles_hash(uncle_bytes.sha3());
+ s.block.base.header.set_state_root(s.block.state.root().clone());
+ s.block.base.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes().to_vec()).collect()));
+ s.block.base.header.set_log_bloom(s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b})); //TODO: use |= operator
+ s.block.base.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used));
ClosedBlock {
block: s.block,
@@ -371,20 +370,19 @@ impl<'x> OpenBlock<'x> {
let mut s = self;
s.engine.on_close_block(&mut s.block);
- if s.block.base.header.transactions_root.is_zero() || s.block.base.header.transactions_root == SHA3_NULL_RLP {
- s.block.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|e| e.rlp_bytes().to_vec()).collect());
+ if s.block.base.header.transactions_root().is_zero() || s.block.base.header.transactions_root() == &SHA3_NULL_RLP {
+ s.block.base.header.set_transactions_root(ordered_trie_root(s.block.base.transactions.iter().map(|e| e.rlp_bytes().to_vec()).collect()));
}
let uncle_bytes = s.block.base.uncles.iter().fold(RlpStream::new_list(s.block.base.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out();
- if s.block.base.header.uncles_hash.is_zero() {
- s.block.base.header.uncles_hash = uncle_bytes.sha3();
+ if s.block.base.header.uncles_hash().is_zero() {
+ s.block.base.header.set_uncles_hash(uncle_bytes.sha3());
}
- if s.block.base.header.receipts_root.is_zero() || s.block.base.header.receipts_root == SHA3_NULL_RLP {
- s.block.base.header.receipts_root = ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes().to_vec()).collect());
+ if s.block.base.header.receipts_root().is_zero() || s.block.base.header.receipts_root() == &SHA3_NULL_RLP {
+ s.block.base.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes().to_vec()).collect()));
}
- s.block.base.header.state_root = s.block.state.root().clone();
- s.block.base.header.log_bloom = s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b}); //TODO: use |= operator
- s.block.base.header.gas_used = s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used);
- s.block.base.header.note_dirty();
+ s.block.base.header.set_state_root(s.block.state.root().clone());
+ s.block.base.header.set_log_bloom(s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b})); //TODO: use |= operator
+ s.block.base.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used));
LockedBlock {
block: s.block,
@@ -625,9 +623,9 @@ mod tests {
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle1_header = Header::new();
- uncle1_header.extra_data = b"uncle1".to_vec();
+ uncle1_header.set_extra_data(b"uncle1".to_vec());
let mut uncle2_header = Header::new();
- uncle2_header.extra_data = b"uncle2".to_vec();
+ uncle2_header.set_extra_data(b"uncle2".to_vec());
open_block.push_uncle(uncle1_header).unwrap();
open_block.push_uncle(uncle2_header).unwrap();
let b = open_block.close_and_lock().seal(engine, vec![]).unwrap();
@@ -643,7 +641,7 @@ mod tests {
let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);
let uncles = BlockView::new(&bytes).uncles();
- assert_eq!(uncles[1].extra_data, b"uncle2");
+ assert_eq!(uncles[1].extra_data(), b"uncle2");
let db = e.drain();
assert_eq!(orig_db.keys(), db.keys());
diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs
index 89a620493..7d686cec0 100644
--- a/ethcore/src/block_queue.rs
+++ b/ethcore/src/block_queue.rs
@@ -260,7 +260,7 @@ impl BlockQueue {
fn drain_verifying(verifying: &mut VecDeque, verified: &mut VecDeque, bad: &mut HashSet) {
while !verifying.is_empty() && verifying.front().unwrap().block.is_some() {
let block = verifying.pop_front().unwrap().block.unwrap();
- if bad.contains(&block.header.parent_hash) {
+ if bad.contains(block.header.parent_hash()) {
bad.insert(block.header.hash());
}
else {
@@ -313,7 +313,7 @@ impl BlockQueue {
return Err(ImportError::KnownBad.into());
}
- if bad.contains(&header.parent_hash) {
+ if bad.contains(header.parent_hash()) {
bad.insert(h.clone());
return Err(ImportError::KnownBad.into());
}
@@ -351,7 +351,7 @@ impl BlockQueue {
let mut new_verified = VecDeque::new();
for block in verified.drain(..) {
- if bad.contains(&block.header.parent_hash) {
+ if bad.contains(block.header.parent_hash()) {
bad.insert(block.header.hash());
processing.remove(&block.header.hash());
} else {
diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs
index 379d77407..a581e59e9 100644
--- a/ethcore/src/blockchain/blockchain.rs
+++ b/ethcore/src/blockchain/blockchain.rs
@@ -1434,7 +1434,7 @@ mod tests {
let mut block_header = bc.block_header(&best_hash);
while !block_header.is_none() {
- block_header = bc.block_header(&block_header.unwrap().parent_hash);
+ block_header = bc.block_header(&block_header.unwrap().parent_hash());
}
assert!(bc.cache_size().blocks > 1024 * 1024);
diff --git a/ethcore/src/blockchain/generator/block.rs b/ethcore/src/blockchain/generator/block.rs
index 0a3dad399..238051d2a 100644
--- a/ethcore/src/blockchain/generator/block.rs
+++ b/ethcore/src/blockchain/generator/block.rs
@@ -44,21 +44,22 @@ impl Encodable for Block {
impl Forkable for Block {
fn fork(mut self, fork_number: usize) -> Self where Self: Sized {
- self.header.difficulty = self.header.difficulty - U256::from(fork_number);
+ let difficulty = self.header.difficulty().clone() - U256::from(fork_number);
+ self.header.set_difficulty(difficulty);
self
}
}
impl WithBloom for Block {
fn with_bloom(mut self, bloom: H2048) -> Self where Self: Sized {
- self.header.log_bloom = bloom;
+ self.header.set_log_bloom(bloom);
self
}
}
impl CompleteBlock for Block {
fn complete(mut self, parent_hash: H256) -> Bytes {
- self.header.parent_hash = parent_hash;
+ self.header.set_parent_hash(parent_hash);
encode(&self).to_vec()
}
}
diff --git a/ethcore/src/blockchain/generator/generator.rs b/ethcore/src/blockchain/generator/generator.rs
index 07ce7242b..179839b5a 100644
--- a/ethcore/src/blockchain/generator/generator.rs
+++ b/ethcore/src/blockchain/generator/generator.rs
@@ -73,8 +73,8 @@ pub struct ChainGenerator {
impl ChainGenerator {
fn prepare_block(&self) -> Block {
let mut block = Block::default();
- block.header.number = self.number;
- block.header.difficulty = self.difficulty;
+ block.header.set_number(self.number);
+ block.header.set_difficulty(self.difficulty);
block
}
}
diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs
index d4ea5e30e..bcd02cbf3 100644
--- a/ethcore/src/builtin.rs
+++ b/ethcore/src/builtin.rs
@@ -14,283 +14,350 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-use crypto::sha2::Sha256;
-use crypto::ripemd160::Ripemd160;
+use crypto::sha2::Sha256 as Sha256Digest;
+use crypto::ripemd160::Ripemd160 as Ripemd160Digest;
use crypto::digest::Digest;
use util::*;
-use ethkey::{Signature, recover};
+use ethkey::{Signature, recover as ec_recover};
use ethjson;
-/// Definition of a contract whose implementation is built-in.
-pub struct Builtin {
- /// The gas cost of running this built-in for the given size of input data.
- pub cost: Box U256>, // TODO: U256 should be bignum.
- /// Run this built-in function with the input being the first argument and the output
- /// being placed into the second.
- pub execute: Box,
+/// 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], out: &mut [u8]);
}
-// Rust does not mark closurer that do not capture as Sync
-// We promise that all builtins are thread safe since they only operate on given input.
-unsafe impl Sync for Builtin {}
-unsafe impl Send for Builtin {}
+/// A gas pricing scheme for built-in contracts.
+pub trait Pricer: Send + Sync {
+ /// The gas cost of running this built-in for the given size of input data.
+ fn cost(&self, in_size: usize) -> U256;
+}
-impl fmt::Debug for Builtin {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "")
+/// A linear pricing model. This computes a price using a base cost and a cost per-word.
+struct Linear {
+ base: usize,
+ word: usize,
+}
+
+impl Pricer for Linear {
+ fn cost(&self, in_size: usize) -> U256 {
+ U256::from(self.base) + U256::from(self.word) * U256::from((in_size + 31) / 32)
}
}
+/// Pricing scheme and execution definition for a built-in contract.
+pub struct Builtin {
+ pricer: Box,
+ native: Box,
+}
+
impl Builtin {
- /// Create a new object from components.
- pub fn new(cost: Box U256>, execute: Box) -> 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) -> Builtin {
- let cost = Box::new(move|s: usize| -> U256 {
- U256::from(base_cost) + U256::from(word_cost) * U256::from((s + 31) / 32)
- });
-
- Self::new(cost, new_builtin_exec(name))
- }
-
/// Simple forwarder for cost.
- pub fn cost(&self, s: usize) -> U256 { (*self.cost)(s) }
+ pub fn cost(&self, s: usize) -> U256 { self.pricer.cost(s) }
/// Simple forwarder for execute.
- pub fn execute(&self, input: &[u8], output: &mut[u8]) { (*self.execute)(input, output); }
+ pub fn execute(&self, input: &[u8], output: &mut[u8]) { self.native.execute(input, output) }
}
impl From for Builtin {
fn from(b: ethjson::spec::Builtin) -> Self {
- match b.pricing {
+ let pricer = match b.pricing {
ethjson::spec::Pricing::Linear(linear) => {
- Self::from_named_linear(b.name.as_ref(), linear.base, linear.word)
+ Box::new(Linear {
+ base: linear.base,
+ word: linear.word,
+ })
}
+ };
+
+ Builtin {
+ pricer: pricer,
+ native: ethereum_builtin(&b.name),
}
}
}
-/// Copy a bunch of bytes to a destination; if the `src` is too small to fill `dest`,
-/// leave the rest unchanged.
-pub fn copy_to(src: &[u8], dest: &mut[u8]) {
- // NICE: optimise
- for i in 0..min(src.len(), dest.len()) {
- dest[i] = src[i];
+// Ethereum builtin creator.
+fn ethereum_builtin(name: &str) -> Box {
+ match name {
+ "identity" => Box::new(Identity) as Box,
+ "ecrecover" => Box::new(EcRecover) as Box,
+ "sha256" => Box::new(Sha256) as Box,
+ "ripemd160" => Box::new(Ripemd160) as Box,
+ _ => panic!("invalid builtin name: {}", name),
}
}
-/// Create a new builtin executor according to `name`.
-/// TODO: turn in to a factory with dynamic registration.
-pub fn new_builtin_exec(name: &str) -> Box {
- match name {
- "identity" => Box::new(move|input: &[u8], output: &mut[u8]| {
- for i in 0..min(input.len(), output.len()) {
- output[i] = input[i];
- }
- }),
- "ecrecover" => Box::new(move|input: &[u8], output: &mut[u8]| {
- #[repr(packed)]
- #[derive(Debug, Default)]
- struct InType {
- hash: H256,
- v: H256,
- r: H256,
- s: H256,
- }
- let mut it = InType::default();
- 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 s.is_valid() {
- if let Ok(p) = recover(&s, &it.hash) {
- 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]};
- }
- }
+// Ethereum builtins:
+//
+// - The identity function
+// - ec recovery
+// - sha256
+// - ripemd160
+
+#[derive(Debug)]
+struct Identity;
+
+#[derive(Debug)]
+struct EcRecover;
+
+#[derive(Debug)]
+struct Sha256;
+
+#[derive(Debug)]
+struct Ripemd160;
+
+impl Impl for Identity {
+ fn execute(&self, input: &[u8], output: &mut [u8]) {
+ let len = min(input.len(), output.len());
+ output[..len].copy_from_slice(&input[..len]);
+ }
+}
+
+impl Impl for EcRecover {
+ fn execute(&self, i: &[u8], output: &mut [u8]) {
+ let len = min(i.len(), 128);
+
+ let mut input = [0; 128];
+ input[..len].copy_from_slice(&i[..len]);
+
+ let hash = H256::from_slice(&input[0..32]);
+ let v = H256::from_slice(&input[32..64]);
+ let r = H256::from_slice(&input[64..96]);
+ let s = H256::from_slice(&input[96..128]);
+
+ let bit = match v[31] {
+ 27 | 28 if &v.as_slice()[..31] == &[0; 31] => v[31] - 27,
+ _ => return,
+ };
+
+ let s = Signature::from_rsv(&r, &s, bit);
+ if s.is_valid() {
+ if let Ok(p) = ec_recover(&s, &hash) {
+ let r = p.as_slice().sha3();
+
+ let out_len = min(output.len(), 32);
+
+ for x in &mut output[0.. min(12, out_len)] {
+ *x = 0;
+ }
+
+ if out_len > 12 {
+ output[12..out_len].copy_from_slice(&r[12..out_len]);
}
}
- }),
- "sha256" => 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" => 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);
- }),
- _ => {
- panic!("invalid builtin name {}", name);
}
}
}
-#[test]
-fn identity() {
- let f = new_builtin_exec("identity");
- let i = [0u8, 1, 2, 3];
+impl Impl for Sha256 {
+ fn execute(&self, input: &[u8], output: &mut [u8]) {
+ let out_len = min(output.len(), 32);
- let mut o2 = [255u8; 2];
- f(&i[..], &mut o2[..]);
- assert_eq!(i[0..2], o2);
+ let mut sha = Sha256Digest::new();
+ sha.input(input);
- let mut o4 = [255u8; 4];
- f(&i[..], &mut o4[..]);
- assert_eq!(i, o4);
+ if out_len == 32 {
+ sha.result(&mut output[0..32]);
+ } else {
+ let mut out = [0; 32];
+ sha.result(&mut out);
- let mut o8 = [255u8; 8];
- f(&i[..], &mut o8[..]);
- assert_eq!(i, o8[..4]);
- assert_eq!([255u8; 4], o8[4..]);
+ output.copy_from_slice(&out[..out_len])
+ }
+ }
}
-#[test]
-fn sha256() {
- use rustc_serialize::hex::FromHex;
- let f = new_builtin_exec("sha256");
- let i = [0u8; 0];
+impl Impl for Ripemd160 {
+ fn execute(&self, input: &[u8], output: &mut [u8]) {
+ let out_len = min(output.len(), 32);
- let mut o = [255u8; 32];
- f(&i[..], &mut o[..]);
- assert_eq!(&o[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").unwrap())[..]);
+ let mut sha = Ripemd160Digest::new();
+ sha.input(input);
- let mut o8 = [255u8; 8];
- f(&i[..], &mut o8[..]);
- assert_eq!(&o8[..], &(FromHex::from_hex("e3b0c44298fc1c14").unwrap())[..]);
+ for x in &mut output[0.. min(12, out_len)] {
+ *x = 0;
+ }
- let mut o34 = [255u8; 34];
- f(&i[..], &mut o34[..]);
- assert_eq!(&o34[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855ffff").unwrap())[..]);
+ if out_len >= 32 {
+ sha.result(&mut output[12..32]);
+ } else if out_len > 12 {
+ let mut out = [0; 20];
+ sha.result(&mut out);
+
+ output.copy_from_slice(&out[12..out_len])
+ }
+ }
}
-#[test]
-fn ripemd160() {
- use rustc_serialize::hex::FromHex;
- let f = new_builtin_exec("ripemd160");
- let i = [0u8; 0];
+#[cfg(test)]
+mod tests {
+ use super::{Builtin, Linear, ethereum_builtin, Pricer};
+ use ethjson;
+ use util::U256;
- let mut o = [255u8; 32];
- f(&i[..], &mut o[..]);
- assert_eq!(&o[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31").unwrap())[..]);
+ #[test]
+ fn identity() {
+ let f = ethereum_builtin("identity");
- let mut o8 = [255u8; 8];
- f(&i[..], &mut o8[..]);
- assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);
+ let i = [0u8, 1, 2, 3];
- let mut o34 = [255u8; 34];
- f(&i[..], &mut o34[..]);
- assert_eq!(&o34[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31ffff").unwrap())[..]);
-}
+ let mut o2 = [255u8; 2];
+ f.execute(&i[..], &mut o2[..]);
+ assert_eq!(i[0..2], o2);
-#[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 mut o4 = [255u8; 4];
+ f.execute(&i[..], &mut o4[..]);
+ assert_eq!(i, o4);
- let f = new_builtin_exec("ecrecover");
- let i = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
+ let mut o8 = [255u8; 8];
+ f.execute(&i[..], &mut o8[..]);
+ assert_eq!(i, o8[..4]);
+ assert_eq!([255u8; 4], o8[4..]);
+ }
- let mut o = [255u8; 32];
- f(&i[..], &mut o[..]);
- assert_eq!(&o[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddb").unwrap())[..]);
+ #[test]
+ fn sha256() {
+ use rustc_serialize::hex::FromHex;
+ let f = ethereum_builtin("sha256");
- let mut o8 = [255u8; 8];
- f(&i[..], &mut o8[..]);
- assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);
+ let i = [0u8; 0];
- let mut o34 = [255u8; 34];
- f(&i[..], &mut o34[..]);
- assert_eq!(&o34[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddbffff").unwrap())[..]);
+ let mut o = [255u8; 32];
+ f.execute(&i[..], &mut o[..]);
+ assert_eq!(&o[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").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 mut o8 = [255u8; 8];
+ f.execute(&i[..], &mut o8[..]);
+ assert_eq!(&o8[..], &(FromHex::from_hex("e3b0c44298fc1c14").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 mut o34 = [255u8; 34];
+ f.execute(&i[..], &mut o34[..]);
+ assert_eq!(&o34[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855ffff").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())[..]);
+ #[test]
+ fn ripemd160() {
+ use rustc_serialize::hex::FromHex;
+ let f = ethereum_builtin("ripemd160");
- 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 = [0u8; 0];
- 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())[..]);
+ let mut o = [255u8; 32];
+ f.execute(&i[..], &mut o[..]);
+ assert_eq!(&o[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31").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())[..]);*/
-}
+ let mut o8 = [255u8; 8];
+ f.execute(&i[..], &mut o8[..]);
+ assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);
-#[test]
-#[should_panic]
-fn from_unknown_linear() {
- let _ = Builtin::from_named_linear("dw", 10, 20);
-}
+ let mut o34 = [255u8; 34];
+ f.execute(&i[..], &mut o34[..]);
+ assert_eq!(&o34[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31ffff").unwrap())[..]);
+ }
-#[test]
-fn from_named_linear() {
- let b = Builtin::from_named_linear("identity", 10, 20);
- 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));
+ #[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 i = [0u8, 1, 2, 3];
- let mut o = [255u8; 4];
- (*b.execute)(&i[..], &mut o[..]);
- assert_eq!(i, o);
-}
+ let f = ethereum_builtin("ecrecover");
-#[test]
-fn from_json() {
- let b = Builtin::from(ethjson::spec::Builtin {
- name: "identity".to_owned(),
- pricing: ethjson::spec::Pricing::Linear(ethjson::spec::Linear {
- base: 10,
- word: 20,
- })
- });
+ let i = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").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 mut o = [255u8; 32];
+ f.execute(&i[..], &mut o[..]);
+ assert_eq!(&o[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddb").unwrap())[..]);
- let i = [0u8, 1, 2, 3];
- let mut o = [255u8; 4];
- (*b.execute)(&i[..], &mut o[..]);
- assert_eq!(i, o);
-}
+ let mut o8 = [255u8; 8];
+ f.execute(&i[..], &mut o8[..]);
+ assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);
+
+ let mut o34 = [255u8; 34];
+ f.execute(&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.execute(&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.execute(&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.execute(&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.execute(&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.execute(&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.execute(&i_bad[..], &mut o[..]);
+ assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);*/
+ }
+
+ #[test]
+ #[should_panic]
+ fn from_unknown_linear() {
+ let _ = ethereum_builtin("foo");
+ }
+
+ #[test]
+ fn from_named_linear() {
+ let pricer = Box::new(Linear { base: 10, word: 20 });
+ let b = Builtin {
+ pricer: pricer as Box,
+ native: ethereum_builtin("identity"),
+ };
+
+ 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 b = Builtin::from(ethjson::spec::Builtin {
+ name: "identity".to_owned(),
+ pricing: ethjson::spec::Pricing::Linear(ethjson::spec::Linear {
+ base: 10,
+ word: 20,
+ })
+ });
+
+ 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);
+ }
+}
\ No newline at end of file
diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs
index 9fea1513a..ecb5ca426 100644
--- a/ethcore/src/client/client.rs
+++ b/ethcore/src/client/client.rs
@@ -100,7 +100,7 @@ impl ClientReport {
pub fn accrue_block(&mut self, block: &PreverifiedBlock) {
self.blocks_imported += 1;
self.transactions_applied += block.transactions.len();
- self.gas_processed = self.gas_processed + block.header.gas_used;
+ self.gas_processed = self.gas_processed + block.header.gas_used().clone();
}
}
@@ -285,15 +285,15 @@ impl Client {
};
// Check if Parent is in chain
- let chain_has_parent = self.chain.block_header(&header.parent_hash);
+ let chain_has_parent = self.chain.block_header(header.parent_hash());
if let None = chain_has_parent {
- warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash);
+ warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash());
return Err(());
};
// Enact Verified Block
let parent = chain_has_parent.unwrap();
- let last_hashes = self.build_last_hashes(header.parent_hash.clone());
+ let last_hashes = self.build_last_hashes(header.parent_hash().clone());
let db = self.state_db.lock().boxed_clone();
let enact_result = enact_verified(block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.factories.clone());
@@ -353,7 +353,7 @@ impl Client {
for block in blocks {
let header = &block.header;
- if invalid_blocks.contains(&header.parent_hash) {
+ if invalid_blocks.contains(header.parent_hash()) {
invalid_blocks.insert(header.hash());
continue;
}
diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs
index 7a5fa28b7..5f83ce21e 100644
--- a/ethcore/src/client/test_client.rs
+++ b/ethcore/src/client/test_client.rs
@@ -169,19 +169,19 @@ impl TestBlockChainClient {
let len = self.numbers.read().len();
for n in len..(len + count) {
let mut header = BlockHeader::new();
- header.difficulty = From::from(n);
- header.parent_hash = self.last_hash.read().clone();
- header.number = n as BlockNumber;
- header.gas_limit = U256::from(1_000_000);
+ header.set_difficulty(From::from(n));
+ header.set_parent_hash(self.last_hash.read().clone());
+ header.set_number(n as BlockNumber);
+ header.set_gas_limit(U256::from(1_000_000));
let uncles = match with {
EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => {
let mut uncles = RlpStream::new_list(1);
let mut uncle_header = BlockHeader::new();
- uncle_header.difficulty = From::from(n);
- uncle_header.parent_hash = self.last_hash.read().clone();
- uncle_header.number = n as BlockNumber;
+ uncle_header.set_difficulty(From::from(n));
+ uncle_header.set_parent_hash(self.last_hash.read().clone());
+ uncle_header.set_number(n as BlockNumber);
uncles.append(&uncle_header);
- header.uncles_hash = uncles.as_raw().sha3();
+ header.set_uncles_hash(uncles.as_raw().sha3());
uncles
},
_ => RlpStream::new_list(0)
@@ -219,7 +219,7 @@ impl TestBlockChainClient {
pub fn corrupt_block(&mut self, n: BlockNumber) {
let hash = self.block_hash(BlockID::Number(n)).unwrap();
let mut header: BlockHeader = decode(&self.block_header(BlockID::Number(n)).unwrap());
- header.extra_data = b"This extra data is way too long to be considered valid".to_vec();
+ header.set_extra_data(b"This extra data is way too long to be considered valid".to_vec());
let mut rlp = RlpStream::new_list(3);
rlp.append(&header);
rlp.append_raw(&rlp::NULL_RLP, 1);
@@ -231,7 +231,7 @@ impl TestBlockChainClient {
pub fn corrupt_block_parent(&mut self, n: BlockNumber) {
let hash = self.block_hash(BlockID::Number(n)).unwrap();
let mut header: BlockHeader = decode(&self.block_header(BlockID::Number(n)).unwrap());
- header.parent_hash = H256::from(42);
+ header.set_parent_hash(H256::from(42));
let mut rlp = RlpStream::new_list(3);
rlp.append(&header);
rlp.append_raw(&rlp::NULL_RLP, 1);
@@ -470,20 +470,20 @@ impl BlockChainClient for TestBlockChainClient {
fn import_block(&self, b: Bytes) -> Result {
let header = Rlp::new(&b).val_at::(0);
let h = header.hash();
- let number: usize = header.number as usize;
+ let number: usize = header.number() as usize;
if number > self.blocks.read().len() {
panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().len(), number);
}
if number > 0 {
- match self.blocks.read().get(&header.parent_hash) {
+ match self.blocks.read().get(header.parent_hash()) {
Some(parent) => {
let parent = Rlp::new(parent).val_at::(0);
- if parent.number != (header.number - 1) {
+ if parent.number() != (header.number() - 1) {
panic!("Unexpected block parent");
}
},
None => {
- panic!("Unknown block parent {:?} for block {}", header.parent_hash, number);
+ panic!("Unknown block parent {:?} for block {}", header.parent_hash(), number);
}
}
}
@@ -491,18 +491,18 @@ impl BlockChainClient for TestBlockChainClient {
if number == len {
{
let mut difficulty = self.difficulty.write();
- *difficulty = *difficulty + header.difficulty;
+ *difficulty = *difficulty + header.difficulty().clone();
}
mem::replace(&mut *self.last_hash.write(), h.clone());
self.blocks.write().insert(h.clone(), b);
self.numbers.write().insert(number, h.clone());
- let mut parent_hash = header.parent_hash;
+ let mut parent_hash = header.parent_hash().clone();
if number > 0 {
let mut n = number - 1;
while n > 0 && self.numbers.read()[&n] != parent_hash {
*self.numbers.write().get_mut(&n).unwrap() = parent_hash.clone();
n -= 1;
- parent_hash = Rlp::new(&self.blocks.read()[&parent_hash]).val_at::(0).parent_hash;
+ parent_hash = Rlp::new(&self.blocks.read()[&parent_hash]).val_at::(0).parent_hash().clone();
}
}
}
diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs
index 926399d7b..332d947c3 100644
--- a/ethcore/src/engines/basic_authority.rs
+++ b/ethcore/src/engines/basic_authority.rs
@@ -82,17 +82,16 @@ impl Engine for BasicAuthority {
}
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {
- header.difficulty = parent.difficulty;
- header.gas_limit = {
- let gas_limit = parent.gas_limit;
+ header.set_difficulty(parent.difficulty().clone());
+ header.set_gas_limit({
+ let gas_limit = parent.gas_limit().clone();
let bound_divisor = self.our_params.gas_limit_bound_divisor;
if gas_limit < gas_floor_target {
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
} else {
max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into())
}
- };
- header.note_dirty();
+ });
// info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number, header.difficulty, header.gas_limit);
}
@@ -123,9 +122,9 @@ impl Engine for BasicAuthority {
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
// check the seal fields.
// TODO: pull this out into common code.
- if header.seal.len() != self.seal_fields() {
+ if header.seal().len() != self.seal_fields() {
return Err(From::from(BlockError::InvalidSealArity(
- Mismatch { expected: self.seal_fields(), found: header.seal.len() }
+ Mismatch { expected: self.seal_fields(), found: header.seal().len() }
)));
}
Ok(())
@@ -133,7 +132,7 @@ impl Engine for BasicAuthority {
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
// check the signature is legit.
- let sig = try!(UntrustedRlp::new(&header.seal[0]).as_val::());
+ let sig = try!(UntrustedRlp::new(&header.seal()[0]).as_val::());
let signer = public_to_address(&try!(recover(&sig.into(), &header.bare_hash())));
if !self.our_params.authorities.contains(&signer) {
return try!(Err(BlockError::InvalidSeal));
@@ -152,10 +151,10 @@ impl Engine for BasicAuthority {
return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: *parent.difficulty(), found: *header.difficulty() })))
}
let gas_limit_divisor = self.our_params.gas_limit_bound_divisor;
- let min_gas = parent.gas_limit - parent.gas_limit / gas_limit_divisor;
- let max_gas = parent.gas_limit + parent.gas_limit / gas_limit_divisor;
- if header.gas_limit <= min_gas || header.gas_limit >= max_gas {
- return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit })));
+ let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor;
+ let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
+ if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
+ return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() })));
}
Ok(())
}
diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs
index 7dbdaf86b..db26b2df3 100644
--- a/ethcore/src/engines/mod.rs
+++ b/ethcore/src/engines/mod.rs
@@ -131,9 +131,8 @@ pub trait Engine : Sync + Send {
/// Don't forget to call Super::populate_from_parent when subclassing & overriding.
// TODO: consider including State in the params.
fn populate_from_parent(&self, header: &mut Header, parent: &Header, _gas_floor_target: U256, _gas_ceil_target: U256) {
- header.difficulty = parent.difficulty;
- header.gas_limit = parent.gas_limit;
- header.note_dirty();
+ header.set_difficulty(parent.difficulty().clone());
+ header.set_gas_limit(parent.gas_limit().clone());
}
/// Handle any potential consensus messages;
diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs
index c658432a2..82a74d9ea 100644
--- a/ethcore/src/ethereum/ethash.rs
+++ b/ethcore/src/ethereum/ethash.rs
@@ -114,9 +114,9 @@ impl Engine for Ethash {
}
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, gas_ceil_target: U256) {
- header.difficulty = self.calculate_difficuty(header, parent);
- header.gas_limit = {
- let gas_limit = parent.gas_limit;
+ let difficulty = self.calculate_difficulty(header, parent);
+ let gas_limit = {
+ let gas_limit = parent.gas_limit().clone();
let bound_divisor = self.ethash_params.gas_limit_bound_divisor;
if gas_limit < gas_floor_target {
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
@@ -126,21 +126,23 @@ impl Engine for Ethash {
min(gas_ceil_target,
max(gas_floor_target,
gas_limit - gas_limit / bound_divisor + 1.into() +
- (header.gas_used * 6.into() / 5.into()) / bound_divisor))
+ (header.gas_used().clone() * 6.into() / 5.into()) / bound_divisor))
}
};
- if header.number >= self.ethash_params.dao_hardfork_transition &&
- header.number <= self.ethash_params.dao_hardfork_transition + 9 {
- header.extra_data = b"dao-hard-fork"[..].to_owned();
+ header.set_difficulty(difficulty);
+ header.set_gas_limit(gas_limit);
+ if header.number() >= self.ethash_params.dao_hardfork_transition &&
+ header.number() <= self.ethash_params.dao_hardfork_transition + 9 {
+ header.set_extra_data(b"dao-hard-fork"[..].to_owned());
}
header.note_dirty();
-// info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number, header.difficulty, header.gas_limit);
+// info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number(), header.difficulty(), header.gas_limit());
}
fn on_new_block(&self, block: &mut ExecutedBlock) {
- if block.fields().header.number == self.ethash_params.dao_hardfork_transition {
+ if block.fields().header.number() == self.ethash_params.dao_hardfork_transition {
// TODO: enable trigger function maybe?
-// if block.fields().header.gas_limit <= 4_000_000.into() {
+// if block.fields().header.gas_limit() <= 4_000_000.into() {
let mut state = block.fields_mut().state;
for child in &self.ethash_params.dao_hardfork_accounts {
let b = state.balance(child);
@@ -157,7 +159,7 @@ impl Engine for Ethash {
let fields = block.fields_mut();
// Bestow block reward
- fields.state.add_balance(&fields.header.author, &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())));
+ fields.state.add_balance(&fields.header.author(), &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())));
// Bestow uncle rewards
let current_number = fields.header.number();
@@ -171,18 +173,18 @@ impl Engine for Ethash {
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
// check the seal fields.
- if header.seal.len() != self.seal_fields() {
+ if header.seal().len() != self.seal_fields() {
return Err(From::from(BlockError::InvalidSealArity(
- Mismatch { expected: self.seal_fields(), found: header.seal.len() }
+ Mismatch { expected: self.seal_fields(), found: header.seal().len() }
)));
}
- try!(UntrustedRlp::new(&header.seal[0]).as_val::());
- try!(UntrustedRlp::new(&header.seal[1]).as_val::());
+ try!(UntrustedRlp::new(&header.seal()[0]).as_val::());
+ try!(UntrustedRlp::new(&header.seal()[1]).as_val::());
// TODO: consider removing these lines.
let min_difficulty = self.ethash_params.minimum_difficulty;
- if header.difficulty < min_difficulty {
- return Err(From::from(BlockError::DifficultyOutOfBounds(OutOfBounds { min: Some(min_difficulty), max: None, found: header.difficulty })))
+ if header.difficulty() < &min_difficulty {
+ return Err(From::from(BlockError::DifficultyOutOfBounds(OutOfBounds { min: Some(min_difficulty), max: None, found: header.difficulty().clone() })))
}
let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(quick_get_difficulty(
@@ -190,37 +192,37 @@ impl Engine for Ethash {
header.nonce().low_u64(),
&Ethash::to_ethash(header.mix_hash())
)));
- if difficulty < header.difficulty {
- return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty), max: None, found: difficulty })));
+ if &difficulty < header.difficulty() {
+ return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty().clone()), max: None, found: difficulty })));
}
- if header.number >= self.ethash_params.dao_hardfork_transition &&
- header.number <= self.ethash_params.dao_hardfork_transition + 9 &&
- header.extra_data[..] != b"dao-hard-fork"[..] {
+ if header.number() >= self.ethash_params.dao_hardfork_transition &&
+ header.number() <= self.ethash_params.dao_hardfork_transition + 9 &&
+ header.extra_data()[..] != b"dao-hard-fork"[..] {
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds { min: None, max: None, found: 0 })));
}
- if header.gas_limit > 0x7fffffffffffffffu64.into() {
- return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: None, max: Some(0x7fffffffffffffffu64.into()), found: header.gas_limit })));
+ if header.gas_limit() > &0x7fffffffffffffffu64.into() {
+ return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: None, max: Some(0x7fffffffffffffffu64.into()), found: header.gas_limit().clone() })));
}
Ok(())
}
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
- if header.seal.len() != self.seal_fields() {
+ if header.seal().len() != self.seal_fields() {
return Err(From::from(BlockError::InvalidSealArity(
- Mismatch { expected: self.seal_fields(), found: header.seal.len() }
+ Mismatch { expected: self.seal_fields(), found: header.seal().len() }
)));
}
- let result = self.pow.compute_light(header.number as u64, &Ethash::to_ethash(header.bare_hash()), header.nonce().low_u64());
+ let result = self.pow.compute_light(header.number() as u64, &Ethash::to_ethash(header.bare_hash()), header.nonce().low_u64());
let mix = Ethash::from_ethash(result.mix_hash);
let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(result.value));
if mix != header.mix_hash() {
return Err(From::from(BlockError::MismatchedH256SealElement(Mismatch { expected: mix, found: header.mix_hash() })));
}
- if difficulty < header.difficulty {
- return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty), max: None, found: difficulty })));
+ if &difficulty < header.difficulty() {
+ return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty().clone()), max: None, found: difficulty })));
}
Ok(())
}
@@ -232,15 +234,15 @@ impl Engine for Ethash {
}
// Check difficulty is correct given the two timestamps.
- let expected_difficulty = self.calculate_difficuty(header, parent);
- if header.difficulty != expected_difficulty {
- return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: expected_difficulty, found: header.difficulty })))
+ let expected_difficulty = self.calculate_difficulty(header, parent);
+ if header.difficulty() != &expected_difficulty {
+ return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: expected_difficulty, found: header.difficulty().clone() })))
}
let gas_limit_divisor = self.ethash_params.gas_limit_bound_divisor;
- let min_gas = parent.gas_limit - parent.gas_limit / gas_limit_divisor;
- let max_gas = parent.gas_limit + parent.gas_limit / gas_limit_divisor;
- if header.gas_limit <= min_gas || header.gas_limit >= max_gas {
- return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit })));
+ let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor;
+ let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
+ if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
+ return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() })));
}
Ok(())
}
@@ -259,9 +261,9 @@ impl Engine for Ethash {
#[cfg_attr(feature="dev", allow(wrong_self_convention))] // to_ethash should take self
impl Ethash {
- fn calculate_difficuty(&self, header: &Header, parent: &Header) -> U256 {
+ fn calculate_difficulty(&self, header: &Header, parent: &Header) -> U256 {
const EXP_DIFF_PERIOD: u64 = 100000;
- if header.number == 0 {
+ if header.number() == 0 {
panic!("Can't calculate genesis block difficulty");
}
@@ -270,25 +272,25 @@ impl Ethash {
let duration_limit = self.ethash_params.duration_limit;
let frontier_limit = self.ethash_params.frontier_compatibility_mode_limit;
- let mut target = if header.number < frontier_limit {
- if header.timestamp >= parent.timestamp + duration_limit {
- parent.difficulty - (parent.difficulty / difficulty_bound_divisor)
+ let mut target = if header.number() < frontier_limit {
+ if header.timestamp() >= parent.timestamp() + duration_limit {
+ parent.difficulty().clone() - (parent.difficulty().clone() / difficulty_bound_divisor)
} else {
- parent.difficulty + (parent.difficulty / difficulty_bound_divisor)
+ parent.difficulty().clone() + (parent.difficulty().clone() / difficulty_bound_divisor)
}
}
else {
- trace!(target: "ethash", "Calculating difficulty parent.difficulty={}, header.timestamp={}, parent.timestamp={}", parent.difficulty, header.timestamp, parent.timestamp);
+ trace!(target: "ethash", "Calculating difficulty parent.difficulty={}, header.timestamp={}, parent.timestamp={}", parent.difficulty(), header.timestamp(), parent.timestamp());
//block_diff = parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)
- let diff_inc = (header.timestamp - parent.timestamp) / 10;
+ let diff_inc = (header.timestamp() - parent.timestamp()) / 10;
if diff_inc <= 1 {
- parent.difficulty + parent.difficulty / From::from(2048) * From::from(1 - diff_inc)
+ parent.difficulty().clone() + parent.difficulty().clone() / From::from(2048) * From::from(1 - diff_inc)
} else {
- parent.difficulty - parent.difficulty / From::from(2048) * From::from(min(diff_inc - 1, 99))
+ parent.difficulty().clone() - parent.difficulty().clone() / From::from(2048) * From::from(min(diff_inc - 1, 99))
}
};
target = max(min_difficulty, target);
- let period = ((parent.number + 1) / EXP_DIFF_PERIOD) as usize;
+ let period = ((parent.number() + 1) / EXP_DIFF_PERIOD) as usize;
if period > 1 {
target = max(min_difficulty, target + (U256::from(1) << (period - 2)));
}
@@ -336,7 +338,7 @@ impl Header {
/// Set the nonce and mix hash fields of the header.
pub fn set_nonce_and_mix_hash(&mut self, nonce: &H64, mix_hash: &H256) {
- self.seal = vec![encode(mix_hash).to_vec(), encode(nonce).to_vec()];
+ self.set_seal(vec![encode(mix_hash).to_vec(), encode(nonce).to_vec()]);
}
}
@@ -374,7 +376,7 @@ mod tests {
let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle = Header::new();
let uncle_author: Address = "ef2d6d194084c2de36e0dabfce45d046b37d1106".into();
- uncle.author = uncle_author.clone();
+ uncle.set_author(uncle_author);
b.push_uncle(uncle).unwrap();
let b = b.close();
diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs
index 40e85d619..1efe001e5 100644
--- a/ethcore/src/ethereum/mod.rs
+++ b/ethcore/src/ethereum/mod.rs
@@ -68,7 +68,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
- let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce(), Default::default()).unwrap();
+ let s = State::from_existing(db, genesis_header.state_root().clone(), engine.account_start_nonce(), Default::default()).unwrap();
assert_eq!(s.balance(&"0000000000000000000000000000000000000001".into()), 1u64.into());
assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()), 1u64.into());
assert_eq!(s.balance(&"0000000000000000000000000000000000000003".into()), 1u64.into());
diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs
index a123197a9..9b0e155f4 100644
--- a/ethcore/src/header.rs
+++ b/ethcore/src/header.rs
@@ -33,43 +33,42 @@ pub type BlockNumber = u64;
/// Doesn't do all that much on its own.
#[derive(Debug, Clone, Eq)]
pub struct Header {
- // TODO: make all private.
/// Parent hash.
- pub parent_hash: H256,
+ parent_hash: H256,
/// Block timestamp.
- pub timestamp: u64,
+ timestamp: u64,
/// Block number.
- pub number: BlockNumber,
+ number: BlockNumber,
/// Block author.
- pub author: Address,
+ author: Address,
/// Transactions root.
- pub transactions_root: H256,
+ transactions_root: H256,
/// Block uncles hash.
- pub uncles_hash: H256,
+ uncles_hash: H256,
/// Block extra data.
- pub extra_data: Bytes,
+ extra_data: Bytes,
/// State root.
- pub state_root: H256,
+ state_root: H256,
/// Block receipts root.
- pub receipts_root: H256,
+ receipts_root: H256,
/// Block bloom.
- pub log_bloom: LogBloom,
+ log_bloom: LogBloom,
/// Gas used for contracts execution.
- pub gas_used: U256,
+ gas_used: U256,
/// Block gas limit.
- pub gas_limit: U256,
+ gas_limit: U256,
/// Block difficulty.
- pub difficulty: U256,
+ difficulty: U256,
/// Vector of post-RLP-encoded fields.
- pub seal: Vec,
+ seal: Vec,
/// The memoized hash of the RLP representation *including* the seal fields.
- pub hash: RefCell