Beispiel #1
0
 def test_sweep(self):
     cmds = MocCommands()
     cmds.wallet.add_address_transaction(120000)
     cmds.wallet.add_address_transaction(120000)
     unspent = []
     for tx in cmds.wallet.transactions.values():
         for output in tx._outputs:
             unspent.append((tx.hash(), output))
     cmds.network = MocNetwork({
         'blockchain.address.listunspent': lambda _: [{
             'tx_hash': tx_hash,
             'tx_pos': 1,
             'address': address,
             'coinbase': False,
             'height': 2,
             'is_claim': False,
             'is_support': False,
             'is_update': False,
             'prevout_hash': 'df303881e9014cce89c7acf55b124372e22979284baa99bb9fa178a9d35c97cb',
             'prevout_n': 0,
             'value': amount
         } for (tx_hash, (type, address, amount)) in unspent]
     })
     destination = cmds.wallet.create_new_address()
     result = cmds.sweep(self.private_key, destination)
     self.assertEqual(True, result['success'])
     sent = Transaction(result['tx'])
     sent.deserialize()
     self.assertEqual(len(sent._outputs), 1)
     self.assertEqual(sent._outputs[0][2], 230000)
Beispiel #2
0
 def test_sweep(self):
     cmds = MocCommands()
     cmds.wallet.add_address_transaction(120000)
     cmds.wallet.add_address_transaction(120000)
     unspent = []
     for tx in cmds.wallet.transactions.values():
         for output in tx._outputs:
             unspent.append((tx.hash(), output))
     cmds.network = MocNetwork({
         'blockchain.address.listunspent':
         lambda _: [{
             'tx_hash': tx_hash,
             'tx_pos': 1,
             'address': address,
             'coinbase': False,
             'height': 2,
             'is_claim': False,
             'is_support': False,
             'is_update': False,
             'prevout_hash':
             'df303881e9014cce89c7acf55b124372e22979284baa99bb9fa178a9d35c97cb',
             'prevout_n': 0,
             'value': amount
         } for (tx_hash, (type, address, amount)) in unspent]
     })
     destination = cmds.wallet.create_new_address()
     result = cmds.sweep(self.private_key, destination)
     self.assertEqual(True, result['success'])
     sent = Transaction(result['tx'])
     sent.deserialize()
     self.assertEqual(len(sent._outputs), 1)
     self.assertEqual(sent._outputs[0][2], 230000)
Beispiel #3
0
 def _get_decoded_tx(self, raw_tx):
     tx = Transaction(raw_tx)
     decoded_tx = {}
     decoded_tx['vout'] = []
     for output in tx.outputs():
         out = {}
         out['value'] = Decimal(output[2]) / Decimal(COIN)
         decoded_tx['vout'].append(out)
     return decoded_tx
Beispiel #4
0
    def make_tx(self,
                coins,
                outputs,
                change_addrs,
                fee_estimator,
                dust_threshold,
                abandon_txid=None):
        '''Select unspent coins to spend to pay outputs.  If the change is
        greater than dust_threshold (after adding the change output to
        the transaction) it is kept, otherwise none is sent and it is
        added to the transaction fee.'''

        # Deterministic randomness from coins
        utxos = [c['prevout_hash'] + str(c['prevout_n']) for c in coins]
        self.p = PRNG(''.join(sorted(utxos)))

        # Copy the ouputs so when adding change we don't modify "outputs"
        tx = Transaction.from_io([], outputs[:])
        # Size of the transaction with no inputs and no change
        base_size = tx.estimated_size()
        spent_amount = tx.output_value()

        claim_coin = None
        if abandon_txid is not None:
            claim_coins = [coin for coin in coins if coin['is_claim']]
            assert len(claim_coins) >= 1
            claim_coin = claim_coins[0]
            spent_amount -= claim_coin['value']
            coins = [coin for coin in coins if not coin['is_claim']]

        def sufficient_funds(buckets):
            '''Given a list of buckets, return True if it has enough
            value to pay for the transaction'''
            total_input = sum(bucket.value for bucket in buckets)
            total_size = sum(bucket.size for bucket in buckets) + base_size
            return total_input >= spent_amount + fee_estimator(total_size)

        # Collect the coins into buckets, choose a subset of the buckets
        buckets = self.bucketize_coins(coins)
        buckets = self.choose_buckets(buckets, sufficient_funds,
                                      self.penalty_func(tx))

        if claim_coin is not None:
            tx.add_inputs([claim_coin])
        tx.add_inputs([coin for b in buckets for coin in b.coins])
        tx_size = base_size + sum(bucket.size for bucket in buckets)

        # This takes a count of change outputs and returns a tx fee;
        # each pay-to-bitcoin-address output serializes as 34 bytes
        def fee(count):
            return fee_estimator(tx_size + count * 34)

        change = self.change_outputs(tx, change_addrs, fee, dust_threshold)
        tx.add_outputs(change)

        log.debug("using %i inputs", len(tx.inputs()))
        log.info("using buckets: %s", [bucket.desc for bucket in buckets])

        return tx
Beispiel #5
0
 def _decode(raw_tx):
     tx = Transaction(raw_tx).deserialize()
     decoded_tx = {}
     for txkey in tx.keys():
         if isinstance(tx[txkey], list):
             decoded_tx[txkey] = []
             for i in tx[txkey]:
                 tmp = {}
                 for k in i.keys():
                     if isinstance(i[k], Decimal):
                         tmp[k] = float(i[k] / 1e8)
                     else:
                         tmp[k] = i[k]
                 decoded_tx[txkey].append(tmp)
         else:
             decoded_tx[txkey] = tx[txkey]
     return decoded_tx
Beispiel #6
0
 def get_input_tx(self, tx_hash):
     # First look up an input transaction in the wallet where it
     # will likely be.  If co-signing a transaction it may not have
     # all the input txs, in which case we ask the network.
     tx = self.transactions.get(tx_hash)
     if not tx:
         request = ('blockchain.transaction.get', [tx_hash])
         # FIXME: what if offline?
         tx = Transaction(self.network.synchronous_get(request))
     return tx
Beispiel #7
0
 def tx_response(self, response):
     params, result = self.parse_response(response)
     if not params:
         return
     tx_hash, tx_height = params
     assert tx_hash == hash_encode(Hash(result.decode('hex')))
     tx = Transaction(result)
     try:
         tx.deserialize()
     except Exception:
         log.info("cannot deserialize transaction, skipping: %s", tx_hash)
         return
     self.wallet.receive_tx_callback(tx_hash, tx, tx_height)
     self.requested_tx.remove((tx_hash, tx_height))
     log.info("received tx %s height: %d bytes: %d", tx_hash, tx_height, len(tx.raw))
     # callbacks
     self.network.trigger_callback('new_transaction', tx)
     if not self.requested_tx:
         self.network.trigger_callback('updated')
Beispiel #8
0
    def make_tx(self, coins, outputs, change_addrs, fee_estimator,
                dust_threshold, abandon_txid=None):
        '''Select unspent coins to spend to pay outputs.  If the change is
        greater than dust_threshold (after adding the change output to
        the transaction) it is kept, otherwise none is sent and it is
        added to the transaction fee.'''

        # Deterministic randomness from coins
        utxos = [c['prevout_hash'] + str(c['prevout_n']) for c in coins]
        self.p = PRNG(''.join(sorted(utxos)))

        # Copy the ouputs so when adding change we don't modify "outputs"
        tx = Transaction.from_io([], outputs[:])
        # Size of the transaction with no inputs and no change
        base_size = tx.estimated_size()
        spent_amount = tx.output_value()

        claim_coin = None
        if abandon_txid is not None:
            claim_coins = [coin for coin in coins if coin['is_claim']]
            assert len(claim_coins) >= 1
            claim_coin = claim_coins[0]
            spent_amount -= claim_coin['value']
            coins = [coin for coin in coins if not coin['is_claim']]

        def sufficient_funds(buckets):
            '''Given a list of buckets, return True if it has enough
            value to pay for the transaction'''
            total_input = sum(bucket.value for bucket in buckets)
            total_size = sum(bucket.size for bucket in buckets) + base_size
            return total_input >= spent_amount + fee_estimator(total_size)

        # Collect the coins into buckets, choose a subset of the buckets
        buckets = self.bucketize_coins(coins)
        buckets = self.choose_buckets(buckets, sufficient_funds,
                                      self.penalty_func(tx))

        if claim_coin is not None:
            tx.add_inputs([claim_coin])
        tx.add_inputs([coin for b in buckets for coin in b.coins])
        tx_size = base_size + sum(bucket.size for bucket in buckets)

        # This takes a count of change outputs and returns a tx fee;
        # each pay-to-bitcoin-address output serializes as 34 bytes
        def fee(count):
            return fee_estimator(tx_size + count * 34)

        change = self.change_outputs(tx, change_addrs, fee, dust_threshold)
        tx.add_outputs(change)

        log.debug("using %i inputs", len(tx.inputs()))
        log.info("using buckets: %s", [bucket.desc for bucket in buckets])

        return tx
Beispiel #9
0
 def tx_response(response):
     params, result = self.parse_response(response)
     if not params:
         log.warning("failed to get %s", txid)
         self.requested_tx.remove((txid, height))
         return
     tx_hash, tx_height = params
     assert tx_hash == hash_encode(Hash(result.decode('hex')))
     tx = Transaction(result)
     try:
         tx.deserialize()
     except Exception:
         log.info("cannot deserialize transaction, skipping: %s", tx_hash)
         return
     self.wallet.receive_tx_callback(tx_hash, tx, tx_height)
     self.requested_tx.remove((tx_hash, tx_height))
     log.info("received tx %s height: %d bytes: %d", tx_hash, tx_height, len(tx.raw))
     # callbacks
     self.network.trigger_callback('new_transaction', tx)
     if not self.requested_tx:
         self.network.trigger_callback('updated')
Beispiel #10
0
 def make_Bucket(desc, coins):
     size = sum(Transaction.estimated_input_size(coin)
                for coin in coins)
     value = sum(coin['value'] for coin in coins)
     return Bucket(desc, size, value, coins)
Beispiel #11
0
 def pubkeys_to_address(self, pubkeys):
     redeem_script = Transaction.multisig_script(sorted(pubkeys), self.m)
     address = hash_160_bytes_to_address(hash_160(redeem_script.decode('hex')), 5)
     return address
Beispiel #12
0
 def redeem_script(self, for_change, n):
     pubkeys = self.get_pubkeys(for_change, n)
     return Transaction.multisig_script(sorted(pubkeys), self.m)
Beispiel #13
0
 def make_Bucket(desc, coins):
     size = sum(
         Transaction.estimated_input_size(coin) for coin in coins)
     value = sum(coin['value'] for coin in coins)
     return Bucket(desc, size, value, coins)
Beispiel #14
0
    def main(self):
        add_menu()
        welcome = 'Use the menu to scan a transaction.'
        droid.fullShow(qr_layout(welcome))
        while True:
            event = droid.eventWait().result
            if not event:
                continue
            elif event["name"] == "key":
                if event["data"]["key"] == '4':
                    if self.qr_data:
                        self.show_qr(None)
                        self.show_title(welcome)
                    else:
                        break

            elif event["name"] == "seed":
                password = self.get_password()
                if password is False:
                    modal_dialog('Error','incorrect password')
                    continue
                seed = wallet.get_mnemonic(password)
                modal_dialog('Your seed is', seed)

            elif event["name"] == "password":
                self.change_password_dialog()

            elif event["name"] == "xpub":
                mpk = wallet.get_master_public_key()
                self.show_qr(mpk)
                self.show_title('master public key')
                droid.setClipboard(mpk)
                droid.makeToast("Master public key copied to clipboard")

            elif event["name"] == "scan":
                r = droid.scanBarcode()
                r = r.result
                if not r:
                    continue
                data = r['extras']['SCAN_RESULT']
                data = base_decode(data.encode('utf8'), None, base=43)
                data = ''.join(chr(ord(b)) for b in data).encode('hex')
                tx = Transaction(data)
                #except:
                #    modal_dialog('Error', 'Cannot parse transaction')
                #    continue
                if not wallet.can_sign(tx):
                    modal_dialog('Error', 'Cannot sign this transaction')
                    continue
                lines = map(lambda x: x[0] + u'\t\t' + format_satoshis(x[1]) if x[1] else x[0], tx.get_outputs())
                if not modal_question('Sign?', '\n'.join(lines)):
                    continue
                password = self.get_password()
                if password is False:
                    modal_dialog('Error','incorrect password')
                    continue
                droid.dialogCreateSpinnerProgress("Signing")
                droid.dialogShow()
                wallet.sign_transaction(tx, password)
                droid.dialogDismiss()
                data = base_encode(str(tx).decode('hex'), base=43)
                self.show_qr(data)
                self.show_title('Signed Transaction')

        droid.makeToast("Bye!")
Beispiel #15
0
 def pubkeys_to_address(self, pubkeys):
     redeem_script = Transaction.multisig_script(sorted(pubkeys), self.m)
     address = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')),
                                      5)
     return address
Beispiel #16
0
 def redeem_script(self, for_change, n):
     pubkeys = self.get_pubkeys(for_change, n)
     return Transaction.multisig_script(sorted(pubkeys), self.m)