Trace comment on new block inclusion (#100)

This commit is contained in:
rakita 2020-12-02 11:31:11 +01:00 committed by GitHub
parent 51d824fbdc
commit 56131b6d92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 146 additions and 45 deletions

View File

@ -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) {
let mut pending_best_ancient_block = self.pending_best_ancient_block.write();
let mut pending_best_block = self.pending_best_block.write();

View File

@ -161,7 +161,7 @@ pub trait Drain {
}
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>>(
engine: &'x dyn EthEngine,
factories: Factories,
@ -176,6 +176,8 @@ impl<'x> OpenBlock<'x> {
ancestry: I,
) -> Result<Self, Error> {
let number = parent.number() + 1;
// t_nb 8.1.1 get parent StateDB.
let state = State::from_existing(
db,
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_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(
&mut r.block.header,
parent,
gas_floor_target,
gas_ceil_target,
);
// t_nb 8.1.3 this adds engine specific things
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.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());
}
/// 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
/// 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> {
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)?;
// t_nb 8.5.2 commit account changes from cache to tree
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.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(
header: Header,
transactions: Vec<SignedTransaction>,
@ -532,6 +541,7 @@ pub(crate) fn enact(
None
};
// t_nb 8.1 Created new OpenBlock
let mut b = OpenBlock::new(
engine,
factories,
@ -556,17 +566,22 @@ pub(crate) fn enact(
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);
// t_nb 8.3 execute transactions one by one
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 {
b.push_uncle(u)?;
}
// t_nb 8.5 close block
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(
block: PreverifiedBlock,
engine: &dyn EthEngine,

View File

@ -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 {
// Shortcut out if we know we're incapable of syncing the chain.
if !client.enabled.load(AtomicOrdering::Relaxed) {
@ -315,11 +315,13 @@ impl Importer {
invalid_blocks.insert(hash);
continue;
}
// t_nb 7.0 check and lock block
match self.check_and_lock_block(&bytes, block, client) {
Ok((closed_block, pending)) => {
imported_blocks.push(hash);
let transactions_len = closed_block.transactions.len();
// t_nb 8.0 commit block to db
let route = self.commit_block(
closed_block,
&header,
@ -362,6 +364,7 @@ impl Importer {
if !imported_blocks.is_empty() {
let route = ChainRoute::from(import_results.as_ref());
// t_nb 10 Notify miner about new included block.
if !has_more_blocks_to_import {
self.miner.chain_new_blocks(
client,
@ -373,6 +376,7 @@ impl Importer {
);
}
// t_nb 11 notify rest of system about new block inclusion
client.notify(|notify| {
notify.new_blocks(NewBlocks::new(
imported_blocks.clone(),
@ -394,6 +398,7 @@ impl Importer {
imported
}
// t_nb 6.0.1 check and lock block,
fn check_and_lock_block(
&self,
bytes: &[u8],
@ -404,13 +409,14 @@ impl Importer {
let header = block.header.clone();
// 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();
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);
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())) {
Some(h) => h,
None => {
@ -420,7 +426,7 @@ impl Importer {
};
let chain = client.chain.read();
// Verify Block Family
// t_nb 7.3 verify block family
let verify_family_result = self.verifier.verify_block_family(
&header,
&parent,
@ -437,6 +443,7 @@ impl Importer {
bail!(e);
};
// t_nb 7.4 verify block external
let verify_external_result = self.verifier.verify_block_external(&header, engine);
if let Err(e) = verify_external_result {
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
@ -444,7 +451,9 @@ impl Importer {
};
// 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 db = client
.state_db
.read()
@ -454,6 +463,7 @@ impl Importer {
.epoch_transition(parent.number(), *header.parent_hash())
.is_some();
// t_nb 8.0 Block enacting. Execution of transactions.
let enact_result = enact_verified(
block,
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.
// (i.e. allow inconsistency in receipts outcome before the transition block)
if header.number() < engine.params().validate_receipts_transition
@ -483,7 +493,7 @@ impl Importer {
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
.verifier
.verify_block_final(&header, &locked_block.header)
@ -570,6 +580,7 @@ impl Importer {
let mut batch = DBTransaction::new();
// t_nb 9.1 Gather all ancestry actions. (Used only by AuRa)
let ancestry_actions = self
.engine
.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");
// t_nb 9.3 Check block total difficulty
let fork_choice = if route.is_from_route_finalized {
ForkChoice::Old
} else {
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.
// TODO: Prove it with a test.
let mut state = block.state.drop().1;
// check epoch end signal, potentially generating a proof on the current
// state.
// t_nb 9.5 check epoch end signal, potentially generating a proof on the current
// state. Write transition into db.
if let Some(pending) = 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
.journal_under(&mut batch, number, hash)
.expect("DB commit failed");
@ -633,6 +648,7 @@ impl Importer {
let AncestryAction::MarkFinalized(a) = ancestry_action;
if a != header.hash() {
// t_nb 9.7 if there are finalized ancester, mark that chainge in block in db. (Used by AuRa)
chain
.mark_finalized(&mut batch, a)
.expect("Engine's ancestry action must be known blocks; qed");
@ -645,6 +661,7 @@ impl Importer {
})
.collect();
// t_nb 9.8 insert block
let route = chain.insert_block(
&mut batch,
block_data,
@ -655,6 +672,7 @@ impl Importer {
},
);
// t_nb 9.9 insert traces (if they are enabled)
client.tracedb.read().import(
&mut batch,
TraceImportRequest {
@ -667,15 +685,22 @@ impl Importer {
);
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);
// Final commit to the DB
// t_nb 9.11 Write Transaction to database (cached)
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();
// t_nb 9.13 check epoch end. Related only to AuRa and it seems light engine
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);
// t_nb 9.15 prune ancient states
if let Err(e) = client.prune_ancient(state, &chain) {
warn!("Failed to prune ancient state data: {}", e);
}
@ -1098,7 +1123,7 @@ impl Client {
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(
&self,
mut state_db: StateDB,
@ -1138,6 +1163,7 @@ impl Client {
Ok(())
}
// t_nb 9.14 update last hashes. They are build in step 7.5
fn update_last_hashes(&self, parent: &H256, hash: &H256) {
let mut hashes = self.last_hashes.write();
if hashes.front().map_or(false, |h| h == parent) {
@ -1721,11 +1747,14 @@ impl CallContract for Client {
}
impl ImportBlock for Client {
// t_nb 2.0 import block to client
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()) {
bail!(EthcoreErrorKind::Import(ImportErrorKind::AlreadyInChain));
}
// t_nb 2.2 check if parent is known
let status = self.block_status(BlockId::Hash(unverified.parent_hash()));
if status == BlockStatus::Unknown {
bail!(EthcoreErrorKind::Block(BlockError::UnknownParent(
@ -1743,14 +1772,16 @@ impl ImportBlock for Client {
None
};
// t_nb 2.3
match self.importer.block_queue.import(unverified) {
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 {
self.notify(move |n| n.block_pre_import(&raw, &hash, &difficulty));
}
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), _))) => {
self.importer
.bad_blocks

View File

@ -1307,6 +1307,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
Ok(())
}
// t_nb 8.1.5
fn on_new_block(
&self,
block: &mut ExecutedBlock,
@ -1531,7 +1532,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
Ok(())
}
// Check the validators.
// t_nb 6.4 Check the validators.
fn verify_block_external(&self, header: &Header) -> Result<(), Error> {
let (validators, set_number) = self.epoch_set(header)?;

View File

@ -488,7 +488,7 @@ pub trait Engine<M: Machine>: Sync + Send {
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.
fn ancestry_actions(
&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 {
if new.total_score() > best.total_score() {
ForkChoice::New
@ -562,7 +562,7 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> {
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,
/// i.e. it should only verify stuff that doesn't assume any previous transactions

View File

@ -238,7 +238,7 @@ impl EthereumMachine {
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.
pub fn on_new_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
self.push_last_hash(block)?;

View File

@ -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.
fn update_sealing<C>(&self, chain: &C, force: ForceUpdateSealing)
where
@ -1339,6 +1339,7 @@ impl miner::MinerService for Miner {
})
}
// t_nb 10 notify miner about new include blocks
fn chain_new_blocks<C>(
&self,
chain: &C,
@ -1363,11 +1364,11 @@ impl miner::MinerService for Miner {
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();
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);
{
retracted
@ -1378,7 +1379,8 @@ impl miner::MinerService for Miner {
let txs = block.transactions()
.into_iter()
.map(pool::verifier::Transaction::Retracted)
.collect();
.collect();
// t_nb 10.2
let _ = self.transaction_queue.import(
client.clone(),
txs,
@ -1387,12 +1389,13 @@ impl miner::MinerService for Miner {
}
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
// new pending block.
self.sealing.lock().next_allowed_reseal = Instant::now();
if !is_internal_import {
// t_nb 10.4 if it is internal import update sealing
// --------------------------------------------------------------------------
// | NOTE Code below requires sealing locks. |
// | Make sure to release the locks before calling that method. |
@ -1402,7 +1405,7 @@ impl miner::MinerService for Miner {
}
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
// (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
@ -1424,7 +1427,9 @@ impl miner::MinerService for Miner {
&*accounts,
service_transaction_checker.as_ref(),
);
// t_nb 10.5 do culling
queue.cull(client);
// reseal is only used by InstaSeal engine
if engine.should_reseal_on_update() {
// force update_sealing here to skip `reseal_required` checks
chain.update_sealing(ForceUpdateSealing::Yes);
@ -1435,13 +1440,16 @@ impl miner::MinerService for Miner {
warn!(target: "miner", "Error queueing cull: {:?}", e);
}
} else {
// t_nb 10.5 do culling
self.transaction_queue.cull(client);
// reseal is only used by InstaSeal engine
if self.engine.should_reseal_on_update() {
// force update_sealing here to skip `reseal_required` checks
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 {
match service_transaction_checker.refresh_cache(chain) {
Ok(true) => {

View File

@ -111,6 +111,7 @@ impl 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) {
if self.oracle.is_major_importing() || new_blocks.has_more_blocks_to_import {
return;

View File

@ -43,7 +43,7 @@ pub trait Backend: Send {
/// Treat the backend as a writeable hashdb.
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);
/// Add a global code cache entry. This doesn't need to worry about canonicality because

View File

@ -996,7 +996,7 @@ impl<B: Backend> State<B> {
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> {
assert!(self.checkpoints.borrow().is_empty());
// first, commit the sub trees.
@ -1036,7 +1036,7 @@ impl<B: Backend> State<B> {
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) {
let mut addresses = self.cache.borrow_mut();
trace!("Committing cache {:?} entries", addresses.len());

View File

@ -147,6 +147,7 @@ impl StateDB {
Ok(records)
}
// t_nb 9.15
/// 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.
pub fn mark_canonical(
@ -158,7 +159,7 @@ impl StateDB {
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.
/// This function updates the global cache by removing entries
/// that are invalidated by chain reorganization. `sync_cache`

View File

@ -95,6 +95,7 @@ pub mod blocks {
type Unverified = Unverified;
type Verified = PreverifiedBlock;
// t_nb 4.0 verify_block_basic
fn create(
input: Self::Input,
engine: &dyn EthEngine,
@ -113,6 +114,7 @@ pub mod blocks {
}
}
// t_nb 5.0 verify standalone block
fn verify(
un: Self::Unverified,
engine: &dyn EthEngine,

View File

@ -364,7 +364,7 @@ impl<K: Kind> VerificationQueue<K> {
}
}
// do work.
// do work on this item.
let item = {
// acquire these locks before getting the item to verify.
let mut unverified = verification.unverified.lock();
@ -387,10 +387,12 @@ impl<K: Kind> VerificationQueue<K> {
};
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) {
Ok(verified) => {
let mut verifying = verification.verifying.lock();
let mut idx = None;
// find item again and remove it from verified queue
for (i, e) in verifying.iter_mut().enumerate() {
if e.hash == hash {
idx = Some(i);
@ -515,17 +517,20 @@ impl<K: Kind> VerificationQueue<K> {
}
/// 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)> {
let hash = input.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) {
bail!((
Some(input),
ErrorKind::Import(ImportErrorKind::AlreadyQueued).into()
));
}
// t_nb 3.1.1 is marked as bad
let mut bad = self.verification.bad.lock();
if bad.contains(&hash) || bad.contains(&raw_hash) {
bail!((
@ -533,7 +538,7 @@ impl<K: Kind> VerificationQueue<K> {
ErrorKind::Import(ImportErrorKind::KnownBad).into()
));
}
// t_nb 3.1.2 its parent is marked as bad
if bad.contains(&input.parent_hash()) {
bad.insert(hash);
bail!((

View File

@ -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(
block: &Unverified,
engine: &dyn EthEngine,
check_seal: bool,
) -> Result<(), Error> {
// t_nb 4.1 verify header params
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)?;
if check_seal {
// t_nb 4.4 Check block seal. It calls engine to verify block basic
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 {
// t_nb 4.5.1
verify_header_params(uncle, engine, false, check_seal)?;
if check_seal {
// t_nb 4.5.2
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 {
engine.verify_transaction_basic(t, &block.header)?;
}
@ -90,7 +100,7 @@ pub fn verify_block_basic(
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
/// Returns a `PreverifiedBlock` structure populated with transactions
pub fn verify_block_unordered(
@ -100,8 +110,10 @@ pub fn verify_block_unordered(
) -> Result<PreverifiedBlock, Error> {
let header = block.header;
if check_seal {
// t_nb 5.1
engine.verify_block_unordered(&header)?;
for uncle in &block.uncles {
// t_nb 5.2
engine.verify_block_unordered(uncle)?;
}
}
@ -112,11 +124,14 @@ pub fn verify_block_unordered(
None
};
// t_nb 5.3 iterate over all transactions
let transactions = block
.transactions
.into_iter()
.map(|t| {
// t_nb 5.3.1 call verify_unordered. Check signatures and calculate address
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 t.nonce >= max_nonce {
return Err(BlockError::TooManyTransactions(t.sender()).into());
@ -146,7 +161,7 @@ pub struct FullFamilyParams<'a, C: BlockInfo + CallContract + 'a> {
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>(
header: &Header,
parent: &Header,
@ -154,6 +169,7 @@ pub fn verify_block_family<C: BlockInfo + CallContract>(
do_full: Option<FullFamilyParams<C>>,
) -> Result<(), Error> {
// TODO: verify timestamp
// t_nb 6.3.1 verify parent
verify_parent(&header, &parent, engine)?;
engine.verify_block_family(&header, &parent)?;
@ -162,8 +178,10 @@ pub fn verify_block_family<C: BlockInfo + CallContract>(
None => return Ok(()),
};
// t_nb 6.3.2 verify uncles
verify_uncles(params.block, params.block_provider, engine)?;
// t_nb 6.3.3 verify all transactions
for tx in &params.block.transactions {
// transactions are verified against the parent header since the current
// state wasn't available when the tx was created

View File

@ -529,6 +529,7 @@ impl ChainNotify for EthSync {
}
}
// t_nb 11.4
fn new_blocks(&self, new_blocks: NewBlocks) {
if new_blocks.has_more_blocks_to_import {
return;

View File

@ -155,6 +155,7 @@ impl SyncHandler {
trace!(target: "sync", "Ignoring new block from unconfirmed peer {}", peer_id);
return Ok(());
}
// t_nb 1.0 decode RLP
let block = Unverified::from_rlp(r.at(0)?.as_raw().to_vec())?;
let hash = block.header.hash();
let number = block.header.number();
@ -166,7 +167,9 @@ impl SyncHandler {
let difficulty: U256 = r.val_at(1)?;
// Most probably the sent block is being imported by peer right 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());
if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) {
if peer
.difficulty
@ -181,6 +184,7 @@ impl SyncHandler {
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();
if last_imported_number > number && last_imported_number - number > MAX_NEW_BLOCK_AGE {
trace!(target: "sync", "Ignored ancient new block {:?}", hash);

View File

@ -1421,7 +1421,7 @@ impl ChainSync {
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(
&mut self,
io: &mut dyn SyncIo,
@ -1437,7 +1437,9 @@ impl ChainSync {
if !is_syncing || !sealed.is_empty() || !proposed.is_empty() {
trace!(target: "sync", "Propagating blocks, state={:?}", self.state);
// t_nb 11.4.1 propagate latest blocks
SyncPropagator::propagate_latest_blocks(self, io, sealed);
// t_nb 11.4.4 propagate proposed blocks
SyncPropagator::propagate_proposed_blocks(self, io, proposed);
}
if !invalid.is_empty() {
@ -1446,7 +1448,7 @@ impl ChainSync {
}
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());
trace!(target: "sync", "Re-broadcasting transactions to a random peer.");
self.peers.values_mut().nth(peer).map(|peer_info| {

View File

@ -39,7 +39,7 @@ use super::{
pub struct 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(
sync: &mut ChainSync,
chain_info: &BlockChainInfo,
@ -72,7 +72,7 @@ impl SyncPropagator {
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(
sync: &mut ChainSync,
chain_info: &BlockChainInfo,
@ -279,6 +279,7 @@ impl SyncPropagator {
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]) {
let chain_info = io.chain().chain_info();
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);
if sealed.is_empty() {
// t_nb 11.4.2
let hashes = SyncPropagator::propagate_new_hashes(sync, &chain_info, io, &peers);
let peers = ChainSync::select_random_peers(&peers);
// t_nb 11.4.3
let blocks =
SyncPropagator::propagate_blocks(sync, &chain_info, io, sealed, &peers);
if blocks != 0 || hashes != 0 {
trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes);
}
} else {
// t_nb 11.4.3
SyncPropagator::propagate_blocks(sync, &chain_info, io, sealed, &peers);
// t_nb 11.4.2
SyncPropagator::propagate_new_hashes(sync, &chain_info, io, &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;
}
/// 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(
sync: &mut ChainSync,
io: &mut dyn SyncIo,

View File

@ -468,7 +468,7 @@ impl From<SignedTransaction> for UnverifiedTransaction {
}
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> {
if transaction.is_unsigned() {
return Err(ethkey::Error::InvalidSignature);

View File

@ -251,6 +251,7 @@ impl TransactionQueue {
self.pool.write().listener_mut().0.set_in_chain_checker(f)
}
// t_nb 10.2
/// Import a set of transactions to the pool.
///
/// Given blockchain and state access (Client)
@ -471,7 +472,7 @@ impl TransactionQueue {
(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) {
trace_time!("pool::cull");
// We don't care about future transactions, so nonce_cap is not important.

View File

@ -336,6 +336,7 @@ impl<T: InformantData> Informant<T> {
}
impl ChainNotify for Informant<FullNodeInformantData> {
// t_nb 11.2 Informant. Prints new block inclusiong to console/log.
fn new_blocks(&self, new_blocks: NewBlocks) {
if new_blocks.has_more_blocks_to_import {
return;

View File

@ -175,6 +175,7 @@ impl<C> 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) {
if self.heads_subscribers.read().is_empty() && self.logs_subscribers.read().is_empty() {
return;

View File

@ -83,6 +83,7 @@ impl AclStorage for OnChainAclStorage {
}
impl ChainNotify for OnChainAclStorage {
// t_nb 11.5 SecretStore OnChainAclStorage.
fn new_blocks(&self, new_blocks: NewBlocks) {
if new_blocks.has_more_blocks_to_import {
return;

View File

@ -168,6 +168,7 @@ impl KeyServerSet for OnChainKeyServerSet {
}
impl ChainNotify for OnChainKeyServerSet {
// t_nb 11.6 SecretStore OnChainKeyServerSet.
fn new_blocks(&self, new_blocks: NewBlocks) {
if new_blocks.has_more_blocks_to_import {
return;

View File

@ -624,6 +624,7 @@ impl Drop for ServiceContractListener {
}
impl ChainNotify for ServiceContractListener {
// t_nb 11.7 SecretStore ServiceContractListener
fn new_blocks(&self, new_blocks: NewBlocks) {
if new_blocks.has_more_blocks_to_import {
return;

View File

@ -332,6 +332,7 @@ impl JournalDB for OverlayRecentDB {
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> {
trace!(target: "journaldb", "entry: #{} ({})", now, id);