Merge branch 'master' into auth-round

Conflicts:
	ethcore/src/miner/miner.rs
	sync/Cargo.toml
This commit is contained in:
keorn
2016-09-19 14:35:44 +02:00
63 changed files with 1746 additions and 517 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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>> {

View File

@@ -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 {

View File

@@ -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>;

View File

@@ -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();

View File

@@ -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,

View File

@@ -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())
}

View File

@@ -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) {

View File

@@ -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]

View File

@@ -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]

View File

@@ -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();

View File

@@ -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> {