last output in a block is the last regular output, failing that the last coinbase output
apply_block() processes regular outputs last so we need to be consistent with this
@@ -687,9 +687,38 @@ where
file_store.rewind(leaf_index - 1)
}*/
-/// Output and kernel MMR indexes at the end of the provided block
+/// Output and kernel MMR indexes at the end of the provided block.
+/// This requires us to know the "last" output processed in the block
+/// and needs to be consistent with how we originally processed
+/// the outputs in apply_block()
fn indexes_at(block: &Block, commit_index: &ChainStore) -> Result<(u64, u64), Error> {
- let out_idx = match block.outputs.last() {
+ // If we have any regular outputs then the "last" output is the last regular output
+ // otherwise it is the last coinbase output.
+ // This is because we process coinbase outputs before regular outputs in apply_block().
+ //
+ // TODO - consider maintaining coinbase outputs in a separate vec in a block?
+ //
+ let mut last_coinbase_output: Option<Output> = None;
+ let mut last_regular_output: Option<Output> = None;
+
+ for x in &block.outputs {
+ if x.features.contains(OutputFeatures::COINBASE_OUTPUT) {
+ last_coinbase_output = Some(*x);
+ } else {
+ last_regular_output = Some(*x);
+ }
+ }
+
+ // use last regular output if we have any, otherwise last coinbase output
+ let last_output = if last_regular_output.is_some() {
+ last_regular_output
+ } else if last_coinbase_output.is_some() {
+ last_coinbase_output
+ } else {
+ None
+ };
+
+ let out_idx = match last_output {
Some(output) => commit_index.get_output_pos(&output.commitment())
.map_err(|e| {
Error::StoreErr(e, format!("missing output pos for known block"))
