@@ -2,7 +2,7 @@ use anyhow::{bail, Context, Result};
22use bitcoin:: {
33 consensus:: { deserialize, serialize} ,
44 hashes:: hex:: { FromHex , ToHex } ,
5- BlockHash , Txid ,
5+ BlockHash , OutPoint , Txid ,
66} ;
77use rayon:: prelude:: * ;
88use serde_derive:: Deserialize ;
@@ -18,7 +18,7 @@ use crate::{
1818 merkle:: Proof ,
1919 metrics:: Histogram ,
2020 signals:: Signal ,
21- status:: ScriptHashStatus ,
21+ status:: { OutPointStatus , ScriptHashStatus } ,
2222 tracker:: Tracker ,
2323 types:: ScriptHash ,
2424} ;
@@ -33,6 +33,7 @@ const UNKNOWN_FEE: isize = -1; // (allowed by Electrum protocol)
3333pub struct Client {
3434 tip : Option < BlockHash > ,
3535 scripthashes : HashMap < ScriptHash , ScriptHashStatus > ,
36+ outpoints : HashMap < OutPoint , OutPointStatus > ,
3637}
3738
3839#[ derive( Deserialize ) ]
@@ -172,7 +173,25 @@ impl Rpc {
172173 }
173174 } )
174175 . collect :: < Result < Vec < Value > > > ( )
175- . context ( "failed to update status" ) ?;
176+ . context ( "failed to update scripthash status" ) ?;
177+
178+ notifications. extend (
179+ client
180+ . outpoints
181+ . par_iter_mut ( )
182+ . filter_map ( |( outpoint, status) | -> Option < Result < Value > > {
183+ match self . tracker . update_outpoint_status ( status, & self . daemon ) {
184+ Ok ( true ) => Some ( Ok ( notification (
185+ "blockchain.outpoint.subscribe" ,
186+ & [ json ! ( [ outpoint. txid, outpoint. vout] ) , json ! ( status) ] ,
187+ ) ) ) ,
188+ Ok ( false ) => None , // outpoint status is the same
189+ Err ( e) => Some ( Err ( e) ) ,
190+ }
191+ } )
192+ . collect :: < Result < Vec < Value > > > ( )
193+ . context ( "failed to update scripthash status" ) ?,
194+ ) ;
176195
177196 if let Some ( old_tip) = client. tip {
178197 let new_tip = self . tracker . chain ( ) . tip ( ) ;
@@ -300,6 +319,28 @@ impl Rpc {
300319 Ok ( json ! ( result) )
301320 }
302321
322+ fn outpoint_subscribe ( & self , client : & mut Client , ( txid, vout) : ( Txid , u32 ) ) -> Result < Value > {
323+ let outpoint = OutPoint :: new ( txid, vout) ;
324+ Ok ( match client. outpoints . entry ( outpoint) {
325+ Entry :: Occupied ( e) => json ! ( e. get( ) ) ,
326+ Entry :: Vacant ( e) => {
327+ let outpoint = OutPoint :: new ( txid, vout) ;
328+ let mut status = OutPointStatus :: new ( outpoint) ;
329+ self . tracker
330+ . update_outpoint_status ( & mut status, & self . daemon ) ?;
331+ json ! ( e. insert( status) )
332+ }
333+ } )
334+ }
335+
336+ fn outpoint_unsubscribe (
337+ & self ,
338+ client : & mut Client ,
339+ ( txid, vout) : ( Txid , u32 ) ,
340+ ) -> Result < Value > {
341+ Ok ( json ! ( client. outpoints. remove( & OutPoint :: new( txid, vout) ) ) )
342+ }
343+
303344 fn new_status ( & self , scripthash : ScriptHash ) -> Result < ScriptHashStatus > {
304345 let mut status = ScriptHashStatus :: new ( scripthash) ;
305346 self . tracker
@@ -434,6 +475,8 @@ impl Rpc {
434475 Call :: HeadersSubscribe => self . headers_subscribe ( client) ,
435476 Call :: MempoolFeeHistogram => self . get_fee_histogram ( ) ,
436477 Call :: PeersSubscribe => Ok ( json ! ( [ ] ) ) ,
478+ Call :: OutPointSubscribe ( args) => self . outpoint_subscribe ( client, args) ,
479+ Call :: OutPointUnsubscribe ( args) => self . outpoint_unsubscribe ( client, args) ,
437480 Call :: Ping => Ok ( Value :: Null ) ,
438481 Call :: RelayFee => self . relayfee ( ) ,
439482 Call :: ScriptHashGetBalance ( args) => self . scripthash_get_balance ( client, args) ,
@@ -467,19 +510,21 @@ enum Call {
467510 Banner ,
468511 BlockHeader ( ( usize , ) ) ,
469512 BlockHeaders ( ( usize , usize ) ) ,
470- TransactionBroadcast ( ( String , ) ) ,
471513 Donation ,
472514 EstimateFee ( ( u16 , ) ) ,
473515 Features ,
474516 HeadersSubscribe ,
475517 MempoolFeeHistogram ,
518+ OutPointSubscribe ( ( Txid , u32 ) ) , // TODO: support spk_hint
519+ OutPointUnsubscribe ( ( Txid , u32 ) ) ,
476520 PeersSubscribe ,
477521 Ping ,
478522 RelayFee ,
479523 ScriptHashGetBalance ( ( ScriptHash , ) ) ,
480524 ScriptHashGetHistory ( ( ScriptHash , ) ) ,
481525 ScriptHashListUnspent ( ( ScriptHash , ) ) ,
482526 ScriptHashSubscribe ( ( ScriptHash , ) ) ,
527+ TransactionBroadcast ( ( String , ) ) ,
483528 TransactionGet ( TxGetArgs ) ,
484529 TransactionGetMerkle ( ( Txid , usize ) ) ,
485530 Version ( ( String , Version ) ) ,
@@ -497,6 +542,8 @@ impl Call {
497542 "blockchain.scripthash.get_history" => Call :: ScriptHashGetHistory ( convert ( params) ?) ,
498543 "blockchain.scripthash.listunspent" => Call :: ScriptHashListUnspent ( convert ( params) ?) ,
499544 "blockchain.scripthash.subscribe" => Call :: ScriptHashSubscribe ( convert ( params) ?) ,
545+ "blockchain.outpoint.subscribe" => Call :: OutPointSubscribe ( convert ( params) ?) ,
546+ "blockchain.outpoint.unsubscribe" => Call :: OutPointUnsubscribe ( convert ( params) ?) ,
500547 "blockchain.transaction.broadcast" => Call :: TransactionBroadcast ( convert ( params) ?) ,
501548 "blockchain.transaction.get" => Call :: TransactionGet ( convert ( params) ?) ,
502549 "blockchain.transaction.get_merkle" => Call :: TransactionGetMerkle ( convert ( params) ?) ,
0 commit comments