From da4b349d49bce21329e16a26fdf9c49b12d2a6e2 Mon Sep 17 00:00:00 2001 From: Ignotus Peverell Date: Mon, 25 Dec 2017 00:27:13 +0000 Subject: [PATCH] Fix `AlreadySpent` when UTXO created and spent on fork When applying a fork, everything is done in memory to be able to rewind if it's either invalid or doesn't have more work. But checking for the UTXO index was done only against the store. Now checking the memory as well to find UTXOs that haven't been stored yet. --- chain/src/sumtree.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/chain/src/sumtree.rs b/chain/src/sumtree.rs index 28ea0017a..925e21217 100644 --- a/chain/src/sumtree.rs +++ b/chain/src/sumtree.rs @@ -248,14 +248,7 @@ impl<'a> Extension<'a> { // same block, enforcing block cut-through for input in &b.inputs { let commit = input.commitment(); - let pos_res = self.commit_index.get_output_pos(&commit); - - // TODO - Assume this hash specific debug can be cleaned up? - if b.hash().to_string() == "f697a877" { - debug!(LOGGER, "input pos: {:?}, commit: {} {:?}", - pos_res, input.commitment().hash(), commit); - } - + let pos_res = self.get_output_pos(&commit); if let Ok(pos) = pos_res { match self.output_pmmr.prune(pos, b.header.height as u32) { Ok(true) => { @@ -273,7 +266,7 @@ impl<'a> Extension<'a> { for out in &b.outputs { let commit = out.commitment(); - if let Ok(pos) = self.commit_index.get_output_pos(&commit) { + if let Ok(pos) = self.get_output_pos(&commit) { // we need to check whether the commitment is in the current MMR view // as well as the index doesn't support rewind and is non-authoritative // (non-historical node will have a much smaller one) @@ -309,7 +302,7 @@ impl<'a> Extension<'a> { } for kernel in &b.kernels { - if let Ok(pos) = self.commit_index.get_kernel_pos(&kernel.excess) { + if let Ok(pos) = self.get_kernel_pos(&kernel.excess) { // same as outputs if let Some(k) = self.kernel_pmmr.get(pos) { let hashsum = HashSum::from_summable( @@ -365,7 +358,7 @@ impl<'a> Extension<'a> { ); let out_pos_rew = match block.outputs.last() { - Some(output) => self.commit_index.get_output_pos(&output.commitment()) + Some(output) => self.get_output_pos(&output.commitment()) .map_err(|e| { Error::StoreErr(e, format!("missing output pos for known block")) })?, @@ -373,7 +366,7 @@ impl<'a> Extension<'a> { }; let kern_pos_rew = match block.kernels.last() { - Some(kernel) => self.commit_index.get_kernel_pos(&kernel.excess) + Some(kernel) => self.get_kernel_pos(&kernel.excess) .map_err(|e| { Error::StoreErr(e, format!("missing kernel pos for known block")) })?, @@ -403,6 +396,22 @@ impl<'a> Extension<'a> { Ok(()) } + fn get_output_pos(&self, commit: &Commitment) -> Result { + if let Some(pos) = self.new_output_commits.get(commit) { + Ok(*pos) + } else { + self.commit_index.get_output_pos(commit) + } + } + + fn get_kernel_pos(&self, excess: &Commitment) -> Result { + if let Some(pos) = self.new_kernel_excesses.get(excess) { + Ok(*pos) + } else { + self.commit_index.get_kernel_pos(excess) + } + } + /// Current root hashes and sums (if applicable) for the UTXO, range proof /// and kernel sum trees. pub fn roots(