Fetch parity-common crates from crates.io (#9410)

* Fetch `parity-common` crates from crates.io

* Add doc tests from `patricia-trie` to `patricia-trie-ethereum`
Fix/update a few deps

* [ethkey] upgrade ethereum-types

* [whisper] update deps

* [network] deps

* [network-devp2p] deps

* [journaldb] deps

* [fastmap] deps

* [miner] deps and test fixes

* [machine] deps

* [json] deps

* [hw] deps

* [ethash] deps

* [registrar] deps

* Update a few more dependencies with new ethabi-*

* [updater] Update deps

* deps

* [ethcore] Update deps

* Use new parity-snappy and parity-rocksdb crates

* Updated submodules

* Use parity-snappy 0.1

* Use kvdb-rocksdb 0.1.2

* Don't use latest ethereum/tests

* Fix merge conflicts errors

* Remove superseeded comment

* Address grumbles: add newlines, add/remove spaces
This commit is contained in:
David
2018-09-04 20:13:51 +02:00
committed by GitHub
parent 51eac1926f
commit 72fd1fa58d
91 changed files with 1547 additions and 3719 deletions

2302
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -33,7 +33,7 @@ fdlimit = "0.1"
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
ethcore = { path = "ethcore", features = ["parity"] }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
ethcore-io = { path = "util/io" }
ethcore-light = { path = "ethcore/light" }
ethcore-logger = { path = "logger" }
@@ -43,10 +43,10 @@ ethcore-private-tx = { path = "ethcore/private-tx" }
ethcore-service = { path = "ethcore/service" }
ethcore-sync = { path = "ethcore/sync" }
ethcore-transaction = { path = "ethcore/transaction" }
ethereum-types = "0.3"
ethereum-types = "0.4"
node-filter = { path = "ethcore/node_filter" }
ethkey = { path = "ethkey" }
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
rpc-cli = { path = "rpc_cli" }
parity-hash-fetch = { path = "hash-fetch" }
parity-ipfs-api = { path = "ipfs" }
@@ -57,12 +57,12 @@ parity-rpc-client = { path = "rpc_client" }
parity-updater = { path = "updater" }
parity-version = { path = "util/version" }
parity-whisper = { path = "whisper" }
path = { git = "https://github.com/paritytech/parity-common" }
parity-path = "0.1"
dir = { path = "util/dir" }
panic_hook = { path = "util/panic_hook" }
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1"
migration-rocksdb = { path = "util/migration-rocksdb" }
kvdb = "0.1.0"
kvdb = "0.1"
kvdb-rocksdb = "0.1.3"
journaldb = { path = "util/journaldb" }
mem = { path = "util/mem" }
@@ -130,7 +130,6 @@ members = [
"evmbin",
"miner",
"parity-clib",
"transaction-pool",
"whisper",
"whisper/cli",
"util/triehash-ethereum",

View File

@@ -6,8 +6,8 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
crunchy = "0.1.0"
either = "1.0.0"
ethereum-types = "0.3"
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.4"
keccak-hash = "0.1"
log = "0.4"
memmap = "0.6"
parking_lot = "0.6"

View File

@@ -15,23 +15,23 @@ common-types = { path = "types" }
crossbeam = "0.3"
ethash = { path = "../ethash" }
ethcore-bloom-journal = { path = "../util/bloom" }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
hashdb = { git = "https://github.com/paritytech/parity-common" }
memorydb = { git = "https://github.com/paritytech/parity-common" }
patricia-trie = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
hashdb = "0.2.1"
memorydb = "0.2.1"
patricia-trie = "0.2.1"
patricia-trie-ethereum = { path = "../util/patricia-trie-ethereum" }
parity-crypto = { git = "https://github.com/paritytech/parity-common" }
parity-crypto = "0.1"
error-chain = { version = "0.12", default-features = false }
ethcore-io = { path = "../util/io" }
ethcore-logger = { path = "../logger" }
ethcore-miner = { path = "../miner" }
ethcore-stratum = { path = "./stratum", optional = true }
ethcore-transaction = { path = "./transaction" }
ethereum-types = "0.3"
ethereum-types = "0.4"
memory-cache = { path = "../util/memory_cache" }
ethabi = "5.1"
ethabi-derive = "5.0"
ethabi-contract = "5.0"
ethabi = "5.1.2"
ethabi-derive = "5.1.3"
ethabi-contract = "5.1.1"
ethjson = { path = "../json" }
ethkey = { path = "../ethkey" }
ethstore = { path = "../ethstore" }
@@ -47,21 +47,21 @@ parity-machine = { path = "../machine" }
parking_lot = "0.6"
rayon = "1.0"
rand = "0.4"
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
rlp_compress = { path = "../util/rlp_compress" }
rlp_derive = { path = "../util/rlp_derive" }
kvdb = "0.1.0"
kvdb-memorydb = "0.1.0"
parity-snappy = "0.1.0"
kvdb = "0.1"
kvdb-memorydb = "0.1"
parity-snappy = "0.1"
stop-guard = { path = "../util/stop-guard" }
macros = { path = "../util/macros" }
rustc-hex = "1.0"
stats = { path = "../util/stats" }
trace-time = { path = "../util/trace-time" }
trace-time = "0.1"
using_queue = { path = "../util/using_queue" }
vm = { path = "vm" }
wasm = { path = "wasm" }
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1"
triehash-ethereum = { version = "0.2", path = "../util/triehash-ethereum" }
unexpected = { path = "../util/unexpected" }
journaldb = { path = "../util/journaldb" }
@@ -77,7 +77,7 @@ fake-hardware-wallet = { path = "../util/fake-hardware-wallet" }
[dev-dependencies]
tempdir = "0.3"
trie-standardmap = { git = "https://github.com/paritytech/parity-common" }
trie-standardmap = "0.1"
[features]
parity = ["work-notify", "price-info", "stratum"]

View File

@@ -5,13 +5,13 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
bit-set = "0.4"
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.3"
parity-bytes = "0.1"
ethereum-types = "0.4"
heapsize = "0.4"
lazy_static = "1.0"
log = "0.4"
vm = { path = "../vm" }
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1"
parking_lot = "0.6"
memory-cache = { path = "../../util/memory_cache" }

View File

@@ -795,7 +795,7 @@ impl<Cost: CostType> Interpreter<Cost> {
TWO_POW_96 => a >> 96,
TWO_POW_224 => a >> 224,
TWO_POW_248 => a >> 248,
_ => a.overflowing_div(b).0,
_ => a / b,
}
} else {
U256::zero()
@@ -805,7 +805,7 @@ impl<Cost: CostType> Interpreter<Cost> {
let a = self.stack.pop_back();
let b = self.stack.pop_back();
self.stack.push(if !b.is_zero() {
a.overflowing_rem(b).0
a % b
} else {
U256::zero()
});
@@ -821,7 +821,7 @@ impl<Cost: CostType> Interpreter<Cost> {
} else if a == min && b == !U256::zero() {
min
} else {
let c = a.overflowing_div(b).0;
let c = a / b;
set_sign(c, sign_a ^ sign_b)
});
},
@@ -832,7 +832,7 @@ impl<Cost: CostType> Interpreter<Cost> {
let b = get_and_reset_sign(ub).0;
self.stack.push(if !b.is_zero() {
let c = a.overflowing_rem(b).0;
let c = a % b;
set_sign(c, sign_a)
} else {
U256::zero()
@@ -920,7 +920,7 @@ impl<Cost: CostType> Interpreter<Cost> {
// upcast to 512
let a5 = U512::from(a);
let res = a5.overflowing_add(U512::from(b)).0;
let x = res.overflowing_rem(U512::from(c)).0;
let x = res % U512::from(c);
U256::from(x)
} else {
U256::zero()
@@ -934,7 +934,7 @@ impl<Cost: CostType> Interpreter<Cost> {
self.stack.push(if !c.is_zero() {
let a5 = U512::from(a);
let res = a5.overflowing_mul(U512::from(b)).0;
let x = res.overflowing_rem(U512::from(c)).0;
let x = res % U512::from(c);
U256::from(x)
} else {
U256::zero()

View File

@@ -9,19 +9,19 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
log = "0.4"
ethcore = { path = ".."}
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
ethcore-transaction = { path = "../transaction" }
ethereum-types = "0.3"
memorydb = { git = "https://github.com/paritytech/parity-common" }
patricia-trie = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.4"
memorydb = "0.2.1"
patricia-trie = "0.2.1"
patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" }
ethcore-network = { path = "../../util/network" }
ethcore-io = { path = "../../util/io" }
hashdb = { git = "https://github.com/paritytech/parity-common" }
hashdb = "0.2.1"
heapsize = "0.4"
vm = { path = "../vm" }
fastmap = { path = "../../util/fastmap" }
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
rlp_derive = { path = "../../util/rlp_derive" }
smallvec = "0.4"
futures = "0.1"
@@ -32,16 +32,16 @@ serde = "1.0"
serde_derive = "1.0"
parking_lot = "0.6"
stats = { path = "../../util/stats" }
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1"
keccak-hasher = { path = "../../util/keccak-hasher" }
triehash-ethereum = { version = "0.2", path = "../../util/triehash-ethereum" }
kvdb = "0.1.0"
kvdb = "0.1"
memory-cache = { path = "../../util/memory_cache" }
error-chain = { version = "0.12", default-features = false }
[dev-dependencies]
ethcore = { path = "..", features = ["test-helpers"] }
kvdb-memorydb = "0.1.0"
kvdb-memorydb = "0.1"
tempdir = "0.3"
[features]

View File

@@ -95,7 +95,7 @@ impl AccountTransactions {
}
fn next_nonce(&self) -> U256 {
self.current.last().map(|last| last.nonce + 1.into())
self.current.last().map(|last| last.nonce + 1)
.unwrap_or_else(|| *self.cur_nonce.value())
}
@@ -113,7 +113,7 @@ impl AccountTransactions {
None => break,
}
next_nonce = next_nonce + 1.into();
next_nonce = next_nonce + 1;
}
promoted
@@ -196,7 +196,7 @@ impl TransactionQueue {
}
Err(idx) => {
let cur_len = acct_txs.current.len();
let incr_nonce = nonce + 1.into();
let incr_nonce = nonce + 1;
// current is sorted with one tx per nonce,
// so if a tx with given nonce wasn't found that means it is either
@@ -215,7 +215,7 @@ impl TransactionQueue {
}
(ImportDestination::Current, vec![hash])
} else if idx == cur_len && acct_txs.current.last().map_or(false, |f| f.nonce + 1.into() != nonce) {
} else if idx == cur_len && acct_txs.current.last().map_or(false, |f| f.nonce + 1 != nonce) {
trace!(target: "txqueue", "Queued future transaction for {}, nonce={}", sender, nonce);
let future_nonce = nonce;
acct_txs.future.insert(future_nonce, tx_info);
@@ -535,7 +535,7 @@ mod tests {
let tx_b: PendingTransaction = Transaction::default().fake_sign(sender).into();
let tx_a: PendingTransaction = {
let mut tx_a = Transaction::default();
tx_a.gas_price = tx_b.gas_price + 1.into();
tx_a.gas_price = tx_b.gas_price + 1;
tx_a.fake_sign(sender).into()
};

View File

@@ -10,16 +10,16 @@ authors = ["Parity Technologies <admin@parity.io>"]
ethcore = { path = ".."}
ethcore-network = { path = "../../util/network" }
ethcore-network-devp2p = { path = "../../util/network-devp2p" }
ethereum-types = "0.3"
ethereum-types = "0.4"
log = "0.4"
parking_lot = "0.6"
ethabi = "5.1"
ethabi-derive = "5.0"
ethabi-contract = "5.0"
ethabi = "5.1.2"
ethabi-derive = "5.1.3"
ethabi-contract = "5.1.1"
lru-cache = "0.1"
[dev-dependencies]
ethcore = { path = "..", features = ["test-helpers"] }
kvdb-memorydb = "0.1.0"
kvdb-memorydb = "0.1"
ethcore-io = { path = "../../util/io" }
tempdir = "0.3"

View File

@@ -7,36 +7,36 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
error-chain = { version = "0.12", default-features = false }
ethabi = "5.1"
ethabi-contract = "5.0"
ethabi-derive = "5.0"
ethabi = "5.1.2"
ethabi-derive = "5.1.3"
ethabi-contract = "5.1.1"
ethcore = { path = ".." }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
parity-crypto = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
parity-crypto = "0.1"
ethcore-io = { path = "../../util/io" }
ethcore-logger = { path = "../../logger" }
ethcore-miner = { path = "../../miner" }
ethcore-transaction = { path = "../transaction" }
ethereum-types = "0.3"
ethereum-types = "0.4"
ethjson = { path = "../../json" }
ethkey = { path = "../../ethkey" }
fetch = { path = "../../util/fetch" }
futures = "0.1"
heapsize = "0.4"
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1.2"
log = "0.4"
parking_lot = "0.6"
patricia-trie = { git = "https://github.com/paritytech/parity-common" }
patricia-trie = "0.2.1"
patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" }
rand = "0.3"
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
rlp_derive = { path = "../../util/rlp_derive" }
rustc-hex = "1.0"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
tiny-keccak = "1.4"
transaction-pool = { path = "../../transaction-pool" }
transaction-pool = "1.13.2"
url = "1"
[dev-dependencies]

View File

@@ -10,11 +10,11 @@ ethcore = { path = ".." }
ethcore-io = { path = "../../util/io" }
ethcore-private-tx = { path = "../private-tx" }
ethcore-sync = { path = "../sync" }
ethereum-types = "0.3"
kvdb = "0.1.0"
ethereum-types = "0.4"
kvdb = "0.1"
log = "0.4"
stop-guard = { path = "../../util/stop-guard" }
trace-time = { path = "../../util/trace-time" }
trace-time = "0.1"
[dev-dependencies]
ethcore = { path = "..", features = ["test-helpers"] }

View File

@@ -1508,7 +1508,7 @@ impl Call for Client {
where F: FnMut(U256) -> Result<bool, E>
{
while upper - lower > 1.into() {
let mid = (lower + upper) / 2.into();
let mid = (lower + upper) / 2;
trace!(target: "estimate_gas", "{} .. {} .. {}", lower, mid, upper);
let c = cond(mid)?;
match c {
@@ -2510,7 +2510,7 @@ mod tests {
block_hash: block_hash,
block_number: block_number,
cumulative_gas_used: gas_used,
gas_used: gas_used - 5.into(),
gas_used: gas_used - 5,
contract_address: None,
logs: vec![LocalizedLogEntry {
entry: logs[0].clone(),

View File

@@ -1919,7 +1919,7 @@ mod tests {
let b2 = b2.close_and_lock().unwrap();
// the spec sets the block reward to 10
assert_eq!(b2.block().state().balance(&addr1).unwrap(), addr1_balance + (10 * 2).into())
assert_eq!(b2.block().state().balance(&addr1).unwrap(), addr1_balance + (10 * 2))
}
#[test]
@@ -2067,7 +2067,7 @@ mod tests {
// the contract rewards (1000 + kind) for each benefactor/reward kind
assert_eq!(
b2.block().state().balance(&addr1).unwrap(),
addr1_balance + (1000 + 0).into() + (1000 + 2).into(),
addr1_balance + (1000 + 0) + (1000 + 2),
)
}
}

View File

@@ -454,8 +454,8 @@ impl Engine<EthereumMachine> for Tendermint {
fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
// Chain scoring: total weight is sqrt(U256::max_value())*height - view
let new_difficulty = U256::from(U128::max_value())
+ consensus_view(parent).expect("Header has been verified; qed").into()
- self.view.load(AtomicOrdering::SeqCst).into();
+ consensus_view(parent).expect("Header has been verified; qed")
- self.view.load(AtomicOrdering::SeqCst);
header.set_difficulty(new_difficulty);
}

View File

@@ -233,8 +233,8 @@ impl EthereumMachine {
if let Some(ref ethash_params) = self.ethash_extensions {
let gas_limit = {
let bound_divisor = self.params().gas_limit_bound_divisor;
let lower_limit = gas_limit - gas_limit / bound_divisor + 1.into();
let upper_limit = gas_limit + gas_limit / bound_divisor - 1.into();
let lower_limit = gas_limit - gas_limit / bound_divisor + 1;
let upper_limit = gas_limit + gas_limit / bound_divisor - 1;
let gas_limit = if gas_limit < gas_floor_target {
let gas_limit = cmp::min(gas_floor_target, upper_limit);
round_block_gas_limit(gas_limit, lower_limit, upper_limit)
@@ -245,7 +245,7 @@ impl EthereumMachine {
let total_lower_limit = cmp::max(lower_limit, gas_floor_target);
let total_upper_limit = cmp::min(upper_limit, gas_ceil_target);
let gas_limit = cmp::max(gas_floor_target, cmp::min(total_upper_limit,
lower_limit + (header.gas_used().clone() * 6u32 / 5.into()) / bound_divisor));
lower_limit + (header.gas_used().clone() * 6u32 / 5) / bound_divisor));
round_block_gas_limit(gas_limit, total_lower_limit, total_upper_limit)
};
// ensure that we are not violating protocol limits
@@ -265,9 +265,9 @@ impl EthereumMachine {
header.set_gas_limit({
let bound_divisor = self.params().gas_limit_bound_divisor;
if gas_limit < gas_floor_target {
cmp::min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
cmp::min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1)
} else {
cmp::max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into())
cmp::max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1)
}
});
}

View File

@@ -852,11 +852,11 @@ impl miner::MinerService for Miner {
fn sensible_gas_price(&self) -> U256 {
// 10% above our minimum.
self.transaction_queue.current_worst_gas_price() * 110u32 / 100.into()
self.transaction_queue.current_worst_gas_price() * 110u32 / 100
}
fn sensible_gas_limit(&self) -> U256 {
self.params.read().gas_range_target.0 / 5.into()
self.params.read().gas_range_target.0 / 5
}
fn import_external_transactions<C: miner::BlockChainClient>(

View File

@@ -131,7 +131,7 @@ fn make_chain(accounts: Arc<AccountProvider>, blocks_beyond: usize, transitions:
data: Vec::new(),
}.sign(&*RICH_SECRET, client.signing_chain_id());
*nonce = *nonce + 1.into();
*nonce = *nonce + 1;
vec![transaction]
};
@@ -174,7 +174,7 @@ fn make_chain(accounts: Arc<AccountProvider>, blocks_beyond: usize, transitions:
data,
}.sign(&*RICH_SECRET, client.signing_chain_id());
*nonce = *nonce + 1.into();
*nonce = *nonce + 1;
vec![transaction]
} else {
make_useless_transactions()

View File

@@ -672,7 +672,7 @@ mod tests {
header.set_uncles_hash(good_uncles_hash.clone());
check_ok(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
header.set_gas_limit(min_gas_limit - From::from(1));
header.set_gas_limit(min_gas_limit - 1);
check_fail(basic_test(&create_test_block(&header), engine),
InvalidGasLimit(OutOfBounds { min: Some(min_gas_limit), max: None, found: header.gas_limit().clone() }));
@@ -682,7 +682,7 @@ mod tests {
RidiculousNumber(OutOfBounds { max: Some(BlockNumber::max_value()), min: None, found: header.number() }));
header = good.clone();
let gas_used = header.gas_limit().clone() + 1.into();
let gas_used = header.gas_limit().clone() + 1;
header.set_gas_used(gas_used);
check_fail(basic_test(&create_test_block(&header), engine),
TooMuchGasUsed(OutOfBounds { max: Some(header.gas_limit().clone()), min: None, found: header.gas_used().clone() }));

View File

@@ -6,8 +6,8 @@ license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
ethereum-types = "0.3"
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.4"
keccak-hash = "0.1"
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
jsonrpc-tcp-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }

View File

@@ -9,22 +9,22 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
common-types = { path = "../types" }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
ethcore-network = { path = "../../util/network" }
ethcore-network-devp2p = { path = "../../util/network-devp2p" }
ethcore-io = { path = "../../util/io" }
ethcore-light = { path = "../light" }
ethcore-transaction = { path = "../transaction" }
ethcore = { path = ".." }
ethereum-types = "0.3"
hashdb = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.4"
hashdb = "0.2.1"
fastmap = { path = "../../util/fastmap" }
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
rustc-hex = "1.0"
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1"
keccak-hasher = { path = "../../util/keccak-hasher" }
triehash-ethereum = {version = "0.2", path = "../../util/triehash-ethereum" }
kvdb = "0.1.0"
kvdb = "0.1"
macros = { path = "../../util/macros" }
log = "0.4"
env_logger = "0.5"
@@ -33,12 +33,12 @@ heapsize = "0.4"
semver = "0.9"
smallvec = { version = "0.4", features = ["heapsizeof"] }
parking_lot = "0.6"
trace-time = { path = "../../util/trace-time" }
trace-time = "0.1"
ipnetwork = "0.12.6"
[dev-dependencies]
ethcore-io = { path = "../../util/io", features = ["mio"] }
ethkey = { path = "../../ethkey" }
kvdb-memorydb = "0.1.0"
kvdb-memorydb = "0.1"
ethcore-private-tx = { path = "../private-tx" }
ethcore = { path = "..", features = ["test-helpers"] }

View File

@@ -9,10 +9,10 @@ ethjson = { path = "../../json" }
ethkey = { path = "../../ethkey" }
evm = { path = "../evm" }
heapsize = "0.4"
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
rlp = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1"
rlp = { version = "0.2.4", features = ["ethereum"] }
unexpected = { path = "../../util/unexpected" }
ethereum-types = "0.3"
ethereum-types = "0.4"
[dev-dependencies]
rustc-hex= "1.0"

View File

@@ -5,12 +5,12 @@ version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
rlp_derive = { path = "../../util/rlp_derive" }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.3"
parity-bytes = "0.1"
ethereum-types = "0.4"
ethjson = { path = "../../json" }
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1"
heapsize = "0.4"
[dev-dependencies]

View File

@@ -5,12 +5,12 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
byteorder = "1.0"
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.3"
patricia-trie = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
ethereum-types = "0.4"
patricia-trie = "0.2.1"
patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" }
log = "0.4"
common-types = { path = "../types" }
ethjson = { path = "../../json" }
rlp = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
keccak-hash = "0.1"

View File

@@ -5,7 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
byteorder = "1.0"
ethereum-types = "0.3"
ethereum-types = "0.4"
log = "0.4"
parity-wasm = "0.31"
libc = "0.2"

View File

@@ -7,7 +7,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
serde = "1"
serde_json = "1"
serde_derive = "1"
ethereum-types = "0.3"
ethereum-types = "0.4"
ethjson = { path = "../../../json" }
vm = { path = "../../vm" }
wasm = { path = "../" }

View File

@@ -6,9 +6,9 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
byteorder = "1.0"
edit-distance = "2.0"
parity-crypto = { git = "https://github.com/paritytech/parity-common" }
parity-crypto = "0.1"
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
ethereum-types = "0.3"
ethereum-types = "0.4"
lazy_static = "1.0"
log = "0.4"
mem = { path = "../util/mem" }

View File

@@ -16,8 +16,8 @@ tiny-keccak = "1.4"
time = "0.1.34"
itertools = "0.5"
parking_lot = "0.6"
parity-crypto = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.3"
parity-crypto = "0.1"
ethereum-types = "0.4"
dir = { path = "../util/dir" }
smallvec = "0.4"
parity-wordlist = "1.0"

View File

@@ -13,9 +13,9 @@ docopt = "0.8"
env_logger = "0.5"
ethcore = { path = "../ethcore", features = ["test-helpers", "json-tests"] }
ethjson = { path = "../json" }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
ethcore-transaction = { path = "../ethcore/transaction" }
ethereum-types = "0.3"
ethereum-types = "0.4"
evm = { path = "../ethcore/evm" }
panic_hook = { path = "../util/panic_hook" }
rustc-hex = "1.0"

View File

@@ -15,15 +15,15 @@ mime_guess = "2.0.0-alpha.2"
rand = "0.4"
rustc-hex = "1.0"
fetch = { path = "../util/fetch" }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.3"
parity-bytes = "0.1"
ethereum-types = "0.4"
parity-reactor = { path = "../util/reactor" }
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1"
registrar = { path = "../registrar" }
ethabi = "5.1"
ethabi-derive = "5.0"
ethabi-contract = "5.0"
ethabi = "5.1.2"
ethabi-derive = "5.1.3"
ethabi-contract = "5.1.1"
[dev-dependencies]
hyper = "0.11"

View File

@@ -14,7 +14,7 @@ hidapi = { git = "https://github.com/paritytech/hidapi-rs" }
libusb = { git = "https://github.com/paritytech/libusb-rs" }
trezor-sys = { git = "https://github.com/paritytech/trezor-sys" }
ethkey = { path = "../ethkey" }
ethereum-types = "0.3"
ethereum-types = "0.4"
semver = "0.9"
[dev-dependencies]

View File

@@ -7,11 +7,11 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
ethcore = { path = "../ethcore" }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.3"
parity-bytes = "0.1"
ethereum-types = "0.4"
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
cid = "0.2"
multihash = "0.7"
unicase = "2.0"

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
ethereum-types = "0.3"
ethereum-types = "0.4"
rustc-hex = "1.0"
serde = "1.0"
serde_json = "1.0"

View File

@@ -8,9 +8,9 @@ authors = ["Parity Technologies <admin@parity.io>"]
ethcore = { path = "../ethcore" }
ethcore-io = { path = "../util/io" }
ethcore-transaction = { path = "../ethcore/transaction" }
kvdb = "0.1.0"
kvdb = "0.1"
log = "0.4"
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
@@ -18,4 +18,4 @@ serde_json = "1.0"
[dev-dependencies]
ethcore = { path = "../ethcore", features = ["test-helpers"] }
ethkey = { path = "../ethkey" }
kvdb-memorydb = "0.1.0"
kvdb-memorydb = "0.1"

View File

@@ -5,4 +5,4 @@ description = "Generalization of a state machine for consensus engines"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
ethereum-types = "0.3"
ethereum-types = "0.4"

View File

@@ -18,18 +18,18 @@ url = { version = "1", optional = true }
ansi_term = "0.10"
error-chain = "0.12"
ethcore-transaction = { path = "../ethcore/transaction" }
ethereum-types = "0.3"
ethereum-types = "0.4"
futures = "0.1"
futures-cpupool = "0.1"
heapsize = "0.4"
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1"
linked-hash-map = "0.5"
log = "0.4"
parking_lot = "0.6"
price-info = { path = "../price-info", optional = true }
rlp = { git = "https://github.com/paritytech/parity-common" }
trace-time = { path = "../util/trace-time" }
transaction-pool = { path = "../transaction-pool" }
rlp = { version = "0.2.4", features = ["ethereum"] }
trace-time = "0.1"
transaction-pool = "1.13"
[dev-dependencies]
env_logger = "0.5"

View File

@@ -72,7 +72,7 @@ impl fmt::Display for Status {
senders = self.status.senders,
mem = self.status.mem_usage / 1024,
mem_max = self.limits.max_mem_usage / 1024,
gp = self.options.minimal_gas_price / 1_000_000.into(),
gp = self.options.minimal_gas_price / 1_000_000,
max_gas = cmp::min(self.options.block_gas_limit, self.options.tx_gas_limit),
)
}
@@ -468,7 +468,7 @@ impl TransactionQueue {
self.pool.read().pending_from_sender(state_readiness, address)
.last()
.map(|tx| tx.signed().nonce + 1.into())
.map(|tx| tx.signed().nonce + 1)
}
/// Retrieve a transaction from the pool.

View File

@@ -95,7 +95,7 @@ impl<C: NonceClient> txpool::Ready<VerifiedTransaction> for State<C> {
},
cmp::Ordering::Less => txpool::Readiness::Stale,
cmp::Ordering::Equal => {
*nonce = *nonce + 1.into();
*nonce = *nonce + 1;
txpool::Readiness::Ready
},
}
@@ -159,7 +159,7 @@ impl<C: Fn(&Address) -> Option<U256>> txpool::Ready<VerifiedTransaction> for Opt
cmp::Ordering::Greater => txpool::Readiness::Future,
cmp::Ordering::Less => txpool::Readiness::Stale,
cmp::Ordering::Equal => {
*nonce = *nonce + 1.into();
*nonce = *nonce + 1;
txpool::Readiness::Ready
},
}

View File

@@ -71,7 +71,7 @@ fn should_return_correct_nonces_when_dropped_because_of_limit() {
assert_eq!(txq.status().status.transaction_count, 1);
// then
assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 1.into()));
assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 1));
// when
let tx1 = Tx::gas_price(2).signed();
@@ -123,7 +123,7 @@ fn should_never_drop_local_transactions_from_different_senders() {
assert_eq!(txq.status().status.transaction_count, 2);
// then
assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 2.into()));
assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 2));
// when
let tx1 = Tx::gas_price(2).signed();
@@ -137,7 +137,7 @@ fn should_never_drop_local_transactions_from_different_senders() {
assert_eq!(res, vec![Ok(()), Ok(())]);
assert_eq!(res2, vec![Ok(()), Ok(())]);
assert_eq!(txq.status().status.transaction_count, 6);
assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 2.into()));
assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 2));
}
#[test]
@@ -604,7 +604,7 @@ fn should_return_correct_nonce_when_transactions_from_given_address_exist() {
txq.import(TestClient::new(), vec![tx.local()]);
// then
assert_eq!(txq.next_nonce(TestClient::new(), &from), Some(nonce + 1.into()));
assert_eq!(txq.next_nonce(TestClient::new(), &from), Some(nonce + 1 ));
}
#[test]

View File

@@ -476,8 +476,8 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
(report.blocks_imported * 1000) as u64 / ms,
report.transactions_applied,
(report.transactions_applied * 1000) as u64 / ms,
report.gas_processed / From::from(1_000_000),
(report.gas_processed / From::from(ms * 1000)).low_u64(),
report.gas_processed / 1_000_000,
(report.gas_processed / (ms * 1000)).low_u64(),
);
Ok(())
}

View File

@@ -306,7 +306,7 @@ impl<T: InformantData> Informant<T> {
format!("{} blk/s {} tx/s {} Mgas/s",
paint(Yellow.bold(), format!("{:7.2}", (client_report.blocks_imported * 1000) as f64 / elapsed.as_milliseconds() as f64)),
paint(Yellow.bold(), format!("{:6.1}", (client_report.transactions_applied * 1000) as f64 / elapsed.as_milliseconds() as f64)),
paint(Yellow.bold(), format!("{:4}", (client_report.gas_processed / From::from(elapsed.as_milliseconds() * 1000)).low_u64()))
paint(Yellow.bold(), format!("{:4}", (client_report.gas_processed / (elapsed.as_milliseconds() * 1000)).low_u64()))
)
} else {
format!("{} hdr/s",

View File

@@ -65,7 +65,7 @@ extern crate parity_rpc;
extern crate parity_updater as updater;
extern crate parity_version;
extern crate parity_whisper;
extern crate path;
extern crate parity_path as path;
extern crate rpc_cli;
extern crate node_filter;
extern crate keccak_hash as hash;

View File

@@ -7,7 +7,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
futures = "0.1"
ethabi = "5.1.0"
ethabi-derive = "5.0.5"
ethabi-contract = "5.0.3"
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
ethabi = "5.1.2"
ethabi-derive = "5.1.3"
ethabi-contract = "5.1.1"
keccak-hash = "0.1"

View File

@@ -52,7 +52,8 @@ impl Registrar {
};
let address_fetcher = self.registrar.functions().get_address();
let id = address_fetcher.input(keccak(key), DNS_A_RECORD);
let hashed_key: [u8; 32] = keccak(key).into();
let id = address_fetcher.input(hashed_key, DNS_A_RECORD);
let future = self.client.call_contract(registrar_address, id).and_then(move |address| {
address_fetcher.output(&address)

View File

@@ -37,9 +37,9 @@ jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc.git", branch = "
ethash = { path = "../ethash" }
ethcore = { path = "../ethcore", features = ["test-helpers"] }
parity-bytes = "0.1"
parity-crypto = "0.1"
fastmap = { path = "../util/fastmap" }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
parity-crypto = { git = "https://github.com/paritytech/parity-common" }
ethcore-devtools = { path = "../devtools" }
ethcore-io = { path = "../util/io" }
ethcore-light = { path = "../ethcore/light" }
@@ -48,18 +48,18 @@ ethcore-miner = { path = "../miner" }
ethcore-private-tx = { path = "../ethcore/private-tx" }
ethcore-sync = { path = "../ethcore/sync" }
ethcore-transaction = { path = "../ethcore/transaction" }
ethereum-types = "0.3.2"
ethereum-types = "0.4"
ethjson = { path = "../json" }
ethkey = { path = "../ethkey" }
ethstore = { path = "../ethstore" }
fetch = { path = "../util/fetch" }
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1.2"
parity-reactor = { path = "../util/reactor" }
parity-updater = { path = "../updater" }
parity-version = { path = "../util/version" }
patricia-trie = { git = "https://github.com/paritytech/parity-common" }
rlp = { git = "https://github.com/paritytech/parity-common" }
patricia-trie = "0.2.1"
rlp = { version = "0.2.4", features = ["ethereum"] }
stats = { path = "../util/stats" }
vm = { path = "../ethcore/vm" }
@@ -73,7 +73,7 @@ fake-hardware-wallet = { path = "../util/fake-hardware-wallet" }
ethcore = { path = "../ethcore", features = ["test-helpers"] }
ethcore-network = { path = "../util/network" }
fake-fetch = { path = "../util/fake-fetch" }
kvdb-memorydb = "0.1.0"
kvdb-memorydb = "0.1"
macros = { path = "../util/macros" }
pretty_assertions = "0.1"
transaction-pool = { path = "../transaction-pool" }
transaction-pool = "1.13"

View File

@@ -346,7 +346,7 @@ impl Dispatcher for LightDispatcher {
to: request.to,
nonce: request.nonce,
gas_price: gas_price,
gas: request.gas.unwrap_or_else(|| gas_limit / 3.into()),
gas: request.gas.unwrap_or_else(|| gas_limit / 3),
value: request.value.unwrap_or_else(|| 0.into()),
data: request.data.unwrap_or_else(Vec::new),
condition: request.condition,

View File

@@ -24,7 +24,7 @@ pub fn sign_call(request: CallRequest) -> Result<SignedTransaction, Error> {
let max_gas = U256::from(50_000_000);
let gas = match request.gas {
Some(gas) => gas,
None => max_gas * 10,
None => max_gas * 10u32,
};
let from = request.from.unwrap_or(0.into());

View File

@@ -104,8 +104,8 @@ impl SenderReservations {
pub fn reserve_nonce(&mut self, minimal: U256) -> Reserved {
// Update prospective value
let dropped = self.dropped.swap(0, atomic::Ordering::SeqCst);
let prospective_value = cmp::max(minimal, self.prospective_value - dropped.into());
self.prospective_value = prospective_value + 1.into();
let prospective_value = cmp::max(minimal, self.prospective_value - dropped);
self.prospective_value = prospective_value + 1;
let (next, rx) = oneshot::channel();
let next = Some(next);
@@ -236,7 +236,7 @@ impl Ready {
pub fn mark_used(mut self) {
let next = self.next.take().expect("Nonce can be marked as used only once; qed");
self.next_sent.store(true, atomic::Ordering::SeqCst);
next.send(self.value + 1.into()).expect(Self::RECV_PROOF);
next.send(self.value + 1).expect(Self::RECV_PROOF);
}
}

View File

@@ -78,7 +78,7 @@ impl TestMinerService {
pub fn increment_nonce(&self, address: &Address) {
let mut next_nonces = self.next_nonces.write();
let nonce = next_nonces.entry(*address).or_insert_with(|| 0.into());
*nonce = *nonce + 1.into();
*nonce = *nonce + 1;
}
}

View File

@@ -17,4 +17,4 @@ parking_lot = "0.6"
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
parity-rpc = { path = "../rpc" }
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1"

View File

@@ -24,19 +24,19 @@ tokio-service = "0.1"
tokio-proto = "0.1"
url = "1.0"
ethcore = { path = "../ethcore" }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
parity-crypto = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
parity-crypto = "0.1"
ethcore-logger = { path = "../logger" }
ethcore-sync = { path = "../ethcore/sync" }
ethcore-transaction = { path = "../ethcore/transaction" }
ethereum-types = "0.3"
kvdb = "0.1.0"
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.4"
kvdb = "0.1"
keccak-hash = "0.1"
ethkey = { path = "../ethkey" }
lazy_static = "1.0"
ethabi = "5.1"
ethabi-derive = "5.0"
ethabi-contract = "5.0"
ethabi = "5.1.2"
ethabi-derive = "5.1.3"
ethabi-contract = "5.1.1"
[dev-dependencies]
ethcore = { path = "../ethcore", features = ["test-helpers"] }

View File

@@ -479,7 +479,7 @@ pub fn serialize_ecdsa_signature(nonce_public: &Public, signature_r: Secret, mut
let mut signature_v = {
let nonce_public_x = public_x(nonce_public);
let nonce_public_y: U256 = public_y(nonce_public).into();
let nonce_public_y_is_odd = !(nonce_public_y % 2.into()).is_zero();
let nonce_public_y_is_odd = !(nonce_public_y % 2).is_zero();
let bit0 = if nonce_public_y_is_odd { 1u8 } else { 0u8 };
let bit1 = if nonce_public_x != *signature_r { 2u8 } else { 0u8 };
bit0 | bit1
@@ -487,7 +487,7 @@ pub fn serialize_ecdsa_signature(nonce_public: &Public, signature_r: Secret, mut
// fix high S
let curve_order = math::curve_order();
let curve_order_half = curve_order / 2.into();
let curve_order_half = curve_order / 2;
let s_numeric: U256 = (*signature_s).into();
if s_numeric > curve_order_half {
let signature_s_hash: H256 = (curve_order - s_numeric).into();

View File

@@ -422,7 +422,7 @@ impl<F> Iterator for PendingRequestsIterator<F> where F: Fn(U256) -> Option<(boo
}
let index = self.index.clone();
self.index = self.index + 1.into();
self.index = self.index + 1;
(self.read_request)(index)
}
@@ -691,7 +691,7 @@ impl DocumentKeyShadowRetrievalService {
for participant in participants {
let participant_index = Self::map_key_server_address(client, contract_address, contract, participant.clone())
.map_err(|e| format!("Error searching for {} participant: {}", participant, e))?;
participants_mask = participants_mask | (U256::one() << participant_index.into());
participants_mask = participants_mask | (U256::one() << participant_index);
}
Ok(contract.functions()
.document_key_personal_retrieved()

View File

@@ -575,8 +575,8 @@ fn is_processed_by_this_key_server(key_server_set: &KeyServerSet, node: &NodeId,
};
let server_key_id_value: U256 = server_key_id.into();
let range_interval = U256::max_value() / total_servers_count.into();
let range_begin = (range_interval + 1.into()) * this_server_index as u32;
let range_interval = U256::max_value() / total_servers_count;
let range_begin = (range_interval + 1) * this_server_index as u32;
let range_end = range_begin.saturating_add(range_interval);
server_key_id_value >= range_begin && server_key_id_value <= range_end

View File

@@ -1,15 +0,0 @@
[package]
description = "Generic transaction pool."
name = "transaction-pool"
version = "1.13.1"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
error-chain = "0.12"
log = "0.4"
smallvec = "0.4"
trace-time = { path = "../util/trace-time", version = "0.1" }
[dev-dependencies]
ethereum-types = "0.3"

View File

@@ -1,53 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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/>.
/// Error chain doesn't let us have generic types.
/// So the hashes are converted to debug strings for easy display.
type Hash = String;
error_chain! {
errors {
/// Transaction is already imported
AlreadyImported(hash: Hash) {
description("transaction is already in the pool"),
display("[{}] already imported", hash)
}
/// Transaction is too cheap to enter the queue
TooCheapToEnter(hash: Hash, min_score: String) {
description("the pool is full and transaction is too cheap to replace any transaction"),
display("[{}] too cheap to enter the pool. Min score: {}", hash, min_score)
}
/// Transaction is too cheap to replace existing transaction that occupies the same slot.
TooCheapToReplace(old_hash: Hash, hash: Hash) {
description("transaction is too cheap to replace existing transaction in the pool"),
display("[{}] too cheap to replace: {}", hash, old_hash)
}
}
}
#[cfg(test)]
impl PartialEq for ErrorKind {
fn eq(&self, other: &Self) -> bool {
use self::ErrorKind::*;
match (self, other) {
(&AlreadyImported(ref h1), &AlreadyImported(ref h2)) => h1 == h2,
(&TooCheapToEnter(ref h1, ref s1), &TooCheapToEnter(ref h2, ref s2)) => h1 == h2 && s1 == s2,
(&TooCheapToReplace(ref old1, ref new1), &TooCheapToReplace(ref old2, ref new2)) => old1 == old2 && new1 == new2,
_ => false,
}
}
}

View File

@@ -1,124 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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/>.
//! Generic Transaction Pool
//!
//! An extensible and performant implementation of Ethereum Transaction Pool.
//! The pool stores ordered, verified transactions according to some pluggable
//! `Scoring` implementation.
//! The pool also allows you to construct a set of `pending` transactions according
//! to some notion of `Readiness` (pluggable).
//!
//! The pool is generic over transactions and should make no assumptions about them.
//! The only thing we can rely on is the `Scoring` that defines:
//! - the ordering of transactions from a single sender
//! - the priority of the transaction compared to other transactions from different senders
//!
//! NOTE: the transactions from a single sender are not ordered by priority,
//! but still when constructing pending set we always need to maintain the ordering
//! (i.e. `txs[1]` always needs to be included after `txs[0]` even if it has higher priority)
//!
//! ### Design Details
//!
//! Performance assumptions:
//! - Possibility to handle tens of thousands of transactions
//! - Fast insertions and replacements `O(per-sender + log(senders))`
//! - Reasonably fast removal of stalled transactions `O(per-sender)`
//! - Reasonably fast construction of pending set `O(txs * (log(senders) + log(per-sender))`
//!
//! The removal performance could be improved by trading some memory. Currently `SmallVec` is used
//! to store senders transactions, instead we could use `VecDeque` and efficiently `pop_front`
//! the best transactions.
//!
//! The pending set construction and insertion complexity could be reduced by introducing
//! a notion of `nonce` - an absolute, numeric ordering of transactions.
//! We don't do that because of possible implications of EIP208 where nonce might not be
//! explicitly available.
//!
//! 1. The pool groups transactions from particular sender together
//! and stores them ordered by `Scoring` within that group
//! i.e. `HashMap<Sender, Vec<Transaction>>`.
//! 2. Additionaly we maintain the best and the worst transaction from each sender
//! (by `Scoring` not `priority`) ordered by `priority`.
//! It means that we can easily identify the best transaction inside the entire pool
//! and the worst transaction.
//! 3. Whenever new transaction is inserted to the queue:
//! - first check all the limits (overall, memory, per-sender)
//! - retrieve all transactions from a sender
//! - binary search for position to insert the transaction
//! - decide if we are replacing existing transaction (3 outcomes: drop, replace, insert)
//! - update best and worst transaction from that sender if affected
//! 4. Pending List construction:
//! - Take the best transaction (by priority) from all senders to the List
//! - Replace the transaction with next transaction (by ordering) from that sender (if any)
//! - Repeat
#![warn(missing_docs)]
extern crate smallvec;
extern crate trace_time;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
#[cfg(test)]
extern crate ethereum_types;
#[cfg(test)]
mod tests;
mod error;
mod listener;
mod options;
mod pool;
mod ready;
mod status;
mod transactions;
mod verifier;
pub mod scoring;
pub use self::error::{Error, ErrorKind};
pub use self::listener::{Listener, NoopListener};
pub use self::options::Options;
pub use self::pool::{Pool, PendingIterator, UnorderedIterator, Transaction};
pub use self::ready::{Ready, Readiness};
pub use self::scoring::Scoring;
pub use self::status::{LightStatus, Status};
pub use self::verifier::Verifier;
use std::fmt;
use std::hash::Hash;
/// Already verified transaction that can be safely queued.
pub trait VerifiedTransaction: fmt::Debug {
/// Transaction hash type.
type Hash: fmt::Debug + fmt::LowerHex + Eq + Clone + Hash;
/// Transaction sender type.
type Sender: fmt::Debug + Eq + Clone + Hash + Send;
/// Transaction hash
fn hash(&self) -> &Self::Hash;
/// Memory usage
fn mem_usage(&self) -> usize;
/// Transaction sender
fn sender(&self) -> &Self::Sender;
}

View File

@@ -1,85 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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 std::sync::Arc;
use error::ErrorKind;
/// Transaction pool listener.
///
/// Listener is being notified about status of every transaction in the pool.
pub trait Listener<T> {
/// The transaction has been successfuly added to the pool.
/// If second argument is `Some` the transaction has took place of some other transaction
/// which was already in pool.
/// NOTE: You won't be notified about drop of `old` transaction separately.
fn added(&mut self, _tx: &Arc<T>, _old: Option<&Arc<T>>) {}
/// The transaction was rejected from the pool.
/// It means that it was too cheap to replace any transaction already in the pool.
fn rejected(&mut self, _tx: &Arc<T>, _reason: &ErrorKind) {}
/// The transaction was pushed out from the pool because of the limit.
fn dropped(&mut self, _tx: &Arc<T>, _by: Option<&T>) {}
/// The transaction was marked as invalid by executor.
fn invalid(&mut self, _tx: &Arc<T>) {}
/// The transaction has been canceled.
fn canceled(&mut self, _tx: &Arc<T>) {}
/// The transaction has been culled from the pool.
fn culled(&mut self, _tx: &Arc<T>) {}
}
/// A no-op implementation of `Listener`.
#[derive(Debug)]
pub struct NoopListener;
impl<T> Listener<T> for NoopListener {}
impl<T, A, B> Listener<T> for (A, B) where
A: Listener<T>,
B: Listener<T>,
{
fn added(&mut self, tx: &Arc<T>, old: Option<&Arc<T>>) {
self.0.added(tx, old);
self.1.added(tx, old);
}
fn rejected(&mut self, tx: &Arc<T>, reason: &ErrorKind) {
self.0.rejected(tx, reason);
self.1.rejected(tx, reason);
}
fn dropped(&mut self, tx: &Arc<T>, by: Option<&T>) {
self.0.dropped(tx, by);
self.1.dropped(tx, by);
}
fn invalid(&mut self, tx: &Arc<T>) {
self.0.invalid(tx);
self.1.invalid(tx);
}
fn canceled(&mut self, tx: &Arc<T>) {
self.0.canceled(tx);
self.1.canceled(tx);
}
fn culled(&mut self, tx: &Arc<T>) {
self.0.culled(tx);
self.1.culled(tx);
}
}

View File

@@ -1,36 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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 Pool options.
#[derive(Clone, Debug, PartialEq)]
pub struct Options {
/// Maximal number of transactions in the pool.
pub max_count: usize,
/// Maximal number of transactions from single sender.
pub max_per_sender: usize,
/// Maximal memory usage.
pub max_mem_usage: usize,
}
impl Default for Options {
fn default() -> Self {
Options {
max_count: 1024,
max_per_sender: 16,
max_mem_usage: 8 * 1024 * 1024,
}
}
}

View File

@@ -1,616 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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 std::sync::Arc;
use std::slice;
use std::collections::{hash_map, HashMap, BTreeSet};
use error;
use listener::{Listener, NoopListener};
use options::Options;
use ready::{Ready, Readiness};
use scoring::{self, Scoring, ScoreWithRef};
use status::{LightStatus, Status};
use transactions::{AddResult, Transactions};
use {VerifiedTransaction};
/// Internal representation of transaction.
///
/// Includes unique insertion id that can be used for scoring explictly,
/// but internally is used to resolve conflicts in case of equal scoring
/// (newer transactionsa are preferred).
#[derive(Debug)]
pub struct Transaction<T> {
/// Sequential id of the transaction
pub insertion_id: u64,
/// Shared transaction
pub transaction: Arc<T>,
}
impl<T> Clone for Transaction<T> {
fn clone(&self) -> Self {
Transaction {
insertion_id: self.insertion_id,
transaction: self.transaction.clone(),
}
}
}
impl<T> ::std::ops::Deref for Transaction<T> {
type Target = Arc<T>;
fn deref(&self) -> &Self::Target {
&self.transaction
}
}
/// A transaction pool.
#[derive(Debug)]
pub struct Pool<T: VerifiedTransaction, S: Scoring<T>, L = NoopListener> {
listener: L,
scoring: S,
options: Options,
mem_usage: usize,
transactions: HashMap<T::Sender, Transactions<T, S>>,
by_hash: HashMap<T::Hash, Transaction<T>>,
best_transactions: BTreeSet<ScoreWithRef<T, S::Score>>,
worst_transactions: BTreeSet<ScoreWithRef<T, S::Score>>,
insertion_id: u64,
}
impl<T: VerifiedTransaction, S: Scoring<T> + Default> Default for Pool<T, S> {
fn default() -> Self {
Self::with_scoring(S::default(), Options::default())
}
}
impl<T: VerifiedTransaction, S: Scoring<T> + Default> Pool<T, S> {
/// Creates a new `Pool` with given options
/// and default `Scoring` and `Listener`.
pub fn with_options(options: Options) -> Self {
Self::with_scoring(S::default(), options)
}
}
impl<T: VerifiedTransaction, S: Scoring<T>> Pool<T, S> {
/// Creates a new `Pool` with given `Scoring` and options.
pub fn with_scoring(scoring: S, options: Options) -> Self {
Self::new(NoopListener, scoring, options)
}
}
const INITIAL_NUMBER_OF_SENDERS: usize = 16;
impl<T, S, L> Pool<T, S, L> where
T: VerifiedTransaction,
S: Scoring<T>,
L: Listener<T>,
{
/// Creates new `Pool` with given `Scoring`, `Listener` and options.
pub fn new(listener: L, scoring: S, options: Options) -> Self {
let transactions = HashMap::with_capacity(INITIAL_NUMBER_OF_SENDERS);
let by_hash = HashMap::with_capacity(options.max_count / 16);
Pool {
listener,
scoring,
options,
mem_usage: 0,
transactions,
by_hash,
best_transactions: Default::default(),
worst_transactions: Default::default(),
insertion_id: 0,
}
}
/// Attempts to import new transaction to the pool, returns a `Arc<T>` or an `Error`.
///
/// NOTE: Since `Ready`ness is separate from the pool it's possible to import stalled transactions.
/// It's the caller responsibility to make sure that's not the case.
///
/// NOTE: The transaction may push out some other transactions from the pool
/// either because of limits (see `Options`) or because `Scoring` decides that the transaction
/// replaces an existing transaction from that sender.
/// If any limit is reached the transaction with the lowest `Score` is evicted to make room.
///
/// The `Listener` will be informed on any drops or rejections.
pub fn import(&mut self, transaction: T) -> error::Result<Arc<T>> {
let mem_usage = transaction.mem_usage();
ensure!(!self.by_hash.contains_key(transaction.hash()), error::ErrorKind::AlreadyImported(format!("{:?}", transaction.hash())));
self.insertion_id += 1;
let transaction = Transaction {
insertion_id: self.insertion_id,
transaction: Arc::new(transaction),
};
// TODO [ToDr] Most likely move this after the transaction is inserted.
// Avoid using should_replace, but rather use scoring for that.
{
let remove_worst = |s: &mut Self, transaction| {
match s.remove_worst(transaction) {
Err(err) => {
s.listener.rejected(transaction, err.kind());
Err(err)
},
Ok(None) => Ok(false),
Ok(Some(removed)) => {
s.listener.dropped(&removed, Some(transaction));
s.finalize_remove(removed.hash());
Ok(true)
},
}
};
while self.by_hash.len() + 1 > self.options.max_count {
trace!("Count limit reached: {} > {}", self.by_hash.len() + 1, self.options.max_count);
if !remove_worst(self, &transaction)? {
break;
}
}
while self.mem_usage + mem_usage > self.options.max_mem_usage {
trace!("Mem limit reached: {} > {}", self.mem_usage + mem_usage, self.options.max_mem_usage);
if !remove_worst(self, &transaction)? {
break;
}
}
}
let (result, prev_state, current_state) = {
let transactions = self.transactions.entry(transaction.sender().clone()).or_insert_with(Transactions::default);
// get worst and best transactions for comparison
let prev = transactions.worst_and_best();
let result = transactions.add(transaction, &self.scoring, self.options.max_per_sender);
let current = transactions.worst_and_best();
(result, prev, current)
};
// update best and worst transactions from this sender (if required)
self.update_senders_worst_and_best(prev_state, current_state);
match result {
AddResult::Ok(tx) => {
self.listener.added(&tx, None);
self.finalize_insert(&tx, None);
Ok(tx.transaction)
},
AddResult::PushedOut { new, old } |
AddResult::Replaced { new, old } => {
self.listener.added(&new, Some(&old));
self.finalize_insert(&new, Some(&old));
Ok(new.transaction)
},
AddResult::TooCheap { new, old } => {
let error = error::ErrorKind::TooCheapToReplace(format!("{:x}", old.hash()), format!("{:x}", new.hash()));
self.listener.rejected(&new, &error);
bail!(error)
},
AddResult::TooCheapToEnter(new, score) => {
let error = error::ErrorKind::TooCheapToEnter(format!("{:x}", new.hash()), format!("{:?}", score));
self.listener.rejected(&new, &error);
bail!(error)
}
}
}
/// Updates state of the pool statistics if the transaction was added to a set.
fn finalize_insert(&mut self, new: &Transaction<T>, old: Option<&Transaction<T>>) {
self.mem_usage += new.mem_usage();
self.by_hash.insert(new.hash().clone(), new.clone());
if let Some(old) = old {
self.finalize_remove(old.hash());
}
}
/// Updates the pool statistics if transaction was removed.
fn finalize_remove(&mut self, hash: &T::Hash) -> Option<Arc<T>> {
self.by_hash.remove(hash).map(|old| {
self.mem_usage -= old.transaction.mem_usage();
old.transaction
})
}
/// Updates best and worst transactions from a sender.
fn update_senders_worst_and_best(
&mut self,
previous: Option<((S::Score, Transaction<T>), (S::Score, Transaction<T>))>,
current: Option<((S::Score, Transaction<T>), (S::Score, Transaction<T>))>,
) {
let worst_collection = &mut self.worst_transactions;
let best_collection = &mut self.best_transactions;
let is_same = |a: &(S::Score, Transaction<T>), b: &(S::Score, Transaction<T>)| {
a.0 == b.0 && a.1.hash() == b.1.hash()
};
let update = |collection: &mut BTreeSet<_>, (score, tx), remove| if remove {
collection.remove(&ScoreWithRef::new(score, tx));
} else {
collection.insert(ScoreWithRef::new(score, tx));
};
match (previous, current) {
(None, Some((worst, best))) => {
update(worst_collection, worst, false);
update(best_collection, best, false);
},
(Some((worst, best)), None) => {
// all transactions from that sender has been removed.
// We can clear a hashmap entry.
self.transactions.remove(worst.1.sender());
update(worst_collection, worst, true);
update(best_collection, best, true);
},
(Some((w1, b1)), Some((w2, b2))) => {
if !is_same(&w1, &w2) {
update(worst_collection, w1, true);
update(worst_collection, w2, false);
}
if !is_same(&b1, &b2) {
update(best_collection, b1, true);
update(best_collection, b2, false);
}
},
(None, None) => {},
}
}
/// Attempts to remove the worst transaction from the pool if it's worse than the given one.
///
/// Returns `None` in case we couldn't decide if the transaction should replace the worst transaction or not.
/// In such case we will accept the transaction even though it is going to exceed the limit.
fn remove_worst(&mut self, transaction: &Transaction<T>) -> error::Result<Option<Transaction<T>>> {
let to_remove = match self.worst_transactions.iter().next_back() {
// No elements to remove? and the pool is still full?
None => {
warn!("The pool is full but there are no transactions to remove.");
return Err(error::ErrorKind::TooCheapToEnter(format!("{:?}", transaction.hash()), "unknown".into()).into());
},
Some(old) => match self.scoring.should_replace(&old.transaction, transaction) {
// We can't decide which of them should be removed, so accept both.
scoring::Choice::InsertNew => None,
// New transaction is better than the worst one so we can replace it.
scoring::Choice::ReplaceOld => Some(old.clone()),
// otherwise fail
scoring::Choice::RejectNew => {
return Err(error::ErrorKind::TooCheapToEnter(format!("{:?}", transaction.hash()), format!("{:?}", old.score)).into())
},
},
};
if let Some(to_remove) = to_remove {
// Remove from transaction set
self.remove_from_set(to_remove.transaction.sender(), |set, scoring| {
set.remove(&to_remove.transaction, scoring)
});
Ok(Some(to_remove.transaction))
} else {
Ok(None)
}
}
/// Removes transaction from sender's transaction `HashMap`.
fn remove_from_set<R, F: FnOnce(&mut Transactions<T, S>, &S) -> R>(&mut self, sender: &T::Sender, f: F) -> Option<R> {
let (prev, next, result) = if let Some(set) = self.transactions.get_mut(sender) {
let prev = set.worst_and_best();
let result = f(set, &self.scoring);
(prev, set.worst_and_best(), result)
} else {
return None;
};
self.update_senders_worst_and_best(prev, next);
Some(result)
}
/// Clears pool from all transactions.
/// This causes a listener notification that all transactions were dropped.
/// NOTE: the drop-notification order will be arbitrary.
pub fn clear(&mut self) {
self.mem_usage = 0;
self.transactions.clear();
self.best_transactions.clear();
self.worst_transactions.clear();
for (_hash, tx) in self.by_hash.drain() {
self.listener.dropped(&tx.transaction, None)
}
}
/// Removes single transaction from the pool.
/// Depending on the `is_invalid` flag the listener
/// will either get a `cancelled` or `invalid` notification.
pub fn remove(&mut self, hash: &T::Hash, is_invalid: bool) -> Option<Arc<T>> {
if let Some(tx) = self.finalize_remove(hash) {
self.remove_from_set(tx.sender(), |set, scoring| {
set.remove(&tx, scoring)
});
if is_invalid {
self.listener.invalid(&tx);
} else {
self.listener.canceled(&tx);
}
Some(tx)
} else {
None
}
}
/// Removes all stalled transactions from given sender.
fn remove_stalled<R: Ready<T>>(&mut self, sender: &T::Sender, ready: &mut R) -> usize {
let removed_from_set = self.remove_from_set(sender, |transactions, scoring| {
transactions.cull(ready, scoring)
});
match removed_from_set {
Some(removed) => {
let len = removed.len();
for tx in removed {
self.finalize_remove(tx.hash());
self.listener.culled(&tx);
}
len
},
None => 0,
}
}
/// Removes all stalled transactions from given sender list (or from all senders).
pub fn cull<R: Ready<T>>(&mut self, senders: Option<&[T::Sender]>, mut ready: R) -> usize {
let mut removed = 0;
match senders {
Some(senders) => {
for sender in senders {
removed += self.remove_stalled(sender, &mut ready);
}
},
None => {
let senders = self.transactions.keys().cloned().collect::<Vec<_>>();
for sender in senders {
removed += self.remove_stalled(&sender, &mut ready);
}
},
}
removed
}
/// Returns a transaction if it's part of the pool or `None` otherwise.
pub fn find(&self, hash: &T::Hash) -> Option<Arc<T>> {
self.by_hash.get(hash).map(|t| t.transaction.clone())
}
/// Returns worst transaction in the queue (if any).
pub fn worst_transaction(&self) -> Option<Arc<T>> {
self.worst_transactions.iter().next_back().map(|x| x.transaction.transaction.clone())
}
/// Returns true if the pool is at it's capacity.
pub fn is_full(&self) -> bool {
self.by_hash.len() >= self.options.max_count
|| self.mem_usage >= self.options.max_mem_usage
}
/// Returns senders ordered by priority of their transactions.
pub fn senders(&self) -> impl Iterator<Item=&T::Sender> {
self.best_transactions.iter().map(|tx| tx.transaction.sender())
}
/// Returns an iterator of pending (ready) transactions.
pub fn pending<R: Ready<T>>(&self, ready: R) -> PendingIterator<T, R, S, L> {
PendingIterator {
ready,
best_transactions: self.best_transactions.clone(),
pool: self,
}
}
/// Returns pending (ready) transactions from given sender.
pub fn pending_from_sender<R: Ready<T>>(&self, ready: R, sender: &T::Sender) -> PendingIterator<T, R, S, L> {
let best_transactions = self.transactions.get(sender)
.and_then(|transactions| transactions.worst_and_best())
.map(|(_, best)| ScoreWithRef::new(best.0, best.1))
.map(|s| {
let mut set = BTreeSet::new();
set.insert(s);
set
})
.unwrap_or_default();
PendingIterator {
ready,
best_transactions,
pool: self,
}
}
/// Returns unprioritized list of ready transactions.
pub fn unordered_pending<R: Ready<T>>(&self, ready: R) -> UnorderedIterator<T, R, S> {
UnorderedIterator {
ready,
senders: self.transactions.iter(),
transactions: None,
}
}
/// Update score of transactions of a particular sender.
pub fn update_scores(&mut self, sender: &T::Sender, event: S::Event) {
let res = if let Some(set) = self.transactions.get_mut(sender) {
let prev = set.worst_and_best();
set.update_scores(&self.scoring, event);
let current = set.worst_and_best();
Some((prev, current))
} else {
None
};
if let Some((prev, current)) = res {
self.update_senders_worst_and_best(prev, current);
}
}
/// Computes the full status of the pool (including readiness).
pub fn status<R: Ready<T>>(&self, mut ready: R) -> Status {
let mut status = Status::default();
for (_sender, transactions) in &self.transactions {
let len = transactions.len();
for (idx, tx) in transactions.iter().enumerate() {
match ready.is_ready(tx) {
Readiness::Stale => status.stalled += 1,
Readiness::Ready => status.pending += 1,
Readiness::Future => {
status.future += len - idx;
break;
}
}
}
}
status
}
/// Returns light status of the pool.
pub fn light_status(&self) -> LightStatus {
LightStatus {
mem_usage: self.mem_usage,
transaction_count: self.by_hash.len(),
senders: self.transactions.len(),
}
}
/// Returns current pool options.
pub fn options(&self) -> Options {
self.options.clone()
}
/// Borrows listener instance.
pub fn listener(&self) -> &L {
&self.listener
}
/// Borrows scoring instance.
pub fn scoring(&self) -> &S {
&self.scoring
}
/// Borrows listener mutably.
pub fn listener_mut(&mut self) -> &mut L {
&mut self.listener
}
}
/// An iterator over all pending (ready) transactions in unoredered fashion.
///
/// NOTE: Current implementation will iterate over all transactions from particular sender
/// ordered by nonce, but that might change in the future.
///
/// NOTE: the transactions are not removed from the queue.
/// You might remove them later by calling `cull`.
pub struct UnorderedIterator<'a, T, R, S> where
T: VerifiedTransaction + 'a,
S: Scoring<T> + 'a,
{
ready: R,
senders: hash_map::Iter<'a, T::Sender, Transactions<T, S>>,
transactions: Option<slice::Iter<'a, Transaction<T>>>,
}
impl<'a, T, R, S> Iterator for UnorderedIterator<'a, T, R, S> where
T: VerifiedTransaction,
R: Ready<T>,
S: Scoring<T>,
{
type Item = Arc<T>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(transactions) = self.transactions.as_mut() {
if let Some(tx) = transactions.next() {
match self.ready.is_ready(&tx) {
Readiness::Ready => {
return Some(tx.transaction.clone());
},
state => trace!("[{:?}] Ignoring {:?} transaction.", tx.hash(), state),
}
}
}
// otherwise fallback and try next sender
let next_sender = self.senders.next()?;
self.transactions = Some(next_sender.1.iter());
}
}
}
/// An iterator over all pending (ready) transactions.
/// NOTE: the transactions are not removed from the queue.
/// You might remove them later by calling `cull`.
pub struct PendingIterator<'a, T, R, S, L> where
T: VerifiedTransaction + 'a,
S: Scoring<T> + 'a,
L: 'a,
{
ready: R,
best_transactions: BTreeSet<ScoreWithRef<T, S::Score>>,
pool: &'a Pool<T, S, L>,
}
impl<'a, T, R, S, L> Iterator for PendingIterator<'a, T, R, S, L> where
T: VerifiedTransaction,
R: Ready<T>,
S: Scoring<T>,
{
type Item = Arc<T>;
fn next(&mut self) -> Option<Self::Item> {
while !self.best_transactions.is_empty() {
let best = {
let best = self.best_transactions.iter().next().expect("current_best is not empty; qed").clone();
self.best_transactions.take(&best).expect("Just taken from iterator; qed")
};
match self.ready.is_ready(&best.transaction) {
Readiness::Ready => {
// retrieve next one from that sender.
let next = self.pool.transactions
.get(best.transaction.sender())
.and_then(|s| s.find_next(&best.transaction, &self.pool.scoring));
if let Some((score, tx)) = next {
self.best_transactions.insert(ScoreWithRef::new(score, tx));
}
return Some(best.transaction.transaction)
},
state => trace!("[{:?}] Ignoring {:?} transaction.", best.transaction.hash(), state),
}
}
None
}
}

View File

@@ -1,54 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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 readiness.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Readiness {
/// The transaction is stale (and should/will be removed from the pool).
Stale,
/// The transaction is ready to be included in pending set.
Ready,
/// The transaction is not yet ready.
Future,
}
/// A readiness indicator.
pub trait Ready<T> {
/// Returns true if transaction is ready to be included in pending block,
/// given all previous transactions that were ready are already included.
///
/// NOTE: readiness of transactions will be checked according to `Score` ordering,
/// the implementation should maintain a state of already checked transactions.
fn is_ready(&mut self, tx: &T) -> Readiness;
}
impl<T, F> Ready<T> for F where F: FnMut(&T) -> Readiness {
fn is_ready(&mut self, tx: &T) -> Readiness {
(*self)(tx)
}
}
impl<T, A, B> Ready<T> for (A, B) where
A: Ready<T>,
B: Ready<T>,
{
fn is_ready(&mut self, tx: &T) -> Readiness {
match self.0.is_ready(tx) {
Readiness::Ready => self.1.is_ready(tx),
r => r,
}
}
}

View File

@@ -1,157 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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/>.
//! A transactions ordering abstraction.
use std::{cmp, fmt};
use pool::Transaction;
/// Represents a decision what to do with
/// a new transaction that tries to enter the pool.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Choice {
/// New transaction should be rejected
/// (i.e. the old transaction that occupies the same spot
/// is better).
RejectNew,
/// The old transaction should be dropped
/// in favour of the new one.
ReplaceOld,
/// The new transaction should be inserted
/// and both (old and new) should stay in the pool.
InsertNew,
}
/// Describes a reason why the `Score` of transactions
/// should be updated.
/// The `Scoring` implementations can use this information
/// to update the `Score` table more efficiently.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Change<T = ()> {
/// New transaction has been inserted at given index.
/// The Score at that index is initialized with default value
/// and needs to be filled in.
InsertedAt(usize),
/// The transaction has been removed at given index and other transactions
/// shifted to it's place.
/// The scores were removed and shifted as well.
/// For simple scoring algorithms no action is required here.
RemovedAt(usize),
/// The transaction at given index has replaced a previous transaction.
/// The score at that index needs to be update (it contains value from previous transaction).
ReplacedAt(usize),
/// Given number of stalled transactions has been culled from the beginning.
/// The scores has been removed from the beginning as well.
/// For simple scoring algorithms no action is required here.
Culled(usize),
/// Custom event to update the score triggered outside of the pool.
/// Handling this event is up to scoring implementation.
Event(T),
}
/// A transaction ordering.
///
/// The implementation should decide on order of transactions in the pool.
/// Each transaction should also get assigned a `Score` which is used to later
/// prioritize transactions in the pending set.
///
/// Implementation notes:
/// - Returned `Score`s should match ordering of `compare` method.
/// - `compare` will be called only within a context of transactions from the same sender.
/// - `choose` may be called even if `compare` returns `Ordering::Equal`
/// - `should_replace` is used to decide if new transaction should push out an old transaction already in the queue.
/// - `Score`s and `compare` should align with `Ready` implementation.
///
/// Example: Natural ordering of Ethereum transactions.
/// - `compare`: compares transaction `nonce` ()
/// - `choose`: compares transactions `gasPrice` (decides if old transaction should be replaced)
/// - `update_scores`: score defined as `gasPrice` if `n==0` and `max(scores[n-1], gasPrice)` if `n>0`
/// - `should_replace`: compares `gasPrice` (decides if transaction from a different sender is more valuable)
///
pub trait Scoring<T>: fmt::Debug {
/// A score of a transaction.
type Score: cmp::Ord + Clone + Default + fmt::Debug + Send;
/// Custom scoring update event type.
type Event: fmt::Debug;
/// Decides on ordering of `T`s from a particular sender.
fn compare(&self, old: &T, other: &T) -> cmp::Ordering;
/// Decides how to deal with two transactions from a sender that seem to occupy the same slot in the queue.
fn choose(&self, old: &T, new: &T) -> Choice;
/// Updates the transaction scores given a list of transactions and a change to previous scoring.
/// NOTE: you can safely assume that both slices have the same length.
/// (i.e. score at index `i` represents transaction at the same index)
fn update_scores(&self, txs: &[Transaction<T>], scores: &mut [Self::Score], change: Change<Self::Event>);
/// Decides if `new` should push out `old` transaction from the pool.
///
/// NOTE returning `InsertNew` here can lead to some transactions being accepted above pool limits.
fn should_replace(&self, old: &T, new: &T) -> Choice;
/// Decides if the transaction should ignore per-sender limit in the pool.
///
/// If you return `true` for given transaction it's going to be accepted even though
/// the per-sender limit is exceeded.
fn should_ignore_sender_limit(&self, _new: &T) -> bool { false }
}
/// A score with a reference to the transaction.
#[derive(Debug)]
pub struct ScoreWithRef<T, S> {
/// Score
pub score: S,
/// Shared transaction
pub transaction: Transaction<T>,
}
impl<T, S> ScoreWithRef<T, S> {
/// Creates a new `ScoreWithRef`
pub fn new(score: S, transaction: Transaction<T>) -> Self {
ScoreWithRef { score, transaction }
}
}
impl<T, S: Clone> Clone for ScoreWithRef<T, S> {
fn clone(&self) -> Self {
ScoreWithRef {
score: self.score.clone(),
transaction: self.transaction.clone(),
}
}
}
impl<S: cmp::Ord, T> Ord for ScoreWithRef<T, S> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
other.score.cmp(&self.score)
.then(other.transaction.insertion_id.cmp(&self.transaction.insertion_id))
}
}
impl<S: cmp::Ord, T> PartialOrd for ScoreWithRef<T, S> {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<S: cmp::Ord, T> PartialEq for ScoreWithRef<T, S> {
fn eq(&self, other: &Self) -> bool {
self.score == other.score && self.transaction.insertion_id == other.transaction.insertion_id
}
}
impl<S: cmp::Ord, T> Eq for ScoreWithRef<T, S> {}

View File

@@ -1,40 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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/>.
/// Light pool status.
/// This status is cheap to compute and can be called frequently.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct LightStatus {
/// Memory usage in bytes.
pub mem_usage: usize,
/// Total number of transactions in the pool.
pub transaction_count: usize,
/// Number of unique senders in the pool.
pub senders: usize,
}
/// A full queue status.
/// To compute this status it is required to provide `Ready`.
/// NOTE: To compute the status we need to visit each transaction in the pool.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Status {
/// Number of stalled transactions.
pub stalled: usize,
/// Number of pending (ready) transactions.
pub pending: usize,
/// Number of future (not ready) transactions.
pub future: usize,
}

View File

@@ -1,110 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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 std::cmp;
use std::collections::HashMap;
use ethereum_types::{H160 as Sender, U256};
use {pool, scoring, Scoring, Ready, Readiness};
use super::Transaction;
#[derive(Debug, Default)]
pub struct DummyScoring {
always_insert: bool,
}
impl DummyScoring {
pub fn always_insert() -> Self {
DummyScoring {
always_insert: true,
}
}
}
impl Scoring<Transaction> for DummyScoring {
type Score = U256;
type Event = ();
fn compare(&self, old: &Transaction, new: &Transaction) -> cmp::Ordering {
old.nonce.cmp(&new.nonce)
}
fn choose(&self, old: &Transaction, new: &Transaction) -> scoring::Choice {
if old.nonce == new.nonce {
if new.gas_price > old.gas_price {
scoring::Choice::ReplaceOld
} else {
scoring::Choice::RejectNew
}
} else {
scoring::Choice::InsertNew
}
}
fn update_scores(&self, txs: &[pool::Transaction<Transaction>], scores: &mut [Self::Score], change: scoring::Change) {
if let scoring::Change::Event(_) = change {
// In case of event reset all scores to 0
for i in 0..txs.len() {
scores[i] = 0.into();
}
} else {
// Set to a gas price otherwise
for i in 0..txs.len() {
scores[i] = txs[i].gas_price;
}
}
}
fn should_replace(&self, old: &Transaction, new: &Transaction) -> scoring::Choice {
if self.always_insert {
scoring::Choice::InsertNew
} else if new.gas_price > old.gas_price {
scoring::Choice::ReplaceOld
} else {
scoring::Choice::RejectNew
}
}
fn should_ignore_sender_limit(&self, _new: &Transaction) -> bool {
self.always_insert
}
}
#[derive(Default)]
pub struct NonceReady(HashMap<Sender, U256>, U256);
impl NonceReady {
pub fn new<T: Into<U256>>(min: T) -> Self {
let mut n = NonceReady::default();
n.1 = min.into();
n
}
}
impl Ready<Transaction> for NonceReady {
fn is_ready(&mut self, tx: &Transaction) -> Readiness {
let min = self.1;
let nonce = self.0.entry(tx.sender).or_insert_with(|| min);
match tx.nonce.cmp(nonce) {
cmp::Ordering::Greater => Readiness::Future,
cmp::Ordering::Equal => {
*nonce = *nonce + 1.into();
Readiness::Ready
},
cmp::Ordering::Less => Readiness::Stale,
}
}
}

View File

@@ -1,748 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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/>.
mod helpers;
mod tx_builder;
use self::helpers::{DummyScoring, NonceReady};
use self::tx_builder::TransactionBuilder;
use std::sync::Arc;
use ethereum_types::{H256, U256, Address};
use super::*;
#[derive(Debug, PartialEq)]
pub struct Transaction {
pub hash: H256,
pub nonce: U256,
pub gas_price: U256,
pub gas: U256,
pub sender: Address,
pub mem_usage: usize,
}
impl VerifiedTransaction for Transaction {
type Hash = H256;
type Sender = Address;
fn hash(&self) -> &H256 { &self.hash }
fn mem_usage(&self) -> usize { self.mem_usage }
fn sender(&self) -> &Address { &self.sender }
}
pub type SharedTransaction = Arc<Transaction>;
type TestPool = Pool<Transaction, DummyScoring>;
impl TestPool {
pub fn with_limit(max_count: usize) -> Self {
Self::with_options(Options {
max_count,
..Default::default()
})
}
}
#[test]
fn should_clear_queue() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
assert_eq!(txq.light_status(), LightStatus {
mem_usage: 0,
transaction_count: 0,
senders: 0,
});
let tx1 = b.tx().nonce(0).new();
let tx2 = b.tx().nonce(1).mem_usage(1).new();
// add
txq.import(tx1).unwrap();
txq.import(tx2).unwrap();
assert_eq!(txq.light_status(), LightStatus {
mem_usage: 1,
transaction_count: 2,
senders: 1,
});
// when
txq.clear();
// then
assert_eq!(txq.light_status(), LightStatus {
mem_usage: 0,
transaction_count: 0,
senders: 0,
});
}
#[test]
fn should_not_allow_same_transaction_twice() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
let tx1 = b.tx().nonce(0).new();
let tx2 = b.tx().nonce(0).new();
// when
txq.import(tx1).unwrap();
txq.import(tx2).unwrap_err();
// then
assert_eq!(txq.light_status().transaction_count, 1);
}
#[test]
fn should_replace_transaction() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
let tx1 = b.tx().nonce(0).gas_price(1).new();
let tx2 = b.tx().nonce(0).gas_price(2).new();
// when
txq.import(tx1).unwrap();
txq.import(tx2).unwrap();
// then
assert_eq!(txq.light_status().transaction_count, 1);
}
#[test]
fn should_reject_if_above_count() {
let b = TransactionBuilder::default();
let mut txq = TestPool::with_options(Options {
max_count: 1,
..Default::default()
});
// Reject second
let tx1 = b.tx().nonce(0).new();
let tx2 = b.tx().nonce(1).new();
let hash = format!("{:?}", tx2.hash());
txq.import(tx1).unwrap();
assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into()));
assert_eq!(txq.light_status().transaction_count, 1);
txq.clear();
// Replace first
let tx1 = b.tx().nonce(0).new();
let tx2 = b.tx().nonce(0).sender(1).gas_price(2).new();
txq.import(tx1).unwrap();
txq.import(tx2).unwrap();
assert_eq!(txq.light_status().transaction_count, 1);
}
#[test]
fn should_reject_if_above_mem_usage() {
let b = TransactionBuilder::default();
let mut txq = TestPool::with_options(Options {
max_mem_usage: 1,
..Default::default()
});
// Reject second
let tx1 = b.tx().nonce(1).mem_usage(1).new();
let tx2 = b.tx().nonce(2).mem_usage(2).new();
let hash = format!("{:?}", tx2.hash());
txq.import(tx1).unwrap();
assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into()));
assert_eq!(txq.light_status().transaction_count, 1);
txq.clear();
// Replace first
let tx1 = b.tx().nonce(1).mem_usage(1).new();
let tx2 = b.tx().nonce(1).sender(1).gas_price(2).mem_usage(1).new();
txq.import(tx1).unwrap();
txq.import(tx2).unwrap();
assert_eq!(txq.light_status().transaction_count, 1);
}
#[test]
fn should_reject_if_above_sender_count() {
let b = TransactionBuilder::default();
let mut txq = TestPool::with_options(Options {
max_per_sender: 1,
..Default::default()
});
// Reject second
let tx1 = b.tx().nonce(1).new();
let tx2 = b.tx().nonce(2).new();
let hash = format!("{:x}", tx2.hash());
txq.import(tx1).unwrap();
assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into()));
assert_eq!(txq.light_status().transaction_count, 1);
txq.clear();
// Replace first
let tx1 = b.tx().nonce(1).new();
let tx2 = b.tx().nonce(2).gas_price(2).new();
let hash = format!("{:x}", tx2.hash());
txq.import(tx1).unwrap();
// This results in error because we also compare nonces
assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into()));
assert_eq!(txq.light_status().transaction_count, 1);
}
#[test]
fn should_construct_pending() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
let tx0 = txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
let tx1 = txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap();
let tx2 = txq.import(b.tx().nonce(2).new()).unwrap();
// this transaction doesn't get to the block despite high gas price
// because of block gas limit and simplistic ordering algorithm.
txq.import(b.tx().nonce(3).gas_price(4).new()).unwrap();
//gap
txq.import(b.tx().nonce(5).new()).unwrap();
let tx5 = txq.import(b.tx().sender(1).nonce(0).new()).unwrap();
let tx6 = txq.import(b.tx().sender(1).nonce(1).new()).unwrap();
let tx7 = txq.import(b.tx().sender(1).nonce(2).new()).unwrap();
let tx8 = txq.import(b.tx().sender(1).nonce(3).gas_price(4).new()).unwrap();
// gap
txq.import(b.tx().sender(1).nonce(5).new()).unwrap();
let tx9 = txq.import(b.tx().sender(2).nonce(0).new()).unwrap();
assert_eq!(txq.light_status().transaction_count, 11);
assert_eq!(txq.status(NonceReady::default()), Status {
stalled: 0,
pending: 9,
future: 2,
});
assert_eq!(txq.status(NonceReady::new(1)), Status {
stalled: 3,
pending: 6,
future: 2,
});
// when
let mut current_gas = U256::zero();
let limit = (21_000 * 8).into();
let mut pending = txq.pending(NonceReady::default()).take_while(|tx| {
let should_take = tx.gas + current_gas <= limit;
if should_take {
current_gas = current_gas + tx.gas
}
should_take
});
assert_eq!(pending.next(), Some(tx0));
assert_eq!(pending.next(), Some(tx1));
assert_eq!(pending.next(), Some(tx9));
assert_eq!(pending.next(), Some(tx5));
assert_eq!(pending.next(), Some(tx6));
assert_eq!(pending.next(), Some(tx7));
assert_eq!(pending.next(), Some(tx8));
assert_eq!(pending.next(), Some(tx2));
assert_eq!(pending.next(), None);
}
#[test]
fn should_return_unordered_iterator() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
let tx0 = txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
let tx1 = txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap();
let tx2 = txq.import(b.tx().nonce(2).new()).unwrap();
let tx3 = txq.import(b.tx().nonce(3).gas_price(4).new()).unwrap();
//gap
txq.import(b.tx().nonce(5).new()).unwrap();
let tx5 = txq.import(b.tx().sender(1).nonce(0).new()).unwrap();
let tx6 = txq.import(b.tx().sender(1).nonce(1).new()).unwrap();
let tx7 = txq.import(b.tx().sender(1).nonce(2).new()).unwrap();
let tx8 = txq.import(b.tx().sender(1).nonce(3).gas_price(4).new()).unwrap();
// gap
txq.import(b.tx().sender(1).nonce(5).new()).unwrap();
let tx9 = txq.import(b.tx().sender(2).nonce(0).new()).unwrap();
assert_eq!(txq.light_status().transaction_count, 11);
assert_eq!(txq.status(NonceReady::default()), Status {
stalled: 0,
pending: 9,
future: 2,
});
assert_eq!(txq.status(NonceReady::new(1)), Status {
stalled: 3,
pending: 6,
future: 2,
});
// when
let all: Vec<_> = txq.unordered_pending(NonceReady::default()).collect();
let chain1 = vec![tx0, tx1, tx2, tx3];
let chain2 = vec![tx5, tx6, tx7, tx8];
let chain3 = vec![tx9];
assert_eq!(all.len(), chain1.len() + chain2.len() + chain3.len());
let mut options = vec![
vec![chain1.clone(), chain2.clone(), chain3.clone()],
vec![chain2.clone(), chain1.clone(), chain3.clone()],
vec![chain2.clone(), chain3.clone(), chain1.clone()],
vec![chain3.clone(), chain2.clone(), chain1.clone()],
vec![chain3.clone(), chain1.clone(), chain2.clone()],
vec![chain1.clone(), chain3.clone(), chain2.clone()],
].into_iter().map(|mut v| {
let mut first = v.pop().unwrap();
for mut x in v {
first.append(&mut x);
}
first
});
assert!(options.any(|opt| all == opt));
}
#[test]
fn should_update_scoring_correctly() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
let tx0 = txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
let tx1 = txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap();
let tx2 = txq.import(b.tx().nonce(2).new()).unwrap();
// this transaction doesn't get to the block despite high gas price
// because of block gas limit and simplistic ordering algorithm.
txq.import(b.tx().nonce(3).gas_price(4).new()).unwrap();
//gap
txq.import(b.tx().nonce(5).new()).unwrap();
let tx5 = txq.import(b.tx().sender(1).nonce(0).new()).unwrap();
let tx6 = txq.import(b.tx().sender(1).nonce(1).new()).unwrap();
let tx7 = txq.import(b.tx().sender(1).nonce(2).new()).unwrap();
let tx8 = txq.import(b.tx().sender(1).nonce(3).gas_price(4).new()).unwrap();
// gap
txq.import(b.tx().sender(1).nonce(5).new()).unwrap();
let tx9 = txq.import(b.tx().sender(2).nonce(0).new()).unwrap();
assert_eq!(txq.light_status().transaction_count, 11);
assert_eq!(txq.status(NonceReady::default()), Status {
stalled: 0,
pending: 9,
future: 2,
});
assert_eq!(txq.status(NonceReady::new(1)), Status {
stalled: 3,
pending: 6,
future: 2,
});
txq.update_scores(&0.into(), ());
// when
let mut current_gas = U256::zero();
let limit = (21_000 * 8).into();
let mut pending = txq.pending(NonceReady::default()).take_while(|tx| {
let should_take = tx.gas + current_gas <= limit;
if should_take {
current_gas = current_gas + tx.gas
}
should_take
});
assert_eq!(pending.next(), Some(tx9));
assert_eq!(pending.next(), Some(tx5));
assert_eq!(pending.next(), Some(tx6));
assert_eq!(pending.next(), Some(tx7));
assert_eq!(pending.next(), Some(tx8));
// penalized transactions
assert_eq!(pending.next(), Some(tx0));
assert_eq!(pending.next(), Some(tx1));
assert_eq!(pending.next(), Some(tx2));
assert_eq!(pending.next(), None);
}
#[test]
fn should_remove_transaction() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
let tx1 = txq.import(b.tx().nonce(0).new()).unwrap();
let tx2 = txq.import(b.tx().nonce(1).new()).unwrap();
txq.import(b.tx().nonce(2).new()).unwrap();
assert_eq!(txq.light_status().transaction_count, 3);
// when
assert!(txq.remove(&tx2.hash(), false).is_some());
// then
assert_eq!(txq.light_status().transaction_count, 2);
let mut pending = txq.pending(NonceReady::default());
assert_eq!(pending.next(), Some(tx1));
assert_eq!(pending.next(), None);
}
#[test]
fn should_cull_stalled_transactions() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
txq.import(b.tx().nonce(1).new()).unwrap();
txq.import(b.tx().nonce(3).new()).unwrap();
txq.import(b.tx().sender(1).nonce(0).new()).unwrap();
txq.import(b.tx().sender(1).nonce(1).new()).unwrap();
txq.import(b.tx().sender(1).nonce(5).new()).unwrap();
assert_eq!(txq.status(NonceReady::new(1)), Status {
stalled: 2,
pending: 2,
future: 2,
});
// when
assert_eq!(txq.cull(None, NonceReady::new(1)), 2);
// then
assert_eq!(txq.status(NonceReady::new(1)), Status {
stalled: 0,
pending: 2,
future: 2,
});
assert_eq!(txq.light_status(), LightStatus {
transaction_count: 4,
senders: 2,
mem_usage: 0,
});
}
#[test]
fn should_cull_stalled_transactions_from_a_sender() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
txq.import(b.tx().nonce(1).new()).unwrap();
txq.import(b.tx().sender(1).nonce(0).new()).unwrap();
txq.import(b.tx().sender(1).nonce(1).new()).unwrap();
txq.import(b.tx().sender(1).nonce(2).new()).unwrap();
assert_eq!(txq.status(NonceReady::new(2)), Status {
stalled: 4,
pending: 1,
future: 0,
});
// when
let sender = 0.into();
assert_eq!(txq.cull(Some(&[sender]), NonceReady::new(2)), 2);
// then
assert_eq!(txq.status(NonceReady::new(2)), Status {
stalled: 2,
pending: 1,
future: 0,
});
assert_eq!(txq.light_status(), LightStatus {
transaction_count: 3,
senders: 1,
mem_usage: 0,
});
}
#[test]
fn should_re_insert_after_cull() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
txq.import(b.tx().nonce(1).new()).unwrap();
txq.import(b.tx().sender(1).nonce(0).new()).unwrap();
txq.import(b.tx().sender(1).nonce(1).new()).unwrap();
assert_eq!(txq.status(NonceReady::new(1)), Status {
stalled: 2,
pending: 2,
future: 0,
});
// when
assert_eq!(txq.cull(None, NonceReady::new(1)), 2);
assert_eq!(txq.status(NonceReady::new(1)), Status {
stalled: 0,
pending: 2,
future: 0,
});
txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
txq.import(b.tx().sender(1).nonce(0).new()).unwrap();
assert_eq!(txq.status(NonceReady::new(1)), Status {
stalled: 2,
pending: 2,
future: 0,
});
}
#[test]
fn should_return_worst_transaction() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
assert!(txq.worst_transaction().is_none());
// when
txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
txq.import(b.tx().sender(1).nonce(0).gas_price(4).new()).unwrap();
// then
assert_eq!(txq.worst_transaction().unwrap().gas_price, 4.into());
}
#[test]
fn should_return_is_full() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::with_limit(2);
assert!(!txq.is_full());
// when
txq.import(b.tx().nonce(0).gas_price(110).new()).unwrap();
assert!(!txq.is_full());
txq.import(b.tx().sender(1).nonce(0).gas_price(100).new()).unwrap();
// then
assert!(txq.is_full());
}
#[test]
fn should_import_even_if_limit_is_reached_and_should_replace_returns_insert_new() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::with_scoring(DummyScoring::always_insert(), Options {
max_count: 1,
..Default::default()
});
txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
assert_eq!(txq.light_status(), LightStatus {
transaction_count: 1,
senders: 1,
mem_usage: 0,
});
// when
txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap();
// then
assert_eq!(txq.light_status(), LightStatus {
transaction_count: 2,
senders: 1,
mem_usage: 0,
});
}
#[test]
fn should_not_import_even_if_limit_is_reached_and_should_replace_returns_false() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::with_scoring(DummyScoring::default(), Options {
max_count: 1,
..Default::default()
});
txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
assert_eq!(txq.light_status(), LightStatus {
transaction_count: 1,
senders: 1,
mem_usage: 0,
});
// when
let err = txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap_err();
// then
assert_eq!(err.kind(),
&error::ErrorKind::TooCheapToEnter("0x00000000000000000000000000000000000000000000000000000000000001f5".into(), "0x5".into()));
assert_eq!(txq.light_status(), LightStatus {
transaction_count: 1,
senders: 1,
mem_usage: 0,
});
}
#[test]
fn should_import_even_if_sender_limit_is_reached() {
// given
let b = TransactionBuilder::default();
let mut txq = TestPool::with_scoring(DummyScoring::always_insert(), Options {
max_count: 1,
max_per_sender: 1,
..Default::default()
});
txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
assert_eq!(txq.light_status(), LightStatus {
transaction_count: 1,
senders: 1,
mem_usage: 0,
});
// when
txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap();
// then
assert_eq!(txq.light_status(), LightStatus {
transaction_count: 2,
senders: 1,
mem_usage: 0,
});
}
mod listener {
use std::cell::RefCell;
use std::rc::Rc;
use super::*;
#[derive(Default)]
struct MyListener(pub Rc<RefCell<Vec<&'static str>>>);
impl Listener<Transaction> for MyListener {
fn added(&mut self, _tx: &SharedTransaction, old: Option<&SharedTransaction>) {
self.0.borrow_mut().push(if old.is_some() { "replaced" } else { "added" });
}
fn rejected(&mut self, _tx: &SharedTransaction, _reason: &error::ErrorKind) {
self.0.borrow_mut().push("rejected".into());
}
fn dropped(&mut self, _tx: &SharedTransaction, _new: Option<&Transaction>) {
self.0.borrow_mut().push("dropped".into());
}
fn invalid(&mut self, _tx: &SharedTransaction) {
self.0.borrow_mut().push("invalid".into());
}
fn canceled(&mut self, _tx: &SharedTransaction) {
self.0.borrow_mut().push("canceled".into());
}
fn culled(&mut self, _tx: &SharedTransaction) {
self.0.borrow_mut().push("culled".into());
}
}
#[test]
fn insert_transaction() {
let b = TransactionBuilder::default();
let listener = MyListener::default();
let results = listener.0.clone();
let mut txq = Pool::new(listener, DummyScoring::default(), Options {
max_per_sender: 1,
max_count: 2,
..Default::default()
});
assert!(results.borrow().is_empty());
// Regular import
txq.import(b.tx().nonce(1).new()).unwrap();
assert_eq!(*results.borrow(), &["added"]);
// Already present (no notification)
txq.import(b.tx().nonce(1).new()).unwrap_err();
assert_eq!(*results.borrow(), &["added"]);
// Push out the first one
txq.import(b.tx().nonce(1).gas_price(1).new()).unwrap();
assert_eq!(*results.borrow(), &["added", "replaced"]);
// Reject
txq.import(b.tx().nonce(1).new()).unwrap_err();
assert_eq!(*results.borrow(), &["added", "replaced", "rejected"]);
results.borrow_mut().clear();
// Different sender (accept)
txq.import(b.tx().sender(1).nonce(1).gas_price(2).new()).unwrap();
assert_eq!(*results.borrow(), &["added"]);
// Third sender push out low gas price
txq.import(b.tx().sender(2).nonce(1).gas_price(4).new()).unwrap();
assert_eq!(*results.borrow(), &["added", "dropped", "added"]);
// Reject (too cheap)
txq.import(b.tx().sender(2).nonce(1).gas_price(2).new()).unwrap_err();
assert_eq!(*results.borrow(), &["added", "dropped", "added", "rejected"]);
assert_eq!(txq.light_status().transaction_count, 2);
}
#[test]
fn remove_transaction() {
let b = TransactionBuilder::default();
let listener = MyListener::default();
let results = listener.0.clone();
let mut txq = Pool::new(listener, DummyScoring::default(), Options::default());
// insert
let tx1 = txq.import(b.tx().nonce(1).new()).unwrap();
let tx2 = txq.import(b.tx().nonce(2).new()).unwrap();
// then
txq.remove(&tx1.hash(), false);
assert_eq!(*results.borrow(), &["added", "added", "canceled"]);
txq.remove(&tx2.hash(), true);
assert_eq!(*results.borrow(), &["added", "added", "canceled", "invalid"]);
assert_eq!(txq.light_status().transaction_count, 0);
}
#[test]
fn clear_queue() {
let b = TransactionBuilder::default();
let listener = MyListener::default();
let results = listener.0.clone();
let mut txq = Pool::new(listener, DummyScoring::default(), Options::default());
// insert
txq.import(b.tx().nonce(1).new()).unwrap();
txq.import(b.tx().nonce(2).new()).unwrap();
// when
txq.clear();
// then
assert_eq!(*results.borrow(), &["added", "added", "dropped", "dropped"]);
}
#[test]
fn cull_stalled() {
let b = TransactionBuilder::default();
let listener = MyListener::default();
let results = listener.0.clone();
let mut txq = Pool::new(listener, DummyScoring::default(), Options::default());
// insert
txq.import(b.tx().nonce(1).new()).unwrap();
txq.import(b.tx().nonce(2).new()).unwrap();
// when
txq.cull(None, NonceReady::new(3));
// then
assert_eq!(*results.borrow(), &["added", "added", "culled", "culled"]);
}
}

View File

@@ -1,64 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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 super::{Transaction, U256, Address};
#[derive(Debug, Default, Clone)]
pub struct TransactionBuilder {
nonce: U256,
gas_price: U256,
gas: U256,
sender: Address,
mem_usage: usize,
}
impl TransactionBuilder {
pub fn tx(&self) -> Self {
self.clone()
}
pub fn nonce<T: Into<U256>>(mut self, nonce: T) -> Self {
self.nonce = nonce.into();
self
}
pub fn gas_price<T: Into<U256>>(mut self, gas_price: T) -> Self {
self.gas_price = gas_price.into();
self
}
pub fn sender<T: Into<Address>>(mut self, sender: T) -> Self {
self.sender = sender.into();
self
}
pub fn mem_usage(mut self, mem_usage: usize) -> Self {
self.mem_usage = mem_usage;
self
}
pub fn new(self) -> Transaction {
let hash = self.nonce ^ (U256::from(100) * self.gas_price) ^ (U256::from(100_000) * U256::from(self.sender.low_u64()));
Transaction {
hash: hash.into(),
nonce: self.nonce,
gas_price: self.gas_price,
gas: 21_000.into(),
sender: self.sender,
mem_usage: self.mem_usage,
}
}
}

View File

@@ -1,221 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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 std::{fmt, mem};
use smallvec::SmallVec;
use ready::{Ready, Readiness};
use scoring::{self, Scoring};
use pool::Transaction;
#[derive(Debug)]
pub enum AddResult<T, S> {
Ok(T),
TooCheapToEnter(T, S),
TooCheap {
old: T,
new: T,
},
Replaced {
old: T,
new: T,
},
PushedOut {
old: T,
new: T,
},
}
/// Represents all transactions from a particular sender ordered by nonce.
const PER_SENDER: usize = 8;
#[derive(Debug)]
pub struct Transactions<T, S: Scoring<T>> {
// TODO [ToDr] Consider using something that doesn't require shifting all records.
transactions: SmallVec<[Transaction<T>; PER_SENDER]>,
scores: SmallVec<[S::Score; PER_SENDER]>,
}
impl<T, S: Scoring<T>> Default for Transactions<T, S> {
fn default() -> Self {
Transactions {
transactions: Default::default(),
scores: Default::default(),
}
}
}
impl<T: fmt::Debug, S: Scoring<T>> Transactions<T, S> {
pub fn is_empty(&self) -> bool {
self.transactions.is_empty()
}
pub fn len(&self) -> usize {
self.transactions.len()
}
pub fn iter(&self) -> ::std::slice::Iter<Transaction<T>> {
self.transactions.iter()
}
pub fn worst_and_best(&self) -> Option<((S::Score, Transaction<T>), (S::Score, Transaction<T>))> {
let len = self.scores.len();
self.scores.get(0).cloned().map(|best| {
let worst = self.scores[len - 1].clone();
let best_tx = self.transactions[0].clone();
let worst_tx = self.transactions[len - 1].clone();
((worst, worst_tx), (best, best_tx))
})
}
pub fn find_next(&self, tx: &T, scoring: &S) -> Option<(S::Score, Transaction<T>)> {
self.transactions.binary_search_by(|old| scoring.compare(old, &tx)).ok().and_then(|index| {
let index = index + 1;
if index < self.scores.len() {
Some((self.scores[index].clone(), self.transactions[index].clone()))
} else {
None
}
})
}
fn push_cheapest_transaction(&mut self, tx: Transaction<T>, scoring: &S, max_count: usize) -> AddResult<Transaction<T>, S::Score> {
let index = self.transactions.len();
if index == max_count && !scoring.should_ignore_sender_limit(&tx) {
let min_score = self.scores[index - 1].clone();
AddResult::TooCheapToEnter(tx, min_score)
} else {
self.transactions.push(tx.clone());
self.scores.push(Default::default());
scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::InsertedAt(index));
AddResult::Ok(tx)
}
}
pub fn update_scores(&mut self, scoring: &S, event: S::Event) {
scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::Event(event));
}
pub fn add(&mut self, new: Transaction<T>, scoring: &S, max_count: usize) -> AddResult<Transaction<T>, S::Score> {
let index = match self.transactions.binary_search_by(|old| scoring.compare(old, &new)) {
Ok(index) => index,
Err(index) => index,
};
// Insert at the end.
if index == self.transactions.len() {
return self.push_cheapest_transaction(new, scoring, max_count)
}
// Decide if the transaction should replace some other.
match scoring.choose(&self.transactions[index], &new) {
// New transaction should be rejected
scoring::Choice::RejectNew => AddResult::TooCheap {
old: self.transactions[index].clone(),
new,
},
// New transaction should be kept along with old ones.
scoring::Choice::InsertNew => {
self.transactions.insert(index, new.clone());
self.scores.insert(index, Default::default());
scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::InsertedAt(index));
if self.transactions.len() > max_count {
let old = self.transactions.pop().expect("len is non-zero");
self.scores.pop();
scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::RemovedAt(self.transactions.len()));
AddResult::PushedOut {
old,
new,
}
} else {
AddResult::Ok(new)
}
},
// New transaction is replacing some other transaction already in the queue.
scoring::Choice::ReplaceOld => {
let old = mem::replace(&mut self.transactions[index], new.clone());
scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::ReplacedAt(index));
AddResult::Replaced {
old,
new,
}
},
}
}
pub fn remove(&mut self, tx: &T, scoring: &S) -> bool {
let index = match self.transactions.binary_search_by(|old| scoring.compare(old, tx)) {
Ok(index) => index,
Err(_) => {
warn!("Attempting to remove non-existent transaction {:?}", tx);
return false;
},
};
self.transactions.remove(index);
self.scores.remove(index);
// Update scoring
scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::RemovedAt(index));
return true;
}
pub fn cull<R: Ready<T>>(&mut self, ready: &mut R, scoring: &S) -> SmallVec<[Transaction<T>; PER_SENDER]> {
let mut result = SmallVec::new();
if self.is_empty() {
return result;
}
let mut first_non_stalled = 0;
for tx in &self.transactions {
match ready.is_ready(tx) {
Readiness::Stale => {
first_non_stalled += 1;
},
Readiness::Ready | Readiness::Future => break,
}
}
if first_non_stalled == 0 {
return result;
}
// reverse the vectors to easily remove first elements.
self.transactions.reverse();
self.scores.reverse();
for _ in 0..first_non_stalled {
self.scores.pop();
result.push(
self.transactions.pop().expect("first_non_stalled is never greater than transactions.len(); qed")
);
}
self.transactions.reverse();
self.scores.reverse();
// update scoring
scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::Culled(result.len()));
// reverse the result to maintain correct order.
result.reverse();
result
}
}

View File

@@ -1,31 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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 {VerifiedTransaction};
/// Transaction verification.
///
/// Verifier is responsible to decide if the transaction should even be considered for pool inclusion.
pub trait Verifier<U> {
/// Verification error.
type Error;
/// Verified transaction.
type VerifiedTransaction: VerifiedTransaction;
/// Verifies a `UnverifiedTransaction` and produces `VerifiedTransaction` instance.
fn verify_transaction(&self, tx: U) -> Result<Self::VerifiedTransaction, Self::Error>;
}

View File

@@ -6,22 +6,22 @@ license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
keccak-hash = "0.1"
lazy_static = "1.0"
log = "0.4"
ethabi = "5.1"
ethabi-derive = "5.0"
ethabi-contract = "5.0"
ethabi = "5.1.2"
ethabi-derive = "5.1.3"
ethabi-contract = "5.1.1"
target_info = "0.1"
semver = "0.9"
ethcore = { path = "../ethcore" }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
ethcore-sync = { path = "../ethcore/sync" }
ethereum-types = "0.3"
ethereum-types = "0.4"
parking_lot = "0.6"
parity-hash-fetch = { path = "../hash-fetch" }
parity-version = { path = "../util/version" }
path = { git = "https://github.com/paritytech/parity-common" }
parity-path = "0.1"
rand = "0.4"
[dev-dependencies]

View File

@@ -27,7 +27,7 @@ extern crate keccak_hash as hash;
extern crate parity_hash_fetch as hash_fetch;
extern crate parity_version as version;
extern crate parking_lot;
extern crate path;
extern crate parity_path;
extern crate rand;
extern crate semver;
extern crate target_info;

View File

@@ -31,7 +31,7 @@ use ethcore::client::{BlockId, BlockChainClient, ChainNotify, ChainRoute};
use ethcore::filter::Filter;
use ethereum_types::H256;
use hash_fetch::{self as fetch, HashFetch};
use path::restrict_permissions_owner;
use parity_path::restrict_permissions_owner;
use service::Service;
use sync::{SyncProvider};
use types::{ReleaseInfo, OperationsInfo, CapState, VersionInfo, ReleaseTrack};

View File

@@ -5,7 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
license = "GPL3"
[dependencies]
ethereum-types = "0.3"
ethereum-types = "0.4"
journaldb = { path = "../journaldb" }
app_dirs = { git = "https://github.com/paritytech/app-dirs-rs" }
home = "0.3"

View File

@@ -6,5 +6,5 @@ license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
ethereum-types = "0.3"
ethereum-types = "0.4"
ethkey = { path = "../../ethkey" }

View File

@@ -6,5 +6,5 @@ description = "Specialized version of `HashMap` with H256 keys and fast hashing
license = "GPL-3.0"
[dependencies]
ethereum-types = "0.3"
plain_hasher = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.4"
plain_hasher = "0.2"

View File

@@ -6,19 +6,19 @@ description = "A `HashDB` which can manage a short-term journal potentially cont
license = "GPL3"
[dependencies]
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.3"
hashdb = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
ethereum-types = "0.4"
hashdb = "0.2.1"
heapsize = "0.4"
keccak-hasher = { path = "../keccak-hasher" }
kvdb = "0.1.0"
kvdb = "0.1"
log = "0.4"
memorydb = { git = "https://github.com/paritytech/parity-common" }
memorydb = "0.2.1"
parking_lot = "0.6"
fastmap = { path = "../../util/fastmap" }
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
[dev-dependencies]
ethcore-logger = { path = "../../logger" }
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
kvdb-memorydb = "0.1.0"
keccak-hash = "0.1"
kvdb-memorydb = "0.1"

View File

@@ -1,12 +1,12 @@
[package]
name = "keccak-hasher"
version = "0.1.0"
version = "0.1.1"
authors = ["Parity Technologies <admin@parity.io>"]
description = "Keccak-256 implementation of the Hasher trait"
license = "GPL-3.0"
[dependencies]
ethereum-types = "0.3"
ethereum-types = "0.4"
tiny-keccak = "1.4.2"
hashdb = { git = "https://github.com/paritytech/parity-common" }
plain_hasher = { git = "https://github.com/paritytech/parity-common" }
hashdb = "0.2.1"
plain_hasher = "0.2"

View File

@@ -6,7 +6,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
log = "0.4"
macros = { path = "../macros" }
kvdb = "0.1.0"
kvdb = "0.1"
kvdb-rocksdb = "0.1.3"
[dev-dependencies]

View File

@@ -20,17 +20,17 @@ parking_lot = "0.6"
ansi_term = "0.10"
rustc-hex = "1.0"
ethcore-io = { path = "../io", features = ["mio"] }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
parity-crypto = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
parity-crypto = "0.1"
ethcore-logger = { path ="../../logger" }
ethcore-network = { path = "../network" }
ethereum-types = "0.3"
ethereum-types = "0.4"
ethkey = { path = "../../ethkey" }
rlp = { git = "https://github.com/paritytech/parity-common" }
path = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
parity-path = "0.1"
ipnetwork = "0.12.6"
keccak-hash = { git = "https://github.com/paritytech/parity-common" }
parity-snappy = "0.1.0"
keccak-hash = "0.1"
parity-snappy = "0.1"
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"

View File

@@ -43,7 +43,7 @@ use network::{NonReservedPeerMode, NetworkContext as NetworkContextTrait};
use network::{SessionInfo, Error, ErrorKind, DisconnectReason, NetworkProtocolHandler};
use discovery::{Discovery, TableUpdates, NodeEntry, MAX_DATAGRAM_SIZE};
use ip_utils::{map_external_address, select_public_address};
use path::restrict_permissions_owner;
use parity_path::restrict_permissions_owner;
use parking_lot::{Mutex, RwLock};
use network::{ConnectionFilter, ConnectionDirection};

View File

@@ -77,7 +77,7 @@ extern crate slab;
extern crate ethkey;
extern crate rlp;
extern crate bytes;
extern crate path;
extern crate parity_path;
extern crate ethcore_logger;
extern crate ethcore_network as network;
extern crate ipnetwork;

View File

@@ -8,15 +8,14 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
error-chain = { version = "0.12", default-features = false }
parity-crypto = { git = "https://github.com/paritytech/parity-common" }
parity-crypto = "0.1"
ethcore-io = { path = "../io" }
ethereum-types = "0.3"
ethereum-types = "0.4"
ethkey = { path = "../../ethkey" }
ipnetwork = "0.12.6"
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
libc = "0.2"
parity-snappy = "0.1.0"
parity-snappy = "0.1"
[dev-dependencies]
assert_matches = "1.2"

View File

@@ -6,10 +6,14 @@ description = "Merkle-Patricia Trie (Ethereum Style)"
license = "GPL-3.0"
[dependencies]
patricia-trie = { git = "https://github.com/paritytech/parity-common" }
keccak-hasher = { path = "../keccak-hasher" }
hashdb = { git = "https://github.com/paritytech/parity-common" }
rlp = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.3"
elastic-array = "0.10"
patricia-trie = "0.2.1"
keccak-hasher = { version = "0.1.1", path = "../keccak-hasher" }
hashdb = "0.2"
rlp = { version = "0.2.4", features = ["ethereum"] }
parity-bytes = "0.1"
ethereum-types = "0.4"
elastic-array = "0.10"
[dev-dependencies]
memorydb = "0.2.1"
keccak-hash = "0.1.2"

View File

@@ -36,6 +36,36 @@ use rlp::DecoderError;
pub type RlpCodec = RlpNodeCodec<KeccakHasher>;
/// Convenience type alias to instantiate a Keccak/Rlp-flavoured `TrieDB`
///
/// Use it as a `Trie` trait object. You can use `db()` to get the backing database object.
/// Use `get` and `contains` to query values associated with keys in the trie.
///
/// # Example
/// ```
/// extern crate patricia_trie as trie;
/// extern crate patricia_trie_ethereum as ethtrie;
/// extern crate hashdb;
/// extern crate keccak_hasher;
/// extern crate memorydb;
/// extern crate ethereum_types;
///
/// use trie::*;
/// use hashdb::*;
/// use keccak_hasher::KeccakHasher;
/// use memorydb::*;
/// use ethereum_types::H256;
/// use ethtrie::{TrieDB, TrieDBMut};
///
///
/// fn main() {
/// let mut memdb = MemoryDB::<KeccakHasher>::new();
/// let mut root = H256::new();
/// TrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar").unwrap();
/// let t = TrieDB::new(&memdb, &root).unwrap();
/// assert!(t.contains(b"foo").unwrap());
/// assert_eq!(t.get(b"foo").unwrap().unwrap(), DBValue::from_slice(b"bar"));
/// }
/// ```
pub type TrieDB<'db> = trie::TrieDB<'db, KeccakHasher, RlpCodec>;
/// Convenience type alias to instantiate a Keccak/Rlp-flavoured `SecTrieDB`
@@ -45,6 +75,41 @@ pub type SecTrieDB<'db> = trie::SecTrieDB<'db, KeccakHasher, RlpCodec>;
pub type FatDB<'db> = trie::FatDB<'db, KeccakHasher, RlpCodec>;
/// Convenience type alias to instantiate a Keccak/Rlp-flavoured `TrieDBMut`
///
/// Use it as a `TrieMut` trait object. You can use `db()` to get the backing database object.
/// Note that changes are not committed to the database until `commit` is called.
/// Querying the root or dropping the trie will commit automatically.
/// # Example
/// ```
/// extern crate patricia_trie as trie;
/// extern crate patricia_trie_ethereum as ethtrie;
/// extern crate hashdb;
/// extern crate keccak_hash;
/// extern crate keccak_hasher;
/// extern crate memorydb;
/// extern crate ethereum_types;
///
/// use keccak_hash::KECCAK_NULL_RLP;
/// use ethtrie::{TrieDBMut, trie::TrieMut};
/// use hashdb::DBValue;
/// use keccak_hasher::KeccakHasher;
/// use memorydb::*;
/// use ethereum_types::H256;
///
/// fn main() {
/// let mut memdb = MemoryDB::<KeccakHasher>::new();
/// let mut root = H256::new();
/// let mut t = TrieDBMut::new(&mut memdb, &mut root);
/// assert!(t.is_empty());
/// assert_eq!(*t.root(), KECCAK_NULL_RLP);
/// t.insert(b"foo", b"bar").unwrap();
/// assert!(t.contains(b"foo").unwrap());
/// assert_eq!(t.get(b"foo").unwrap().unwrap(), DBValue::from_slice(b"bar"));
/// t.remove(b"foo").unwrap();
/// assert!(!t.contains(b"foo").unwrap());
/// }
/// ```
pub type TrieDBMut<'db> = trie::TrieDBMut<'db, KeccakHasher, RlpCodec>;
/// Convenience type alias to instantiate a Keccak/Rlp-flavoured `SecTrieDBMut`

View File

@@ -4,6 +4,6 @@ version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = "0.2.4"
elastic-array = "0.10"
lazy_static = "1.0"

View File

@@ -12,4 +12,4 @@ syn = "0.13"
quote = "0.5"
[dev-dependencies]
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = "0.2.4"

View File

@@ -1,9 +0,0 @@
[package]
name = "trace-time"
description = "Easily trace time to execute a scope."
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "GPL-3.0"
[dependencies]
log = "0.4"

View File

@@ -1,55 +0,0 @@
// Copyright 2015-2018 Parity Technologies (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/>.
//! Performance timer with logging
#[macro_use]
extern crate log;
use std::time::Instant;
#[macro_export]
macro_rules! trace_time {
($name: expr) => {
let _timer = $crate::PerfTimer::new($name);
}
}
/// Performance timer with logging. Starts measuring time in the constructor, prints
/// elapsed time in the destructor or when `stop` is called.
pub struct PerfTimer {
name: &'static str,
start: Instant,
}
impl PerfTimer {
/// Create an instance with given name.
pub fn new(name: &'static str) -> PerfTimer {
PerfTimer {
name,
start: Instant::now(),
}
}
}
impl Drop for PerfTimer {
fn drop(&mut self) {
let elapsed = self.start.elapsed();
let ms = elapsed.subsec_nanos() as f32 / 1_000_000.0 +
elapsed.as_secs() as f32 * 1_000.0;
trace!(target: "perf", "{}: {:.2}ms", self.name, ms);
}
}

View File

@@ -6,6 +6,6 @@ description = "Trie-root helpers, ethereum style"
license = "GPL-3.0"
[dependencies]
triehash = { git = "https://github.com/paritytech/parity-common" }
ethereum-types = "0.3"
keccak-hasher = { path = "../keccak-hasher" }
triehash = { version = "0.2.3", features = ["ethereum"] }
ethereum-types = "0.4"
keccak-hasher = { path = "../keccak-hasher" }

View File

@@ -21,8 +21,8 @@ ropsten = { forkBlock = 10, critical = false }
kovan = { forkBlock = 6600000, critical = false }
[dependencies]
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
rlp = { git = "https://github.com/paritytech/parity-common" }
parity-bytes = "0.1"
rlp = { version = "0.2.4", features = ["ethereum"] }
target_info = "0.1"
[build-dependencies]

View File

@@ -7,9 +7,9 @@ description = "Whisper Protocol implementation for Parity"
[dependencies]
bitflags = "0.9"
byteorder = "1.0.0"
ethereum-types = "0.3"
ethereum-types = "0.4"
ethcore-network = { path = "../util/network" }
parity-crypto = { git = "https://github.com/paritytech/parity-common" }
parity-crypto = "0.1"
ethkey = { path = "../ethkey" }
hex = "0.2"
log = "0.4"
@@ -17,7 +17,7 @@ mem = { path = "../util/mem" }
ordered-float = "0.5"
parking_lot = "0.6"
rand = "0.4"
rlp = { git = "https://github.com/paritytech/parity-common" }
rlp = { version = "0.2.4", features = ["ethereum"] }
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"

View File

@@ -19,7 +19,7 @@
use std::fmt;
use std::ops::Deref;
use ethereum_types::{H32, H64, H128, H256, H264, H512, H1024};
use ethereum_types::{H32, H64, H128, H256, H264, H512};
use hex::{ToHex, FromHex};
use serde::{Serialize, Serializer, Deserialize, Deserializer};
@@ -51,7 +51,7 @@ macro_rules! impl_hex_for_hash {
}
impl_hex_for_hash!(
H32 H64 H128 H256 H264 H512 H1024
H32 H64 H128 H256 H264 H512
);
/// Wrapper structure around hex-encoded data.