Beispiel #1
0
def address_to_scriptpubkey(address):
    # Raise ValueError if we cannot identify the address.
    get_version(address)
    try:
        version = b58decode_check(address)[:1]
    except ValueError:
        witver, data = segwit_decode(address)
        return segwit_scriptpubkey(witver, data)

    if version == MAIN_PUBKEY_HASH or version == TEST_PUBKEY_HASH:
        return OP_DUP + OP_HASH160 + OP_PUSH_20 + address_to_public_key_hash(
            address) + OP_EQUALVERIFY + OP_CHECKSIG
    elif version == MAIN_SCRIPT_HASH or version == TEST_SCRIPT_HASH:
        return OP_HASH160 + OP_PUSH_20 + address_to_public_key_hash(
            address) + OP_EQUAL
Beispiel #2
0
    def _validate_outputs(self):
        """Validates output addresses."""

        if not self.outputs:
            raise EmptyOutputs()

        # Sanity check: If spending from main-/testnet, then all output addresses must also be for main-/testnet.
        for dest in self.outputs.keys():
            if dest[0] not in supported_out_prefixes:
                raise NotSupportedOutputAddress()

            try:
                vs = get_version(dest)
            except ValueError as err:
                raise InvalidOutputAddress(dest, str(err))
            else:
                if vs and vs != self.requested_net:
                    raise NetworkMismatchOutputAddress(
                        self.source_address,
                        self.source_net,
                        dest,
                        vs,
                        self.requested_net,
                    )

            try:
                self.outputs[dest] = int(self.outputs[dest])
                if self.outputs[dest] < DUST_THRESHOLD:
                    raise ValueError(
                        "Output amount is lower that dust threshold.")
            except ValueError as err:
                raise InvalidOutputAmount(self.outputs[dest], DUST_THRESHOLD,
                                          str(err))
Beispiel #3
0
def sanitize_tx_data(unspents,
                     outputs,
                     fee,
                     leftover,
                     combine=True,
                     message=None,
                     compressed=True,
                     min_change=0,
                     version='main'):
    """
    sanitize_tx_data()
    """

    outputs = outputs.copy()

    for i, output in enumerate(outputs):
        dest, amount, currency = output
        outputs[i] = (dest, currency_to_satoshi_cached(amount, currency))

    if not unspents:
        raise ValueError('Transactions must have at least one unspent.')

    # Temporary storage so all outputs precede messages.
    messages = []

    if message:
        message_chunks = chunk_data(message.encode('utf-8'), MESSAGE_LIMIT)

        for message in message_chunks:
            messages.append((message, 0))

    # Include return address in output count.
    # Calculate output size as a list (including return address).
    output_size = [len(address_to_scriptpubkey(o[0])) + 9 for o in outputs]
    output_size.append(len(messages) * (MESSAGE_LIMIT + 9))
    output_size.append(len(address_to_scriptpubkey(leftover)) + 9)
    sum_outputs = sum(out[1] for out in outputs)

    # Use Branch-and-Bound for coin selection:
    unspents[:], remaining = select_coins(sum_outputs,
                                          fee,
                                          output_size,
                                          min_change=min_change,
                                          consolidate=combine,
                                          unspents=unspents)

    if remaining > 0:
        outputs.append((leftover, remaining))

    # Sanity check: If spending from main-/testnet, then all output addresses must also be for main-/testnet.
    for output in outputs:
        dest, amount = output
        vs = get_version(dest)
        if vs and vs != version:
            raise ValueError('Cannot send to ' + vs + 'net address when '
                             'spending from a ' + version + 'net address.')

    outputs.extend(messages)

    return unspents, outputs
Beispiel #4
0
    def _validate_source_address(self):
        """Validates source_address attr."""

        if not self.source_address:
            raise EmptySourceAddress()

        try:
            self.source_net = get_version(self.source_address)
        except ValueError as err:
            raise InvalidSourceAddress(self.source_address, str(err))
        else:
            if self.source_net != self.requested_net:
                raise NetworkMismatchSourceAddress(self.source_address,
                                                   self.source_net,
                                                   self.requested_net)

        if self.source_address[0] not in supported_in_prefixes:
            raise NotSupportedSourceAddress()
Beispiel #5
0
def get_withdrawal():
    address = request.args.get('address', 0, type=str)
    amount = request.args.get('amount', 0, type=float)
    withdrawal = 'None'
    try:
        check = get_version(address)
        if check == 'test':
            if type(amount) is not float:
                withdrawal = 'error-amount'
            else:
                user = current_user
                balances = Balance.query.filter_by(user_id=user.id).first()
                latest_transfers = Transfer.query.filter_by(user_id=user.id).all()
                db_txs = []
                for transfer in latest_transfers:
                    db_txs.append(transfer.tx_id)
                new_balance_btc = balances.balance_btc - amount
                key = PrivateKeyTestnet('cPvDDZ8XREaxWnZNaZ2V8FeUrZYvwHk8kAMHVaFbFte1QZUuuTur')
                address_balance = key.get_balance()
                txid = key.send([(address, amount, 'btc')])
                if txid not in db_txs:
                    db.session.delete(balances)
                    db.session.commit()
                    transfer = Transfer(tx_type='withdrawal', amount=amount, currency='BTC', tx_id=txid, user_id=user.id)
                    new_balances = Balance(balance_btc=new_balance_btc, balance_usd=balances.balance_usd, user_id=user.id)
                    db.session.add_all([transfer, new_balances])
                    db.session.commit()
                    print(("\nTransfer: {}\nNew balances: {}\n").format(transfer, new_balances))
                    withdrawal = txid
        else:
            withdrawal = 'error-main'
    except ValueError:
        withdrawal = 'error-address'
    if withdrawal in ['error-main', 'error-address']:
        if type(amount) is not float:
            withdrawal = 'error-both'
    return jsonify(result=withdrawal)
Beispiel #6
0
 def test_invalid(self):
     with pytest.raises(ValueError):
         get_version('dg2dNAjuezub6iJVPNML5pW5ZQvtA9ocL')
Beispiel #7
0
 def test_testnet(self):
     assert get_version(BITCOIN_ADDRESS_TEST) == 'test'
     assert get_version(BITCOIN_ADDRESS_TEST_COMPRESSED) == 'test'
Beispiel #8
0
 def test_mainnet(self):
     assert get_version(BITCOIN_ADDRESS) == 'main'
     assert get_version(BITCOIN_ADDRESS_COMPRESSED) == 'main'
Beispiel #9
0
def sanitize_tx_data(unspents,
                     outputs,
                     fee,
                     leftover,
                     combine=True,
                     message=None,
                     compressed=True,
                     version='main'):
    """
    sanitize_tx_data()
    fee is in satoshis per byte.
    """

    outputs = outputs.copy()

    for i, output in enumerate(outputs):
        dest, amount, currency = output

        # Sanity check: If spending from main-/testnet, then all output addresses must also be for main-/testnet.
        if amount:  # ``dest`` could be a text to be stored in the blockchain; but only if ``amount`` is exactly zero.
            vs = get_version(dest)
            if vs and vs != version:
                raise ValueError('Cannot send to ' + vs +
                                 'net address when spending from a ' +
                                 version + 'net address.')

        outputs[i] = (dest, currency_to_satoshi_cached(amount, currency))

    if not unspents:
        raise ValueError('Transactions must have at least one unspent.')

    # Temporary storage so all outputs precede messages.
    messages = []

    if message:
        message_chunks = chunk_data(message.encode('utf-8'), MESSAGE_LIMIT)

        for message in message_chunks:
            messages.append((message, 0))

    # Include return address in fee estimate.

    total_in = 0
    num_outputs = len(outputs) + len(messages) + 1
    sum_outputs = sum(out[1] for out in outputs)

    if combine:
        # calculated_fee is in total satoshis.
        calculated_fee = estimate_tx_fee(len(unspents), num_outputs, fee,
                                         compressed)
        total_out = sum_outputs + calculated_fee
        unspents = unspents.copy()
        total_in += sum(unspent.amount for unspent in unspents)

    else:
        unspents = sorted(unspents, key=lambda x: x.amount)

        index = 0

        for index, unspent in enumerate(unspents):
            total_in += unspent.amount
            calculated_fee = estimate_tx_fee(len(unspents[:index + 1]),
                                             num_outputs, fee, compressed)
            total_out = sum_outputs + calculated_fee

            if total_in >= total_out:
                break

        unspents[:] = unspents[:index + 1]

    remaining = total_in - total_out

    if remaining > 0:
        outputs.append((leftover, remaining))
    elif remaining < 0:
        raise InsufficientFunds('Balance {} is less than {} (including '
                                'fee).'.format(total_in, total_out))

    outputs.extend(messages)

    return unspents, outputs
Beispiel #10
0
 def test_testnet_pay2sh(self):
     assert get_version(BITCOIN_ADDRESS_TEST_PAY2SH) == 'test'
Beispiel #11
0
 def test_mainnet_pay2sh(self):
     assert get_version(BITCOIN_ADDRESS_PAY2SH) == 'main'
Beispiel #12
0
 def test_testnet_pay2sh(self):
     with pytest.raises(ValueError):
         get_version(BITCOIN_ADDRESS_TEST_PAY2SH)
Beispiel #13
0
def is_valid_address(bitcoin_address: str) -> bool:
    try:
        return get_version(bitcoin_address) == settings.btc_network
    except ValueError:
        return False