diff --git a/.gitignore b/.gitignore
index 58b1895c6..3226ea5a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,6 @@
# jetbrains ide stuff
.idea
*.iml
+
+# Build artifacts
+out/
diff --git a/Cargo.lock b/Cargo.lock
index 622ac2e54..9cfc4de62 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -14,6 +14,7 @@ dependencies = [
"ethsync 0.9.99",
"fdlimit 0.1.0",
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -43,6 +44,18 @@ dependencies = [
"syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "bigint"
+version = "0.1.0"
+dependencies = [
+ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "bitflags"
version = "0.3.3"
@@ -151,15 +164,15 @@ dependencies = [
[[package]]
name = "eth-secp256k1"
version = "0.5.4"
-source = "git+https://github.com/arkpar/rust-secp256k1.git#45503e1de68d909b1862e3f2bdb9e1cdfdff3f1e"
+source = "git+https://github.com/ethcore/rust-secp256k1#283a0677d8327536be58a87e0494d7e0e7b1d1d8"
dependencies = [
"arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -205,12 +218,12 @@ dependencies = [
"ethcore 0.9.99",
"ethcore-util 0.9.99",
"ethsync 0.9.99",
- "jsonrpc-core 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-http-server 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-http-server 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
"transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -220,11 +233,12 @@ name = "ethcore-util"
version = "0.9.99"
dependencies = [
"arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bigint 0.1.0",
"clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "eth-secp256k1 0.5.4 (git+https://github.com/arkpar/rust-secp256k1.git)",
+ "eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)",
"ethcore-devtools 0.9.99",
"heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -239,7 +253,7 @@ dependencies = [
"rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sha3 0.1.0",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -256,6 +270,7 @@ dependencies = [
"env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 0.9.99",
"ethcore-util 0.9.99",
+ "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -372,22 +387,22 @@ dependencies = [
[[package]]
name = "jsonrpc-core"
-version = "1.1.4"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "jsonrpc-http-server"
-version = "2.0.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hyper 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-core 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -542,6 +557,14 @@ dependencies = [
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "number_prefix"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "odds"
version = "0.2.12"
@@ -690,9 +713,14 @@ dependencies = [
"num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "serde"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "serde_codegen"
-version = "0.6.14"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aster 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -704,11 +732,11 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "0.6.0"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 2de097ad9..9b8ec6405 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,6 +20,7 @@ ethcore-rpc = { path = "rpc", optional = true }
fdlimit = { path = "util/fdlimit" }
daemonize = "0.2"
ethcore-devtools = { path = "devtools" }
+number_prefix = "0.2"
[features]
default = ["rpc"]
diff --git a/README.md b/README.md
index f8b24f088..4fd2a53cc 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ First (if you don't already have it) get multirust:
- Linux:
```bash
-curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes
+curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sudo sh -s -- --yes
```
- OSX with Homebrew:
diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json
index 6e31a2fce..cd66ad3f1 100644
--- a/ethcore/res/ethereum/frontier.json
+++ b/ethcore/res/ethereum/frontier.json
@@ -1,9 +1,9 @@
{
- "name": "Frontier",
+ "name": "Frontier/Homestead",
"engineName": "Ethash",
"params": {
"accountStartNonce": "0x00",
- "frontierCompatibilityModeLimit": "0x10c8e0",
+ "frontierCompatibilityModeLimit": "0x118c30",
"maximumExtraDataSize": "0x20",
"tieBreakingGas": false,
"minGasLimit": "0x1388",
diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json
index 553bb8018..3e4108566 100644
--- a/ethcore/res/ethereum/frontier_like_test.json
+++ b/ethcore/res/ethereum/frontier_like_test.json
@@ -3,7 +3,7 @@
"engineName": "Ethash",
"params": {
"accountStartNonce": "0x00",
- "frontierCompatibilityModeLimit": "0x10c8e0",
+ "frontierCompatibilityModeLimit": "0x118c30",
"maximumExtraDataSize": "0x20",
"tieBreakingGas": false,
"minGasLimit": "0x1388",
diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json
index 2e45c2edd..e9f8e0e99 100644
--- a/ethcore/res/ethereum/morden.json
+++ b/ethcore/res/ethereum/morden.json
@@ -3,7 +3,7 @@
"engineName": "Ethash",
"params": {
"accountStartNonce": "0x0100000",
- "frontierCompatibilityModeLimit": "0x10c8e0",
+ "frontierCompatibilityModeLimit": "0x789b0",
"maximumExtraDataSize": "0x20",
"tieBreakingGas": false,
"minGasLimit": "0x1388",
diff --git a/ethcore/src/account.rs b/ethcore/src/account.rs
index c36c35232..6901996bc 100644
--- a/ethcore/src/account.rs
+++ b/ethcore/src/account.rs
@@ -92,10 +92,10 @@ impl Account {
/// Create a new contract account.
/// NOTE: make sure you use `init_code` on this before `commit`ing.
- pub fn new_contract(balance: U256) -> Account {
+ pub fn new_contract(balance: U256, nonce: U256) -> Account {
Account {
balance: balance,
- nonce: U256::from(0u8),
+ nonce: nonce,
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(HashMap::new()),
code_hash: None,
@@ -261,7 +261,7 @@ mod tests {
let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new());
let rlp = {
- let mut a = Account::new_contract(U256::from(69u8));
+ let mut a = Account::new_contract(x!(69), x!(0));
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
a.commit_storage(&mut db);
a.init_code(vec![]);
@@ -281,7 +281,7 @@ mod tests {
let mut db = AccountDBMut::new(&mut db, &Address::new());
let rlp = {
- let mut a = Account::new_contract(U256::from(69u8));
+ let mut a = Account::new_contract(x!(69), x!(0));
a.init_code(vec![0x55, 0x44, 0xffu8]);
a.commit_code(&mut db);
a.rlp()
@@ -296,7 +296,7 @@ mod tests {
#[test]
fn commit_storage() {
- let mut a = Account::new_contract(U256::from(69u8));
+ let mut a = Account::new_contract(x!(69), x!(0));
let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new());
a.set_storage(x!(0), x!(0x1234));
@@ -307,7 +307,7 @@ mod tests {
#[test]
fn commit_remove_commit_storage() {
- let mut a = Account::new_contract(U256::from(69u8));
+ let mut a = Account::new_contract(x!(69), x!(0));
let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new());
a.set_storage(x!(0), x!(0x1234));
@@ -321,7 +321,7 @@ mod tests {
#[test]
fn commit_code() {
- let mut a = Account::new_contract(U256::from(69u8));
+ let mut a = Account::new_contract(x!(69), x!(0));
let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new());
a.init_code(vec![0x55, 0x44, 0xffu8]);
diff --git a/ethcore/src/action_params.rs b/ethcore/src/action_params.rs
index 9e2d72c73..fa40d30a0 100644
--- a/ethcore/src/action_params.rs
+++ b/ethcore/src/action_params.rs
@@ -15,9 +15,7 @@
// along with Parity. If not, see .
//! Evm input params.
-use util::hash::*;
-use util::uint::*;
-use util::bytes::*;
+use common::*;
/// Transaction value
#[derive(Clone, Debug)]
diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs
index 62763386f..668c004e5 100644
--- a/ethcore/src/block_queue.rs
+++ b/ethcore/src/block_queue.rs
@@ -28,6 +28,31 @@ use service::*;
use client::BlockStatus;
use util::panics::*;
+known_heap_size!(0, UnVerifiedBlock, VerifyingBlock, PreVerifiedBlock);
+
+const MIN_MEM_LIMIT: usize = 16384;
+const MIN_QUEUE_LIMIT: usize = 512;
+
+/// Block queue configuration
+#[derive(Debug)]
+pub struct BlockQueueConfig {
+ /// Maximum number of blocks to keep in unverified queue.
+ /// When the limit is reached, is_full returns true.
+ pub max_queue_size: usize,
+ /// Maximum heap memory to use.
+ /// When the limit is reached, is_full returns true.
+ pub max_mem_use: usize,
+}
+
+impl Default for BlockQueueConfig {
+ fn default() -> Self {
+ BlockQueueConfig {
+ max_queue_size: 30000,
+ max_mem_use: 50 * 1024 * 1024,
+ }
+ }
+}
+
/// Block queue status
#[derive(Debug)]
pub struct BlockQueueInfo {
@@ -37,6 +62,12 @@ pub struct BlockQueueInfo {
pub verified_queue_size: usize,
/// Number of blocks being verified
pub verifying_queue_size: usize,
+ /// Configured maximum number of blocks in the queue
+ pub max_queue_size: usize,
+ /// Configured maximum number of bytes to use
+ pub max_mem_use: usize,
+ /// Heap memory used in bytes
+ pub mem_used: usize,
}
impl BlockQueueInfo {
@@ -48,7 +79,8 @@ impl BlockQueueInfo {
/// Indicates that queue is full
pub fn is_full(&self) -> bool {
- self.unverified_queue_size + self.verified_queue_size + self.verifying_queue_size > MAX_UNVERIFIED_QUEUE_SIZE
+ self.unverified_queue_size + self.verified_queue_size + self.verifying_queue_size > self.max_queue_size ||
+ self.mem_used > self.max_mem_use
}
/// Indicates that queue is empty
@@ -68,7 +100,9 @@ pub struct BlockQueue {
deleting: Arc,
ready_signal: Arc,
empty: Arc,
- processing: RwLock>
+ processing: RwLock>,
+ max_queue_size: usize,
+ max_mem_use: usize,
}
struct UnVerifiedBlock {
@@ -106,11 +140,9 @@ struct Verification {
bad: HashSet,
}
-const MAX_UNVERIFIED_QUEUE_SIZE: usize = 50000;
-
impl BlockQueue {
/// Creates a new queue instance.
- pub fn new(engine: Arc>, message_channel: IoChannel) -> BlockQueue {
+ pub fn new(config: BlockQueueConfig, engine: Arc>, message_channel: IoChannel) -> BlockQueue {
let verification = Arc::new(Mutex::new(Verification::default()));
let more_to_verify = Arc::new(Condvar::new());
let ready_signal = Arc::new(QueueSignal { signalled: AtomicBool::new(false), message_channel: message_channel });
@@ -133,7 +165,7 @@ impl BlockQueue {
.name(format!("Verifier #{}", i))
.spawn(move || {
panic_handler.catch_panic(move || {
- BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty)
+ BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty)
}).unwrap()
})
.expect("Error starting block verification thread")
@@ -149,6 +181,8 @@ impl BlockQueue {
deleting: deleting.clone(),
processing: RwLock::new(HashSet::new()),
empty: empty.clone(),
+ max_queue_size: max(config.max_queue_size, MIN_QUEUE_LIMIT),
+ max_mem_use: max(config.max_mem_use, MIN_MEM_LIMIT),
}
}
@@ -340,8 +374,26 @@ impl BlockQueue {
verified_queue_size: verification.verified.len(),
unverified_queue_size: verification.unverified.len(),
verifying_queue_size: verification.verifying.len(),
+ max_queue_size: self.max_queue_size,
+ max_mem_use: self.max_mem_use,
+ mem_used:
+ verification.unverified.heap_size_of_children()
+ + verification.verifying.heap_size_of_children()
+ + verification.verified.heap_size_of_children(),
+ // TODO: https://github.com/servo/heapsize/pull/50
+ //+ self.processing.read().unwrap().heap_size_of_children(),
}
}
+
+ pub fn collect_garbage(&self) {
+ {
+ let mut verification = self.verification.lock().unwrap();
+ verification.unverified.shrink_to_fit();
+ verification.verifying.shrink_to_fit();
+ verification.verified.shrink_to_fit();
+ }
+ self.processing.write().unwrap().shrink_to_fit();
+ }
}
impl MayPanic for BlockQueue {
@@ -373,7 +425,7 @@ mod tests {
fn get_test_queue() -> BlockQueue {
let spec = get_test_spec();
let engine = spec.to_engine().unwrap();
- BlockQueue::new(Arc::new(engine), IoChannel::disconnected())
+ BlockQueue::new(BlockQueueConfig::default(), Arc::new(engine), IoChannel::disconnected())
}
#[test]
@@ -381,7 +433,7 @@ mod tests {
// TODO better test
let spec = Spec::new_test();
let engine = spec.to_engine().unwrap();
- let _ = BlockQueue::new(Arc::new(engine), IoChannel::disconnected());
+ let _ = BlockQueue::new(BlockQueueConfig::default(), Arc::new(engine), IoChannel::disconnected());
}
#[test]
@@ -437,4 +489,19 @@ mod tests {
assert!(queue.queue_info().is_empty());
}
+
+ #[test]
+ fn test_mem_limit() {
+ let spec = get_test_spec();
+ let engine = spec.to_engine().unwrap();
+ let mut config = BlockQueueConfig::default();
+ config.max_mem_use = super::MIN_MEM_LIMIT; // empty queue uses about 15000
+ let mut queue = BlockQueue::new(config, Arc::new(engine), IoChannel::disconnected());
+ assert!(!queue.queue_info().is_full());
+ let mut blocks = get_good_dummy_block_seq(50);
+ for b in blocks.drain(..) {
+ queue.import_block(b).unwrap();
+ }
+ assert!(queue.queue_info().is_full());
+ }
}
diff --git a/ethcore/src/blockchain/best_block.rs b/ethcore/src/blockchain/best_block.rs
new file mode 100644
index 000000000..00c092713
--- /dev/null
+++ b/ethcore/src/blockchain/best_block.rs
@@ -0,0 +1,29 @@
+// 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 util::numbers::{U256,H256};
+use header::BlockNumber;
+
+/// Best block info.
+#[derive(Default)]
+pub struct BestBlock {
+ /// Best block hash.
+ pub hash: H256,
+ /// Best block number.
+ pub number: BlockNumber,
+ /// Best block total difficulty.
+ pub total_difficulty: U256
+}
diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs
new file mode 100644
index 000000000..ce639bfed
--- /dev/null
+++ b/ethcore/src/blockchain/block_info.rs
@@ -0,0 +1,47 @@
+// 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 util::numbers::{U256,H256};
+use header::BlockNumber;
+
+/// Brief info about inserted block.
+pub struct BlockInfo {
+ /// Block hash.
+ pub hash: H256,
+ /// Block number.
+ pub number: BlockNumber,
+ /// Total block difficulty.
+ pub total_difficulty: U256,
+ /// Block location in blockchain.
+ pub location: BlockLocation
+}
+
+/// Describes location of newly inserted block.
+pub enum BlockLocation {
+ /// It's part of the canon chain.
+ CanonChain,
+ /// It's not a part of the canon chain.
+ Branch,
+ /// It's part of the fork which should become canon chain,
+ /// because it's total difficulty is higher than current
+ /// canon chain difficulty.
+ BranchBecomingCanonChain {
+ /// Hash of the newest common ancestor with old canon chain.
+ ancestor: H256,
+ /// Hashes of the blocks between ancestor and this block.
+ route: Vec
+ }
+}
diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain/blockchain.rs
similarity index 68%
rename from ethcore/src/blockchain.rs
rename to ethcore/src/blockchain/blockchain.rs
index 7e878b81e..53dcfb62c 100644
--- a/ethcore/src/blockchain.rs
+++ b/ethcore/src/blockchain/blockchain.rs
@@ -23,109 +23,30 @@ use transaction::*;
use views::*;
use receipt::Receipt;
use chainfilter::{ChainFilter, BloomIndex, FilterDataSource};
+use blockchain::block_info::{BlockInfo, BlockLocation};
+use blockchain::best_block::BestBlock;
+use blockchain::bloom_indexer::BloomIndexer;
+use blockchain::tree_route::TreeRoute;
+use blockchain::update::ExtrasUpdate;
+use blockchain::CacheSize;
const BLOOM_INDEX_SIZE: usize = 16;
const BLOOM_LEVELS: u8 = 3;
-/// Represents a tree route between `from` block and `to` block:
-pub struct TreeRoute {
- /// A vector of hashes of all blocks, ordered from `from` to `to`.
- pub blocks: Vec,
- /// Best common ancestor of these blocks.
- pub ancestor: H256,
- /// An index where best common ancestor would be.
- pub index: usize,
-}
-
-/// Represents blockchain's in-memory cache size in bytes.
+/// Blockchain configuration.
#[derive(Debug)]
-pub struct CacheSize {
- /// Blocks cache size.
- pub blocks: usize,
- /// BlockDetails cache size.
- pub block_details: usize,
- /// Transaction addresses cache size.
- pub transaction_addresses: usize,
- /// Logs cache size.
- pub block_logs: usize,
- /// Blooms cache size.
- pub blocks_blooms: usize,
- /// Block receipts size.
- pub block_receipts: usize,
+pub struct BlockChainConfig {
+ /// Preferred cache size in bytes.
+ pub pref_cache_size: usize,
+ /// Maximum cache size in bytes.
+ pub max_cache_size: usize,
}
-struct BloomIndexer {
- index_size: usize,
- levels: u8,
-}
-
-impl BloomIndexer {
- fn new(index_size: usize, levels: u8) -> Self {
- BloomIndexer {
- index_size: index_size,
- levels: levels
- }
- }
-
- /// Calculates bloom's position in database.
- fn location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation {
- use std::{mem, ptr};
-
- let hash = unsafe {
- let mut hash: H256 = mem::zeroed();
- ptr::copy(&[bloom_index.index / self.index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8);
- hash[8] = bloom_index.level;
- hash.reverse();
- hash
- };
-
- BlocksBloomLocation {
- hash: hash,
- index: bloom_index.index % self.index_size
- }
- }
-
- fn index_size(&self) -> usize {
- self.index_size
- }
-
- fn levels(&self) -> u8 {
- self.levels
- }
-}
-
-/// Blockchain update info.
-struct ExtrasUpdate {
- /// Block hash.
- hash: H256,
- /// DB update batch.
- batch: DBTransaction,
- /// Inserted block familial details.
- details: BlockDetails,
- /// New best block (if it has changed).
- new_best: Option,
- /// Changed blocks bloom location hashes.
- bloom_hashes: HashSet,
-}
-
-impl CacheSize {
- /// Total amount used by the cache.
- fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms }
-}
-
-/// Information about best block gathered together
-struct BestBlock {
- pub hash: H256,
- pub number: BlockNumber,
- pub total_difficulty: U256
-}
-
-impl BestBlock {
- fn new() -> BestBlock {
- BestBlock {
- hash: H256::new(),
- number: 0,
- total_difficulty: U256::from(0)
+impl Default for BlockChainConfig {
+ fn default() -> Self {
+ BlockChainConfig {
+ pref_cache_size: 1 << 14,
+ max_cache_size: 1 << 20,
}
}
}
@@ -308,33 +229,7 @@ const COLLECTION_QUEUE_SIZE: usize = 8;
impl BlockChain {
/// Create new instance of blockchain from given Genesis
- ///
- /// ```rust
- /// extern crate ethcore_util as util;
- /// extern crate ethcore;
- /// use std::env;
- /// use std::str::FromStr;
- /// use ethcore::spec::*;
- /// use ethcore::blockchain::*;
- /// use ethcore::ethereum;
- /// use util::hash::*;
- /// use util::uint::*;
- ///
- /// fn main() {
- /// let spec = ethereum::new_frontier();
- ///
- /// let mut dir = env::temp_dir();
- /// dir.push(H32::random().hex());
- ///
- /// let bc = BlockChain::new(&spec.genesis_block(), &dir);
- ///
- /// let genesis_hash = "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3";
- /// assert_eq!(bc.genesis_hash(), H256::from_str(genesis_hash).unwrap());
- /// assert!(bc.is_known(&bc.genesis_hash()));
- /// assert_eq!(bc.genesis_hash(), bc.block_hash(0).unwrap());
- /// }
- /// ```
- pub fn new(genesis: &[u8], path: &Path) -> BlockChain {
+ pub fn new(config: BlockChainConfig, genesis: &[u8], path: &Path) -> BlockChain {
// open extras db
let mut extras_path = path.to_path_buf();
extras_path.push("extras");
@@ -349,9 +244,9 @@ impl BlockChain {
(0..COLLECTION_QUEUE_SIZE).foreach(|_| cache_man.cache_usage.push_back(HashSet::new()));
let bc = BlockChain {
- pref_cache_size: 1 << 14,
- max_cache_size: 1 << 20,
- best_block: RwLock::new(BestBlock::new()),
+ pref_cache_size: config.pref_cache_size,
+ max_cache_size: config.max_cache_size,
+ best_block: RwLock::new(BestBlock::default()),
blocks: RwLock::new(HashMap::new()),
block_details: RwLock::new(HashMap::new()),
block_hashes: RwLock::new(HashMap::new()),
@@ -452,40 +347,26 @@ impl BlockChain {
/// ```json
/// { blocks: [B4, B3, A3, A4], ancestor: A2, index: 2 }
/// ```
- pub fn tree_route(&self, from: H256, to: H256) -> Option {
- let from_details = match self.block_details(&from) {
- Some(h) => h,
- None => return None,
- };
- let to_details = match self.block_details(&to) {
- Some(h) => h,
- None => return None,
- };
- Some(self.tree_route_aux((&from_details, &from), (&to_details, &to)))
- }
-
- /// Similar to `tree_route` function, but can be used to return a route
- /// between blocks which may not be in database yet.
- fn tree_route_aux(&self, from: (&BlockDetails, &H256), to: (&BlockDetails, &H256)) -> TreeRoute {
+ pub fn tree_route(&self, from: H256, to: H256) -> TreeRoute {
let mut from_branch = vec![];
let mut to_branch = vec![];
- let mut from_details = from.0.clone();
- let mut to_details = to.0.clone();
- let mut current_from = from.1.clone();
- let mut current_to = to.1.clone();
+ let mut from_details = self.block_details(&from).expect(&format!("0. Expected to find details for block {:?}", from));
+ let mut to_details = self.block_details(&to).expect(&format!("1. Expected to find details for block {:?}", to));
+ let mut current_from = from;
+ let mut current_to = to;
// reset from && to to the same level
while from_details.number > to_details.number {
from_branch.push(current_from);
current_from = from_details.parent.clone();
- from_details = self.block_details(&from_details.parent).expect(&format!("1. Expected to find details for block {:?}", from_details.parent));
+ from_details = self.block_details(&from_details.parent).expect(&format!("2. Expected to find details for block {:?}", from_details.parent));
}
while to_details.number > from_details.number {
to_branch.push(current_to);
current_to = to_details.parent.clone();
- to_details = self.block_details(&to_details.parent).expect(&format!("2. Expected to find details for block {:?}", to_details.parent));
+ to_details = self.block_details(&to_details.parent).expect(&format!("3. Expected to find details for block {:?}", to_details.parent));
}
assert_eq!(from_details.number, to_details.number);
@@ -494,11 +375,11 @@ impl BlockChain {
while current_from != current_to {
from_branch.push(current_from);
current_from = from_details.parent.clone();
- from_details = self.block_details(&from_details.parent).expect(&format!("3. Expected to find details for block {:?}", from_details.parent));
+ from_details = self.block_details(&from_details.parent).expect(&format!("4. Expected to find details for block {:?}", from_details.parent));
to_branch.push(current_to);
current_to = to_details.parent.clone();
- to_details = self.block_details(&to_details.parent).expect(&format!("4. Expected to find details for block {:?}", from_details.parent));
+ to_details = self.block_details(&to_details.parent).expect(&format!("5. Expected to find details for block {:?}", from_details.parent));
}
let index = from_branch.len();
@@ -527,165 +408,237 @@ impl BlockChain {
// store block in db
self.blocks_db.put(&hash, &bytes).unwrap();
- let update = self.block_to_extras_update(bytes, receipts);
- self.apply_update(update);
+
+ let info = self.block_info(bytes);
+
+ self.apply_update(ExtrasUpdate {
+ block_hashes: self.prepare_block_hashes_update(bytes, &info),
+ block_details: self.prepare_block_details_update(bytes, &info),
+ block_receipts: self.prepare_block_receipts_update(receipts, &info),
+ transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
+ blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
+ info: info
+ });
}
/// Applies extras update.
fn apply_update(&self, update: ExtrasUpdate) {
+ let batch = DBTransaction::new();
+ batch.put(b"best", &update.info.hash).unwrap();
+
// update best block
let mut best_block = self.best_block.write().unwrap();
- if let Some(b) = update.new_best {
- *best_block = b;
+ match update.info.location {
+ BlockLocation::Branch => (),
+ _ => {
+ *best_block = BestBlock {
+ hash: update.info.hash,
+ number: update.info.number,
+ total_difficulty: update.info.total_difficulty
+ };
+ }
}
- // update details cache
- let mut write_details = self.block_details.write().unwrap();
- write_details.remove(&update.details.parent);
- write_details.insert(update.hash.clone(), update.details);
- self.note_used(CacheID::Block(update.hash));
+ let mut write_hashes = self.block_hashes.write().unwrap();
+ for (number, hash) in &update.block_hashes {
+ batch.put_extras(number, hash);
+ write_hashes.remove(number);
+ }
+
+ let mut write_details = self.block_details.write().unwrap();
+ for (hash, details) in update.block_details.into_iter() {
+ batch.put_extras(&hash, &details);
+ write_details.insert(hash, details);
+ }
+
+ let mut write_receipts = self.block_receipts.write().unwrap();
+ for (hash, receipt) in &update.block_receipts {
+ batch.put_extras(hash, receipt);
+ write_receipts.remove(hash);
+ }
+
+ let mut write_txs = self.transaction_addresses.write().unwrap();
+ for (hash, tx_address) in &update.transactions_addresses {
+ batch.put_extras(hash, tx_address);
+ write_txs.remove(hash);
+ }
- // update blocks blooms cache
let mut write_blocks_blooms = self.blocks_blooms.write().unwrap();
- for bloom_hash in &update.bloom_hashes {
+ for (bloom_hash, blocks_bloom) in &update.blocks_blooms {
+ batch.put_extras(bloom_hash, blocks_bloom);
write_blocks_blooms.remove(bloom_hash);
}
// update extras database
- self.extras_db.write(update.batch).unwrap();
+ self.extras_db.write(batch).unwrap();
}
- /// Transforms block into WriteBatch that may be written into database
- /// Additionally, if it's new best block it returns new best block object.
- fn block_to_extras_update(&self, bytes: &[u8], receipts: Vec) -> ExtrasUpdate {
- // create views onto rlp
- let block = BlockView::new(bytes);
+ /// Get inserted block info which is critical to preapre extras updates.
+ fn block_info(&self, block_bytes: &[u8]) -> BlockInfo {
+ let block = BlockView::new(block_bytes);
let header = block.header_view();
-
- // prepare variables
let hash = block.sha3();
- let mut parent_details = self.block_details(&header.parent_hash()).expect(format!("Invalid parent hash: {:?}", header.parent_hash()).as_ref());
+ let number = header.number();
+ let parent_hash = header.parent_hash();
+ let parent_details = self.block_details(&parent_hash).expect(format!("Invalid parent hash: {:?}", parent_hash).as_ref());
let total_difficulty = parent_details.total_difficulty + header.difficulty();
let is_new_best = total_difficulty > self.best_block_total_difficulty();
+
+ BlockInfo {
+ hash: hash,
+ number: number,
+ total_difficulty: total_difficulty,
+ location: if is_new_best {
+ // on new best block we need to make sure that all ancestors
+ // are moved to "canon chain"
+ // find the route between old best block and the new one
+ let best_hash = self.best_block_hash();
+ let route = self.tree_route(best_hash, parent_hash);
+
+ assert_eq!(number, parent_details.number + 1);
+
+ match route.blocks.len() {
+ 0 => BlockLocation::CanonChain,
+ _ => BlockLocation::BranchBecomingCanonChain {
+ ancestor: route.ancestor,
+ route: route.blocks.into_iter().skip(route.index).collect()
+ }
+ }
+ } else {
+ BlockLocation::Branch
+ }
+ }
+ }
+
+ /// This function returns modified block hashes.
+ fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap {
+ let mut block_hashes = HashMap::new();
+ let block = BlockView::new(block_bytes);
+ let header = block.header_view();
+ let number = header.number();
+
+ match info.location {
+ BlockLocation::Branch => (),
+ BlockLocation::CanonChain => {
+ block_hashes.insert(number, info.hash.clone());
+ },
+ BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route } => {
+ let ancestor_number = self.block_number(ancestor).unwrap();
+ let start_number = ancestor_number + 1;
+
+ for (index, hash) in route.iter().cloned().enumerate() {
+ block_hashes.insert(start_number + index as BlockNumber, hash);
+ }
+
+ block_hashes.insert(number, info.hash.clone());
+ }
+ }
+
+ block_hashes
+ }
+
+ /// This function returns modified block details.
+ fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap {
+ let block = BlockView::new(block_bytes);
+ let header = block.header_view();
let parent_hash = header.parent_hash();
+ // update parent
+ let mut parent_details = self.block_details(&parent_hash).expect(format!("Invalid parent hash: {:?}", parent_hash).as_ref());
+ parent_details.children.push(info.hash.clone());
+
// create current block details
let details = BlockDetails {
number: header.number(),
- total_difficulty: total_difficulty,
+ total_difficulty: info.total_difficulty,
parent: parent_hash.clone(),
children: vec![]
};
- // prepare the batch
- let batch = DBTransaction::new();
+ // write to batch
+ let mut block_details = HashMap::new();
+ block_details.insert(parent_hash, parent_details);
+ block_details.insert(info.hash.clone(), details);
+ block_details
+ }
- // insert new block details
- batch.put_extras(&hash, &details);
+ /// This function returns modified block receipts.
+ fn prepare_block_receipts_update(&self, receipts: Vec, info: &BlockInfo) -> HashMap {
+ let mut block_receipts = HashMap::new();
+ block_receipts.insert(info.hash.clone(), BlockReceipts::new(receipts));
+ block_receipts
+ }
- // update parent details
- parent_details.children.push(hash.clone());
- batch.put_extras(&parent_hash, &parent_details);
+ /// This function returns modified transaction addresses.
+ fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap {
+ let block = BlockView::new(block_bytes);
+ let transaction_hashes = block.transaction_hashes();
- // update transaction addresses
- for (i, tx_hash) in block.transaction_hashes().iter().enumerate() {
- batch.put_extras(tx_hash, &TransactionAddress {
- block_hash: hash.clone(),
- index: i
- });
- }
+ transaction_hashes.into_iter()
+ .enumerate()
+ .fold(HashMap::new(), |mut acc, (i ,tx_hash)| {
+ acc.insert(tx_hash, TransactionAddress {
+ block_hash: info.hash.clone(),
+ index: i
+ });
+ acc
+ })
+ }
- // update block receipts
- batch.put_extras(&hash, &BlockReceipts::new(receipts));
+ /// This functions returns modified blocks blooms.
+ ///
+ /// To accelerate blooms lookups, blomms are stored in multiple
+ /// layers (BLOOM_LEVELS, currently 3).
+ /// ChainFilter is responsible for building and rebuilding these layers.
+ /// It returns them in HashMap, where values are Blooms and
+ /// keys are BloomIndexes. BloomIndex represents bloom location on one
+ /// of these layers.
+ ///
+ /// To reduce number of queries to databse, block blooms are stored
+ /// in BlocksBlooms structure which contains info about several
+ /// (BLOOM_INDEX_SIZE, currently 16) consecutive blocks blooms.
+ ///
+ /// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex)
+ /// to bloom location in database (BlocksBloomLocation).
+ ///
+ fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap {
+ let block = BlockView::new(block_bytes);
+ let header = block.header_view();
- // if it's not new best block, just return
- if !is_new_best {
- return ExtrasUpdate {
- hash: hash.clone(),
- batch: batch,
- details: details,
- new_best: None,
- bloom_hashes: HashSet::new()
- };
- }
-
- // if its new best block we need to make sure that all ancestors
- // are moved to "canon chain"
- // find the route between old best block and the new one
- let best_hash = self.best_block_hash();
- let best_details = self.block_details(&best_hash).expect("best block hash is invalid!");
- let route = self.tree_route_aux((&best_details, &best_hash), (&details, &hash));
-
- let modified_blooms;
-
- match route.blocks.len() {
- // its our parent
- 1 => {
- batch.put_extras(&header.number(), &hash);
-
- // update block blooms
- modified_blooms = ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels())
- .add_bloom(&header.log_bloom(), header.number() as usize);
+ let modified_blooms = match info.location {
+ BlockLocation::Branch => HashMap::new(),
+ BlockLocation::CanonChain => {
+ ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels())
+ .add_bloom(&header.log_bloom(), header.number() as usize)
},
- // it is a fork
- i if i > 1 => {
- let ancestor_number = self.block_number(&route.ancestor).unwrap();
+ BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route } => {
+ let ancestor_number = self.block_number(ancestor).unwrap();
let start_number = ancestor_number + 1;
- for (index, hash) in route.blocks.iter().skip(route.index).enumerate() {
- batch.put_extras(&(start_number + index as BlockNumber), hash);
- }
- // get all blocks that are not part of canon chain (TODO: optimize it to one query)
- let blooms: Vec = route.blocks.iter()
- .skip(route.index)
+ let mut blooms: Vec = route.iter()
.map(|hash| self.block(hash).unwrap())
.map(|bytes| BlockView::new(&bytes).header_view().log_bloom())
.collect();
- // reset blooms chain head
- modified_blooms = ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels())
- .reset_chain_head(&blooms, start_number as usize, self.best_block_number() as usize);
- },
- // route.blocks.len() could be 0 only if inserted block is best block,
- // and this is not possible at this stage
- _ => { unreachable!(); }
+ blooms.push(header.log_bloom());
+
+ ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels())
+ .reset_chain_head(&blooms, start_number as usize, self.best_block_number() as usize)
+ }
};
- let bloom_hashes = modified_blooms.iter()
- .map(|(bloom_index, _)| self.bloom_indexer.location(&bloom_index).hash)
- .collect();
-
- for (bloom_hash, blocks_blooms) in modified_blooms.into_iter()
+ modified_blooms.into_iter()
.fold(HashMap::new(), | mut acc, (bloom_index, bloom) | {
{
let location = self.bloom_indexer.location(&bloom_index);
let mut blocks_blooms = acc
.entry(location.hash.clone())
.or_insert_with(|| self.blocks_blooms(&location.hash).unwrap_or_else(BlocksBlooms::new));
- assert_eq!(self.bloom_indexer.index_size, blocks_blooms.blooms.len());
+ assert_eq!(self.bloom_indexer.index_size(), blocks_blooms.blooms.len());
blocks_blooms.blooms[location.index] = bloom;
}
acc
- }) {
- batch.put_extras(&bloom_hash, &blocks_blooms);
- }
-
- // this is new best block
- batch.put(b"best", &hash).unwrap();
-
- let best_block = BestBlock {
- hash: hash.clone(),
- number: header.number(),
- total_difficulty: total_difficulty
- };
-
- ExtrasUpdate {
- hash: hash,
- batch: batch,
- new_best: Some(best_block),
- details: details,
- bloom_hashes: bloom_hashes
- }
+ })
}
/// Get best block hash.
@@ -813,18 +766,23 @@ mod tests {
use std::str::FromStr;
use rustc_serialize::hex::FromHex;
use util::hash::*;
- use blockchain::{BlockProvider, BlockChain};
+ use util::sha3::Hashable;
+ use blockchain::{BlockProvider, BlockChain, BlockChainConfig};
use tests::helpers::*;
use devtools::*;
+ use blockchain::helpers::generators::{ChainGenerator, ChainIterator};
+ use views::BlockView;
#[test]
- fn valid_tests_extra32() {
- let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0363659b251bf8b819179874c8cce7b9b983d7f3704cbb58a3b334431f7032871889032d09c281e1236c0c0".from_hex().unwrap();
+ fn basic_blockchain_insert() {
+ let mut canon_chain = ChainGenerator::default();
+ let genesis = canon_chain.next().unwrap().rlp();
+ let first = canon_chain.next().unwrap().rlp();
+ let genesis_hash = BlockView::new(&genesis).header_view().sha3();
+ let first_hash = BlockView::new(&first).header_view().sha3();
let temp = RandomTempPath::new();
- let bc = BlockChain::new(&genesis, temp.as_path());
-
- let genesis_hash = H256::from_str("3caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942").unwrap();
+ let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
assert_eq!(bc.genesis_hash(), genesis_hash.clone());
assert_eq!(bc.best_block_number(), 0);
@@ -832,13 +790,9 @@ mod tests {
assert_eq!(bc.block_hash(0), Some(genesis_hash.clone()));
assert_eq!(bc.block_hash(1), None);
assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]);
-
- let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap();
bc.insert_block(&first, vec![]);
- let first_hash = H256::from_str("a940e5af7d146b3b917c953a82e1966b906dace3a4e355b5b0a4560190357ea1").unwrap();
-
assert_eq!(bc.block_hash(0), Some(genesis_hash.clone()));
assert_eq!(bc.best_block_number(), 1);
assert_eq!(bc.best_block_hash(), first_hash.clone());
@@ -851,23 +805,27 @@ mod tests {
#[test]
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
fn test_small_fork() {
- let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap();
- let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap();
- let b2 = "f902ccf901f9a0437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
- let b3a = "f90261f901f9a036fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a09dc4b1357c0b7b8108f8a098f4f9a1a274957bc9ebc22a9ae67ae81739e5b19ca007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd882524d84562791eb80a074861666bd346c025889745c793b91ab9cd1e2ca19b5cf3c50d04d135b0a4d2b8809fe9587ea4cdc04f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba06fd84874d36d5de9e8e48978c03619b53a96b7ae0a4cd1ac118f103098b44801a00572596974dd7df4f9f69bd7456585618c568d8434ef6453391b89281ce12ae1c0".from_hex().unwrap();
- let b3b = "f90265f901f9a036fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ab87dc338bfd6f662b1cd90bc0c9e40a1b2146a095312393c9e13ce3a5008b09a0e609b7a7d4b8a2403ec1268627ecd98783627246e8f1b26addb3ff504f76a054a0592fabf92476512952db3a69a2481a42912e668a1ee28c4c322e703bb665f8beb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd882a1f084562791ee80a0fe7098fa7e4ac5d637eea81fb23f8f78346826dbab430068dd9a249d0afa99818853e1a6b201ae3545f866f86402018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d0284c04062261ca06edc9ce8e7da4cc34067beb325dcad59e5655a164a5100a50bc3eb681b12c716a0abf9053d5de65b1be81fe50d327b84de685efbeecea34e7b747180a6c6023e44c0".from_hex().unwrap();
+ let mut canon_chain = ChainGenerator::default();
+ let genesis = canon_chain.next().unwrap().rlp();
+ let blocks = canon_chain.clone().take(3).map(|block| block.rlp()).collect::>();
+ let fork = canon_chain.skip(2).fork(1).take(1).next().unwrap().rlp();
- let genesis_hash = H256::from_str("5716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2").unwrap();
- let b1_hash = H256::from_str("437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4f").unwrap();
- let b2_hash = H256::from_str("36fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781a").unwrap();
- let b3a_hash = H256::from_str("c208f88c9f5bf7e00840439742c12e5226d9752981f3ec0521bdcb6dd08af277").unwrap();
- let b3b_hash = H256::from_str("bf72270ae0d95c9ea39a6adab994793fddb8c10fba7391e26279474124605d54").unwrap();
+ let b1 = blocks[0].clone();
+ let b2 = blocks[1].clone();
+ let b3a = blocks[2].clone();
+ let b3b = fork;
+
+ let genesis_hash = BlockView::new(&genesis).header_view().sha3();
+ let b1_hash= BlockView::new(&b1).header_view().sha3();
+ let b2_hash= BlockView::new(&b2).header_view().sha3();
+ let b3a_hash= BlockView::new(&b3a).header_view().sha3();
+ let b3b_hash= BlockView::new(&b3b).header_view().sha3();
// b3a is a part of canon chain, whereas b3b is part of sidechain
- let best_block_hash = H256::from_str("c208f88c9f5bf7e00840439742c12e5226d9752981f3ec0521bdcb6dd08af277").unwrap();
+ let best_block_hash = b3a_hash.clone();
let temp = RandomTempPath::new();
- let bc = BlockChain::new(&genesis, temp.as_path());
+ let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
bc.insert_block(&b1, vec![]);
bc.insert_block(&b2, vec![]);
bc.insert_block(&b3a, vec![]);
@@ -886,52 +844,52 @@ mod tests {
assert_eq!(bc.block_hash(3).unwrap(), b3a_hash);
// test trie route
- let r0_1 = bc.tree_route(genesis_hash.clone(), b1_hash.clone()).unwrap();
+ let r0_1 = bc.tree_route(genesis_hash.clone(), b1_hash.clone());
assert_eq!(r0_1.ancestor, genesis_hash);
assert_eq!(r0_1.blocks, [b1_hash.clone()]);
assert_eq!(r0_1.index, 0);
- let r0_2 = bc.tree_route(genesis_hash.clone(), b2_hash.clone()).unwrap();
+ let r0_2 = bc.tree_route(genesis_hash.clone(), b2_hash.clone());
assert_eq!(r0_2.ancestor, genesis_hash);
assert_eq!(r0_2.blocks, [b1_hash.clone(), b2_hash.clone()]);
assert_eq!(r0_2.index, 0);
- let r1_3a = bc.tree_route(b1_hash.clone(), b3a_hash.clone()).unwrap();
+ let r1_3a = bc.tree_route(b1_hash.clone(), b3a_hash.clone());
assert_eq!(r1_3a.ancestor, b1_hash);
assert_eq!(r1_3a.blocks, [b2_hash.clone(), b3a_hash.clone()]);
assert_eq!(r1_3a.index, 0);
- let r1_3b = bc.tree_route(b1_hash.clone(), b3b_hash.clone()).unwrap();
+ let r1_3b = bc.tree_route(b1_hash.clone(), b3b_hash.clone());
assert_eq!(r1_3b.ancestor, b1_hash);
assert_eq!(r1_3b.blocks, [b2_hash.clone(), b3b_hash.clone()]);
assert_eq!(r1_3b.index, 0);
- let r3a_3b = bc.tree_route(b3a_hash.clone(), b3b_hash.clone()).unwrap();
+ let r3a_3b = bc.tree_route(b3a_hash.clone(), b3b_hash.clone());
assert_eq!(r3a_3b.ancestor, b2_hash);
assert_eq!(r3a_3b.blocks, [b3a_hash.clone(), b3b_hash.clone()]);
assert_eq!(r3a_3b.index, 1);
- let r1_0 = bc.tree_route(b1_hash.clone(), genesis_hash.clone()).unwrap();
+ let r1_0 = bc.tree_route(b1_hash.clone(), genesis_hash.clone());
assert_eq!(r1_0.ancestor, genesis_hash);
assert_eq!(r1_0.blocks, [b1_hash.clone()]);
assert_eq!(r1_0.index, 1);
- let r2_0 = bc.tree_route(b2_hash.clone(), genesis_hash.clone()).unwrap();
+ let r2_0 = bc.tree_route(b2_hash.clone(), genesis_hash.clone());
assert_eq!(r2_0.ancestor, genesis_hash);
assert_eq!(r2_0.blocks, [b2_hash.clone(), b1_hash.clone()]);
assert_eq!(r2_0.index, 2);
- let r3a_1 = bc.tree_route(b3a_hash.clone(), b1_hash.clone()).unwrap();
+ let r3a_1 = bc.tree_route(b3a_hash.clone(), b1_hash.clone());
assert_eq!(r3a_1.ancestor, b1_hash);
assert_eq!(r3a_1.blocks, [b3a_hash.clone(), b2_hash.clone()]);
assert_eq!(r3a_1.index, 2);
- let r3b_1 = bc.tree_route(b3b_hash.clone(), b1_hash.clone()).unwrap();
+ let r3b_1 = bc.tree_route(b3b_hash.clone(), b1_hash.clone());
assert_eq!(r3b_1.ancestor, b1_hash);
assert_eq!(r3b_1.blocks, [b3b_hash.clone(), b2_hash.clone()]);
assert_eq!(r3b_1.index, 2);
- let r3b_3a = bc.tree_route(b3b_hash.clone(), b3a_hash.clone()).unwrap();
+ let r3b_3a = bc.tree_route(b3b_hash.clone(), b3a_hash.clone());
assert_eq!(r3b_3a.ancestor, b2_hash);
assert_eq!(r3b_3a.blocks, [b3b_hash.clone(), b3a_hash.clone()]);
assert_eq!(r3b_3a.index, 1);
@@ -946,14 +904,14 @@ mod tests {
let temp = RandomTempPath::new();
{
- let bc = BlockChain::new(&genesis, temp.as_path());
+ let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
assert_eq!(bc.best_block_hash(), genesis_hash);
bc.insert_block(&b1, vec![]);
assert_eq!(bc.best_block_hash(), b1_hash);
}
{
- let bc = BlockChain::new(&genesis, temp.as_path());
+ let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
assert_eq!(bc.best_block_hash(), b1_hash);
}
}
@@ -1006,9 +964,9 @@ mod tests {
let b1_hash = H256::from_str("f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3").unwrap();
let temp = RandomTempPath::new();
- let bc = BlockChain::new(&genesis, temp.as_path());
+ let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
bc.insert_block(&b1, vec![]);
-
+
let transactions = bc.transactions(&b1_hash).unwrap();
assert_eq!(transactions.len(), 7);
for t in transactions {
@@ -1028,7 +986,7 @@ mod tests {
// prepare for fork (b1a, child of genesis)
let b1a = "f902ccf901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004001832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
-
+
// fork (b2a, child of b1a, with higher total difficulty)
let b2a = "f902ccf901f9a0626b0774a7cbdad7bdce07b87d74b6fa91c1c359d725076215d76348f8399f56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
@@ -1042,13 +1000,13 @@ mod tests {
let bloom_ba = H2048::from_str("00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let temp = RandomTempPath::new();
- let bc = BlockChain::new(&genesis, temp.as_path());
+ let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5);
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5);
assert_eq!(blocks_b1, vec![]);
assert_eq!(blocks_b2, vec![]);
-
+
bc.insert_block(&b1, vec![]);
let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5);
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5);
@@ -1088,31 +1046,4 @@ mod tests {
assert_eq!(blocks_b2, vec![2]);
assert_eq!(blocks_ba, vec![3]);
}
-
- #[test]
- fn test_bloom_indexer() {
- use chainfilter::BloomIndex;
- use blockchain::BloomIndexer;
- use extras::BlocksBloomLocation;
-
- let bi = BloomIndexer::new(16, 3);
-
- let index = BloomIndex::new(0, 0);
- assert_eq!(bi.location(&index), BlocksBloomLocation {
- hash: H256::new(),
- index: 0
- });
-
- let index = BloomIndex::new(1, 0);
- assert_eq!(bi.location(&index), BlocksBloomLocation {
- hash: H256::from_str("0000000000000000000000000000000000000000000000010000000000000000").unwrap(),
- index: 0
- });
-
- let index = BloomIndex::new(0, 299_999);
- assert_eq!(bi.location(&index), BlocksBloomLocation {
- hash: H256::from_str("000000000000000000000000000000000000000000000000000000000000493d").unwrap(),
- index: 15
- });
- }
}
diff --git a/ethcore/src/blockchain/bloom_indexer.rs b/ethcore/src/blockchain/bloom_indexer.rs
new file mode 100644
index 000000000..a672a5445
--- /dev/null
+++ b/ethcore/src/blockchain/bloom_indexer.rs
@@ -0,0 +1,102 @@
+// 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 util::numbers::H256;
+use chainfilter::BloomIndex;
+
+/// Represents location of block bloom in extras database.
+#[derive(Debug, PartialEq)]
+pub struct BlocksBloomLocation {
+ /// Unique hash of BlocksBloom
+ pub hash: H256,
+ /// Index within BlocksBloom
+ pub index: usize,
+}
+
+/// Should be used to localize blocks blooms in extras database.
+pub struct BloomIndexer {
+ index_size: usize,
+ levels: u8,
+}
+
+impl BloomIndexer {
+ /// Plain constructor.
+ pub fn new(index_size: usize, levels: u8) -> Self {
+ BloomIndexer {
+ index_size: index_size,
+ levels: levels
+ }
+ }
+
+ /// Calculates bloom's position in database.
+ pub fn location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation {
+ use std::{mem, ptr};
+
+ let hash = unsafe {
+ let mut hash: H256 = mem::zeroed();
+ ptr::copy(&[bloom_index.index / self.index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8);
+ hash[8] = bloom_index.level;
+ hash.reverse();
+ hash
+ };
+
+ BlocksBloomLocation {
+ hash: hash,
+ index: bloom_index.index % self.index_size
+ }
+ }
+
+ /// Returns index size.
+ pub fn index_size(&self) -> usize {
+ self.index_size
+ }
+
+ /// Returns number of cache levels.
+ pub fn levels(&self) -> u8 {
+ self.levels
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::str::FromStr;
+ use util::hash::{H256, FixedHash};
+ use chainfilter::BloomIndex;
+ use blockchain::bloom_indexer::{BloomIndexer, BlocksBloomLocation};
+
+ #[test]
+ fn test_bloom_indexer() {
+ let bi = BloomIndexer::new(16, 3);
+
+ let index = BloomIndex::new(0, 0);
+ assert_eq!(bi.location(&index), BlocksBloomLocation {
+ hash: H256::new(),
+ index: 0
+ });
+
+ let index = BloomIndex::new(1, 0);
+ assert_eq!(bi.location(&index), BlocksBloomLocation {
+ hash: H256::from_str("0000000000000000000000000000000000000000000000010000000000000000").unwrap(),
+ index: 0
+ });
+
+ let index = BloomIndex::new(0, 299_999);
+ assert_eq!(bi.location(&index), BlocksBloomLocation {
+ hash: H256::from_str("000000000000000000000000000000000000000000000000000000000000493d").unwrap(),
+ index: 15
+ });
+ }
+}
diff --git a/ethcore/src/blockchain/cache.rs b/ethcore/src/blockchain/cache.rs
new file mode 100644
index 000000000..722f83c16
--- /dev/null
+++ b/ethcore/src/blockchain/cache.rs
@@ -0,0 +1,37 @@
+// 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 .
+
+/// Represents blockchain's in-memory cache size in bytes.
+#[derive(Debug)]
+pub struct CacheSize {
+ /// Blocks cache size.
+ pub blocks: usize,
+ /// BlockDetails cache size.
+ pub block_details: usize,
+ /// Transaction addresses cache size.
+ pub transaction_addresses: usize,
+ /// Logs cache size.
+ pub block_logs: usize,
+ /// Blooms cache size.
+ pub blocks_blooms: usize,
+ /// Block receipts size.
+ pub block_receipts: usize,
+}
+
+impl CacheSize {
+ /// Total amount used by the cache.
+ pub fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms }
+}
diff --git a/ethcore/src/blockchain/helpers/generators.rs b/ethcore/src/blockchain/helpers/generators.rs
new file mode 100644
index 000000000..a20b0cf79
--- /dev/null
+++ b/ethcore/src/blockchain/helpers/generators.rs
@@ -0,0 +1,203 @@
+// 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 util::rlp::*;
+use util::hash::{H256, H2048};
+use util::uint::{U256};
+use util::bytes::Bytes;
+use header::{BlockNumber, Header};
+use transaction::SignedTransaction;
+
+pub trait Forkable {
+ fn fork(self, fork_number: usize) -> Self where Self: Sized;
+}
+
+pub struct Fork {
+ iter: I,
+ fork_number: usize,
+}
+
+impl Iterator for Fork where I: Iterator, ::Item: Forkable {
+ type Item = ::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option {
+ self.iter.next().map(|item| item.fork(self.fork_number))
+ }
+}
+
+pub trait WithBloom {
+ fn with_bloom(self, bloom: H2048) -> Self where Self: Sized;
+}
+
+pub struct Bloom {
+ iter: I,
+ bloom: H2048,
+}
+
+impl Iterator for Bloom where I: Iterator, ::Item: WithBloom {
+ type Item = ::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option {
+ self.iter.next().map(|item| item.with_bloom(self.bloom.clone()))
+ }
+}
+
+/// Chain iterator interface.
+pub trait ChainIterator: Iterator {
+ /// Should be called to create a fork of current iterator.
+ /// Blocks generated by fork will have lower difficulty than current chain.
+ fn fork(&mut self, fork_number: usize) -> Fork where Self: Sized;
+ /// Should be called to make every consecutive block have given bloom.
+ fn with_bloom(&mut self, bloom: H2048) -> Bloom where Self: Sized;
+}
+
+impl ChainIterator for I where I: Iterator + Sized + Clone {
+ fn fork(&mut self, fork_number: usize) -> Fork {
+ Fork {
+ iter: self.clone(),
+ fork_number: fork_number
+ }
+ }
+
+ fn with_bloom(&mut self, bloom: H2048) -> Bloom {
+ Bloom {
+ iter: self.clone(),
+ bloom: bloom
+ }
+ }
+}
+
+/// Helper structure, used for encoding blocks.
+#[derive(Default)]
+pub struct Block {
+ header: Header,
+ transactions: Vec,
+ uncles: Vec
+}
+
+impl Block {
+ pub fn rlp(&self) -> Bytes {
+ encode(self).to_vec()
+ }
+}
+
+impl Encodable for Block {
+ fn rlp_append(&self, s: &mut RlpStream) {
+ s.begin_list(3);
+ s.append(&self.header);
+ s.append(&self.transactions);
+ s.append(&self.uncles);
+ }
+}
+
+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);
+ self
+ }
+}
+
+impl WithBloom for Block {
+ fn with_bloom(mut self, bloom: H2048) -> Self where Self: Sized {
+ self.header.log_bloom = bloom;
+ self
+ }
+}
+
+/// Blockchain generator.
+#[derive(Clone)]
+pub struct ChainGenerator {
+ /// Next block number.
+ number: BlockNumber,
+ /// Next block parent hash.
+ parent_hash: H256,
+ /// Next block difficulty.
+ difficulty: U256,
+}
+
+impl ChainGenerator {
+ fn prepare_block(&self) -> Block {
+ let mut block = Block::default();
+ block.header.parent_hash = self.parent_hash.clone();
+ block.header.number = self.number;
+ block.header.difficulty = self.difficulty;
+ block
+ }
+}
+
+impl Default for ChainGenerator {
+ fn default() -> Self {
+ ChainGenerator {
+ number: 0,
+ parent_hash: H256::default(),
+ difficulty: U256::from(1000),
+ }
+ }
+}
+
+impl Iterator for ChainGenerator {
+ type Item = Block;
+
+ fn next(&mut self) -> Option {
+ let block = self.prepare_block();
+ self.number += 1;
+ self.parent_hash = block.header.hash();
+ Some(block)
+ }
+}
+
+
+#[cfg(test)]
+mod tests {
+ use util::hash::H256;
+ use util::sha3::Hashable;
+ use views::BlockView;
+ use super::{ChainIterator, ChainGenerator};
+
+ #[test]
+ fn canon_chain_generator() {
+ let mut canon_chain = ChainGenerator::default();
+
+ let genesis_rlp = canon_chain.next().unwrap().rlp();
+ let genesis = BlockView::new(&genesis_rlp);
+
+ assert_eq!(genesis.header_view().parent_hash(), H256::default());
+ assert_eq!(genesis.header_view().number(), 0);
+
+ let b1_rlp = canon_chain.next().unwrap().rlp();
+ let b1 = BlockView::new(&b1_rlp);
+
+ assert_eq!(b1.header_view().parent_hash(), genesis.header_view().sha3());
+ assert_eq!(b1.header_view().number(), 1);
+
+ let mut fork_chain = canon_chain.fork(1);
+
+ let b2_rlp_fork = fork_chain.next().unwrap().rlp();
+ let b2_fork = BlockView::new(&b2_rlp_fork);
+
+ assert_eq!(b2_fork.header_view().parent_hash(), b1.header_view().sha3());
+ assert_eq!(b2_fork.header_view().number(), 2);
+
+ let b2_rlp = canon_chain.next().unwrap().rlp();
+ let b2 = BlockView::new(&b2_rlp);
+
+ assert_eq!(b2.header_view().parent_hash(), b1.header_view().sha3());
+ assert_eq!(b2.header_view().number(), 2);
+ assert!(b2.header_view().difficulty() > b2_fork.header_view().difficulty());
+ }
+}
diff --git a/ethcore/src/blockchain/helpers/mod.rs b/ethcore/src/blockchain/helpers/mod.rs
new file mode 100644
index 000000000..233f8f1f8
--- /dev/null
+++ b/ethcore/src/blockchain/helpers/mod.rs
@@ -0,0 +1,17 @@
+// 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 .
+
+pub mod generators;
diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs
new file mode 100644
index 000000000..60a1aeb33
--- /dev/null
+++ b/ethcore/src/blockchain/mod.rs
@@ -0,0 +1,31 @@
+// 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 .
+
+//! Blockchain database.
+
+pub mod blockchain;
+mod best_block;
+mod block_info;
+mod bloom_indexer;
+mod cache;
+mod tree_route;
+mod update;
+#[cfg(test)]
+mod helpers;
+
+pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig};
+pub use self::cache::CacheSize;
+pub use self::tree_route::TreeRoute;
diff --git a/ethcore/src/blockchain/tree_route.rs b/ethcore/src/blockchain/tree_route.rs
new file mode 100644
index 000000000..3c4906449
--- /dev/null
+++ b/ethcore/src/blockchain/tree_route.rs
@@ -0,0 +1,29 @@
+// 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 util::numbers::H256;
+
+/// Represents a tree route between `from` block and `to` block:
+#[derive(Debug)]
+pub struct TreeRoute {
+ /// A vector of hashes of all blocks, ordered from `from` to `to`.
+ pub blocks: Vec,
+ /// Best common ancestor of these blocks.
+ pub ancestor: H256,
+ /// An index where best common ancestor would be.
+ pub index: usize,
+}
+
diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs
new file mode 100644
index 000000000..6be2647d3
--- /dev/null
+++ b/ethcore/src/blockchain/update.rs
@@ -0,0 +1,21 @@
+use std::collections::HashMap;
+use util::numbers::H256;
+use header::BlockNumber;
+use blockchain::block_info::BlockInfo;
+use extras::{BlockDetails, BlockReceipts, TransactionAddress, BlocksBlooms};
+
+/// Block extras update info.
+pub struct ExtrasUpdate {
+ /// Block info.
+ pub info: BlockInfo,
+ /// Modified block hashes.
+ pub block_hashes: HashMap,
+ /// Modified block details.
+ pub block_details: HashMap,
+ /// Modified block receipts.
+ pub block_receipts: HashMap,
+ /// Modified transaction addresses.
+ pub transactions_addresses: HashMap,
+ /// Modified blocks blooms.
+ pub blocks_blooms: HashMap,
+}
diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs
index ef6917b3a..5aabafec1 100644
--- a/ethcore/src/client.rs
+++ b/ethcore/src/client.rs
@@ -18,7 +18,7 @@
use util::*;
use util::panics::*;
-use blockchain::{BlockChain, BlockProvider, CacheSize};
+use blockchain::{BlockChain, BlockProvider};
use views::BlockView;
use error::*;
use header::{BlockNumber, Header};
@@ -26,7 +26,7 @@ use state::State;
use spec::Spec;
use engine::Engine;
use views::HeaderView;
-use block_queue::{BlockQueue, BlockQueueInfo};
+use block_queue::BlockQueue;
use service::{NetSyncMessage, SyncMessage};
use env_info::LastHashes;
use verification::*;
@@ -35,7 +35,8 @@ use transaction::LocalizedTransaction;
use extras::TransactionAddress;
use filter::Filter;
use log_entry::LocalizedLogEntry;
-pub use blockchain::TreeRoute;
+pub use block_queue::{BlockQueueConfig, BlockQueueInfo};
+pub use blockchain::{TreeRoute, BlockChainConfig, CacheSize as BlockChainCacheSize};
/// Uniquely identifies block.
#[derive(Debug, PartialEq, Clone)]
@@ -74,7 +75,16 @@ pub enum BlockStatus {
Unknown,
}
-/// Information about the blockchain gthered together.
+/// Client configuration. Includes configs for all sub-systems.
+#[derive(Debug, Default)]
+pub struct ClientConfig {
+ /// Block queue configuration.
+ pub queue: BlockQueueConfig,
+ /// Blockchain configuration.
+ pub blockchain: BlockChainConfig,
+}
+
+/// Information about the blockchain gathered together.
#[derive(Debug)]
pub struct BlockChainInfo {
/// Blockchain difficulty.
@@ -193,14 +203,14 @@ const CLIENT_DB_VER_STR: &'static str = "4.0";
impl Client {
/// Create a new client with given spec and DB path.
- pub fn new(spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, Error> {
+ pub fn new(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, Error> {
let mut dir = path.to_path_buf();
dir.push(H64::from(spec.genesis_header().hash()).hex());
//TODO: sec/fat: pruned/full versioning
dir.push(format!("v{}-sec-pruned", CLIENT_DB_VER_STR));
let path = dir.as_path();
let gb = spec.genesis_block();
- let chain = Arc::new(RwLock::new(BlockChain::new(&gb, path)));
+ let chain = Arc::new(RwLock::new(BlockChain::new(config.blockchain, &gb, path)));
let mut state_path = path.to_path_buf();
state_path.push("state");
@@ -210,7 +220,7 @@ impl Client {
state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB");
}
- let block_queue = BlockQueue::new(engine.clone(), message_channel);
+ let block_queue = BlockQueue::new(config.queue, engine.clone(), message_channel);
let panic_handler = PanicHandler::new_in_arc();
panic_handler.forward_from(&block_queue);
@@ -359,7 +369,7 @@ impl Client {
}
/// Get info on the cache.
- pub fn cache_info(&self) -> CacheSize {
+ pub fn blockchain_cache_info(&self) -> BlockChainCacheSize {
self.chain.read().unwrap().cache_size()
}
@@ -371,6 +381,7 @@ impl Client {
/// Tick the client.
pub fn tick(&self) {
self.chain.read().unwrap().collect_garbage();
+ self.block_queue.read().unwrap().collect_garbage();
}
/// Set up the cache behaviour.
@@ -458,7 +469,11 @@ impl BlockChainClient for Client {
}
fn tree_route(&self, from: &H256, to: &H256) -> Option {
- self.chain.read().unwrap().tree_route(from.clone(), to.clone())
+ let chain = self.chain.read().unwrap();
+ match chain.is_known(from) && chain.is_known(to) {
+ true => Some(chain.tree_route(from.clone(), to.clone())),
+ false => None
+ }
}
fn state_data(&self, _hash: &H256) -> Option {
diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs
index ae4cff3be..f4172f10a 100644
--- a/ethcore/src/evm/ext.rs
+++ b/ethcore/src/evm/ext.rs
@@ -16,9 +16,7 @@
//! Interface for Evm externalities.
-use common::Bytes;
-use util::hash::*;
-use util::uint::*;
+use util::common::*;
use evm::{Schedule, Error};
use env_info::*;
@@ -60,22 +58,22 @@ pub trait Ext {
fn blockhash(&self, number: &U256) -> H256;
/// Creates new contract.
- ///
+ ///
/// Returns gas_left and contract address if contract creation was succesfull.
fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult;
/// Message call.
- ///
+ ///
/// Returns Err, if we run out of gas.
- /// Otherwise returns call_result which contains gas left
+ /// Otherwise returns call_result which contains gas left
/// and true if subcall was successfull.
- fn call(&mut self,
- gas: &U256,
- sender_address: &Address,
- receive_address: &Address,
+ fn call(&mut self,
+ gas: &U256,
+ sender_address: &Address,
+ receive_address: &Address,
value: Option,
- data: &[u8],
- code_address: &Address,
+ data: &[u8],
+ code_address: &Address,
output: &mut [u8]) -> MessageCallResult;
/// Returns code at given address
@@ -99,7 +97,7 @@ pub trait Ext {
fn env_info(&self) -> &EnvInfo;
/// Returns current depth of execution.
- ///
+ ///
/// If contract A calls contract B, and contract B calls C,
/// then A depth is 0, B is 1, C is 2 and so on.
fn depth(&self) -> usize;
diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs
index 128357576..f4759b040 100644
--- a/ethcore/src/extras.rs
+++ b/ethcore/src/extras.rs
@@ -262,15 +262,6 @@ impl Encodable for BlocksBlooms {
}
}
-/// Represents location of bloom in database.
-#[derive(Debug, PartialEq)]
-pub struct BlocksBloomLocation {
- /// Unique hash of BlocksBloom
- pub hash: H256,
- /// Index within BlocksBloom
- pub index: usize,
-}
-
/// Represents address of certain transaction within block
#[derive(Clone)]
pub struct TransactionAddress {
diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs
index a386e2854..89bd5da2b 100644
--- a/ethcore/src/json_tests/chain.rs
+++ b/ethcore/src/json_tests/chain.rs
@@ -15,7 +15,7 @@
// along with Parity. If not, see .
use super::test_common::*;
-use client::{BlockChainClient,Client};
+use client::{BlockChainClient, Client, ClientConfig};
use pod_state::*;
use block::Block;
use ethereum;
@@ -53,7 +53,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec {
let temp = RandomTempPath::new();
{
- let client = Client::new(spec, temp.as_path(), IoChannel::disconnected()).unwrap();
+ let client = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()).unwrap();
assert_eq!(client.chain_info().best_block_hash, genesis_hash);
for (b, is_valid) in blocks.into_iter() {
if Block::is_good(&b) {
diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs
index 5eb3beeb2..938da02a0 100644
--- a/ethcore/src/lib.rs
+++ b/ethcore/src/lib.rs
@@ -75,7 +75,7 @@
#[macro_use] extern crate ethcore_util as util;
#[macro_use] extern crate lazy_static;
extern crate rustc_serialize;
-extern crate heapsize;
+#[macro_use] extern crate heapsize;
extern crate crypto;
extern crate time;
extern crate env_logger;
@@ -86,8 +86,6 @@ extern crate crossbeam;
#[cfg(feature = "jit" )] extern crate evmjit;
pub mod block;
-pub mod blockchain;
-pub mod block_queue;
pub mod client;
pub mod error;
pub mod ethereum;
@@ -121,6 +119,8 @@ mod substate;
mod executive;
mod externalities;
mod verification;
+mod block_queue;
+mod blockchain;
#[cfg(test)]
mod tests;
diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs
index cdf3425e8..756d02407 100644
--- a/ethcore/src/service.rs
+++ b/ethcore/src/service.rs
@@ -20,7 +20,7 @@ use util::*;
use util::panics::*;
use spec::Spec;
use error::*;
-use client::Client;
+use client::{Client, ClientConfig};
/// Message type for external and internal events
#[derive(Clone)]
@@ -48,14 +48,14 @@ pub struct ClientService {
impl ClientService {
/// Start the service in a separate thread.
- pub fn start(spec: Spec, net_config: NetworkConfiguration, db_path: &Path) -> Result {
+ pub fn start(config: ClientConfig, spec: Spec, net_config: NetworkConfiguration, db_path: &Path) -> Result {
let panic_handler = PanicHandler::new_in_arc();
let mut net_service = try!(NetworkService::start(net_config));
panic_handler.forward_from(&net_service);
info!("Starting {}", net_service.host_info());
info!("Configured for {} using {} engine", spec.name, spec.engine_name);
- let client = try!(Client::new(spec, db_path, net_service.io().channel()));
+ let client = try!(Client::new(config, spec, db_path, net_service.io().channel()));
panic_handler.forward_from(client.deref());
let client_io = Arc::new(ClientIoHandler {
client: client.clone()
@@ -135,12 +135,13 @@ mod tests {
use tests::helpers::*;
use util::network::*;
use devtools::*;
+ use client::ClientConfig;
#[test]
fn it_can_be_started() {
let spec = get_test_spec();
let temp_path = RandomTempPath::new();
- let service = ClientService::start(spec, NetworkConfiguration::new_with_port(40456), &temp_path.as_path());
+ let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_with_port(40456), &temp_path.as_path());
assert!(service.is_ok());
}
}
diff --git a/ethcore/src/spec.rs b/ethcore/src/spec.rs
index 5714ca734..38a0dda53 100644
--- a/ethcore/src/spec.rs
+++ b/ethcore/src/spec.rs
@@ -58,6 +58,8 @@ pub struct Spec {
/// Known nodes on the network in enode format.
pub nodes: Vec,
+ /// Network ID
+ pub network_id: U256,
/// Parameters concerning operation of the specific engine we're using.
/// Maps the parameter name to an RLP-encoded value.
@@ -120,6 +122,9 @@ impl Spec {
/// Get the known knodes of the network in enode format.
pub fn nodes(&self) -> &Vec { &self.nodes }
+ /// Get the configured Network ID.
+ pub fn network_id(&self) -> U256 { self.network_id }
+
/// Get the header of the genesis block.
pub fn genesis_header(&self) -> Header {
Header {
@@ -250,6 +255,7 @@ impl FromJson for Spec {
engine_name: json["engineName"].as_string().unwrap().to_owned(),
engine_params: json_to_rlp_map(&json["params"]),
nodes: nodes,
+ network_id: U256::from_str(&json["params"]["networkID"].as_string().unwrap()[2..]).unwrap(),
builtins: builtins,
parent_hash: H256::from_str(&genesis["parentHash"].as_string().unwrap()[2..]).unwrap(),
author: Address::from_str(&genesis["author"].as_string().unwrap()[2..]).unwrap(),
diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs
index 8bbf317c1..c13678c38 100644
--- a/ethcore/src/state.rs
+++ b/ethcore/src/state.rs
@@ -138,7 +138,7 @@ impl State {
/// Create a new contract at address `contract`. If there is already an account at the address
/// it will have its code reset, ready for `init_code()`.
pub fn new_contract(&mut self, contract: &Address, balance: U256) {
- self.insert_cache(&contract, Some(Account::new_contract(balance)));
+ self.insert_cache(&contract, Some(Account::new_contract(balance, self.account_start_nonce)));
}
/// Remove an existing account.
@@ -204,7 +204,7 @@ impl State {
/// Initialise the code of account `a` so that it is `value` for `key`.
/// NOTE: Account should have been created with `new_contract`.
pub fn init_code(&mut self, a: &Address, code: Bytes) {
- self.require_or_from(a, true, || Account::new_contract(U256::from(0u8)), |_|{}).init_code(code);
+ self.require_or_from(a, true, || Account::new_contract(x!(0), self.account_start_nonce), |_|{}).init_code(code);
}
/// Execute a given transaction.
@@ -335,10 +335,9 @@ impl fmt::Debug for State {
mod tests {
use super::*;
-use util::hash::*;
+use util::common::*;
use util::trie::*;
use util::rlp::*;
-use util::uint::*;
use account::*;
use tests::helpers::*;
use devtools::*;
@@ -349,7 +348,7 @@ fn code_from_database() {
let temp = RandomTempPath::new();
let (root, db) = {
let mut state = get_temp_state_in(temp.as_path());
- state.require_or_from(&a, false, ||Account::new_contract(U256::from(42u32)), |_|{});
+ state.require_or_from(&a, false, ||Account::new_contract(x!(42), x!(0)), |_|{});
state.init_code(&a, vec![1, 2, 3]);
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
state.commit();
diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs
index af25d1b72..83df81fa2 100644
--- a/ethcore/src/tests/client.rs
+++ b/ethcore/src/tests/client.rs
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-use client::{BlockChainClient, Client, BlockId};
+use client::{BlockChainClient, Client, ClientConfig, BlockId};
use tests::helpers::*;
use common::*;
use devtools::*;
@@ -22,14 +22,14 @@ use devtools::*;
#[test]
fn created() {
let dir = RandomTempPath::new();
- let client_result = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected());
+ let client_result = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected());
assert!(client_result.is_ok());
}
#[test]
fn imports_from_empty() {
let dir = RandomTempPath::new();
- let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
+ let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
client.import_verified_blocks(&IoChannel::disconnected());
client.flush_queue();
}
@@ -37,7 +37,7 @@ fn imports_from_empty() {
#[test]
fn imports_good_block() {
let dir = RandomTempPath::new();
- let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
+ let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
let good_block = get_good_dummy_block();
if let Err(_) = client.import_block(good_block) {
panic!("error importing block being good by definition");
@@ -52,7 +52,7 @@ fn imports_good_block() {
#[test]
fn query_none_block() {
let dir = RandomTempPath::new();
- let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
+ let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
let non_existant = client.block_header(BlockId::Number(188));
assert!(non_existant.is_none());
@@ -104,5 +104,5 @@ fn can_collect_garbage() {
let client_result = generate_dummy_client(100);
let client = client_result.reference();
client.tick();
- assert!(client.cache_info().blocks < 100 * 1024);
+ assert!(client.blockchain_cache_info().blocks < 100 * 1024);
}
diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs
index f1a4e6c03..44ad667b9 100644
--- a/ethcore/src/tests/helpers.rs
+++ b/ethcore/src/tests/helpers.rs
@@ -14,10 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-use client::{BlockChainClient, Client};
+use client::{BlockChainClient, Client, ClientConfig};
use common::*;
use spec::*;
-use blockchain::{BlockChain};
+use blockchain::{BlockChain, BlockChainConfig};
use state::*;
use evm::{Schedule, Factory};
use engine::*;
@@ -134,7 +134,7 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans
pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult> {
let dir = RandomTempPath::new();
- let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
+ let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
let test_spec = get_test_spec();
let test_engine = test_spec.to_engine().unwrap();
let state_root = test_engine.spec().genesis_header().state_root;
@@ -172,7 +172,7 @@ pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult
pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> {
let dir = RandomTempPath::new();
- let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
+ let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
for block in &blocks {
if let Err(_) = client.import_block(block.clone()) {
panic!("panic importing block which is well-formed");
@@ -189,7 +189,7 @@ pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult GuardedTempResult {
let temp = RandomTempPath::new();
- let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path());
+ let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), temp.as_path());
for block_order in 1..block_number {
bc.insert_block(&create_unverifiable_block(block_order, bc.best_block_hash()), vec![]);
}
@@ -202,7 +202,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult GuardedTempResult {
let temp = RandomTempPath::new();
- let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path());
+ let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), temp.as_path());
for block_order in 1..block_number {
bc.insert_block(&create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![]);
}
@@ -215,7 +215,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempRes
pub fn generate_dummy_empty_blockchain() -> GuardedTempResult {
let temp = RandomTempPath::new();
- let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path());
+ let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), temp.as_path());
GuardedTempResult:: {
_temp: temp,
@@ -250,6 +250,25 @@ pub fn get_temp_state_in(path: &Path) -> State {
State::new(journal_db, U256::from(0u8))
}
+pub fn get_good_dummy_block_seq(count: usize) -> Vec {
+ let test_spec = get_test_spec();
+ let test_engine = test_spec.to_engine().unwrap();
+ let mut parent = test_engine.spec().genesis_header().hash();
+ let mut r = Vec::new();
+ for i in 1 .. count + 1 {
+ let mut block_header = Header::new();
+ block_header.gas_limit = decode(test_engine.spec().engine_params.get("minGasLimit").unwrap());
+ block_header.difficulty = decode(test_engine.spec().engine_params.get("minimumDifficulty").unwrap());
+ block_header.timestamp = i as u64;
+ block_header.number = i as u64;
+ block_header.parent_hash = parent;
+ block_header.state_root = test_engine.spec().genesis_header().state_root;
+ parent = block_header.hash();
+ r.push(create_test_block(&block_header));
+ }
+ r
+}
+
pub fn get_good_dummy_block() -> Bytes {
let mut block_header = Header::new();
let test_spec = get_test_spec();
diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs
index fc9886a4d..a51824494 100644
--- a/ethcore/src/transaction.rs
+++ b/ethcore/src/transaction.rs
@@ -100,10 +100,10 @@ impl FromJson for SignedTransaction {
v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 },
r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) },
s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) },
- hash: RefCell::new(None),
+ hash: Cell::new(None),
sender: match json.find("sender") {
- Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))),
- _ => RefCell::new(None),
+ Some(&Json::String(ref sender)) => Cell::new(Some(address_from_hex(clean(sender)))),
+ _ => Cell::new(None),
}
}
}
@@ -127,8 +127,8 @@ impl Transaction {
r: r,
s: s,
v: v + 27,
- hash: RefCell::new(None),
- sender: RefCell::new(None)
+ hash: Cell::new(None),
+ sender: Cell::new(None),
}
}
@@ -140,8 +140,8 @@ impl Transaction {
r: U256::zero(),
s: U256::zero(),
v: 0,
- hash: RefCell::new(None),
- sender: RefCell::new(None)
+ hash: Cell::new(None),
+ sender: Cell::new(None),
}
}
@@ -171,9 +171,9 @@ pub struct SignedTransaction {
/// The S field of the signature; helps describe the point on the curve.
s: U256,
/// Cached hash.
- hash: RefCell