def sign(self, keypairs): print_error("tx.sign(), keypairs:", keypairs) for i, txin in enumerate(self.inputs): # if the input is multisig, parse redeem script redeem_script = txin.get('redeemScript') num, redeem_pubkeys = parse_redeemScript(redeem_script) if redeem_script else (1, [txin.get('redeemPubkey')]) # add pubkeys txin["pubkeys"] = redeem_pubkeys # get list of already existing signatures signatures = txin.get("signatures",{}) # continue if this txin is complete if len(signatures) == num: continue for_sig = Hash(self.tx_for_sig(i).decode('hex')) for pubkey in redeem_pubkeys: if pubkey in keypairs.keys(): # add signature sec = keypairs[pubkey] pkey = regenerate_key(sec) secexp = pkey.secret private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 ) public_key = private_key.get_verifying_key() sig = private_key.sign_digest_deterministic( for_sig, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der ) assert public_key.verify_digest( sig, for_sig, sigdecode = ecdsa.util.sigdecode_der) self.add_signature(i, pubkey, sig.encode('hex')) print_error("is_complete", self.is_complete()) self.raw = self.serialize( self.inputs, self.outputs )
def send(self, messages, callback): sub = [] for message in messages: m, v = message if m[-10:] == '.subscribe': sub.append(message) if sub: with self.lock: if self.subscriptions.get(callback) is None: self.subscriptions[callback] = [] for message in sub: if message not in self.subscriptions[callback]: self.subscriptions[callback].append(message) if not self.is_connected: print_error("interface: trying to send while not connected") return if self.protocol in 'st': with self.lock: out = self.send_tcp(messages, callback) else: # do not use lock, http is synchronous out = self.send_http(messages, callback) return out
def new_blockchain_height(self, blockchain_height, i): if self.is_connected(): if self.server_is_lagging(): print_error( "Server is lagging", blockchain_height, self.get_server_height()) if self.config.get('auto_cycle'): self.set_server(i.server) self.notify('updated')
def run(self): threading.Thread(target=self.reading_thread).start() while self.is_running(): try: r = self.response_queue.get(timeout=0.1) except Queue.Empty: continue id = r.get('id') if id is None: method = r.get('method') params = r.get('params') else: ws, amount, rr = self.sub_ws[id] method = rr.get('method') params = rr.get('params') result = r.get('result') if method == 'blockchain.address.subscribe': util.print_error('response', r) if result is not None: request = {'method':'blockchain.address.get_balance', 'params':params, 'id':self.counter} self.server.send_request(self, request) self.sub_ws[self.counter] = ws, amount, request self.counter += 1 if r.get('method') == 'blockchain.address.get_balance': util.print_error('response', r) if not ws.closed: if sum(result.values()) >=amount: ws.sendMessage(unicode('paid')) self.server.remove_client(self)
def process_request(self, request): method = request['method'] params = request['params'] _id = request['id'] if method.startswith('network.'): out = {'id':_id} try: f = getattr(self, method[8:]) except AttributeError: out['error'] = "unknown method" try: out['result'] = f(*params) except BaseException as e: out['error'] = str(e) print_error("network error", str(e)) self.response_queue.put(out) return if method == 'blockchain.address.subscribe': addr = params[0] if addr in self.addresses: self.response_queue.put({'id':_id, 'result':self.addresses[addr]}) return self.interface.send_request(request)
def get_socket(self): if self.use_ssl: cert_path = os.path.join( self.config.path, 'certs', self.host) if not os.path.exists(cert_path): is_new = True s = self.get_simple_socket() if s is None: return # try with CA first try: s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23, cert_reqs=ssl.CERT_REQUIRED, ca_certs=ca_path, do_handshake_on_connect=True) except ssl.SSLError, e: s = None if s and self.check_host_name(s.getpeercert(), self.host): print_error("SSL certificate signed by CA:", self.host) return s # get server certificate. # Do not use ssl.get_server_certificate because it does not work with proxy s = self.get_simple_socket() try: s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23, cert_reqs=ssl.CERT_NONE, ca_certs=None) except ssl.SSLError, e: print_error("SSL error retrieving SSL certificate:", self.host, e) return dercert = s.getpeercert(True) s.close() cert = ssl.DER_cert_to_PEM_cert(dercert) # workaround android bug cert = re.sub("([^\n])-----END CERTIFICATE-----","\\1\n-----END CERTIFICATE-----",cert) temporary_path = cert_path + '.temp' with open(temporary_path,"w") as f: f.write(cert)
def sign(self, keypairs): for i, txin in enumerate(self.inputs()): num = txin['num_sig'] for x_pubkey in txin['x_pubkeys']: signatures = filter(None, txin['signatures']) if len(signatures) == num: # txin is complete break if x_pubkey in keypairs.keys(): print_error("adding signature for", x_pubkey) # add pubkey to txin txin = self._inputs[i] x_pubkeys = txin['x_pubkeys'] ii = x_pubkeys.index(x_pubkey) sec = keypairs[x_pubkey] pubkey = public_key_from_private_key(sec) txin['x_pubkeys'][ii] = pubkey txin['pubkeys'][ii] = pubkey self._inputs[i] = txin # add signature for_sig = Hash(self.tx_for_sig(i).decode('hex')) pkey = regenerate_key(sec) secexp = pkey.secret private_key = bitcoin.MySigningKey.from_secret_exponent( secexp, curve = SECP256k1 ) public_key = private_key.get_verifying_key() sig = private_key.sign_digest_deterministic( for_sig, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der ) assert public_key.verify_digest( sig, for_sig, sigdecode = ecdsa.util.sigdecode_der) txin['signatures'][ii] = sig.encode('hex') self._inputs[i] = txin print_error("is_complete", self.is_complete()) self.raw = self.serialize()
def run(self): self.network.start(self.network_queue) while self.is_running(): try: response = self.network_queue.get(timeout=0.1) except Queue.Empty: continue if self.debug: print_error("<--", response) response_id = response.get('id') if response_id: with self.lock: client_id, client = self.requests.pop(response_id) response['id'] = client_id client.response_queue.put(response) else: # notification m = response.get('method') v = response.get('params') for client in self.clients: if repr((m, v)) in client.subscriptions: client.response_queue.put(response) self.network.stop() print_error("server exiting")
def verify_chunk(self, index, hexdata): data = hexdata.decode('hex') height = index*1920 num = len(data)/80 if index == 0: previous_hash = ("0"*64) else: prev_header = self.read_header(index*1920-1) if prev_header is None: raise previous_hash = self.hash_header(prev_header) if height < 43847: bits, target = self.get_target(index) for i in xrange(num): height = index*1920 + i raw_header = data[i*80:(i+1)*80] header = self.header_from_string(raw_header) _hash = self.pow_hash_header(header) if height >= 43847: bits, target = self.get_target(height, data=data) assert previous_hash == header.get('prev_block_hash') assert bits == header.get('bits') assert int('0x'+_hash,16) < target print_error( 'verified height ', str(height)) previous_header = header previous_hash = self.hash_header(header) self.save_chunk(index, data) print_error("validated chunk %d"%height)
def daemon_loop(server): s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) daemon_socket = os.path.join(server.config.path, DAEMON_SOCKET) if os.path.exists(daemon_socket): os.remove(daemon_socket) daemon_timeout = server.config.get('daemon_timeout', None) s.bind(daemon_socket) s.listen(5) s.settimeout(1) t = time.time() while server.running: try: connection, address = s.accept() except socket.timeout: if daemon_timeout is None: continue if not server.clients: if time.time() - t > daemon_timeout: print_error("Daemon timeout") break else: t = time.time() continue t = time.time() client = ClientThread(server, connection) client.start() server.stop() # sleep so that other threads can terminate cleanly time.sleep(0.5) print_error("Daemon exiting")
def get_chain(self, interface, final_header): header = final_header chain = [ final_header ] requested_header = False queue = Queue.Queue() height = header.get('block_height') while self.is_running(): if requested_header: header = self.retrieve_header(interface, queue) if not header: return chain = [ header ] + chain requested_header = False height = header.get('block_height') previous_header = self.read_header(height -1) if not previous_header: self.request_header(interface, height - 1, queue) requested_header = True continue # verify that it connects to my chain prev_hash = self.hash_header(previous_header) if prev_hash != header.get('prev_block_hash'): print_error("reorg") self.request_header(interface, height - 1, queue) requested_header = True continue else: # the chain is complete return chain
def retrieve_header(self, i, queue): timeout = 1 while True: try: ir = queue.get(timeout=timeout) timeout = 1 except Queue.Empty: print_error('timeout', timeout) if timeout < 32: timeout *= 2 continue if not ir: continue i, r = ir if r.get('error'): print_error('Verifier received an error:', r) continue # 3. handle response method = r['method'] params = r['params'] result = r['result'] if method == 'blockchain.block.get_header': return result
def verify_chunk(self, index, hexdata): data = hexdata.decode('hex') height = index num = len(data)/88 if index == 0: previous_hash = ("0"*64) else: prev_header = self.read_header(index-1) if prev_header is None: raise previous_hash = self.hash_header(prev_header) bits, target = self.get_target(index) for i in range(num): height = index + i raw_header = data[i*88:(i+1)*88] header = self.header_from_string(raw_header) _hash = self.hash_header(header) assert previous_hash == header.get('prev_block_hash') #assert bits == header.get('bits') #assert int('0x'+_hash,16) < target # Cant do bits for memorycoin yet previous_header = header previous_hash = _hash self.save_chunk(index, data) print_error("validated chunk %d"%height)
def sign(self, keypairs): print_error("tx.sign(), keypairs:", keypairs) for i, txin in enumerate(self.inputs): # continue if this txin is complete signatures = filter(lambda x: x is not None, txin['signatures']) num = txin['num_sig'] if len(signatures) == num: continue redeem_pubkeys = txin['pubkeys'] for_sig = Hash(self.tx_for_sig(i).decode('hex')) for pubkey in redeem_pubkeys: if pubkey in keypairs.keys(): # add signature sec = keypairs[pubkey] pkey = regenerate_key(sec) secexp = pkey.secret private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 ) public_key = private_key.get_verifying_key() sig = private_key.sign_digest_deterministic( for_sig, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der ) assert public_key.verify_digest( sig, for_sig, sigdecode = ecdsa.util.sigdecode_der) self.add_signature(i, pubkey, sig.encode('hex')) print_error("is_complete", self.is_complete()) self.raw = self.serialize( self.inputs, self.outputs )
def verify_header(self, header): # add header to the blockchain file # if there is a reorg, push it in a stack height = header.get('block_height') prev_header = self.read_header(height -1) if not prev_header: # return False to request previous header return False prev_hash = self.hash_header(prev_header) bits, target = self.get_target(height/2016) _hash = self.hash_header(header) try: assert prev_hash == header.get('prev_block_hash') assert bits == header.get('bits') assert eval('0x'+_hash) < target except: # this can be caused by a reorg. print_error("verify header failed"+ repr(header)) verifier.undo_verifications() # return False to request previous header. return False self.save_header(header) print_error("verify header:", _hash, height) return True
def get_chunks(self, i, header, height): requested_chunks = [] min_index = (self.local_height + 1)/2016 max_index = (height + 1)/2016 for n in range(min_index, max_index + 1): print_error( "requesting chunk", n ) i.send([ ('blockchain.block.get_chunk',[n])], 'get_header') requested_chunks.append(n) break while requested_chunks: try: r = i.get_response('get_header',timeout=1) except Queue.Empty: continue if not r: continue if r.get('error'): print_error('Verifier received an error:', r) continue # 3. handle response method = r['method'] params = r['params'] result = r['result'] if method == 'blockchain.block.get_chunk': index = params[0] self.verify_chunk(index, result) requested_chunks.remove(index)
def set_parameters(self, host, port, protocol, proxy, auto_connect): proxy_str = interface.serialize_proxy(proxy) server_str = ':'.join([ host, port, protocol ]) self.config.set_key('auto_cycle', auto_connect, True) self.config.set_key("proxy", proxy_str, True) self.config.set_key("protocol", protocol, True) self.config.set_key("server", server_str, True) if self.proxy != proxy_str or self.protocol != protocol: print_error('restarting network') self.proxy = proxy_str self.protocol = protocol for i in self.interfaces.values(): i.stop() if auto_connect: #self.interface = None return if auto_connect: if not self.interface.is_connected: self.switch_to_random_interface() else: if self.server_is_lagging(): self.stop_interface() else: self.set_server(server_str)
def verify_chunk(self, index, hexdata): data = hexdata.decode('hex') height = index*2016 num = len(data)/80 print_error("validating headers %d"%height) if index == 0: previous_hash = ("0"*64) else: prev_header = self.read_header(index*2016-1) if prev_header is None: raise previous_hash = self.hash_header(prev_header) bits, target = self.get_target(index) for i in range(num): height = index*2016 + i raw_header = data[i*80:(i+1)*80] header = self.header_from_string(raw_header) _hash = self.hash_header(header) assert previous_hash == header.get('prev_block_hash') assert bits == header.get('bits') assert eval('0x'+_hash) < target previous_header = header previous_hash = _hash self.save_chunk(index, data)
def verify_message(address, signature, message): try: EC_KEY.verify_message(address, signature, message) return True except Exception as e: print_error("Verification error: {0}".format(e)) return False
def daemon_loop(server): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) daemon_port = server.config.get('daemon_port', DAEMON_PORT) daemon_timeout = server.config.get('daemon_timeout', 5*60) s.bind(('localhost', daemon_port)) s.listen(5) s.settimeout(1) t = time.time() while server.running: try: connection, address = s.accept() except socket.timeout: if not server.clients: if time.time() - t > daemon_timeout: print_error("Daemon timeout") break else: t = time.time() continue t = time.time() client = ClientThread(server, connection) client.start() server.stop() # sleep so that other threads can terminate cleanly time.sleep(0.5) print_error("Daemon exiting")
def run(self): self.blockchain.start() with self.lock: self.running = True while self.is_running(): try: i = self.queue.get(timeout = 30 if self.interfaces else 3) except Queue.Empty: if len(self.interfaces) < NUM_SERVERS: self.start_random_interface() continue if i.is_connected: self.add_recent_server(i) i.send([ ('blockchain.headers.subscribe',[])], self.on_header) if i == self.interface: print_error('sending subscriptions to', self.interface.server) self.send_subscriptions() self.trigger_callback('connected') else: self.disconnected_servers.append(i.server) self.interfaces.pop(i.server) if i.server in self.heights: self.heights.pop(i.server) if i == self.interface: self.interface = None self.trigger_callback('disconnected') if self.interface is None and self.config.get('auto_cycle'): self.switch_to_random_interface()
def run(self): self.start_tcp() self.change_status() if not self.is_connected: return t = 0 while self.is_connected: # ping the server with server.version if time.time() - t > 60: if self.is_ping: print_error("ping timeout", self.server) self.is_connected = False break else: self.send_request({'method':'server.version', 'params':[ELECTRUM_VERSION, PROTOCOL_VERSION]}) self.is_ping = True t = time.time() try: response = self.pipe.get() except util.timeout: continue if response is None: self.is_connected = False break self.process_response(response) self.change_status() print_error("closing connection:", self.server)
def update_signatures(self, raw): """Add new signatures to a transaction""" d = deserialize(raw) for i, txin in enumerate(self.inputs()): sigs1 = txin.get('signatures') sigs2 = d['inputs'][i].get('signatures') for sig in sigs2: if sig in sigs1: continue for_sig = Hash(self.tx_for_sig(i).decode('hex')) # der to string order = ecdsa.ecdsa.generator_secp256k1.order() r, s = ecdsa.util.sigdecode_der(sig.decode('hex'), order) sig_string = ecdsa.util.sigencode_string(r, s, order) pubkeys = txin.get('pubkeys') compressed = True for recid in range(4): public_key = MyVerifyingKey.from_signature(sig_string, recid, for_sig, curve = SECP256k1) pubkey = point_to_ser(public_key.pubkey.point, compressed).encode('hex') if pubkey in pubkeys: public_key.verify_digest(sig_string, for_sig, sigdecode = ecdsa.util.sigdecode_string) j = pubkeys.index(pubkey) print_error("adding sig", i, j, pubkey, sig) self._inputs[i]['signatures'][j] = sig self._inputs[i]['x_pubkeys'][j] = pubkey break # redo raw self.raw = self.serialize()
def load_certificates(): try: ca_f = open(ca_path, "r") except Exception: print "ERROR: Could not open %s" % ca_path print "ca-bundle.crt file should be placed in ~/.electrum/ca/ca-bundle.crt" print "Documentation on how to download or create the file here: http://curl.haxx.se/docs/caextract.html" print "Payment will continue with manual verification." return False c = "" for line in ca_f: if line == "-----BEGIN CERTIFICATE-----\n": c = line else: c += line if line == "-----END CERTIFICATE-----\n": x = x509.X509() try: x.parse(c) except Exception as e: util.print_error("cannot parse cert:", e) ca_list[x.getFingerprint()] = x ca_f.close() util.print_error("%d certificates" % len(ca_list)) return True
def __init__(self, options={}): # system conf, readonly self.system_config = {} if options.get('portable') == False: self.read_system_config() # user conf, writeable self.user_dir = user_dir() self.user_config = {} if options.get('portable') == False: self.read_user_config() # command-line options self.options_config = options self.wallet_config = {} self.wallet_file_exists = False self.init_path(self.options_config.get('wallet_path')) print_error( "path", self.path ) if self.path: self.read_wallet_config(self.path) # portable wallet: use the same directory for wallet and headers file if options.get('portable'): self.wallet_config['blockchain_headers_path'] = os.path.dirname(self.path)
def send(self, messages, callback): """return the ids of the requests that we sent""" # detect subscriptions sub = [] for message in messages: m, v = message if m[-10:] == '.subscribe': sub.append(message) if sub: with self.lock: if self.subscriptions.get(callback) is None: self.subscriptions[callback] = [] for message in sub: if message not in self.subscriptions[callback]: self.subscriptions[callback].append(message) with self.lock: requests = [] ids = [] for m in messages: method, params = m request = {'id': self.message_id, 'method': method, 'params': params} self.unanswered_requests[self.message_id] = method, params, callback ids.append(self.message_id) requests.append(request) if self.debug: print_error("-->", request) self.message_id += 1 self.pipe.send_all(requests) return ids
def server_is_lagging(self): h = self.get_server_height() if not h: print_error('no height for main interface') return False lag = self.get_local_height() - self.get_server_height() return lag > 1
def process_pending_sends(self): # Requests needs connectivity. If we don't have an interface, # we cannot process them. if not self.interface: return with self.lock: sends = self.pending_sends self.pending_sends = [] for messages, callback in sends: for method, params in messages: r = None if method.endswith('.subscribe'): k = self.get_index(method, params) # add callback to list l = self.subscriptions.get(k, []) if callback not in l: l.append(callback) self.subscriptions[k] = l # check cached response for subscriptions r = self.sub_cache.get(k) if r is not None: util.print_error("cache hit", k) callback(r) else: message_id = self.queue_request(method, params) self.unanswered_requests[message_id] = method, params, callback
def add_client(self, client): for key in ['status', 'banner', 'updated', 'servers', 'interfaces']: value = self.network.get_status_value(key) client.response_queue.put({'method':'network.status', 'params':[key, value]}) with self.lock: self.clients.append(client) print_error("new client:", len(self.clients))
def send_tcp(self, messages, callback): """return the ids of the requests that we sent""" out = '' ids = [] for m in messages: method, params = m request = json.dumps( { 'id':self.message_id, 'method':method, 'params':params } ) self.unanswered_requests[self.message_id] = method, params, callback ids.append(self.message_id) if self.debug: print "-->", request self.message_id += 1 out += request + '\n' while out: try: sent = self.s.send( out ) out = out[sent:] except socket.error,e: if e[0] in (errno.EWOULDBLOCK,errno.EAGAIN): print_error( "EAGAIN: retrying") time.sleep(0.1) continue else: traceback.print_exc(file=sys.stdout) # this happens when we get disconnected print_error( "Not connected, cannot send" ) return None
def execute(self, printer): # currently we fetch top buzzfeed articles (don't judge me, they are a good laugh) params = {'country': 'de', 'pageSize': self.count} r = requests.get( News.API_ENDPOINT, params=params, headers={'Authorization': 'Bearer ' + config.NEWSAPI_KEY}) util.print_header(printer, 'Nachrichten') if r.status_code != 200: print("Error: Couldn't fetch news articles (request failed)") util.print_error(printer) return try: json = r.json() except ValueError as e: print(e) print( "Error: Couldn't fetch headlines (invalid or missing response content)" ) util.print_error(printer) return try: articles = [_Article(**current) for current in json['articles']][0:self.count] except KeyError as e: print(e) print( "Error: Couldn't fetch headlines (unexpected response format)") util.print_error(printer) return for a in articles: # print the source printer.underlineOn() printer.write(a.source_name + '\n') printer.underlineOff() # print the headline printer.write(a.title + '\n') printer.feed(1) # TODO: implement QR-Code generation printer.feed(1)
def evaluate_scan(pred_file, gt_file, confusion): try: pred_ids = util_3d.load_ids(pred_file) except: util.print_error('unable to load ' + pred_file + ': ' + str(e)) try: gt_ids = util_3d.load_ids(gt_file) except: util.print_error('unable to load ' + gt_file + ': ' + str(e)) # sanity checks if not pred_ids.shape == gt_ids.shape: util.print_error('%s: number of predicted values does not match number of vertices' % pred_file, user_fault=True) for (gt_val,pred_val) in izip(gt_ids.flatten(),pred_ids.flatten()): if gt_val not in VALID_CLASS_IDS: continue if pred_val not in VALID_CLASS_IDS: pred_val = UNKNOWN_ID confusion[gt_val][pred_val] += 1
def visualize(pred_file, mesh_file, output_file): if not output_file.endswith('.ply'): util.print_error('output file must be a .ply file') colors = util.create_color_palette() num_colors = len(colors) ids = util_3d.load_ids(pred_file) with open(mesh_file, 'rb') as f: plydata = PlyData.read(f) num_verts = plydata['vertex'].count if num_verts != len(ids): util.print_error('#predicted labels = ' + str(len(ids)) + 'vs #mesh vertices = ' + str(num_verts)) # *_vh_clean_2.ply has colors already for i in range(num_verts): if ids[i] >= num_colors: util.print_error('found predicted label ' + str(ids[i]) + ' not in nyu40 label set') color = colors[ids[i]] plydata['vertex']['red'][i] = color[0] plydata['vertex']['green'][i] = color[1] plydata['vertex']['blue'][i] = color[2] plydata.write(output_file)
def read_instance_prediction_file(filename, pred_path): lines = open(filename).read().splitlines() instance_info = {} abs_pred_path = os.path.abspath(pred_path) for line in lines: parts = line.split(' ') if len(parts) != 3: util.print_error('invalid instance prediction file. Expected (per line): [rel path prediction] [label id prediction] [confidence prediction]') if os.path.isabs(parts[0]): util.print_error('invalid instance prediction file. First entry in line must be a relative path') mask_file = os.path.join(os.path.dirname(filename), parts[0]) mask_file = os.path.abspath(mask_file) # check that mask_file lives inside prediction path if os.path.commonprefix([mask_file, abs_pred_path]) != abs_pred_path: util.print_error('predicted mask {} in prediction text file {} points outside of prediction path.'.format(mask_file,filename)) info = {} info["label_id"] = int(float(parts[1])) info["conf"] = float(parts[2]) instance_info[mask_file] = info return instance_info
def validate_single_rule(config_id: str, rule_index: int, rule: Dict[str, Any]) -> bool: rule_id_err_msg = f'(rule id: {rule.get("id", MISSING_RULE_ID)})' if not set(rule.keys()).issuperset(YAML_MUST_HAVE_KEYS): print_error( f"{config_id} is missing keys at rule {rule_index+1} {rule_id_err_msg}, must have: {YAML_MUST_HAVE_KEYS}" ) return False if not set(rule.keys()).issubset(YAML_ALL_VALID_RULE_KEYS): print_error( f"{config_id} has invalid rule key at rule {rule_index+1} {rule_id_err_msg}, can only have: {YAML_ALL_VALID_RULE_KEYS}" ) return False try: _ = build_boolean_expression(rule) except InvalidRuleSchema as ex: print_error( f"{config_id}: inside rule {rule_index+1} {rule_id_err_msg}, pattern fields can't look like this: {ex}" ) return False return True
def sign(self, keypairs): print_error("tx.sign(), keypairs:", keypairs) for i, txin in enumerate(self.inputs): signatures = filter(None, txin['signatures']) num = txin['num_sig'] if len(signatures) == num: # continue if this txin is complete continue for x_pubkey in txin['x_pubkeys']: if x_pubkey in keypairs.keys(): print_error("adding signature for", x_pubkey) # add pubkey to txin txin = self.inputs[i] x_pubkeys = txin['x_pubkeys'] ii = x_pubkeys.index(x_pubkey) sec = keypairs[x_pubkey] pubkey = public_key_from_private_key(sec) txin['x_pubkeys'][ii] = pubkey txin['pubkeys'][ii] = pubkey self.inputs[i] = txin # add signature # signature for input skips nTime for_sig = Hash(self.tx_for_sig(i).decode('hex')) pkey = regenerate_key(sec) secexp = pkey.secret private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve=SECP256k1) public_key = private_key.get_verifying_key() sig = private_key.sign_digest_deterministic( for_sig, hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_der) assert public_key.verify_digest( sig, for_sig, sigdecode=ecdsa.util.sigdecode_der) txin['signatures'][ii] = sig.encode('hex') self.inputs[i] = txin print_error("is_complete", self.is_complete()) self.raw = self.serialize()
def run(self): self.init_headers_file() self.set_local_height() self.print_error("%d blocks"%self.local_height) while self.is_running(): try: result = self.queue.get(timeout=0.1) except Queue.Empty: continue if not result: continue i, header = result if not header: continue height = header.get('block_height') if height <= self.local_height: continue if height > self.local_height + 50: if not self.get_and_verify_chunks(i, header, height): continue if height > self.local_height: # get missing parts from interface (until it connects to my chain) chain = self.get_chain( i, header ) # skip that server if the result is not consistent if not chain: print_error('e') continue # verify the chain if self.verify_chain( chain ): print_error("height:", height, i.server) for header in chain: self.save_header(header) else: print_error("error", i.server) # todo: dismiss that server continue self.network.new_blockchain_height(height, i) self.print_error("stopped")
def run(self): self.s = self.get_socket() if self.s: self.s.settimeout(60) self.is_connected = True print_error("connected to", self.host, self.port) self.pipe = util.SocketPipe(self.s) self.change_status() if not self.is_connected: return t = 0 while self.is_connected: # ping the server with server.version if time.time() - t > 60: if self.is_ping: print_error("ping timeout", self.server) self.is_connected = False break else: self.send_request({ 'method': 'server.version', 'params': [ELECTRUM_VERSION, PROTOCOL_VERSION] }) self.is_ping = True t = time.time() try: response = self.pipe.get() except util.timeout: continue if response is None: self.is_connected = False break self.process_response(response) self.change_status() print_error("closing connection:", self.server)
def verify_header(self, header): # add header to the blockchain file # if there is a reorg, push it in a stack height = header.get('block_height') prev_header = self.read_header(height -1) if not prev_header: # return False to request previous header return False prev_hash = self.hash_header(prev_header) bits, target = self.get_target(height/2016) _hash = self.hash_header(header) try: assert prev_hash == header.get('prev_block_hash') assert bits == header.get('bits') assert eval('0x'+_hash) < target except: # this can be caused by a reorg. print_error("verify header failed"+ repr(header)) # undo verifications with self.lock: items = self.verified_tx.items()[:] for tx_hash, item in items: tx_height, timestamp, pos = item if tx_height >= height: print_error("redoing", tx_hash) with self.lock: self.verified_tx.pop(tx_hash) if tx_hash in self.merkle_roots: self.merkle_roots.pop(tx_hash) # return False to request previous header. return False self.save_header(header) print_error("verify header:", _hash, height) return True
def verify_chain(self, chain): first_header = chain[0] first_height = first_header.get('block_height') # get preceding headers to use in KGW prev_chain = [ self.read_header(x) for x in range(first_height - self.cache_kgw_size, first_height) ] prev_header = prev_chain[-1] chain_target = self.kgw.get_chain_target(prev_chain, chain) for i, header in enumerate(chain): height = header.get('block_height') prev_hash = self.hash_header(prev_header) bits, target = chain_target[i] if prev_hash != header.get('prev_block_hash'): print_error("height %d: prev_hash mismatch" % height) return False if bits != header.get('bits'): print_error("height %d: bits mismatch %u vs %u" % (height, bits, header.get('bits'))) return False if height <= self.kgw.last_pow_block: _hash = self.pow_hash_header(header) if int('0x' + _hash, 16) >= target: print_error("height %d: PoW hash >= target" % height) return False prev_header = header return True
def get_and_verify_chunks(self, i, header, height): requested_chunks = [] queue = Queue.Queue() min_index = (self.local_height + 1) / 2016 max_index = (height + 1) / 2016 for n in range(min_index, max_index + 1): i.send([('blockchain.block.get_chunk', [n])], lambda i, r: queue.put(r)) requested_chunks.append(n) print_error("requested chunks:", requested_chunks) while requested_chunks: try: r = queue.get(timeout=1) except Queue.Empty: continue if not r: continue if r.get('error'): print_error('Verifier received an error:', r) continue # 3. handle response params = r['params'] result = r['result'] index = params[0] try: self.verify_chunk(index, result) except Exception: print_error('Verify chunk failed!!') return False requested_chunks.remove(index) return True
def attempt_key_import(keyid, key_fullpath): """Ask user to import key.""" global IMPORTED print(SEPT) ig = InputGetter( '\nDo you want to attempt to import keyid {}: (y/N) '.format(keyid)) import_key_answer = ig.get_answer() if import_key_answer in [None, False]: return False with cli_gpg_ctx() as ctx: err, _ = ctx.import_key(keyid) if err is not None: util.print_error(err.strerror) return False err, key_content = ctx.export_key(keyid) if err is not None: util.print_error(err.strerror) return False util.write_out(key_fullpath, key_content) print('\n') util.print_success('Public key id: {} was imported'.format(keyid)) err, content = ctx.display_keyinfo(key_fullpath) if err is not None: util.print_error( 'Unable to parse {}, will be removed'.format(key_fullpath)) os.unlink(key_fullpath) return False print("\n", content) ig = InputGetter(message='\nDo you want to keep this key: (Y/n) ', default='y') if ig.get_answer() is True: IMPORTED = content return True else: os.unlink(key_fullpath) return False
def parse_scriptSig(d, bytes): try: decoded = [x for x in script_GetOp(bytes)] except Exception: # coinbase transactions raise an exception print_error("cannot find address in input script", bytes.encode('hex')) return # payto_pubkey match = [opcodes.OP_PUSHDATA4] if match_decoded(decoded, match): sig = decoded[0][1].encode('hex') d['address'] = "(pubkey)" d['signatures'] = [sig] d['num_sig'] = 1 d['x_pubkeys'] = ["(pubkey)"] d['pubkeys'] = ["(pubkey)"] return # 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): sig = decoded[0][1].encode('hex') x_pubkey = decoded[1][1].encode('hex') try: signatures = parse_sig([sig]) pubkey, address = parse_xpub(x_pubkey) except: import traceback traceback.print_exc(file=sys.stdout) print_error("cannot find address in input script", bytes.encode('hex')) return d['signatures'] = signatures d['x_pubkeys'] = [x_pubkey] d['num_sig'] = 1 d['pubkeys'] = [pubkey] d['address'] = address return # p2sh transaction, m of n match = [opcodes.OP_0] + [opcodes.OP_PUSHDATA4] * (len(decoded) - 1) if not match_decoded(decoded, match): print_error("cannot find address in input script", bytes.encode('hex')) return x_sig = [x[1].encode('hex') for x in decoded[1:-1]] dec2 = [x for x in script_GetOp(decoded[-1][1])] m = dec2[0][0] - opcodes.OP_1 + 1 n = dec2[-2][0] - opcodes.OP_1 + 1 op_m = opcodes.OP_1 + m - 1 op_n = opcodes.OP_1 + n - 1 match_multisig = [op_m] + [opcodes.OP_PUSHDATA4] * n + [ op_n, opcodes.OP_CHECKMULTISIG ] if not match_decoded(dec2, match_multisig): print_error("cannot find address in input script", bytes.encode('hex')) return x_pubkeys = map(lambda x: x[1].encode('hex'), dec2[1:-2]) pubkeys = [parse_xpub(x)[0] for x in x_pubkeys] # xpub, addr = parse_xpub() redeemScript = Transaction.multisig_script(pubkeys, m) # write result in d d['num_sig'] = m d['signatures'] = parse_sig(x_sig) d['x_pubkeys'] = x_pubkeys d['pubkeys'] = pubkeys d['redeemScript'] = redeemScript d['address'] = hash_160_to_bc_address(hash_160(redeemScript.decode('hex')), 30)
def print_error(self, *msg): util.print_error("[blockchain]", *msg)
def request_header(self, i, h, queue): print_error("requesting header %d from %s" % (h, i.server)) i.send([('blockchain.block.get_header', [h])], lambda i, r: queue.put( (i, r)))
def parse_scriptSig(d, bytes): try: decoded = [x for x in script_GetOp(bytes)] except Exception: # coinbase transactions raise an exception print_error("cannot find address in input script", bytes.encode('hex')) return match = [opcodes.OP_PUSHDATA4] if match_decoded(decoded, match): item = decoded[0][1] if item[0] == chr(0): redeemScript = item.encode('hex') d['address'] = bitcoin.hash160_to_p2sh( bitcoin.hash_160(redeemScript.decode('hex'))) d['type'] = 'p2wpkh-p2sh' d['redeemScript'] = redeemScript d['x_pubkeys'] = ["(witness)"] d['pubkeys'] = ["(witness)"] d['signatures'] = ['(witness)'] d['num_sig'] = 1 else: # payto_pubkey d['type'] = 'p2pk' d['address'] = "(pubkey)" d['signatures'] = [item.encode('hex')] d['num_sig'] = 1 d['x_pubkeys'] = ["(pubkey)"] d['pubkeys'] = ["(pubkey)"] return # 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): sig = decoded[0][1].encode('hex') x_pubkey = decoded[1][1].encode('hex') try: signatures = parse_sig([sig]) pubkey, address = xpubkey_to_address(x_pubkey) except BaseException: print_error("cannot find address in input script", bytes.encode('hex')) return d['type'] = 'p2pkh' d['signatures'] = signatures d['x_pubkeys'] = [x_pubkey] d['num_sig'] = 1 d['pubkeys'] = [pubkey] d['address'] = address return # p2sh transaction, m of n match = [opcodes.OP_0] + [opcodes.OP_PUSHDATA4] * (len(decoded) - 1) if not match_decoded(decoded, match): print_error("cannot find address in input script", bytes.encode('hex')) return x_sig = [x[1].encode('hex') for x in decoded[1:-1]] dec2 = [x for x in script_GetOp(decoded[-1][1])] m = dec2[0][0] - opcodes.OP_1 + 1 n = dec2[-2][0] - opcodes.OP_1 + 1 op_m = opcodes.OP_1 + m - 1 op_n = opcodes.OP_1 + n - 1 match_multisig = [op_m] + [opcodes.OP_PUSHDATA4] * n + [ op_n, opcodes.OP_CHECKMULTISIG ] if not match_decoded(dec2, match_multisig): print_error("cannot find address in input script", bytes.encode('hex')) return x_pubkeys = map(lambda x: x[1].encode('hex'), dec2[1:-2]) pubkeys = [safe_parse_pubkey(x) for x in x_pubkeys] redeemScript = multisig_script(pubkeys, m) # write result in d d['type'] = 'p2sh' d['num_sig'] = m d['signatures'] = parse_sig(x_sig) d['x_pubkeys'] = x_pubkeys d['pubkeys'] = pubkeys d['redeemScript'] = redeemScript d['address'] = hash160_to_p2sh(hash_160(redeemScript.decode('hex')))
def __init__(self, lang=None): lang = lang or 'en' print_error('language', lang) filename = filenames.get(lang[0:2], 'english.txt') self.wordlist = load_wordlist(filename) print_error("wordlist has %d words" % len(self.wordlist))
def parse_scriptSig(d, bytes): try: decoded = [x for x in script_GetOp(bytes)] except Exception: # coinbase transactions raise an exception print_error("cannot find address in input script", bytes.encode('hex')) return # payto_pubkey match = [opcodes.OP_PUSHDATA4] if match_decoded(decoded, match): sig = decoded[0][1].encode('hex') d['address'] = "(pubkey)" d['signatures'] = [sig] d['num_sig'] = 1 d['x_pubkeys'] = ["(pubkey)"] d['pubkeys'] = ["(pubkey)"] return # 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): sig = decoded[0][1].encode('hex') x_pubkey = decoded[1][1].encode('hex') try: signatures = parse_sig([sig]) pubkey = parse_xpub(x_pubkey) except: import traceback traceback.print_exc(file=sys.stdout) print_error("cannot find address in input script", bytes.encode('hex')) return d['signatures'] = signatures d['x_pubkeys'] = [x_pubkey] d['num_sig'] = 1 d['pubkeys'] = [pubkey] d['address'] = public_key_to_bc_address(pubkey.decode('hex')) return # p2sh transaction, 2 of n match = [opcodes.OP_0] while len(match) < len(decoded): match.append(opcodes.OP_PUSHDATA4) if not match_decoded(decoded, match): print_error("cannot find address in input script", bytes.encode('hex')) return x_sig = map(lambda x: x[1].encode('hex'), decoded[1:-1]) d['signatures'] = parse_sig(x_sig) d['num_sig'] = 2 dec2 = [x for x in script_GetOp(decoded[-1][1])] match_2of2 = [ opcodes.OP_2, opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4, opcodes.OP_2, opcodes.OP_CHECKMULTISIG ] match_2of3 = [ opcodes.OP_2, opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4, opcodes.OP_3, opcodes.OP_CHECKMULTISIG ] if match_decoded(dec2, match_2of2): x_pubkeys = [dec2[1][1].encode('hex'), dec2[2][1].encode('hex')] elif match_decoded(dec2, match_2of3): x_pubkeys = [ dec2[1][1].encode('hex'), dec2[2][1].encode('hex'), dec2[3][1].encode('hex') ] else: print_error("cannot find address in input script", bytes.encode('hex')) return d['x_pubkeys'] = x_pubkeys pubkeys = map(parse_xpub, x_pubkeys) d['pubkeys'] = pubkeys redeemScript = Transaction.multisig_script(pubkeys, 2) d['redeemScript'] = redeemScript d['address'] = hash_160_to_bc_address(hash_160(redeemScript.decode('hex')), 5)
def handleConnected(self): util.print_error("connected", self.address)
def send_http(self, messages, callback): import urllib2, json, time, cookielib print_error("send_http", messages) if self.proxy: socks.setdefaultproxy(self.proxy_mode, self.proxy["host"], int(self.proxy["port"])) socks.wrapmodule(urllib2) cj = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) urllib2.install_opener(opener) t1 = time.time() data = [] ids = [] for m in messages: method, params = m if type(params) != type([]): params = [params] data.append({ 'method': method, 'id': self.message_id, 'params': params }) self.unanswered_requests[ self.message_id] = method, params, callback ids.append(self.message_id) self.message_id += 1 if data: data_json = json.dumps(data) else: # poll with GET data_json = None headers = {'content-type': 'application/json'} if self.session_id: headers['cookie'] = 'SESSION=%s' % self.session_id try: req = urllib2.Request(self.connection_msg, data_json, headers) response_stream = urllib2.urlopen(req, timeout=DEFAULT_TIMEOUT) except Exception: return for index, cookie in enumerate(cj): if cookie.name == 'SESSION': self.session_id = cookie.value response = response_stream.read() self.bytes_received += len(response) if response: response = json.loads(response) if type(response) is not type([]): self.queue_json_response(response) else: for item in response: self.queue_json_response(item) if response: self.poll_interval = 1 else: if self.poll_interval < 15: self.poll_interval += 1 #print self.poll_interval, response self.rtime = time.time() - t1 self.is_connected = True return ids
def queue_json_response(self, c): # uncomment to debug if self.debug: print_error("<--", c) msg_id = c.get('id') error = c.get('error') if error: print_error("received error:", c) if msg_id is not None: with self.lock: method, params, callback = self.unanswered_requests.pop( msg_id) callback( self, { 'method': method, 'params': params, 'error': error, 'id': msg_id }) return if msg_id is not None: with self.lock: method, params, callback = self.unanswered_requests.pop(msg_id) result = c.get('result') else: # notification method = c.get('method') params = c.get('params') if method == 'blockchain.numblocks.subscribe': result = params[0] params = [] elif method == 'blockchain.headers.subscribe': result = params[0] params = [] elif method == 'blockchain.address.subscribe': addr = params[0] result = params[1] params = [addr] with self.lock: for k, v in self.subscriptions.items(): if (method, params) in v: callback = k break else: print_error("received unexpected notification", method, params) print_error(self.subscriptions) return callback(self, { 'method': method, 'params': params, 'result': result, 'id': msg_id })
os.unlink(rej) os.rename(temporary_path, rej) else: if cert_has_expired(cert_path): print_error("certificate has expired:", cert_path) os.unlink(cert_path) else: print_msg("wrong certificate", self.host) return except Exception: print_error("wrap_socket failed", self.host) traceback.print_exc(file=sys.stdout) return if is_new: print_error("saving certificate for", self.host) os.rename(temporary_path, cert_path) s.settimeout(60) self.s = s self.is_connected = True print_error("connected to", self.host, self.port) def run_tcp(self): try: #if self.use_ssl: self.s.do_handshake() out = '' while self.is_connected: try: timeout = False msg = self.s.recv(1024)
def run(self): while self.is_running(): try: i, response = self.queue.get(timeout=0.1) except Queue.Empty: if len(self.interfaces) + len( self.pending_servers) < self.num_server: self.start_random_interface() if not self.interfaces: if time.time( ) - self.disconnected_time > DISCONNECTED_RETRY_INTERVAL: print_error('network: retrying connections') self.disconnected_servers = set([]) self.disconnected_time = time.time() continue if response is not None: self.process_response(i, response) continue # if response is None it is a notification about the interface if i.server in self.pending_servers: self.pending_servers.remove(i.server) if i.is_connected: self.add_interface(i) self.add_recent_server(i) i.send_request({ 'method': 'blockchain.headers.subscribe', 'params': [] }) if i == self.interface: print_error('sending subscriptions to', self.interface.server) self.send_subscriptions() self.set_status('connected') else: self.disconnected_servers.add(i.server) if i.server in self.interfaces: self.remove_interface(i) if i.server in self.heights: self.heights.pop(i.server) if i == self.interface: self.set_status('disconnected') if not self.interface.is_connected: if self.config.get('auto_cycle'): self.switch_to_random_interface() else: if self.default_server not in self.disconnected_servers: print_error("restarting main interface") if self.default_server in self.interfaces.keys(): self.switch_to_interface( self.interfaces[self.default_server]) else: self.interface = self.start_interface( self.default_server) print_error("Network: Stopping interfaces") for i in self.interfaces.values(): i.stop()
def stop(self): print_error("stopping network") with self.lock: self.running = False
if s is None: return s.settimeout(2) s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) if self.use_ssl: try: s = ssl.wrap_socket( s, ssl_version=ssl.PROTOCOL_SSLv3, cert_reqs=ssl.CERT_REQUIRED, ca_certs=(temporary_path if is_new else cert_path), do_handshake_on_connect=True) except ssl.SSLError, e: print_error("SSL error:", self.host, e) if e.errno != 1: return if is_new: rej = cert_path + '.rej' if os.path.exists(rej): os.unlink(rej) os.rename(temporary_path, rej) else: with open(cert_path) as f: cert = f.read() try: x = x509.X509() x.parse(cert) x.slow_parse() except:
def start_tcp(self): self.connection_msg = self.host + ':%d' % self.port if self.proxy is not None: socks.setdefaultproxy(self.proxy_mode, self.proxy["host"], int(self.proxy["port"])) socket.socket = socks.socksocket # prevent dns leaks, see http://stackoverflow.com/questions/13184205/dns-over-proxy def getaddrinfo(*args): return [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (args[0], args[1]))] socket.getaddrinfo = getaddrinfo if self.use_ssl: cert_path = os.path.join(self.config.path, 'certs', self.host) if not os.path.exists(cert_path): is_new = True # get server certificate. # Do not use ssl.get_server_certificate because it does not work with proxy try: l = socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM) except socket.gaierror: print_error("error: cannot resolve", self.host) return for res in l: try: s = socket.socket(res[0], socket.SOCK_STREAM) s.connect(res[4]) except: s = None continue try: s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv3, cert_reqs=ssl.CERT_NONE, ca_certs=None) except ssl.SSLError, e: print_error("SSL error retrieving SSL certificate:", self.host, e) s = None break if s is None: return dercert = s.getpeercert(True) s.close() cert = ssl.DER_cert_to_PEM_cert(dercert) # workaround android bug cert = re.sub("([^\n])-----END CERTIFICATE-----", "\\1\n-----END CERTIFICATE-----", cert) temporary_path = cert_path + '.temp' with open(temporary_path, "w") as f: f.write(cert) else: is_new = False
def handleMessage(self): assert self.data[0:3] == 'id:' util.print_error("message received", self.data) request_id = self.data[3:] request_queue.put((self, request_id))
class Interface(threading.Thread): def __init__(self, server, config=None): threading.Thread.__init__(self) self.daemon = True self.config = config if config is not None else SimpleConfig() self.connect_event = threading.Event() self.subscriptions = {} self.lock = threading.Lock() self.rtime = 0 self.bytes_received = 0 self.is_connected = False self.poll_interval = 1 self.debug = False # dump network messages. can be changed at runtime using the console #json self.message_id = 0 self.unanswered_requests = {} self.pending_transactions_for_notifications = [] # parse server self.server = server try: host, port, protocol = self.server.split(':') port = int(port) except Exception: self.server = None return if protocol not in 'ghst': raise Exception('Unknown protocol: %s' % protocol) self.host = host self.port = port self.protocol = protocol self.use_ssl = (protocol in 'sg') self.proxy = self.parse_proxy_options(self.config.get('proxy')) if self.proxy: self.proxy_mode = proxy_modes.index(self.proxy["mode"]) + 1 def queue_json_response(self, c): # uncomment to debug if self.debug: print_error("<--", c) msg_id = c.get('id') error = c.get('error') if error: print_error("received error:", c) if msg_id is not None: with self.lock: method, params, callback = self.unanswered_requests.pop( msg_id) callback( self, { 'method': method, 'params': params, 'error': error, 'id': msg_id }) return if msg_id is not None: with self.lock: method, params, callback = self.unanswered_requests.pop(msg_id) result = c.get('result') else: # notification method = c.get('method') params = c.get('params') if method == 'blockchain.numblocks.subscribe': result = params[0] params = [] elif method == 'blockchain.headers.subscribe': result = params[0] params = [] elif method == 'blockchain.address.subscribe': addr = params[0] result = params[1] params = [addr] with self.lock: for k, v in self.subscriptions.items(): if (method, params) in v: callback = k break else: print_error("received unexpected notification", method, params) print_error(self.subscriptions) return callback(self, { 'method': method, 'params': params, 'result': result, 'id': msg_id }) def on_version(self, i, result): self.server_version = result def start_http(self): self.session_id = None self.is_connected = True self.connection_msg = ('https' if self.use_ssl else 'http') + '://%s:%d' % (self.host, self.port) try: self.poll() except Exception: print_error("http init session failed") self.is_connected = False return if self.session_id: print_error('http session:', self.session_id) self.is_connected = True else: self.is_connected = False def run_http(self): self.is_connected = True while self.is_connected: try: if self.session_id: self.poll() time.sleep(self.poll_interval) except socket.gaierror: break except socket.error: break except Exception: traceback.print_exc(file=sys.stdout) break self.is_connected = False def poll(self): self.send([], None) def send_http(self, messages, callback): import urllib2, json, time, cookielib print_error("send_http", messages) if self.proxy: socks.setdefaultproxy(self.proxy_mode, self.proxy["host"], int(self.proxy["port"])) socks.wrapmodule(urllib2) cj = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) urllib2.install_opener(opener) t1 = time.time() data = [] ids = [] for m in messages: method, params = m if type(params) != type([]): params = [params] data.append({ 'method': method, 'id': self.message_id, 'params': params }) self.unanswered_requests[ self.message_id] = method, params, callback ids.append(self.message_id) self.message_id += 1 if data: data_json = json.dumps(data) else: # poll with GET data_json = None headers = {'content-type': 'application/json'} if self.session_id: headers['cookie'] = 'SESSION=%s' % self.session_id try: req = urllib2.Request(self.connection_msg, data_json, headers) response_stream = urllib2.urlopen(req, timeout=DEFAULT_TIMEOUT) except Exception: return for index, cookie in enumerate(cj): if cookie.name == 'SESSION': self.session_id = cookie.value response = response_stream.read() self.bytes_received += len(response) if response: response = json.loads(response) if type(response) is not type([]): self.queue_json_response(response) else: for item in response: self.queue_json_response(item) if response: self.poll_interval = 1 else: if self.poll_interval < 15: self.poll_interval += 1 #print self.poll_interval, response self.rtime = time.time() - t1 self.is_connected = True return ids def start_tcp(self): self.connection_msg = self.host + ':%d' % self.port if self.proxy is not None: socks.setdefaultproxy(self.proxy_mode, self.proxy["host"], int(self.proxy["port"])) socket.socket = socks.socksocket # prevent dns leaks, see http://stackoverflow.com/questions/13184205/dns-over-proxy def getaddrinfo(*args): return [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (args[0], args[1]))] socket.getaddrinfo = getaddrinfo if self.use_ssl: cert_path = os.path.join(self.config.path, 'certs', self.host) if not os.path.exists(cert_path): is_new = True # get server certificate. # Do not use ssl.get_server_certificate because it does not work with proxy try: l = socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM) except socket.gaierror: print_error("error: cannot resolve", self.host) return for res in l: try: s = socket.socket(res[0], socket.SOCK_STREAM) s.connect(res[4]) except: s = None continue try: s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv3, cert_reqs=ssl.CERT_NONE, ca_certs=None) except ssl.SSLError, e: print_error("SSL error retrieving SSL certificate:", self.host, e) s = None break if s is None: return dercert = s.getpeercert(True) s.close() cert = ssl.DER_cert_to_PEM_cert(dercert) # workaround android bug cert = re.sub("([^\n])-----END CERTIFICATE-----", "\\1\n-----END CERTIFICATE-----", cert) temporary_path = cert_path + '.temp' with open(temporary_path, "w") as f: f.write(cert) else: is_new = False try: addrinfo = socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM) except socket.gaierror: print_error("error: cannot resolve", self.host) return for res in addrinfo: try: s = socket.socket(res[0], socket.SOCK_STREAM) s.settimeout(2) s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) s.connect(res[4]) except: s = None continue break if s is None: print_error("failed to connect", self.host, self.port) return if self.use_ssl: try: s = ssl.wrap_socket( s, ssl_version=ssl.PROTOCOL_SSLv3, cert_reqs=ssl.CERT_REQUIRED, ca_certs=(temporary_path if is_new else cert_path), do_handshake_on_connect=True) except ssl.SSLError, e: print_error("SSL error:", self.host, e) if e.errno != 1: return if is_new: rej = cert_path + '.rej' if os.path.exists(rej): os.unlink(rej) os.rename(temporary_path, rej) else: if cert_has_expired(cert_path): print_error("certificate has expired:", cert_path) os.unlink(cert_path) else: print_msg("wrong certificate", self.host) return except Exception: print_error("wrap_socket failed", self.host) traceback.print_exc(file=sys.stdout) return
def handleClose(self): util.print_error("closed", self.address)
def sign(self, private_keys): import deserialize for i in range(len(self.inputs)): txin = self.inputs[i] tx_for_sig = self.serialize(self.inputs, self.outputs, for_sig=i) if txin.get('redeemScript'): # 1 parse the redeem script num, redeem_pubkeys = deserialize.parse_redeemScript( txin.get('redeemScript')) self.inputs[i]["pubkeys"] = redeem_pubkeys # build list of public/private keys keypairs = {} for sec in private_keys.values(): compressed = is_compressed(sec) pkey = regenerate_key(sec) pubkey = GetPubKey(pkey.pubkey, compressed) keypairs[pubkey.encode('hex')] = sec # list of already existing signatures signatures = txin.get("signatures", []) print_error("signatures", signatures) for pubkey in redeem_pubkeys: public_key = ecdsa.VerifyingKey.from_string( pubkey[2:].decode('hex'), curve=SECP256k1) for s in signatures: try: public_key.verify_digest( s.decode('hex')[:-1], Hash(tx_for_sig.decode('hex')), sigdecode=ecdsa.util.sigdecode_der) break except ecdsa.keys.BadSignatureError: continue else: # check if we have a key corresponding to the redeem script if pubkey in keypairs.keys(): # add signature sec = keypairs[pubkey] compressed = is_compressed(sec) pkey = regenerate_key(sec) secexp = pkey.secret private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve=SECP256k1) public_key = private_key.get_verifying_key() sig = private_key.sign_digest( Hash(tx_for_sig.decode('hex')), sigencode=ecdsa.util.sigencode_der) assert public_key.verify_digest( sig, Hash(tx_for_sig.decode('hex')), sigdecode=ecdsa.util.sigdecode_der) signatures.append(sig.encode('hex')) # for p2sh, pubkeysig is a tuple (may be incomplete) self.inputs[i]["signatures"] = signatures print_error("signatures", signatures) self.is_complete = len(signatures) == num else: sec = private_keys[txin['address']] compressed = is_compressed(sec) pkey = regenerate_key(sec) secexp = pkey.secret private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve=SECP256k1) public_key = private_key.get_verifying_key() pkey = EC_KEY(secexp) pubkey = GetPubKey(pkey.pubkey, compressed) sig = private_key.sign_digest( Hash(tx_for_sig.decode('hex')), sigencode=ecdsa.util.sigencode_der) assert public_key.verify_digest( sig, Hash(tx_for_sig.decode('hex')), sigdecode=ecdsa.util.sigdecode_der) self.inputs[i]["pubkeysig"] = [(pubkey, sig)] self.is_complete = True self.raw = self.serialize(self.inputs, self.outputs)