1
1
use std:: { collections:: HashMap , num:: NonZeroUsize , str:: FromStr } ;
2
2
3
- use bitcoin:: Network ;
4
- use chainhook_sdk:: {
5
- types:: bitcoin:: { TxIn , TxOut } ,
6
- utils:: Context ,
7
- } ;
3
+ use bitcoin:: { Network , ScriptBuf } ;
4
+ use chainhook_sdk:: { types:: bitcoin:: TxIn , utils:: Context } ;
8
5
use lru:: LruCache ;
9
6
use ordinals:: { Cenotaph , Edict , Etching , Rune , RuneId , Runestone } ;
10
7
use tokio_postgres:: { Client , Transaction } ;
@@ -26,13 +23,14 @@ use crate::{
26
23
use super :: {
27
24
db_cache:: DbCache ,
28
25
transaction_cache:: { InputRuneBalance , TransactionCache } ,
29
- utils:: move_tx_output_cache_to_output_cache,
26
+ transaction_location:: TransactionLocation ,
27
+ utils:: move_block_output_cache_to_output_cache,
30
28
} ;
31
29
32
30
/// Holds rune data across multiple blocks for faster computations. Processes rune events as they happen during transactions and
33
31
/// generates database rows for later insertion.
34
32
pub struct IndexCache {
35
- network : Network ,
33
+ pub network : Network ,
36
34
/// Number to be assigned to the next rune etching.
37
35
next_rune_number : u32 ,
38
36
/// LRU cache for runes.
@@ -41,9 +39,9 @@ pub struct IndexCache {
41
39
rune_total_mints_cache : LruCache < RuneId , u128 > ,
42
40
/// LRU cache for outputs with rune balances.
43
41
output_cache : LruCache < ( String , u32 ) , HashMap < RuneId , Vec < InputRuneBalance > > > ,
44
- /// Same as above but only for the current transaction . We use a `HashMap` instead of an LRU cache to make sure we keep all
45
- /// outputs in memory while we index this transaction . Must be cleared every time a new transaction is processed.
46
- tx_output_cache : HashMap < ( String , u32 ) , HashMap < RuneId , Vec < InputRuneBalance > > > ,
42
+ /// Same as above but only for the current block . We use a `HashMap` instead of an LRU cache to make sure we keep all outputs
43
+ /// in memory while we index this block . Must be cleared every time a new block is processed.
44
+ block_output_cache : HashMap < ( String , u32 ) , HashMap < RuneId , Vec < InputRuneBalance > > > ,
47
45
/// Holds a single transaction's rune cache. Must be cleared every time a new transaction is processed.
48
46
tx_cache : TransactionCache ,
49
47
/// Keeps rows that have not yet been inserted in the DB.
@@ -60,8 +58,21 @@ impl IndexCache {
60
58
rune_cache : LruCache :: new ( cap) ,
61
59
rune_total_mints_cache : LruCache :: new ( cap) ,
62
60
output_cache : LruCache :: new ( cap) ,
63
- tx_output_cache : HashMap :: new ( ) ,
64
- tx_cache : TransactionCache :: new ( network, & "" . to_string ( ) , 1 , 0 , & "" . to_string ( ) , 0 ) ,
61
+ block_output_cache : HashMap :: new ( ) ,
62
+ tx_cache : TransactionCache :: new (
63
+ TransactionLocation {
64
+ network,
65
+ block_hash : "" . to_string ( ) ,
66
+ block_height : 1 ,
67
+ timestamp : 0 ,
68
+ tx_index : 0 ,
69
+ tx_id : "" . to_string ( ) ,
70
+ } ,
71
+ HashMap :: new ( ) ,
72
+ HashMap :: new ( ) ,
73
+ None ,
74
+ 0 ,
75
+ ) ,
65
76
db_cache : DbCache :: new ( ) ,
66
77
}
67
78
}
@@ -73,69 +84,69 @@ impl IndexCache {
73
84
/// Creates a fresh transaction index cache.
74
85
pub async fn begin_transaction (
75
86
& mut self ,
76
- block_hash : & String ,
77
- block_height : u64 ,
78
- tx_index : u32 ,
79
- tx_id : & String ,
80
- timestamp : u32 ,
87
+ location : TransactionLocation ,
88
+ tx_inputs : & Vec < TxIn > ,
89
+ eligible_outputs : HashMap < u32 , ScriptBuf > ,
90
+ first_eligible_output : Option < u32 > ,
91
+ total_outputs : u32 ,
92
+ db_tx : & mut Transaction < ' _ > ,
93
+ ctx : & Context ,
81
94
) {
95
+ let input_runes = input_rune_balances_from_tx_inputs (
96
+ tx_inputs,
97
+ & self . block_output_cache ,
98
+ & mut self . output_cache ,
99
+ db_tx,
100
+ ctx,
101
+ )
102
+ . await ;
103
+ #[ cfg( not( feature = "release" ) ) ]
104
+ {
105
+ for ( rune_id, balances) in input_runes. iter ( ) {
106
+ try_debug ! ( ctx, "INPUT {rune_id} {balances:?} {location}" ) ;
107
+ }
108
+ if input_runes. len ( ) > 0 {
109
+ try_debug ! ( ctx, "First output: {first_eligible_output:?}, total_outputs: {total_outputs}" ) ;
110
+ }
111
+ }
82
112
self . tx_cache = TransactionCache :: new (
83
- self . network ,
84
- block_hash,
85
- block_height,
86
- tx_index,
87
- tx_id,
88
- timestamp,
113
+ location,
114
+ input_runes,
115
+ eligible_outputs,
116
+ first_eligible_output,
117
+ total_outputs,
89
118
) ;
90
- self . tx_output_cache . clear ( ) ;
91
119
}
92
120
93
- /// Finalizes the current transaction index cache.
121
+ /// Finalizes the current transaction index cache by moving all unallocated balances to the correct output .
94
122
pub fn end_transaction ( & mut self , _db_tx : & mut Transaction < ' _ > , ctx : & Context ) {
95
123
let entries = self . tx_cache . allocate_remaining_balances ( ctx) ;
96
124
self . add_ledger_entries_to_db_cache ( & entries) ;
97
- move_tx_output_cache_to_output_cache ( & mut self . tx_output_cache , & mut self . output_cache ) ;
125
+ }
126
+
127
+ pub fn end_block ( & mut self ) {
128
+ move_block_output_cache_to_output_cache ( & mut self . block_output_cache , & mut self . output_cache ) ;
98
129
}
99
130
100
131
pub async fn apply_runestone (
101
132
& mut self ,
102
133
runestone : & Runestone ,
103
- tx_inputs : & Vec < TxIn > ,
104
- tx_outputs : & Vec < TxOut > ,
105
- db_tx : & mut Transaction < ' _ > ,
134
+ _db_tx : & mut Transaction < ' _ > ,
106
135
ctx : & Context ,
107
136
) {
108
137
try_debug ! ( ctx, "{:?} {}" , runestone, self . tx_cache. location) ;
109
- let input_balances = input_rune_balances_from_tx_inputs (
110
- tx_inputs,
111
- & self . tx_output_cache ,
112
- & mut self . output_cache ,
113
- db_tx,
114
- ctx,
115
- )
116
- . await ;
117
- self . tx_cache . set_input_rune_balances ( input_balances, ctx) ;
118
- self . tx_cache
119
- . apply_runestone_pointer ( runestone, tx_outputs, ctx) ;
138
+ if let Some ( new_pointer) = runestone. pointer {
139
+ self . tx_cache . output_pointer = Some ( new_pointer) ;
140
+ }
120
141
}
121
142
122
143
pub async fn apply_cenotaph (
123
144
& mut self ,
124
145
cenotaph : & Cenotaph ,
125
- tx_inputs : & Vec < TxIn > ,
126
- db_tx : & mut Transaction < ' _ > ,
146
+ _db_tx : & mut Transaction < ' _ > ,
127
147
ctx : & Context ,
128
148
) {
129
149
try_debug ! ( ctx, "{:?} {}" , cenotaph, self . tx_cache. location) ;
130
- let input_balances = input_rune_balances_from_tx_inputs (
131
- tx_inputs,
132
- & self . tx_output_cache ,
133
- & mut self . output_cache ,
134
- db_tx,
135
- ctx,
136
- )
137
- . await ;
138
- self . tx_cache . set_input_rune_balances ( input_balances, ctx) ;
139
150
let entries = self . tx_cache . apply_cenotaph_input_burn ( cenotaph) ;
140
151
self . add_ledger_entries_to_db_cache ( & entries) ;
141
152
}
@@ -407,7 +418,7 @@ impl IndexCache {
407
418
address,
408
419
entry. amount . unwrap ( ) ,
409
420
) ) ;
410
- // Add to current transaction 's output cache if it's received balance.
421
+ // Add to current block 's output cache if it's received balance.
411
422
let k = ( entry. tx_id . clone ( ) , entry. output . unwrap ( ) . 0 ) ;
412
423
let rune_id = RuneId :: from_str ( entry. rune_id . as_str ( ) ) . unwrap ( ) ;
413
424
let balance = InputRuneBalance {
@@ -416,7 +427,7 @@ impl IndexCache {
416
427
} ;
417
428
let mut default = HashMap :: new ( ) ;
418
429
default. insert ( rune_id, vec ! [ balance. clone( ) ] ) ;
419
- self . tx_output_cache
430
+ self . block_output_cache
420
431
. entry ( k)
421
432
. and_modify ( |i| {
422
433
i. entry ( rune_id)
0 commit comments