Master port #605 (#606)

* port of stack overflow fix from testnet to master
* update process_block to encapsulate orphan check workflow
This commit is contained in:
Yeastplume 2018-01-24 18:20:34 +00:00 committed by Ignotus Peverell
parent 8710d52797
commit 2def215553
2 changed files with 53 additions and 16 deletions

View file

@ -194,12 +194,31 @@ impl Chain {
pow_verifier: pow_verifier, pow_verifier: pow_verifier,
}) })
} }
/// Processes a single block, then checks for orphans, processing
/// those as well if they're found
pub fn process_block(&self, b: Block, opts: Options)
-> Result<(Option<Tip>, Option<Block>), Error>
{
let res = self.process_block_no_orphans(b, opts);
match res {
Ok((t, b)) => {
// We accepted a block, so see if we can accept any orphans
if b.is_some() {
self.check_orphans(&b.clone().unwrap());
}
Ok((t, b))
},
Err(e) => {
Err(e)
}
}
}
/// Attempt to add a new block to the chain. Returns the new chain tip if it /// Attempt to add a new block to the chain. Returns the new chain tip if it
/// has been added to the longest chain, None if it's added to an (as of /// has been added to the longest chain, None if it's added to an (as of
/// now) orphan chain. /// now) orphan chain.
pub fn process_block(&self, b: Block, opts: Options) pub fn process_block_no_orphans(&self, b: Block, opts: Options)
-> Result<Option<Tip>, Error> -> Result<(Option<Tip>, Option<Block>), Error>
{ {
let head = self.store let head = self.store
.head() .head()
@ -223,8 +242,7 @@ impl Chain {
let adapter = self.adapter.clone(); let adapter = self.adapter.clone();
adapter.block_accepted(&b); adapter.block_accepted(&b);
} }
// We just accepted a block so see if we can now accept any orphan(s) Ok((Some(tip.clone()), Some(b.clone())))
self.check_orphans(&b);
}, },
Ok(None) => { Ok(None) => {
// block got accepted but we did not extend the head // block got accepted but we did not extend the head
@ -241,8 +259,7 @@ impl Chain {
let adapter = self.adapter.clone(); let adapter = self.adapter.clone();
adapter.block_accepted(&b); adapter.block_accepted(&b);
} }
// We just accepted a block so see if we can now accept any orphan(s) Ok((None, Some(b.clone())))
self.check_orphans(&b);
}, },
Err(Error::Orphan) => { Err(Error::Orphan) => {
let block_hash = b.hash(); let block_hash = b.hash();
@ -264,6 +281,7 @@ impl Chain {
block_hash, block_hash,
self.orphans.len(), self.orphans.len(),
); );
Err(Error::Orphan)
}, },
Err(Error::Unfit(ref msg)) => { Err(Error::Unfit(ref msg)) => {
debug!( debug!(
@ -273,8 +291,9 @@ impl Chain {
b.header.height, b.header.height,
msg msg
); );
Err(Error::Unfit(msg.clone()))
} }
Err(ref e) => { Err(e) => {
info!( info!(
LOGGER, LOGGER,
"Rejected block {} at {}: {:?}", "Rejected block {} at {}: {:?}",
@ -282,9 +301,9 @@ impl Chain {
b.header.height, b.header.height,
e e
); );
Err(e)
} }
} }
res
} }
/// Attempt to add a new header to the header chain. /// Attempt to add a new header to the header chain.
@ -316,19 +335,38 @@ impl Chain {
self.orphans.contains(hash) self.orphans.contains(hash)
} }
fn check_orphans(&self, block: &Block) {
/// Check for orphans, once a block is successfully added
pub fn check_orphans(&self, block: &Block) {
debug!( debug!(
LOGGER, LOGGER,
"chain: check_orphans: # orphans {}", "chain: check_orphans: # orphans {}",
self.orphans.len(), self.orphans.len(),
); );
let mut last_block_hash = block.hash();
// Is there an orphan in our orphans that we can now process? // Is there an orphan in our orphans that we can now process?
// We just processed the given block, are there any orphans that have this block // We just processed the given block, are there any orphans that have this block
// as their "previous" block? // as their "previous" block?
if let Some(orphan) = self.orphans.get_by_previous(&block.hash()) { loop {
if let Some(orphan) = self.orphans.get_by_previous(&last_block_hash) {
self.orphans.remove(&orphan.block.hash()); self.orphans.remove(&orphan.block.hash());
let _ = self.process_block(orphan.block, orphan.opts); let res = self.process_block_no_orphans(orphan.block, orphan.opts);
match res {
Ok((_, b)) => {
// We accepted a block, so see if we can accept any orphans
if b.is_some() {
last_block_hash = b.unwrap().hash();
} else {
break;
}
},
Err(_) => {
break;
},
};
} else {
break;
}
} }
} }

View file

@ -75,15 +75,14 @@ impl p2p::ChainAdapter for NetToChainAdapter {
// pushing the new block through the chain pipeline // pushing the new block through the chain pipeline
let res = self.chain.process_block(b, self.chain_opts()); let res = self.chain.process_block(b, self.chain_opts());
if let Err(ref e) = res {
if let &Err(ref e) = &res {
debug!(LOGGER, "Block {} refused by chain: {:?}", bhash, e); debug!(LOGGER, "Block {} refused by chain: {:?}", bhash, e);
if e.is_bad_block() { if e.is_bad_block() {
debug!(LOGGER, "block_received: {} is a bad block, resetting head", bhash); debug!(LOGGER, "block_received: {} is a bad block, resetting head", bhash);
let _ = self.chain.reset_head(); let _ = self.chain.reset_head();
return false; return false;
} }
} };
true true
} }