X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=backends%2Fbitcoind%2Fblockchain_processor.py;h=1b8d92fd7202dac063c7d99cc23d743672fffc18;hb=83c23065055998912c661ff49edf93568c488689;hp=a1f382268dc5c1edfef64430372b1d58497a337f;hpb=b9d74456c47ed3a54c73185d449ff7f23cb6edf4;p=electrum-server.git diff --git a/backends/bitcoind/blockchain_processor.py b/backends/bitcoind/blockchain_processor.py index a1f3822..1b8d92f 100644 --- a/backends/bitcoind/blockchain_processor.py +++ b/backends/bitcoind/blockchain_processor.py @@ -9,7 +9,7 @@ import time import threading import traceback import urllib - +from ltc_scrypt import getPoWHash from backends.bitcoind import deserialize from processor import Processor, print_log from utils import * @@ -65,7 +65,7 @@ class BlockchainProcessor(Processor): self.bitcoind('getinfo') break except: - print_log('cannot contact bitcoind...') + print_log('cannot contact novacoind...') time.sleep(5) continue @@ -113,7 +113,7 @@ class BlockchainProcessor(Processor): try: respdata = urllib.urlopen(self.bitcoind_url, postdata).read() except: - print_log("error calling bitcoind") + print_log("error calling novacoind") traceback.print_exc(file=sys.stdout) self.shared.stop() @@ -135,8 +135,7 @@ class BlockchainProcessor(Processor): } def get_header(self, height): - block_hash = self.bitcoind('getblockhash', [height]) - b = self.bitcoind('getblock', [block_hash]) + b = self.bitcoind('getblockbynumber', [height]) return self.block2header(b) def init_headers(self, db_height): @@ -159,10 +158,17 @@ class BlockchainProcessor(Processor): try: while height < db_height: - height = height + 1 + height += 1 header = self.get_header(height) if height > 1: - assert prev_hash == header.get('prev_block_hash') + if prev_hash != header.get('prev_block_hash'): + # The prev_hash block is orphaned, go back + print_log("reorganizing, a block in file is orphaned:", prev_hash) + # Go to the parent of the orphaned block + height -= 2 + prev_hash = self.hash_header(self.read_header(height)) + continue + self.write_header(header, sync=False) prev_hash = self.hash_header(header) if (height % 1000) == 0: @@ -174,7 +180,7 @@ class BlockchainProcessor(Processor): self.flush_headers() def hash_header(self, header): - return rev_hex(Hash(header_to_string(header).decode('hex')).encode('hex')) + return rev_hex(getPoWHash(header_to_string(header).decode('hex')).encode('hex')) def read_header(self, block_height): if os.path.exists(self.headers_filename): @@ -256,7 +262,7 @@ class BlockchainProcessor(Processor): is_known = True except: print_log("error get_history") - self.shared.stop() + traceback.print_exc(file=sys.stdout) raise if hist: is_known = True @@ -302,8 +308,7 @@ class BlockchainProcessor(Processor): def get_merkle(self, tx_hash, height): - block_hash = self.bitcoind('getblockhash', [height]) - b = self.bitcoind('getblock', [block_hash]) + b = self.bitcoind('getblockbynumber', [height]) tx_list = b.get('tx') tx_pos = tx_list.index(tx_hash) @@ -359,21 +364,21 @@ class BlockchainProcessor(Processor): def deserialize_block(self, block): txlist = block.get('tx') + tx_hashes = [] # ordered txids txdict = {} # deserialized tx - is_coinbase = True - for raw_tx in txlist: + + for i, raw_tx in enumerate(txlist): tx_hash = hash_encode(Hash(raw_tx.decode('hex'))) vds = deserialize.BCDataStream() vds.write(raw_tx.decode('hex')) try: - tx = deserialize.parse_Transaction(vds, is_coinbase) + tx = deserialize.parse_Transaction(vds, i == 0) # first transaction is always coinbase except: print_log("ERROR: cannot parse", tx_hash) continue tx_hashes.append(tx_hash) txdict[tx_hash] = tx - is_coinbase = False return tx_hashes, txdict @@ -600,39 +605,6 @@ class BlockchainProcessor(Processor): elif result != '': self.push_response(session, {'id': message_id, 'result': result}) - - def getfullblock(self, block_hash): - block = self.bitcoind('getblock', [block_hash]) - - rawtxreq = [] - i = 0 - for txid in block['tx']: - rawtxreq.append({ - "method": "getrawtransaction", - "params": [txid], - "id": i, - }) - i += 1 - - postdata = dumps(rawtxreq) - try: - respdata = urllib.urlopen(self.bitcoind_url, postdata).read() - except: - print_log("bitcoind error (getfullblock)") - traceback.print_exc(file=sys.stdout) - self.shared.stop() - - r = loads(respdata) - rawtxdata = [] - for ir in r: - if ir['error'] is not None: - self.shared.stop() - print_log("Error: make sure you run bitcoind with txindex=1; use -reindex if needed.") - raise BaseException(ir['error']) - rawtxdata.append(ir['result']) - block['tx'] = rawtxdata - return block - def catch_up(self, sync=True): prev_root_hash = None @@ -648,14 +620,19 @@ class BlockchainProcessor(Processor): self.up_to_date = True break + # fixme: this is unsafe, if we revert when the undo info is not yet written + revert = (random.randint(1, 100) == 1) if self.test_reorgs else False + # not done.. self.up_to_date = False - next_block_hash = self.bitcoind('getblockhash', [self.storage.height + 1]) - next_block = self.getfullblock(next_block_hash) - self.mtime('daemon') + try: + next_block = self.bitcoind('getblockbynumber', [self.storage.height + 1, True]) + next_block_hash = next_block.get('hash') + except BaseException, e: + revert = True + next_block = next_block.get(self.storage.last_hash) - # fixme: this is unsafe, if we revert when the undo info is not yet written - revert = (random.randint(1, 100) == 1) if self.test_reorgs else False + self.mtime('daemon') if (next_block.get('previousblockhash') == self.storage.last_hash) and not revert: @@ -677,7 +654,7 @@ class BlockchainProcessor(Processor): else: # revert current block - block = self.getfullblock(self.storage.last_hash) + block = self.bitcoind('getblock', [self.storage.last_hash, True]) print_log("blockchain reorg", self.storage.height, block.get('previousblockhash'), self.storage.last_hash) self.import_block(block, self.storage.last_hash, self.storage.height, sync, revert=True) self.pop_header() @@ -755,7 +732,11 @@ class BlockchainProcessor(Processor): value = v[ x.get('prevout_n')] else: txi = (x.get('prevout_hash') + int_to_hex(x.get('prevout_n'), 4)).decode('hex') - value = self.storage.get_utxo_value(addr,txi) + try: + value = self.storage.get_utxo_value(addr,txi) + except: + print_log("utxo not in database; postponing mempool update") + return v = mpa.get(addr,0) v -= value