X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=backends%2Fabe%2F__init__.py;h=13cd73d989bf00d1fa6f6628943d2207db7bbd20;hb=bfba96e76cc02dac0c401d36153d4fd73ddcf9f3;hp=745493caa817b7c9bc51328c415a88b98dac4f8a;hpb=d659a2f2020b052c8c33f4903091f2d0e64398f2;p=electrum-server.git diff --git a/backends/abe/__init__.py b/backends/abe/__init__.py index 745493c..13cd73d 100644 --- a/backends/abe/__init__.py +++ b/backends/abe/__init__.py @@ -48,6 +48,7 @@ class AbeStore(Datastore_class): self.dblock = thread.allocate_lock() self.last_tx_id = 0 + self.known_mempool_hashes = [] def import_tx(self, tx, is_coinbase): @@ -380,37 +381,128 @@ class AbeStore(Datastore_class): return status + def get_block_header(self, block_height): + out = self.safe_sql(""" + SELECT + block_hash, + block_version, + block_hashMerkleRoot, + block_nTime, + block_nBits, + block_nNonce, + block_height, + prev_block_hash, + block_id + FROM chain_summary + WHERE block_height = %d AND in_longest = 1"""%block_height) + + if not out: raise BaseException("block not found") + row = out[0] + (block_hash, block_version, hashMerkleRoot, nTime, nBits, nNonce, height,prev_block_hash, block_id) \ + = ( self.hashout_hex(row[0]), int(row[1]), self.hashout_hex(row[2]), int(row[3]), int(row[4]), int(row[5]), int(row[6]), self.hashout_hex(row[7]), int(row[8]) ) + + out = {"block_height":block_height, "version":block_version, "prev_block_hash":prev_block_hash, + "merkle_root":hashMerkleRoot, "timestamp":nTime, "bits":nBits, "nonce":nNonce} + return out + + + def get_tx_merkle(self, tx_hash): + + out = self.safe_sql(""" + SELECT block_tx.block_id FROM tx + JOIN block_tx on tx.tx_id = block_tx.tx_id + JOIN chain_summary on chain_summary.block_id = block_tx.block_id + WHERE tx_hash='%s' AND in_longest = 1"""%tx_hash) + block_id = out[0] + + # get block height + out = self.safe_sql("SELECT block_height FROM chain_summary WHERE block_id = %d AND in_longest = 1"%block_id) + + if not out: raise BaseException("block not found") + block_height = int(out[0][0]) + + merkle = [] + # list all tx in block + for row in self.safe_sql(""" + SELECT DISTINCT tx_id, tx_pos, tx_hash + FROM txin_detail + WHERE block_id = ? + ORDER BY tx_pos""", (block_id,)): + tx_id, tx_pos, tx_h = row + merkle.append(tx_h) + + # find subset. + # TODO: do not compute this on client request, better store the hash tree of each block in a database... + import hashlib + encode = lambda x: x[::-1].encode('hex') + decode = lambda x: x.decode('hex')[::-1] + Hash = lambda x: hashlib.sha256(hashlib.sha256(x).digest()).digest() + + merkle = map(decode, merkle) + target_hash = decode(tx_hash) + + s = [] + while len(merkle) != 1: + if len(merkle)%2: merkle.append( merkle[-1] ) + n = [] + while merkle: + if merkle[0] == target_hash: + s.append( "L" + encode(merkle[1])) + n.append( target_hash ) + elif merkle[1] == target_hash: + s.append( "R" + encode(merkle[0])) + n.append( target_hash) + else: + n.append( Hash( merkle[0] + merkle[1] ) ) + merkle = merkle[2:] + merkle = n + + # send result + return {"block_height":block_height,"merkle":s} + + + def memorypool_update(store): ds = BCDataStream.BCDataStream() - postdata = dumps({"method": 'getmemorypool', 'params': [], 'id':'jsonrpc'}) - + postdata = dumps({"method": 'getrawmempool', 'params': [], 'id':'jsonrpc'}) respdata = urllib.urlopen(store.bitcoind_url, postdata).read() r = loads(respdata) if r['error'] != None: + print r['error'] return - v = r['result'].get('transactions') - for hextx in v: + mempool_hashes = r.get('result') + for tx_hash in mempool_hashes: + + if tx_hash in store.known_mempool_hashes: continue + store.known_mempool_hashes.append(tx_hash) + + postdata = dumps({"method": 'getrawtransaction', 'params': [tx_hash], 'id':'jsonrpc'}) + respdata = urllib.urlopen(store.bitcoind_url, postdata).read() + r = loads(respdata) + if r['error'] != None: + continue + hextx = r.get('result') ds.clear() ds.write(hextx.decode('hex')) tx = deserialize.parse_Transaction(ds) tx['hash'] = util.double_sha256(tx['tx']) - tx_hash = store.hashin(tx['hash']) - + if store.tx_find_id_and_value(tx): pass else: tx_id = store.import_tx(tx, False) store.update_tx_cache(tx_id) #print tx_hash - + store.commit() + store.known_mempool_hashes = mempool_hashes def send_tx(self,tx): - postdata = dumps({"method": 'importtransaction', 'params': [tx], 'id':'jsonrpc'}) + postdata = dumps({"method": 'sendrawtransaction', 'params': [tx], 'id':'jsonrpc'}) respdata = urllib.urlopen(self.bitcoind_url, postdata).read() r = loads(respdata) if r['error'] != None: @@ -489,11 +581,27 @@ class BlockchainProcessor(Processor): error = str(e) + ': ' + address print "error:", error + elif method == 'blockchain.block.get_header': + try: + height = params[0] + result = self.store.get_block_header( height ) + except BaseException, e: + error = str(e) + ': %d'% height + print "error:", error + elif method == 'blockchain.transaction.broadcast': txo = self.store.send_tx(params[0]) print "sent tx:", txo result = txo + elif method == 'blockchain.transaction.get_merkle': + try: + tx_hash = params[0] + result = self.store.get_tx_merkle(tx_hash ) + except BaseException, e: + error = str(e) + ': ' + tx_hash + print "error:", error + else: error = "unknown method:%s"%method