Trace comment on new block inclusion (#100)
This commit is contained in:
parent
51d824fbdc
commit
56131b6d92
@ -1476,7 +1476,7 @@ impl BlockChain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply pending insertion updates
|
// t_nb 9.12 commit changed to become current greatest by applying pending insertion updates
|
||||||
pub fn commit(&self) {
|
pub fn commit(&self) {
|
||||||
let mut pending_best_ancient_block = self.pending_best_ancient_block.write();
|
let mut pending_best_ancient_block = self.pending_best_ancient_block.write();
|
||||||
let mut pending_best_block = self.pending_best_block.write();
|
let mut pending_best_block = self.pending_best_block.write();
|
||||||
|
@ -161,7 +161,7 @@ pub trait Drain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'x> OpenBlock<'x> {
|
impl<'x> OpenBlock<'x> {
|
||||||
/// Create a new `OpenBlock` ready for transaction pushing.
|
// t_nb 8.1 Create a new `OpenBlock` ready for transaction pushing.
|
||||||
pub fn new<'a, I: IntoIterator<Item = ExtendedHeader>>(
|
pub fn new<'a, I: IntoIterator<Item = ExtendedHeader>>(
|
||||||
engine: &'x dyn EthEngine,
|
engine: &'x dyn EthEngine,
|
||||||
factories: Factories,
|
factories: Factories,
|
||||||
@ -176,6 +176,8 @@ impl<'x> OpenBlock<'x> {
|
|||||||
ancestry: I,
|
ancestry: I,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let number = parent.number() + 1;
|
let number = parent.number() + 1;
|
||||||
|
|
||||||
|
// t_nb 8.1.1 get parent StateDB.
|
||||||
let state = State::from_existing(
|
let state = State::from_existing(
|
||||||
db,
|
db,
|
||||||
parent.state_root().clone(),
|
parent.state_root().clone(),
|
||||||
@ -198,14 +200,17 @@ impl<'x> OpenBlock<'x> {
|
|||||||
let gas_floor_target = cmp::max(gas_range_target.0, engine.params().min_gas_limit);
|
let gas_floor_target = cmp::max(gas_range_target.0, engine.params().min_gas_limit);
|
||||||
let gas_ceil_target = cmp::max(gas_range_target.1, gas_floor_target);
|
let gas_ceil_target = cmp::max(gas_range_target.1, gas_floor_target);
|
||||||
|
|
||||||
|
// t_nb 8.1.2 It calculated child gas limits should be.
|
||||||
engine.machine().populate_from_parent(
|
engine.machine().populate_from_parent(
|
||||||
&mut r.block.header,
|
&mut r.block.header,
|
||||||
parent,
|
parent,
|
||||||
gas_floor_target,
|
gas_floor_target,
|
||||||
gas_ceil_target,
|
gas_ceil_target,
|
||||||
);
|
);
|
||||||
|
// t_nb 8.1.3 this adds engine specific things
|
||||||
engine.populate_from_parent(&mut r.block.header, parent);
|
engine.populate_from_parent(&mut r.block.header, parent);
|
||||||
|
|
||||||
|
// t_nb 8.1.3 updating last hashes and the DAO fork, for ethash.
|
||||||
engine.machine().on_new_block(&mut r.block)?;
|
engine.machine().on_new_block(&mut r.block)?;
|
||||||
engine.on_new_block(&mut r.block, is_epoch_begin, &mut ancestry.into_iter())?;
|
engine.on_new_block(&mut r.block, is_epoch_begin, &mut ancestry.into_iter())?;
|
||||||
|
|
||||||
@ -222,7 +227,7 @@ impl<'x> OpenBlock<'x> {
|
|||||||
self.block.header.set_gas_limit(U256::max_value());
|
self.block.header.set_gas_limit(U256::max_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an uncle to the block, if possible.
|
// t_nb 8.4 Add an uncle to the block, if possible.
|
||||||
///
|
///
|
||||||
/// NOTE Will check chain constraints and the uncle number but will NOT check
|
/// NOTE Will check chain constraints and the uncle number but will NOT check
|
||||||
/// that the header itself is actually valid.
|
/// that the header itself is actually valid.
|
||||||
@ -343,13 +348,17 @@ impl<'x> OpenBlock<'x> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turn this into a `LockedBlock`.
|
// t_nb 8.5 Turn this into a `LockedBlock`.
|
||||||
pub fn close_and_lock(self) -> Result<LockedBlock, Error> {
|
pub fn close_and_lock(self) -> Result<LockedBlock, Error> {
|
||||||
let mut s = self;
|
let mut s = self;
|
||||||
|
|
||||||
|
// t_nb 8.5.1 engine applies block rewards (Ethash and AuRa do.Clique is empty)
|
||||||
s.engine.on_close_block(&mut s.block)?;
|
s.engine.on_close_block(&mut s.block)?;
|
||||||
|
|
||||||
|
// t_nb 8.5.2 commit account changes from cache to tree
|
||||||
s.block.state.commit()?;
|
s.block.state.commit()?;
|
||||||
|
|
||||||
|
// t_nb 8.5.3 fill open block header with all other fields
|
||||||
s.block.header.set_transactions_root(ordered_trie_root(
|
s.block.header.set_transactions_root(ordered_trie_root(
|
||||||
s.block.transactions.iter().map(|e| e.rlp_bytes()),
|
s.block.transactions.iter().map(|e| e.rlp_bytes()),
|
||||||
));
|
));
|
||||||
@ -506,7 +515,7 @@ impl Drain for SealedBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enact the block given by block header, transactions and uncles
|
// t_nb 8.0 Enact the block given by block header, transactions and uncles
|
||||||
pub(crate) fn enact(
|
pub(crate) fn enact(
|
||||||
header: Header,
|
header: Header,
|
||||||
transactions: Vec<SignedTransaction>,
|
transactions: Vec<SignedTransaction>,
|
||||||
@ -532,6 +541,7 @@ pub(crate) fn enact(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// t_nb 8.1 Created new OpenBlock
|
||||||
let mut b = OpenBlock::new(
|
let mut b = OpenBlock::new(
|
||||||
engine,
|
engine,
|
||||||
factories,
|
factories,
|
||||||
@ -556,17 +566,22 @@ pub(crate) fn enact(
|
|||||||
b.block.header.number(), root, env.author, author_balance);
|
b.block.header.number(), root, env.author, author_balance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 8.2 transfer all field from current header to OpenBlock header that we created
|
||||||
b.populate_from(&header);
|
b.populate_from(&header);
|
||||||
|
|
||||||
|
// t_nb 8.3 execute transactions one by one
|
||||||
b.push_transactions(transactions)?;
|
b.push_transactions(transactions)?;
|
||||||
|
|
||||||
|
// t_nb 8.4 Push uncles to OpenBlock and check if we have more then max uncles
|
||||||
for u in uncles {
|
for u in uncles {
|
||||||
b.push_uncle(u)?;
|
b.push_uncle(u)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 8.5 close block
|
||||||
b.close_and_lock()
|
b.close_and_lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
|
// t_nb 8.0 Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
|
||||||
pub fn enact_verified(
|
pub fn enact_verified(
|
||||||
block: PreverifiedBlock,
|
block: PreverifiedBlock,
|
||||||
engine: &dyn EthEngine,
|
engine: &dyn EthEngine,
|
||||||
|
@ -275,7 +275,7 @@ impl Importer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is triggered by a message coming from a block queue when the block is ready for insertion
|
// t_nb 6.0 This is triggered by a message coming from a block queue when the block is ready for insertion
|
||||||
pub fn import_verified_blocks(&self, client: &Client) -> usize {
|
pub fn import_verified_blocks(&self, client: &Client) -> usize {
|
||||||
// Shortcut out if we know we're incapable of syncing the chain.
|
// Shortcut out if we know we're incapable of syncing the chain.
|
||||||
if !client.enabled.load(AtomicOrdering::Relaxed) {
|
if !client.enabled.load(AtomicOrdering::Relaxed) {
|
||||||
@ -315,11 +315,13 @@ impl Importer {
|
|||||||
invalid_blocks.insert(hash);
|
invalid_blocks.insert(hash);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// t_nb 7.0 check and lock block
|
||||||
match self.check_and_lock_block(&bytes, block, client) {
|
match self.check_and_lock_block(&bytes, block, client) {
|
||||||
Ok((closed_block, pending)) => {
|
Ok((closed_block, pending)) => {
|
||||||
imported_blocks.push(hash);
|
imported_blocks.push(hash);
|
||||||
let transactions_len = closed_block.transactions.len();
|
let transactions_len = closed_block.transactions.len();
|
||||||
|
|
||||||
|
// t_nb 8.0 commit block to db
|
||||||
let route = self.commit_block(
|
let route = self.commit_block(
|
||||||
closed_block,
|
closed_block,
|
||||||
&header,
|
&header,
|
||||||
@ -362,6 +364,7 @@ impl Importer {
|
|||||||
if !imported_blocks.is_empty() {
|
if !imported_blocks.is_empty() {
|
||||||
let route = ChainRoute::from(import_results.as_ref());
|
let route = ChainRoute::from(import_results.as_ref());
|
||||||
|
|
||||||
|
// t_nb 10 Notify miner about new included block.
|
||||||
if !has_more_blocks_to_import {
|
if !has_more_blocks_to_import {
|
||||||
self.miner.chain_new_blocks(
|
self.miner.chain_new_blocks(
|
||||||
client,
|
client,
|
||||||
@ -373,6 +376,7 @@ impl Importer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 11 notify rest of system about new block inclusion
|
||||||
client.notify(|notify| {
|
client.notify(|notify| {
|
||||||
notify.new_blocks(NewBlocks::new(
|
notify.new_blocks(NewBlocks::new(
|
||||||
imported_blocks.clone(),
|
imported_blocks.clone(),
|
||||||
@ -394,6 +398,7 @@ impl Importer {
|
|||||||
imported
|
imported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 6.0.1 check and lock block,
|
||||||
fn check_and_lock_block(
|
fn check_and_lock_block(
|
||||||
&self,
|
&self,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
@ -404,13 +409,14 @@ impl Importer {
|
|||||||
let header = block.header.clone();
|
let header = block.header.clone();
|
||||||
|
|
||||||
// Check the block isn't so old we won't be able to enact it.
|
// Check the block isn't so old we won't be able to enact it.
|
||||||
|
// t_nb 7.1 check if block is older then last pruned block
|
||||||
let best_block_number = client.chain.read().best_block_number();
|
let best_block_number = client.chain.read().best_block_number();
|
||||||
if client.pruning_info().earliest_state > header.number() {
|
if client.pruning_info().earliest_state > header.number() {
|
||||||
warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number);
|
warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number);
|
||||||
bail!("Block is ancient");
|
bail!("Block is ancient");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if parent is in chain
|
// t_nb 7.2 Check if parent is in chain
|
||||||
let parent = match client.block_header_decoded(BlockId::Hash(*header.parent_hash())) {
|
let parent = match client.block_header_decoded(BlockId::Hash(*header.parent_hash())) {
|
||||||
Some(h) => h,
|
Some(h) => h,
|
||||||
None => {
|
None => {
|
||||||
@ -420,7 +426,7 @@ impl Importer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let chain = client.chain.read();
|
let chain = client.chain.read();
|
||||||
// Verify Block Family
|
// t_nb 7.3 verify block family
|
||||||
let verify_family_result = self.verifier.verify_block_family(
|
let verify_family_result = self.verifier.verify_block_family(
|
||||||
&header,
|
&header,
|
||||||
&parent,
|
&parent,
|
||||||
@ -437,6 +443,7 @@ impl Importer {
|
|||||||
bail!(e);
|
bail!(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// t_nb 7.4 verify block external
|
||||||
let verify_external_result = self.verifier.verify_block_external(&header, engine);
|
let verify_external_result = self.verifier.verify_block_external(&header, engine);
|
||||||
if let Err(e) = verify_external_result {
|
if let Err(e) = verify_external_result {
|
||||||
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||||
@ -444,7 +451,9 @@ impl Importer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Enact Verified Block
|
// Enact Verified Block
|
||||||
|
// t_nb 7.5 Get build last hashes. Get parent state db. Get epoch_transition
|
||||||
let last_hashes = client.build_last_hashes(header.parent_hash());
|
let last_hashes = client.build_last_hashes(header.parent_hash());
|
||||||
|
|
||||||
let db = client
|
let db = client
|
||||||
.state_db
|
.state_db
|
||||||
.read()
|
.read()
|
||||||
@ -454,6 +463,7 @@ impl Importer {
|
|||||||
.epoch_transition(parent.number(), *header.parent_hash())
|
.epoch_transition(parent.number(), *header.parent_hash())
|
||||||
.is_some();
|
.is_some();
|
||||||
|
|
||||||
|
// t_nb 8.0 Block enacting. Execution of transactions.
|
||||||
let enact_result = enact_verified(
|
let enact_result = enact_verified(
|
||||||
block,
|
block,
|
||||||
engine,
|
engine,
|
||||||
@ -474,7 +484,7 @@ impl Importer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Strip receipts for blocks before validate_receipts_transition,
|
// t_nb 7.6 Strip receipts for blocks before validate_receipts_transition,
|
||||||
// if the expected receipts root header does not match.
|
// if the expected receipts root header does not match.
|
||||||
// (i.e. allow inconsistency in receipts outcome before the transition block)
|
// (i.e. allow inconsistency in receipts outcome before the transition block)
|
||||||
if header.number() < engine.params().validate_receipts_transition
|
if header.number() < engine.params().validate_receipts_transition
|
||||||
@ -483,7 +493,7 @@ impl Importer {
|
|||||||
locked_block.strip_receipts_outcomes();
|
locked_block.strip_receipts_outcomes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final Verification
|
// t_nb 7.7 Final Verification. See if block that we created (executed) matches exactly with block that we received.
|
||||||
if let Err(e) = self
|
if let Err(e) = self
|
||||||
.verifier
|
.verifier
|
||||||
.verify_block_final(&header, &locked_block.header)
|
.verify_block_final(&header, &locked_block.header)
|
||||||
@ -570,6 +580,7 @@ impl Importer {
|
|||||||
|
|
||||||
let mut batch = DBTransaction::new();
|
let mut batch = DBTransaction::new();
|
||||||
|
|
||||||
|
// t_nb 9.1 Gather all ancestry actions. (Used only by AuRa)
|
||||||
let ancestry_actions = self
|
let ancestry_actions = self
|
||||||
.engine
|
.engine
|
||||||
.ancestry_actions(&header, &mut chain.ancestry_with_metadata_iter(*parent));
|
.ancestry_actions(&header, &mut chain.ancestry_with_metadata_iter(*parent));
|
||||||
@ -605,24 +616,28 @@ impl Importer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// t_nb 9.2 calcuate route between current and latest block.
|
||||||
let route = chain.tree_route(best_hash, *parent).expect("forks are only kept when it has common ancestors; tree route from best to prospective's parent always exists; qed");
|
let route = chain.tree_route(best_hash, *parent).expect("forks are only kept when it has common ancestors; tree route from best to prospective's parent always exists; qed");
|
||||||
|
|
||||||
|
// t_nb 9.3 Check block total difficulty
|
||||||
let fork_choice = if route.is_from_route_finalized {
|
let fork_choice = if route.is_from_route_finalized {
|
||||||
ForkChoice::Old
|
ForkChoice::Old
|
||||||
} else {
|
} else {
|
||||||
self.engine.fork_choice(&new, &best)
|
self.engine.fork_choice(&new, &best)
|
||||||
};
|
};
|
||||||
|
|
||||||
// CHECK! I *think* this is fine, even if the state_root is equal to another
|
// t_nb 9.4 CHECK! I *think* this is fine, even if the state_root is equal to another
|
||||||
// already-imported block of the same number.
|
// already-imported block of the same number.
|
||||||
// TODO: Prove it with a test.
|
// TODO: Prove it with a test.
|
||||||
let mut state = block.state.drop().1;
|
let mut state = block.state.drop().1;
|
||||||
|
|
||||||
// check epoch end signal, potentially generating a proof on the current
|
// t_nb 9.5 check epoch end signal, potentially generating a proof on the current
|
||||||
// state.
|
// state. Write transition into db.
|
||||||
if let Some(pending) = pending {
|
if let Some(pending) = pending {
|
||||||
chain.insert_pending_transition(&mut batch, header.hash(), pending);
|
chain.insert_pending_transition(&mut batch, header.hash(), pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 9.6 push state to database Transaction. (It calls journal_under from JournalDB)
|
||||||
state
|
state
|
||||||
.journal_under(&mut batch, number, hash)
|
.journal_under(&mut batch, number, hash)
|
||||||
.expect("DB commit failed");
|
.expect("DB commit failed");
|
||||||
@ -633,6 +648,7 @@ impl Importer {
|
|||||||
let AncestryAction::MarkFinalized(a) = ancestry_action;
|
let AncestryAction::MarkFinalized(a) = ancestry_action;
|
||||||
|
|
||||||
if a != header.hash() {
|
if a != header.hash() {
|
||||||
|
// t_nb 9.7 if there are finalized ancester, mark that chainge in block in db. (Used by AuRa)
|
||||||
chain
|
chain
|
||||||
.mark_finalized(&mut batch, a)
|
.mark_finalized(&mut batch, a)
|
||||||
.expect("Engine's ancestry action must be known blocks; qed");
|
.expect("Engine's ancestry action must be known blocks; qed");
|
||||||
@ -645,6 +661,7 @@ impl Importer {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
// t_nb 9.8 insert block
|
||||||
let route = chain.insert_block(
|
let route = chain.insert_block(
|
||||||
&mut batch,
|
&mut batch,
|
||||||
block_data,
|
block_data,
|
||||||
@ -655,6 +672,7 @@ impl Importer {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// t_nb 9.9 insert traces (if they are enabled)
|
||||||
client.tracedb.read().import(
|
client.tracedb.read().import(
|
||||||
&mut batch,
|
&mut batch,
|
||||||
TraceImportRequest {
|
TraceImportRequest {
|
||||||
@ -667,15 +685,22 @@ impl Importer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let is_canon = route.enacted.last().map_or(false, |h| h == hash);
|
let is_canon = route.enacted.last().map_or(false, |h| h == hash);
|
||||||
|
|
||||||
|
// t_nb 9.10 sync cache
|
||||||
state.sync_cache(&route.enacted, &route.retracted, is_canon);
|
state.sync_cache(&route.enacted, &route.retracted, is_canon);
|
||||||
// Final commit to the DB
|
// Final commit to the DB
|
||||||
|
// t_nb 9.11 Write Transaction to database (cached)
|
||||||
client.db.read().key_value().write_buffered(batch);
|
client.db.read().key_value().write_buffered(batch);
|
||||||
|
// t_nb 9.12 commit changed to become current greatest by applying pending insertion updates (Sync point)
|
||||||
chain.commit();
|
chain.commit();
|
||||||
|
|
||||||
|
// t_nb 9.13 check epoch end. Related only to AuRa and it seems light engine
|
||||||
self.check_epoch_end(&header, &finalized, &chain, client);
|
self.check_epoch_end(&header, &finalized, &chain, client);
|
||||||
|
|
||||||
|
// t_nb 9.14 update last hashes. They are build in step 7.5
|
||||||
client.update_last_hashes(&parent, hash);
|
client.update_last_hashes(&parent, hash);
|
||||||
|
|
||||||
|
// t_nb 9.15 prune ancient states
|
||||||
if let Err(e) = client.prune_ancient(state, &chain) {
|
if let Err(e) = client.prune_ancient(state, &chain) {
|
||||||
warn!("Failed to prune ancient state data: {}", e);
|
warn!("Failed to prune ancient state data: {}", e);
|
||||||
}
|
}
|
||||||
@ -1098,7 +1123,7 @@ impl Client {
|
|||||||
with_call(&call)
|
with_call(&call)
|
||||||
}
|
}
|
||||||
|
|
||||||
// prune ancient states until below the memory limit or only the minimum amount remain.
|
// t_nb 9.15 prune ancient states until below the memory limit or only the minimum amount remain.
|
||||||
fn prune_ancient(
|
fn prune_ancient(
|
||||||
&self,
|
&self,
|
||||||
mut state_db: StateDB,
|
mut state_db: StateDB,
|
||||||
@ -1138,6 +1163,7 @@ impl Client {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 9.14 update last hashes. They are build in step 7.5
|
||||||
fn update_last_hashes(&self, parent: &H256, hash: &H256) {
|
fn update_last_hashes(&self, parent: &H256, hash: &H256) {
|
||||||
let mut hashes = self.last_hashes.write();
|
let mut hashes = self.last_hashes.write();
|
||||||
if hashes.front().map_or(false, |h| h == parent) {
|
if hashes.front().map_or(false, |h| h == parent) {
|
||||||
@ -1721,11 +1747,14 @@ impl CallContract for Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ImportBlock for Client {
|
impl ImportBlock for Client {
|
||||||
|
// t_nb 2.0 import block to client
|
||||||
fn import_block(&self, unverified: Unverified) -> EthcoreResult<H256> {
|
fn import_block(&self, unverified: Unverified) -> EthcoreResult<H256> {
|
||||||
|
// t_nb 2.1 check if header hash is known to us.
|
||||||
if self.chain.read().is_known(&unverified.hash()) {
|
if self.chain.read().is_known(&unverified.hash()) {
|
||||||
bail!(EthcoreErrorKind::Import(ImportErrorKind::AlreadyInChain));
|
bail!(EthcoreErrorKind::Import(ImportErrorKind::AlreadyInChain));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 2.2 check if parent is known
|
||||||
let status = self.block_status(BlockId::Hash(unverified.parent_hash()));
|
let status = self.block_status(BlockId::Hash(unverified.parent_hash()));
|
||||||
if status == BlockStatus::Unknown {
|
if status == BlockStatus::Unknown {
|
||||||
bail!(EthcoreErrorKind::Block(BlockError::UnknownParent(
|
bail!(EthcoreErrorKind::Block(BlockError::UnknownParent(
|
||||||
@ -1743,14 +1772,16 @@ impl ImportBlock for Client {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// t_nb 2.3
|
||||||
match self.importer.block_queue.import(unverified) {
|
match self.importer.block_queue.import(unverified) {
|
||||||
Ok(hash) => {
|
Ok(hash) => {
|
||||||
|
// t_nb 2.4 If block is okay and the queue is empty we propagate the block in a `PriorityTask` to be rebrodcasted
|
||||||
if let Some((raw, hash, difficulty)) = raw {
|
if let Some((raw, hash, difficulty)) = raw {
|
||||||
self.notify(move |n| n.block_pre_import(&raw, &hash, &difficulty));
|
self.notify(move |n| n.block_pre_import(&raw, &hash, &difficulty));
|
||||||
}
|
}
|
||||||
Ok(hash)
|
Ok(hash)
|
||||||
}
|
}
|
||||||
// we only care about block errors (not import errors)
|
// t_nb 2.5 if block is not okay print error. we only care about block errors (not import errors)
|
||||||
Err((Some(block), EthcoreError(EthcoreErrorKind::Block(err), _))) => {
|
Err((Some(block), EthcoreError(EthcoreErrorKind::Block(err), _))) => {
|
||||||
self.importer
|
self.importer
|
||||||
.bad_blocks
|
.bad_blocks
|
||||||
|
@ -1307,6 +1307,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 8.1.5
|
||||||
fn on_new_block(
|
fn on_new_block(
|
||||||
&self,
|
&self,
|
||||||
block: &mut ExecutedBlock,
|
block: &mut ExecutedBlock,
|
||||||
@ -1531,7 +1532,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the validators.
|
// t_nb 6.4 Check the validators.
|
||||||
fn verify_block_external(&self, header: &Header) -> Result<(), Error> {
|
fn verify_block_external(&self, header: &Header) -> Result<(), Error> {
|
||||||
let (validators, set_number) = self.epoch_set(header)?;
|
let (validators, set_number) = self.epoch_set(header)?;
|
||||||
|
|
||||||
|
@ -488,7 +488,7 @@ pub trait Engine<M: Machine>: Sync + Send {
|
|||||||
header_timestamp > parent_timestamp
|
header_timestamp > parent_timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gather all ancestry actions. Called at the last stage when a block is committed. The Engine must guarantee that
|
// t_nb 9.1 Gather all ancestry actions. Called at the last stage when a block is committed. The Engine must guarantee that
|
||||||
/// the ancestry exists.
|
/// the ancestry exists.
|
||||||
fn ancestry_actions(
|
fn ancestry_actions(
|
||||||
&self,
|
&self,
|
||||||
@ -507,7 +507,7 @@ pub trait Engine<M: Machine>: Sync + Send {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether a given block is the best block based on the default total difficulty rule.
|
// t_nb 9.3 Check whether a given block is the best block based on the default total difficulty rule.
|
||||||
pub fn total_difficulty_fork_choice(new: &ExtendedHeader, best: &ExtendedHeader) -> ForkChoice {
|
pub fn total_difficulty_fork_choice(new: &ExtendedHeader, best: &ExtendedHeader) -> ForkChoice {
|
||||||
if new.total_score() > best.total_score() {
|
if new.total_score() > best.total_score() {
|
||||||
ForkChoice::New
|
ForkChoice::New
|
||||||
@ -562,7 +562,7 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> {
|
|||||||
self.machine().create_address_scheme(number)
|
self.machine().create_address_scheme(number)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a particular transaction is valid.
|
// t_nb 5.3.1 Verify a particular transaction is valid.
|
||||||
///
|
///
|
||||||
/// Unordered verification doesn't rely on the transaction execution order,
|
/// Unordered verification doesn't rely on the transaction execution order,
|
||||||
/// i.e. it should only verify stuff that doesn't assume any previous transactions
|
/// i.e. it should only verify stuff that doesn't assume any previous transactions
|
||||||
|
@ -238,7 +238,7 @@ impl EthereumMachine {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Logic to perform on a new block: updating last hashes and the DAO
|
// t_nb 8.1.3 Logic to perform on a new block: updating last hashes and the DAO
|
||||||
/// fork, for ethash.
|
/// fork, for ethash.
|
||||||
pub fn on_new_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
|
pub fn on_new_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
|
||||||
self.push_last_hash(block)?;
|
self.push_last_hash(block)?;
|
||||||
|
@ -1230,7 +1230,7 @@ impl miner::MinerService for Miner {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update sealing if required.
|
// t_nb 10.4 Update sealing if required.
|
||||||
/// Prepare the block and work if the Engine does not seal internally.
|
/// Prepare the block and work if the Engine does not seal internally.
|
||||||
fn update_sealing<C>(&self, chain: &C, force: ForceUpdateSealing)
|
fn update_sealing<C>(&self, chain: &C, force: ForceUpdateSealing)
|
||||||
where
|
where
|
||||||
@ -1339,6 +1339,7 @@ impl miner::MinerService for Miner {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 10 notify miner about new include blocks
|
||||||
fn chain_new_blocks<C>(
|
fn chain_new_blocks<C>(
|
||||||
&self,
|
&self,
|
||||||
chain: &C,
|
chain: &C,
|
||||||
@ -1363,11 +1364,11 @@ impl miner::MinerService for Miner {
|
|||||||
self.nonce_cache.clear();
|
self.nonce_cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// First update gas limit in transaction queue and minimal gas price.
|
// t_nb 10.1 First update gas limit in transaction queue and minimal gas price.
|
||||||
let gas_limit = *chain.best_block_header().gas_limit();
|
let gas_limit = *chain.best_block_header().gas_limit();
|
||||||
self.update_transaction_queue_limits(gas_limit);
|
self.update_transaction_queue_limits(gas_limit);
|
||||||
|
|
||||||
// Then import all transactions from retracted blocks.
|
// t_nb 10.2 Then import all transactions from retracted blocks (retracted means from side chain).
|
||||||
let client = self.pool_client(chain);
|
let client = self.pool_client(chain);
|
||||||
{
|
{
|
||||||
retracted
|
retracted
|
||||||
@ -1378,7 +1379,8 @@ impl miner::MinerService for Miner {
|
|||||||
let txs = block.transactions()
|
let txs = block.transactions()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(pool::verifier::Transaction::Retracted)
|
.map(pool::verifier::Transaction::Retracted)
|
||||||
.collect();
|
.collect();
|
||||||
|
// t_nb 10.2
|
||||||
let _ = self.transaction_queue.import(
|
let _ = self.transaction_queue.import(
|
||||||
client.clone(),
|
client.clone(),
|
||||||
txs,
|
txs,
|
||||||
@ -1387,12 +1389,13 @@ impl miner::MinerService for Miner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if has_new_best_block || (imported.len() > 0 && self.options.reseal_on_uncle) {
|
if has_new_best_block || (imported.len() > 0 && self.options.reseal_on_uncle) {
|
||||||
// Reset `next_allowed_reseal` in case a block is imported.
|
// t_nb 10.3 Reset `next_allowed_reseal` in case a block is imported.
|
||||||
// Even if min_period is high, we will always attempt to create
|
// Even if min_period is high, we will always attempt to create
|
||||||
// new pending block.
|
// new pending block.
|
||||||
self.sealing.lock().next_allowed_reseal = Instant::now();
|
self.sealing.lock().next_allowed_reseal = Instant::now();
|
||||||
|
|
||||||
if !is_internal_import {
|
if !is_internal_import {
|
||||||
|
// t_nb 10.4 if it is internal import update sealing
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// | NOTE Code below requires sealing locks. |
|
// | NOTE Code below requires sealing locks. |
|
||||||
// | Make sure to release the locks before calling that method. |
|
// | Make sure to release the locks before calling that method. |
|
||||||
@ -1402,7 +1405,7 @@ impl miner::MinerService for Miner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if has_new_best_block {
|
if has_new_best_block {
|
||||||
// Make sure to cull transactions after we update sealing.
|
// t_nb 10.5 Make sure to cull transactions after we update sealing.
|
||||||
// Not culling won't lead to old transactions being added to the block
|
// Not culling won't lead to old transactions being added to the block
|
||||||
// (thanks to Ready), but culling can take significant amount of time,
|
// (thanks to Ready), but culling can take significant amount of time,
|
||||||
// so best to leave it after we create some work for miners to prevent increased
|
// so best to leave it after we create some work for miners to prevent increased
|
||||||
@ -1424,7 +1427,9 @@ impl miner::MinerService for Miner {
|
|||||||
&*accounts,
|
&*accounts,
|
||||||
service_transaction_checker.as_ref(),
|
service_transaction_checker.as_ref(),
|
||||||
);
|
);
|
||||||
|
// t_nb 10.5 do culling
|
||||||
queue.cull(client);
|
queue.cull(client);
|
||||||
|
// reseal is only used by InstaSeal engine
|
||||||
if engine.should_reseal_on_update() {
|
if engine.should_reseal_on_update() {
|
||||||
// force update_sealing here to skip `reseal_required` checks
|
// force update_sealing here to skip `reseal_required` checks
|
||||||
chain.update_sealing(ForceUpdateSealing::Yes);
|
chain.update_sealing(ForceUpdateSealing::Yes);
|
||||||
@ -1435,13 +1440,16 @@ impl miner::MinerService for Miner {
|
|||||||
warn!(target: "miner", "Error queueing cull: {:?}", e);
|
warn!(target: "miner", "Error queueing cull: {:?}", e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// t_nb 10.5 do culling
|
||||||
self.transaction_queue.cull(client);
|
self.transaction_queue.cull(client);
|
||||||
|
// reseal is only used by InstaSeal engine
|
||||||
if self.engine.should_reseal_on_update() {
|
if self.engine.should_reseal_on_update() {
|
||||||
// force update_sealing here to skip `reseal_required` checks
|
// force update_sealing here to skip `reseal_required` checks
|
||||||
self.update_sealing(chain, ForceUpdateSealing::Yes);
|
self.update_sealing(chain, ForceUpdateSealing::Yes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// t_nb 10.6 For service transaction checker update addresses to latest block
|
||||||
if let Some(ref service_transaction_checker) = self.service_transaction_checker {
|
if let Some(ref service_transaction_checker) = self.service_transaction_checker {
|
||||||
match service_transaction_checker.refresh_cache(chain) {
|
match service_transaction_checker.refresh_cache(chain) {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
|
@ -111,6 +111,7 @@ impl Watcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ChainNotify for Watcher {
|
impl ChainNotify for Watcher {
|
||||||
|
// t_nb 11.1 check number of block and trigger snapshot creation if needed.
|
||||||
fn new_blocks(&self, new_blocks: NewBlocks) {
|
fn new_blocks(&self, new_blocks: NewBlocks) {
|
||||||
if self.oracle.is_major_importing() || new_blocks.has_more_blocks_to_import {
|
if self.oracle.is_major_importing() || new_blocks.has_more_blocks_to_import {
|
||||||
return;
|
return;
|
||||||
|
@ -43,7 +43,7 @@ pub trait Backend: Send {
|
|||||||
/// Treat the backend as a writeable hashdb.
|
/// Treat the backend as a writeable hashdb.
|
||||||
fn as_hash_db_mut(&mut self) -> &mut dyn HashDB<KeccakHasher, DBValue>;
|
fn as_hash_db_mut(&mut self) -> &mut dyn HashDB<KeccakHasher, DBValue>;
|
||||||
|
|
||||||
/// Add an account entry to the cache.
|
// t_nb 9.4 Add an account entry to the cache.
|
||||||
fn add_to_account_cache(&mut self, addr: Address, data: Option<Account>, modified: bool);
|
fn add_to_account_cache(&mut self, addr: Address, data: Option<Account>, modified: bool);
|
||||||
|
|
||||||
/// Add a global code cache entry. This doesn't need to worry about canonicality because
|
/// Add a global code cache entry. This doesn't need to worry about canonicality because
|
||||||
|
@ -996,7 +996,7 @@ impl<B: Backend> State<B> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commits our cached account changes into the trie.
|
// t_nb 8.5.2 Commits our cached account changes into the trie.
|
||||||
pub fn commit(&mut self) -> Result<(), Error> {
|
pub fn commit(&mut self) -> Result<(), Error> {
|
||||||
assert!(self.checkpoints.borrow().is_empty());
|
assert!(self.checkpoints.borrow().is_empty());
|
||||||
// first, commit the sub trees.
|
// first, commit the sub trees.
|
||||||
@ -1036,7 +1036,7 @@ impl<B: Backend> State<B> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Propagate local cache into shared canonical state cache.
|
// t_nb 9.4 Propagate local cache into shared canonical state cache.
|
||||||
fn propagate_to_global_cache(&mut self) {
|
fn propagate_to_global_cache(&mut self) {
|
||||||
let mut addresses = self.cache.borrow_mut();
|
let mut addresses = self.cache.borrow_mut();
|
||||||
trace!("Committing cache {:?} entries", addresses.len());
|
trace!("Committing cache {:?} entries", addresses.len());
|
||||||
|
@ -147,6 +147,7 @@ impl StateDB {
|
|||||||
Ok(records)
|
Ok(records)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 9.15
|
||||||
/// Mark a given candidate from an ancient era as canonical, enacting its removals from the
|
/// Mark a given candidate from an ancient era as canonical, enacting its removals from the
|
||||||
/// backing database and reverting any non-canonical historical commit's insertions.
|
/// backing database and reverting any non-canonical historical commit's insertions.
|
||||||
pub fn mark_canonical(
|
pub fn mark_canonical(
|
||||||
@ -158,7 +159,7 @@ impl StateDB {
|
|||||||
self.db.mark_canonical(batch, end_era, canon_id)
|
self.db.mark_canonical(batch, end_era, canon_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Propagate local cache into the global cache and synchonize
|
// t_nb 9.10 Propagate local cache into the global cache and synchonize
|
||||||
/// the global cache with the best block state.
|
/// the global cache with the best block state.
|
||||||
/// This function updates the global cache by removing entries
|
/// This function updates the global cache by removing entries
|
||||||
/// that are invalidated by chain reorganization. `sync_cache`
|
/// that are invalidated by chain reorganization. `sync_cache`
|
||||||
|
@ -95,6 +95,7 @@ pub mod blocks {
|
|||||||
type Unverified = Unverified;
|
type Unverified = Unverified;
|
||||||
type Verified = PreverifiedBlock;
|
type Verified = PreverifiedBlock;
|
||||||
|
|
||||||
|
// t_nb 4.0 verify_block_basic
|
||||||
fn create(
|
fn create(
|
||||||
input: Self::Input,
|
input: Self::Input,
|
||||||
engine: &dyn EthEngine,
|
engine: &dyn EthEngine,
|
||||||
@ -113,6 +114,7 @@ pub mod blocks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 5.0 verify standalone block
|
||||||
fn verify(
|
fn verify(
|
||||||
un: Self::Unverified,
|
un: Self::Unverified,
|
||||||
engine: &dyn EthEngine,
|
engine: &dyn EthEngine,
|
||||||
|
@ -364,7 +364,7 @@ impl<K: Kind> VerificationQueue<K> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// do work.
|
// do work on this item.
|
||||||
let item = {
|
let item = {
|
||||||
// acquire these locks before getting the item to verify.
|
// acquire these locks before getting the item to verify.
|
||||||
let mut unverified = verification.unverified.lock();
|
let mut unverified = verification.unverified.lock();
|
||||||
@ -387,10 +387,12 @@ impl<K: Kind> VerificationQueue<K> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let hash = item.hash();
|
let hash = item.hash();
|
||||||
|
// t_nb 5.0 verify standalone block (this verification is done in VerificationQueue thread pool)
|
||||||
let is_ready = match K::verify(item, &*engine, verification.check_seal) {
|
let is_ready = match K::verify(item, &*engine, verification.check_seal) {
|
||||||
Ok(verified) => {
|
Ok(verified) => {
|
||||||
let mut verifying = verification.verifying.lock();
|
let mut verifying = verification.verifying.lock();
|
||||||
let mut idx = None;
|
let mut idx = None;
|
||||||
|
// find item again and remove it from verified queue
|
||||||
for (i, e) in verifying.iter_mut().enumerate() {
|
for (i, e) in verifying.iter_mut().enumerate() {
|
||||||
if e.hash == hash {
|
if e.hash == hash {
|
||||||
idx = Some(i);
|
idx = Some(i);
|
||||||
@ -515,17 +517,20 @@ impl<K: Kind> VerificationQueue<K> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add a block to the queue.
|
/// Add a block to the queue.
|
||||||
|
// t_nb 3.0 import block to verification queue
|
||||||
pub fn import(&self, input: K::Input) -> Result<H256, (Option<K::Input>, Error)> {
|
pub fn import(&self, input: K::Input) -> Result<H256, (Option<K::Input>, Error)> {
|
||||||
let hash = input.hash();
|
let hash = input.hash();
|
||||||
let raw_hash = input.raw_hash();
|
let raw_hash = input.raw_hash();
|
||||||
|
// t_nb 3.1 check if block is currently processing or marked as bad.
|
||||||
{
|
{
|
||||||
|
// t_nb 3.1.0 is currently processing
|
||||||
if self.processing.read().contains_key(&hash) {
|
if self.processing.read().contains_key(&hash) {
|
||||||
bail!((
|
bail!((
|
||||||
Some(input),
|
Some(input),
|
||||||
ErrorKind::Import(ImportErrorKind::AlreadyQueued).into()
|
ErrorKind::Import(ImportErrorKind::AlreadyQueued).into()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
// t_nb 3.1.1 is marked as bad
|
||||||
let mut bad = self.verification.bad.lock();
|
let mut bad = self.verification.bad.lock();
|
||||||
if bad.contains(&hash) || bad.contains(&raw_hash) {
|
if bad.contains(&hash) || bad.contains(&raw_hash) {
|
||||||
bail!((
|
bail!((
|
||||||
@ -533,7 +538,7 @@ impl<K: Kind> VerificationQueue<K> {
|
|||||||
ErrorKind::Import(ImportErrorKind::KnownBad).into()
|
ErrorKind::Import(ImportErrorKind::KnownBad).into()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
// t_nb 3.1.2 its parent is marked as bad
|
||||||
if bad.contains(&input.parent_hash()) {
|
if bad.contains(&input.parent_hash()) {
|
||||||
bad.insert(hash);
|
bad.insert(hash);
|
||||||
bail!((
|
bail!((
|
||||||
|
@ -63,26 +63,36 @@ impl HeapSizeOf for PreverifiedBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 1 quick block verification. Only does checks that are cheap. Operates on a single block
|
// t_nb 4.0 Phase 1 quick block verification. Only does checks that are cheap. Operates on a single block
|
||||||
pub fn verify_block_basic(
|
pub fn verify_block_basic(
|
||||||
block: &Unverified,
|
block: &Unverified,
|
||||||
engine: &dyn EthEngine,
|
engine: &dyn EthEngine,
|
||||||
check_seal: bool,
|
check_seal: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
// t_nb 4.1 verify header params
|
||||||
verify_header_params(&block.header, engine, true, check_seal)?;
|
verify_header_params(&block.header, engine, true, check_seal)?;
|
||||||
|
// t_nb 4.2 verify header time (addded in new OE version)
|
||||||
|
// t_nb 4.3 verify block integrity
|
||||||
verify_block_integrity(block)?;
|
verify_block_integrity(block)?;
|
||||||
|
|
||||||
if check_seal {
|
if check_seal {
|
||||||
|
// t_nb 4.4 Check block seal. It calls engine to verify block basic
|
||||||
engine.verify_block_basic(&block.header)?;
|
engine.verify_block_basic(&block.header)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 4.5 for all uncled verify header and call engine to verify block basic
|
||||||
for uncle in &block.uncles {
|
for uncle in &block.uncles {
|
||||||
|
// t_nb 4.5.1
|
||||||
verify_header_params(uncle, engine, false, check_seal)?;
|
verify_header_params(uncle, engine, false, check_seal)?;
|
||||||
if check_seal {
|
if check_seal {
|
||||||
|
// t_nb 4.5.2
|
||||||
engine.verify_block_basic(uncle)?;
|
engine.verify_block_basic(uncle)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 4.6 call engine.gas_limit_override (Used only by Aura) TODO added in new version
|
||||||
|
|
||||||
|
// t_nb 4.7 for every transaction call engine.verify_transaction_basic
|
||||||
for t in &block.transactions {
|
for t in &block.transactions {
|
||||||
engine.verify_transaction_basic(t, &block.header)?;
|
engine.verify_transaction_basic(t, &block.header)?;
|
||||||
}
|
}
|
||||||
@ -90,7 +100,7 @@ pub fn verify_block_basic(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash.
|
// t_nb 5.0 Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash.
|
||||||
/// Still operates on a individual block
|
/// Still operates on a individual block
|
||||||
/// Returns a `PreverifiedBlock` structure populated with transactions
|
/// Returns a `PreverifiedBlock` structure populated with transactions
|
||||||
pub fn verify_block_unordered(
|
pub fn verify_block_unordered(
|
||||||
@ -100,8 +110,10 @@ pub fn verify_block_unordered(
|
|||||||
) -> Result<PreverifiedBlock, Error> {
|
) -> Result<PreverifiedBlock, Error> {
|
||||||
let header = block.header;
|
let header = block.header;
|
||||||
if check_seal {
|
if check_seal {
|
||||||
|
// t_nb 5.1
|
||||||
engine.verify_block_unordered(&header)?;
|
engine.verify_block_unordered(&header)?;
|
||||||
for uncle in &block.uncles {
|
for uncle in &block.uncles {
|
||||||
|
// t_nb 5.2
|
||||||
engine.verify_block_unordered(uncle)?;
|
engine.verify_block_unordered(uncle)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,11 +124,14 @@ pub fn verify_block_unordered(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// t_nb 5.3 iterate over all transactions
|
||||||
let transactions = block
|
let transactions = block
|
||||||
.transactions
|
.transactions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|t| {
|
.map(|t| {
|
||||||
|
// t_nb 5.3.1 call verify_unordered. Check signatures and calculate address
|
||||||
let t = engine.verify_transaction_unordered(t, &header)?;
|
let t = engine.verify_transaction_unordered(t, &header)?;
|
||||||
|
// t_nb 5.3.2 check if nonce is more then max nonce (EIP-168 and EIP169)
|
||||||
if let Some(max_nonce) = nonce_cap {
|
if let Some(max_nonce) = nonce_cap {
|
||||||
if t.nonce >= max_nonce {
|
if t.nonce >= max_nonce {
|
||||||
return Err(BlockError::TooManyTransactions(t.sender()).into());
|
return Err(BlockError::TooManyTransactions(t.sender()).into());
|
||||||
@ -146,7 +161,7 @@ pub struct FullFamilyParams<'a, C: BlockInfo + CallContract + 'a> {
|
|||||||
pub client: &'a C,
|
pub client: &'a C,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 3 verification. Check block information against parent and uncles.
|
// t_nb 6.3 Phase 3 verification. Check block information against parent and uncles.
|
||||||
pub fn verify_block_family<C: BlockInfo + CallContract>(
|
pub fn verify_block_family<C: BlockInfo + CallContract>(
|
||||||
header: &Header,
|
header: &Header,
|
||||||
parent: &Header,
|
parent: &Header,
|
||||||
@ -154,6 +169,7 @@ pub fn verify_block_family<C: BlockInfo + CallContract>(
|
|||||||
do_full: Option<FullFamilyParams<C>>,
|
do_full: Option<FullFamilyParams<C>>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// TODO: verify timestamp
|
// TODO: verify timestamp
|
||||||
|
// t_nb 6.3.1 verify parent
|
||||||
verify_parent(&header, &parent, engine)?;
|
verify_parent(&header, &parent, engine)?;
|
||||||
engine.verify_block_family(&header, &parent)?;
|
engine.verify_block_family(&header, &parent)?;
|
||||||
|
|
||||||
@ -162,8 +178,10 @@ pub fn verify_block_family<C: BlockInfo + CallContract>(
|
|||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// t_nb 6.3.2 verify uncles
|
||||||
verify_uncles(params.block, params.block_provider, engine)?;
|
verify_uncles(params.block, params.block_provider, engine)?;
|
||||||
|
|
||||||
|
// t_nb 6.3.3 verify all transactions
|
||||||
for tx in ¶ms.block.transactions {
|
for tx in ¶ms.block.transactions {
|
||||||
// transactions are verified against the parent header since the current
|
// transactions are verified against the parent header since the current
|
||||||
// state wasn't available when the tx was created
|
// state wasn't available when the tx was created
|
||||||
|
@ -529,6 +529,7 @@ impl ChainNotify for EthSync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 11.4
|
||||||
fn new_blocks(&self, new_blocks: NewBlocks) {
|
fn new_blocks(&self, new_blocks: NewBlocks) {
|
||||||
if new_blocks.has_more_blocks_to_import {
|
if new_blocks.has_more_blocks_to_import {
|
||||||
return;
|
return;
|
||||||
|
@ -155,6 +155,7 @@ impl SyncHandler {
|
|||||||
trace!(target: "sync", "Ignoring new block from unconfirmed peer {}", peer_id);
|
trace!(target: "sync", "Ignoring new block from unconfirmed peer {}", peer_id);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
// t_nb 1.0 decode RLP
|
||||||
let block = Unverified::from_rlp(r.at(0)?.as_raw().to_vec())?;
|
let block = Unverified::from_rlp(r.at(0)?.as_raw().to_vec())?;
|
||||||
let hash = block.header.hash();
|
let hash = block.header.hash();
|
||||||
let number = block.header.number();
|
let number = block.header.number();
|
||||||
@ -166,7 +167,9 @@ impl SyncHandler {
|
|||||||
let difficulty: U256 = r.val_at(1)?;
|
let difficulty: U256 = r.val_at(1)?;
|
||||||
// Most probably the sent block is being imported by peer right now
|
// Most probably the sent block is being imported by peer right now
|
||||||
// Use td and hash, that peer must have for now
|
// Use td and hash, that peer must have for now
|
||||||
|
// t_nb 1.1 check new block diffuculty it can be found as second item in RLP and update peer diffuculty
|
||||||
let parent_td = difficulty.checked_sub(*block.header.difficulty());
|
let parent_td = difficulty.checked_sub(*block.header.difficulty());
|
||||||
|
|
||||||
if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) {
|
if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) {
|
||||||
if peer
|
if peer
|
||||||
.difficulty
|
.difficulty
|
||||||
@ -181,6 +184,7 @@ impl SyncHandler {
|
|||||||
peer.latest_hash = *parent_hash;
|
peer.latest_hash = *parent_hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 1.2 if block number is to older then 20 dont process it
|
||||||
let last_imported_number = sync.new_blocks.last_imported_block_number();
|
let last_imported_number = sync.new_blocks.last_imported_block_number();
|
||||||
if last_imported_number > number && last_imported_number - number > MAX_NEW_BLOCK_AGE {
|
if last_imported_number > number && last_imported_number - number > MAX_NEW_BLOCK_AGE {
|
||||||
trace!(target: "sync", "Ignored ancient new block {:?}", hash);
|
trace!(target: "sync", "Ignored ancient new block {:?}", hash);
|
||||||
|
@ -1421,7 +1421,7 @@ impl ChainSync {
|
|||||||
self.check_resume(io);
|
self.check_resume(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// called when block is imported to chain - propagates the blocks and updates transactions sent to peers
|
// t_nb 11.4 called when block is imported to chain - propagates the blocks and updates transactions sent to peers
|
||||||
pub fn chain_new_blocks(
|
pub fn chain_new_blocks(
|
||||||
&mut self,
|
&mut self,
|
||||||
io: &mut dyn SyncIo,
|
io: &mut dyn SyncIo,
|
||||||
@ -1437,7 +1437,9 @@ impl ChainSync {
|
|||||||
|
|
||||||
if !is_syncing || !sealed.is_empty() || !proposed.is_empty() {
|
if !is_syncing || !sealed.is_empty() || !proposed.is_empty() {
|
||||||
trace!(target: "sync", "Propagating blocks, state={:?}", self.state);
|
trace!(target: "sync", "Propagating blocks, state={:?}", self.state);
|
||||||
|
// t_nb 11.4.1 propagate latest blocks
|
||||||
SyncPropagator::propagate_latest_blocks(self, io, sealed);
|
SyncPropagator::propagate_latest_blocks(self, io, sealed);
|
||||||
|
// t_nb 11.4.4 propagate proposed blocks
|
||||||
SyncPropagator::propagate_proposed_blocks(self, io, proposed);
|
SyncPropagator::propagate_proposed_blocks(self, io, proposed);
|
||||||
}
|
}
|
||||||
if !invalid.is_empty() {
|
if !invalid.is_empty() {
|
||||||
@ -1446,7 +1448,7 @@ impl ChainSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !is_syncing && !enacted.is_empty() && !self.peers.is_empty() {
|
if !is_syncing && !enacted.is_empty() && !self.peers.is_empty() {
|
||||||
// Select random peer to re-broadcast transactions to.
|
// t_nb 11.4.5 Select random peer to re-broadcast transactions to.
|
||||||
let peer = random::new().gen_range(0, self.peers.len());
|
let peer = random::new().gen_range(0, self.peers.len());
|
||||||
trace!(target: "sync", "Re-broadcasting transactions to a random peer.");
|
trace!(target: "sync", "Re-broadcasting transactions to a random peer.");
|
||||||
self.peers.values_mut().nth(peer).map(|peer_info| {
|
self.peers.values_mut().nth(peer).map(|peer_info| {
|
||||||
|
@ -39,7 +39,7 @@ use super::{
|
|||||||
pub struct SyncPropagator;
|
pub struct SyncPropagator;
|
||||||
|
|
||||||
impl SyncPropagator {
|
impl SyncPropagator {
|
||||||
/// propagates latest block to a set of peers
|
// t_nb 11.4.3 propagates latest block to a set of peers
|
||||||
pub fn propagate_blocks(
|
pub fn propagate_blocks(
|
||||||
sync: &mut ChainSync,
|
sync: &mut ChainSync,
|
||||||
chain_info: &BlockChainInfo,
|
chain_info: &BlockChainInfo,
|
||||||
@ -72,7 +72,7 @@ impl SyncPropagator {
|
|||||||
sent
|
sent
|
||||||
}
|
}
|
||||||
|
|
||||||
/// propagates new known hashes to all peers
|
// t_nb 11.4.2 propagates new known hashes to all peers
|
||||||
pub fn propagate_new_hashes(
|
pub fn propagate_new_hashes(
|
||||||
sync: &mut ChainSync,
|
sync: &mut ChainSync,
|
||||||
chain_info: &BlockChainInfo,
|
chain_info: &BlockChainInfo,
|
||||||
@ -279,6 +279,7 @@ impl SyncPropagator {
|
|||||||
sent_to_peers
|
sent_to_peers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 11.4.1 propagate latest blocks to peers
|
||||||
pub fn propagate_latest_blocks(sync: &mut ChainSync, io: &mut dyn SyncIo, sealed: &[H256]) {
|
pub fn propagate_latest_blocks(sync: &mut ChainSync, io: &mut dyn SyncIo, sealed: &[H256]) {
|
||||||
let chain_info = io.chain().chain_info();
|
let chain_info = io.chain().chain_info();
|
||||||
if (((chain_info.best_block_number as i64) - (sync.last_sent_block_number as i64)).abs()
|
if (((chain_info.best_block_number as i64) - (sync.last_sent_block_number as i64)).abs()
|
||||||
@ -287,15 +288,19 @@ impl SyncPropagator {
|
|||||||
{
|
{
|
||||||
let peers = sync.get_lagging_peers(&chain_info);
|
let peers = sync.get_lagging_peers(&chain_info);
|
||||||
if sealed.is_empty() {
|
if sealed.is_empty() {
|
||||||
|
// t_nb 11.4.2
|
||||||
let hashes = SyncPropagator::propagate_new_hashes(sync, &chain_info, io, &peers);
|
let hashes = SyncPropagator::propagate_new_hashes(sync, &chain_info, io, &peers);
|
||||||
let peers = ChainSync::select_random_peers(&peers);
|
let peers = ChainSync::select_random_peers(&peers);
|
||||||
|
// t_nb 11.4.3
|
||||||
let blocks =
|
let blocks =
|
||||||
SyncPropagator::propagate_blocks(sync, &chain_info, io, sealed, &peers);
|
SyncPropagator::propagate_blocks(sync, &chain_info, io, sealed, &peers);
|
||||||
if blocks != 0 || hashes != 0 {
|
if blocks != 0 || hashes != 0 {
|
||||||
trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes);
|
trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// t_nb 11.4.3
|
||||||
SyncPropagator::propagate_blocks(sync, &chain_info, io, sealed, &peers);
|
SyncPropagator::propagate_blocks(sync, &chain_info, io, sealed, &peers);
|
||||||
|
// t_nb 11.4.2
|
||||||
SyncPropagator::propagate_new_hashes(sync, &chain_info, io, &peers);
|
SyncPropagator::propagate_new_hashes(sync, &chain_info, io, &peers);
|
||||||
trace!(target: "sync", "Sent sealed block to all peers");
|
trace!(target: "sync", "Sent sealed block to all peers");
|
||||||
};
|
};
|
||||||
@ -303,7 +308,7 @@ impl SyncPropagator {
|
|||||||
sync.last_sent_block_number = chain_info.best_block_number;
|
sync.last_sent_block_number = chain_info.best_block_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Distribute valid proposed blocks to subset of current peers.
|
// t_nb 11.4.4 Distribute valid proposed blocks to subset of current peers. (if there is any proposed)
|
||||||
pub fn propagate_proposed_blocks(
|
pub fn propagate_proposed_blocks(
|
||||||
sync: &mut ChainSync,
|
sync: &mut ChainSync,
|
||||||
io: &mut dyn SyncIo,
|
io: &mut dyn SyncIo,
|
||||||
|
@ -468,7 +468,7 @@ impl From<SignedTransaction> for UnverifiedTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SignedTransaction {
|
impl SignedTransaction {
|
||||||
/// Try to verify transaction and recover sender.
|
// t_nb 5.3.1 Try to verify transaction and recover sender.
|
||||||
pub fn new(transaction: UnverifiedTransaction) -> Result<Self, ethkey::Error> {
|
pub fn new(transaction: UnverifiedTransaction) -> Result<Self, ethkey::Error> {
|
||||||
if transaction.is_unsigned() {
|
if transaction.is_unsigned() {
|
||||||
return Err(ethkey::Error::InvalidSignature);
|
return Err(ethkey::Error::InvalidSignature);
|
||||||
|
@ -251,6 +251,7 @@ impl TransactionQueue {
|
|||||||
self.pool.write().listener_mut().0.set_in_chain_checker(f)
|
self.pool.write().listener_mut().0.set_in_chain_checker(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 10.2
|
||||||
/// Import a set of transactions to the pool.
|
/// Import a set of transactions to the pool.
|
||||||
///
|
///
|
||||||
/// Given blockchain and state access (Client)
|
/// Given blockchain and state access (Client)
|
||||||
@ -471,7 +472,7 @@ impl TransactionQueue {
|
|||||||
(pending_readiness, state_readiness)
|
(pending_readiness, state_readiness)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Culls all stalled transactions from the pool.
|
// t_nb 10.5.1 Culls all stalled transactions from the pool.
|
||||||
pub fn cull<C: client::NonceClient + Clone>(&self, client: C) {
|
pub fn cull<C: client::NonceClient + Clone>(&self, client: C) {
|
||||||
trace_time!("pool::cull");
|
trace_time!("pool::cull");
|
||||||
// We don't care about future transactions, so nonce_cap is not important.
|
// We don't care about future transactions, so nonce_cap is not important.
|
||||||
|
@ -336,6 +336,7 @@ impl<T: InformantData> Informant<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ChainNotify for Informant<FullNodeInformantData> {
|
impl ChainNotify for Informant<FullNodeInformantData> {
|
||||||
|
// t_nb 11.2 Informant. Prints new block inclusiong to console/log.
|
||||||
fn new_blocks(&self, new_blocks: NewBlocks) {
|
fn new_blocks(&self, new_blocks: NewBlocks) {
|
||||||
if new_blocks.has_more_blocks_to_import {
|
if new_blocks.has_more_blocks_to_import {
|
||||||
return;
|
return;
|
||||||
|
@ -175,6 +175,7 @@ impl<C> ChainNotificationHandler<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<C: BlockChainClient> ChainNotify for ChainNotificationHandler<C> {
|
impl<C: BlockChainClient> ChainNotify for ChainNotificationHandler<C> {
|
||||||
|
// t_nb 11.3 RPC. Notify subscriber header/logs about new block
|
||||||
fn new_blocks(&self, new_blocks: NewBlocks) {
|
fn new_blocks(&self, new_blocks: NewBlocks) {
|
||||||
if self.heads_subscribers.read().is_empty() && self.logs_subscribers.read().is_empty() {
|
if self.heads_subscribers.read().is_empty() && self.logs_subscribers.read().is_empty() {
|
||||||
return;
|
return;
|
||||||
|
@ -83,6 +83,7 @@ impl AclStorage for OnChainAclStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ChainNotify for OnChainAclStorage {
|
impl ChainNotify for OnChainAclStorage {
|
||||||
|
// t_nb 11.5 SecretStore OnChainAclStorage.
|
||||||
fn new_blocks(&self, new_blocks: NewBlocks) {
|
fn new_blocks(&self, new_blocks: NewBlocks) {
|
||||||
if new_blocks.has_more_blocks_to_import {
|
if new_blocks.has_more_blocks_to_import {
|
||||||
return;
|
return;
|
||||||
|
@ -168,6 +168,7 @@ impl KeyServerSet for OnChainKeyServerSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ChainNotify for OnChainKeyServerSet {
|
impl ChainNotify for OnChainKeyServerSet {
|
||||||
|
// t_nb 11.6 SecretStore OnChainKeyServerSet.
|
||||||
fn new_blocks(&self, new_blocks: NewBlocks) {
|
fn new_blocks(&self, new_blocks: NewBlocks) {
|
||||||
if new_blocks.has_more_blocks_to_import {
|
if new_blocks.has_more_blocks_to_import {
|
||||||
return;
|
return;
|
||||||
|
@ -624,6 +624,7 @@ impl Drop for ServiceContractListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ChainNotify for ServiceContractListener {
|
impl ChainNotify for ServiceContractListener {
|
||||||
|
// t_nb 11.7 SecretStore ServiceContractListener
|
||||||
fn new_blocks(&self, new_blocks: NewBlocks) {
|
fn new_blocks(&self, new_blocks: NewBlocks) {
|
||||||
if new_blocks.has_more_blocks_to_import {
|
if new_blocks.has_more_blocks_to_import {
|
||||||
return;
|
return;
|
||||||
|
@ -332,6 +332,7 @@ impl JournalDB for OverlayRecentDB {
|
|||||||
self.journal_overlay.read().earliest_era
|
self.journal_overlay.read().earliest_era
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t_nb 9.6
|
||||||
fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> io::Result<u32> {
|
fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> io::Result<u32> {
|
||||||
trace!(target: "journaldb", "entry: #{} ({})", now, id);
|
trace!(target: "journaldb", "entry: #{} ({})", now, id);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user