Ejemplo n.º 1
0
 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)
Ejemplo n.º 3
0
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']
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
    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()
Ejemplo n.º 6
0
 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()
Ejemplo n.º 7
0
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()
Ejemplo n.º 9
0
 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() )
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
    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