Merge branch 'master' into client-ipc-refact
This commit is contained in:
commit
b873d3befb
@ -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
28
Cargo.lock
generated
@ -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)",
|
||||
]
|
||||
|
@ -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" }
|
||||
|
@ -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.
|
||||
|
@ -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 }
|
||||
|
@ -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" }
|
||||
|
@ -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 && \
|
||||
|
@ -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'\
|
||||
|
@ -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'\
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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" }
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -18,3 +18,4 @@
|
||||
|
||||
#![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues
|
||||
include!(concat!(env!("OUT_DIR"), "/client.ipc.rs"));
|
||||
|
||||
|
@ -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"),
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
|
@ -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) {
|
||||
|
@ -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};
|
||||
|
@ -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() {
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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;
|
||||
|
52
ethcore/src/types/transaction_import.rs
Normal file
52
ethcore/src/types/transaction_import.rs
Normal 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)),
|
||||
}
|
||||
}
|
||||
}
|
@ -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> {
|
||||
|
@ -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 }
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -16,5 +16,5 @@ ethcore-ipc-nano = { path = "../nano" }
|
||||
ethcore-util = { path = "../../util" }
|
||||
|
||||
[build-dependencies]
|
||||
syntex = "*"
|
||||
syntex = "0.33"
|
||||
ethcore-ipc-codegen = { path = "../codegen" }
|
||||
|
@ -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");
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -28,3 +28,4 @@ mod examples;
|
||||
mod over_nano;
|
||||
mod nested;
|
||||
mod binary;
|
||||
mod with_attrs;
|
||||
|
@ -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
18
ipc/tests/with_attrs.rs
Normal 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"));
|
@ -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 {}
|
@ -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 }
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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!");
|
||||
|
@ -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"])
|
||||
|
@ -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" }
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"]
|
||||
|
@ -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"
|
||||
|
@ -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" }
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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]
|
||||
|
@ -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
113
util/src/trie/fatdb.rs
Normal 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
95
util/src/trie/fatdbmut.rs
Normal 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]);
|
||||
}
|
@ -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)))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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]);
|
||||
|
@ -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]);
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user