@@ -1285,13 +1285,13 @@ async def _notify_inner(
12851285 method = 'blockchain.outpoint.subscribe'
12861286 txo_to_status = {}
12871287 for prevout in touched_outpoints :
1288- txo_to_status [prevout ] = await self .txoutpoint_status (* prevout )
1288+ txo_to_status [prevout ] = await self .txoutpoint_status_for_notif (* prevout )
12891289
12901290 # Check mempool TXOs - the status is a function of the confirmed state of
12911291 # other transactions. (this is to detect if height changed from -1 to 0)
12921292 mempool_txoutpoint_statuses = self .mempool_txoutpoint_statuses .copy ()
12931293 for prevout , old_status in mempool_txoutpoint_statuses .items ():
1294- status = await self .txoutpoint_status (* prevout )
1294+ status = await self .txoutpoint_status_for_notif (* prevout )
12951295 if status != old_status :
12961296 txo_to_status [prevout ] = status
12971297
@@ -1332,6 +1332,7 @@ async def address_status(self, hashX: bytes) -> Optional[str]:
13321332 '''Returns an address status.
13331333
13341334 Status is a hex string, but must be None if there is no history.
1335+ Side-effect: updates client-last-seen status, used by notifications.
13351336 '''
13361337 # Note both confirmed history and mempool history are ordered
13371338 # For mempool, height is -1 if it has unconfirmed inputs, otherwise 0
@@ -1353,6 +1354,7 @@ async def address_status(self, hashX: bytes) -> Optional[str]:
13531354 else :
13541355 status = None
13551356
1357+ # update status last sent to client
13561358 if mempool :
13571359 self .mempool_hashX_statuses [hashX ] = status
13581360 else :
@@ -1369,7 +1371,7 @@ async def subscription_address_status(self, hashX):
13691371 self .unsubscribe_hashX (hashX )
13701372 return None
13711373
1372- async def txoutpoint_status (self , prev_txhash : bytes , txout_idx : int ) -> Dict [str , Any ]:
1374+ async def _calc_txoutpoint_status (self , prev_txhash : bytes , txout_idx : int ) -> Dict [str , Any ]:
13731375 self .bump_cost (0.2 )
13741376 spend_status = await self .db .spender_for_txo (prev_txhash , txout_idx )
13751377 if spend_status .spender_height is not None :
@@ -1393,14 +1395,20 @@ async def txoutpoint_status(self, prev_txhash: bytes, txout_idx: int) -> Dict[st
13931395 assert spend_status .spender_height is not None
13941396 status ['spender_txhash' ] = hash_to_hex_str (spend_status .spender_txhash )
13951397 status ['spender_height' ] = spend_status .spender_height
1398+ return status
13961399
1400+ async def txoutpoint_status_for_notif (self , prev_txhash : bytes , txout_idx : int ) -> Dict [str , Any ]:
1401+ """Side-effect: updates client-last-seen status, used by notifications."""
1402+ status = await self ._calc_txoutpoint_status (prev_txhash = prev_txhash , txout_idx = txout_idx )
1403+ # update status last sent to client
13971404 prevout = (prev_txhash , txout_idx )
1398- if ((spend_status .prev_height is not None and spend_status .prev_height <= 0 )
1399- or (spend_status .spender_height is not None and spend_status .spender_height <= 0 )):
1405+ prev_height = status .get ('height' ) # type: Optional[int]
1406+ spender_height = status .get ('spender_height' ) # type: Optional[int]
1407+ if ((prev_height is not None and prev_height <= 0 )
1408+ or (spender_height is not None and spender_height <= 0 )):
14001409 self .mempool_txoutpoint_statuses [prevout ] = status
14011410 else :
14021411 self .mempool_txoutpoint_statuses .pop (prevout , None )
1403-
14041412 return status
14051413
14061414 async def hashX_listunspent (self , hashX ):
@@ -1506,6 +1514,20 @@ def scriptpubkey_unsubscribe(self, spk: str):
15061514 scripthash = spk_to_scripthash (spk )
15071515 return self .scripthash_unsubscribe (scripthash )
15081516
1517+ async def txoutpoint_get_status (self , tx_hash , txout_idx , spk_hint = None ):
1518+ '''Return the status of an outpoint, without subscribing.
1519+
1520+ spk_hint: scriptPubKey corresponding to the outpoint. Might be used by
1521+ other servers, but we don't need and hence ignore it.
1522+ '''
1523+ tx_hash = assert_tx_hash (tx_hash )
1524+ txout_idx = non_negative_integer (txout_idx )
1525+ if spk_hint is not None :
1526+ assert_hex_str (spk_hint )
1527+ # calc status (but do not side-effect client-last-seen status)
1528+ spend_status = await self ._calc_txoutpoint_status (tx_hash , txout_idx )
1529+ return spend_status
1530+
15091531 async def txoutpoint_subscribe (self , tx_hash , txout_idx , spk_hint = None ):
15101532 '''Subscribe to an outpoint.
15111533
@@ -1516,7 +1538,8 @@ async def txoutpoint_subscribe(self, tx_hash, txout_idx, spk_hint=None):
15161538 txout_idx = non_negative_integer (txout_idx )
15171539 if spk_hint is not None :
15181540 assert_hex_str (spk_hint )
1519- spend_status = await self .txoutpoint_status (tx_hash , txout_idx )
1541+ # calc status, update client-last-seen status, and sub to outpoint
1542+ spend_status = await self .txoutpoint_status_for_notif (tx_hash , txout_idx )
15201543 self .txoutpoint_subs .add ((tx_hash , txout_idx ))
15211544 return spend_status
15221545
@@ -2026,6 +2049,7 @@ def set_request_handlers(self, ptuple):
20262049 # experimental:
20272050 if ptuple >= (1 , 7 ):
20282051 handlers ['blockchain.outpoint.subscribe' ] = self .txoutpoint_subscribe
2052+ handlers ['blockchain.outpoint.get_status' ] = self .txoutpoint_get_status
20292053 handlers ['blockchain.outpoint.unsubscribe' ] = self .txoutpoint_unsubscribe
20302054 handlers ['blockchain.scriptpubkey.get_balance' ] = self .scriptpubkey_get_balance
20312055 handlers ['blockchain.scriptpubkey.get_history' ] = self .scriptpubkey_get_history
0 commit comments