@@ -2,7 +2,7 @@ use anyhow::{bail, Context, Result};
2
2
use bitcoin:: {
3
3
consensus:: { deserialize, encode:: serialize_hex} ,
4
4
hashes:: hex:: FromHex ,
5
- BlockHash , Txid ,
5
+ BlockHash , OutPoint , Txid ,
6
6
} ;
7
7
use crossbeam_channel:: Receiver ;
8
8
use rayon:: prelude:: * ;
@@ -21,7 +21,7 @@ use crate::{
21
21
merkle:: Proof ,
22
22
metrics:: { self , Histogram , Metrics } ,
23
23
signals:: Signal ,
24
- status:: ScriptHashStatus ,
24
+ status:: { OutPointStatus , ScriptHashStatus } ,
25
25
tracker:: Tracker ,
26
26
types:: ScriptHash ,
27
27
} ;
@@ -36,6 +36,7 @@ const UNSUBSCRIBED_QUERY_MESSAGE: &str = "your wallet uses less efficient method
36
36
pub struct Client {
37
37
tip : Option < BlockHash > ,
38
38
scripthashes : HashMap < ScriptHash , ScriptHashStatus > ,
39
+ outpoints : HashMap < OutPoint , OutPointStatus > ,
39
40
}
40
41
41
42
#[ derive( Deserialize ) ]
@@ -185,7 +186,25 @@ impl Rpc {
185
186
}
186
187
} )
187
188
. collect :: < Result < Vec < Value > > > ( )
188
- . context ( "failed to update status" ) ?;
189
+ . context ( "failed to update scripthash status" ) ?;
190
+
191
+ notifications. extend (
192
+ client
193
+ . outpoints
194
+ . par_iter_mut ( )
195
+ . filter_map ( |( outpoint, status) | -> Option < Result < Value > > {
196
+ match self . tracker . update_outpoint_status ( status, & self . daemon ) {
197
+ Ok ( true ) => Some ( Ok ( notification (
198
+ "blockchain.outpoint.subscribe" ,
199
+ & [ json ! ( [ outpoint. txid, outpoint. vout] ) , json ! ( status) ] ,
200
+ ) ) ) ,
201
+ Ok ( false ) => None , // outpoint status is the same
202
+ Err ( e) => Some ( Err ( e) ) ,
203
+ }
204
+ } )
205
+ . collect :: < Result < Vec < Value > > > ( )
206
+ . context ( "failed to update scripthash status" ) ?,
207
+ ) ;
189
208
190
209
if let Some ( old_tip) = client. tip {
191
210
let new_tip = self . tracker . chain ( ) . tip ( ) ;
@@ -350,6 +369,28 @@ impl Rpc {
350
369
} )
351
370
}
352
371
372
+ fn outpoint_subscribe ( & self , client : & mut Client , ( txid, vout) : ( Txid , u32 ) ) -> Result < Value > {
373
+ let outpoint = OutPoint :: new ( txid, vout) ;
374
+ Ok ( match client. outpoints . entry ( outpoint) {
375
+ Entry :: Occupied ( e) => json ! ( e. get( ) ) ,
376
+ Entry :: Vacant ( e) => {
377
+ let outpoint = OutPoint :: new ( txid, vout) ;
378
+ let mut status = OutPointStatus :: new ( outpoint) ;
379
+ self . tracker
380
+ . update_outpoint_status ( & mut status, & self . daemon ) ?;
381
+ json ! ( e. insert( status) )
382
+ }
383
+ } )
384
+ }
385
+
386
+ fn outpoint_unsubscribe (
387
+ & self ,
388
+ client : & mut Client ,
389
+ ( txid, vout) : ( Txid , u32 ) ,
390
+ ) -> Result < Value > {
391
+ Ok ( json ! ( client. outpoints. remove( & OutPoint :: new( txid, vout) ) ) )
392
+ }
393
+
353
394
fn new_status ( & self , scripthash : ScriptHash ) -> Result < ScriptHashStatus > {
354
395
let mut status = ScriptHashStatus :: new ( scripthash) ;
355
396
self . tracker
@@ -548,6 +589,8 @@ impl Rpc {
548
589
Params :: Features => self . features ( ) ,
549
590
Params :: HeadersSubscribe => self . headers_subscribe ( client) ,
550
591
Params :: MempoolFeeHistogram => self . get_fee_histogram ( ) ,
592
+ Params :: OutPointSubscribe ( args) => self . outpoint_subscribe ( client, * args) ,
593
+ Params :: OutPointUnsubscribe ( args) => self . outpoint_unsubscribe ( client, * args) ,
551
594
Params :: PeersSubscribe => Ok ( json ! ( [ ] ) ) ,
552
595
Params :: Ping => Ok ( Value :: Null ) ,
553
596
Params :: RelayFee => self . relayfee ( ) ,
@@ -572,12 +615,13 @@ enum Params {
572
615
Banner ,
573
616
BlockHeader ( ( usize , ) ) ,
574
617
BlockHeaders ( ( usize , usize ) ) ,
575
- TransactionBroadcast ( ( String , ) ) ,
576
618
Donation ,
577
619
EstimateFee ( ( u16 , ) ) ,
578
620
Features ,
579
621
HeadersSubscribe ,
580
622
MempoolFeeHistogram ,
623
+ OutPointSubscribe ( ( Txid , u32 ) ) , // TODO: support spk_hint
624
+ OutPointUnsubscribe ( ( Txid , u32 ) ) ,
581
625
PeersSubscribe ,
582
626
Ping ,
583
627
RelayFee ,
@@ -586,6 +630,7 @@ enum Params {
586
630
ScriptHashListUnspent ( ( ScriptHash , ) ) ,
587
631
ScriptHashSubscribe ( ( ScriptHash , ) ) ,
588
632
ScriptHashUnsubscribe ( ( ScriptHash , ) ) ,
633
+ TransactionBroadcast ( ( String , ) ) ,
589
634
TransactionGet ( TxGetArgs ) ,
590
635
TransactionGetMerkle ( ( Txid , usize ) ) ,
591
636
TransactionFromPosition ( ( usize , usize , bool ) ) ,
@@ -599,6 +644,8 @@ impl Params {
599
644
"blockchain.block.headers" => Params :: BlockHeaders ( convert ( params) ?) ,
600
645
"blockchain.estimatefee" => Params :: EstimateFee ( convert ( params) ?) ,
601
646
"blockchain.headers.subscribe" => Params :: HeadersSubscribe ,
647
+ "blockchain.outpoint.subscribe" => Params :: OutPointSubscribe ( convert ( params) ?) ,
648
+ "blockchain.outpoint.unsubscribe" => Params :: OutPointUnsubscribe ( convert ( params) ?) ,
602
649
"blockchain.relayfee" => Params :: RelayFee ,
603
650
"blockchain.scripthash.get_balance" => Params :: ScriptHashGetBalance ( convert ( params) ?) ,
604
651
"blockchain.scripthash.get_history" => Params :: ScriptHashGetHistory ( convert ( params) ?) ,
0 commit comments