def check_server(self, quick = False, ssl_verify = True): def _do_check_server(timeout, ssl_verify): try: self.port, self.poolSize, connections, pools = query_server_for_stats(self.host, self.info_port, self.ssl, timeout) if self.ssl and ssl_verify and not verify_ssl_socket(self.host, self.port, timeout=timeout): self.print_error("SSL Verification failed") return False self.print_error("Server {}:{} told us that it has shufflePort={} poolSize={} connections={}".format(self.host, self.info_port, self.port, self.poolSize, connections)) return True except BaseException as e: self.print_error("Exception: {}".format(str(e))) self.print_error("Could not query shuffle port for server {}:{} -- defaulting to {}".format(self.host, self.info_port, self.port)) return False finally: self._last_server_check = time.time() # /_do_check_server to_hi, to_lo = self.CHECKER_MAX_TIMEOUT, self.CHECKER_MAX_TIMEOUT/3.0 # 15.0,5.0 secs if quick: to_hi, to_lo = to_hi*0.6, to_lo*0.6 # 9.0, 3.0 seconds respectively timeout = to_hi if (Network.get_instance() and Network.get_instance().get_proxies()) else to_lo if not _do_check_server(timeout = timeout, ssl_verify = ssl_verify): self.logger.send(ERR_SERVER_CONNECT, "MAINLOG") return False else: self.logger.send(MSG_SERVER_OK, "MAINLOG") return True
class TestNetworkFault(unittest.TestCase): def setUp(self): self.config = SimpleConfig() self.network = Network(self.config) self.network.start() def tearDown(self): self.network.stop() def test_000_no_connection(self): address = "1HdGRAJjzsPZrVrJfkFRMjM3jCib7viZgD" self.network.stop() try: res = self.network.synchronous_get(('blockchain.address.listunspent', [address]), timeout=5) self.assertFalse(True) print(res) except BaseException as e: print("Error: {}".format(e)) self.assertFalse(False) def test_001_erorr_message(self): address = "realy fake address" try: res = self.network.synchronous_get(('blockchain.address.listunspent', [address]), timeout=5) self.assertFalse(True) print(res) except BaseException as e: print("Error: {}".format(e)) self.assertFalse(False)
def query_server_for_stats(host: str, stat_port: int, ssl: bool, timeout=None): ''' May raise OSError, ValueError, TypeError if there are connectivity or other issues ''' proxies = (Network.get_instance() and Network.get_instance().get_proxies()) or None if timeout is None: timeout = 3.0 if not proxies else 10.0 secure = "s" if ssl else "" stat_endpoint = "http{}://{}:{}/stats".format(secure, host, stat_port) res = requests.get(stat_endpoint, verify=False, timeout=timeout, proxies=proxies) json = res.json() return int(json["shufflePort"]), int(json["poolSize"]), int( json["connections"]), json['pools']
def verify_ssl_socket(host, port, timeout=5.0): path = (Network.get_instance() and Network.get_instance().config and Network.get_instance().config.path) or None if not path: print_error("verify_ssl_socket: no config path!") return False server = "{}:{}:s".format(host, port) q = queue.Queue() c = Connection(server, q, path) socket = None try: server, socket = q.get(timeout=timeout) except queue.Empty: pass ret = bool(socket and socket.fileno() > -1) if socket: socket.close() del (q, c, socket, server) return ret
def run(self): network = Network.get_instance() if not network: self.notify_offline() return for i, p in enumerate(self.DERIVATION_PATHS): if self.aborting: return k = keystore.from_seed(self.seed, '', derivation=p, seed_type=self.seed_type) p_safe = p.replace('/', '_').replace("'", 'h') storage_path = os.path.join( tempfile.gettempdir(), p_safe + '_' + random.getrandbits(32).to_bytes(4, 'big').hex()[:8] + "_not_saved_") tmp_storage = WalletStorage(storage_path, in_memory_only=True) tmp_storage.put('seed_type', self.seed_type) tmp_storage.put('keystore', k.dump()) wallet = Standard_Wallet(tmp_storage) try: wallet.start_threads(network) wallet.synchronize() wallet.print_error("Scanning", p) synched = False for ctr in range(25): try: wallet.wait_until_synchronized(timeout=1.0) synched = True except TimeoutException: wallet.print_error(f'timeout try {ctr+1}/25') if self.aborting: return if not synched: wallet.print_error("Timeout on", p) self.notify_timedout(i) continue while network.is_connecting(): time.sleep(0.1) if self.aborting: return num_tx = len(wallet.get_history()) self.update_table_cb(i, str(num_tx)) finally: wallet.clear_history() wallet.stop_threads()
def start_protocol(self): "This method starts the protocol thread" coin_utils = CoinUtils(Network.get_instance()) crypto = Crypto() self.messages.clear_packets() begin_phase = 'Announcement' # Make Round self.protocol = Round( coin_utils, crypto, self.messages, self.comm, self.comm, self.logger, self.session, begin_phase, self.amount, self.fee, self.sk, self.sks, self.all_inputs, self.vk, self.players, self.addr_new, self.change, self.coin, total_amount = self.total_amount, fake_change = self.fake_change ) if not self.done.is_set(): self.protocol.start_protocol()
basic_logger = SimpleLogger() args = parse_args() # Get network config = SimpleConfig({}) password = args.password wallet_path = args.wallet storage = WalletStorage(wallet_path) if not storage.file_exists(): basic_logger.send("Error: Wallet file not found.") sys.exit(0) if storage.is_encrypted(): storage.decrypt(password) if args.testnet: NetworkConstants.set_testnet() config = SimpleConfig({'server': "bch0.kister.net:51002:s"}) network = Network(config) network.start() wallet = Wallet(storage) wallet.start_threads(network) coin = Coin(network) # # setup server port = args.port host = args.server stat_port = args.stat_port ssl = args.ssl fee = args.fee secured = ("s" if ssl else "") stat_endpoint = "http{}://{}:{}/stats".format(secured, host, stat_port) schedule.every(args.period).minutes.do(job)
def setUp(self): self.config = SimpleConfig() self.network = Network(self.config) self.network.start()
def is_wallet_ready(self): return bool( self.wallet and self.wallet.is_up_to_date() and self.wallet.network and self.wallet.network.is_connected() and self.wallet.verifier and self.wallet.verifier.is_up_to_date() and self.wallet.synchronizer and self.wallet.synchronizer.is_up_to_date() and Network.get_instance() )
def _make_protocol_thread(self, scale, coins): def get_coin_for_shuffling(scale, coins): if not getattr(self.wallet, "is_coin_shuffled", None): raise RuntimeWarning('Wallet lacks is_coin_shuffled method!') unshuffled_coins = [coin for coin in coins # Note: the 'is False' is intentional -- we are interested in coins that we know for SURE are not shuffled. # is_coin_shuffled() also returns None in cases where the tx isn't in the history (a rare occurrence) if self.wallet.is_coin_shuffled(coin) is False] upper_amount = min(scale*10 + self.FEE, self.UPPER_BOUND) lower_amount = scale + self.FEE unshuffled_coins_on_scale = [coin for coin in unshuffled_coins # exclude coins out of range and 'done' coins still in history # also exclude coinbase coins (see issue #64) if coin['value'] < upper_amount and coin['value'] >= lower_amount and get_name(coin) not in self.done_utxos and not coin['coinbase']] unshuffled_coins_on_scale.sort(key=lambda x: (x['value'], -x['height'])) # sort by value, preferring older coins on tied value if unshuffled_coins_on_scale: return unshuffled_coins_on_scale[-1] # take the largest,oldest on the scale return None # / coin = get_coin_for_shuffling(scale, coins) if not coin: return try: private_key = self.wallet.export_private_key(coin['address'], self.get_password()) except InvalidPassword: # This shouldn't normally happen but can if the user JUST changed their password in the GUI thread # and we didn't yet get informed of the new password. In which case we give up for now and 10 seconds later # (the next 'period' time), this coin will be picked up again. raise RuntimeWarning('Invalid Password caught when trying to export a private key -- if this keeps happening tell the devs!') utxo_name = get_name(coin) self.wallet.set_frozen_coin_state([utxo_name], True) self._coins_busy_shuffling.add(utxo_name) self.wallet.storage.put(COINS_FROZEN_BY_SHUFFLING, list(self._coins_busy_shuffling)) inputs = {} sks = {} public_key = self.wallet.get_public_key(coin['address']) sk = regenerate_key(deserialize_privkey(private_key)[1]) inputs[public_key] = [utxo_name] sks[public_key] = sk id_sk = generate_random_sk() id_pub = id_sk.GetPubKey(True).hex() output = None for address in self.wallet.get_unused_addresses(): if address not in self.wallet._addresses_cashshuffle_reserved: output = address break while not output: address = self.wallet.create_new_address(for_change = False) if address not in self.wallet._addresses_cashshuffle_reserved: output = address # Reserve the output address so other threads don't use it self.wallet._addresses_cashshuffle_reserved.add(output) # NB: only modify this when holding wallet locks # Check if we will really use the change address. We won't be receving to it if the change is below dust threshold (see #67) will_receive_change = coin['value'] - scale - self.FEE >= dust_threshold(Network.get_instance()) if will_receive_change: change = self.wallet.cashshuffle_get_new_change_address(for_shufflethread=True) # We anticipate using the change address in the shuffle tx, so reserve this address self.wallet._addresses_cashshuffle_reserved.add(change) else: # We still have to specify a change address to the protocol even if it won't be used. :/ # We'll just take whatever address. The leftover dust amount will go to fee. change = self.wallet.get_change_addresses()[0] self.print_error("Scale {} Coin {} OutAddr {} {} {} make_protocol_thread".format(scale, utxo_name, output.to_storage_string(), "Change" if will_receive_change else "FakeChange",change.to_storage_string())) #self.print_error("Reserved addresses:", self.wallet._addresses_cashshuffle_reserved) ctimeout = 12.5 if (Network.get_instance() and Network.get_instance().get_proxies()) else 5.0 # allow for 12.5 second connection timeouts if using a proxy server thr = ProtocolThread(host=self.host, port=self.port, ssl=self.ssl, comm_timeout=self.timeout, ctimeout=ctimeout, # comm timeout and connect timeout coin=utxo_name, amount=scale, fee=self.FEE, total_amount=coin['value'], addr_new_addr=output, change_addr=change, fake_change=not will_receive_change, sk=id_sk, sks=sks, inputs=inputs, pubk=id_pub, logger=None) thr.logger = ChannelSendLambda(lambda msg: self.protocol_thread_callback(thr, msg)) self.threads[scale] = thr coins.remove(coin) thr.start() return True
def _make_protocol_thread(self, scale, coins, scale_lower_bound, scale_upper_bound): def get_coin_for_shuffling(scale, coins, scale_lower_bound, scale_upper_bound): upper_bound = min(scale_upper_bound, self.UPPER_BOUND) lower_bound = max(scale_lower_bound, self.LOWER_BOUND) unshuffled_coins_on_scale = [coin for coin in coins # exclude coins out of range and 'done' coins still in history # also exclude coinbase coins (see issue #64) if (coin['value'] < upper_bound and coin['value'] >= lower_bound) ] unshuffled_coins_on_scale.sort(key=lambda x: (x['value'], -x['height'])) # sort by value, preferring older coins on tied value if unshuffled_coins_on_scale: return unshuffled_coins_on_scale[-1] # take the largest,oldest on the scale return None # / coin = get_coin_for_shuffling(scale, coins, scale_lower_bound, scale_upper_bound) if not coin: return try: private_key = self.wallet.export_private_key(coin['address'], self.get_password()) except InvalidPassword: # This shouldn't normally happen but can if the user JUST changed their password in the GUI thread # and we didn't yet get informed of the new password. In which case we give up for now and 10 seconds later # (the next 'period' time), this coin will be picked up again. raise RuntimeWarning('Invalid Password caught when trying to export a private key -- if this keeps happening tell the devs!') utxo_name = CoinUtils.get_name(coin) self.wallet.set_frozen_coin_state([utxo_name], True) self._coins_busy_shuffling.add(utxo_name) self.wallet.storage.put(ConfKeys.PerWallet.COINS_FROZEN_BY_SHUFFLING, list(self._coins_busy_shuffling)) inputs = {} sks = {} public_key = self.wallet.get_public_key(coin['address']) sk = regenerate_key(deserialize_privkey(private_key)[1]) inputs[public_key] = [utxo_name] sks[public_key] = sk id_sk = self.generate_random_sk() id_pub = id_sk.GetPubKey(True).hex() output = self.wallet.cashshuffle_get_new_change_address(for_shufflethread=2) # Check if we will really use the change address. We definitely won't # be receving to it if the change is below dust threshold (see #67). # Furthermore, we may not receive change even if this check predicts we # will due to #68. may_receive_change = coin['value'] - scale - self.FEE >= dust_threshold(Network.get_instance()) if may_receive_change: # We anticipate (maybe) using the change address in the shuffle tx, # so reserve this address. Note that due to "smallest player raises # shuffle amount" rules in version=200+ (#68) we WON'T necessarily # USE this change address. (In that case it will be freed up later # after shuffling anyway so no address leaking occurs). # We just reserve it if we think we MAY need it. change = self.wallet.cashshuffle_get_new_change_address(for_shufflethread=1) else: # We *definitely* won't receive any change no matter who # participates because we are very close to scale. # (The leftover dust amount will go to fee.) # We still have to specify a change address to the protocol even if # it definitely won't be used. :/ # We'll just take a hard-coded address whose private key is the # number 1337 (we do it this way so we don't leak anything # identifying every time we shuffle). # Don't worry: It's 100% guaranteed we won't be using this address. change = self._dummy_address self.print_error("Scale {} Coin {} OutAddr {} {} {} make_protocol_thread".format(scale, utxo_name, output.to_storage_string(), "Change" if may_receive_change else "FakeChange", change.to_storage_string())) #self.print_error("Reserved addresses:", self.wallet._addresses_cashshuffle_reserved) ctimeout = 12.5 if (Network.get_instance() and Network.get_instance().get_proxies()) else 5.0 # allow for 12.5 second connection timeouts if using a proxy server thr = ProtocolThread(host=self.host, port=self.port, ssl=self.ssl, comm_timeout=self.timeout, ctimeout=ctimeout, # comm timeout and connect timeout coin=utxo_name, scale=scale, fee=self.FEE, coin_value=coin['value'], addr_new_addr=output, change_addr=change, sk=id_sk, sks=sks, inputs=inputs, pubk=id_pub, logger=None, version=self.version, typ=self.type) thr.logger = ChannelSendLambda(lambda msg: self.protocol_thread_callback(thr, msg)) cls = type(self) cls.latest_shuffle_settings = cls.ShuffleSettings(thr.type, Messages.TYPE_NAME_DICT[thr.type], thr.version, scale, coin['value'], self.FEE) self.threads[scale] = thr coins.remove(coin) thr.start() return True