Backports for stable 2.1.10 (#10046)
* bump stable to 2.1.10 * RPC: parity_getBlockReceipts (#9527) * Block receipts RPC. * Use lazy evaluation of block receipts (ecrecover). * Optimize transaction_receipt to prevent performance regression. * Fix RPC grumbles. * Add block & transaction receipt tests. * Fix conversion to block id. * Update a few parity-common dependencies (#9663) * Update a few parity-common dependencies * cleanup * cleanup * revert update of ethereum/tests * better reporting of network rlp errors * Use rlp 0.3.0-beta.1 * fix util function get_dummy_blocks * Already a Vec * encode_list returns vec already * Address grumble * No need for betas * Fix double spaces * Fix empty steps (#9939) * Don't send empty step twice or empty step then block. * Perform basic validation of locally sealed blocks. * Don't include empty step twice. * Strict empty steps validation (#10041) * Add two failings tests for strict empty steps. * Implement strict validation of empty steps. * ethcore: enable constantinople on ethereum (#10031) * ethcore: change blockreward to 2e18 for foundation after constantinople * ethcore: delay diff bomb by 2e6 blocks for foundation after constantinople * ethcore: enable eip-{145,1014,1052,1283} for foundation after constantinople * Change test miner max memory to malloc reports. (#10024) * Bump crossbeam. (#10048) * Revert "Bump crossbeam. (#10048)" This reverts commit ed1db0c2d3d3b8e6bfde3124fb03b093a264e241.
This commit is contained in:
@@ -58,7 +58,7 @@ impl Default for Factory {
|
||||
impl Factory {
|
||||
/// Create a read-only accountdb.
|
||||
/// This will panic when write operations are called.
|
||||
pub fn readonly<'db>(&self, db: &'db HashDB<KeccakHasher>, address_hash: H256) -> Box<HashDB<KeccakHasher> + 'db> {
|
||||
pub fn readonly<'db>(&self, db: &'db HashDB<KeccakHasher, DBValue>, address_hash: H256) -> Box<HashDB<KeccakHasher, DBValue> + 'db> {
|
||||
match *self {
|
||||
Factory::Mangled => Box::new(AccountDB::from_hash(db, address_hash)),
|
||||
Factory::Plain => Box::new(Wrapping(db)),
|
||||
@@ -66,7 +66,7 @@ impl Factory {
|
||||
}
|
||||
|
||||
/// Create a new mutable hashdb.
|
||||
pub fn create<'db>(&self, db: &'db mut HashDB<KeccakHasher>, address_hash: H256) -> Box<HashDB<KeccakHasher> + 'db> {
|
||||
pub fn create<'db>(&self, db: &'db mut HashDB<KeccakHasher, DBValue>, address_hash: H256) -> Box<HashDB<KeccakHasher, DBValue> + 'db> {
|
||||
match *self {
|
||||
Factory::Mangled => Box::new(AccountDBMut::from_hash(db, address_hash)),
|
||||
Factory::Plain => Box::new(WrappingMut(db)),
|
||||
@@ -78,19 +78,19 @@ impl Factory {
|
||||
/// DB backend wrapper for Account trie
|
||||
/// Transforms trie node keys for the database
|
||||
pub struct AccountDB<'db> {
|
||||
db: &'db HashDB<KeccakHasher>,
|
||||
db: &'db HashDB<KeccakHasher, DBValue>,
|
||||
address_hash: H256,
|
||||
}
|
||||
|
||||
impl<'db> AccountDB<'db> {
|
||||
/// Create a new AccountDB from an address.
|
||||
#[cfg(test)]
|
||||
pub fn new(db: &'db HashDB<KeccakHasher>, address: &Address) -> Self {
|
||||
pub fn new(db: &'db HashDB<KeccakHasher, DBValue>, address: &Address) -> Self {
|
||||
Self::from_hash(db, keccak(address))
|
||||
}
|
||||
|
||||
/// Create a new AcountDB from an address' hash.
|
||||
pub fn from_hash(db: &'db HashDB<KeccakHasher>, address_hash: H256) -> Self {
|
||||
pub fn from_hash(db: &'db HashDB<KeccakHasher, DBValue>, address_hash: H256) -> Self {
|
||||
AccountDB {
|
||||
db: db,
|
||||
address_hash: address_hash,
|
||||
@@ -98,12 +98,12 @@ impl<'db> AccountDB<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> AsHashDB<KeccakHasher> for AccountDB<'db> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
|
||||
impl<'db> AsHashDB<KeccakHasher, DBValue> for AccountDB<'db> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue> { self }
|
||||
}
|
||||
|
||||
impl<'db> HashDB<KeccakHasher> for AccountDB<'db> {
|
||||
impl<'db> HashDB<KeccakHasher, DBValue> for AccountDB<'db> {
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -137,19 +137,19 @@ impl<'db> HashDB<KeccakHasher> for AccountDB<'db> {
|
||||
|
||||
/// DB backend wrapper for Account trie
|
||||
pub struct AccountDBMut<'db> {
|
||||
db: &'db mut HashDB<KeccakHasher>,
|
||||
db: &'db mut HashDB<KeccakHasher, DBValue>,
|
||||
address_hash: H256,
|
||||
}
|
||||
|
||||
impl<'db> AccountDBMut<'db> {
|
||||
/// Create a new AccountDB from an address.
|
||||
#[cfg(test)]
|
||||
pub fn new(db: &'db mut HashDB<KeccakHasher>, address: &Address) -> Self {
|
||||
pub fn new(db: &'db mut HashDB<KeccakHasher, DBValue>, address: &Address) -> Self {
|
||||
Self::from_hash(db, keccak(address))
|
||||
}
|
||||
|
||||
/// Create a new AcountDB from an address' hash.
|
||||
pub fn from_hash(db: &'db mut HashDB<KeccakHasher>, address_hash: H256) -> Self {
|
||||
pub fn from_hash(db: &'db mut HashDB<KeccakHasher, DBValue>, address_hash: H256) -> Self {
|
||||
AccountDBMut {
|
||||
db: db,
|
||||
address_hash: address_hash,
|
||||
@@ -162,7 +162,7 @@ impl<'db> AccountDBMut<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> HashDB<KeccakHasher> for AccountDBMut<'db>{
|
||||
impl<'db> HashDB<KeccakHasher, DBValue> for AccountDBMut<'db>{
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -208,19 +208,19 @@ impl<'db> HashDB<KeccakHasher> for AccountDBMut<'db>{
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> AsHashDB<KeccakHasher> for AccountDBMut<'db> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
|
||||
impl<'db> AsHashDB<KeccakHasher, DBValue> for AccountDBMut<'db> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue> { self }
|
||||
}
|
||||
|
||||
struct Wrapping<'db>(&'db HashDB<KeccakHasher>);
|
||||
struct Wrapping<'db>(&'db HashDB<KeccakHasher, DBValue>);
|
||||
|
||||
impl<'db> AsHashDB<KeccakHasher> for Wrapping<'db> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
|
||||
impl<'db> AsHashDB<KeccakHasher, DBValue> for Wrapping<'db> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue> { self }
|
||||
}
|
||||
|
||||
impl<'db> HashDB<KeccakHasher> for Wrapping<'db> {
|
||||
impl<'db> HashDB<KeccakHasher, DBValue> for Wrapping<'db> {
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -252,13 +252,13 @@ impl<'db> HashDB<KeccakHasher> for Wrapping<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
struct WrappingMut<'db>(&'db mut HashDB<KeccakHasher>);
|
||||
impl<'db> AsHashDB<KeccakHasher> for WrappingMut<'db> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
|
||||
struct WrappingMut<'db>(&'db mut HashDB<KeccakHasher, DBValue>);
|
||||
impl<'db> AsHashDB<KeccakHasher, DBValue> for WrappingMut<'db> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue> { self }
|
||||
}
|
||||
|
||||
impl<'db> HashDB<KeccakHasher> for WrappingMut<'db>{
|
||||
impl<'db> HashDB<KeccakHasher, DBValue> for WrappingMut<'db>{
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@@ -160,11 +160,6 @@ pub trait BlockProvider {
|
||||
.and_then(|n| body.view().localized_transaction_at(&address.block_hash, n, address.index)))
|
||||
}
|
||||
|
||||
/// Get transaction receipt.
|
||||
fn transaction_receipt(&self, address: &TransactionAddress) -> Option<Receipt> {
|
||||
self.block_receipts(&address.block_hash).and_then(|br| br.receipts.into_iter().nth(address.index))
|
||||
}
|
||||
|
||||
/// Get a list of transactions for a given block.
|
||||
/// Returns None if block does not exist.
|
||||
fn transactions(&self, hash: &H256) -> Option<Vec<LocalizedTransaction>> {
|
||||
|
||||
@@ -51,7 +51,7 @@ impl Block {
|
||||
|
||||
#[inline]
|
||||
pub fn encoded(&self) -> encoded::Block {
|
||||
encoded::Block::new(encode(self).into_vec())
|
||||
encoded::Block::new(encode(self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -1795,26 +1795,49 @@ impl BlockChainClient for Client {
|
||||
}
|
||||
|
||||
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> {
|
||||
// NOTE Don't use block_receipts here for performance reasons
|
||||
let address = self.transaction_address(id)?;
|
||||
let hash = address.block_hash;
|
||||
let chain = self.chain.read();
|
||||
self.transaction_address(id)
|
||||
.and_then(|address| chain.block_number(&address.block_hash).and_then(|block_number| {
|
||||
let transaction = chain.block_body(&address.block_hash)
|
||||
.and_then(|body| body.view().localized_transaction_at(&address.block_hash, block_number, address.index));
|
||||
let number = chain.block_number(&hash)?;
|
||||
let body = chain.block_body(&hash)?;
|
||||
let mut receipts = chain.block_receipts(&hash)?.receipts;
|
||||
receipts.truncate(address.index + 1);
|
||||
|
||||
let previous_receipts = (0..address.index + 1)
|
||||
.map(|index| {
|
||||
let mut address = address.clone();
|
||||
address.index = index;
|
||||
chain.transaction_receipt(&address)
|
||||
})
|
||||
.collect();
|
||||
match (transaction, previous_receipts) {
|
||||
(Some(transaction), Some(previous_receipts)) => {
|
||||
Some(transaction_receipt(self.engine().machine(), transaction, previous_receipts))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}))
|
||||
let transaction = body.view().localized_transaction_at(&hash, number, address.index)?;
|
||||
let receipt = receipts.pop()?;
|
||||
let gas_used = receipts.last().map_or_else(|| 0.into(), |r| r.gas_used);
|
||||
let no_of_logs = receipts.into_iter().map(|receipt| receipt.logs.len()).sum::<usize>();
|
||||
|
||||
let receipt = transaction_receipt(self.engine().machine(), transaction, receipt, gas_used, no_of_logs);
|
||||
Some(receipt)
|
||||
}
|
||||
|
||||
fn block_receipts(&self, id: BlockId) -> Option<Vec<LocalizedReceipt>> {
|
||||
let hash = self.block_hash(id)?;
|
||||
|
||||
let chain = self.chain.read();
|
||||
let receipts = chain.block_receipts(&hash)?;
|
||||
let number = chain.block_number(&hash)?;
|
||||
let body = chain.block_body(&hash)?;
|
||||
let engine = self.engine.clone();
|
||||
|
||||
let mut gas_used = 0.into();
|
||||
let mut no_of_logs = 0;
|
||||
|
||||
Some(body
|
||||
.view()
|
||||
.localized_transactions(&hash, number)
|
||||
.into_iter()
|
||||
.zip(receipts.receipts)
|
||||
.map(move |(transaction, receipt)| {
|
||||
let result = transaction_receipt(engine.machine(), transaction, receipt, gas_used, no_of_logs);
|
||||
gas_used = result.cumulative_gas_used;
|
||||
no_of_logs += result.logs.len();
|
||||
result
|
||||
})
|
||||
.collect()
|
||||
)
|
||||
}
|
||||
|
||||
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> {
|
||||
@@ -1833,8 +1856,8 @@ impl BlockChainClient for Client {
|
||||
self.state_db.read().journal_db().state(hash)
|
||||
}
|
||||
|
||||
fn block_receipts(&self, hash: &H256) -> Option<Bytes> {
|
||||
self.chain.read().block_receipts(hash).map(|receipts| ::rlp::encode(&receipts).into_vec())
|
||||
fn encoded_block_receipts(&self, hash: &H256) -> Option<Bytes> {
|
||||
self.chain.read().block_receipts(hash).map(|receipts| ::rlp::encode(&receipts))
|
||||
}
|
||||
|
||||
fn queue_info(&self) -> BlockQueueInfo {
|
||||
@@ -2249,8 +2272,7 @@ impl ScheduleInfo for Client {
|
||||
}
|
||||
|
||||
impl ImportSealedBlock for Client {
|
||||
fn import_sealed_block(&self, block: SealedBlock) -> ImportResult {
|
||||
let h = block.header().hash();
|
||||
fn import_sealed_block(&self, block: SealedBlock) -> EthcoreResult<H256> {
|
||||
let start = Instant::now();
|
||||
let header = block.header().clone();
|
||||
let route = {
|
||||
@@ -2396,16 +2418,14 @@ impl Drop for Client {
|
||||
|
||||
/// Returns `LocalizedReceipt` given `LocalizedTransaction`
|
||||
/// and a vector of receipts from given block up to transaction index.
|
||||
fn transaction_receipt(machine: &::machine::EthereumMachine, mut tx: LocalizedTransaction, mut receipts: Vec<Receipt>) -> LocalizedReceipt {
|
||||
assert_eq!(receipts.len(), tx.transaction_index + 1, "All previous receipts are provided.");
|
||||
|
||||
fn transaction_receipt(
|
||||
machine: &::machine::EthereumMachine,
|
||||
mut tx: LocalizedTransaction,
|
||||
receipt: Receipt,
|
||||
prior_gas_used: U256,
|
||||
prior_no_of_logs: usize,
|
||||
) -> LocalizedReceipt {
|
||||
let sender = tx.sender();
|
||||
let receipt = receipts.pop().expect("Current receipt is provided; qed");
|
||||
let prior_gas_used = match tx.transaction_index {
|
||||
0 => 0.into(),
|
||||
i => receipts.get(i - 1).expect("All previous receipts are provided; qed").gas_used,
|
||||
};
|
||||
let no_of_logs = receipts.into_iter().map(|receipt| receipt.logs.len()).sum::<usize>();
|
||||
let transaction_hash = tx.hash();
|
||||
let block_hash = tx.block_hash;
|
||||
let block_number = tx.block_number;
|
||||
@@ -2434,7 +2454,7 @@ fn transaction_receipt(machine: &::machine::EthereumMachine, mut tx: LocalizedTr
|
||||
transaction_hash: transaction_hash,
|
||||
transaction_index: transaction_index,
|
||||
transaction_log_index: i,
|
||||
log_index: no_of_logs + i,
|
||||
log_index: prior_no_of_logs + i,
|
||||
}).collect(),
|
||||
log_bloom: receipt.log_bloom,
|
||||
outcome: receipt.outcome,
|
||||
@@ -2482,6 +2502,33 @@ mod tests {
|
||||
assert!(client.tree_route(&genesis, &new_hash).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_block_receipts() {
|
||||
use client::{BlockChainClient, BlockId, TransactionId};
|
||||
use test_helpers::{generate_dummy_client_with_data};
|
||||
|
||||
let client = generate_dummy_client_with_data(2, 2, &[1.into(), 1.into()]);
|
||||
let receipts = client.block_receipts(BlockId::Latest).unwrap();
|
||||
|
||||
assert_eq!(receipts.len(), 2);
|
||||
assert_eq!(receipts[0].transaction_index, 0);
|
||||
assert_eq!(receipts[0].block_number, 2);
|
||||
assert_eq!(receipts[0].cumulative_gas_used, 53_000.into());
|
||||
assert_eq!(receipts[0].gas_used, 53_000.into());
|
||||
|
||||
assert_eq!(receipts[1].transaction_index, 1);
|
||||
assert_eq!(receipts[1].block_number, 2);
|
||||
assert_eq!(receipts[1].cumulative_gas_used, 106_000.into());
|
||||
assert_eq!(receipts[1].gas_used, 53_000.into());
|
||||
|
||||
|
||||
let receipt = client.transaction_receipt(TransactionId::Hash(receipts[0].transaction_hash));
|
||||
assert_eq!(receipt, Some(receipts[0].clone()));
|
||||
|
||||
let receipt = client.transaction_receipt(TransactionId::Hash(receipts[1].transaction_hash));
|
||||
assert_eq!(receipt, Some(receipts[1].clone()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_correct_log_index() {
|
||||
use hash::keccak;
|
||||
@@ -2525,20 +2572,15 @@ mod tests {
|
||||
topics: vec![],
|
||||
data: vec![],
|
||||
}];
|
||||
let receipts = vec![Receipt {
|
||||
outcome: TransactionOutcome::StateRoot(state_root),
|
||||
gas_used: 5.into(),
|
||||
log_bloom: Default::default(),
|
||||
logs: vec![logs[0].clone()],
|
||||
}, Receipt {
|
||||
let receipt = Receipt {
|
||||
outcome: TransactionOutcome::StateRoot(state_root),
|
||||
gas_used: gas_used,
|
||||
log_bloom: Default::default(),
|
||||
logs: logs.clone(),
|
||||
}];
|
||||
};
|
||||
|
||||
// when
|
||||
let receipt = transaction_receipt(&machine, transaction, receipts);
|
||||
let receipt = transaction_receipt(&machine, transaction, receipt, 5.into(), 1);
|
||||
|
||||
// then
|
||||
assert_eq!(receipt, LocalizedReceipt {
|
||||
|
||||
@@ -686,6 +686,10 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
self.receipts.read().get(&id).cloned()
|
||||
}
|
||||
|
||||
fn block_receipts(&self, _id: BlockId) -> Option<Vec<LocalizedReceipt>> {
|
||||
Some(self.receipts.read().values().cloned().collect())
|
||||
}
|
||||
|
||||
fn logs(&self, filter: Filter) -> Result<Vec<LocalizedLogEntry>, BlockId> {
|
||||
match self.error_on_logs.read().as_ref() {
|
||||
Some(id) => return Err(id.clone()),
|
||||
@@ -785,7 +789,7 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
None
|
||||
}
|
||||
|
||||
fn block_receipts(&self, hash: &H256) -> Option<Bytes> {
|
||||
fn encoded_block_receipts(&self, hash: &H256) -> Option<Bytes> {
|
||||
// starts with 'f' ?
|
||||
if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") {
|
||||
let receipt = BlockReceipts::new(vec![Receipt::new(
|
||||
|
||||
@@ -42,7 +42,7 @@ use engines::EthEngine;
|
||||
use ethereum_types::{H256, U256, Address};
|
||||
use ethcore_miner::pool::VerifiedTransaction;
|
||||
use bytes::Bytes;
|
||||
use hashdb::DBValue;
|
||||
use kvdb::DBValue;
|
||||
|
||||
use types::ids::*;
|
||||
use types::basic_account::BasicAccount;
|
||||
@@ -281,6 +281,9 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra
|
||||
/// Get transaction receipt with given hash.
|
||||
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt>;
|
||||
|
||||
/// Get localized receipts for all transaction in given block.
|
||||
fn block_receipts(&self, id: BlockId) -> Option<Vec<LocalizedReceipt>>;
|
||||
|
||||
/// Get a tree route between `from` and `to`.
|
||||
/// See `BlockChain::tree_route`.
|
||||
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute>;
|
||||
@@ -292,7 +295,7 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra
|
||||
fn state_data(&self, hash: &H256) -> Option<Bytes>;
|
||||
|
||||
/// Get raw block receipts data by block header hash.
|
||||
fn block_receipts(&self, hash: &H256) -> Option<Bytes>;
|
||||
fn encoded_block_receipts(&self, hash: &H256) -> Option<Bytes>;
|
||||
|
||||
/// Get block queue information.
|
||||
fn queue_info(&self) -> BlockQueueInfo;
|
||||
|
||||
@@ -80,6 +80,8 @@ pub struct AuthorityRoundParams {
|
||||
pub empty_steps_transition: u64,
|
||||
/// Number of accepted empty steps.
|
||||
pub maximum_empty_steps: usize,
|
||||
/// Transition block to strict empty steps validation.
|
||||
pub strict_empty_steps_transition: u64,
|
||||
}
|
||||
|
||||
const U16_MAX: usize = ::std::u16::MAX as usize;
|
||||
@@ -109,6 +111,7 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
||||
maximum_uncle_count: p.maximum_uncle_count.map_or(0, Into::into),
|
||||
empty_steps_transition: p.empty_steps_transition.map_or(u64::max_value(), |n| ::std::cmp::max(n.into(), 1)),
|
||||
maximum_empty_steps: p.maximum_empty_steps.map_or(0, Into::into),
|
||||
strict_empty_steps_transition: p.strict_empty_steps_transition.map_or(0, Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -420,6 +423,7 @@ pub struct AuthorityRound {
|
||||
maximum_uncle_count_transition: u64,
|
||||
maximum_uncle_count: usize,
|
||||
empty_steps_transition: u64,
|
||||
strict_empty_steps_transition: u64,
|
||||
maximum_empty_steps: usize,
|
||||
machine: EthereumMachine,
|
||||
}
|
||||
@@ -673,6 +677,7 @@ impl AuthorityRound {
|
||||
maximum_uncle_count: our_params.maximum_uncle_count,
|
||||
empty_steps_transition: our_params.empty_steps_transition,
|
||||
maximum_empty_steps: our_params.maximum_empty_steps,
|
||||
strict_empty_steps_transition: our_params.strict_empty_steps_transition,
|
||||
machine: machine,
|
||||
});
|
||||
|
||||
@@ -1011,7 +1016,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
|
||||
let empty_steps_rlp = if header.number() >= self.empty_steps_transition {
|
||||
let empty_steps: Vec<_> = empty_steps.iter().map(|e| e.sealed()).collect();
|
||||
Some(::rlp::encode_list(&empty_steps).into_vec())
|
||||
Some(::rlp::encode_list(&empty_steps))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -1033,8 +1038,8 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
}
|
||||
|
||||
let mut fields = vec![
|
||||
encode(&step).into_vec(),
|
||||
encode(&(&H520::from(signature) as &[u8])).into_vec(),
|
||||
encode(&step),
|
||||
encode(&(&H520::from(signature) as &[u8])),
|
||||
];
|
||||
|
||||
if let Some(empty_steps_rlp) = empty_steps_rlp {
|
||||
@@ -1186,8 +1191,11 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
// reported as there's no way to tell whether the empty step message was never sent or simply not included.
|
||||
let empty_steps_len = if header.number() >= self.empty_steps_transition {
|
||||
let validate_empty_steps = || -> Result<usize, Error> {
|
||||
let strict_empty_steps = header.number() >= self.strict_empty_steps_transition;
|
||||
let empty_steps = header_empty_steps(header)?;
|
||||
let empty_steps_len = empty_steps.len();
|
||||
let mut prev_empty_step = 0;
|
||||
|
||||
for empty_step in empty_steps {
|
||||
if empty_step.step <= parent_step || empty_step.step >= step {
|
||||
Err(EngineError::InsufficientProof(
|
||||
@@ -1203,7 +1211,20 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
Err(EngineError::InsufficientProof(
|
||||
format!("invalid empty step proof: {:?}", empty_step)))?;
|
||||
}
|
||||
|
||||
if strict_empty_steps {
|
||||
if empty_step.step <= prev_empty_step {
|
||||
Err(EngineError::InsufficientProof(format!(
|
||||
"{} empty step: {:?}",
|
||||
if empty_step.step == prev_empty_step { "duplicate" } else { "unordered" },
|
||||
empty_step
|
||||
)))?;
|
||||
}
|
||||
|
||||
prev_empty_step = empty_step.step;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(empty_steps_len)
|
||||
};
|
||||
|
||||
@@ -1459,10 +1480,40 @@ mod tests {
|
||||
use spec::Spec;
|
||||
use transaction::{Action, Transaction};
|
||||
use engines::{Seal, Engine, EngineError, EthEngine};
|
||||
use engines::validator_set::TestSet;
|
||||
use engines::validator_set::{TestSet, SimpleList};
|
||||
use error::{Error, ErrorKind};
|
||||
use super::{AuthorityRoundParams, AuthorityRound, EmptyStep, SealedEmptyStep, calculate_score};
|
||||
|
||||
fn aura<F>(f: F) -> Arc<AuthorityRound> where
|
||||
F: FnOnce(&mut AuthorityRoundParams),
|
||||
{
|
||||
let mut params = AuthorityRoundParams {
|
||||
step_duration: 1,
|
||||
start_step: Some(1),
|
||||
validators: Box::new(TestSet::default()),
|
||||
validate_score_transition: 0,
|
||||
validate_step_transition: 0,
|
||||
immediate_transitions: true,
|
||||
maximum_uncle_count_transition: 0,
|
||||
maximum_uncle_count: 0,
|
||||
empty_steps_transition: u64::max_value(),
|
||||
maximum_empty_steps: 0,
|
||||
block_reward: Default::default(),
|
||||
block_reward_contract_transition: 0,
|
||||
block_reward_contract: Default::default(),
|
||||
strict_empty_steps_transition: 0,
|
||||
};
|
||||
|
||||
// mutate aura params
|
||||
f(&mut params);
|
||||
|
||||
// create engine
|
||||
let mut c_params = ::spec::CommonParams::default();
|
||||
c_params.gas_limit_bound_divisor = 5.into();
|
||||
let machine = ::machine::EthereumMachine::regular(c_params, Default::default());
|
||||
AuthorityRound::new(params, machine).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn has_valid_metadata() {
|
||||
let engine = Spec::new_test_round().engine;
|
||||
@@ -1481,7 +1532,7 @@ mod tests {
|
||||
fn can_do_signature_verification_fail() {
|
||||
let engine = Spec::new_test_round().engine;
|
||||
let mut header: Header = Header::default();
|
||||
header.set_seal(vec![encode(&H520::default()).into_vec()]);
|
||||
header.set_seal(vec![encode(&H520::default())]);
|
||||
|
||||
let verify_result = engine.verify_block_external(&header);
|
||||
assert!(verify_result.is_err());
|
||||
@@ -1558,7 +1609,7 @@ mod tests {
|
||||
let tap = AccountProvider::transient_provider();
|
||||
let addr = tap.insert_account(keccak("0").into(), &"0".into()).unwrap();
|
||||
let mut parent_header: Header = Header::default();
|
||||
parent_header.set_seal(vec![encode(&0usize).into_vec()]);
|
||||
parent_header.set_seal(vec![encode(&0usize)]);
|
||||
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||
let mut header: Header = Header::default();
|
||||
header.set_number(1);
|
||||
@@ -1571,12 +1622,12 @@ mod tests {
|
||||
// Spec starts with step 2.
|
||||
header.set_difficulty(calculate_score(0, 2, 0));
|
||||
let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap();
|
||||
header.set_seal(vec![encode(&2usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]);
|
||||
header.set_seal(vec![encode(&2usize), encode(&(&*signature as &[u8]))]);
|
||||
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
||||
assert!(engine.verify_block_external(&header).is_err());
|
||||
header.set_difficulty(calculate_score(0, 1, 0));
|
||||
let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap();
|
||||
header.set_seal(vec![encode(&1usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]);
|
||||
header.set_seal(vec![encode(&1usize), encode(&(&*signature as &[u8]))]);
|
||||
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
||||
assert!(engine.verify_block_external(&header).is_ok());
|
||||
}
|
||||
@@ -1587,7 +1638,7 @@ mod tests {
|
||||
let addr = tap.insert_account(keccak("0").into(), &"0".into()).unwrap();
|
||||
|
||||
let mut parent_header: Header = Header::default();
|
||||
parent_header.set_seal(vec![encode(&0usize).into_vec()]);
|
||||
parent_header.set_seal(vec![encode(&0usize)]);
|
||||
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||
let mut header: Header = Header::default();
|
||||
header.set_number(1);
|
||||
@@ -1600,10 +1651,10 @@ mod tests {
|
||||
// Spec starts with step 2.
|
||||
header.set_difficulty(calculate_score(0, 1, 0));
|
||||
let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap();
|
||||
header.set_seal(vec![encode(&1usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]);
|
||||
header.set_seal(vec![encode(&1usize), encode(&(&*signature as &[u8]))]);
|
||||
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
||||
assert!(engine.verify_block_external(&header).is_ok());
|
||||
header.set_seal(vec![encode(&5usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]);
|
||||
header.set_seal(vec![encode(&5usize), encode(&(&*signature as &[u8]))]);
|
||||
assert!(engine.verify_block_basic(&header).is_err());
|
||||
}
|
||||
|
||||
@@ -1613,7 +1664,7 @@ mod tests {
|
||||
let addr = tap.insert_account(keccak("0").into(), &"0".into()).unwrap();
|
||||
|
||||
let mut parent_header: Header = Header::default();
|
||||
parent_header.set_seal(vec![encode(&4usize).into_vec()]);
|
||||
parent_header.set_seal(vec![encode(&4usize)]);
|
||||
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||
let mut header: Header = Header::default();
|
||||
header.set_number(1);
|
||||
@@ -1625,10 +1676,10 @@ mod tests {
|
||||
let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap();
|
||||
// Two validators.
|
||||
// Spec starts with step 2.
|
||||
header.set_seal(vec![encode(&5usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]);
|
||||
header.set_seal(vec![encode(&5usize), encode(&(&*signature as &[u8]))]);
|
||||
header.set_difficulty(calculate_score(4, 5, 0));
|
||||
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
||||
header.set_seal(vec![encode(&3usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]);
|
||||
header.set_seal(vec![encode(&3usize), encode(&(&*signature as &[u8]))]);
|
||||
header.set_difficulty(calculate_score(4, 3, 0));
|
||||
assert!(engine.verify_block_family(&header, &parent_header).is_err());
|
||||
}
|
||||
@@ -1636,36 +1687,17 @@ mod tests {
|
||||
#[test]
|
||||
fn reports_skipped() {
|
||||
let last_benign = Arc::new(AtomicUsize::new(0));
|
||||
let params = AuthorityRoundParams {
|
||||
step_duration: 1,
|
||||
start_step: Some(1),
|
||||
validators: Box::new(TestSet::new(Default::default(), last_benign.clone())),
|
||||
validate_score_transition: 0,
|
||||
validate_step_transition: 0,
|
||||
immediate_transitions: true,
|
||||
maximum_uncle_count_transition: 0,
|
||||
maximum_uncle_count: 0,
|
||||
empty_steps_transition: u64::max_value(),
|
||||
maximum_empty_steps: 0,
|
||||
block_reward: Default::default(),
|
||||
block_reward_contract_transition: 0,
|
||||
block_reward_contract: Default::default(),
|
||||
};
|
||||
|
||||
let aura = {
|
||||
let mut c_params = ::spec::CommonParams::default();
|
||||
c_params.gas_limit_bound_divisor = 5.into();
|
||||
let machine = ::machine::EthereumMachine::regular(c_params, Default::default());
|
||||
AuthorityRound::new(params, machine).unwrap()
|
||||
};
|
||||
let aura = aura(|p| {
|
||||
p.validators = Box::new(TestSet::new(Default::default(), last_benign.clone()));
|
||||
});
|
||||
|
||||
let mut parent_header: Header = Header::default();
|
||||
parent_header.set_seal(vec![encode(&1usize).into_vec()]);
|
||||
parent_header.set_seal(vec![encode(&1usize)]);
|
||||
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||
let mut header: Header = Header::default();
|
||||
header.set_difficulty(calculate_score(1, 3, 0));
|
||||
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||
header.set_seal(vec![encode(&3usize).into_vec()]);
|
||||
header.set_seal(vec![encode(&3usize)]);
|
||||
|
||||
// Do not report when signer not present.
|
||||
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
|
||||
@@ -1686,29 +1718,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_uncles_transition() {
|
||||
let last_benign = Arc::new(AtomicUsize::new(0));
|
||||
let params = AuthorityRoundParams {
|
||||
step_duration: 1,
|
||||
start_step: Some(1),
|
||||
validators: Box::new(TestSet::new(Default::default(), last_benign.clone())),
|
||||
validate_score_transition: 0,
|
||||
validate_step_transition: 0,
|
||||
immediate_transitions: true,
|
||||
maximum_uncle_count_transition: 1,
|
||||
maximum_uncle_count: 0,
|
||||
empty_steps_transition: u64::max_value(),
|
||||
maximum_empty_steps: 0,
|
||||
block_reward: Default::default(),
|
||||
block_reward_contract_transition: 0,
|
||||
block_reward_contract: Default::default(),
|
||||
};
|
||||
|
||||
let aura = {
|
||||
let mut c_params = ::spec::CommonParams::default();
|
||||
c_params.gas_limit_bound_divisor = 5.into();
|
||||
let machine = ::machine::EthereumMachine::regular(c_params, Default::default());
|
||||
AuthorityRound::new(params, machine).unwrap()
|
||||
};
|
||||
let aura = aura(|params| {
|
||||
params.maximum_uncle_count_transition = 1;
|
||||
});
|
||||
|
||||
assert_eq!(aura.maximum_uncle_count(0), 2);
|
||||
assert_eq!(aura.maximum_uncle_count(1), 0);
|
||||
@@ -1742,27 +1754,9 @@ mod tests {
|
||||
#[test]
|
||||
#[should_panic(expected="authority_round: step duration can't be zero")]
|
||||
fn test_step_duration_zero() {
|
||||
let last_benign = Arc::new(AtomicUsize::new(0));
|
||||
let params = AuthorityRoundParams {
|
||||
step_duration: 0,
|
||||
start_step: Some(1),
|
||||
validators: Box::new(TestSet::new(Default::default(), last_benign.clone())),
|
||||
validate_score_transition: 0,
|
||||
validate_step_transition: 0,
|
||||
immediate_transitions: true,
|
||||
maximum_uncle_count_transition: 0,
|
||||
maximum_uncle_count: 0,
|
||||
empty_steps_transition: u64::max_value(),
|
||||
maximum_empty_steps: 0,
|
||||
block_reward: Default::default(),
|
||||
block_reward_contract_transition: 0,
|
||||
block_reward_contract: Default::default(),
|
||||
};
|
||||
|
||||
let mut c_params = ::spec::CommonParams::default();
|
||||
c_params.gas_limit_bound_divisor = 5.into();
|
||||
let machine = ::machine::EthereumMachine::regular(c_params, Default::default());
|
||||
AuthorityRound::new(params, machine).unwrap();
|
||||
aura(|params| {
|
||||
params.step_duration = 0;
|
||||
});
|
||||
}
|
||||
|
||||
fn setup_empty_steps() -> (Spec, Arc<AccountProvider>, Vec<Address>) {
|
||||
@@ -1790,6 +1784,23 @@ mod tests {
|
||||
SealedEmptyStep { signature, step }
|
||||
}
|
||||
|
||||
fn set_empty_steps_seal(header: &mut Header, step: u64, block_signature: ðkey::Signature, empty_steps: &[SealedEmptyStep]) {
|
||||
header.set_seal(vec![
|
||||
encode(&(step as usize)),
|
||||
encode(&(&**block_signature as &[u8])),
|
||||
::rlp::encode_list(&empty_steps),
|
||||
]);
|
||||
}
|
||||
|
||||
fn assert_insufficient_proof<T: ::std::fmt::Debug>(result: Result<T, Error>, contains: &str) {
|
||||
match result {
|
||||
Err(Error(ErrorKind::Engine(EngineError::InsufficientProof(ref s)), _)) =>{
|
||||
assert!(s.contains(contains), "Expected {:?} to contain {:?}", s, contains);
|
||||
},
|
||||
e => assert!(false, "Unexpected result: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn broadcast_empty_step_message() {
|
||||
let (spec, tap, accounts) = setup_empty_steps();
|
||||
@@ -1816,7 +1827,7 @@ mod tests {
|
||||
assert_eq!(engine.generate_seal(b1.block(), &genesis_header), Seal::None);
|
||||
|
||||
// spec starts with step 2
|
||||
let empty_step_rlp = encode(&empty_step(engine, 2, &genesis_header.hash())).into_vec();
|
||||
let empty_step_rlp = encode(&empty_step(engine, 2, &genesis_header.hash()));
|
||||
|
||||
// we've received the message
|
||||
assert!(notify.messages.read().contains(&empty_step_rlp));
|
||||
@@ -1874,8 +1885,8 @@ mod tests {
|
||||
let empty_step2 = sealed_empty_step(engine, 2, &genesis_header.hash());
|
||||
let empty_steps = ::rlp::encode_list(&vec![empty_step2]);
|
||||
|
||||
assert_eq!(seal[0], encode(&3usize).into_vec());
|
||||
assert_eq!(seal[2], empty_steps.into_vec());
|
||||
assert_eq!(seal[0], encode(&3usize));
|
||||
assert_eq!(seal[2], empty_steps);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1928,8 +1939,8 @@ mod tests {
|
||||
|
||||
let empty_steps = ::rlp::encode_list(&vec![empty_step2, empty_step3]);
|
||||
|
||||
assert_eq!(seal[0], encode(&4usize).into_vec());
|
||||
assert_eq!(seal[2], empty_steps.into_vec());
|
||||
assert_eq!(seal[0], encode(&4usize));
|
||||
assert_eq!(seal[2], empty_steps);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1978,7 +1989,7 @@ mod tests {
|
||||
let engine = &*spec.engine;
|
||||
|
||||
let mut parent_header: Header = Header::default();
|
||||
parent_header.set_seal(vec![encode(&0usize).into_vec()]);
|
||||
parent_header.set_seal(vec![encode(&0usize)]);
|
||||
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||
|
||||
let mut header: Header = Header::default();
|
||||
@@ -1991,46 +2002,31 @@ mod tests {
|
||||
|
||||
// empty step with invalid step
|
||||
let empty_steps = vec![SealedEmptyStep { signature: 0.into(), step: 2 }];
|
||||
header.set_seal(vec![
|
||||
encode(&2usize).into_vec(),
|
||||
encode(&(&*signature as &[u8])).into_vec(),
|
||||
::rlp::encode_list(&empty_steps).into_vec(),
|
||||
]);
|
||||
set_empty_steps_seal(&mut header, 2, &signature, &empty_steps);
|
||||
|
||||
assert!(match engine.verify_block_family(&header, &parent_header) {
|
||||
Err(Error(ErrorKind::Engine(EngineError::InsufficientProof(ref s)), _))
|
||||
if s.contains("invalid step") => true,
|
||||
_ => false,
|
||||
});
|
||||
assert_insufficient_proof(
|
||||
engine.verify_block_family(&header, &parent_header),
|
||||
"invalid step"
|
||||
);
|
||||
|
||||
// empty step with invalid signature
|
||||
let empty_steps = vec![SealedEmptyStep { signature: 0.into(), step: 1 }];
|
||||
header.set_seal(vec![
|
||||
encode(&2usize).into_vec(),
|
||||
encode(&(&*signature as &[u8])).into_vec(),
|
||||
::rlp::encode_list(&empty_steps).into_vec(),
|
||||
]);
|
||||
set_empty_steps_seal(&mut header, 2, &signature, &empty_steps);
|
||||
|
||||
assert!(match engine.verify_block_family(&header, &parent_header) {
|
||||
Err(Error(ErrorKind::Engine(EngineError::InsufficientProof(ref s)), _))
|
||||
if s.contains("invalid empty step proof") => true,
|
||||
_ => false,
|
||||
});
|
||||
assert_insufficient_proof(
|
||||
engine.verify_block_family(&header, &parent_header),
|
||||
"invalid empty step proof"
|
||||
);
|
||||
|
||||
// empty step with valid signature from incorrect proposer for step
|
||||
engine.set_signer(tap.clone(), addr1, "1".into());
|
||||
let empty_steps = vec![sealed_empty_step(engine, 1, &parent_header.hash())];
|
||||
header.set_seal(vec![
|
||||
encode(&2usize).into_vec(),
|
||||
encode(&(&*signature as &[u8])).into_vec(),
|
||||
::rlp::encode_list(&empty_steps).into_vec(),
|
||||
]);
|
||||
set_empty_steps_seal(&mut header, 2, &signature, &empty_steps);
|
||||
|
||||
assert!(match engine.verify_block_family(&header, &parent_header) {
|
||||
Err(Error(ErrorKind::Engine(EngineError::InsufficientProof(ref s)), _))
|
||||
if s.contains("invalid empty step proof") => true,
|
||||
_ => false,
|
||||
});
|
||||
assert_insufficient_proof(
|
||||
engine.verify_block_family(&header, &parent_header),
|
||||
"invalid empty step proof"
|
||||
);
|
||||
|
||||
// valid empty steps
|
||||
engine.set_signer(tap.clone(), addr1, "1".into());
|
||||
@@ -2041,11 +2037,7 @@ mod tests {
|
||||
let empty_steps = vec![empty_step2, empty_step3];
|
||||
header.set_difficulty(calculate_score(0, 4, 2));
|
||||
let signature = tap.sign(addr1, Some("1".into()), header.bare_hash()).unwrap();
|
||||
header.set_seal(vec![
|
||||
encode(&4usize).into_vec(),
|
||||
encode(&(&*signature as &[u8])).into_vec(),
|
||||
::rlp::encode_list(&empty_steps).into_vec(),
|
||||
]);
|
||||
set_empty_steps_seal(&mut header, 4, &signature, &empty_steps);
|
||||
|
||||
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
||||
}
|
||||
@@ -2157,28 +2149,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_empty_steps() {
|
||||
let last_benign = Arc::new(AtomicUsize::new(0));
|
||||
let params = AuthorityRoundParams {
|
||||
step_duration: 4,
|
||||
start_step: Some(1),
|
||||
validators: Box::new(TestSet::new(Default::default(), last_benign.clone())),
|
||||
validate_score_transition: 0,
|
||||
validate_step_transition: 0,
|
||||
immediate_transitions: true,
|
||||
maximum_uncle_count_transition: 0,
|
||||
maximum_uncle_count: 0,
|
||||
empty_steps_transition: 0,
|
||||
maximum_empty_steps: 10,
|
||||
block_reward: Default::default(),
|
||||
block_reward_contract_transition: 0,
|
||||
block_reward_contract: Default::default(),
|
||||
};
|
||||
|
||||
let mut c_params = ::spec::CommonParams::default();
|
||||
c_params.gas_limit_bound_divisor = 5.into();
|
||||
let machine = ::machine::EthereumMachine::regular(c_params, Default::default());
|
||||
let engine = AuthorityRound::new(params, machine).unwrap();
|
||||
|
||||
let engine = aura(|p| {
|
||||
p.step_duration = 4;
|
||||
p.empty_steps_transition = 0;
|
||||
p.maximum_empty_steps = 0;
|
||||
});
|
||||
|
||||
let parent_hash: H256 = 1.into();
|
||||
let signature = H520::default();
|
||||
@@ -2202,4 +2177,85 @@ mod tests {
|
||||
assert_eq!(engine.empty_steps(0, 3, parent_hash), vec![]);
|
||||
assert_eq!(engine.empty_steps(0, 4, parent_hash), vec![step(3)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_reject_duplicate_empty_steps() {
|
||||
// given
|
||||
let (_spec, tap, accounts) = setup_empty_steps();
|
||||
let engine = aura(|p| {
|
||||
p.validators = Box::new(SimpleList::new(accounts.clone()));
|
||||
p.step_duration = 4;
|
||||
p.empty_steps_transition = 0;
|
||||
p.maximum_empty_steps = 0;
|
||||
});
|
||||
|
||||
let mut parent = Header::default();
|
||||
parent.set_seal(vec![encode(&0usize)]);
|
||||
|
||||
let mut header = Header::default();
|
||||
header.set_number(parent.number() + 1);
|
||||
header.set_parent_hash(parent.hash());
|
||||
header.set_author(accounts[0]);
|
||||
|
||||
// when
|
||||
engine.set_signer(tap.clone(), accounts[1], "0".into());
|
||||
let empty_steps = vec![
|
||||
sealed_empty_step(&*engine, 1, &parent.hash()),
|
||||
sealed_empty_step(&*engine, 1, &parent.hash()),
|
||||
];
|
||||
let step = 2;
|
||||
let signature = tap.sign(accounts[0], Some("1".into()), header.bare_hash()).unwrap();
|
||||
set_empty_steps_seal(&mut header, step, &signature, &empty_steps);
|
||||
header.set_difficulty(calculate_score(0, step, empty_steps.len()));
|
||||
|
||||
// then
|
||||
assert_insufficient_proof(
|
||||
engine.verify_block_family(&header, &parent),
|
||||
"duplicate empty step"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_reject_empty_steps_out_of_order() {
|
||||
// given
|
||||
let (_spec, tap, accounts) = setup_empty_steps();
|
||||
let engine = aura(|p| {
|
||||
p.validators = Box::new(SimpleList::new(accounts.clone()));
|
||||
p.step_duration = 4;
|
||||
p.empty_steps_transition = 0;
|
||||
p.maximum_empty_steps = 0;
|
||||
});
|
||||
|
||||
let mut parent = Header::default();
|
||||
parent.set_seal(vec![encode(&0usize)]);
|
||||
|
||||
let mut header = Header::default();
|
||||
header.set_number(parent.number() + 1);
|
||||
header.set_parent_hash(parent.hash());
|
||||
header.set_author(accounts[0]);
|
||||
|
||||
// when
|
||||
engine.set_signer(tap.clone(), accounts[1], "0".into());
|
||||
let es1 = sealed_empty_step(&*engine, 1, &parent.hash());
|
||||
engine.set_signer(tap.clone(), accounts[0], "1".into());
|
||||
let es2 = sealed_empty_step(&*engine, 2, &parent.hash());
|
||||
|
||||
let mut empty_steps = vec![es2, es1];
|
||||
|
||||
let step = 3;
|
||||
let signature = tap.sign(accounts[1], Some("0".into()), header.bare_hash()).unwrap();
|
||||
set_empty_steps_seal(&mut header, step, &signature, &empty_steps);
|
||||
header.set_difficulty(calculate_score(0, step, empty_steps.len()));
|
||||
|
||||
// then make sure it's rejected because of the order
|
||||
assert_insufficient_proof(
|
||||
engine.verify_block_family(&header, &parent),
|
||||
"unordered empty step"
|
||||
);
|
||||
|
||||
// now try to fix the order
|
||||
empty_steps.reverse();
|
||||
set_empty_steps_seal(&mut header, step, &signature, &empty_steps);
|
||||
assert_eq!(engine.verify_block_family(&header, &parent).unwrap(), ());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ impl Engine<EthereumMachine> for BasicAuthority {
|
||||
if self.validators.contains(header.parent_hash(), author) {
|
||||
// account should be pernamently unlocked, otherwise sealing will fail
|
||||
if let Ok(signature) = self.sign(header.bare_hash()) {
|
||||
return Seal::Regular(vec![::rlp::encode(&(&H520::from(signature) as &[u8])).into_vec()]);
|
||||
return Seal::Regular(vec![::rlp::encode(&(&H520::from(signature) as &[u8]))]);
|
||||
} else {
|
||||
trace!(target: "basicauthority", "generate_seal: FAIL: accounts secret key unavailable");
|
||||
}
|
||||
@@ -234,7 +234,7 @@ mod tests {
|
||||
fn can_do_signature_verification_fail() {
|
||||
let engine = new_test_authority().engine;
|
||||
let mut header: Header = Header::default();
|
||||
header.set_seal(vec![::rlp::encode(&H520::default()).into_vec()]);
|
||||
header.set_seal(vec![::rlp::encode(&H520::default())]);
|
||||
|
||||
let verify_result = engine.verify_block_external(&header);
|
||||
assert!(verify_result.is_err());
|
||||
|
||||
@@ -120,7 +120,7 @@ mod tests {
|
||||
|
||||
assert!(engine.verify_block_basic(&header).is_ok());
|
||||
|
||||
header.set_seal(vec![::rlp::encode(&H520::default()).into_vec()]);
|
||||
header.set_seal(vec![::rlp::encode(&H520::default())]);
|
||||
|
||||
assert!(engine.verify_block_unordered(&header).is_ok());
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ mod tests {
|
||||
},
|
||||
block_hash: Some(keccak("1")),
|
||||
};
|
||||
let raw_rlp = ::rlp::encode(&message).into_vec();
|
||||
let raw_rlp = ::rlp::encode(&message);
|
||||
let rlp = Rlp::new(&raw_rlp);
|
||||
assert_eq!(Ok(message), rlp.as_val());
|
||||
|
||||
@@ -268,8 +268,8 @@ mod tests {
|
||||
fn proposal_message() {
|
||||
let mut header = Header::default();
|
||||
let seal = vec![
|
||||
::rlp::encode(&0u8).into_vec(),
|
||||
::rlp::encode(&H520::default()).into_vec(),
|
||||
::rlp::encode(&0u8),
|
||||
::rlp::encode(&H520::default()),
|
||||
Vec::new()
|
||||
];
|
||||
|
||||
|
||||
@@ -407,9 +407,9 @@ impl Tendermint {
|
||||
let precommits = self.votes.round_signatures(vote_step, &bh);
|
||||
trace!(target: "engine", "Collected seal: {:?}", precommits);
|
||||
let seal = vec![
|
||||
::rlp::encode(&vote_step.view).into_vec(),
|
||||
::rlp::encode(&vote_step.view),
|
||||
::rlp::NULL_RLP.to_vec(),
|
||||
::rlp::encode_list(&precommits).into_vec()
|
||||
::rlp::encode_list(&precommits)
|
||||
];
|
||||
self.submit_seal(bh, seal);
|
||||
self.votes.throw_out_old(&vote_step);
|
||||
@@ -491,8 +491,8 @@ impl Engine<EthereumMachine> for Tendermint {
|
||||
*self.proposal.write() = bh;
|
||||
*self.proposal_parent.write() = header.parent_hash().clone();
|
||||
Seal::Proposal(vec![
|
||||
::rlp::encode(&view).into_vec(),
|
||||
::rlp::encode(&signature).into_vec(),
|
||||
::rlp::encode(&view),
|
||||
::rlp::encode(&signature),
|
||||
::rlp::EMPTY_LIST_RLP.to_vec()
|
||||
])
|
||||
} else {
|
||||
@@ -520,7 +520,7 @@ impl Engine<EthereumMachine> for Tendermint {
|
||||
self.broadcast_message(rlp.as_raw().to_vec());
|
||||
if let Some(double) = self.votes.vote(message.clone(), sender) {
|
||||
let height = message.vote_step.height as BlockNumber;
|
||||
self.validators.report_malicious(&sender, height, height, ::rlp::encode(&double).into_vec());
|
||||
self.validators.report_malicious(&sender, height, height, ::rlp::encode(&double));
|
||||
return Err(EngineError::DoubleVote(sender));
|
||||
}
|
||||
trace!(target: "engine", "Handling a valid {:?} from {}.", message, sender);
|
||||
@@ -823,8 +823,8 @@ mod tests {
|
||||
let vote_info = message_info_rlp(&VoteStep::new(header.number() as Height, view, Step::Propose), Some(header.bare_hash()));
|
||||
let signature = tap.sign(*author, None, keccak(vote_info)).unwrap();
|
||||
vec![
|
||||
::rlp::encode(&view).into_vec(),
|
||||
::rlp::encode(&H520::from(signature)).into_vec(),
|
||||
::rlp::encode(&view),
|
||||
::rlp::encode(&H520::from(signature)),
|
||||
::rlp::EMPTY_LIST_RLP.to_vec()
|
||||
]
|
||||
}
|
||||
@@ -928,7 +928,7 @@ mod tests {
|
||||
let signature1 = tap.sign(proposer, None, keccak(&vote_info)).unwrap();
|
||||
|
||||
seal[1] = ::rlp::NULL_RLP.to_vec();
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone())]).into_vec();
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone())]);
|
||||
header.set_seal(seal.clone());
|
||||
|
||||
// One good signature is not enough.
|
||||
@@ -940,7 +940,7 @@ mod tests {
|
||||
let voter = insert_and_unlock(&tap, "0");
|
||||
let signature0 = tap.sign(voter, None, keccak(&vote_info)).unwrap();
|
||||
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone()), H520::from(signature0.clone())]).into_vec();
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone()), H520::from(signature0.clone())]);
|
||||
header.set_seal(seal.clone());
|
||||
|
||||
assert!(engine.verify_block_external(&header).is_ok());
|
||||
@@ -948,7 +948,7 @@ mod tests {
|
||||
let bad_voter = insert_and_unlock(&tap, "101");
|
||||
let bad_signature = tap.sign(bad_voter, None, keccak(vote_info)).unwrap();
|
||||
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1), H520::from(bad_signature)]).into_vec();
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1), H520::from(bad_signature)]);
|
||||
header.set_seal(seal);
|
||||
|
||||
// One good and one bad signature.
|
||||
@@ -1084,7 +1084,7 @@ mod tests {
|
||||
let signature0 = tap.sign(voter, None, keccak(&vote_info)).unwrap();
|
||||
|
||||
seal[1] = ::rlp::NULL_RLP.to_vec();
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone())]).into_vec();
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone())]);
|
||||
header.set_seal(seal.clone());
|
||||
|
||||
let epoch_verifier = super::EpochVerifier {
|
||||
@@ -1112,7 +1112,7 @@ mod tests {
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone()), H520::from(signature0.clone())]).into_vec();
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone()), H520::from(signature0.clone())]);
|
||||
header.set_seal(seal.clone());
|
||||
|
||||
assert!(epoch_verifier.verify_light(&header).is_ok());
|
||||
@@ -1120,7 +1120,7 @@ mod tests {
|
||||
let bad_voter = insert_and_unlock(&tap, "101");
|
||||
let bad_signature = tap.sign(bad_voter, None, keccak(&vote_info)).unwrap();
|
||||
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1), H520::from(bad_signature)]).into_vec();
|
||||
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1), H520::from(bad_signature)]);
|
||||
header.set_seal(seal);
|
||||
|
||||
// One good and one bad signature.
|
||||
|
||||
@@ -174,7 +174,7 @@ mod tests {
|
||||
|
||||
// Check a block that is a bit in future, reject it but don't report the validator.
|
||||
let mut header = Header::default();
|
||||
let seal = vec![encode(&4u8).into_vec(), encode(&(&H520::default() as &[u8])).into_vec()];
|
||||
let seal = vec![encode(&4u8), encode(&(&H520::default() as &[u8]))];
|
||||
header.set_seal(seal);
|
||||
header.set_author(v1);
|
||||
header.set_number(2);
|
||||
@@ -185,7 +185,7 @@ mod tests {
|
||||
|
||||
// Now create one that is more in future. That one should be rejected and validator should be reported.
|
||||
let mut header = Header::default();
|
||||
let seal = vec![encode(&8u8).into_vec(), encode(&(&H520::default() as &[u8])).into_vec()];
|
||||
let seal = vec![encode(&8u8), encode(&(&H520::default() as &[u8]))];
|
||||
header.set_seal(seal);
|
||||
header.set_author(v1);
|
||||
header.set_number(2);
|
||||
|
||||
@@ -158,7 +158,7 @@ fn decode_first_proof(rlp: &Rlp) -> Result<(Header, Vec<DBValue>), ::error::Erro
|
||||
fn encode_proof(header: &Header, receipts: &[Receipt]) -> Bytes {
|
||||
let mut stream = RlpStream::new_list(2);
|
||||
stream.append(header).append_list(receipts);
|
||||
stream.drain().into_vec()
|
||||
stream.drain()
|
||||
}
|
||||
|
||||
fn decode_proof(rlp: &Rlp) -> Result<(Header, Vec<Receipt>), ::error::Error> {
|
||||
|
||||
@@ -34,12 +34,18 @@ pub struct TestSet {
|
||||
last_benign: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl Default for TestSet {
|
||||
fn default() -> Self {
|
||||
TestSet::new(Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl TestSet {
|
||||
pub fn new(last_malicious: Arc<AtomicUsize>, last_benign: Arc<AtomicUsize>) -> Self {
|
||||
TestSet {
|
||||
validator: SimpleList::new(vec![Address::from_str("7d577a597b2742b498cb5cf0c26cdcd726d39e6e").unwrap()]),
|
||||
last_malicious: last_malicious,
|
||||
last_benign: last_benign,
|
||||
last_malicious,
|
||||
last_benign,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,7 +681,7 @@ mod tests {
|
||||
fn can_do_difficulty_verification_fail() {
|
||||
let engine = test_spec().engine;
|
||||
let mut header: Header = Header::default();
|
||||
header.set_seal(vec![rlp::encode(&H256::zero()).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
||||
header.set_seal(vec![rlp::encode(&H256::zero()), rlp::encode(&H64::zero())]);
|
||||
|
||||
let verify_result = engine.verify_block_basic(&header);
|
||||
|
||||
@@ -696,7 +696,7 @@ mod tests {
|
||||
fn can_do_proof_of_work_verification_fail() {
|
||||
let engine = test_spec().engine;
|
||||
let mut header: Header = Header::default();
|
||||
header.set_seal(vec![rlp::encode(&H256::zero()).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
||||
header.set_seal(vec![rlp::encode(&H256::zero()), rlp::encode(&H64::zero())]);
|
||||
header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap());
|
||||
|
||||
let verify_result = engine.verify_block_basic(&header);
|
||||
@@ -737,7 +737,7 @@ mod tests {
|
||||
fn can_do_seal256_verification_fail() {
|
||||
let engine = test_spec().engine;
|
||||
let mut header: Header = Header::default();
|
||||
header.set_seal(vec![rlp::encode(&H256::zero()).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
||||
header.set_seal(vec![rlp::encode(&H256::zero()), rlp::encode(&H64::zero())]);
|
||||
let verify_result = engine.verify_block_unordered(&header);
|
||||
|
||||
match verify_result {
|
||||
@@ -751,7 +751,7 @@ mod tests {
|
||||
fn can_do_proof_of_work_unordered_verification_fail() {
|
||||
let engine = test_spec().engine;
|
||||
let mut header: Header = Header::default();
|
||||
header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
||||
header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")), rlp::encode(&H64::zero())]);
|
||||
header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap());
|
||||
|
||||
let verify_result = engine.verify_block_unordered(&header);
|
||||
@@ -944,7 +944,7 @@ mod tests {
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
let ethash = Ethash::new(tempdir.path(), ethparams, machine, None);
|
||||
let mut header = Header::default();
|
||||
header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
||||
header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")), rlp::encode(&H64::zero())]);
|
||||
let info = ethash.extra_info(&header);
|
||||
assert_eq!(info["nonce"], "0x0000000000000000");
|
||||
assert_eq!(info["mixHash"], "0xb251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d");
|
||||
|
||||
@@ -449,7 +449,7 @@ mod tests {
|
||||
let header_rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap();
|
||||
|
||||
let header: Header = rlp::decode(&header_rlp).expect("error decoding header");
|
||||
let encoded_header = rlp::encode(&header).into_vec();
|
||||
let encoded_header = rlp::encode(&header);
|
||||
|
||||
assert_eq!(header_rlp, encoded_header);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ use ethtrie::RlpCodec;
|
||||
use ethereum_types::H256;
|
||||
use memorydb::MemoryDB;
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use kvdb::DBValue;
|
||||
|
||||
use super::HookType;
|
||||
|
||||
@@ -36,7 +37,7 @@ fn test_trie<H: FnMut(&str, HookType)>(json: &[u8], trie: TrieSpec, start_stop_h
|
||||
for (name, test) in tests.into_iter() {
|
||||
start_stop_hook(&name, HookType::OnStart);
|
||||
|
||||
let mut memdb = MemoryDB::<KeccakHasher>::new();
|
||||
let mut memdb = MemoryDB::<KeccakHasher, DBValue>::new();
|
||||
let mut root = H256::default();
|
||||
let mut t = factory.create(&mut memdb, &mut root);
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ use executive::contract_address;
|
||||
use header::{Header, BlockNumber};
|
||||
use miner;
|
||||
use miner::pool_client::{PoolClient, CachedNonceClient, NonceCache};
|
||||
use receipt::{Receipt, RichReceipt};
|
||||
use receipt::RichReceipt;
|
||||
use spec::Spec;
|
||||
use state::State;
|
||||
use ethkey::Password;
|
||||
@@ -1039,19 +1039,17 @@ impl miner::MinerService for Miner {
|
||||
self.transaction_queue.status()
|
||||
}
|
||||
|
||||
fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option<RichReceipt> {
|
||||
fn pending_receipts(&self, best_block: BlockNumber) -> Option<Vec<RichReceipt>> {
|
||||
self.map_existing_pending_block(|pending| {
|
||||
let txs = pending.transactions();
|
||||
txs.iter()
|
||||
.map(|t| t.hash())
|
||||
.position(|t| t == *hash)
|
||||
.map(|index| {
|
||||
let receipts = pending.receipts();
|
||||
let receipts = pending.receipts();
|
||||
pending.transactions()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, tx)| {
|
||||
let prev_gas = if index == 0 { Default::default() } else { receipts[index - 1].gas_used };
|
||||
let tx = &txs[index];
|
||||
let receipt = &receipts[index];
|
||||
RichReceipt {
|
||||
transaction_hash: hash.clone(),
|
||||
transaction_hash: tx.hash(),
|
||||
transaction_index: index,
|
||||
cumulative_gas_used: receipt.gas_used,
|
||||
gas_used: receipt.gas_used - prev_gas,
|
||||
@@ -1067,15 +1065,7 @@ impl miner::MinerService for Miner {
|
||||
outcome: receipt.outcome.clone(),
|
||||
}
|
||||
})
|
||||
}, best_block).and_then(|x| x)
|
||||
}
|
||||
|
||||
fn pending_receipts(&self, best_block: BlockNumber) -> Option<BTreeMap<H256, Receipt>> {
|
||||
self.map_existing_pending_block(|pending| {
|
||||
let hashes = pending.transactions().iter().map(|t| t.hash());
|
||||
let receipts = pending.receipts().iter().cloned();
|
||||
|
||||
hashes.zip(receipts).collect()
|
||||
.collect()
|
||||
}, best_block)
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ use client::{
|
||||
};
|
||||
use error::Error;
|
||||
use header::{BlockNumber, Header};
|
||||
use receipt::{RichReceipt, Receipt};
|
||||
use receipt::RichReceipt;
|
||||
use transaction::{self, UnverifiedTransaction, SignedTransaction, PendingTransaction};
|
||||
use state::StateInfo;
|
||||
use ethkey::Password;
|
||||
@@ -95,10 +95,13 @@ pub trait MinerService : Send + Sync {
|
||||
// Pending block
|
||||
|
||||
/// Get a list of all pending receipts from pending block.
|
||||
fn pending_receipts(&self, best_block: BlockNumber) -> Option<BTreeMap<H256, Receipt>>;
|
||||
fn pending_receipts(&self, best_block: BlockNumber) -> Option<Vec<RichReceipt>>;
|
||||
|
||||
/// Get a particular receipt from pending block.
|
||||
fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option<RichReceipt>;
|
||||
fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option<RichReceipt> {
|
||||
let receipts = self.pending_receipts(best_block)?;
|
||||
receipts.into_iter().find(|r| &r.transaction_hash == hash)
|
||||
}
|
||||
|
||||
/// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing.
|
||||
fn pending_state(&self, latest_block_number: BlockNumber) -> Option<Self::State>;
|
||||
|
||||
@@ -138,7 +138,7 @@ impl JobDispatcher for StratumJobDispatcher {
|
||||
);
|
||||
|
||||
self.with_core_result(|client, miner| {
|
||||
let seal = vec![encode(&payload.mix_hash).into_vec(), encode(&payload.nonce).into_vec()];
|
||||
let seal = vec![encode(&payload.mix_hash), encode(&payload.nonce)];
|
||||
|
||||
let import = miner.submit_seal(payload.pow_hash, seal)
|
||||
.and_then(|block| client.import_sealed_block(block));
|
||||
|
||||
@@ -20,6 +20,7 @@ use itertools::Itertools;
|
||||
use hash::{keccak};
|
||||
use ethereum_types::{H256, U256};
|
||||
use hashdb::HashDB;
|
||||
use kvdb::DBValue;
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use triehash::sec_trie_root;
|
||||
use bytes::Bytes;
|
||||
@@ -67,7 +68,7 @@ impl PodAccount {
|
||||
}
|
||||
|
||||
/// Place additional data into given hash DB.
|
||||
pub fn insert_additional(&self, db: &mut HashDB<KeccakHasher>, factory: &TrieFactory<KeccakHasher, RlpCodec>) {
|
||||
pub fn insert_additional(&self, db: &mut HashDB<KeccakHasher, DBValue>, factory: &TrieFactory<KeccakHasher, RlpCodec>) {
|
||||
match self.code {
|
||||
Some(ref c) if !c.is_empty() => { db.insert(c); }
|
||||
_ => {}
|
||||
|
||||
@@ -123,7 +123,7 @@ pub fn to_fat_rlps(account_hash: &H256, acc: &BasicAccount, acct_db: &AccountDB,
|
||||
let stream = ::std::mem::replace(&mut account_stream, RlpStream::new_list(2));
|
||||
chunks.push(stream.out());
|
||||
target_chunk_size = max_chunk_size;
|
||||
leftover = Some(pair.into_vec());
|
||||
leftover = Some(pair);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -34,12 +34,11 @@ use ids::BlockId;
|
||||
use ethereum_types::{H256, U256};
|
||||
use hashdb::HashDB;
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use kvdb::DBValue;
|
||||
use snappy;
|
||||
use bytes::Bytes;
|
||||
use parking_lot::Mutex;
|
||||
use journaldb::{self, Algorithm, JournalDB};
|
||||
use kvdb::KeyValueDB;
|
||||
use kvdb::{KeyValueDB, DBValue};
|
||||
use trie::{Trie, TrieMut};
|
||||
use ethtrie::{TrieDB, TrieDBMut};
|
||||
use rlp::{RlpStream, Rlp};
|
||||
@@ -152,7 +151,7 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(
|
||||
engine: &EthEngine,
|
||||
chain: &BlockChain,
|
||||
block_at: H256,
|
||||
state_db: &HashDB<KeccakHasher>,
|
||||
state_db: &HashDB<KeccakHasher, DBValue>,
|
||||
writer: W,
|
||||
p: &Progress,
|
||||
processing_threads: usize,
|
||||
@@ -322,7 +321,7 @@ impl<'a> StateChunker<'a> {
|
||||
///
|
||||
/// Returns a list of hashes of chunks created, or any error it may
|
||||
/// have encountered.
|
||||
pub fn chunk_state<'a>(db: &HashDB<KeccakHasher>, root: &H256, writer: &Mutex<SnapshotWriter + 'a>, progress: &'a Progress, part: Option<usize>) -> Result<Vec<H256>, Error> {
|
||||
pub fn chunk_state<'a>(db: &HashDB<KeccakHasher, DBValue>, root: &H256, writer: &Mutex<SnapshotWriter + 'a>, progress: &'a Progress, part: Option<usize>) -> Result<Vec<H256>, Error> {
|
||||
let account_trie = TrieDB::new(db, &root)?;
|
||||
|
||||
let mut chunker = StateChunker {
|
||||
@@ -494,7 +493,7 @@ struct RebuiltStatus {
|
||||
// rebuild a set of accounts and their storage.
|
||||
// returns a status detailing newly-loaded code and accounts missing code.
|
||||
fn rebuild_accounts(
|
||||
db: &mut HashDB<KeccakHasher>,
|
||||
db: &mut HashDB<KeccakHasher, DBValue>,
|
||||
account_fat_rlps: Rlp,
|
||||
out_chunk: &mut [(H256, Bytes)],
|
||||
known_code: &HashMap<H256, H256>,
|
||||
@@ -541,7 +540,7 @@ fn rebuild_accounts(
|
||||
}
|
||||
}
|
||||
|
||||
::rlp::encode(&acc).into_vec()
|
||||
::rlp::encode(&acc)
|
||||
};
|
||||
|
||||
*out = (hash, thin_rlp);
|
||||
|
||||
@@ -62,7 +62,7 @@ impl StateProducer {
|
||||
|
||||
/// Tick the state producer. This alters the state, writing new data into
|
||||
/// the database.
|
||||
pub fn tick<R: Rng>(&mut self, rng: &mut R, db: &mut HashDB<KeccakHasher>) {
|
||||
pub fn tick<R: Rng>(&mut self, rng: &mut R, db: &mut HashDB<KeccakHasher, DBValue>) {
|
||||
// modify existing accounts.
|
||||
let mut accounts_to_modify: Vec<_> = {
|
||||
let trie = TrieDB::new(&*db, &self.state_root).unwrap();
|
||||
@@ -80,7 +80,7 @@ impl StateProducer {
|
||||
let mut account: BasicAccount = ::rlp::decode(&*account_data).expect("error decoding basic account");
|
||||
let acct_db = AccountDBMut::from_hash(db, *address_hash);
|
||||
fill_storage(acct_db, &mut account.storage_root, &mut self.storage_seed);
|
||||
*account_data = DBValue::from_vec(::rlp::encode(&account).into_vec());
|
||||
*account_data = DBValue::from_vec(::rlp::encode(&account));
|
||||
}
|
||||
|
||||
// sweep again to alter account trie.
|
||||
@@ -131,7 +131,7 @@ pub fn fill_storage(mut db: AccountDBMut, root: &mut H256, seed: &mut H256) {
|
||||
}
|
||||
|
||||
/// Compare two state dbs.
|
||||
pub fn compare_dbs(one: &HashDB<KeccakHasher>, two: &HashDB<KeccakHasher>) {
|
||||
pub fn compare_dbs(one: &HashDB<KeccakHasher, DBValue>, two: &HashDB<KeccakHasher, DBValue>) {
|
||||
let keys = one.keys();
|
||||
|
||||
for key in keys.keys() {
|
||||
|
||||
@@ -213,7 +213,7 @@ impl Account {
|
||||
|
||||
/// Get (and cache) the contents of the trie's storage at `key`.
|
||||
/// Takes modified storage into account.
|
||||
pub fn storage_at(&self, db: &HashDB<KeccakHasher>, key: &H256) -> TrieResult<H256> {
|
||||
pub fn storage_at(&self, db: &HashDB<KeccakHasher, DBValue>, key: &H256) -> TrieResult<H256> {
|
||||
if let Some(value) = self.cached_storage_at(key) {
|
||||
return Ok(value);
|
||||
}
|
||||
@@ -226,7 +226,7 @@ impl Account {
|
||||
|
||||
/// Get (and cache) the contents of the trie's storage at `key`.
|
||||
/// Does not take modified storage into account.
|
||||
pub fn original_storage_at(&self, db: &HashDB<KeccakHasher>, key: &H256) -> TrieResult<H256> {
|
||||
pub fn original_storage_at(&self, db: &HashDB<KeccakHasher, DBValue>, key: &H256) -> TrieResult<H256> {
|
||||
if let Some(value) = self.cached_original_storage_at(key) {
|
||||
return Ok(value);
|
||||
}
|
||||
@@ -248,7 +248,7 @@ impl Account {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_and_cache_storage(storage_root: &H256, storage_cache: &mut LruCache<H256, H256>, db: &HashDB<KeccakHasher>, key: &H256) -> TrieResult<H256> {
|
||||
fn get_and_cache_storage(storage_root: &H256, storage_cache: &mut LruCache<H256, H256>, db: &HashDB<KeccakHasher, DBValue>, key: &H256) -> TrieResult<H256> {
|
||||
let db = SecTrieDB::new(db, storage_root)?;
|
||||
let panicky_decoder = |bytes:&[u8]| ::rlp::decode(&bytes).expect("decoding db value failed");
|
||||
let item: U256 = db.get_with(key, panicky_decoder)?.unwrap_or_else(U256::zero);
|
||||
@@ -354,7 +354,7 @@ impl Account {
|
||||
|
||||
/// Provide a database to get `code_hash`. Should not be called if it is a contract without code. Returns the cached code, if successful.
|
||||
#[must_use]
|
||||
pub fn cache_code(&mut self, db: &HashDB<KeccakHasher>) -> Option<Arc<Bytes>> {
|
||||
pub fn cache_code(&mut self, db: &HashDB<KeccakHasher, DBValue>) -> Option<Arc<Bytes>> {
|
||||
// TODO: fill out self.code_cache;
|
||||
trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
|
||||
|
||||
@@ -384,7 +384,7 @@ impl Account {
|
||||
/// Provide a database to get `code_size`. Should not be called if it is a contract without code. Returns whether
|
||||
/// the cache succeeds.
|
||||
#[must_use]
|
||||
pub fn cache_code_size(&mut self, db: &HashDB<KeccakHasher>) -> bool {
|
||||
pub fn cache_code_size(&mut self, db: &HashDB<KeccakHasher, DBValue>) -> bool {
|
||||
// TODO: fill out self.code_cache;
|
||||
trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
|
||||
self.code_size.is_some() ||
|
||||
@@ -473,7 +473,7 @@ impl Account {
|
||||
}
|
||||
|
||||
/// Commit the `storage_changes` to the backing DB and update `storage_root`.
|
||||
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut HashDB<KeccakHasher>) -> TrieResult<()> {
|
||||
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut HashDB<KeccakHasher, DBValue>) -> TrieResult<()> {
|
||||
let mut t = trie_factory.from_existing(db, &mut self.storage_root)?;
|
||||
for (k, v) in self.storage_changes.drain() {
|
||||
// cast key and value to trait type,
|
||||
@@ -490,7 +490,7 @@ impl Account {
|
||||
}
|
||||
|
||||
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
|
||||
pub fn commit_code(&mut self, db: &mut HashDB<KeccakHasher>) {
|
||||
pub fn commit_code(&mut self, db: &mut HashDB<KeccakHasher, DBValue>) {
|
||||
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_filth == Filth::Dirty, self.code_cache.is_empty());
|
||||
match (self.code_filth == Filth::Dirty, self.code_cache.is_empty()) {
|
||||
(true, true) => {
|
||||
@@ -579,7 +579,7 @@ impl Account {
|
||||
/// trie.
|
||||
/// `storage_key` is the hash of the desired storage key, meaning
|
||||
/// this will only work correctly under a secure trie.
|
||||
pub fn prove_storage(&self, db: &HashDB<KeccakHasher>, storage_key: H256) -> TrieResult<(Vec<Bytes>, H256)> {
|
||||
pub fn prove_storage(&self, db: &HashDB<KeccakHasher, DBValue>, storage_key: H256) -> TrieResult<(Vec<Bytes>, H256)> {
|
||||
let mut recorder = Recorder::new();
|
||||
|
||||
let trie = TrieDB::new(db, &self.storage_root)?;
|
||||
|
||||
@@ -28,16 +28,17 @@ use state::Account;
|
||||
use parking_lot::Mutex;
|
||||
use ethereum_types::{Address, H256};
|
||||
use memorydb::MemoryDB;
|
||||
use hashdb::{AsHashDB, HashDB, DBValue};
|
||||
use hashdb::{AsHashDB, HashDB};
|
||||
use kvdb::DBValue;
|
||||
use keccak_hasher::KeccakHasher;
|
||||
|
||||
/// State backend. See module docs for more details.
|
||||
pub trait Backend: Send {
|
||||
/// Treat the backend as a read-only hashdb.
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher>;
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue>;
|
||||
|
||||
/// Treat the backend as a writeable hashdb.
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher>;
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue>;
|
||||
|
||||
/// Add an account entry to the cache.
|
||||
fn add_to_account_cache(&mut self, addr: Address, data: Option<Account>, modified: bool);
|
||||
@@ -76,18 +77,18 @@ pub trait Backend: Send {
|
||||
// TODO: when account lookup moved into backends, this won't rely as tenuously on intended
|
||||
// usage.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct ProofCheck(MemoryDB<KeccakHasher>);
|
||||
pub struct ProofCheck(MemoryDB<KeccakHasher, DBValue>);
|
||||
|
||||
impl ProofCheck {
|
||||
/// Create a new `ProofCheck` backend from the given state items.
|
||||
pub fn new(proof: &[DBValue]) -> Self {
|
||||
let mut db = MemoryDB::<KeccakHasher>::new();
|
||||
let mut db = MemoryDB::<KeccakHasher, DBValue>::new();
|
||||
for item in proof { db.insert(item); }
|
||||
ProofCheck(db)
|
||||
}
|
||||
}
|
||||
|
||||
impl HashDB<KeccakHasher> for ProofCheck {
|
||||
impl HashDB<KeccakHasher, DBValue> for ProofCheck {
|
||||
fn keys(&self) -> HashMap<H256, i32> { self.0.keys() }
|
||||
fn get(&self, key: &H256) -> Option<DBValue> {
|
||||
self.0.get(key)
|
||||
@@ -108,14 +109,14 @@ impl HashDB<KeccakHasher> for ProofCheck {
|
||||
fn remove(&mut self, _key: &H256) { }
|
||||
}
|
||||
|
||||
impl AsHashDB<KeccakHasher> for ProofCheck {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
|
||||
impl AsHashDB<KeccakHasher, DBValue> for ProofCheck {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue> { self }
|
||||
}
|
||||
|
||||
impl Backend for ProofCheck {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue> { self }
|
||||
fn add_to_account_cache(&mut self, _addr: Address, _data: Option<Account>, _modified: bool) {}
|
||||
fn cache_code(&self, _hash: H256, _code: Arc<Vec<u8>>) {}
|
||||
fn get_cached_account(&self, _addr: &Address) -> Option<Option<Account>> { None }
|
||||
@@ -134,18 +135,18 @@ impl Backend for ProofCheck {
|
||||
/// The proof-of-execution can be extracted with `extract_proof`.
|
||||
///
|
||||
/// This doesn't cache anything or rely on the canonical state caches.
|
||||
pub struct Proving<H: AsHashDB<KeccakHasher>> {
|
||||
pub struct Proving<H: AsHashDB<KeccakHasher, DBValue>> {
|
||||
base: H, // state we're proving values from.
|
||||
changed: MemoryDB<KeccakHasher>, // changed state via insertions.
|
||||
changed: MemoryDB<KeccakHasher, DBValue>, // changed state via insertions.
|
||||
proof: Mutex<HashSet<DBValue>>,
|
||||
}
|
||||
|
||||
impl<AH: AsHashDB<KeccakHasher> + Send + Sync> AsHashDB<KeccakHasher> for Proving<AH> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
|
||||
impl<AH: AsHashDB<KeccakHasher, DBValue> + Send + Sync> AsHashDB<KeccakHasher, DBValue> for Proving<AH> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue> { self }
|
||||
}
|
||||
|
||||
impl<H: AsHashDB<KeccakHasher> + Send + Sync> HashDB<KeccakHasher> for Proving<H> {
|
||||
impl<H: AsHashDB<KeccakHasher, DBValue> + Send + Sync> HashDB<KeccakHasher, DBValue> for Proving<H> {
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
let mut keys = self.base.as_hashdb().keys();
|
||||
keys.extend(self.changed.keys());
|
||||
@@ -182,10 +183,10 @@ impl<H: AsHashDB<KeccakHasher> + Send + Sync> HashDB<KeccakHasher> for Proving<H
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: AsHashDB<KeccakHasher> + Send + Sync> Backend for Proving<H> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
|
||||
impl<H: AsHashDB<KeccakHasher, DBValue> + Send + Sync> Backend for Proving<H> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue> { self }
|
||||
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue> { self }
|
||||
|
||||
fn add_to_account_cache(&mut self, _: Address, _: Option<Account>, _: bool) { }
|
||||
|
||||
@@ -204,13 +205,13 @@ impl<H: AsHashDB<KeccakHasher> + Send + Sync> Backend for Proving<H> {
|
||||
fn is_known_null(&self, _: &Address) -> bool { false }
|
||||
}
|
||||
|
||||
impl<H: AsHashDB<KeccakHasher>> Proving<H> {
|
||||
impl<H: AsHashDB<KeccakHasher, DBValue>> Proving<H> {
|
||||
/// Create a new `Proving` over a base database.
|
||||
/// This will store all values ever fetched from that base.
|
||||
pub fn new(base: H) -> Self {
|
||||
Proving {
|
||||
base: base,
|
||||
changed: MemoryDB::<KeccakHasher>::new(),
|
||||
changed: MemoryDB::<KeccakHasher, DBValue>::new(),
|
||||
proof: Mutex::new(HashSet::new()),
|
||||
}
|
||||
}
|
||||
@@ -222,7 +223,7 @@ impl<H: AsHashDB<KeccakHasher>> Proving<H> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: AsHashDB<KeccakHasher> + Clone> Clone for Proving<H> {
|
||||
impl<H: AsHashDB<KeccakHasher, DBValue> + Clone> Clone for Proving<H> {
|
||||
fn clone(&self) -> Self {
|
||||
Proving {
|
||||
base: self.base.clone(),
|
||||
@@ -236,12 +237,12 @@ impl<H: AsHashDB<KeccakHasher> + Clone> Clone for Proving<H> {
|
||||
/// it. Doesn't cache anything.
|
||||
pub struct Basic<H>(pub H);
|
||||
|
||||
impl<H: AsHashDB<KeccakHasher> + Send + Sync> Backend for Basic<H> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher> {
|
||||
impl<H: AsHashDB<KeccakHasher, DBValue> + Send + Sync> Backend for Basic<H> {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue> {
|
||||
self.0.as_hashdb()
|
||||
}
|
||||
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> {
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue> {
|
||||
self.0.as_hashdb_mut()
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ pub fn check_proof(
|
||||
/// Prove a `virtual` transaction on the given state.
|
||||
/// Returns `None` when the transacion could not be proved,
|
||||
/// and a proof otherwise.
|
||||
pub fn prove_transaction_virtual<H: AsHashDB<KeccakHasher> + Send + Sync>(
|
||||
pub fn prove_transaction_virtual<H: AsHashDB<KeccakHasher, DBValue> + Send + Sync>(
|
||||
db: H,
|
||||
root: H256,
|
||||
transaction: &SignedTransaction,
|
||||
@@ -618,7 +618,7 @@ impl<B: Backend> State<B> {
|
||||
&self, address: &Address, key: &H256, f_cached_at: FCachedStorageAt, f_at: FStorageAt,
|
||||
) -> TrieResult<H256> where
|
||||
FCachedStorageAt: Fn(&Account, &H256) -> Option<H256>,
|
||||
FStorageAt: Fn(&Account, &HashDB<KeccakHasher>, &H256) -> TrieResult<H256>
|
||||
FStorageAt: Fn(&Account, &HashDB<KeccakHasher, DBValue>, &H256) -> TrieResult<H256>
|
||||
{
|
||||
// Storage key search and update works like this:
|
||||
// 1. If there's an entry for the account in the local cache check for the key and return it if found.
|
||||
@@ -1014,7 +1014,7 @@ impl<B: Backend> State<B> {
|
||||
|
||||
/// Load required account data from the databases. Returns whether the cache succeeds.
|
||||
#[must_use]
|
||||
fn update_account_cache(require: RequireCache, account: &mut Account, state_db: &B, db: &HashDB<KeccakHasher>) -> bool {
|
||||
fn update_account_cache(require: RequireCache, account: &mut Account, state_db: &B, db: &HashDB<KeccakHasher, DBValue>) -> bool {
|
||||
if let RequireCache::None = require {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ use hashdb::HashDB;
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use header::BlockNumber;
|
||||
use journaldb::JournalDB;
|
||||
use kvdb::{KeyValueDB, DBTransaction};
|
||||
use kvdb::{KeyValueDB, DBTransaction, DBValue};
|
||||
use lru_cache::LruCache;
|
||||
use memory_cache::MemoryLruCache;
|
||||
use parking_lot::Mutex;
|
||||
@@ -312,12 +312,12 @@ impl StateDB {
|
||||
}
|
||||
|
||||
/// Conversion method to interpret self as `HashDB` reference
|
||||
pub fn as_hashdb(&self) -> &HashDB<KeccakHasher> {
|
||||
pub fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue> {
|
||||
self.db.as_hashdb()
|
||||
}
|
||||
|
||||
/// Conversion method to interpret self as mutable `HashDB` reference
|
||||
pub fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> {
|
||||
pub fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue> {
|
||||
self.db.as_hashdb_mut()
|
||||
}
|
||||
|
||||
@@ -412,9 +412,9 @@ impl StateDB {
|
||||
}
|
||||
|
||||
impl state::Backend for StateDB {
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self.db.as_hashdb() }
|
||||
fn as_hashdb(&self) -> &HashDB<KeccakHasher, DBValue> { self.db.as_hashdb() }
|
||||
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> {
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher, DBValue> {
|
||||
self.db.as_hashdb_mut()
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[SignedTransa
|
||||
rlp.append(header);
|
||||
rlp.begin_list(transactions.len());
|
||||
for t in transactions {
|
||||
rlp.append_raw(&rlp::encode(t).into_vec(), 1);
|
||||
rlp.append_raw(&rlp::encode(t), 1);
|
||||
}
|
||||
rlp.append_list(&uncles);
|
||||
rlp.out()
|
||||
|
||||
@@ -38,9 +38,9 @@ impl<'a> BodyView<'a> {
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate ethcore;
|
||||
///
|
||||
///
|
||||
/// use ethcore::views::{BodyView};
|
||||
///
|
||||
///
|
||||
/// fn main() {
|
||||
/// let bytes : &[u8] = &[];
|
||||
/// let body_view = view!(BodyView, bytes);
|
||||
|
||||
Reference in New Issue
Block a user