Browse Source

Handle a couple more requests.

master
Neil Booth 8 years ago
parent
commit
6ad8c16c47
  1. 5
      lib/hash.py
  2. 36
      server/controller.py
  3. 14
      server/protocol.py

5
lib/hash.py

@ -30,13 +30,16 @@ def hmac_sha512(key, msg):
def hash160(x):
return ripemd160(sha256(x))
def hash_to_str(x):
'''Converts a big-endian binary hash to a little-endian hex string, as
shown in block explorers, etc.
'''
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):
pass

36
server/controller.py

@ -11,7 +11,8 @@ import aiohttp
from server.db import DB
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
@ -116,6 +117,29 @@ class Controller(LoggedClass):
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):
'''Returns a dictionary of IRC nick to (ip, host, ports) tuples, one
per peer.'''
@ -127,6 +151,9 @@ class BlockCache(LoggedClass):
block chain reorganisations.
'''
class DaemonError:
pass
def __init__(self, env, db):
super().__init__()
self.db = db
@ -165,7 +192,10 @@ class BlockCache(LoggedClass):
'''Loops forever polling for more blocks.'''
self.logger.info('prefetching blocks...')
while True:
await self.maybe_prefetch()
try:
await self.maybe_prefetch()
except self.DaemonError:
pass
await asyncio.sleep(2)
def cache_used(self):
@ -246,7 +276,7 @@ class BlockCache(LoggedClass):
secs = 30
else:
msg = 'daemon errors: {}'.format(errs)
secs = 3
raise self.DaemonError(msg)
self.logger.error('{}. Sleeping {:d}s and trying again...'
.format(msg, secs))

14
server/protocol.py

@ -148,6 +148,20 @@ class ElectrumX(JSONRPC):
net_info = await self.BC.send_single('getnetworkinfo')
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):
'''Return the server banner.'''
banner = 'Welcome to Electrum!'

Loading…
Cancel
Save