Add raw header subscriptions.
This commit is contained in:
parent
0654d96291
commit
47f65ffda2
@ -52,6 +52,8 @@ Changes
|
|||||||
|
|
||||||
* :func:`blockchain.transaction.get` now has an optional parameter
|
* :func:`blockchain.transaction.get` now has an optional parameter
|
||||||
*verbose*.
|
*verbose*.
|
||||||
|
* :func:`blockchain.headers.subscribe` now has an optional parameter
|
||||||
|
*raw*.
|
||||||
|
|
||||||
New methods
|
New methods
|
||||||
-----------
|
-----------
|
||||||
@ -75,3 +77,4 @@ Deprecated methods
|
|||||||
:func:`blockchain.scripthash.listunspent`.
|
:func:`blockchain.scripthash.listunspent`.
|
||||||
* :func:`blockchain.address.subscribe`. Switch to
|
* :func:`blockchain.address.subscribe`. Switch to
|
||||||
:func:`blockchain.scripthash.subscribe`.
|
:func:`blockchain.scripthash.subscribe`.
|
||||||
|
* :func:`blockchain.headers.subscribe` with *raw* other than :const:`True`.
|
||||||
|
|||||||
@ -243,12 +243,51 @@ Subscribe to receive block headers when a new block is found.
|
|||||||
|
|
||||||
**Signature**
|
**Signature**
|
||||||
|
|
||||||
.. function:: blockchain.headers.subscribe()
|
.. function:: blockchain.headers.subscribe(raw=False)
|
||||||
|
.. versionchanged:: 1.2
|
||||||
|
Optional *raw* parameter added.
|
||||||
|
|
||||||
|
* *raw*
|
||||||
|
|
||||||
|
:const:`False` or :const:`True`. The value :const:`False` is
|
||||||
|
deprecated.
|
||||||
|
|
||||||
**Result**
|
**Result**
|
||||||
|
|
||||||
The coin-specific :ref:`deserialized header <deserialized header>`
|
The header of the current block chain tip. If *raw* is
|
||||||
of the current block chain tip.
|
:const:`True` the result is a dictionary with two members:
|
||||||
|
|
||||||
|
* *hex*
|
||||||
|
|
||||||
|
The binary header as a hexadecimal string.
|
||||||
|
|
||||||
|
* *height*
|
||||||
|
|
||||||
|
The height of the header, an integer.
|
||||||
|
|
||||||
|
If *raw* is :const:`False` the result is the coin-specific
|
||||||
|
:ref:`deserialized header <deserialized header>`.
|
||||||
|
|
||||||
|
**Example Result**
|
||||||
|
|
||||||
|
With *raw* :const:`False`::
|
||||||
|
|
||||||
|
{
|
||||||
|
"bits": 402858285,
|
||||||
|
"block_height": 520481,
|
||||||
|
"merkle_root": "8e8e932eb858fd53cf09943d7efc9a8f674dc1363010ee64907a292d2fb0c25d",
|
||||||
|
"nonce": 3288656012,
|
||||||
|
"prev_block_hash": "000000000000000000b512b5d9fc7c5746587268547c04aa92383aaea0080289",
|
||||||
|
"timestamp": 1520495819,
|
||||||
|
"version": 536870912
|
||||||
|
}
|
||||||
|
|
||||||
|
With *raw* :const:`True`::
|
||||||
|
|
||||||
|
{
|
||||||
|
"height": 520481,
|
||||||
|
"hex": "00000020890208a0ae3a3892aa047c5468725846577cfcd9b512b50000000000000000005dc2b02f2d297a9064ee103036c14d678f9afc7e3d9409cf53fd58b82e938e8ecbeca05a2d2103188ce804c4"
|
||||||
|
}
|
||||||
|
|
||||||
**Notifications**
|
**Notifications**
|
||||||
|
|
||||||
@ -257,13 +296,14 @@ Subscribe to receive block headers when a new block is found.
|
|||||||
|
|
||||||
.. function:: blockchain.headers.subscribe(header)
|
.. function:: blockchain.headers.subscribe(header)
|
||||||
|
|
||||||
* *header* The coin-specific :ref:`deserialized header
|
* *header*
|
||||||
<deserialized header>` of the new block chain tip.
|
|
||||||
|
See **Result** above.
|
||||||
|
|
||||||
.. note:: should a new block arrive quickly, perhaps while the server
|
.. note:: should a new block arrive quickly, perhaps while the server
|
||||||
is still processing prior blocks, the server may only notify of the
|
is still processing prior blocks, the server may only notify of the
|
||||||
most recent chain tip. The protocol does not guarantee notification
|
most recent chain tip. The protocol does not guarantee notification
|
||||||
of all intermediate blocks.
|
of all intermediate block headers.
|
||||||
|
|
||||||
In a similar way the client must be prepared to handle chain
|
In a similar way the client must be prepared to handle chain
|
||||||
reorganisations. Should a re-org happen the new chain tip will not
|
reorganisations. Should a re-org happen the new chain tip will not
|
||||||
@ -294,13 +334,6 @@ Subscribe to receive the block height when a new block is found.
|
|||||||
|
|
||||||
.. function:: blockchain.numblocks.subscribe(height)
|
.. function:: blockchain.numblocks.subscribe(height)
|
||||||
|
|
||||||
.. note:: should a new block arrive quickly, perhaps while the server
|
|
||||||
is still processing prior blocks, the server may only notify of the
|
|
||||||
most recent height. The protocol does not guarantee notification of
|
|
||||||
all intermediate block heights. Similarly if a chain reorganization
|
|
||||||
occurs resulting in the same chain height, the client may or may not
|
|
||||||
receive a notification.
|
|
||||||
|
|
||||||
blockchain.relayfee
|
blockchain.relayfee
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
@ -724,8 +757,8 @@ Return the address paid to by a UTXO.
|
|||||||
**Signature**
|
**Signature**
|
||||||
|
|
||||||
.. function:: blockchain.utxo.get_address(tx_hash, index)
|
.. function:: blockchain.utxo.get_address(tx_hash, index)
|
||||||
*Optional in version 1.0.*
|
|
||||||
*Removed in version 1.1.*
|
*Optional in version 1.0. Removed in version 1.1.*
|
||||||
|
|
||||||
*tx_hash*
|
*tx_hash*
|
||||||
|
|
||||||
|
|||||||
@ -297,17 +297,21 @@ class Controller(ServerBase):
|
|||||||
for session in self.sessions:
|
for session in self.sessions:
|
||||||
session.notify_peers(updates)
|
session.notify_peers(updates)
|
||||||
|
|
||||||
def electrum_header(self, height):
|
def raw_header(self, height):
|
||||||
'''Return the binary header at the given height.'''
|
'''Return the binary header at the given height.'''
|
||||||
if height in self.header_cache:
|
|
||||||
return self.header_cache[height]
|
|
||||||
header, n = self.bp.read_headers(height, 1)
|
header, n = self.bp.read_headers(height, 1)
|
||||||
if n != 1:
|
if n != 1:
|
||||||
raise RPCError('height {:,d} out of range'.format(height))
|
raise RPCError('height {:,d} out of range'.format(height))
|
||||||
header = self.coin.electrum_header(header, height)
|
|
||||||
self.header_cache[height] = header
|
|
||||||
return header
|
return header
|
||||||
|
|
||||||
|
def electrum_header(self, height):
|
||||||
|
'''Return the deserialized header at the given height.'''
|
||||||
|
if height not in self.header_cache:
|
||||||
|
raw_header = self.raw_header(height)
|
||||||
|
self.header_cache[height] = self.coin.electrum_header(raw_header,
|
||||||
|
height)
|
||||||
|
return self.header_cache[height]
|
||||||
|
|
||||||
def session_delay(self, session):
|
def session_delay(self, session):
|
||||||
priority = self.session_priority(session)
|
priority = self.session_priority(session)
|
||||||
excess = max(0, priority - self.BANDS)
|
excess = max(0, priority - self.BANDS)
|
||||||
|
|||||||
@ -108,6 +108,7 @@ class ElectrumX(SessionBase):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.subscribe_headers = False
|
self.subscribe_headers = False
|
||||||
|
self.subscribe_headers_raw = False
|
||||||
self.subscribe_height = False
|
self.subscribe_height = False
|
||||||
self.notified_height = None
|
self.notified_height = None
|
||||||
self.max_send = self.env.max_send
|
self.max_send = self.env.max_send
|
||||||
@ -164,7 +165,7 @@ class ElectrumX(SessionBase):
|
|||||||
if height_changed:
|
if height_changed:
|
||||||
self.notified_height = height
|
self.notified_height = height
|
||||||
if self.subscribe_headers:
|
if self.subscribe_headers:
|
||||||
args = (self.controller.electrum_header(height), )
|
args = (self.subscribe_headers_result(height), )
|
||||||
self.send_notification('blockchain.headers.subscribe', args)
|
self.send_notification('blockchain.headers.subscribe', args)
|
||||||
if self.subscribe_height:
|
if self.subscribe_height:
|
||||||
args = (height, )
|
args = (height, )
|
||||||
@ -180,12 +181,25 @@ class ElectrumX(SessionBase):
|
|||||||
'''Return the current flushed database height.'''
|
'''Return the current flushed database height.'''
|
||||||
return self.bp.db_height
|
return self.bp.db_height
|
||||||
|
|
||||||
def headers_subscribe(self):
|
def assert_boolean(self, value):
|
||||||
|
'''Return param value it is boolean otherwise raise an RPCError.'''
|
||||||
|
if value in (False, True):
|
||||||
|
return value
|
||||||
|
raise RPCError('{} should be a boolean value'.format(value))
|
||||||
|
|
||||||
|
def subscribe_headers_result(self, height):
|
||||||
|
'''The result of a header subscription for the given height.'''
|
||||||
|
if self.subscribe_headers_raw:
|
||||||
|
raw_header = self.controller.raw_header(height)
|
||||||
|
return {'hex': raw_header.hex(), 'height': height}
|
||||||
|
return self.controller.electrum_header(height)
|
||||||
|
|
||||||
|
def headers_subscribe(self, raw=False):
|
||||||
'''Subscribe to get headers of new blocks.'''
|
'''Subscribe to get headers of new blocks.'''
|
||||||
self.subscribe_headers = True
|
self.subscribe_headers = True
|
||||||
height = self.height()
|
self.subscribe_headers_raw = self.assert_boolean(raw)
|
||||||
self.notified_height = height
|
self.notified_height = self.height()
|
||||||
return self.controller.electrum_header(height)
|
return self.subscribe_headers_result(self.height())
|
||||||
|
|
||||||
def numblocks_subscribe(self):
|
def numblocks_subscribe(self):
|
||||||
'''Subscribe to get height of new blocks.'''
|
'''Subscribe to get height of new blocks.'''
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user