From 5807a6b27043c3b84e4b092d6ce05c381092b636 Mon Sep 17 00:00:00 2001 From: Ignotus Peverell Date: Wed, 22 Nov 2017 15:14:42 -0500 Subject: [PATCH] Fix sumtree checks ignoring total size Duplicate commitment and ducplicate kernel errors, as well as `is_unspent` did not check the total PMMR size, leading to wrong detection of duplicates or unspent. --- chain/src/sumtree.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/chain/src/sumtree.rs b/chain/src/sumtree.rs index fe118c8a3..7c5ceb100 100644 --- a/chain/src/sumtree.rs +++ b/chain/src/sumtree.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Grin Developers + // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -93,7 +93,13 @@ impl SumTrees { pub fn is_unspent(&self, commit: &Commitment) -> Result { let rpos = self.commit_index.get_output_pos(commit); match rpos { - Ok(pos) => Ok(self.output_pmmr_h.backend.get(pos).is_some()), + Ok(pos) => { + if pos > self.output_pmmr_h.last_pos { + Ok(false) + } else { + Ok(self.output_pmmr_h.backend.get(pos).is_some()) + } + } Err(grin_store::Error::NotFoundErr) => Ok(false), Err(e) => Err(Error::StoreErr(e, "sumtree unspent check".to_owned())), } @@ -252,8 +258,10 @@ impl<'a> Extension<'a> { } for out in &b.outputs { - if let Ok(_) = self.commit_index.get_output_pos(&out.commitment()) { - return Err(Error::DuplicateCommitment(out.commitment())); + if let Ok(pos) = self.commit_index.get_output_pos(&out.commitment()) { + if pos <= self.output_pmmr.unpruned_size() { + return Err(Error::DuplicateCommitment(out.commitment())); + } } // push new outputs commitments in their MMR and save them in the index let pos = self.output_pmmr @@ -274,8 +282,10 @@ impl<'a> Extension<'a> { } for kernel in &b.kernels { - if let Ok(_) = self.commit_index.get_kernel_pos(&kernel.excess) { - return Err(Error::DuplicateKernel(kernel.excess.clone())); + if let Ok(pos) = self.commit_index.get_kernel_pos(&kernel.excess) { + if pos <= self.kernel_pmmr.unpruned_size() { + return Err(Error::DuplicateKernel(kernel.excess.clone())); + } } // push kernels in their MMR let pos = self.kernel_pmmr