@@ -16,14 +16,15 @@ use dashmap::DashMap;
16
16
use deadpool_postgres:: Transaction ;
17
17
use fxhash:: FxHasher ;
18
18
19
+ use crate :: core:: protocol:: satoshi_tracking:: UNBOUND_INSCRIPTION_SATPOINT ;
19
20
use crate :: {
20
21
config:: Config ,
21
22
core:: resolve_absolute_pointer,
22
23
db:: { self , cursor:: TransactionBytesCursor , ordinals_pg} ,
23
24
try_debug, try_error, try_info,
24
25
utils:: format_inscription_id,
25
26
} ;
26
- use ord:: { charm:: Charm , height :: Height , sat:: Sat } ;
27
+ use ord:: { charm:: Charm , sat:: Sat } ;
27
28
28
29
use std:: sync:: mpsc:: channel;
29
30
@@ -401,12 +402,9 @@ pub async fn update_block_inscriptions_with_consensus_sequence_data(
401
402
// Check if we've previously inscribed over any satoshi being inscribed to in this new block. This would be a reinscription.
402
403
let mut reinscriptions_data =
403
404
ordinals_pg:: get_reinscriptions_for_block ( inscriptions_data, db_tx) . await ?;
404
- // Keep a reference of inscribed satoshis that fall outside of this block's total sats . These would be unbound inscriptions.
405
+ // Keep a reference of inscribed satoshis that will go towards miner fees . These would be unbound inscriptions.
405
406
let mut sat_overflows = VecDeque :: new ( ) ;
406
407
let network = get_bitcoin_network ( & block. metadata . network ) ;
407
- let coinbase_subsidy = Height ( block. block_identifier . index as u32 ) . subsidy ( ) ;
408
- let coinbase_tx = & block. transactions [ 0 ] . clone ( ) ;
409
- let mut cumulated_fees = 0u64 ;
410
408
411
409
for ( tx_index, tx) in block. transactions . iter_mut ( ) . enumerate ( ) {
412
410
update_tx_inscriptions_with_consensus_sequence_data (
@@ -416,9 +414,6 @@ pub async fn update_block_inscriptions_with_consensus_sequence_data(
416
414
sequence_cursor,
417
415
& network,
418
416
inscriptions_data,
419
- coinbase_tx,
420
- coinbase_subsidy,
421
- & mut cumulated_fees,
422
417
& mut sat_overflows,
423
418
& mut reinscriptions_data,
424
419
db_tx,
@@ -427,19 +422,28 @@ pub async fn update_block_inscriptions_with_consensus_sequence_data(
427
422
. await ?;
428
423
}
429
424
425
+ // Assign inscription numbers to remaining unbound inscriptions.
430
426
while let Some ( ( tx_index, op_index) ) = sat_overflows. pop_front ( ) {
431
427
let OrdinalOperation :: InscriptionRevealed ( ref mut inscription_data) =
432
428
block. transactions [ tx_index] . metadata . ordinal_operations [ op_index]
433
429
else {
434
430
continue ;
435
431
} ;
432
+
436
433
let is_cursed = inscription_data. curse_type . is_some ( ) ;
437
434
let inscription_number = sequence_cursor
438
435
. pick_next ( is_cursed, block. block_identifier . index , & network, db_tx)
439
436
. await ?;
440
437
inscription_data. inscription_number = inscription_number;
441
-
442
438
sequence_cursor. increment ( is_cursed, db_tx) . await ?;
439
+
440
+ // Also assign an unbound sequence number and set outpoint to all zeros, just like `ord`.
441
+ let unbound_sequence = sequence_cursor. increment_unbound ( db_tx) . await ?;
442
+ inscription_data. satpoint_post_inscription =
443
+ format ! ( "{UNBOUND_INSCRIPTION_SATPOINT}:{unbound_sequence}" ) ;
444
+ inscription_data. ordinal_offset = unbound_sequence as u64 ;
445
+ inscription_data. unbound_sequence = Some ( unbound_sequence) ;
446
+
443
447
try_info ! (
444
448
ctx,
445
449
"Unbound inscription {} (#{}) detected on Satoshi {} (block #{}, {} transfers)" ,
@@ -464,9 +468,6 @@ async fn update_tx_inscriptions_with_consensus_sequence_data(
464
468
sequence_cursor : & mut SequenceCursor ,
465
469
network : & Network ,
466
470
inscriptions_data : & mut BTreeMap < ( TransactionIdentifier , usize , u64 ) , TraversalResult > ,
467
- coinbase_tx : & BitcoinTransactionData ,
468
- coinbase_subsidy : u64 ,
469
- cumulated_fees : & mut u64 ,
470
471
sats_overflows : & mut VecDeque < ( usize , usize ) > ,
471
472
reinscriptions_data : & mut HashMap < u64 , String > ,
472
473
db_tx : & Transaction < ' _ > ,
@@ -559,16 +560,8 @@ async fn update_tx_inscriptions_with_consensus_sequence_data(
559
560
}
560
561
}
561
562
562
- let ( destination, satpoint_post_transfer, output_value) = compute_satpoint_post_transfer (
563
- & & * tx,
564
- input_index,
565
- relative_offset,
566
- network,
567
- coinbase_tx,
568
- coinbase_subsidy,
569
- cumulated_fees,
570
- ctx,
571
- ) ;
563
+ let ( destination, satpoint_post_transfer, output_value) =
564
+ compute_satpoint_post_transfer ( & & * tx, input_index, relative_offset, network, ctx) ;
572
565
inscription. satpoint_post_inscription = satpoint_post_transfer;
573
566
inscription_subindex += 1 ;
574
567
@@ -637,11 +630,150 @@ mod test {
637
630
protocol:: { satoshi_numbering:: TraversalResult , sequence_cursor:: SequenceCursor } ,
638
631
test_builders:: { TestBlockBuilder , TestTransactionBuilder } ,
639
632
} ,
640
- db:: { ordinals_pg, pg_reset_db, pg_test_connection, pg_test_connection_pool} ,
633
+ db:: {
634
+ ordinals_pg:: { self , insert_block} ,
635
+ pg_reset_db, pg_test_connection, pg_test_connection_pool,
636
+ } ,
641
637
} ;
642
638
643
639
use super :: update_block_inscriptions_with_consensus_sequence_data;
644
640
641
+ #[ test_case( None => Ok ( ( "0000000000000000000000000000000000000000000000000000000000000000:0:0" . into( ) , Some ( 0 ) ) ) ; "first unbound sequence" ) ]
642
+ #[ test_case( Some ( 230 ) => Ok ( ( "0000000000000000000000000000000000000000000000000000000000000000:0:231" . into( ) , Some ( 231 ) ) ) ; "next unbound sequence" ) ]
643
+ #[ tokio:: test]
644
+ async fn unbound_inscription_sequence (
645
+ curr_sequence : Option < i64 > ,
646
+ ) -> Result < ( String , Option < i64 > ) , String > {
647
+ let ctx = Context :: empty ( ) ;
648
+ let mut sequence_cursor = SequenceCursor :: new ( ) ;
649
+ let mut cache_l1 = BTreeMap :: new ( ) ;
650
+ let tx_id = TransactionIdentifier {
651
+ hash : "0xb4722ad74e7092a194e367f2ec0609994ef7a006db4f9b9d055b46cfb6514e06" . into ( ) ,
652
+ } ;
653
+ let input_index = 1 ;
654
+
655
+ cache_l1. insert (
656
+ ( tx_id. clone ( ) , input_index, 0 ) ,
657
+ TraversalResult {
658
+ inscription_number : OrdinalInscriptionNumber {
659
+ classic : 0 ,
660
+ jubilee : 0 ,
661
+ } ,
662
+ inscription_input_index : input_index,
663
+ transaction_identifier_inscription : tx_id. clone ( ) ,
664
+ ordinal_number : 817263817263 ,
665
+ transfers : 0 ,
666
+ } ,
667
+ ) ;
668
+ let mut pg_client = pg_test_connection ( ) . await ;
669
+ ordinals_pg:: migrate ( & mut pg_client) . await ?;
670
+ let result = {
671
+ let mut ord_client = pg_pool_client ( & pg_test_connection_pool ( ) ) . await ?;
672
+ let client = pg_begin ( & mut ord_client) . await ?;
673
+
674
+ if let Some ( curr_sequence) = curr_sequence {
675
+ // Simulate previous unbound sequence
676
+ let mut tx = TestTransactionBuilder :: new_with_operation ( ) . build ( ) ;
677
+ if let OrdinalOperation :: InscriptionRevealed ( data) =
678
+ & mut tx. metadata . ordinal_operations [ 0 ]
679
+ {
680
+ data. unbound_sequence = Some ( curr_sequence) ;
681
+ } ;
682
+ let block = TestBlockBuilder :: new ( ) . transactions ( vec ! [ tx] ) . build ( ) ;
683
+ insert_block ( & block, & client) . await ?;
684
+ }
685
+
686
+ // Insert new block
687
+ let mut block = TestBlockBuilder :: new ( )
688
+ . height ( 878878 )
689
+ // Coinbase
690
+ . add_transaction ( TestTransactionBuilder :: new ( ) . build ( ) )
691
+ . add_transaction (
692
+ TestTransactionBuilder :: new ( )
693
+ . hash ( tx_id. hash . clone ( ) )
694
+ // Normal input
695
+ . add_input ( TxIn {
696
+ previous_output : OutPoint {
697
+ txid : TransactionIdentifier { hash : "0xf181aa98f2572879bd02278c72c83c7eaac2db82af713d1d239fc41859b2a26e" . into ( ) } ,
698
+ vout : 0 ,
699
+ value : 8000 ,
700
+ block_height : 884200 ,
701
+ } ,
702
+ script_sig : "0x00" . into ( ) ,
703
+ sequence : 0 ,
704
+ witness : vec ! [ "0x00" . into( ) ] ,
705
+ } )
706
+ // Goes to fees
707
+ . add_input ( TxIn {
708
+ previous_output : OutPoint {
709
+ txid : TransactionIdentifier { hash : "0xf181aa98f2572879bd02278c72c83c7eaac2db82af713d1d239fc41859b2a26e" . into ( ) } ,
710
+ vout : 1 ,
711
+ value : 250 ,
712
+ block_height : 884200 ,
713
+ } ,
714
+ script_sig : "0x00" . into ( ) ,
715
+ sequence : 0 ,
716
+ witness : vec ! [ "0x00" . into( ) ] ,
717
+ } )
718
+ . add_output ( TxOut { value : 8000 , script_pubkey : "0x5120694b38ea24908e86a857279105c376a82cd1556f51655abb2ebef398b57daa8b" . into ( ) } )
719
+ . add_ordinal_operation ( OrdinalOperation :: InscriptionRevealed (
720
+ OrdinalInscriptionRevealData {
721
+ content_bytes : "0x101010" . into ( ) ,
722
+ content_type : "text/plain" . into ( ) ,
723
+ content_length : 3 ,
724
+ inscription_number : OrdinalInscriptionNumber {
725
+ classic : 0 ,
726
+ jubilee : 0 ,
727
+ } ,
728
+ inscription_fee : 0 ,
729
+ inscription_output_value : 0 ,
730
+ inscription_id : "" . into ( ) ,
731
+ inscription_input_index : input_index,
732
+ inscription_pointer : Some ( 8000 ) ,
733
+ inscriber_address : Some ( "bc1pd99n363yjz8gd2zhy7gstsmk4qkdz4t029j44wewhmee3dta429sm5xqrd" . into ( ) ) ,
734
+ delegate : None ,
735
+ metaprotocol : None ,
736
+ metadata : None ,
737
+ parents : vec ! [ ] ,
738
+ ordinal_number : 0 ,
739
+ ordinal_block_height : 0 ,
740
+ ordinal_offset : 0 ,
741
+ tx_index : 1 ,
742
+ transfers_pre_inscription : 0 ,
743
+ satpoint_post_inscription : "" . into ( ) ,
744
+ curse_type : Some ( OrdinalInscriptionCurseType :: DuplicateField ) ,
745
+ charms : 0 ,
746
+ unbound_sequence : None ,
747
+ } ,
748
+ ) )
749
+ . build ( ) ,
750
+ )
751
+ . build ( ) ;
752
+
753
+ update_block_inscriptions_with_consensus_sequence_data (
754
+ & mut block,
755
+ & mut sequence_cursor,
756
+ & mut cache_l1,
757
+ & client,
758
+ & ctx,
759
+ )
760
+ . await ?;
761
+
762
+ let result = & block. transactions [ 1 ] . metadata . ordinal_operations [ 0 ] ;
763
+ let data = match result {
764
+ OrdinalOperation :: InscriptionRevealed ( data) => data,
765
+ _ => unreachable ! ( ) ,
766
+ } ;
767
+ Ok ( (
768
+ data. satpoint_post_inscription . clone ( ) ,
769
+ data. unbound_sequence ,
770
+ ) )
771
+ } ;
772
+ pg_reset_db ( & mut pg_client) . await ?;
773
+
774
+ result
775
+ }
776
+
645
777
#[ test_case( ( 884207 , false , 1262349832364434 , "0x5120694b38ea24908e86a857279105c376a82cd1556f51655abb2ebef398b57daa8b" . into( ) ) => Ok ( vec![ ] ) ; "common sat" ) ]
646
778
#[ test_case( ( 884207 , false , 0 , "0x5120694b38ea24908e86a857279105c376a82cd1556f51655abb2ebef398b57daa8b" . into( ) ) => Ok ( vec![ Charm :: Coin , Charm :: Mythic , Charm :: Palindrome ] ) ; "mythic sat" ) ]
647
779
#[ test_case( ( 884207 , false , 1050000000000000 , "0x5120694b38ea24908e86a857279105c376a82cd1556f51655abb2ebef398b57daa8b" . into( ) ) => Ok ( vec![ Charm :: Coin , Charm :: Epic ] ) ; "epic sat" ) ]
@@ -727,6 +859,7 @@ mod test {
727
859
satpoint_post_inscription : "" . into ( ) ,
728
860
curse_type : if cursed { Some ( OrdinalInscriptionCurseType :: Generic ) } else { None } ,
729
861
charms : 0 ,
862
+ unbound_sequence : None ,
730
863
} ,
731
864
) )
732
865
. build ( ) ,
@@ -743,12 +876,10 @@ mod test {
743
876
. await ?;
744
877
745
878
let result = & block. transactions [ 1 ] . metadata . ordinal_operations [ 0 ] ;
746
- // println!("{:?}", result);
747
879
let charms = match result {
748
880
OrdinalOperation :: InscriptionRevealed ( data) => data. charms ,
749
881
_ => unreachable ! ( ) ,
750
882
} ;
751
- // println!("{:?}", Charm::charms(charms));
752
883
Ok ( Charm :: charms ( charms) )
753
884
} ;
754
885
pg_reset_db ( & mut pg_client) . await ?;
0 commit comments