diff --git a/src/index.rs b/src/index.rs index c6165c4f2d..e6be061f34 100644 --- a/src/index.rs +++ b/src/index.rs @@ -2653,6 +2653,51 @@ mod tests { } } + #[test] + fn transaction_with_inscription_inside_zero_value_2nd_input_should_be_unbound_and_cursed() { + for context in Context::configurations() { + context.mine_blocks(1); + + // create zero value input + context.rpc_server.broadcast_tx(TransactionTemplate { + inputs: &[(1, 0, 0)], + fee: 50 * 100_000_000, + ..Default::default() + }); + + context.mine_blocks(1); + + let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + inputs: &[(2, 0, 0), (2, 1, 0)], + witness: inscription("text/plain", "hello").to_witness(), + ..Default::default() + }); + + let second_inscription_id = InscriptionId { txid, index: 1 }; + + context.mine_blocks(1); + + context.index.assert_inscription_location( + second_inscription_id, + SatPoint { + outpoint: unbound_outpoint(), + offset: 0, + }, + None, + ); + + assert_eq!( + context + .index + .get_inscription_entry(second_inscription_id) + .unwrap() + .unwrap() + .number, + -1 + ); + } + } + #[test] fn multiple_inscriptions_in_same_tx_all_but_first_input_are_cursed() { for context in Context::configurations() { diff --git a/src/index/updater/inscription_updater.rs b/src/index/updater/inscription_updater.rs index 732816b816..aac51eed35 100644 --- a/src/index/updater/inscription_updater.rs +++ b/src/index/updater/inscription_updater.rs @@ -105,13 +105,13 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { let mut new_inscriptions = Inscription::from_transaction(tx).into_iter().peekable(); let mut floating_inscriptions = Vec::new(); let mut inscribed_offsets = BTreeMap::new(); - let mut input_value = 0; + let mut total_input_value = 0; let mut id_counter = 0; for (input_index, tx_in) in tx.input.iter().enumerate() { // skip subsidy since no inscriptions possible if tx_in.previous_output.is_null() { - input_value += Height(self.height).subsidy(); + total_input_value += Height(self.height).subsidy(); continue; } @@ -121,7 +121,7 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { self.satpoint_to_id, tx_in.previous_output, )? { - let offset = input_value + old_satpoint.offset; + let offset = total_input_value + old_satpoint.offset; floating_inscriptions.push(Flotsam { offset, inscription_id, @@ -134,10 +134,11 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { .or_insert((inscription_id, 0)); } - let offset = input_value; + let offset = total_input_value; // multi-level cache for UTXO set to get to the input amount - input_value += if let Some(value) = self.value_cache.remove(&tx_in.previous_output) { + let current_input_value = if let Some(value) = self.value_cache.remove(&tx_in.previous_output) + { value } else if let Some(value) = self .outpoint_to_value @@ -153,6 +154,8 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { })? }; + total_input_value += current_input_value; + // go through all inscriptions in this input while let Some(inscription) = new_inscriptions.peek() { if inscription.tx_in_index != u32::try_from(input_index).unwrap() { @@ -216,7 +219,7 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { curse.is_some() }; - let unbound = input_value == 0 + let unbound = current_input_value == 0 || inscription.tx_in_offset != 0 || curse == Some(Curse::UnrecognizedEvenField); @@ -264,7 +267,7 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { inscription_id, offset, origin: Origin::New { - fee: (input_value - total_output_value) / u64::from(id_counter), + fee: (total_input_value - total_output_value) / u64::from(id_counter), cursed, unbound, }, @@ -338,7 +341,7 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { offset: self.reward + flotsam.offset - output_value, ..flotsam })); - self.reward += input_value - output_value; + self.reward += total_input_value - output_value; Ok(()) } }