Merge branch 'master' into auth-round
Conflicts: ethcore/src/miner/miner.rs sync/Cargo.toml
This commit is contained in:
@@ -417,7 +417,7 @@ impl ClosedBlock {
|
||||
}
|
||||
|
||||
/// Given an engine reference, reopen the `ClosedBlock` into an `OpenBlock`.
|
||||
pub fn reopen<'a>(self, engine: &'a Engine) -> OpenBlock<'a> {
|
||||
pub fn reopen(self, engine: &Engine) -> OpenBlock {
|
||||
// revert rewards (i.e. set state back at last transaction's state).
|
||||
let mut block = self.block;
|
||||
block.state = self.unclosed_state;
|
||||
|
||||
@@ -23,6 +23,7 @@ use header::*;
|
||||
use super::extras::*;
|
||||
use transaction::*;
|
||||
use views::*;
|
||||
use log_entry::{LogEntry, LocalizedLogEntry};
|
||||
use receipt::Receipt;
|
||||
use blooms::{Bloom, BloomGroup};
|
||||
use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData};
|
||||
@@ -127,6 +128,10 @@ pub trait BlockProvider {
|
||||
|
||||
/// Returns numbers of blocks containing given bloom.
|
||||
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber>;
|
||||
|
||||
/// Returns logs matching given filter.
|
||||
fn logs<F>(&self, mut blocks: Vec<BlockNumber>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
where F: Fn(&LogEntry) -> bool, Self: Sized;
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
|
||||
@@ -315,6 +320,51 @@ impl BlockProvider for BlockChain {
|
||||
.map(|b| b as BlockNumber)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn logs<F>(&self, mut blocks: Vec<BlockNumber>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
where F: Fn(&LogEntry) -> bool, Self: Sized {
|
||||
// sort in reverse order
|
||||
blocks.sort_by(|a, b| b.cmp(a));
|
||||
|
||||
let mut log_index = 0;
|
||||
let mut logs = blocks.into_iter()
|
||||
.filter_map(|number| self.block_hash(number).map(|hash| (number, hash)))
|
||||
.filter_map(|(number, hash)| self.block_receipts(&hash).map(|r| (number, hash, r.receipts)))
|
||||
.filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, BodyView::new(b).transaction_hashes())))
|
||||
.flat_map(|(number, hash, mut receipts, hashes)| {
|
||||
assert_eq!(receipts.len(), hashes.len());
|
||||
log_index = receipts.iter().fold(0, |sum, receipt| sum + receipt.logs.len());
|
||||
|
||||
let receipts_len = receipts.len();
|
||||
receipts.reverse();
|
||||
receipts.into_iter()
|
||||
.map(|receipt| receipt.logs)
|
||||
.zip(hashes)
|
||||
.enumerate()
|
||||
.flat_map(move |(index, (mut logs, tx_hash))| {
|
||||
let current_log_index = log_index;
|
||||
log_index -= logs.len();
|
||||
|
||||
logs.reverse();
|
||||
logs.into_iter()
|
||||
.enumerate()
|
||||
.map(move |(i, log)| LocalizedLogEntry {
|
||||
entry: log,
|
||||
block_hash: hash,
|
||||
block_number: number,
|
||||
transaction_hash: tx_hash,
|
||||
// iterating in reverse order
|
||||
transaction_index: receipts_len - index - 1,
|
||||
log_index: current_log_index - i - 1,
|
||||
})
|
||||
})
|
||||
})
|
||||
.filter(|log_entry| matches(&log_entry.entry))
|
||||
.take(limit.unwrap_or(::std::usize::MAX))
|
||||
.collect::<Vec<LocalizedLogEntry>>();
|
||||
logs.reverse();
|
||||
logs
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AncestryIter<'a> {
|
||||
@@ -1160,6 +1210,7 @@ mod tests {
|
||||
use blockchain::extras::TransactionAddress;
|
||||
use views::BlockView;
|
||||
use transaction::{Transaction, Action};
|
||||
use log_entry::{LogEntry, LocalizedLogEntry};
|
||||
|
||||
fn new_db(path: &str) -> Arc<Database> {
|
||||
Arc::new(Database::open(&DatabaseConfig::with_columns(::db::NUM_COLUMNS), path).unwrap())
|
||||
@@ -1235,7 +1286,7 @@ mod tests {
|
||||
let bc = BlockChain::new(Config::default(), &genesis, db.clone());
|
||||
|
||||
let mut block_hashes = vec![genesis_hash.clone()];
|
||||
let mut batch =db.transaction();
|
||||
let mut batch = db.transaction();
|
||||
for _ in 0..10 {
|
||||
let block = canon_chain.generate(&mut finalizer).unwrap();
|
||||
block_hashes.push(BlockView::new(&block).header_view().sha3());
|
||||
@@ -1566,7 +1617,7 @@ mod tests {
|
||||
let mut block_header = bc.block_header(&best_hash);
|
||||
|
||||
while !block_header.is_none() {
|
||||
block_header = bc.block_header(&block_header.unwrap().parent_hash());
|
||||
block_header = bc.block_header(block_header.unwrap().parent_hash());
|
||||
}
|
||||
assert!(bc.cache_size().blocks > 1024 * 1024);
|
||||
|
||||
@@ -1612,13 +1663,134 @@ mod tests {
|
||||
}
|
||||
|
||||
fn insert_block(db: &Arc<Database>, bc: &BlockChain, bytes: &[u8], receipts: Vec<Receipt>) -> ImportRoute {
|
||||
let mut batch =db.transaction();
|
||||
let mut batch = db.transaction();
|
||||
let res = bc.insert_block(&mut batch, bytes, receipts);
|
||||
db.write(batch).unwrap();
|
||||
bc.commit();
|
||||
res
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_logs() {
|
||||
// given
|
||||
let mut canon_chain = ChainGenerator::default();
|
||||
let mut finalizer = BlockFinalizer::default();
|
||||
let genesis = canon_chain.generate(&mut finalizer).unwrap();
|
||||
// just insert dummy transaction so that #transactions=#receipts
|
||||
let t1 = Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
action: Action::Create,
|
||||
value: 100.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
let t2 = Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
action: Action::Create,
|
||||
value: 100.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
let t3 = Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
action: Action::Create,
|
||||
value: 100.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
let tx_hash1 = t1.hash();
|
||||
let tx_hash2 = t2.hash();
|
||||
let tx_hash3 = t3.hash();
|
||||
let b1 = canon_chain.with_transaction(t1).with_transaction(t2).generate(&mut finalizer).unwrap();
|
||||
let b2 = canon_chain.with_transaction(t3).generate(&mut finalizer).unwrap();
|
||||
|
||||
let temp = RandomTempPath::new();
|
||||
let db = new_db(temp.as_str());
|
||||
let bc = BlockChain::new(Config::default(), &genesis, db.clone());
|
||||
insert_block(&db, &bc, &b1, vec![Receipt {
|
||||
state_root: H256::default(),
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
logs: vec![
|
||||
LogEntry { address: Default::default(), topics: vec![], data: vec![1], },
|
||||
LogEntry { address: Default::default(), topics: vec![], data: vec![2], },
|
||||
],
|
||||
},
|
||||
Receipt {
|
||||
state_root: H256::default(),
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
logs: vec![
|
||||
LogEntry { address: Default::default(), topics: vec![], data: vec![3], },
|
||||
],
|
||||
}]);
|
||||
insert_block(&db, &bc, &b2, vec![
|
||||
Receipt {
|
||||
state_root: H256::default(),
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
logs: vec![
|
||||
LogEntry { address: Default::default(), topics: vec![], data: vec![4], },
|
||||
],
|
||||
}
|
||||
]);
|
||||
|
||||
// when
|
||||
let block1 = BlockView::new(&b1);
|
||||
let block2 = BlockView::new(&b2);
|
||||
let logs1 = bc.logs(vec![1, 2], |_| true, None);
|
||||
let logs2 = bc.logs(vec![1, 2], |_| true, Some(1));
|
||||
|
||||
// then
|
||||
assert_eq!(logs1, vec![
|
||||
LocalizedLogEntry {
|
||||
entry: LogEntry { address: Default::default(), topics: vec![], data: vec![1] },
|
||||
block_hash: block1.hash(),
|
||||
block_number: block1.header().number(),
|
||||
transaction_hash: tx_hash1.clone(),
|
||||
transaction_index: 0,
|
||||
log_index: 0,
|
||||
},
|
||||
LocalizedLogEntry {
|
||||
entry: LogEntry { address: Default::default(), topics: vec![], data: vec![2] },
|
||||
block_hash: block1.hash(),
|
||||
block_number: block1.header().number(),
|
||||
transaction_hash: tx_hash1.clone(),
|
||||
transaction_index: 0,
|
||||
log_index: 1,
|
||||
},
|
||||
LocalizedLogEntry {
|
||||
entry: LogEntry { address: Default::default(), topics: vec![], data: vec![3] },
|
||||
block_hash: block1.hash(),
|
||||
block_number: block1.header().number(),
|
||||
transaction_hash: tx_hash2.clone(),
|
||||
transaction_index: 1,
|
||||
log_index: 2,
|
||||
},
|
||||
LocalizedLogEntry {
|
||||
entry: LogEntry { address: Default::default(), topics: vec![], data: vec![4] },
|
||||
block_hash: block2.hash(),
|
||||
block_number: block2.header().number(),
|
||||
transaction_hash: tx_hash3.clone(),
|
||||
transaction_index: 0,
|
||||
log_index: 0,
|
||||
}
|
||||
]);
|
||||
assert_eq!(logs2, vec![
|
||||
LocalizedLogEntry {
|
||||
entry: LogEntry { address: Default::default(), topics: vec![], data: vec![4] },
|
||||
block_hash: block2.hash(),
|
||||
block_number: block2.header().number(),
|
||||
transaction_hash: tx_hash3.clone(),
|
||||
transaction_index: 0,
|
||||
log_index: 0,
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bloom_filter_simple() {
|
||||
// TODO: From here
|
||||
|
||||
@@ -968,10 +968,8 @@ impl BlockChainClient for Client {
|
||||
}
|
||||
}
|
||||
|
||||
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry> {
|
||||
// TODO: lock blockchain only once
|
||||
|
||||
let mut blocks = filter.bloom_possibilities().iter()
|
||||
fn logs(&self, filter: Filter, limit: Option<usize>) -> Vec<LocalizedLogEntry> {
|
||||
let blocks = filter.bloom_possibilities().iter()
|
||||
.filter_map(|bloom| self.blocks_with_bloom(bloom, filter.from_block.clone(), filter.to_block.clone()))
|
||||
.flat_map(|m| m)
|
||||
// remove duplicate elements
|
||||
@@ -979,35 +977,7 @@ impl BlockChainClient for Client {
|
||||
.into_iter()
|
||||
.collect::<Vec<u64>>();
|
||||
|
||||
blocks.sort();
|
||||
|
||||
let chain = self.chain.read();
|
||||
blocks.into_iter()
|
||||
.filter_map(|number| chain.block_hash(number).map(|hash| (number, hash)))
|
||||
.filter_map(|(number, hash)| chain.block_receipts(&hash).map(|r| (number, hash, r.receipts)))
|
||||
.filter_map(|(number, hash, receipts)| chain.block_body(&hash).map(|ref b| (number, hash, receipts, BodyView::new(b).transaction_hashes())))
|
||||
.flat_map(|(number, hash, receipts, hashes)| {
|
||||
let mut log_index = 0;
|
||||
receipts.into_iter()
|
||||
.enumerate()
|
||||
.flat_map(|(index, receipt)| {
|
||||
log_index += receipt.logs.len();
|
||||
receipt.logs.into_iter()
|
||||
.enumerate()
|
||||
.filter(|tuple| filter.matches(&tuple.1))
|
||||
.map(|(i, log)| LocalizedLogEntry {
|
||||
entry: log,
|
||||
block_hash: hash.clone(),
|
||||
block_number: number,
|
||||
transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::default),
|
||||
transaction_index: index,
|
||||
log_index: log_index + i
|
||||
})
|
||||
.collect::<Vec<LocalizedLogEntry>>()
|
||||
})
|
||||
.collect::<Vec<LocalizedLogEntry>>()
|
||||
})
|
||||
.collect()
|
||||
self.chain.read().logs(blocks, |entry| filter.matches(entry), limit)
|
||||
}
|
||||
|
||||
fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>> {
|
||||
|
||||
@@ -395,8 +395,8 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn logs(&self, _filter: Filter) -> Vec<LocalizedLogEntry> {
|
||||
unimplemented!();
|
||||
fn logs(&self, _filter: Filter, _limit: Option<usize>) -> Vec<LocalizedLogEntry> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn last_hashes(&self) -> LastHashes {
|
||||
|
||||
@@ -156,7 +156,7 @@ pub trait BlockChainClient : Sync + Send {
|
||||
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockID, to_block: BlockID) -> Option<Vec<BlockNumber>>;
|
||||
|
||||
/// Returns logs matching given filter.
|
||||
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry>;
|
||||
fn logs(&self, filter: Filter, limit: Option<usize>) -> Vec<LocalizedLogEntry>;
|
||||
|
||||
/// Makes a non-persistent transaction call.
|
||||
fn call(&self, t: &SignedTransaction, block: BlockID, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
||||
|
||||
@@ -160,7 +160,7 @@ impl Engine for Ethash {
|
||||
let fields = block.fields_mut();
|
||||
|
||||
// Bestow block reward
|
||||
fields.state.add_balance(&fields.header.author(), &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())));
|
||||
fields.state.add_balance(fields.header.author(), &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())));
|
||||
|
||||
// Bestow uncle rewards
|
||||
let current_number = fields.header.number();
|
||||
|
||||
@@ -251,6 +251,7 @@ impl Miner {
|
||||
self.sealing_work.lock().queue.peek_last_ref().map(|b| b.base().clone())
|
||||
}
|
||||
|
||||
#[cfg_attr(feature="dev", allow(match_same_arms))]
|
||||
/// Prepares new block for sealing including top transactions from queue.
|
||||
fn prepare_block(&self, chain: &MiningBlockChainClient) -> (ClosedBlock, Option<H256>) {
|
||||
{
|
||||
@@ -374,7 +375,7 @@ impl Miner {
|
||||
|
||||
/// Attempts to perform internal sealing (one that does not require work) to return Ok(sealed),
|
||||
/// Err(Some(block)) returns for unsuccesful sealing while Err(None) indicates misspecified engine.
|
||||
fn seal_block_internally(&self, block: ClosedBlock) -> Result<SealedBlock, Option<ClosedBlock>> {
|
||||
fn seal_block_internally(&self, block: ClosedBlock) -> Result<SealedBlock, Option<ClosedBlock>> {
|
||||
trace!(target: "miner", "seal_block_internally: block has transaction - attempting internal seal.");
|
||||
let s = self.engine.generate_seal(block.block(), match self.accounts {
|
||||
Some(ref x) => Some(&**x),
|
||||
@@ -678,6 +679,7 @@ impl MinerService for Miner {
|
||||
results
|
||||
}
|
||||
|
||||
#[cfg_attr(feature="dev", allow(collapsible_if))]
|
||||
fn import_own_transaction(
|
||||
&self,
|
||||
chain: &MiningBlockChainClient,
|
||||
|
||||
@@ -949,7 +949,7 @@ mod test {
|
||||
new_tx_pair(default_nonce(), default_gas_price(), nonce_increment, gas_price_increment)
|
||||
}
|
||||
|
||||
/// Returns two transactions with identical (sender, nonce) but different gas_price/hash.
|
||||
/// Returns two transactions with identical (sender, nonce) but different gas price/hash.
|
||||
fn new_similar_tx_pair() -> (SignedTransaction, SignedTransaction) {
|
||||
new_tx_pair_default(0.into(), 1.into())
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ impl StateProducer {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature="dev", allow(let_and_return))]
|
||||
/// 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) {
|
||||
|
||||
@@ -184,7 +184,7 @@ impl Spec {
|
||||
let r = Rlp::new(&seal);
|
||||
(0..self.seal_fields).map(|i| r.at(i).as_raw().to_vec()).collect()
|
||||
});
|
||||
return header;
|
||||
header
|
||||
}
|
||||
|
||||
/// Compose the genesis block for this chain.
|
||||
@@ -285,7 +285,7 @@ mod tests {
|
||||
// https://github.com/ethcore/parity/issues/1840
|
||||
#[test]
|
||||
fn test_load_empty() {
|
||||
assert!(Spec::load(&vec![] as &[u8]).is_err());
|
||||
assert!(Spec::load(&[] as &[u8]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1314,13 +1314,13 @@ fn storage_at_from_database() {
|
||||
let temp = RandomTempPath::new();
|
||||
let (root, db) = {
|
||||
let mut state = get_temp_state_in(temp.as_path());
|
||||
state.set_storage(&a, H256::from(&U256::from(01u64)), H256::from(&U256::from(69u64)));
|
||||
state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(69u64)));
|
||||
state.commit().unwrap();
|
||||
state.drop()
|
||||
};
|
||||
|
||||
let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||
assert_eq!(s.storage_at(&a, &H256::from(&U256::from(01u64))), H256::from(&U256::from(69u64)));
|
||||
assert_eq!(s.storage_at(&a, &H256::from(&U256::from(1u64))), H256::from(&U256::from(69u64)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -19,6 +19,7 @@ use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, Blo
|
||||
use ethereum;
|
||||
use block::IsBlock;
|
||||
use tests::helpers::*;
|
||||
use types::filter::Filter;
|
||||
use common::*;
|
||||
use devtools::*;
|
||||
use miner::Miner;
|
||||
@@ -131,6 +132,34 @@ fn returns_chain_info() {
|
||||
assert_eq!(info.best_block_hash, block.header().hash());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_logs() {
|
||||
let dummy_block = get_good_dummy_block();
|
||||
let client_result = get_test_client_with_blocks(vec![dummy_block.clone()]);
|
||||
let client = client_result.reference();
|
||||
let logs = client.logs(Filter {
|
||||
from_block: BlockID::Earliest,
|
||||
to_block: BlockID::Latest,
|
||||
address: None,
|
||||
topics: vec![],
|
||||
}, None);
|
||||
assert_eq!(logs.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_logs_with_limit() {
|
||||
let dummy_block = get_good_dummy_block();
|
||||
let client_result = get_test_client_with_blocks(vec![dummy_block.clone()]);
|
||||
let client = client_result.reference();
|
||||
let logs = client.logs(Filter {
|
||||
from_block: BlockID::Earliest,
|
||||
to_block: BlockID::Latest,
|
||||
address: None,
|
||||
topics: vec![],
|
||||
}, Some(2));
|
||||
assert_eq!(logs.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_block_body() {
|
||||
let dummy_block = get_good_dummy_block();
|
||||
|
||||
@@ -241,6 +241,7 @@ mod tests {
|
||||
use spec::*;
|
||||
use transaction::*;
|
||||
use tests::helpers::*;
|
||||
use types::log_entry::{LogEntry, LocalizedLogEntry};
|
||||
use rlp::View;
|
||||
|
||||
fn check_ok(result: Result<(), Error>) {
|
||||
@@ -333,6 +334,12 @@ mod tests {
|
||||
fn block_receipts(&self, _hash: &H256) -> Option<BlockReceipts> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
||||
fn logs<F>(&self, _blocks: Vec<BlockNumber>, _matches: F, _limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
where F: Fn(&LogEntry) -> bool, Self: Sized {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
fn basic_test(bytes: &[u8], engine: &Engine) -> Result<(), Error> {
|
||||
|
||||
Reference in New Issue
Block a user