@@ -43,7 +43,8 @@ type Explorer interface {
43
43
BaseUrl () string
44
44
GetFeeRate () (float64 , error )
45
45
TrackAddress (addr string ) error
46
- ListenAddresses (messageHandler func ([]BlockUtxo ) error ) error
46
+ ListenAddresses (messageHandler func ([]BlockUtxo , []BlockUtxo ) error ) error
47
+ FetchMempoolRBFTx (txid string ) (bool , []string , error )
47
48
}
48
49
49
50
type AddrTracker struct {
@@ -187,6 +188,28 @@ func (e *explorerSvc) GetTxs(addr string) ([]tx, error) {
187
188
return payload , nil
188
189
}
189
190
191
+ func (e * explorerSvc ) GetTxByTxid (addr string ) ([]tx , error ) {
192
+ resp , err := http .Get (fmt .Sprintf ("%s/address/%s/txs" , e .baseUrl , addr ))
193
+ if err != nil {
194
+ return nil , err
195
+ }
196
+ // nolint:all
197
+ defer resp .Body .Close ()
198
+ body , err := io .ReadAll (resp .Body )
199
+ if err != nil {
200
+ return nil , err
201
+ }
202
+ if resp .StatusCode != http .StatusOK {
203
+ return nil , fmt .Errorf ("failed to get txs: %s" , string (body ))
204
+ }
205
+ payload := []tx {}
206
+ if err := json .Unmarshal (body , & payload ); err != nil {
207
+ return nil , err
208
+ }
209
+
210
+ return payload , nil
211
+ }
212
+
190
213
func (e explorerSvc ) IsRBFTx (txid , txHex string ) (bool , string , int64 , error ) {
191
214
resp , err := http .Get (fmt .Sprintf ("%s/v1/fullrbf/replacements" , e .baseUrl ))
192
215
if err != nil {
@@ -206,8 +229,8 @@ func (e explorerSvc) IsRBFTx(txid, txHex string) (bool, string, int64, error) {
206
229
return false , "" , - 1 , fmt .Errorf ("%s" , string (body ))
207
230
}
208
231
209
- isRbf , replacedBy , timestamp , err := e .mempoolIsRBFTx (
210
- fmt .Sprintf ("%s/v1/fullrbf/replacements" , e .baseUrl ), txid ,
232
+ isRbf , replacedBy , timestamp , _ , err := e .mempoolIsRBFTx (
233
+ fmt .Sprintf ("%s/v1/fullrbf/replacements" , e .baseUrl ), txid , false ,
211
234
)
212
235
if err != nil {
213
236
return false , "" , - 1 , err
@@ -216,7 +239,24 @@ func (e explorerSvc) IsRBFTx(txid, txHex string) (bool, string, int64, error) {
216
239
return isRbf , replacedBy , timestamp , nil
217
240
}
218
241
219
- return e .mempoolIsRBFTx (fmt .Sprintf ("%s/v1/replacements" , e .baseUrl ), txid )
242
+ isRbf , replacedBy , timestamp , _ , err = e .mempoolIsRBFTx (fmt .Sprintf ("%s/v1/replacements" , e .baseUrl ), txid , false )
243
+
244
+ return isRbf , replacedBy , timestamp , err
245
+ }
246
+
247
+ func (e * explorerSvc ) FetchMempoolRBFTx (txid string ) (bool , []string , error ) {
248
+ isRbf , _ , _ , replacements , err := e .mempoolIsRBFTx (
249
+ fmt .Sprintf ("%s/v1/fullrbf/replacements" , e .baseUrl ), txid , true ,
250
+ )
251
+ if err != nil {
252
+ return false , nil , err
253
+ }
254
+ if isRbf {
255
+ return true , replacements , nil
256
+ }
257
+
258
+ isRbf , _ , _ , replacements , err = e .mempoolIsRBFTx (fmt .Sprintf ("%s/v1/replacements" , e .baseUrl ), txid , false )
259
+ return isRbf , replacements , err
220
260
}
221
261
222
262
func (e * explorerSvc ) GetTxOutspends (txid string ) ([]spentStatus , error ) {
@@ -310,7 +350,7 @@ func (e *explorerSvc) GetRedeemedVtxosBalance(
310
350
return
311
351
}
312
352
313
- func (e * explorerSvc ) ListenAddresses (messageHandler func ([]BlockUtxo ) error ) error {
353
+ func (e * explorerSvc ) ListenAddresses (messageHandler func ([]BlockUtxo , [] BlockUtxo ) error ) error {
314
354
if e .addrTracker == nil {
315
355
return fmt .Errorf ("address tracker not initialized" )
316
356
}
@@ -395,36 +435,49 @@ func (e *explorerSvc) broadcast(txHex string) (string, error) {
395
435
return string (bodyResponse ), nil
396
436
}
397
437
398
- func (e * explorerSvc ) mempoolIsRBFTx (url , txid string ) (bool , string , int64 , error ) {
438
+ func (e * explorerSvc ) mempoolIsRBFTx (url , txid string , isReplacing bool ) (bool , string , int64 , [] string , error ) {
399
439
resp , err := http .Get (url )
400
440
if err != nil {
401
- return false , "" , - 1 , err
441
+ return false , "" , - 1 , nil , err
402
442
}
403
443
404
444
// nolint:all
405
445
defer resp .Body .Close ()
406
446
body , err := io .ReadAll (resp .Body )
407
447
if err != nil {
408
- return false , "" , - 1 , err
448
+ return false , "" , - 1 , nil , err
409
449
}
410
450
411
451
if resp .StatusCode != http .StatusOK {
412
- return false , "" , - 1 , fmt .Errorf ("%s" , string (body ))
452
+ return false , "" , - 1 , nil , fmt .Errorf ("%s" , string (body ))
413
453
}
414
454
415
455
replacements := make ([]replacement , 0 )
416
456
if err := json .Unmarshal (body , & replacements ); err != nil {
417
- return false , "" , - 1 , err
457
+ return false , "" , - 1 , nil , err
458
+ }
459
+
460
+ if isReplacing {
461
+ for _ , r := range replacements {
462
+ if r .Tx .Txid == txid {
463
+ replacementTxIds := make ([]string , 0 , len (r .Replaces ))
464
+ for _ , rr := range r .Replaces {
465
+ replacementTxIds = append (replacementTxIds , rr .Tx .Txid )
466
+ }
467
+ return true , r .Tx .Txid , r .Timestamp , replacementTxIds , nil
468
+ }
469
+ }
470
+ return false , "" , 0 , nil , nil
418
471
}
419
472
420
473
for _ , r := range replacements {
421
474
for _ , rr := range r .Replaces {
422
475
if rr .Tx .Txid == txid {
423
- return true , r .Tx .Txid , r .Timestamp , nil
476
+ return true , r .Tx .Txid , r .Timestamp , nil , nil
424
477
}
425
478
}
426
479
}
427
- return false , "" , 0 , nil
480
+ return false , "" , 0 , nil , nil
428
481
}
429
482
430
483
func (e * explorerSvc ) esploraIsRBFTx (txid , txHex string ) (bool , string , int64 , error ) {
@@ -557,7 +610,7 @@ func (t *AddrTracker) TrackAddress(addr string) error {
557
610
return nil
558
611
}
559
612
560
- func (t * AddrTracker ) ListenAddresses (messageHandler func ([]BlockUtxo ) error ) error {
613
+ func (t * AddrTracker ) ListenAddresses (messageHandler func ([]BlockUtxo , [] BlockUtxo ) error ) error {
561
614
// Send ping every 25s to keep alive
562
615
go func () {
563
616
ticker := time .NewTicker (25 * time .Second )
@@ -571,28 +624,27 @@ func (t *AddrTracker) ListenAddresses(messageHandler func([]BlockUtxo) error) er
571
624
}()
572
625
573
626
for {
574
- var payload WSBlockTransactions
627
+ var payload WSFetchTransactions
575
628
err := t .conn .ReadJSON (& payload )
576
629
if err != nil {
577
630
return fmt .Errorf ("read message failed: %w" , err )
578
631
}
579
632
580
- if len (payload .BlockTransactions ) == 0 {
581
- continue
582
- }
633
+ mempoolutxos := t .deriveUtxos (payload .MempoolTransactions )
634
+ blockutxos := t .deriveUtxos (payload .BlockTransactions )
635
+
636
+ err = messageHandler (blockutxos , mempoolutxos )
583
637
584
- utxos := t .deriveUtxos (payload )
585
- err = messageHandler (utxos )
586
638
if err != nil {
587
639
return err
588
640
}
589
641
}
590
642
591
643
}
592
644
593
- func (t * AddrTracker ) deriveUtxos (block WSBlockTransactions ) []BlockUtxo {
645
+ func (t * AddrTracker ) deriveUtxos (trasactions [] RawTx ) []BlockUtxo {
594
646
utxos := make ([]BlockUtxo , 0 , len (t .subscribedMap ))
595
- for _ , rawTransaction := range block . BlockTransactions {
647
+ for _ , rawTransaction := range trasactions {
596
648
597
649
for index , out := range rawTransaction .Vout {
598
650
if _ , ok := t .subscribedMap [out .ScriptPubKeyAddr ]; ok {
@@ -605,5 +657,6 @@ func (t *AddrTracker) deriveUtxos(block WSBlockTransactions) []BlockUtxo {
605
657
}
606
658
}
607
659
}
660
+
608
661
return utxos
609
662
}
0 commit comments