Merge branch 'master' into client-ipc-refact

This commit is contained in:
NikVolf 2016-07-05 11:29:46 +03:00
commit b873d3befb
69 changed files with 929 additions and 246 deletions

View File

@ -33,7 +33,7 @@ env:
global:
# GH_TOKEN
- secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw=
- TARGETS="-p ethkey -p ethstore -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethjson -p ethcore-dapps -p ethcore-signer"
- TARGETS="-p ethkey -p ethstore -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethjson -p ethcore-dapps -p ethcore-signer -p bigint"
- ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}"
- KCOV_FEATURES=""
- KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests,ethstore/tests target/kcov"

28
Cargo.lock generated
View File

@ -3,7 +3,7 @@ name = "parity"
version = "1.3.0"
dependencies = [
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
"ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)",
"daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)",
@ -129,15 +129,15 @@ dependencies = [
[[package]]
name = "clippy"
version = "0.0.77"
version = "0.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clippy_lints 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy_lints 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clippy_lints"
version = "0.0.77"
version = "0.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -250,7 +250,7 @@ name = "ethcore"
version = "1.3.0"
dependencies = [
"bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethash 1.3.0",
@ -277,7 +277,7 @@ dependencies = [
name = "ethcore-dapps"
version = "1.3.0"
dependencies = [
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-rpc 1.3.0",
"ethcore-util 1.3.0",
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
@ -287,7 +287,7 @@ dependencies = [
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
"parity-dapps-builtins 0.5.2 (git+https://github.com/ethcore/parity-dapps-builtins-rs.git)",
"parity-dapps-status 0.5.0 (git+https://github.com/ethcore/parity-dapps-status-rs.git)",
"parity-dapps-status 0.5.1 (git+https://github.com/ethcore/parity-dapps-status-rs.git)",
"parity-dapps-wallet 0.6.1 (git+https://github.com/ethcore/parity-dapps-wallet-rs.git)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -339,7 +339,7 @@ dependencies = [
name = "ethcore-rpc"
version = "1.3.0"
dependencies = [
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
"ethash 1.3.0",
"ethcore 1.3.0",
"ethcore-devtools 1.3.0",
@ -363,7 +363,7 @@ dependencies = [
name = "ethcore-signer"
version = "1.3.0"
dependencies = [
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-rpc 1.3.0",
"ethcore-util 1.3.0",
@ -383,7 +383,7 @@ dependencies = [
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"bigint 0.1.0",
"chrono 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.2.9 (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.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -455,7 +455,7 @@ dependencies = [
name = "ethsync"
version = "1.3.0"
dependencies = [
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.3.0",
"ethcore-util 1.3.0",
@ -900,7 +900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "parity-dapps"
version = "0.3.0"
source = "git+https://github.com/ethcore/parity-dapps-rs.git#8cc812c26c903cf5764ce0f4cc3f2a7c3ddb0dc2"
source = "git+https://github.com/ethcore/parity-dapps-rs.git#8ce18c014d8b69fa31fb203b68ff240091d77a23"
dependencies = [
"aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -921,8 +921,8 @@ dependencies = [
[[package]]
name = "parity-dapps-status"
version = "0.5.0"
source = "git+https://github.com/ethcore/parity-dapps-status-rs.git#0cdd3512004e403aff7da3b8c16ba0bf5d6c911c"
version = "0.5.1"
source = "git+https://github.com/ethcore/parity-dapps-status-rs.git#110ef2e66142ec8dc15fc40b8ddda5ed3bcfc1fb"
dependencies = [
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
]

View File

@ -22,7 +22,7 @@ fdlimit = { path = "util/fdlimit" }
num_cpus = "0.2"
number_prefix = "0.2"
rpassword = "0.2.1"
clippy = { version = "0.0.77", optional = true}
clippy = { version = "0.0.78", optional = true}
ethcore = { path = "ethcore" }
ethcore-util = { path = "util" }
ethsync = { path = "sync" }

View File

@ -29,7 +29,7 @@ This includes a few useful Dapps, including Ethereum Wallet, Maker OTC, and a no
In a near-future release, it will be easy to install Dapps and use them through this web interface.
If you run into an issue while using parity, feel free to file one in this repository
or hop on our [gitter chat room]([gitter-url]) to ask a question. We are glad to help!
or hop on our [gitter chat room][gitter-url] to ask a question. We are glad to help!
Parity's current release is 1.2. You can download it at https://ethcore.io/parity.html or follow the instructions
below to build from source.

View File

@ -22,13 +22,13 @@ ethcore-rpc = { path = "../rpc" }
ethcore-util = { path = "../util" }
parity-dapps = { git = "https://github.com/ethcore/parity-dapps-rs.git", version = "0.3" }
# List of apps
parity-dapps-status = { git = "https://github.com/ethcore/parity-dapps-status-rs.git", version = "0.5.0" }
parity-dapps-status = { git = "https://github.com/ethcore/parity-dapps-status-rs.git", version = "0.5.1" }
parity-dapps-builtins = { git = "https://github.com/ethcore/parity-dapps-builtins-rs.git", version = "0.5.2" }
parity-dapps-wallet = { git = "https://github.com/ethcore/parity-dapps-wallet-rs.git", version = "0.6.0", optional = true }
parity-dapps-dao = { git = "https://github.com/ethcore/parity-dapps-dao-rs.git", version = "0.4.0", optional = true }
parity-dapps-makerotc = { git = "https://github.com/ethcore/parity-dapps-makerotc-rs.git", version = "0.3.0", optional = true }
mime_guess = { version = "1.6.1" }
clippy = { version = "0.0.77", optional = true}
clippy = { version = "0.0.78", optional = true}
[build-dependencies]
serde_codegen = { version = "0.7.0", optional = true }

View File

@ -12,7 +12,7 @@ syntex = "*"
ethcore-ipc-codegen = { path = "../ipc/codegen" }
[dependencies]
clippy = { version = "0.0.77", optional = true}
clippy = { version = "0.0.78", optional = true}
ethcore-devtools = { path = "../devtools" }
ethcore-ipc = { path = "../ipc/rpc" }
rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" }

View File

@ -20,6 +20,8 @@ g++ -v
# build parity
RUN git clone https://github.com/ethcore/parity && \
cd parity&&\
git checkout beta && \
git pull && \
ls -a&&\
cargo build --release --verbose && \
ls /build/parity/target/release/parity && \

View File

@ -36,6 +36,8 @@ ENV CC aarch64-linux-gnu-gcc
# build parity
RUN git clone https://github.com/ethcore/parity && \
cd parity && \
git checkout beta && \
git pull && \
mkdir -p .cargo && \
echo '[target.aarch64-unknown-linux-gnu]\n\
linker = "aarch64-linux-gnu-gcc"\n'\

View File

@ -36,6 +36,8 @@ ENV CC arm-linux-gnueabihf-gcc
# build parity
RUN git clone https://github.com/ethcore/parity && \
cd parity && \
git checkout beta && \
git pull && \
mkdir -p .cargo && \
echo '[target.armv7-unknown-linux-gnueabihf]\n\
linker = "arm-linux-gnueabihf-gcc"\n'\

View File

@ -47,6 +47,8 @@ g++ -v
# build parity
RUN git clone https://github.com/ethcore/parity && \
cd parity && \
git checkout beta && \
git pull && \
cargo build --release --features ethcore/jit --verbose && \
ls /build/parity/target/release/parity && \
strip /build/parity/target/release/parity

View File

@ -27,7 +27,9 @@ g++ -v
# build parity
RUN git clone https://github.com/ethcore/parity && \
cd parity && \
git checkout beta && \
git pull && \
cargo build --release --verbose && \
ls /build/parity/target/release/parity && \
ls /build/parity/target/release/parity && \
strip /build/parity/target/release/parity
RUN file /build/parity/target/release/parity

View File

@ -22,7 +22,7 @@ ethcore-util = { path = "../util" }
evmjit = { path = "../evmjit", optional = true }
ethash = { path = "../ethash" }
num_cpus = "0.2"
clippy = { version = "0.0.77", optional = true}
clippy = { version = "0.0.78", optional = true}
crossbeam = "0.2.9"
lazy_static = "0.2"
ethcore-devtools = { path = "../devtools" }

View File

@ -214,8 +214,8 @@ impl Account {
}
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
pub fn commit_storage(&mut self, db: &mut AccountDBMut) {
let mut t = SecTrieDBMut::from_existing(db, &mut self.storage_root)
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut AccountDBMut) {
let mut t = trie_factory.from_existing(db, &mut self.storage_root)
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail.");
@ -275,7 +275,7 @@ mod tests {
let rlp = {
let mut a = Account::new_contract(69.into(), 0.into());
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
a.commit_storage(&mut db);
a.commit_storage(&Default::default(), &mut db);
a.init_code(vec![]);
a.commit_code(&mut db);
a.rlp()
@ -313,7 +313,7 @@ mod tests {
let mut db = AccountDBMut::new(&mut db, &Address::new());
a.set_storage(0.into(), 0x1234.into());
assert_eq!(a.storage_root(), None);
a.commit_storage(&mut db);
a.commit_storage(&Default::default(), &mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
}
@ -323,11 +323,11 @@ mod tests {
let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new());
a.set_storage(0.into(), 0x1234.into());
a.commit_storage(&mut db);
a.commit_storage(&Default::default(), &mut db);
a.set_storage(1.into(), 0x1234.into());
a.commit_storage(&mut db);
a.commit_storage(&Default::default(), &mut db);
a.set_storage(1.into(), 0.into());
a.commit_storage(&mut db);
a.commit_storage(&Default::default(), &mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
}

View File

@ -254,7 +254,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
assert!(b.try_seal(engine.deref(), seal).is_ok());

View File

@ -222,6 +222,7 @@ impl<'x> OpenBlock<'x> {
pub fn new(
engine: &'x Engine,
vm_factory: &'x EvmFactory,
trie_factory: TrieFactory,
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
@ -231,7 +232,7 @@ impl<'x> OpenBlock<'x> {
gas_range_target: (U256, U256),
extra_data: Bytes,
) -> Result<Self, Error> {
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()));
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(), trie_factory));
let mut r = OpenBlock {
block: ExecutedBlock::new(state, tracing),
engine: engine,
@ -481,16 +482,17 @@ pub fn enact(
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
{
if ::log::max_log_level() >= ::log::LogLevel::Trace {
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce()));
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(), trie_factory.clone()));
trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
}
}
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), (3141562.into(), 31415620.into()), header.extra_data().clone()));
let mut b = try!(OpenBlock::new(engine, vm_factory, trie_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), (3141562.into(), 31415620.into()), header.extra_data().clone()));
b.set_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp());
@ -509,11 +511,12 @@ pub fn enact_bytes(
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
let block = BlockView::new(block_bytes);
let header = block.header();
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
@ -526,10 +529,11 @@ pub fn enact_verified(
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
let view = BlockView::new(&block.bytes);
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
@ -542,10 +546,11 @@ pub fn enact_and_seal(
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view();
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)).seal(engine, header.seal())))
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)).seal(engine, header.seal())))
}
#[cfg(test)]
@ -565,7 +570,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
let _ = b.seal(engine.deref(), vec![]);
}
@ -581,7 +586,7 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
@ -589,7 +594,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default(), Default::default()).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes);
@ -609,7 +614,7 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default();
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new();
@ -624,7 +629,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default(), Default::default()).unwrap();
let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);

View File

@ -30,7 +30,7 @@ use blockchain::best_block::BestBlock;
use types::tree_route::TreeRoute;
use blockchain::update::ExtrasUpdate;
use blockchain::{CacheSize, ImportRoute, Config};
use db::{Writable, Readable, CacheUpdatePolicy};
use db::{Writable, Readable, CacheUpdatePolicy, Key};
const LOG_BLOOMS_LEVELS: usize = 3;
const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16;
@ -295,7 +295,22 @@ impl BlockChain {
// load best block
let best_block_hash = match bc.extras_db.get(b"best").unwrap() {
Some(best) => H256::from_slice(&best),
Some(best) => {
let best = H256::from_slice(&best);
let mut b = best.clone();
while !bc.blocks_db.get(&b).unwrap().is_some() {
// track back to the best block we have in the blocks database
let extras: BlockDetails = bc.extras_db.read(&b).unwrap();
type DetailsKey = Key<BlockDetails, Target=H264>;
bc.extras_db.delete(&(DetailsKey::key(&b))).unwrap();
b = extras.parent;
}
if b != best {
info!("Restored mismatched best block. Was: {}, new: {}", best.hex(), b.hex());
bc.extras_db.put(b"best", &b).unwrap();
}
b
}
None => {
// best block does not exist
// we need to insert genesis into the cache

View File

@ -18,3 +18,4 @@
#![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/client.ipc.rs"));

View File

@ -122,6 +122,7 @@ pub struct Client {
panic_handler: Arc<PanicHandler>,
verifier: Box<Verifier>,
vm_factory: Arc<EvmFactory>,
trie_factory: TrieFactory,
miner: Arc<Miner>,
io_channel: IoChannel<NetSyncMessage>,
queue_transactions: AtomicUsize,
@ -203,6 +204,7 @@ impl Client {
panic_handler: panic_handler,
verifier: verification::new(config.verifier_type),
vm_factory: Arc::new(EvmFactory::new(config.vm_type)),
trie_factory: TrieFactory::new(config.trie_spec),
miner: miner,
io_channel: message_channel,
queue_transactions: AtomicUsize::new(0),
@ -261,7 +263,7 @@ impl Client {
let last_hashes = self.build_last_hashes(header.parent_hash.clone());
let db = self.state_db.lock().unwrap().boxed_clone();
let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(header.parent_hash.clone()), &self.vm_factory);
let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(header.parent_hash.clone()), &self.vm_factory, self.trie_factory.clone());
if let Err(e) = enact_result {
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(());
@ -376,7 +378,7 @@ impl Client {
imported
}
fn commit_block<B>(&self, block: B, hash: &H256, block_data: &Bytes) -> ImportRoute where B: IsBlock + Drain {
fn commit_block<B>(&self, block: B, hash: &H256, block_data: &[u8]) -> ImportRoute where B: IsBlock + Drain {
let number = block.header().number();
// Are we committing an era?
let ancient = if number >= HISTORY {
@ -446,13 +448,17 @@ impl Client {
let root = HeaderView::new(&header).state_root();
State::from_existing(db, root, self.engine.account_start_nonce()).ok()
State::from_existing(db, root, self.engine.account_start_nonce(), self.trie_factory.clone()).ok()
})
}
/// Get a copy of the best block's state.
pub fn state(&self) -> State {
State::from_existing(self.state_db.lock().unwrap().boxed_clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce())
State::from_existing(
self.state_db.lock().unwrap().boxed_clone(),
HeaderView::new(&self.best_block_header()).state_root(),
self.engine.account_start_nonce(),
self.trie_factory.clone())
.expect("State root of best block header always valid.")
}
@ -509,7 +515,6 @@ impl Client {
}
}
#[derive(Ipc)]
impl BlockChainClient for Client {
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
let header = self.block_header(BlockID::Latest).unwrap();
@ -610,7 +615,7 @@ impl BlockChainClient for Client {
fn uncle(&self, id: UncleID) -> Option<Bytes> {
let index = id.position;
self.block(id.block).and_then(|block| BlockView::new(&block).uncle_at(index).and_then(|u| Some(u.rlp(Seal::With))))
self.block(id.block).and_then(|block| BlockView::new(&block).uncle_rlp_at(index))
}
fn transaction_receipt(&self, id: TransactionID) -> Option<LocalizedReceipt> {
@ -684,7 +689,7 @@ impl BlockChainClient for Client {
return Err(BlockImportError::Import(ImportError::AlreadyInChain));
}
if self.block_status(BlockID::Hash(header.parent_hash())) == BlockStatus::Unknown {
return Err(BlockImportError::Block(BlockError::UnknownParent(header.parent_hash()));
return Err(BlockImportError::Block(BlockError::UnknownParent(header.parent_hash())));
}
}
Ok(try!(self.block_queue.import_block(bytes)))
@ -694,9 +699,8 @@ impl BlockChainClient for Client {
self.block_queue.queue_info()
}
fn clear_queue(&self) -> bool {
fn clear_queue(&self) {
self.block_queue.clear();
true
}
fn chain_info(&self) -> BlockChainInfo {
@ -742,8 +746,8 @@ impl BlockChainClient for Client {
receipt.logs.into_iter()
.enumerate()
.filter(|tuple| filter.matches(&tuple.1))
.map(|(i, log)| LocalizedLogEntry {
entry: log,
.map(|(i, log)| LocalizedLogEntry {
entry: log,
block_hash: hash.clone(),
block_number: number,
transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::new),
@ -802,31 +806,29 @@ impl BlockChainClient for Client {
self.build_last_hashes(self.chain.best_block_hash())
}
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, String>> {
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, TransactionImportError>> {
let fetch_account = |a: &Address| AccountDetails {
nonce: self.latest_nonce(a),
balance: self.latest_balance(a),
};
self.miner.import_transactions(self, transactions, fetch_account)
.iter()
.map(|res| match res { &Ok(ref t) => Ok(t.clone()), &Err(ref e) => Err(format!("{:?}", e)) })
.collect::<Vec<Result<TransactionImportResult, String>>>()
self.miner.import_transactions(self, transactions, &fetch_account)
.into_iter()
.map(|res| res.map_err(|e| e.into()))
.collect()
}
fn queue_transactions(&self, transactions: Vec<Bytes>) -> bool {
fn queue_transactions(&self, transactions: Vec<Bytes>) {
if self.queue_transactions.load(AtomicOrdering::Relaxed) > MAX_TX_QUEUE_SIZE {
debug!("Ignoring {} transactions: queue is full", transactions.len());
false
} else {
let len = transactions.len();
match self.io_channel.send(NetworkIoMessage::User(SyncMessage::NewTransactions(transactions))) {
Ok(_) => {
self.queue_transactions.fetch_add(len, AtomicOrdering::SeqCst);
true
}
Err(e) => {
debug!("Ignoring {} transactions: error queueing: {}", len, e);
false
}
}
}
@ -845,6 +847,7 @@ impl MiningBlockChainClient for Client {
let mut open_block = OpenBlock::new(
engine,
&self.vm_factory,
self.trie_factory.clone(),
false, // TODO: this will need to be parameterised once we want to do immediate mining insertion.
self.state_db.lock().unwrap().boxed_clone(),
&self.chain.block_header(&h).expect("h is best block hash: so it's header must exist: qed"),

View File

@ -20,6 +20,7 @@ pub use trace::{Config as TraceConfig, Switch};
pub use evm::VMType;
pub use verification::VerifierType;
use util::journaldb;
use util::trie::TrieSpec;
/// Client state db compaction profile
#[derive(Debug, PartialEq)]
@ -45,6 +46,8 @@ pub struct ClientConfig {
pub tracing: TraceConfig,
/// VM type.
pub vm_type: VMType,
/// Trie type.
pub trie_spec: TrieSpec,
/// The JournalDB ("pruning") algorithm to use.
pub pruning: journaldb::Algorithm,
/// The name of the client instance.

View File

@ -47,9 +47,25 @@ use error::{ImportResult, ExecutionError};
use receipt::LocalizedReceipt;
use trace::LocalizedTrace;
use evm::Factory as EvmFactory;
<<<<<<< HEAD
use miner::{TransactionImportResult};
pub use types::call_analytics::CallAnalytics;
pub use types::block_import_error::BlockImportError;
=======
pub use block_import_error::BlockImportError;
pub use transaction_import::{TransactionImportResult, TransactionImportError};
/// Options concerning what analytics we run on the call.
#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)]
pub struct CallAnalytics {
/// Make a transaction trace.
pub transaction_tracing: bool,
/// Make a VM trace.
pub vm_tracing: bool,
/// Make a diff.
pub state_diffing: bool,
}
>>>>>>> master
/// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send {
@ -178,7 +194,11 @@ pub trait BlockChainClient : Sync + Send {
fn last_hashes(&self) -> LastHashes;
/// import transactions from network/other 3rd party
<<<<<<< HEAD
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, String>>;
=======
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, TransactionImportError>>;
>>>>>>> master
/// Queue transactions for importing.
fn queue_transactions(&self, transactions: Vec<Bytes>) -> bool;

View File

@ -21,7 +21,8 @@ use util::*;
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
use blockchain::TreeRoute;
use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID,
TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError};
TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics,
TransactionImportError, BlockImportError};
use header::{Header as BlockHeader, BlockNumber};
use filter::Filter;
use log_entry::LocalizedLogEntry;
@ -488,7 +489,7 @@ impl BlockChainClient for TestBlockChainClient {
unimplemented!();
}
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, String>> {
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, TransactionImportError>> {
let nonces = self.nonces.read().unwrap();
let balances = self.balances.read().unwrap();
let fetch_account = |a: &Address| AccountDetails {
@ -496,10 +497,10 @@ impl BlockChainClient for TestBlockChainClient {
balance: balances[a],
};
self.miner.import_transactions(self, transactions, fetch_account)
.iter()
.map(|res| match res { &Ok(ref t) => Ok(t.clone()), &Err(ref e) => Err(format!("{:?}", e)) })
.collect::<Vec<Result<TransactionImportResult, String>>>()
self.miner.import_transactions(self, transactions, &fetch_account)
.into_iter()
.map(|res| res.map_err(|e| e.into()))
.collect()
}
fn queue_transactions(&self, transactions: Vec<Bytes>) -> bool {

View File

@ -20,12 +20,11 @@ use util::*;
use header::BlockNumber;
use basic_types::LogBloom;
use client::Error as ClientError;
use client::BlockImportError;
use ipc::binary::{BinaryConvertable, BinaryConvertError};
use ipc::binary::{BinaryConvertError, BinaryConvertable};
use types::block_import_error::BlockImportError;
pub use types::executed::ExecutionError;
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
/// Errors concerning transaction processing.
pub enum TransactionError {
/// Transaction is already imported to the queue
@ -196,9 +195,6 @@ pub enum ImportError {
KnownBad,
}
binary_fixed_size!(BlockError);
binary_fixed_size!(ImportError);
impl fmt::Display for ImportError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = match *self {
@ -327,6 +323,10 @@ impl From<BlockImportError> for Error {
}
}
binary_fixed_size!(BlockError);
binary_fixed_size!(ImportError);
binary_fixed_size!(TransactionError);
// TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted.
/*#![feature(concat_idents)]
macro_rules! assimilate {

View File

@ -325,7 +325,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close();
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
}
@ -340,7 +340,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle = Header::new();
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
uncle.author = uncle_author.clone();

View File

@ -67,7 +67,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce()).unwrap();
let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce(), Default::default()).unwrap();
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000002")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000003")), U256::from(1u64));

View File

@ -29,8 +29,10 @@ use transaction::SignedTransaction;
use receipt::{Receipt};
use spec::Spec;
use engine::Engine;
use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionOrigin};
use miner::work_notify::WorkPoster;
use client::TransactionImportResult;
/// Different possible definitions for pending transaction set.
#[derive(Debug)]
@ -158,7 +160,7 @@ impl Miner {
fn prepare_sealing(&self, chain: &MiningBlockChainClient) {
trace!(target: "miner", "prepare_sealing: entering");
let (transactions, mut open_block, last_work_hash) = {
let (transactions, mut open_block, original_work_hash) = {
let transactions = {self.transaction_queue.lock().unwrap().top_transactions()};
let mut sealing_work = self.sealing_work.lock().unwrap();
let last_work_hash = sealing_work.peek_last_ref().map(|pb| pb.block().fields().header.hash());
@ -254,23 +256,31 @@ impl Miner {
}
}
let work = {
let (work, is_new) = {
let mut sealing_work = self.sealing_work.lock().unwrap();
trace!(target: "miner", "Checking whether we need to reseal: last={:?}, this={:?}", last_work_hash, block.block().fields().header.hash());
let work = if last_work_hash.map_or(true, |h| h != block.block().fields().header.hash()) {
let last_work_hash = sealing_work.peek_last_ref().map(|pb| pb.block().fields().header.hash());
trace!(target: "miner", "Checking whether we need to reseal: orig={:?} last={:?}, this={:?}", original_work_hash, last_work_hash, block.block().fields().header.hash());
let (work, is_new) = if last_work_hash.map_or(true, |h| h != block.block().fields().header.hash()) {
trace!(target: "miner", "Pushing a new, refreshed or borrowed pending {}...", block.block().fields().header.hash());
let pow_hash = block.block().fields().header.hash();
let number = block.block().fields().header.number();
let difficulty = *block.block().fields().header.difficulty();
let is_new = original_work_hash.map_or(true, |h| block.block().fields().header.hash() != h);
sealing_work.push(block);
Some((pow_hash, difficulty, number))
// If push notifications are enabled we assume all work items are used.
if self.work_poster.is_some() && is_new {
sealing_work.use_last_ref();
}
(Some((pow_hash, difficulty, number)), is_new)
} else {
None
(None, false)
};
trace!(target: "miner", "prepare_sealing: leaving (last={:?})", sealing_work.peek_last_ref().map(|b| b.block().fields().header.hash()));
work
(work, is_new)
};
work.map(|(pow_hash, difficulty, number)| self.work_poster.as_ref().map(|ref p| p.notify(pow_hash, difficulty, number)));
if is_new {
work.map(|(pow_hash, difficulty, number)| self.work_poster.as_ref().map(|ref p| p.notify(pow_hash, difficulty, number)));
}
}
fn update_gas_limit(&self, chain: &MiningBlockChainClient) {

View File

@ -47,9 +47,10 @@ mod external;
mod transaction_queue;
mod work_notify;
pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionOrigin};
pub use self::miner::{Miner, MinerOptions, PendingSet};
pub use self::external::{ExternalMiner, ExternalMinerService};
pub use client::TransactionImportResult;
use std::collections::BTreeMap;
use util::{H256, U256, Address, Bytes};

View File

@ -90,7 +90,11 @@ use util::hash::{Address, H256};
use util::table::*;
use transaction::*;
use error::{Error, TransactionError};
<<<<<<< HEAD
pub use types::transaction_import_result::TransactionImportResult;
=======
use client::TransactionImportResult;
>>>>>>> master
/// Transaction origin
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -805,6 +809,7 @@ mod test {
use error::{Error, TransactionError};
use super::*;
use super::{TransactionSet, TransactionOrder, VerifiedTransaction};
use client::TransactionImportResult;
fn unwrap_tx_err(err: Result<TransactionImportResult, Error>) -> TransactionError {
match err.unwrap_err() {

View File

@ -52,10 +52,10 @@ impl WorkPoster {
}
fn create_client() -> Client<PostHandler> {
let client = Client::<PostHandler>::configure()
Client::<PostHandler>::configure()
.keep_alive(true)
.build().expect("Error creating HTTP client") as Client<PostHandler>;
client
.build()
.expect("Error creating HTTP client")
}
pub fn notify(&self, pow_hash: H256, difficulty: U256, number: u64) {
@ -63,8 +63,10 @@ impl WorkPoster {
let target = Ethash::difficulty_to_boundary(&difficulty);
let seed_hash = &self.seed_compute.lock().unwrap().get_seedhash(number);
let seed_hash = H256::from_slice(&seed_hash[..]);
let body = format!(r#"{{ "result": ["0x{}","0x{}","0x{}","0x{:x}"] }}"#,
pow_hash.hex(), seed_hash.hex(), target.hex(), number);
let body = format!(
r#"{{ "result": ["0x{}","0x{}","0x{}","0x{:x}"] }}"#,
pow_hash.hex(), seed_hash.hex(), target.hex(), number
);
let mut client = self.client.lock().unwrap();
for u in &self.urls {
if let Err(e) = client.request(u.clone(), PostHandler { body: body.clone() }) {
@ -104,12 +106,12 @@ impl hyper::client::Handler<HttpStream> for PostHandler {
}
fn on_response_readable(&mut self, _decoder: &mut hyper::Decoder<HttpStream>) -> Next {
Next::end()
Next::end()
}
fn on_error(&mut self, err: hyper::Error) -> Next {
fn on_error(&mut self, err: hyper::Error) -> Next {
trace!("Error posting work data: {}", err);
Next::end()
}
}
}

View File

@ -42,6 +42,7 @@ pub struct State {
cache: RefCell<HashMap<Address, Option<Account>>>,
snapshots: RefCell<Vec<HashMap<Address, Option<Option<Account>>>>>,
account_start_nonce: U256,
trie_factory: TrieFactory,
}
const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \
@ -50,11 +51,11 @@ const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with v
impl State {
/// Creates new state with empty state root
#[cfg(test)]
pub fn new(mut db: Box<JournalDB>, account_start_nonce: U256) -> State {
pub fn new(mut db: Box<JournalDB>, account_start_nonce: U256, trie_factory: TrieFactory) -> State {
let mut root = H256::new();
{
// init trie and reset root too null
let _ = SecTrieDBMut::new(db.as_hashdb_mut(), &mut root);
let _ = trie_factory.create(db.as_hashdb_mut(), &mut root);
}
State {
@ -63,22 +64,26 @@ impl State {
cache: RefCell::new(HashMap::new()),
snapshots: RefCell::new(Vec::new()),
account_start_nonce: account_start_nonce,
trie_factory: trie_factory,
}
}
/// Creates new state with existing state root
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256) -> Result<State, TrieError> {
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256, trie_factory: TrieFactory) -> Result<State, TrieError> {
if !db.as_hashdb().contains(&root) {
Err(TrieError::InvalidStateRoot)
} else {
Ok(State {
db: db,
root: root,
cache: RefCell::new(HashMap::new()),
snapshots: RefCell::new(Vec::new()),
account_start_nonce: account_start_nonce,
})
return Err(TrieError::InvalidStateRoot);
}
let state = State {
db: db,
root: root,
cache: RefCell::new(HashMap::new()),
snapshots: RefCell::new(Vec::new()),
account_start_nonce: account_start_nonce,
trie_factory: trie_factory,
};
Ok(state)
}
/// Create a recoverable snaphot of this state
@ -156,7 +161,7 @@ impl State {
/// Determine whether an account exists.
pub fn exists(&self, a: &Address) -> bool {
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
self.cache.borrow().get(&a).unwrap_or(&None).is_some() || db.contains(&a)
}
@ -242,7 +247,10 @@ impl State {
for a in &addresses {
if self.code(a).map_or(false, |c| c.sha3() == broken_dao) {
// Figure out if the balance has been reduced.
let maybe_original = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR).get(&a).map(Account::from_rlp);
let maybe_original = self.trie_factory
.readonly(self.db.as_hashdb(), &self.root)
.expect(SEC_TRIE_DB_UNWRAP_STR)
.get(&a).map(Account::from_rlp);
if maybe_original.map_or(false, |original| *original.balance() > self.balance(a)) {
return Err(Error::Transaction(TransactionError::DAORescue));
}
@ -262,14 +270,14 @@ impl State {
/// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit.
/// `accounts` is mutable because we may need to commit the code or storage and record that.
#[cfg_attr(feature="dev", allow(match_ref_pats))]
pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap<Address, Option<Account>>) {
pub fn commit_into(trie_factory: &TrieFactory, db: &mut HashDB, root: &mut H256, accounts: &mut HashMap<Address, Option<Account>>) {
// first, commit the sub trees.
// TODO: is this necessary or can we dispense with the `ref mut a` for just `a`?
for (address, ref mut a) in accounts.iter_mut() {
match a {
&mut&mut Some(ref mut account) => {
let mut account_db = AccountDBMut::new(db, address);
account.commit_storage(&mut account_db);
account.commit_storage(trie_factory, &mut account_db);
account.commit_code(&mut account_db);
}
&mut&mut None => {}
@ -277,7 +285,7 @@ impl State {
}
{
let mut trie = SecTrieDBMut::from_existing(db, root).unwrap();
let mut trie = trie_factory.from_existing(db, root).unwrap();
for (address, ref a) in accounts.iter() {
match **a {
Some(ref account) => trie.insert(address, &account.rlp()),
@ -290,7 +298,7 @@ impl State {
/// Commits our cached account changes into the trie.
pub fn commit(&mut self) {
assert!(self.snapshots.borrow().is_empty());
Self::commit_into(self.db.as_hashdb_mut(), &mut self.root, self.cache.borrow_mut().deref_mut());
Self::commit_into(&self.trie_factory, self.db.as_hashdb_mut(), &mut self.root, self.cache.borrow_mut().deref_mut());
}
#[cfg(test)]
@ -340,7 +348,7 @@ impl State {
fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option<Account> {
let have_key = self.cache.borrow().contains_key(a);
if !have_key {
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
self.insert_cache(a, db.get(&a).map(Account::from_rlp))
}
if require_code {
@ -361,7 +369,7 @@ impl State {
fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> &'a mut Account {
let have_key = self.cache.borrow().contains_key(a);
if !have_key {
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
self.insert_cache(a, db.get(&a).map(Account::from_rlp))
} else {
self.note_cache(a);
@ -396,6 +404,7 @@ impl Clone for State {
cache: RefCell::new(self.cache.borrow().clone()),
snapshots: RefCell::new(self.snapshots.borrow().clone()),
account_start_nonce: self.account_start_nonce.clone(),
trie_factory: self.trie_factory.clone(),
}
}
}
@ -1179,7 +1188,7 @@ fn code_from_database() {
state.drop()
};
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
}
@ -1194,7 +1203,7 @@ fn storage_at_from_database() {
state.drop()
};
let s = State::from_existing(db, root, U256::from(0u8)).unwrap();
let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert_eq!(s.storage_at(&a, &H256::from(&U256::from(01u64))), H256::from(&U256::from(69u64)));
}
@ -1211,7 +1220,7 @@ fn get_from_database() {
state.drop()
};
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert_eq!(state.balance(&a), U256::from(69u64));
assert_eq!(state.nonce(&a), U256::from(1u64));
}
@ -1244,7 +1253,7 @@ fn remove_from_database() {
};
let (root, db) = {
let mut state = State::from_existing(db, root, U256::from(0u8)).unwrap();
let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert_eq!(state.exists(&a), true);
assert_eq!(state.nonce(&a), U256::from(1u64));
state.kill_account(&a);
@ -1254,7 +1263,7 @@ fn remove_from_database() {
state.drop()
};
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert_eq!(state.exists(&a), false);
assert_eq!(state.nonce(&a), U256::from(0u64));
}

View File

@ -175,6 +175,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
let mut b = OpenBlock::new(
test_engine.deref(),
&vm_factory,
Default::default(),
false,
db,
&last_header,
@ -315,7 +316,7 @@ pub fn get_temp_state() -> GuardedTempResult<State> {
let journal_db = get_temp_journal_db_in(temp.as_path());
GuardedTempResult {
_temp: temp,
result: Some(State::new(journal_db, U256::from(0u8)))
result: Some(State::new(journal_db, U256::from(0), Default::default())),
}
}
@ -325,7 +326,7 @@ pub fn get_temp_journal_db_in(path: &Path) -> Box<JournalDB> {
pub fn get_temp_state_in(path: &Path) -> State {
let journal_db = get_temp_journal_db_in(path);
State::new(journal_db, U256::from(0u8))
State::new(journal_db, U256::from(0), Default::default())
}
pub fn get_good_dummy_block_seq(count: usize) -> Vec<Bytes> {

View File

@ -26,8 +26,8 @@ pub mod block_status;
pub mod account_diff;
pub mod state_diff;
pub mod block_queue_info;
pub mod transaction_import_result;
pub mod filter;
pub mod trace_filter;
pub mod call_analytics;
pub mod transaction_import;
pub mod block_import_error;

View File

@ -0,0 +1,52 @@
// 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 <http://www.gnu.org/licenses/>.
//! Transaction import result related types
use ipc::binary::{BinaryConvertError, BinaryConvertable};
use std::collections::VecDeque;
use error::{TransactionError, Error};
use std::mem;
use util::Populatable;
#[derive(Debug, Clone, PartialEq)]
/// Represents the result of importing transaction.
pub enum TransactionImportResult {
/// Transaction was imported to current queue.
Current,
/// Transaction was imported to future queue.
Future
}
binary_fixed_size!(TransactionImportResult);
/// Api-level error for transaction import
#[derive(Debug, Clone, Binary)]
pub enum TransactionImportError {
/// Transaction error
Transaction(TransactionError),
/// Other error
Other(String),
}
impl From<Error> for TransactionImportError {
fn from(e: Error) -> Self {
match e {
Error::Transaction(transaction_error) => TransactionImportError::Transaction(transaction_error),
_ => TransactionImportError::Other(format!("other block import error: {:?}", e)),
}
}
}

View File

@ -139,6 +139,11 @@ impl<'a> BlockView<'a> {
pub fn uncle_at(&self, index: usize) -> Option<Header> {
self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_val())
}
/// Return nth uncle rlp.
pub fn uncle_rlp_at(&self, index: usize) -> Option<Bytes> {
self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_raw().to_vec())
}
}
impl<'a> Hashable for BlockView<'a> {

View File

@ -22,5 +22,5 @@ aster = { version = "0.17", default-features = false }
clippy = { version = "^0.*", optional = true }
quasi = { version = "0.11", default-features = false }
quasi_macros = { version = "0.11", optional = true }
syntex = { version = "*", optional = true }
syntex_syntax = { version = "*", optional = true }
syntex = { version = "0.33", optional = true }
syntex_syntax = { version = "0.33", optional = true }

View File

@ -201,15 +201,20 @@ fn implement_dispatch_arm_invoke_stmt(
{
let _sp = ext_cx.call_site();
let mut tt = ::std::vec::Vec::new();
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("ipc"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("binary"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
if dispatch.return_type_ty.is_some() {
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("ipc"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("binary"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
}
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter());
@ -221,12 +226,25 @@ fn implement_dispatch_arm_invoke_stmt(
}
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
if dispatch.return_type_ty.is_some() {
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
}
else {
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Semi));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Vec"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("new"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
}
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
tt
})).unwrap()
}
@ -497,9 +515,9 @@ fn client_generics(builder: &aster::AstBuilder, interface_map: &InterfaceMap) ->
.build()
}
fn client_qualified_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P<Ty> {
fn client_qualified_ident(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P<Ty> {
let generics = client_generics(builder, interface_map);
aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(builder))
aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item))
.with_generics(generics).build()
.build()
}
@ -515,7 +533,7 @@ fn client_phantom_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMa
/// for say `Service` it generates `ServiceClient`
fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap, push: &mut FnMut(Annotatable)) {
let generics = client_generics(builder, interface_map);
let client_short_ident = interface_map.ident_map.client_ident(builder);
let client_short_ident = interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item);
let phantom = client_phantom_ident(builder, interface_map);
let client_struct_item = quote_item!(cx,
@ -547,9 +565,9 @@ fn push_with_socket_client_implementation(
push: &mut FnMut(Annotatable))
{
let generics = client_generics(builder, interface_map);
let client_ident = client_qualified_ident(builder, interface_map);
let client_ident = client_qualified_ident(cx, builder, interface_map);
let where_clause = &generics.where_clause;
let client_short_ident = interface_map.ident_map.client_ident(builder);
let client_short_ident = interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item);
let implement = quote_item!(cx,
impl $generics ::ipc::WithSocket<S> for $client_ident $where_clause {
@ -578,7 +596,7 @@ fn push_client_implementation(
.collect::<Vec<P<ast::ImplItem>>>();
let generics = client_generics(builder, interface_map);
let client_ident = client_qualified_ident(builder, interface_map);
let client_ident = client_qualified_ident(cx, builder, interface_map);
let where_clause = &generics.where_clause;
let handshake_item = quote_impl_item!(cx,
@ -682,6 +700,52 @@ fn implement_handshake_arm(
}
fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<String, ()> {
match lit.node {
ast::LitKind::Str(ref s, _) => Ok(format!("{}", s)),
_ => {
cx.span_err(
lit.span,
&format!("ipc client_ident annotation `{}` must be a string, not `{}`",
name,
::syntax::print::pprust::lit_to_string(lit)));
return Err(());
}
}
}
pub fn get_ipc_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
match attr.node.value.node {
ast::MetaItemKind::List(ref name, ref items) if name == &"ipc" => {
Some(items)
}
_ => None
}
}
fn client_ident_renamed(cx: &ExtCtxt, item: &ast::Item) -> Option<String> {
for meta_items in item.attrs().iter().filter_map(get_ipc_meta_items) {
for meta_item in meta_items {
let span = meta_item.span;
match meta_item.node {
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"client_ident" => {
if let Ok(s) = get_str_from_lit(cx, name, lit) {
return Some(s);
}
}
_ => {
cx.span_err(
meta_item.span,
&format!("unknown client_ident container attribute `{}`",
::syntax::print::pprust::meta_item_to_string(meta_item)));
}
}
}
}
None
}
struct InterfaceMap {
pub original_item: Item,
pub item: P<ast::Item>,
@ -700,8 +764,13 @@ impl IdentMap {
builder.id(format!("{}", ::syntax::print::pprust::path_to_string(&self.original_path)))
}
fn client_ident(&self, builder: &aster::AstBuilder) -> Ident {
builder.id(format!("{}Client", self.original_path.segments[0].identifier))
fn client_ident(&self, cx: &ExtCtxt, builder: &aster::AstBuilder, item: &ast::Item) -> Ident {
if let Some(new_name) = client_ident_renamed(cx, item) {
builder.id(new_name)
}
else {
builder.id(format!("{}Client", self.original_path.segments[0].identifier))
}
}
fn qualified_ident(&self, builder: &aster::AstBuilder) -> Ident {

View File

@ -50,11 +50,36 @@ include!("lib.rs.in");
#[cfg(feature = "with-syntex")]
pub fn register(reg: &mut syntex::Registry) {
use syntax::{ast, fold};
#[cfg(feature = "with-syntex")]
fn strip_attributes(krate: ast::Crate) -> ast::Crate {
struct StripAttributeFolder;
impl fold::Folder for StripAttributeFolder {
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
match attr.node.value.node {
ast::MetaItemKind::List(ref n, _) if n == &"ipc" => { return None; }
_ => {}
}
Some(attr)
}
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
fold::noop_fold_mac(mac, self)
}
}
fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
}
reg.add_attr("feature(custom_derive)");
reg.add_attr("feature(custom_attribute)");
reg.add_decorator("derive_Ipc", codegen::expand_ipc_implementation);
reg.add_decorator("derive_Binary", serialization::expand_serialization_implementation);
reg.add_post_expansion_pass(strip_attributes);
}
#[cfg(not(feature = "with-syntex"))]
@ -67,4 +92,6 @@ pub fn register(reg: &mut rustc_plugin::Registry) {
syntax::parse::token::intern("derive_Binary"),
syntax::ext::base::MultiDecorator(
Box::new(serialization::expand_serialization_implementation)));
reg.register_attribute("ipc".to_owned(), AttributeType::Normal);
}

View File

@ -144,10 +144,8 @@ impl<K, V> BinaryConvertable for BTreeMap<K, V> where K : BinaryConvertable + Or
0usize + match K::len_params() {
0 => mem::size_of::<K>() * self.len(),
_ => self.iter().fold(0usize, |acc, (k, _)| acc + k.size())
}
+
match V::len_params() {
0 => mem::size_of::<V>() * self.len(),
} + match V::len_params() {
0 => mem::size_of::<V>() * self.len(), 0 => mem::size_of::<V>() * self.len(),
_ => self.iter().fold(0usize, |acc, (_, v)| acc + v.size())
}
}
@ -179,7 +177,7 @@ impl<K, V> BinaryConvertable for BTreeMap<K, V> where K : BinaryConvertable + Or
Ok(())
}
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize> ) -> Result<Self, BinaryConvertError> {
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
let mut index = 0;
let mut result = Self::new();
@ -192,8 +190,7 @@ impl<K, V> BinaryConvertable for BTreeMap<K, V> where K : BinaryConvertable + Or
};
let key = if key_size == 0 {
try!(K::from_empty_bytes())
}
else {
} else {
try!(K::from_bytes(&buffer[index..index+key_size], length_stack))
};
index = index + key_size;
@ -204,8 +201,7 @@ impl<K, V> BinaryConvertable for BTreeMap<K, V> where K : BinaryConvertable + Or
};
let val = if val_size == 0 {
try!(V::from_empty_bytes())
}
else {
} else {
try!(V::from_bytes(&buffer[index..index+val_size], length_stack))
};
result.insert(key, val);

View File

@ -16,5 +16,5 @@ ethcore-ipc-nano = { path = "../nano" }
ethcore-util = { path = "../../util" }
[build-dependencies]
syntex = "*"
syntex = "0.33"
ethcore-ipc-codegen = { path = "../codegen" }

View File

@ -58,6 +58,23 @@ pub fn main() {
registry.expand("", &src, &dst).unwrap();
}
// rpc pass
if {
let src = Path::new("with_attrs.rs.in");
let dst = Path::new(&out_dir).join("with_attrs_ipc.rs");
let mut registry = syntex::Registry::new();
codegen::register(&mut registry);
registry.expand("", &src, &dst).is_ok()
}
// serialization pass
{
let src = Path::new(&out_dir).join("with_attrs_ipc.rs");
let dst = Path::new(&out_dir).join("with_attrs_cg.rs");
let mut registry = syntex::Registry::new();
codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}
// rpc pass
{
let src = Path::new("binary.rs.in");

View File

@ -86,7 +86,7 @@ mod tests {
0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0],
service_client.socket().borrow().write_buffer.clone());
service_client.socket().write().unwrap().write_buffer.clone());
assert_eq!(10, result);
}
@ -103,7 +103,7 @@ mod tests {
1, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0, 10, 0, 0, 0], service_client.socket().borrow().write_buffer.clone());
5, 0, 0, 0, 10, 0, 0, 0], service_client.socket().write().unwrap().write_buffer.clone());
assert_eq!(10, result);
}
@ -145,7 +145,7 @@ mod tests {
// items
3, 0, 0, 0, 0, 0, 0, 0,
11, 0, 0, 0, 0, 0, 0, 0],
service_client.socket().borrow().write_buffer.clone());
service_client.socket().write().unwrap().write_buffer.clone());
assert_eq!(true, result);
}
@ -190,4 +190,20 @@ mod tests {
assert_eq!(struct_, new_struct);
}
#[test]
fn can_call_void_method() {
let mut socket = TestSocket::new();
socket.read_buffer = vec![1];
let service_client = ServiceClient::init(socket);
service_client.void(99);
assert_eq!(vec![
0, 19,
0, 0, 0, 0, 0, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0,
99, 0, 0, 0, 0, 0, 0, 0],
service_client.socket().write().unwrap().write_buffer.clone());
}
}

View File

@ -18,6 +18,7 @@
mod tests {
use super::super::service::*;
use super::super::with_attrs::PrettyNamedClient;
use nanoipc;
use std::sync::Arc;
use std::io::Write;
@ -43,6 +44,12 @@ mod tests {
assert!(client.is_ok());
}
#[test]
fn can_create_renamed_client() {
let client = nanoipc::init_duplex_client::<PrettyNamedClient<_>>("ipc:///tmp/parity-nano-test10.ipc");
assert!(client.is_ok());
}
#[test]
fn can_call_handshake() {
let url = "ipc:///tmp/parity-test-nano-20.ipc";

View File

@ -28,3 +28,4 @@ mod examples;
mod over_nano;
mod nested;
mod binary;
mod with_attrs;

View File

@ -39,12 +39,14 @@ impl Service {
*lock = *lock + f as usize;
f
}
pub fn rollback(&self, a: Option<u32>, b: u32) -> i32 {
let a_0 = a.unwrap_or_else(|| 0);
let mut lock = self.rollbacks.write().unwrap();
*lock = *lock + a_0 as usize - b as usize;
(a_0 - b) as i32
}
pub fn push_custom(&self, data: CustomData) -> bool {
let mut clock = self.commits.write().unwrap();
let mut rlock = self.commits.write().unwrap();
@ -54,6 +56,9 @@ impl Service {
true
}
pub fn void(&self, a: u64) {
}
}
impl Service {

18
ipc/tests/with_attrs.rs Normal file
View File

@ -0,0 +1,18 @@
// 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 <http://www.gnu.org/licenses/>.
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/with_attrs_cg.rs"));

View File

@ -14,16 +14,21 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Transaction import result related types
use std::sync::RwLock;
use std::ops::*;
use ipc::IpcConfig;
use std::mem;
use ipc::binary::BinaryConvertError;
use std::collections::VecDeque;
#[derive(Debug, Clone, PartialEq, Binary)]
/// Represents the result of importing transaction.
pub enum TransactionImportResult {
/// Transaction was imported to current queue.
Current,
/// Transaction was imported to future queue.
Future
pub struct BadlyNamedService;
#[derive(Ipc)]
#[ipc(client_ident="PrettyNamedClient")]
impl BadlyNamedService {
fn is_zero(&self, x: u64) -> bool {
x == 0
}
}
impl ::ipc::IpcConfig for BadlyNamedService {}

View File

@ -10,7 +10,7 @@ rustc-serialize = "0.3"
serde = "0.7.0"
serde_json = "0.7.0"
serde_macros = { version = "0.7.0", optional = true }
clippy = { version = "0.0.77", optional = true}
clippy = { version = "0.0.78", optional = true}
[build-dependencies]
serde_codegen = { version = "0.7.0", optional = true }

View File

@ -52,12 +52,21 @@ Protocol Options:
Account Options:
--unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution.
ACCOUNTS is a comma-delimited list of addresses.
Implies --no-signer.
--password FILE Provide a file containing a password for unlocking
an account.
--keys-iterations NUM Specify the number of iterations to use when
deriving key from the password (bigger is more
secure) [default: 10240].
--no-import-keys Do not import keys from legacy clients.
--force-signer Enable Trusted Signer WebSocket endpoint used by
Signer UIs, even when --unlock is in use.
--no-signer Disable Trusted Signer WebSocket endpoint used by
Signer UIs.
--signer-port PORT Specify the port of Trusted Signer server
[default: 8180].
--signer-path PATH Specify directory where Signer UIs tokens should
be stored. [default: $HOME/.parity/signer]
Networking Options:
--no-network Disable p2p networking.
@ -114,17 +123,6 @@ API and Console Options:
--dapps-path PATH Specify directory where dapps should be installed.
[default: $HOME/.parity/dapps]
--signer Enable Trusted Signer WebSocket endpoint used by
Signer UIs. Default if run with ui command.
--no-signer Disable Trusted Signer WebSocket endpoint used by
Signer UIs. Default if no command is specified.
--signer-port PORT Specify the port of Trusted Signer server
[default: 8180].
--signer-path PATH Specify directory where Signer UIs tokens should
be stored. [default: $HOME/.parity/signer]
--no-token By default a new system UI security token will be
output on start up. This will prevent it.
Sealing/Mining Options:
--author ADDRESS Specify the block author (aka "coinbase") address
for sending block rewards from sealed blocks.
@ -203,6 +201,7 @@ Database Options:
--db-compaction TYPE Database compaction type. TYPE may be one of:
ssd - suitable for SSDs and fast HDDs;
hdd - suitable for slow HDDs [default: ssd].
--fat-db Fat database.
Import/Export Options:
--from BLOCK Export from block BLOCK, which may be an index or
@ -308,11 +307,10 @@ pub struct Args {
pub flag_dapps_user: Option<String>,
pub flag_dapps_pass: Option<String>,
pub flag_dapps_path: String,
pub flag_signer: bool,
pub flag_force_signer: bool,
pub flag_no_signer: bool,
pub flag_signer_port: u16,
pub flag_signer_path: String,
pub flag_no_token: bool,
pub flag_force_sealing: bool,
pub flag_reseal_on_txs: String,
pub flag_reseal_min_period: u64,
@ -362,6 +360,7 @@ pub struct Args {
pub flag_ipcapi: Option<String>,
pub flag_db_cache_size: Option<usize>,
pub flag_db_compaction: String,
pub flag_fat_db: bool,
}
pub fn print_version() {

View File

@ -254,7 +254,7 @@ impl Configuration {
let host = IpAddr::from_str(host).unwrap_or_else(|_| die!("Invalid host given with `--nat extip:{}`", host));
Some(SocketAddr::new(host, port))
} else {
listen_address
None
};
(listen_address, public_address)
}
@ -333,6 +333,14 @@ impl Configuration {
_ => { die!("Invalid pruning method given."); }
};
if self.args.flag_fat_db {
if let journaldb::Algorithm::Archive = client_config.pruning {
client_config.trie_spec = TrieSpec::Fat;
} else {
die!("Fatdb is not supported. Please rerun with --pruning=archive")
}
}
// forced state db cache size if provided
client_config.db_cache_size = self.args.flag_db_cache_size.and_then(|cs| Some(cs / 4));
@ -340,7 +348,7 @@ impl Configuration {
client_config.db_compaction = match self.args.flag_db_compaction.as_str() {
"ssd" => DatabaseCompactionProfile::Default,
"hdd" => DatabaseCompactionProfile::HDD,
_ => { die!("Invalid compaction profile given (--db-compaction argument), expected hdd/default."); }
_ => { die!("Invalid compaction profile given (--db-compaction argument), expected hdd/ssd (default)."); }
};
if self.args.flag_jitvm {
@ -467,6 +475,11 @@ impl Configuration {
let signer_path = Configuration::replace_home(&self.args.flag_signer_path);
::std::fs::create_dir_all(&signer_path).unwrap_or_else(|e| die_with_io_error("main", e));
if self.args.flag_geth {
let geth_path = path::ethereum::default();
::std::fs::create_dir_all(geth_path.as_path()).unwrap_or_else(
|e| die!("Error while attempting to create '{}' for geth mode: {}", &geth_path.to_str().unwrap(), e));
}
Directories {
keys: keys_path,
@ -531,8 +544,8 @@ impl Configuration {
}
pub fn signer_enabled(&self) -> bool {
(self.args.cmd_ui && !self.args.flag_no_signer) ||
(!self.args.cmd_ui && self.args.flag_signer)
(self.args.flag_unlock.is_none() && !self.args.flag_no_signer) ||
self.args.flag_force_signer
}
}

View File

@ -193,13 +193,6 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
let net_settings = conf.net_settings(&spec);
let sync_config = conf.sync_config(&spec);
// Create and display a new token for UIs.
if conf.signer_enabled() && !conf.args.flag_no_token {
new_token(conf.directories().signer).unwrap_or_else(|e| {
die!("Error generating token: {:?}", e)
});
}
// Display warning about using unlock with signer
if conf.signer_enabled() && conf.args.flag_unlock.is_some() {
warn!("Using Trusted Signer and --unlock is not recommended!");

View File

@ -28,10 +28,12 @@ impl PriceInfo {
pub fn get() -> Option<PriceInfo> {
let mut body = String::new();
// TODO: Handle each error type properly
Client::new()
.get("http://api.etherscan.io/api?module=stats&action=ethprice")
let mut client = Client::new();
client.set_read_timeout(Some(::std::time::Duration::from_secs(3)));
client.get("http://api.etherscan.io/api?module=stats&action=ethprice")
.header(Connection::close())
.send().ok()
.send()
.ok()
.and_then(|mut s| s.read_to_string(&mut body).ok())
.and_then(|_| Json::from_str(&body).ok())
.and_then(|json| json.find_path(&["result", "ethusd"])

View File

@ -23,7 +23,7 @@ ethcore-devtools = { path = "../devtools" }
rustc-serialize = "0.3"
transient-hashmap = "0.1"
serde_macros = { version = "0.7.0", optional = true }
clippy = { version = "0.0.77", optional = true}
clippy = { version = "0.0.78", optional = true}
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" }
ethcore-ipc = { path = "../ipc/rpc" }

View File

@ -42,6 +42,7 @@ use v1::traits::Eth;
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, OptionalValue, Index, Filter, Log, Receipt};
use v1::impls::{default_gas_price, dispatch_transaction, error_codes};
use serde;
use ethcore::header::Header as BlockHeader;
/// Eth rpc implementation.
pub struct EthClient<C, S, M, EM> where

View File

@ -20,7 +20,7 @@ ethcore-util = { path = "../util" }
ethcore-rpc = { path = "../rpc" }
parity-minimal-sysui = { git = "https://github.com/ethcore/parity-dapps-minimal-sysui-rs.git", version = "0.2.0" }
clippy = { version = "0.0.77", optional = true}
clippy = { version = "0.0.78", optional = true}
[features]
dev = ["clippy"]

View File

@ -10,7 +10,7 @@ authors = ["Ethcore <admin@ethcore.io"]
[dependencies]
ethcore-util = { path = "../util" }
ethcore = { path = "../ethcore" }
clippy = { version = "0.0.77", optional = true}
clippy = { version = "0.0.78", optional = true}
log = "0.3"
env_logger = "0.3"
time = "0.1.34"

View File

@ -28,7 +28,7 @@ crossbeam = "0.2"
slab = "0.2"
sha3 = { path = "sha3" }
serde = "0.7.0"
clippy = { version = "0.0.77", optional = true}
clippy = { version = "0.0.78", optional = true}
json-tests = { path = "json-tests" }
igd = "0.4.2"
ethcore-devtools = { path = "../devtools" }

View File

@ -43,7 +43,7 @@ use std::cmp;
use std::str::{FromStr};
use std::convert::From;
use std::hash::{Hash, Hasher};
use std::hash::Hash;
use std::ops::*;
use std::cmp::*;
@ -1031,7 +1031,7 @@ macro_rules! construct_uint {
// shift
for i in word_shift..$n_words {
ret[i] += original[i - word_shift] << bit_shift;
ret[i] = original[i - word_shift] << bit_shift;
}
// carry
if bit_shift > 0 {
@ -1052,14 +1052,18 @@ macro_rules! construct_uint {
let word_shift = shift / 64;
let bit_shift = shift % 64;
// shift
for i in word_shift..$n_words {
// Shift
ret[i - word_shift] += original[i] >> bit_shift;
// Carry
if bit_shift > 0 && i < $n_words - 1 {
ret[i - word_shift] += original[i + 1] << (64 - bit_shift);
ret[i - word_shift] = original[i] >> bit_shift;
}
// Carry
if bit_shift > 0 {
for i in word_shift+1..$n_words {
ret[i - word_shift - 1] += original[i] << (64 - bit_shift);
}
}
$name(ret)
}
}

View File

@ -101,7 +101,7 @@ impl<T: fmt::Debug + fmt::Display> fmt::Display for Mismatch<T> {
}
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
/// Error indicating value found is outside of a valid range.
pub struct OutOfBounds<T: fmt::Debug> {
/// Minimum allowed value.

View File

@ -104,6 +104,21 @@ pub trait HashDB: AsHashDB {
/// }
/// ```
fn remove(&mut self, key: &H256);
/// Insert auxiliary data into hashdb.
fn insert_aux(&mut self, _hash: Vec<u8>, _value: Vec<u8>) {
unimplemented!();
}
/// Get auxiliary data from hashdb.
fn get_aux(&self, _hash: &[u8]) -> Option<Vec<u8>> {
unimplemented!();
}
/// Removes auxiliary data from hashdb.
fn remove_aux(&mut self, _hash: &[u8]) {
unimplemented!();
}
}
/// Upcast trait.

View File

@ -26,6 +26,13 @@ use kvdb::{Database, DBTransaction, DatabaseConfig};
#[cfg(test)]
use std::env;
/// Suffix appended to auxiliary keys to distinguish them from normal keys.
/// Would be nich to use rocksdb columns for this eventually.
const AUX_FLAG: u8 = 255;
/// Database version.
const DB_VERSION : u32 = 0x103;
/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay
/// and latent-removal semantics.
///
@ -39,8 +46,6 @@ pub struct ArchiveDB {
latest_era: Option<u64>,
}
const DB_VERSION : u32 = 0x103;
impl ArchiveDB {
/// Create a new instance from file
pub fn new(path: &str, config: DatabaseConfig) -> ArchiveDB {
@ -115,12 +120,35 @@ impl HashDB for ArchiveDB {
fn insert(&mut self, value: &[u8]) -> H256 {
self.overlay.insert(value)
}
fn emplace(&mut self, key: H256, value: Bytes) {
self.overlay.emplace(key, value);
}
fn remove(&mut self, key: &H256) {
self.overlay.remove(key);
}
fn insert_aux(&mut self, hash: Vec<u8>, value: Vec<u8>) {
self.overlay.insert_aux(hash, value);
}
fn get_aux(&self, hash: &[u8]) -> Option<Vec<u8>> {
if let Some(res) = self.overlay.get_aux(hash) {
return Some(res)
}
let mut db_hash = hash.to_vec();
db_hash.push(AUX_FLAG);
self.backing.get(&db_hash)
.expect("Low-level database error. Some issue with your hard disk?")
.map(|v| v.to_vec())
}
fn remove_aux(&mut self, hash: &[u8]) {
self.overlay.remove_aux(hash);
}
}
impl JournalDB for ArchiveDB {
@ -144,6 +172,7 @@ impl JournalDB for ArchiveDB {
let batch = DBTransaction::new();
let mut inserts = 0usize;
let mut deletes = 0usize;
for i in self.overlay.drain().into_iter() {
let (key, (value, rc)) = i;
if rc > 0 {
@ -156,6 +185,12 @@ impl JournalDB for ArchiveDB {
deletes += 1;
}
}
for (mut key, value) in self.overlay.drain_aux().into_iter() {
key.push(AUX_FLAG);
batch.put(&key, &value).expect("Low-level database error. Some issue with your hard disk?");
}
if self.latest_era.map_or(true, |e| now > e) {
try!(batch.put(&LATEST_ERA_KEY, &encode(&now)));
self.latest_era = Some(now);

View File

@ -74,6 +74,7 @@ use std::default::Default;
pub struct MemoryDB {
data: HashMap<H256, (Bytes, i32)>,
static_null_rlp: (Bytes, i32),
aux: HashMap<Bytes, Bytes>,
}
impl Default for MemoryDB {
@ -88,6 +89,7 @@ impl MemoryDB {
MemoryDB {
data: HashMap::new(),
static_null_rlp: (vec![0x80u8; 1], 1),
aux: HashMap::new(),
}
}
@ -134,9 +136,12 @@ impl MemoryDB {
/// Return the internal map of hashes to data, clearing the current state.
pub fn drain(&mut self) -> HashMap<H256, (Bytes, i32)> {
let mut data = HashMap::new();
mem::swap(&mut self.data, &mut data);
data
mem::replace(&mut self.data, HashMap::new())
}
/// Return the internal map of auxiliary data, clearing the current state.
pub fn drain_aux(&mut self) -> HashMap<Bytes, Bytes> {
mem::replace(&mut self.aux, HashMap::new())
}
/// Denote than an existing value has the given key. Used when a key gets removed without
@ -233,6 +238,18 @@ impl HashDB for MemoryDB {
self.data.insert(key.clone(), (Bytes::new(), -1));
}
}
fn insert_aux(&mut self, hash: Vec<u8>, value: Vec<u8>) {
self.aux.insert(hash, value);
}
fn get_aux(&self, hash: &[u8]) -> Option<Vec<u8>> {
self.aux.get(hash).cloned()
}
fn remove_aux(&mut self, hash: &[u8]) {
self.aux.remove(hash);
}
}
#[test]

View File

@ -539,7 +539,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
self.info.write().unwrap().public_endpoint = Some(public_endpoint.clone());
if self.first_time.load(AtomicOrdering::Relaxed) {
info!("Public node URL: {}", paint(White.bold(), format!("{}", self.external_url().unwrap())));
info!("Public node URL: {}", paint(White.bold(), self.external_url().unwrap()));
self.first_time.store(false, AtomicOrdering::Relaxed);
}

113
util/src/trie/fatdb.rs Normal file
View File

@ -0,0 +1,113 @@
// 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 <http://www.gnu.org/licenses/>.
use hash::H256;
use sha3::Hashable;
use hashdb::HashDB;
use super::{TrieDB, Trie, TrieDBIterator, TrieError};
use trie::trietraits::TrieItem;
/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
/// Additionaly it stores inserted hash-key mappings for later retrieval.
///
/// Use it as a `Trie` or `TrieMut` trait object.
pub struct FatDB<'db> {
raw: TrieDB<'db>,
}
impl<'db> FatDB<'db> {
/// Create a new trie with the backing database `db` and empty `root`
/// Initialise to the state entailed by the genesis block.
/// This guarantees the trie is built correctly.
pub fn new(db: &'db HashDB, root: &'db H256) -> Result<Self, TrieError> {
let fatdb = FatDB {
raw: try!(TrieDB::new(db, root))
};
Ok(fatdb)
}
/// Get the backing database.
pub fn db(&self) -> &HashDB {
self.raw.db()
}
/// Iterator over all key / vlaues in the trie.
pub fn iter(&self) -> FatDBIterator {
FatDBIterator::new(&self.raw)
}
}
impl<'db> Trie for FatDB<'db> {
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
Box::new(FatDB::iter(self))
}
fn root(&self) -> &H256 {
self.raw.root()
}
fn contains(&self, key: &[u8]) -> bool {
self.raw.contains(&key.sha3())
}
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.raw.get(&key.sha3())
}
}
/// Itarator over inserted pairs of key values.
pub struct FatDBIterator<'db> {
trie_iterator: TrieDBIterator<'db>,
trie: &'db TrieDB<'db>,
}
impl<'db> FatDBIterator<'db> {
/// Creates new iterator.
pub fn new(trie: &'db TrieDB) -> Self {
FatDBIterator {
trie_iterator: TrieDBIterator::new(trie),
trie: trie,
}
}
}
impl<'db> Iterator for FatDBIterator<'db> {
type Item = (Vec<u8>, &'db [u8]);
fn next(&mut self) -> Option<Self::Item> {
self.trie_iterator.next()
.map(|(hash, value)| {
(self.trie.db().get_aux(&hash).expect("Missing fatdb hash"), value)
})
}
}
#[test]
fn fatdb_to_trie() {
use memorydb::MemoryDB;
use trie::{FatDBMut, TrieMut};
let mut memdb = MemoryDB::new();
let mut root = H256::default();
{
let mut t = FatDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
}
let t = FatDB::new(&memdb, &root).unwrap();
assert_eq!(t.get(&[0x01u8, 0x23]).unwrap(), &[0x01u8, 0x23]);
assert_eq!(t.iter().collect::<Vec<_>>(), vec![(vec![0x01u8, 0x23], &[0x01u8, 0x23] as &[u8])]);
}

95
util/src/trie/fatdbmut.rs Normal file
View File

@ -0,0 +1,95 @@
// 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 <http://www.gnu.org/licenses/>.
use hash::H256;
use sha3::Hashable;
use hashdb::HashDB;
use super::{TrieDBMut, TrieMut, TrieError};
/// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
/// Additionaly it stores inserted hash-key mappings for later retrieval.
///
/// Use it as a `Trie` or `TrieMut` trait object.
pub struct FatDBMut<'db> {
raw: TrieDBMut<'db>,
}
impl<'db> FatDBMut<'db> {
/// Create a new trie with the backing database `db` and empty `root`
/// Initialise to the state entailed by the genesis block.
/// This guarantees the trie is built correctly.
pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self {
FatDBMut { raw: TrieDBMut::new(db, root) }
}
/// Create a new trie with the backing database `db` and `root`.
///
/// Returns an error if root does not exist.
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Result<Self, TrieError> {
Ok(FatDBMut { raw: try!(TrieDBMut::from_existing(db, root)) })
}
/// Get the backing database.
pub fn db(&self) -> &HashDB {
self.raw.db()
}
/// Get the backing database.
pub fn db_mut(&mut self) -> &mut HashDB {
self.raw.db_mut()
}
}
impl<'db> TrieMut for FatDBMut<'db> {
fn root(&self) -> &H256 {
self.raw.root()
}
fn contains(&self, key: &[u8]) -> bool {
self.raw.contains(&key.sha3())
}
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.raw.get(&key.sha3())
}
fn insert(&mut self, key: &[u8], value: &[u8]) {
let hash = key.sha3();
self.raw.insert(&hash, value);
let db = self.raw.db_mut();
db.insert_aux(hash.to_vec(), key.to_vec());
}
fn remove(&mut self, key: &[u8]) {
self.raw.remove(&key.sha3());
}
}
#[test]
fn fatdb_to_trie() {
use memorydb::MemoryDB;
use super::TrieDB;
use super::Trie;
let mut memdb = MemoryDB::new();
let mut root = H256::default();
{
let mut t = FatDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
}
let t = TrieDB::new(&memdb, &root).unwrap();
assert_eq!(t.get(&(&[0x01u8, 0x23]).sha3()).unwrap(), &[0x01u8, 0x23]);
}

View File

@ -17,6 +17,8 @@
//! Trie interface and implementation.
use std::fmt;
use hash::H256;
use hashdb::HashDB;
/// Export the trietraits module.
pub mod trietraits;
@ -35,12 +37,18 @@ pub mod sectriedb;
/// Export the sectriedbmut module.
pub mod sectriedbmut;
mod fatdb;
mod fatdbmut;
pub use self::trietraits::{Trie, TrieMut};
pub use self::standardmap::{Alphabet, StandardMap, ValueMode};
pub use self::triedbmut::TrieDBMut;
pub use self::triedb::TrieDB;
pub use self::triedb::{TrieDB, TrieDBIterator};
pub use self::sectriedbmut::SecTrieDBMut;
pub use self::sectriedb::SecTrieDB;
pub use self::fatdb::{FatDB, FatDBIterator};
pub use self::fatdbmut::FatDBMut;
/// Trie Errors
#[derive(Debug)]
@ -54,3 +62,63 @@ impl fmt::Display for TrieError {
write!(f, "Trie Error: Invalid state root.")
}
}
/// Trie types
#[derive(Debug, Clone)]
pub enum TrieSpec {
/// Generic trie.
Generic,
/// Secure trie.
Secure,
/// Secure trie with fat database.
Fat,
}
impl Default for TrieSpec {
fn default() -> TrieSpec {
TrieSpec::Secure
}
}
/// Trie factory.
#[derive(Default, Clone)]
pub struct TrieFactory {
spec: TrieSpec,
}
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
impl TrieFactory {
/// Creates new factory.
pub fn new(spec: TrieSpec) -> Self {
TrieFactory {
spec: spec,
}
}
/// Create new immutable instance of Trie.
pub fn readonly<'db>(&self, db: &'db HashDB, root: &'db H256) -> Result<Box<Trie + 'db>, TrieError> {
match self.spec {
TrieSpec::Generic => Ok(Box::new(try!(TrieDB::new(db, root)))),
TrieSpec::Secure => Ok(Box::new(try!(SecTrieDB::new(db, root)))),
TrieSpec::Fat => Ok(Box::new(try!(FatDB::new(db, root)))),
}
}
/// Create new mutable instance of Trie.
pub fn create<'db>(&self, db: &'db mut HashDB, root: &'db mut H256) -> Box<TrieMut + 'db> {
match self.spec {
TrieSpec::Generic => Box::new(TrieDBMut::new(db, root)),
TrieSpec::Secure => Box::new(SecTrieDBMut::new(db, root)),
TrieSpec::Fat => Box::new(FatDBMut::new(db, root)),
}
}
/// Create new mutable instance of trie and check for errors.
pub fn from_existing<'db>(&self, db: &'db mut HashDB, root: &'db mut H256) -> Result<Box<TrieMut + 'db>, TrieError> {
match self.spec {
TrieSpec::Generic => Ok(Box::new(try!(TrieDBMut::from_existing(db, root)))),
TrieSpec::Secure => Ok(Box::new(try!(SecTrieDBMut::from_existing(db, root)))),
TrieSpec::Fat => Ok(Box::new(try!(FatDBMut::from_existing(db, root)))),
}
}
}

View File

@ -14,11 +14,11 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use hash::*;
use sha3::*;
use hash::H256;
use sha3::Hashable;
use hashdb::HashDB;
use super::triedb::TrieDB;
use super::trietraits::Trie;
use super::trietraits::{Trie, TrieItem};
use super::TrieError;
/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
@ -50,6 +50,10 @@ impl<'db> SecTrieDB<'db> {
}
impl<'db> Trie for SecTrieDB<'db> {
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
Box::new(TrieDB::iter(&self.raw))
}
fn root(&self) -> &H256 { self.raw.root() }
fn contains(&self, key: &[u8]) -> bool {
@ -68,7 +72,7 @@ fn trie_to_sectrie() {
use super::trietraits::TrieMut;
let mut memdb = MemoryDB::new();
let mut root = H256::new();
let mut root = H256::default();
{
let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&(&[0x01u8, 0x23]).sha3(), &[0x01u8, 0x23]);

View File

@ -14,11 +14,11 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use hash::*;
use sha3::*;
use hash::H256;
use sha3::Hashable;
use hashdb::HashDB;
use super::triedbmut::TrieDBMut;
use super::trietraits::{Trie, TrieMut};
use super::trietraits::TrieMut;
use super::TrieError;
/// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
@ -44,13 +44,13 @@ impl<'db> SecTrieDBMut<'db> {
}
/// Get the backing database.
pub fn db(&'db self) -> &'db HashDB { self.raw.db() }
pub fn db(&self) -> &HashDB { self.raw.db() }
/// Get the backing database.
pub fn db_mut(&'db mut self) -> &'db mut HashDB { self.raw.db_mut() }
pub fn db_mut(&mut self) -> &mut HashDB { self.raw.db_mut() }
}
impl<'db> Trie for SecTrieDBMut<'db> {
impl<'db> TrieMut for SecTrieDBMut<'db> {
fn root(&self) -> &H256 { self.raw.root() }
fn contains(&self, key: &[u8]) -> bool {
@ -60,9 +60,7 @@ impl<'db> Trie for SecTrieDBMut<'db> {
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.raw.get(&key.sha3())
}
}
impl<'db> TrieMut for SecTrieDBMut<'db> {
fn insert(&mut self, key: &[u8], value: &[u8]) {
self.raw.insert(&key.sha3(), value);
}
@ -76,9 +74,10 @@ impl<'db> TrieMut for SecTrieDBMut<'db> {
fn sectrie_to_trie() {
use memorydb::*;
use super::triedb::*;
use super::Trie;
let mut memdb = MemoryDB::new();
let mut root = H256::new();
let mut root = H256::default();
{
let mut t = SecTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);

View File

@ -18,7 +18,7 @@ use common::*;
use hashdb::*;
use nibbleslice::*;
use rlp::*;
use super::trietraits::Trie;
use super::trietraits::{Trie, TrieItem};
use super::node::Node;
use super::TrieError;
@ -257,7 +257,7 @@ pub struct TrieDBIterator<'a> {
impl<'a> TrieDBIterator<'a> {
/// Create a new iterator.
fn new(db: &'a TrieDB) -> TrieDBIterator<'a> {
pub fn new(db: &'a TrieDB) -> TrieDBIterator<'a> {
let mut r = TrieDBIterator {
db: db,
trail: vec![],
@ -331,10 +331,16 @@ impl<'a> Iterator for TrieDBIterator<'a> {
impl<'db> TrieDB<'db> {
/// Get all keys/values stored in the trie.
pub fn iter(&self) -> TrieDBIterator { TrieDBIterator::new(self) }
pub fn iter(&self) -> TrieDBIterator {
TrieDBIterator::new(self)
}
}
impl<'db> Trie for TrieDB<'db> {
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
Box::new(TrieDB::iter(self))
}
fn root(&self) -> &H256 { &self.root }
fn contains(&self, key: &[u8]) -> bool {

View File

@ -20,7 +20,7 @@ use nibbleslice::*;
use rlp::*;
use super::node::Node;
use super::journal::Journal;
use super::trietraits::{Trie, TrieMut};
use super::trietraits::TrieMut;
use super::TrieError;
/// A `Trie` implementation using a generic `HashDB` backing database.
@ -99,12 +99,12 @@ impl<'db> TrieDBMut<'db> {
}
/// Get the backing database.
pub fn db(&'db self) -> &'db HashDB {
pub fn db(&self) -> &HashDB {
self.db
}
/// Get the backing database.
pub fn db_mut(&'db mut self) -> &'db mut HashDB {
pub fn db_mut(&mut self) -> &mut HashDB {
self.db
}
@ -642,7 +642,7 @@ impl<'db> TrieDBMut<'db> {
}
}
impl<'db> Trie for TrieDBMut<'db> {
impl<'db> TrieMut for TrieDBMut<'db> {
fn root(&self) -> &H256 { &self.root }
fn contains(&self, key: &[u8]) -> bool {
@ -652,9 +652,7 @@ impl<'db> Trie for TrieDBMut<'db> {
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.do_lookup(&NibbleSlice::new(key))
}
}
impl<'db> TrieMut for TrieDBMut<'db> {
fn insert(&mut self, key: &[u8], value: &[u8]) {
match value.is_empty() {
false => self.insert_ns(&NibbleSlice::new(key), value),

View File

@ -17,6 +17,9 @@
use hash::H256;
use rlp::SHA3_NULL_RLP;
/// Trie-Item type.
pub type TrieItem<'a> = (Vec<u8>, &'a[u8]);
/// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait Trie {
/// Return the root of the trie.
@ -30,10 +33,25 @@ pub trait Trie {
/// What is the value of the given key in this trie?
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key;
/// Returns an iterator over elements of trie.
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a>;
}
/// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait TrieMut: Trie {
pub trait TrieMut {
/// Return the root of the trie.
fn root(&self) -> &H256;
/// Is the trie empty?
fn is_empty(&self) -> bool { *self.root() == SHA3_NULL_RLP }
/// Does the trie contain a given key?
fn contains(&self, key: &[u8]) -> bool;
/// What is the value of the given key in this trie?
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key;
/// Insert a `key`/`value` pair into the trie. An `empty` value is equivalent to removing
/// `key` from the trie.
fn insert(&mut self, key: &[u8], value: &[u8]);
@ -42,4 +60,3 @@ pub trait TrieMut: Trie {
/// value.
fn remove(&mut self, key: &[u8]);
}