infinite loops in check_orphans, if block in orphans has a forked parent (#1452)

* fix: if block in orphans queue has a forked parent, cause infinite loop in check_orphans()
* process all orphans at a given height before go to next height
This commit is contained in:
Gary Yu 2018-09-02 03:09:38 +08:00 committed by Ignotus Peverell
parent 8a39f1fc75
commit f971e8de77

View file

@ -350,42 +350,60 @@ impl Chain {
/// Check for orphans, once a block is successfully added /// Check for orphans, once a block is successfully added
pub fn check_orphans(&self, mut height: u64) { pub fn check_orphans(&self, mut height: u64) {
let initial_height = height;
// Is there an orphan in our orphans that we can now process?
loop {
trace!( trace!(
LOGGER, LOGGER,
"chain: doing check_orphans at {}, # orphans {}", "check_orphans: at {}, # orphans {}",
height, height,
self.orphans.len(), self.orphans.len(),
); );
// Is there an orphan in our orphans that we can now process?
loop { let mut orphan_accepted = false;
let mut height_accepted = height;
if let Some(orphans) = self.orphans.remove_by_height(&height) { if let Some(orphans) = self.orphans.remove_by_height(&height) {
for orphan in orphans { let orphans_len = orphans.len();
trace!( for (i, orphan) in orphans.into_iter().enumerate() {
debug!(
LOGGER, LOGGER,
"chain: got block {} at {} from orphans. # orphans remaining {}", "check_orphans: get block {} at {}{}",
orphan.block.hash(), orphan.block.hash(),
height, height,
self.orphans.len(), if orphans_len > 1 {
format!(", no.{} of {} orphans", i, orphans_len)
} else {
String::new()
},
); );
let res = self.process_block_no_orphans(orphan.block, orphan.opts); let res = self.process_block_no_orphans(orphan.block, orphan.opts);
if let Ok((_, Some(b))) = res { if let Ok((_, Some(b))) = res {
orphan_accepted = true;
height_accepted = b.header.height;
}
}
if orphan_accepted {
// We accepted a block, so see if we can accept any orphans // We accepted a block, so see if we can accept any orphans
height = b.header.height + 1; height = height_accepted + 1;
} else { continue;
}
}
break; break;
} }
}
} else { if initial_height != height {
break; debug!(
}
}
trace!(
LOGGER, LOGGER,
"chain: done check_orphans at {}. # remaining orphans {}", "check_orphans: {} blocks accepted since height {}, remaining # orphans {}",
height - 1, height - initial_height,
initial_height,
self.orphans.len(), self.orphans.len(),
); );
} }
}
/// For the given commitment find the unspent output and return the /// For the given commitment find the unspent output and return the
/// associated Return an error if the output does not exist or has been /// associated Return an error if the output does not exist or has been