Example #1
0
    def check_inputs_for_sufficient_funds_and_return_total(
            self, inputs, amount):
        """
        This function check on blockchain for sufficient funds.

        inputs is a dict with bitcoin pubkeys as a keys
        and list of utxo hashes as values.

        the sum of all utxo values should be greater then amount

        it does as follows:
        1. check utxo list for every pubkey in the dict
        2. check if utxo from inputs are in the utxo list on blockchain for these pubkeys
            2.a return None if there is a utxo from list not in utxo set from blockchain
            2.b return None if utxo in list is not confirmed
        3. return True, total_amt if summary values of utxos are greater then amount and False, None otherwise
           returns None,None on blockchain communication error
        """
        assert amount > 0, "Amount must be > 0!"

        def _utxo_name(x):
            return x['tx_hash'] + ":" + str(x['tx_pos'])

        total = 0
        try:
            for public_key, pk_inputs in inputs.items():
                try:
                    address = Address.from_pubkey(public_key)
                except AddressError:
                    # refuse to accept something that doesn't parse as a pubkey
                    return False, None
                unspent_list = self.getaddressunspent(address)
                utxos = {
                    _utxo_name(utxo): utxo['value']
                    for utxo in unspent_list if utxo.get('height', -1) >
                    0  # all inputs must have at least 1 confirmation
                }
                for utxo in pk_inputs:
                    val = utxos.get(utxo)
                    if val is None:
                        return False, None  # utxo does not exist or was spent
                    total += val
            answer = total >= amount
            if answer:
                return True, total
            return False, total

        except BaseException as e:
            #import traceback
            #traceback.print_exc()
            self.print_error("check_inputs_for_sufficient_funds: ", repr(e))
        return None, None
Example #2
0
 def make_unsigned_transaction(self, amount, fee, all_inputs, outputs,
                               changes):
     ''' make unsigned transaction '''
     dust = self.dust_threshold(
     )  # always 546 for now, but this call is here in case something more sophisticated happens in the future
     coins = {}
     tx_inputs = []
     amounts = {}
     try:
         for player in all_inputs:
             inputs_coins = self.get_coins(all_inputs[player])
             # if there are no coins on input it terminates the process
             if inputs_coins:
                 coins[player] = inputs_coins
             else:
                 return None
     except BaseException as e:
         self.print_error('make_unsigned_transaction:', repr(e))
         return None
     for player, pubkey_utxos in coins.items():
         amounts[player] = 0
         for pubkey, utxos in pubkey_utxos.items():
             for utxo in utxos:
                 utxo['type'] = 'p2pkh'
                 utxo['address'] = Address.from_pubkey(pubkey)
                 utxo['pubkeys'] = [pubkey]
                 utxo['x_pubkeys'] = [pubkey]
                 utxo['prevout_hash'] = utxo['tx_hash']
                 utxo['prevout_n'] = utxo['tx_pos']
                 utxo['signatures'] = [None]
                 utxo['num_sig'] = 1
                 tx_inputs.append(utxo)
                 amounts[player] += utxo['value']
     tx_inputs.sort(key=lambda x: x['prevout_hash'] + str(x["tx_pos"]))
     tx_outputs = [(TYPE_ADDRESS, Address.from_string(output), int(amount))
                   for output in outputs]
     transaction = Transaction.from_io(tx_inputs,
                                       tx_outputs,
                                       sign_schnorr=False)
     tx_changes = [
         (TYPE_ADDRESS, Address.from_string(changes[player]),
          int(amounts[player] - amount - fee)) for player in sorted(changes)
         if Address.is_valid(changes[player]) and int(amounts[player] -
                                                      amount - fee) >= dust
     ]
     transaction.add_outputs(tx_changes)
     return transaction
Example #3
0
 def get_coins(self, inputs):
     coins = {}
     for public_key, utxos in inputs.items():
         address = Address.from_pubkey(public_key)
         coins[public_key] = [
         ]  # FIXME: Should probably use a defaultdict here but maybe we want calling code to fail on KeyError ?
         unspent_list = self.getaddressunspent(address)
         utxo_dicts = {
             "{}:{}".format(utxo["tx_hash"], utxo["tx_pos"]): utxo
             for utxo in unspent_list
         }
         for utxo in utxos:
             utxo_dict = utxo_dicts.get(utxo)
             if utxo_dict:
                 coins[public_key].append(utxo_dict)
             else:
                 # uh-oh.. not found. may have been double-spent in the meantimg or buggy Player peer.
                 return None
     return coins
Example #4
0
 def __init__(self, window, wallet, network_settings,
              period = 10.0, logger = None, password=None, timeout=60.0,
              typ=Messages.DEFAULT  # NB: Only DEFAULT is currently supported
              ):
     super().__init__()
     cls = type(self)
     self.daemon = True
     self.timeout = timeout
     self.version = cls.PROTOCOL_VERSION + (1 if networks.net.TESTNET else 0)
     self.type = typ
     assert self.type == Messages.DEFAULT, "BackgroundShufflingThread currently only supports DEFAULT shuffles"
     cls.latest_shuffle_settings = cls.ShuffleSettings(self.type, Messages.TYPE_NAME_DICT[self.type], self.version, 0, 0, self.FEE)
     # set UPPER_BOUND and LOWER_BOUND from config keys here. Note all instances will see these changes immediately.
     cls.update_lower_and_upper_bound_from_config()
     self.period = period
     self.logger = logger
     self.wallet = wallet
     self.window = window
     self.host = network_settings.get("host", None)
     self.info_port = network_settings.get("info", None)
     self.port = 1337  # default value -- will get set to real value from server's stat port in run() method
     self.poolSize = 3  # default value -- will get set to real value from server's stat port in run() method
     self.banScore = 0  # comes from stats port -- our own personal ban score
     self.banned = False  # comes from stats port. True if our IP is banned (default ban duration: 30 mins)
     self.ssl = network_settings.get("ssl", None)
     self.lock = threading.RLock()
     self.password = password
     self.threads = {scale:None for scale in self.scales}
     self.shared_chan = Channel(switch_timeout=None)  # threads write a 3-tuple here: (killme_flg, thr, msg)
     self.stop_flg = threading.Event()
     self.last_idle_check = 0.0  # timestamp in seconds unix time
     self.done_utxos = dict()
     self._paused = False
     self._coins_busy_shuffling = set()  # 'prevout_hash:n' (name) set of all coins that are currently being shuffled by a ProtocolThread. Both wallet locks should be held to read/write this.
     self._last_server_check = 0.0  # timestamp in seconds unix time
     self._dummy_address = Address.from_pubkey(EC_KEY(number_to_string(1337, generator_secp256k1.order())).get_public_key())  # dummy address
     # below 4 vars are related to the "delayed unreserve address" mechanism as part of the bug #70 & #97 workaround and the complexity created by it..
     self._delayed_unreserve_addresses = dict()  # dict of Address -> time.time() timestamp when its shuffle ended
     self._last_delayed_unreserve_check = 0.0  # timestamp in seconds unix time
     self._delayed_unreserve_check_interval = 60.0  # check these addresses every 60 seconds.
     self._delayed_unreserve_timeout = 600.0  # how long before the delayed-unreserve addresses expire; 10 minutes
Example #5
0
def check_input_electrumx(network, inpcomp):
    """ Check an InputComponent against electrumx service. This can be a bit slow
    since it gets all utxos on that address.

    Returns normally if the check passed. Raises ValidationError if the input is not
    consistent with blockchain (according to server), and raises other exceptions if
    the server times out or gives an unexpected kind of response.
    """
    address = Address.from_pubkey(inpcomp.pubkey)
    prevhash = inpcomp.prev_txid[::-1].hex()
    prevn = inpcomp.prev_index
    sh = address.to_scripthash_hex()
    u = network.synchronous_get(('blockchain.scripthash.listunspent', [sh]), timeout=5)
    for item in u:
        if prevhash == item['tx_hash'] and prevn == item['tx_pos']:
            break
    else:
        raise ValidationError('missing or spent or scriptpubkey mismatch')

    check(item['height'] > 0, 'not confirmed')
    check(item['value'] == inpcomp.amount, 'amount mismatch')