@@ -19,7 +19,6 @@ use ergo_lib::{
19
19
token:: TokenId ,
20
20
} ,
21
21
ergo_tree:: ErgoTree ,
22
- mir:: constant:: TryExtractInto ,
23
22
serialization:: SigmaSerializable ,
24
23
} ,
25
24
} ;
@@ -44,6 +43,81 @@ pub enum ScannerError {
44
43
InvalidReserveBox ( TokenId , TxId ) ,
45
44
}
46
45
46
+ struct ContractScan < ' a > {
47
+ scan_type : ScanType ,
48
+ scan : Scan < ' a > ,
49
+ }
50
+
51
+ impl < ' a > ContractScan < ' a > {
52
+ async fn new (
53
+ state : & ServerState ,
54
+ scan_type : ScanType ,
55
+ public_keys : & [ EcPoint ] ,
56
+ ) -> Result < Self , ScannerError > {
57
+ let ( contract, register) = match scan_type {
58
+ ScanType :: Reserves => (
59
+ state. compiler . reserve_contract ( ) . await ?,
60
+ NonMandatoryRegisterId :: R4 ,
61
+ ) ,
62
+ ScanType :: Notes => (
63
+ state. compiler . note_contract ( ) . await ?,
64
+ NonMandatoryRegisterId :: R5 ,
65
+ ) ,
66
+ ScanType :: Receipts => (
67
+ state. compiler . receipt_contract ( ) . await ?,
68
+ NonMandatoryRegisterId :: R7 ,
69
+ ) ,
70
+ } ;
71
+ let scan = Self :: pubkey_scan (
72
+ format ! ( "Chaincash {} scan" , scan_type. to_str( ) ) ,
73
+ contract,
74
+ register,
75
+ public_keys,
76
+ ) ;
77
+ Ok ( Self { scan_type, scan } )
78
+ }
79
+
80
+ fn pubkey_scan (
81
+ scan_name : impl Into < std:: borrow:: Cow < ' a , str > > ,
82
+ contract : & ErgoTree ,
83
+ pubkey_register : NonMandatoryRegisterId ,
84
+ public_keys : & [ EcPoint ] ,
85
+ ) -> Scan < ' a > {
86
+ Scan {
87
+ scan_name : scan_name. into ( ) ,
88
+ wallet_interaction : "off" . into ( ) ,
89
+ tracking_rule : TrackingRule :: And {
90
+ args : vec ! [
91
+ TrackingRule :: Contains {
92
+ register: Some ( RegisterId :: R1 ) ,
93
+ value: contract. sigma_serialize_bytes( ) . unwrap( ) . into( ) ,
94
+ } ,
95
+ TrackingRule :: Or {
96
+ args: public_keys
97
+ . iter( )
98
+ . map( |pubkey| TrackingRule :: Equals {
99
+ register: Some ( pubkey_register. into( ) ) ,
100
+ value: pubkey. clone( ) . into( ) ,
101
+ } )
102
+ . collect( ) ,
103
+ } ,
104
+ ] ,
105
+ } ,
106
+ remove_offchain : true ,
107
+ }
108
+ }
109
+ async fn register (
110
+ & ' a self ,
111
+ state : & ServerState ,
112
+ ) -> Result < chaincash_store:: scans:: Scan < ' a > , ScannerError > {
113
+ let scan_id = state. node . endpoints ( ) . scan ( ) ?. register ( & self . scan ) . await ?;
114
+ let store_scan =
115
+ chaincash_store:: scans:: Scan :: new ( scan_id, & * self . scan . scan_name , self . scan_type ) ;
116
+ state. store . scans ( ) . add ( & store_scan) ?;
117
+ Ok ( store_scan)
118
+ }
119
+ }
120
+
47
121
// Wait for the next block before re-checking scans
48
122
async fn wait_scan_block ( state : & ServerState ) -> Result < ( ) , ScannerError > {
49
123
let wallet = state. node . endpoints ( ) . wallet ( ) ?;
@@ -67,83 +141,6 @@ async fn get_transaction(
67
141
. find ( |tx| tx. id ( ) == * tx_id) )
68
142
}
69
143
70
- fn pubkey_scan < ' a > (
71
- scan_name : impl Into < std:: borrow:: Cow < ' a , str > > ,
72
- contract : & ErgoTree ,
73
- pubkey_register : NonMandatoryRegisterId ,
74
- public_keys : & [ EcPoint ] ,
75
- ) -> Scan < ' a > {
76
- Scan {
77
- scan_name : scan_name. into ( ) ,
78
- wallet_interaction : "off" . into ( ) ,
79
- tracking_rule : TrackingRule :: And {
80
- args : vec ! [
81
- TrackingRule :: Contains {
82
- register: Some ( RegisterId :: R1 ) ,
83
- value: contract. sigma_serialize_bytes( ) . unwrap( ) . into( ) ,
84
- } ,
85
- TrackingRule :: Or {
86
- args: public_keys
87
- . iter( )
88
- . map( |pubkey| TrackingRule :: Equals {
89
- register: Some ( pubkey_register. into( ) ) ,
90
- value: pubkey. clone( ) . into( ) ,
91
- } )
92
- . collect( ) ,
93
- } ,
94
- ] ,
95
- } ,
96
- remove_offchain : true ,
97
- }
98
- }
99
-
100
- fn pubkeys_from_scan ( scan : & RegisteredScan ) -> Option < Vec < EcPoint > > {
101
- match & scan. scan . tracking_rule {
102
- TrackingRule :: And { args } => match & args[ ..] {
103
- [ .., TrackingRule :: Or { args } ] => Some (
104
- args. iter ( )
105
- . filter_map ( |arg| {
106
- if let TrackingRule :: Equals { register : _, value } = arg {
107
- value. clone ( ) . try_extract_into :: < EcPoint > ( ) . ok ( )
108
- } else {
109
- None
110
- }
111
- } )
112
- . collect ( ) ,
113
- ) ,
114
- _ => None ,
115
- } ,
116
- _ => None ,
117
- }
118
- }
119
-
120
- async fn register_scan < ' a > (
121
- state : & ServerState ,
122
- scan_type : ScanType ,
123
- public_keys : & [ EcPoint ] ,
124
- ) -> Result < chaincash_store:: scans:: Scan < ' a > , ScannerError > {
125
- let name = format ! ( "Chaincash {} scan" , scan_type. to_str( ) ) ;
126
- let ( contract, register) = match scan_type {
127
- ScanType :: Reserves => (
128
- state. compiler . reserve_contract ( ) . await ?,
129
- NonMandatoryRegisterId :: R4 ,
130
- ) ,
131
- ScanType :: Notes => (
132
- state. compiler . note_contract ( ) . await ?,
133
- NonMandatoryRegisterId :: R5 ,
134
- ) ,
135
- ScanType :: Receipts => (
136
- state. compiler . receipt_contract ( ) . await ?,
137
- NonMandatoryRegisterId :: R7 ,
138
- ) ,
139
- } ;
140
- let scan = pubkey_scan ( name, contract, register, public_keys) ;
141
- let scan_id = state. node . endpoints ( ) . scan ( ) ?. register ( & scan) . await ?;
142
- let store_scan = chaincash_store:: scans:: Scan :: new ( scan_id, scan. scan_name , scan_type) ;
143
- state. store . scans ( ) . add ( & store_scan) ?;
144
- Ok ( store_scan)
145
- }
146
-
147
144
// Load scans by type. If node changes then wrong scans will be detected and re-registered
148
145
// Returns (needs_rescan, scan_type)
149
146
async fn load_scan (
@@ -163,29 +160,20 @@ async fn load_scan(
163
160
_ => None ,
164
161
} )
165
162
. collect :: < Vec < _ > > ( ) ;
163
+ let contract_scan = ContractScan :: new ( state, scan_type, & addresses) . await ?;
166
164
let scan = state. store . scans ( ) . scan_by_type ( scan_type) ?;
167
165
if let Some ( scan) = scan {
168
- let node_scan = node_scans
169
- . iter ( )
170
- . find ( |node_scan| scan. scan_name == node_scan. scan . scan_name ) ;
171
- if let Some ( reserve_scan) = node_scan {
172
- if let Some ( scan_pubkeys) = pubkeys_from_scan ( reserve_scan) {
173
- if addresses. iter ( ) . all ( |wallet_pubkey| {
174
- scan_pubkeys
175
- . iter ( )
176
- . any ( |scan_pubkey| wallet_pubkey == scan_pubkey)
177
- } ) {
178
- return Ok ( ( false , scan. scan_id ) ) ;
179
- }
180
- } else {
181
- warn ! (
182
- "Scan #{} ({}) invalidated, re-registering" ,
183
- scan. scan_id, scan. scan_name
184
- ) ;
185
- }
166
+ if node_scans. iter ( ) . any ( |node_scan| {
167
+ scan. scan_id as u32 == node_scan. scan_id
168
+ && scan. scan_name == node_scan. scan . scan_name
169
+ && node_scan. scan == contract_scan. scan
170
+ } ) {
171
+ return Ok ( ( false , scan. scan_id ) ) ;
172
+ } else {
173
+ warn ! ( "Scan {} invalidated, re-registering" , scan. scan_id) ;
186
174
}
187
175
}
188
- let scan_id = register_scan ( state, scan_type , & addresses ) . await ?. scan_id ;
176
+ let scan_id = contract_scan . register ( state) . await ?. scan_id ;
189
177
Ok ( ( true , scan_id) )
190
178
}
191
179
@@ -196,7 +184,7 @@ async fn reserve_scanner(state: Arc<ServerState>, scan_id: i32) -> Result<(), Sc
196
184
. extensions ( )
197
185
. get_all_unspent_boxes ( scan_id as u32 , false )
198
186
. await ?;
199
- for scan_box in scan_boxes {
187
+ for scan_box in & scan_boxes {
200
188
match ReserveBoxSpec :: try_from ( & scan_box. ergo_box ) {
201
189
Ok ( reserve_box) => {
202
190
state. store . reserves ( ) . add_or_update ( & reserve_box) ?;
@@ -207,6 +195,12 @@ async fn reserve_scanner(state: Arc<ServerState>, scan_id: i32) -> Result<(), Sc
207
195
) ,
208
196
}
209
197
}
198
+ state
199
+ . store
200
+ . reserves ( )
201
+ . delete_not_in ( scan_boxes. iter ( ) . map ( |b| b. ergo_box . box_id ( ) ) ) ?
202
+ . into_iter ( )
203
+ . for_each ( |deleted| info ! ( "Deleting box id: {deleted}" ) ) ;
210
204
wait_scan_block ( & state) . await ?;
211
205
}
212
206
}
@@ -337,8 +331,8 @@ pub async fn start_scanner(state: Arc<ServerState>) -> Result<(), ScannerError>
337
331
let ( rescan, note_scan) = load_scan ( & state, ScanType :: Notes , & scans) . await ?;
338
332
needs_rescan |= rescan;
339
333
if needs_rescan {
340
- //Rescan from block #1,100,000 . This height can be increased later when chaincash is deployed
341
- let _ = state. node . endpoints ( ) . wallet ( ) ?. rescan ( 1_100_000 ) . await ;
334
+ //Rescan from block #1,318_639 . This height can be increased later when chaincash is deployed
335
+ let _ = state. node . endpoints ( ) . wallet ( ) ?. rescan ( 1_318_639 ) . await ;
342
336
}
343
337
tokio:: spawn ( reserve_scanner ( state. clone ( ) , reserve_scan) ) ;
344
338
tokio:: spawn ( note_scanner ( state. clone ( ) , note_scan) ) ;
0 commit comments