Browse Source

new protocol method: blockchain.transaction.id_from_pos (#524)

patch-2
ghost43 7 years ago
committed by Neil
parent
commit
c7f3f7ac6d
  1. 5
      docs/protocol-changes.rst
  2. 64
      docs/protocol-methods.rst
  3. 38
      electrumx/server/session.py

5
docs/protocol-changes.rst

@ -133,6 +133,11 @@ Changes
* Optional *cp_height* argument added to * Optional *cp_height* argument added to
:func:`blockchain.block.header` and :func:`blockchain.block.headers` :func:`blockchain.block.header` and :func:`blockchain.block.headers`
New methods
-----------
* :func:`blockchain.transaction.id_from_pos`
Removed methods Removed methods
--------------- ---------------

64
docs/protocol-methods.rst

@ -671,6 +671,70 @@ and height.
"pos": 710 "pos": 710
} }
blockchain.transaction.id_from_pos
==================================
Return a transaction hash and optionally a merkle proof,
given a block height and a position in the block.
**Signature**
.. function:: blockchain.transaction.id_from_pos(height, tx_pos, merkle=False)
.. versionadded:: 1.4
*height*
A block height in the main chain, an integer.
*tx_pos*
A zero-based index of the transaction in the given block, an integer.
*merkle*
Whether a merkle proof should also be returned, a boolean.
**Result**
If *merkle* is :const:`False`, the transaction hash as a hexadecimal string.
If :const:`True`, a dictionary with the following keys:
* *tx_hash*
The transaction hash as a hexadecimal string.
* *merkle*
A list of transaction hashes the current hash is paired with,
recursively, in order to trace up to obtain merkle root of the
block, deepest pairing first.
**Example Results**
When *merkle* is :const:`False`::
"fc12dfcb4723715a456c6984e298e00c479706067da81be969e8085544b0ba08"
When *merkle* is :const:`True`::
{
"tx_hash": "fc12dfcb4723715a456c6984e298e00c479706067da81be969e8085544b0ba08",
"merkle":
[
"928c4275dfd6270349e76aa5a49b355eefeb9e31ffbe95dd75fed81d219a23f8",
"5f35bfb3d5ef2ba19e105dcd976928e675945b9b82d98a93d71cbad0e714d04e",
"f136bcffeeed8844d54f90fc3ce79ce827cd8f019cf1d18470f72e4680f99207",
"6539b8ab33cedf98c31d4e5addfe40995ff96c4ea5257620dfbf86b34ce005ab",
"7ecc598708186b0b5bd10404f5aeb8a1a35fd91d1febbb2aac2d018954885b1e",
"a263aae6c470b9cde03b90675998ff6116f3132163911fafbeeb7843095d3b41",
"c203983baffe527edb4da836bc46e3607b9a36fa2c6cb60c1027f0964d971b29",
"306d89790df94c4632d652d142207f53746729a7809caa1c294b895a76ce34a9",
"c0b4eff21eea5e7974fe93c62b5aab51ed8f8d3adad4583c7a84a98f9e428f04",
"f0bd9d2d4c4cf00a1dd7ab3b48bbbb4218477313591284dcc2d7ca0aaa444e8d",
"503d3349648b985c1b571f59059e4da55a57b0163b08cc50379d73be80c4c8f3"
]
}
mempool.get_fee_histogram mempool.get_fee_histogram
========================= =========================

38
electrumx/server/session.py

@ -1068,6 +1068,17 @@ class ElectrumX(SessionBase):
block = await self.daemon_request('deserialised_block', block_hash) block = await self.daemon_request('deserialised_block', block_hash)
return block_hash, block['tx'] return block_hash, block['tx']
def _get_merkle_branch(self, tx_hashes, tx_pos):
'''Return a merkle branch to a transaction.
tx_hashes: ordered list of hex strings of tx hashes in a block
tx_pos: index of transaction in tx_hashes to create branch for
'''
hashes = [hex_str_to_hash(hash) for hash in tx_hashes]
branch, root = self.bp.merkle.branch_and_root(hashes, tx_pos)
branch = [hash_to_hex_str(hash) for hash in branch]
return branch
async def transaction_merkle(self, tx_hash, height): async def transaction_merkle(self, tx_hash, height):
'''Return the markle tree to a confirmed transaction given its hash '''Return the markle tree to a confirmed transaction given its hash
and height. and height.
@ -1082,12 +1093,29 @@ class ElectrumX(SessionBase):
except ValueError: except ValueError:
raise RPCError(BAD_REQUEST, f'tx hash {tx_hash} not in ' raise RPCError(BAD_REQUEST, f'tx hash {tx_hash} not in '
f'block {block_hash} at height {height:,d}') f'block {block_hash} at height {height:,d}')
branch = self._get_merkle_branch(tx_hashes, pos)
return {"block_height": height, "merkle": branch, "pos": pos}
hashes = [hex_str_to_hash(hash) for hash in tx_hashes] async def transaction_id_from_pos(self, height, tx_pos, merkle=False):
branch, root = self.bp.merkle.branch_and_root(hashes, pos) '''Return the txid and optionally a merkle proof, given
branch = [hash_to_hex_str(hash) for hash in branch] a block height and position in the block.
'''
tx_pos = non_negative_integer(tx_pos)
if merkle not in (True, False):
raise RPCError(BAD_REQUEST, f'"merkle" must be a boolean')
return {"block_height": height, "merkle": branch, "pos": pos} block_hash, tx_hashes = await self.block_hash_and_tx_hashes(height)
try:
tx_hash = tx_hashes[tx_pos]
except IndexError:
raise RPCError(BAD_REQUEST, f'no tx at position {tx_pos:,d} in '
f'block {block_hash} at height {height:,d}')
branch = self._get_merkle_branch(tx_hashes, tx_pos)
if merkle:
return {"tx_hash": tx_hash, "merkle": branch}
else:
return tx_hash
def set_protocol_handlers(self, ptuple): def set_protocol_handlers(self, ptuple):
self.protocol_tuple = ptuple self.protocol_tuple = ptuple
@ -1126,6 +1154,8 @@ class ElectrumX(SessionBase):
'blockchain.block.header': self.block_header, 'blockchain.block.header': self.block_header,
'blockchain.block.headers': self.block_headers, 'blockchain.block.headers': self.block_headers,
'blockchain.headers.subscribe': self.headers_subscribe, 'blockchain.headers.subscribe': self.headers_subscribe,
'blockchain.transaction.id_from_pos':
self.transaction_id_from_pos,
}) })
elif ptuple >= (1, 3): elif ptuple >= (1, 3):
handlers.update({ handlers.update({

Loading…
Cancel
Save