Esempio n. 1
0
    def test_no_combine_mainnet_with_testnet(self):
        unspents = [Unspent(20000, 0, '', '', 0)]
        outputs = [(BITCOIN_ADDRESS, 500, 'satoshi'),
                   (BITCOIN_ADDRESS_TEST, 500, 'satoshi')]

        with pytest.raises(ValueError):
            sanitize_tx_data(
                unspents,
                outputs,
                fee=50,
                leftover=RETURN_ADDRESS,  # leftover is a testnet-address
                combine=False,
                message=None,
                version='main',
            )

        with pytest.raises(ValueError):
            sanitize_tx_data(
                unspents,
                outputs,
                fee=50,
                leftover=BITCOIN_ADDRESS,  # leftover is a mainnet-address
                combine=False,
                message=None,
                version='main',
            )
Esempio n. 2
0
    def test_no_combine_with_fee(self):
        """
        Verify that unused unspents do not increase fee.
        """
        unspents_single = [Unspent(5000, 0, '', '', 0)]
        unspents_original = [
            Unspent(5000, 0, '', '', 0),
            Unspent(5000, 0, '', '', 0)
        ]
        outputs_original = [(RETURN_ADDRESS, 1000, 'satoshi')]

        unspents, outputs = sanitize_tx_data(unspents_original,
                                             outputs_original,
                                             fee=1,
                                             leftover=RETURN_ADDRESS,
                                             combine=False,
                                             message=None)

        unspents_single, outputs_single = sanitize_tx_data(
            unspents_single,
            outputs_original,
            fee=1,
            leftover=RETURN_ADDRESS,
            combine=False,
            message=None)

        assert unspents == [Unspent(5000, 0, '', '', 0)]
        assert unspents_single == [Unspent(5000, 0, '', '', 0)]
        assert len(outputs) == 2
        assert len(outputs_single) == 2
        assert outputs[1][0] == RETURN_ADDRESS
        assert outputs_single[1][0] == RETURN_ADDRESS
        assert outputs[1][1] == outputs_single[1][1]
Esempio n. 3
0
    def test_no_combine_insufficient_funds(self):
        unspents_original = [Unspent(1000, 0, '', '', 0),
                             Unspent(1000, 0, '', '', 0)]
        outputs_original = [(BITCOIN_ADDRESS_TEST, 2500, 'satoshi')]

        with pytest.raises(InsufficientFunds):
            sanitize_tx_data(
                unspents_original, outputs_original, fee=50, leftover=RETURN_ADDRESS,
                combine=False, message=None
            )
Esempio n. 4
0
    def test_fee_applied(self):
        unspents_original = [Unspent(1000, 0, '', '', 0),
                             Unspent(1000, 0, '', '', 0)]
        outputs_original = [(BITCOIN_ADDRESS, 2000, 'satoshi')]

        with pytest.raises(InsufficientFunds):
            sanitize_tx_data(
                unspents_original, outputs_original, fee=1, leftover=RETURN_ADDRESS,
                combine=True, message=None
            )
Esempio n. 5
0
 def test_outputs_pay2sh_testnet(self):
     amount = b'\x01\x00\x00\x00\x00\x00\x00\x00'
     _, outputs = sanitize_tx_data(
         UNSPENTS, [(BITCOIN_ADDRESS_TEST_PAY2SH, 1, 'satoshi')], 0, RETURN_ADDRESS, version='test'
     )
     outs = construct_outputs(outputs)
     assert len(outs) == 2 and outs[0].amount == amount and outs[0].script_pubkey.hex() == 'a914' + PAY2SH_TEST_HASH.hex() + '87'
Esempio n. 6
0
    def test_no_combine_with_absolute_fee(self):
        # Based on simplifications branch_and_bound roughly reduces
        # to this formula with one input
        # amount + overhead*fee <= unspent - unspent.vsize*fee < amount + overhead*fee + input*fee + output*fee
        # amount + 40*fee <= unspent - 148*fee < amount + 40*fee + 182*fee
        # amount <= unspent - 188*fee < amount + 182*fee

        fee = 8000
        unspents_original = [Unspent(2000000, 0, '', '', 0)]
        outputs_original = [(BITCOIN_ADDRESS_TEST, 100000, 'satoshi')]

        unspents, outputs = sanitize_tx_data(
            unspents_original,
            outputs_original,
            fee=fee,
            absolute_fee=True,
            leftover=RETURN_ADDRESS,
            combine=False,
            message=None,
            version='test',
        )

        assert unspents == unspents_original
        assert len(outputs) == 2
        assert sum(u.amount for u in unspents) - sum(o[1]
                                                     for o in outputs) == fee
Esempio n. 7
0
    def prepare_transaction(cls,
                            address,
                            outputs,
                            compressed=True,
                            fee=None,
                            leftover=None,
                            combine=True,
                            message=None,
                            unspents=None):
        """Prepares a P2PKH transaction for offline signing.

        :param address: The address the funds will be sent from.
        :type address: ``str``
        :param outputs: A sequence of outputs you wish to send in the form
                        ``(destination, amount, currency)``. The amount can
                        be either an int, float, or string as long as it is
                        a valid input to ``decimal.Decimal``. The currency
                        must be :ref:`supported <supported currencies>`.
        :type outputs: ``list`` of ``tuple``
        :param compressed: Whether or not the ``address`` corresponds to a
                           compressed public key. This influences the fee.
        :type compressed: ``bool``
        :param fee: The number of satoshi per byte to pay to miners. By default
                    Bit will poll `<https://bitcoinfees.21.co>`_ and use a fee
                    that will allow your transaction to be confirmed as soon as
                    possible.
        :type fee: ``int``
        :param leftover: The destination that will receive any change from the
                         transaction. By default Bit will send any change to
                         the same address you sent from.
        :type leftover: ``str``
        :param combine: Whether or not Bit should use all available UTXOs to
                        make future transactions smaller and therefore reduce
                        fees. By default Bit will consolidate UTXOs.
        :type combine: ``bool``
        :param message: A message to include in the transaction. This will be
                        stored in the blockchain forever. Due to size limits,
                        each message will be stored in chunks of 40 bytes.
        :type message: ``str``
        :param unspents: The UTXOs to use as the inputs. By default Bit will
                         communicate with the blockchain itself.
        :type unspents: ``list`` of :class:`~bit.network.meta.Unspent`
        :returns: JSON storing data required to create an offline transaction.
        :rtype: ``str``
        """
        unspents, outputs = sanitize_tx_data(
            unspents or NetworkAPI.get_unspent_testnet(address),
            outputs,
            fee or get_fee_cached(),
            leftover or address,
            combine=combine,
            message=message,
            compressed=compressed)

        data = {
            'unspents': [unspent.to_dict() for unspent in unspents],
            'outputs': outputs
        }

        return json.dumps(data, separators=(',', ':'))
Esempio n. 8
0
 def test_long_message(self):
     amount = b'\x00\x00\x00\x00\x00\x00\x00\x00'
     _, outputs = sanitize_tx_data(
         UNSPENTS, [(out[0], out[1], 'satoshi') for out in OUTPUTS], 0, RETURN_ADDRESS,
         message='hello'*9, version='test'
     )
     outs = construct_outputs(outputs)
     assert len(outs) == 5 and outs[3].amount == amount and outs[4].amount == amount
Esempio n. 9
0
 def test_outputs_pay2sh(self):
     amount = b'\x01\x00\x00\x00\x00\x00\x00\x00'
     _, outputs = sanitize_tx_data(UNSPENTS,
                                   [(BITCOIN_ADDRESS_PAY2SH, 1, 'satoshi')],
                                   0, RETURN_ADDRESS_MAIN)
     outs = construct_outputs(outputs)
     assert len(outs) == 2 and outs[0].value == amount and outs[
         0].script.hex() == 'a914' + BITCOIN_HASH_PAY2SH + '87'
Esempio n. 10
0
 def test_long_message(self):
     amount = b'\x00\x00\x00\x00\x00\x00\x00\x00'
     _, outputs = sanitize_tx_data(UNSPENTS, [(out[0], out[1], 'satoshi')
                                              for out in OUTPUTS],
                                   0,
                                   RETURN_ADDRESS,
                                   message='hello' * 9)
     assert construct_output_block(outputs).count(amount) == 2
Esempio n. 11
0
 def test_outputs_pay2segwit_testnet(self):
     amount = b'\x01\x00\x00\x00\x00\x00\x00\x00'
     _, outputs = sanitize_tx_data(
         UNSPENTS, [(BITCOIN_SEGWIT_ADDRESS_TEST, 1, 'satoshi'), (BITCOIN_SEGWIT_ADDRESS_TEST_PAY2SH, 1, 'satoshi')], 0, RETURN_ADDRESS, version='test'
     )
     outs = construct_outputs(outputs)
     assert len(outs) == 3 and outs[0].amount == amount and outs[0].script_pubkey.hex() == '0014' + BITCOIN_SEGWIT_HASH_TEST
     assert outs[1].amount == amount and outs[1].script_pubkey.hex() == '0020' + BITCOIN_SEGWIT_HASH_TEST_PAY2SH
Esempio n. 12
0
 def test_outputs_pay2segwit(self):
     amount = b'\x01\x00\x00\x00\x00\x00\x00\x00'
     _, outputs = sanitize_tx_data(
         UNSPENTS, [(BITCOIN_SEGWIT_ADDRESS, 1, 'satoshi'),
                    (BITCOIN_SEGWIT_ADDRESS_PAY2SH, 1, 'satoshi')], 0,
         RETURN_ADDRESS_MAIN)
     outs = construct_outputs(outputs)
     assert len(outs) == 3 and outs[0].value == amount and outs[
         0].script.hex() == '0014' + BITCOIN_SEGWIT_HASH
     assert outs[1].value == amount and outs[1].script.hex(
     ) == '0020' + BITCOIN_SEGWIT_HASH_PAY2SH
Esempio n. 13
0
    def test_zero_remaining(self):
        unspents_original = [Unspent(1000, 0, '', '', 0),
                             Unspent(1000, 0, '', '', 0)]
        outputs_original = [(BITCOIN_ADDRESS_TEST, 2000, 'satoshi')]

        unspents, outputs = sanitize_tx_data(
            unspents_original, outputs_original, fee=0, leftover=RETURN_ADDRESS,
            combine=True, message=None, version='test'
        )

        assert unspents == unspents_original
        assert outputs == [(BITCOIN_ADDRESS_TEST, 2000)]
Esempio n. 14
0
    def test_message(self):
        unspents_original = [Unspent(10000, 0, '', '', 0),
                             Unspent(10000, 0, '', '', 0)]
        outputs_original = [(BITCOIN_ADDRESS_TEST, 1000, 'satoshi')]

        unspents, outputs = sanitize_tx_data(
            unspents_original, outputs_original, fee=5, leftover=RETURN_ADDRESS,
            combine=True, message='hello', version='test'
        )

        assert len(outputs) == 3
        assert outputs[2][0] == b'hello'
        assert outputs[2][1] == 0
Esempio n. 15
0
    def test_no_combine_remaining(self):
        unspents_original = [Unspent(7000, 0, '', '', 0),
                             Unspent(3000, 0, '', '', 0)]
        outputs_original = [(BITCOIN_ADDRESS_TEST, 2000, 'satoshi')]

        unspents, outputs = sanitize_tx_data(
            unspents_original, outputs_original, fee=0, leftover=RETURN_ADDRESS,
            combine=False, message=None, version='test'
        )

        assert(len(unspents)) == 1
        assert len(outputs) == 2
        assert outputs[1][0] == RETURN_ADDRESS
        assert outputs[1][1] == unspents[0].amount - 2000
Esempio n. 16
0
    def test_no_combine_remaining(self):
        unspents_original = [Unspent(7000, 0, '', '', 0),
                             Unspent(3000, 0, '', '', 0)]
        outputs_original = [('test', 2000, 'satoshi')]

        unspents, outputs = sanitize_tx_data(
            unspents_original, outputs_original, fee=0, leftover=RETURN_ADDRESS,
            combine=False, message=None
        )

        assert unspents == [Unspent(3000, 0, '', '', 0)]
        assert len(outputs) == 2
        assert outputs[1][0] == RETURN_ADDRESS
        assert outputs[1][1] == 1000
Esempio n. 17
0
    def create_transaction(self,
                           outputs,
                           fee=None,
                           leftover=None,
                           combine=True,
                           message=None,
                           unspents=None):
        """Creates a signed P2PKH transaction.

        :param outputs: A sequence of outputs you wish to send in the form
                        ``(destination, amount, currency)``. The amount can
                        be either an int, float, or string as long as it is
                        a valid input to ``decimal.Decimal``. The currency
                        must be :ref:`supported <supported currencies>`.
        :type outputs: ``list`` of ``tuple``
        :param fee: The number of satoshi per byte to pay to miners. By default
                    Bit will poll `<https://bitcoinfees.21.co>`_ and use a fee
                    that will allow your transaction to be confirmed as soon as
                    possible.
        :type fee: ``int``
        :param leftover: The destination that will receive any change from the
                         transaction. By default Bit will send any change to
                         the same address you sent from.
        :type leftover: ``str``
        :param combine: Whether or not Bit should use all available UTXOs to
                        make future transactions smaller and therefore reduce
                        fees. By default Bit will consolidate UTXOs.
        :type combine: ``bool``
        :param message: A message to include in the transaction. This will be
                        stored in the blockchain forever. Due to size limits,
                        each message will be stored in chunks of 40 bytes.
        :type message: ``str``
        :param unspents: The UTXOs to use as the inputs. By default Bit will
                         communicate with the testnet blockchain itself.
        :type unspents: ``list`` of :class:`~bit.network.meta.Unspent`
        :returns: The signed transaction as hex.
        :rtype: ``str``
        """

        unspents, outputs = sanitize_tx_data(unspents or self.unspents,
                                             outputs,
                                             fee or get_fee_cached(),
                                             leftover or self.address,
                                             combine=combine,
                                             message=message,
                                             compressed=self.is_compressed())

        return create_p2pkh_transaction(self, unspents, outputs)
Esempio n. 18
0
    def test_combine_remaining(self):
        unspents_original = [
            Unspent(1000, 0, '', '', 0),
            Unspent(1000, 0, '', '', 0)
        ]
        outputs_original = [(BITCOIN_ADDRESS, 500, 'satoshi')]

        unspents, outputs = sanitize_tx_data(unspents_original,
                                             outputs_original,
                                             fee=0,
                                             leftover=RETURN_ADDRESS_MAIN,
                                             combine=True,
                                             message=None)

        assert unspents == unspents_original
        assert len(outputs) == 2
        assert outputs[1][0] == RETURN_ADDRESS_MAIN
        assert outputs[1][1] == 1500
Esempio n. 19
0
    def test_no_combine_remaining_small_inputs(self):
        unspents_original = [
            Unspent(1500, 0, '', '', 0),
            Unspent(1600, 0, '', '', 0),
            Unspent(1700, 0, '', '', 0)
        ]
        outputs_original = [(RETURN_ADDRESS_MAIN, 2000, 'satoshi')]

        unspents, outputs = sanitize_tx_data(unspents_original,
                                             outputs_original,
                                             fee=0,
                                             leftover=RETURN_ADDRESS_MAIN,
                                             combine=False,
                                             message=None)
        assert unspents == [
            Unspent(1500, 0, '', '', 0),
            Unspent(1600, 0, '', '', 0)
        ]
        assert len(outputs) == 2
        assert outputs[1][0] == RETURN_ADDRESS_MAIN
        assert outputs[1][1] == 1100
Esempio n. 20
0
 def test_no_input(self):
     with pytest.raises(ValueError):
         sanitize_tx_data([], [], 70, '')