From 6ba22e71c84f2d85e96f97fc5de7b33f89c71c6b Mon Sep 17 00:00:00 2001 From: Ignotus Peverell Date: Sat, 9 Dec 2017 18:43:13 +0000 Subject: [PATCH] Fix for buffer-pruned positions in MMR store The MMR storage has a buffer for all changes so they can either be discarded without side effects or committed to disk. Pruning can also happen in the buffer if an input directly spends an output in a block (not likely), or a fork has an input spending a previous output within it. When the buffer gets flushed to storage, the pruned element was just skipped, causing an offset within the underlying storage and a shorter file than expected. This fix writes zeroes instead, so the size is consistent. Note that the zeroes will be removed with all other pruned elements on next compaction. Fixes #444 --- store/src/sumtree.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/store/src/sumtree.rs b/store/src/sumtree.rs index 2bbd334a..f1b1f27f 100644 --- a/store/src/sumtree.rs +++ b/store/src/sumtree.rs @@ -394,18 +394,25 @@ where /// data has been successfully written to disk. pub fn sync(&mut self) -> io::Result<()> { // truncating the storage file if a rewind occurred + let record_len = 32 + T::sum_len() as u64; if let Some((pos, _, _)) = self.rewind { - let record_len = 32 + T::sum_len() as u64; self.hashsum_file.truncate(pos * record_len)?; } + for elem in &self.buffer.elems { - if let Some(ref hs) = *elem { - if let Err(e) = self.hashsum_file.append(&ser::ser_vec(&hs).unwrap()[..]) { - return Err(io::Error::new( - io::ErrorKind::Interrupted, - format!("Could not write to log storage, disk full? {:?}", e), - )); - } + let res = if let Some(ref hs) = *elem { + self.hashsum_file.append(&ser::ser_vec(&hs).unwrap()[..]) + } else { + // the element has alredy been pruned in the buffer, we just insert + // zeros until compaction to avoid wrong hashum store offsets + self.hashsum_file.append(&vec![0; record_len as usize]) + }; + + if let Err(e) = res { + return Err(io::Error::new( + io::ErrorKind::Interrupted, + format!("Could not write to log storage, disk full? {:?}", e), + )); } } @@ -422,7 +429,7 @@ where if let Some((_, _, bi)) = self.rewind { self.buffer_index = bi; } - self.buffer = VecBackend::new(); + self.buffer.clear(); self.remove_log.discard(); self.rewind = None; }