perform the operation described here, you are expected to fix the
issue so you can continue following this howto.
-**Software.** A recent Linux distribution with the following software
+**Software.** A recent Linux 64-bit distribution with the following software
installed: `python`, `easy_install`, `git`, standard C/C++
build chain. You will need root access in order to install other software or
Python libraries.
self.dblock = threading.Lock()
try:
- self.db = leveldb.LevelDB(self.dbpath)
+ self.db = leveldb.LevelDB(self.dbpath, paranoid_checks=True)
except:
traceback.print_exc(file=sys.stdout)
self.shared.stop()
config.get('bitcoind', 'host'),
config.get('bitcoind', 'port'))
+ while True:
+ try:
+ self.bitcoind('getinfo')
+ break
+ except:
+ print_log('cannot contact bitcoind...')
+ time.sleep(5)
+ continue
+
self.height = 0
self.is_test = False
self.sent_height = 0
if not tx:
continue
+ mpa = self.mempool_addresses.get(tx_hash, [])
for x in tx.get('inputs'):
- txi = (x.get('prevout_hash') + int_to_hex(x.get('prevout_n'), 4)).decode('hex')
- try:
- addr = self.db.Get(txi)
- except:
- tx_prev = self.get_mempool_transaction(x.get('prevout_hash'))
- try:
- addr = tx_prev['outputs'][x.get('prevout_n')]['address']
- if not addr: continue
- except:
- continue
- l = self.mempool_addresses.get(tx_hash, [])
- if addr not in l:
- l.append(addr)
- self.mempool_addresses[tx_hash] = l
- if addr not in touched_addresses: touched_addresses.append(addr)
+ # we assume that the input address can be parsed by deserialize(); this is true for Electrum transactions
+ addr = x.get('address')
+ if addr and addr not in mpa:
+ mpa.append(addr)
+ touched_addresses.append(addr)
for x in tx.get('outputs'):
addr = x.get('address')
- l = self.mempool_addresses.get(tx_hash, [])
- if addr not in l:
- l.append(addr)
- self.mempool_addresses[tx_hash] = l
- if addr not in touched_addresses: touched_addresses.append(addr)
+ if addr and addr not in mpa:
+ mpa.append(addr)
+ touched_addresses.append(addr)
+ self.mempool_addresses[tx_hash] = mpa
self.mempool_hashes.append(tx_hash)
# remove older entries from mempool_hashes
if tx_hash not in self.mempool_hashes:
self.mempool_addresses.pop(tx_hash)
for addr in addresses:
- if addr not in touched_addresses: touched_addresses.append(addr)
+ touched_addresses.append(addr)
# rebuild mempool histories
new_mempool_hist = {}
d['prevout_n'] = vds.read_uint32()
scriptSig = vds.read_bytes(vds.read_compact_size())
d['sequence'] = vds.read_uint32()
- # actually I don't need that at all
- # if not is_coinbase: d['address'] = extract_public_key(scriptSig)
- # d['script'] = decode_script(scriptSig)
+
+ if scriptSig:
+ pubkeys, signatures, address = get_address_from_input_script(scriptSig)
+ else:
+ pubkeys = []
+ signatures = []
+ address = None
+
+ d['address'] = address
+ d['signatures'] = signatures
+
return d
+def get_address_from_input_script(bytes):
+ try:
+ decoded = [ x for x in script_GetOp(bytes) ]
+ except:
+ # coinbase transactions raise an exception
+ return [], [], None
+
+ # non-generated TxIn transactions push a signature
+ # (seventy-something bytes) and then their public key
+ # (65 bytes) onto the stack:
+
+ match = [ opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4 ]
+ if match_decoded(decoded, match):
+ return None, None, public_key_to_bc_address(decoded[1][1])
+
+ # p2sh transaction, 2 of n
+ match = [ opcodes.OP_0 ]
+ while len(match) < len(decoded):
+ match.append(opcodes.OP_PUSHDATA4)
+
+ if match_decoded(decoded, match):
+
+ redeemScript = decoded[-1][1]
+ num = len(match) - 2
+ signatures = map(lambda x:x[1].encode('hex'), decoded[1:-1])
+ dec2 = [ x for x in script_GetOp(redeemScript) ]
+
+ # 2 of 2
+ match2 = [ opcodes.OP_2, opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4, opcodes.OP_2, opcodes.OP_CHECKMULTISIG ]
+ if match_decoded(dec2, match2):
+ pubkeys = [ dec2[1][1].encode('hex'), dec2[2][1].encode('hex') ]
+ return pubkeys, signatures, hash_160_to_bc_address(hash_160(redeemScript), 5)
+
+ # 2 of 3
+ match2 = [ opcodes.OP_2, opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4, opcodes.OP_3, opcodes.OP_CHECKMULTISIG ]
+ if match_decoded(dec2, match2):
+ pubkeys = [ dec2[1][1].encode('hex'), dec2[2][1].encode('hex'), dec2[3][1].encode('hex') ]
+ return pubkeys, signatures, hash_160_to_bc_address(hash_160(redeemScript), 5)
+
+ return [], [], None
+
def get_address_from_output_script(bytes):
decoded = [ x for x in script_GetOp(bytes) ]
self.address = address[0]
self.name = "TCP " if not use_ssl else "SSL "
+ self.response_queue = queue.Queue()
def do_handshake(self):
if self.use_ssl:
self._stopped = True
def send_response(self, response):
- data = json.dumps(response) + "\n"
- # Possible race condition here by having session
- # close connection?
- # I assume Python connections are thread safe interfaces
- try:
- connection = self.connection()
- while data:
- l = connection.send(data)
- data = data[l:]
- except:
- self.stop()
+ self.response_queue.put(response)
+
+
+class TcpClientResponder(threading.Thread):
+
+ def __init__(self, session):
+ self.session = session
+ threading.Thread.__init__(self)
+
+ def run(self):
+ while not self.session.stopped():
+ response = self.session.response_queue.get()
+ data = json.dumps(response) + "\n"
+ try:
+ while data:
+ l = self.session.connection().send(data)
+ data = data[l:]
+ except:
+ self.session.stop()
+
class TcpClientRequestor(threading.Thread):
while not self.shared.stopped():
+ #if self.use_ssl: print_log("SSL: socket listening")
try:
connection, address = sock.accept()
except:
time.sleep(0.1)
continue
+ #if self.use_ssl: print_log("SSL: new session", address)
try:
session = TcpSession(connection, address, use_ssl=self.use_ssl, ssl_certfile=self.ssl_certfile, ssl_keyfile=self.ssl_keyfile)
except BaseException, e:
self.dispatcher.collect_garbage()
client_req = TcpClientRequestor(self.dispatcher, session)
client_req.start()
+ responder = TcpClientResponder(session)
+ responder.start()