diff --git a/src/index.rs b/src/index.rs index 799a8d2169..51ddf713c0 100644 --- a/src/index.rs +++ b/src/index.rs @@ -2562,6 +2562,52 @@ mod tests { } } + #[test] + fn unrecognized_even_field_inscriptions_are_cursed_and_unbound() { + for context in Context::configurations() { + context.mine_blocks(1); + + let witness = envelope(&[ + b"ord", + &[1], + b"text/plain;charset=utf-8", + &[2], + b"bar", + &[4], + b"ord", + ]); + + let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + inputs: &[(1, 0, 0)], + witness, + ..Default::default() + }); + + let inscription_id = InscriptionId { txid, index: 0 }; + + context.mine_blocks(1); + + context.index.assert_inscription_location( + inscription_id, + SatPoint { + outpoint: unbound_outpoint(), + offset: 0, + }, + None, + ); + + assert_eq!( + context + .index + .get_inscription_entry(inscription_id) + .unwrap() + .unwrap() + .number, + -1 + ); + } + } + #[test] // https://github.com/ordinals/ord/issues/2062 fn zero_value_transaction_inscription_not_cursed_but_unbound() { diff --git a/src/index/updater/inscription_updater.rs b/src/index/updater/inscription_updater.rs index fce36e608e..f4a03dc6be 100644 --- a/src/index/updater/inscription_updater.rs +++ b/src/index/updater/inscription_updater.rs @@ -164,7 +164,9 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { index: id_counter, }; - let curse = if inscription.tx_in_index != 0 { + let curse = if inscription.inscription.unrecognized_even_field { + Some(Curse::UnrecognizedEvenField) + } else if inscription.tx_in_index != 0 { Some(Curse::NotInFirstInput) } else if inscription.tx_in_offset != 0 { Some(Curse::NotAtOffsetZero) @@ -214,7 +216,9 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { curse.is_some() }; - let unbound = input_value == 0 || inscription.tx_in_offset != 0; + let unbound = input_value == 0 + || inscription.tx_in_offset != 0 + || curse == Some(Curse::UnrecognizedEvenField); if curse.is_some() || unbound { log::info!( diff --git a/src/inscription.rs b/src/inscription.rs index a63d4f0d4f..3cecac98dc 100644 --- a/src/inscription.rs +++ b/src/inscription.rs @@ -20,12 +20,14 @@ pub(crate) enum Curse { NotInFirstInput, NotAtOffsetZero, Reinscription, + UnrecognizedEvenField, } #[derive(Debug, PartialEq, Clone)] pub struct Inscription { body: Option>, content_type: Option>, + pub(crate) unrecognized_even_field: bool, } #[derive(Debug, PartialEq, Clone)] @@ -38,7 +40,11 @@ pub(crate) struct TransactionInscription { impl Inscription { #[cfg(test)] pub(crate) fn new(content_type: Option>, body: Option>) -> Self { - Self { content_type, body } + Self { + content_type, + body, + unrecognized_even_field: false, + } } pub(crate) fn from_transaction(tx: &Transaction) -> Vec { @@ -81,6 +87,7 @@ impl Inscription { Ok(Self { body: Some(body), content_type: Some(content_type.into()), + unrecognized_even_field: false, }) } @@ -160,7 +167,6 @@ pub(crate) enum InscriptionError { KeyPathSpend, NoInscription, Script(script::Error), - UnrecognizedEvenField, } type Result = std::result::Result; @@ -250,12 +256,20 @@ impl<'a> InscriptionParser<'a> { for tag in fields.keys() { if let Some(lsb) = tag.first() { if lsb % 2 == 0 { - return Err(InscriptionError::UnrecognizedEvenField); + return Ok(Inscription { + body, + content_type, + unrecognized_even_field: true, + }); } } } - Ok(Inscription { body, content_type }) + Ok(Inscription { + body, + content_type, + unrecognized_even_field: false, + }) } fn advance(&mut self) -> Result> { @@ -413,6 +427,7 @@ mod tests { Ok(vec![Inscription { content_type: Some(b"text/plain;charset=utf-8".to_vec()), body: None, + unrecognized_even_field: false, }]), ); } @@ -424,6 +439,7 @@ mod tests { Ok(vec![Inscription { content_type: None, body: Some(b"foo".to_vec()), + unrecognized_even_field: false, }]), ); } @@ -754,6 +770,7 @@ mod tests { &Inscription { content_type: None, body: None, + unrecognized_even_field: false, } .append_reveal_script(script::Builder::new()), ); @@ -765,6 +782,7 @@ mod tests { vec![Inscription { content_type: None, body: None, + unrecognized_even_field: false, }] ); } @@ -776,15 +794,20 @@ mod tests { Ok(vec![Inscription { content_type: None, body: None, + unrecognized_even_field: false, }]), ); } #[test] - fn unknown_even_fields_are_invalid() { + fn unknown_even_fields() { assert_eq!( InscriptionParser::parse(&envelope(&[b"ord", &[2], &[0]])), - Err(InscriptionError::UnrecognizedEvenField), + Ok(vec![Inscription { + content_type: None, + body: None, + unrecognized_even_field: true, + }]), ); } } diff --git a/src/test.rs b/src/test.rs index 43fd74e927..1ea1634daf 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,9 +1,10 @@ pub(crate) use { super::*, crate::inscription::TransactionInscription, - bitcoin::blockdata::script::PushBytesBuf, - bitcoin::blockdata::{opcodes, script}, - bitcoin::{ScriptBuf, Witness}, + bitcoin::{ + blockdata::{opcodes, script, script::PushBytesBuf}, + ScriptBuf, Witness, + }, pretty_assertions::assert_eq as pretty_assert_eq, std::iter, test_bitcoincore_rpc::TransactionTemplate,