From 2def215553bdfca6556dfe29347f83c2d20dd462 Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Wed, 24 Jan 2018 18:20:34 +0000 Subject: [PATCH] Master port #605 (#606) * port of stack overflow fix from testnet to master * update process_block to encapsulate orphan check workflow --- chain/src/chain.rs | 64 +++++++++++++++++++++++++++++++++++--------- grin/src/adapters.rs | 5 ++-- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 6772471ab..242dd3b9d 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -194,12 +194,31 @@ impl Chain { 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, Option), 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 /// has been added to the longest chain, None if it's added to an (as of /// now) orphan chain. - pub fn process_block(&self, b: Block, opts: Options) - -> Result, Error> + pub fn process_block_no_orphans(&self, b: Block, opts: Options) + -> Result<(Option, Option), Error> { let head = self.store .head() @@ -223,8 +242,7 @@ impl Chain { let adapter = self.adapter.clone(); adapter.block_accepted(&b); } - // We just accepted a block so see if we can now accept any orphan(s) - self.check_orphans(&b); + Ok((Some(tip.clone()), Some(b.clone()))) }, Ok(None) => { // block got accepted but we did not extend the head @@ -241,8 +259,7 @@ impl Chain { let adapter = self.adapter.clone(); adapter.block_accepted(&b); } - // We just accepted a block so see if we can now accept any orphan(s) - self.check_orphans(&b); + Ok((None, Some(b.clone()))) }, Err(Error::Orphan) => { let block_hash = b.hash(); @@ -264,6 +281,7 @@ impl Chain { block_hash, self.orphans.len(), ); + Err(Error::Orphan) }, Err(Error::Unfit(ref msg)) => { debug!( @@ -273,8 +291,9 @@ impl Chain { b.header.height, msg ); + Err(Error::Unfit(msg.clone())) } - Err(ref e) => { + Err(e) => { info!( LOGGER, "Rejected block {} at {}: {:?}", @@ -282,9 +301,9 @@ impl Chain { b.header.height, e ); + Err(e) } } - res } /// Attempt to add a new header to the header chain. @@ -316,19 +335,38 @@ impl Chain { 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!( LOGGER, "chain: check_orphans: # orphans {}", self.orphans.len(), ); - + let mut last_block_hash = block.hash(); // 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 // as their "previous" block? - if let Some(orphan) = self.orphans.get_by_previous(&block.hash()) { - self.orphans.remove(&orphan.block.hash()); - let _ = self.process_block(orphan.block, orphan.opts); + loop { + if let Some(orphan) = self.orphans.get_by_previous(&last_block_hash) { + self.orphans.remove(&orphan.block.hash()); + 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; + } } } diff --git a/grin/src/adapters.rs b/grin/src/adapters.rs index 7fc8f1d33..b5f83ae39 100644 --- a/grin/src/adapters.rs +++ b/grin/src/adapters.rs @@ -75,15 +75,14 @@ impl p2p::ChainAdapter for NetToChainAdapter { // pushing the new block through the chain pipeline 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); if e.is_bad_block() { debug!(LOGGER, "block_received: {} is a bad block, resetting head", bhash); let _ = self.chain.reset_head(); return false; } - } + }; true }