diff --git a/src/bitcoinrpc.py b/src/bitcoinrpc.py new file mode 100644 index 00000000..0d338717 --- /dev/null +++ b/src/bitcoinrpc.py @@ -0,0 +1,52 @@ +import ast +import hashlib +from json import dumps, loads +import random +import sys +import time +import threading +import urllib +from utils import logger +from processor import Processor + + +class BitcoinRPC(Processor): + + def __init__(self, config, shared): + Processor.__init__(self) + self.shared = shared + self.config = config + self.bitcoind_url = 'http://%s:%s@%s:%s/' % ( + config.get('bitcoind', 'bitcoind_user'), + config.get('bitcoind', 'bitcoind_password'), + config.get('bitcoind', 'bitcoind_host'), + config.get('bitcoind', 'bitcoind_port')) + + def wait_on_bitcoind(self): + self.shared.pause() + time.sleep(10) + if self.shared.stopped(): + # this will end the thread + raise BaseException() + + def call(self, method, params=[]): + postdata = dumps({"method": method, 'params': params, 'id': 'jsonrpc'}) + while True: + try: + connection = urllib.urlopen(self.bitcoind_url, postdata) + respdata = connection.read() + connection.close() + except: + print_log("cannot reach bitcoind...") + self.wait_on_bitcoind() + else: + r = loads(respdata) + if r['error'] is not None: + if r['error'].get('code') == -28: + print_log("bitcoind still warming up...") + self.wait_on_bitcoind() + continue + raise BaseException(r['error']) + break + return r.get('result') + diff --git a/src/blockchain_processor.py b/src/blockchain_processor.py index cfdd2b02..acd9c50a 100644 --- a/src/blockchain_processor.py +++ b/src/blockchain_processor.py @@ -10,6 +10,7 @@ import urllib import deserialize +from bitcoinrpc import BitcoinRPC from processor import Processor, print_log from utils import * from storage import Storage @@ -49,19 +50,17 @@ def __init__(self, config, shared): self.mempool_lock = threading.Lock() self.address_queue = Queue() - + self.bitcoind_url = 'http://%s:%s@%s:%s/' % ( + config.get('bitcoind', 'bitcoind_user'), + config.get('bitcoind', 'bitcoind_password'), + config.get('bitcoind', 'bitcoind_host'), + config.get('bitcoind', 'bitcoind_port')) try: self.test_reorgs = config.getboolean('leveldb', 'test_reorgs') # simulate random blockchain reorgs except: self.test_reorgs = False self.storage = Storage(config, shared, self.test_reorgs) - - self.bitcoind_url = 'http://%s:%s@%s:%s/' % ( - config.get('bitcoind', 'bitcoind_user'), - config.get('bitcoind', 'bitcoind_password'), - config.get('bitcoind', 'bitcoind_host'), - config.get('bitcoind', 'bitcoind_port')) - + self.bitcoind = BitcoinRPC(config, shared) self.sent_height = 0 self.sent_header = None @@ -78,7 +77,7 @@ def __init__(self, config, shared): def do_catch_up(self): - self.header = self.block2header(self.bitcoind('getblock', [self.storage.last_hash])) + self.header = self.block2header(self.bitcoind.call('getblock', [self.storage.last_hash])) self.header['utxo_root'] = self.storage.get_root_hash().encode('hex') self.catch_up(sync=False) if not self.shared.stopped(): @@ -122,13 +121,6 @@ def print_time(self, num_tx): msg += " (eta %s, %d blocks)" % (rt, remaining_blocks) print_log(msg) - def wait_on_bitcoind(self): - self.shared.pause() - time.sleep(10) - if self.shared.stopped(): - # this will end the thread - raise BaseException() - def bitcoind(self, method, params=[]): postdata = dumps({"method": method, 'params': params, 'id': 'jsonrpc'}) while True: @@ -163,8 +155,8 @@ def block2header(self, b): } def get_header(self, height): - block_hash = self.bitcoind('getblockhash', [height]) - b = self.bitcoind('getblock', [block_hash]) + block_hash = self.bitcoind.call('getblockhash', [height]) + b = self.bitcoind.call('getblock', [block_hash]) return self.block2header(b) def init_headers(self, db_height): @@ -265,7 +257,7 @@ def get_chunk(self, i): def get_mempool_transaction(self, txid): try: - raw_tx = self.bitcoind('getrawtransaction', [txid, 0]) + raw_tx = self.bitcoind.call('getrawtransaction', [txid, 0]) except: return None @@ -337,8 +329,8 @@ def get_merkle(self, tx_hash, height, cache_only): if cache_only: return -1 - block_hash = self.bitcoind('getblockhash', [height]) - b = self.bitcoind('getblock', [block_hash]) + block_hash = self.bitcoind.call('getblockhash', [height]) + b = self.bitcoind.call('getblock', [block_hash]) tx_list = b.get('tx') tx_pos = tx_list.index(tx_hash) @@ -555,7 +547,7 @@ def process(self, request, cache_only=False): elif method == 'blockchain.transaction.broadcast': try: - txo = self.bitcoind('sendrawtransaction', params) + txo = self.bitcoind.call('sendrawtransaction', params) print_log("sent tx:", txo) result = txo except BaseException, e: @@ -581,11 +573,11 @@ def process(self, request, cache_only=False): elif method == 'blockchain.transaction.get': tx_hash = params[0] - result = self.bitcoind('getrawtransaction', [tx_hash, 0]) + result = self.bitcoind.call('getrawtransaction', [tx_hash, 0]) elif method == 'blockchain.estimatefee': num = int(params[0]) - result = self.bitcoind('estimatefee', [num]) + result = self.bitcoind.call('estimatefee', [num]) else: raise BaseException("unknown method:%s" % method) @@ -597,7 +589,7 @@ def process(self, request, cache_only=False): def getfullblock(self, block_hash): - block = self.bitcoind('getblock', [block_hash]) + block = self.bitcoind.call('getblock', [block_hash]) rawtxreq = [] i = 0 @@ -643,9 +635,9 @@ def catch_up(self, sync=True): while not self.shared.stopped(): # are we done yet? - info = self.bitcoind('getinfo') + info = self.bitcoind.call('getinfo') self.bitcoind_height = info.get('blocks') - bitcoind_block_hash = self.bitcoind('getblockhash', [self.bitcoind_height]) + bitcoind_block_hash = self.bitcoind.call('getblockhash', [self.bitcoind_height]) if self.storage.last_hash == bitcoind_block_hash: self.up_to_date = True break @@ -657,7 +649,7 @@ def catch_up(self, sync=True): # not done.. self.up_to_date = False try: - next_block_hash = self.bitcoind('getblockhash', [self.storage.height + 1]) + next_block_hash = self.bitcoind.call('getblockhash', [self.storage.height + 1]) except BaseException, e: revert = True @@ -694,7 +686,7 @@ def catch_up(self, sync=True): # print time self.print_time(n) - self.header = self.block2header(self.bitcoind('getblock', [self.storage.last_hash])) + self.header = self.block2header(self.bitcoind.call('getblock', [self.storage.last_hash])) self.header['utxo_root'] = self.storage.get_root_hash().encode('hex') if self.shared.stopped(): @@ -704,7 +696,7 @@ def catch_up(self, sync=True): def memorypool_update(self): t0 = time.time() - mempool_hashes = set(self.bitcoind('getrawmempool')) + mempool_hashes = set(self.bitcoind.call('getrawmempool')) touched_addresses = set([]) # get new transactions diff --git a/src/server_processor.py b/src/server_processor.py index a406b36a..905aa7fa 100644 --- a/src/server_processor.py +++ b/src/server_processor.py @@ -10,7 +10,7 @@ from version import VERSION from utils import logger from ircthread import IrcThread - +from bitcoinrpc import BitcoinRPC class ServerProcessor(Processor): @@ -19,6 +19,7 @@ def __init__(self, config, shared): Processor.__init__(self) self.daemon = True self.config = config + self.bitcoind = BitcoinRPC(config) self.shared = shared self.irc_queue = Queue.Queue() self.peers = {} @@ -61,6 +62,19 @@ def process(self, request): if method == 'server.banner': result = self.config.get('server', 'banner').replace('\\n', '\n') + elif method == 'server.core.version': + info = self.bitcoind.call('getnetworkinfo') + info.get('version') + elif method == 'server.core.subversion': + info = self.bitcoind.call('getnetworkinfo') + info.get('subversion') + result = self.config.get('server', 'subversion') + elif method == 'server.core.protocolversion': + info = self.bitcoind.call('getnetworkinfo') + info.get('protocolversion') + elif method == 'server.core.relayfee': + info = self.bitcoind.call('getnetworkinfo') + info.get('relayfee') elif method == 'server.donation_address': result = self.config.get('server', 'donation_address')