Handle a couple more requests.
This commit is contained in:
parent
1084060493
commit
6ad8c16c47
@ -30,13 +30,16 @@ def hmac_sha512(key, msg):
|
|||||||
def hash160(x):
|
def hash160(x):
|
||||||
return ripemd160(sha256(x))
|
return ripemd160(sha256(x))
|
||||||
|
|
||||||
|
|
||||||
def hash_to_str(x):
|
def hash_to_str(x):
|
||||||
'''Converts a big-endian binary hash to a little-endian hex string, as
|
'''Converts a big-endian binary hash to a little-endian hex string, as
|
||||||
shown in block explorers, etc.
|
shown in block explorers, etc.
|
||||||
'''
|
'''
|
||||||
return bytes(reversed(x)).hex()
|
return bytes(reversed(x)).hex()
|
||||||
|
|
||||||
|
def hex_str_to_hash(x):
|
||||||
|
'''Converts a little-endian hex string as shown to a big-endian binary
|
||||||
|
hash.'''
|
||||||
|
return bytes(reversed(bytes.fromhex(x)))
|
||||||
|
|
||||||
class InvalidBase58String(Exception):
|
class InvalidBase58String(Exception):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -11,7 +11,8 @@ import aiohttp
|
|||||||
|
|
||||||
from server.db import DB
|
from server.db import DB
|
||||||
from server.protocol import ElectrumX, LocalRPC
|
from server.protocol import ElectrumX, LocalRPC
|
||||||
from lib.hash import sha256, hash_to_str, Base58
|
from lib.hash import (sha256, double_sha256, hash_to_str,
|
||||||
|
Base58, hex_str_to_hash)
|
||||||
from lib.util import LoggedClass
|
from lib.util import LoggedClass
|
||||||
|
|
||||||
|
|
||||||
@ -116,6 +117,29 @@ class Controller(LoggedClass):
|
|||||||
|
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
async def get_merkle(self, tx_hash, height):
|
||||||
|
'''tx_hash is a hex string.'''
|
||||||
|
daemon_send = self.block_cache.send_single
|
||||||
|
block_hash = await daemon_send('getblockhash', (height,))
|
||||||
|
block = await daemon_send('getblock', (block_hash, True))
|
||||||
|
tx_hashes = block['tx']
|
||||||
|
# This will throw if the tx_hash is bad
|
||||||
|
pos = tx_hashes.index(tx_hash)
|
||||||
|
|
||||||
|
idx = pos
|
||||||
|
hashes = [hex_str_to_hash(txh) for txh in tx_hashes]
|
||||||
|
merkle_branch = []
|
||||||
|
while len(hashes) > 1:
|
||||||
|
if len(hashes) & 1:
|
||||||
|
hashes.append(hashes[-1])
|
||||||
|
idx = idx - 1 if (idx & 1) else idx + 1
|
||||||
|
merkle_branch.append(hash_to_str(hashes[idx]))
|
||||||
|
idx //= 2
|
||||||
|
hashes = [double_sha256(hashes[n] + hashes[n + 1])
|
||||||
|
for n in range(0, len(hashes), 2)]
|
||||||
|
|
||||||
|
return {"block_height": height, "merkle": merkle_branch, "pos": pos}
|
||||||
|
|
||||||
def get_peers(self):
|
def get_peers(self):
|
||||||
'''Returns a dictionary of IRC nick to (ip, host, ports) tuples, one
|
'''Returns a dictionary of IRC nick to (ip, host, ports) tuples, one
|
||||||
per peer.'''
|
per peer.'''
|
||||||
@ -127,6 +151,9 @@ class BlockCache(LoggedClass):
|
|||||||
block chain reorganisations.
|
block chain reorganisations.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
class DaemonError:
|
||||||
|
pass
|
||||||
|
|
||||||
def __init__(self, env, db):
|
def __init__(self, env, db):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.db = db
|
self.db = db
|
||||||
@ -165,7 +192,10 @@ class BlockCache(LoggedClass):
|
|||||||
'''Loops forever polling for more blocks.'''
|
'''Loops forever polling for more blocks.'''
|
||||||
self.logger.info('prefetching blocks...')
|
self.logger.info('prefetching blocks...')
|
||||||
while True:
|
while True:
|
||||||
await self.maybe_prefetch()
|
try:
|
||||||
|
await self.maybe_prefetch()
|
||||||
|
except self.DaemonError:
|
||||||
|
pass
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
def cache_used(self):
|
def cache_used(self):
|
||||||
@ -246,7 +276,7 @@ class BlockCache(LoggedClass):
|
|||||||
secs = 30
|
secs = 30
|
||||||
else:
|
else:
|
||||||
msg = 'daemon errors: {}'.format(errs)
|
msg = 'daemon errors: {}'.format(errs)
|
||||||
secs = 3
|
raise self.DaemonError(msg)
|
||||||
|
|
||||||
self.logger.error('{}. Sleeping {:d}s and trying again...'
|
self.logger.error('{}. Sleeping {:d}s and trying again...'
|
||||||
.format(msg, secs))
|
.format(msg, secs))
|
||||||
|
|||||||
@ -148,6 +148,20 @@ class ElectrumX(JSONRPC):
|
|||||||
net_info = await self.BC.send_single('getnetworkinfo')
|
net_info = await self.BC.send_single('getnetworkinfo')
|
||||||
return net_info['relayfee']
|
return net_info['relayfee']
|
||||||
|
|
||||||
|
async def handle_blockchain_transaction_get(self, params):
|
||||||
|
if len(params) != 1:
|
||||||
|
raise Error(Error.BAD_REQUEST,
|
||||||
|
'params should contain a transaction hash')
|
||||||
|
tx_hash = params[0]
|
||||||
|
return await self.BC.send_single('getrawtransaction', (tx_hash, 0))
|
||||||
|
|
||||||
|
async def handle_blockchain_transaction_get_merkle(self, params):
|
||||||
|
if len(params) != 2:
|
||||||
|
raise Error(Error.BAD_REQUEST,
|
||||||
|
'params should contain a transaction hash and height')
|
||||||
|
tx_hash, height = params
|
||||||
|
return await self.controller.get_merkle(tx_hash, height)
|
||||||
|
|
||||||
async def handle_server_banner(self, params):
|
async def handle_server_banner(self, params):
|
||||||
'''Return the server banner.'''
|
'''Return the server banner.'''
|
||||||
banner = 'Welcome to Electrum!'
|
banner = 'Welcome to Electrum!'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user