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
|
||||
*verbose*.
|
||||
* :func:`blockchain.headers.subscribe` now has an optional parameter
|
||||
*raw*.
|
||||
|
||||
New methods
|
||||
-----------
|
||||
@ -75,3 +77,4 @@ Deprecated methods
|
||||
:func:`blockchain.scripthash.listunspent`.
|
||||
* :func:`blockchain.address.subscribe`. Switch to
|
||||
: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**
|
||||
|
||||
.. 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**
|
||||
|
||||
The coin-specific :ref:`deserialized header <deserialized header>`
|
||||
of the current block chain tip.
|
||||
The header of the current block chain tip. If *raw* is
|
||||
: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**
|
||||
|
||||
@ -257,13 +296,14 @@ Subscribe to receive block headers when a new block is found.
|
||||
|
||||
.. function:: blockchain.headers.subscribe(header)
|
||||
|
||||
* *header* The coin-specific :ref:`deserialized header
|
||||
<deserialized header>` of the new block chain tip.
|
||||
* *header*
|
||||
|
||||
See **Result** above.
|
||||
|
||||
.. 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 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
|
||||
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)
|
||||
|
||||
.. 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
|
||||
-------------------
|
||||
|
||||
@ -724,8 +757,8 @@ Return the address paid to by a UTXO.
|
||||
**Signature**
|
||||
|
||||
.. 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*
|
||||
|
||||
|
||||
@ -297,17 +297,21 @@ class Controller(ServerBase):
|
||||
for session in self.sessions:
|
||||
session.notify_peers(updates)
|
||||
|
||||
def electrum_header(self, height):
|
||||
def raw_header(self, 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)
|
||||
if n != 1:
|
||||
raise RPCError('height {:,d} out of range'.format(height))
|
||||
header = self.coin.electrum_header(header, height)
|
||||
self.header_cache[height] = 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):
|
||||
priority = self.session_priority(session)
|
||||
excess = max(0, priority - self.BANDS)
|
||||
|
||||
@ -108,6 +108,7 @@ class ElectrumX(SessionBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.subscribe_headers = False
|
||||
self.subscribe_headers_raw = False
|
||||
self.subscribe_height = False
|
||||
self.notified_height = None
|
||||
self.max_send = self.env.max_send
|
||||
@ -164,7 +165,7 @@ class ElectrumX(SessionBase):
|
||||
if height_changed:
|
||||
self.notified_height = height
|
||||
if self.subscribe_headers:
|
||||
args = (self.controller.electrum_header(height), )
|
||||
args = (self.subscribe_headers_result(height), )
|
||||
self.send_notification('blockchain.headers.subscribe', args)
|
||||
if self.subscribe_height:
|
||||
args = (height, )
|
||||
@ -180,12 +181,25 @@ class ElectrumX(SessionBase):
|
||||
'''Return the current flushed database 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.'''
|
||||
self.subscribe_headers = True
|
||||
height = self.height()
|
||||
self.notified_height = height
|
||||
return self.controller.electrum_header(height)
|
||||
self.subscribe_headers_raw = self.assert_boolean(raw)
|
||||
self.notified_height = self.height()
|
||||
return self.subscribe_headers_result(self.height())
|
||||
|
||||
def numblocks_subscribe(self):
|
||||
'''Subscribe to get height of new blocks.'''
|
||||
|
||||
Loading…
Reference in New Issue
Block a user