Exemplo n.º 1
0
def multisig_to_redeemscript(public_keys, m):

    if m > 16:
        raise ValueError(
            'More than the allowed maximum of 16 public keys cannot be used.')

    redeemscript = int_to_unknown_bytes(m + 80)

    for key in public_keys:
        key_byte = hex_to_bytes(key)
        length = len(key_byte)

        if length not in (33, 65):
            raise ValueError(
                'At least one of the provided public keys is of invalid length {}.'
                .format(length))

        redeemscript += script_push(length) + key_byte

    redeemscript += int_to_unknown_bytes(
        len(public_keys) + 80
    ) + b'\xae'  # Only works for n = len(public_keys) < 17. OK due to P2SH script-length limitation.

    if len(redeemscript) > 520:
        raise ValueError(
            'The redeemScript exceeds the allowed 520-byte limitation with the number of public keys.'
        )

    return redeemscript
Exemplo n.º 2
0
def multisig_to_redeemscript(public_keys, m):

    if m > len(public_keys):
        raise ValueError(
            'Required signatures cannot be more than the total number of public keys.'
        )

    redeemscript = int_to_unknown_bytes(m + 80)

    for key in public_keys:
        length = len(key)

        if length not in (33, 65):
            raise ValueError(
                'At least one of the provided public keys is of invalid length {}.'
                .format(length))

        redeemscript += script_push(length) + key

    redeemscript += (
        int_to_unknown_bytes(len(public_keys) + 80) + b'\xae'
    )  # Only works for n = len(public_keys) < 17. OK due to P2SH script-length limitation.

    if len(redeemscript) > 520:
        raise ValueError(
            'The redeemScript exceeds the allowed 520-byte limitation with the number of public keys.'
        )

    return redeemscript
Exemplo n.º 3
0
def estimate_tx_fee(n_in, n_out, satoshis, compressed):

    if not satoshis:
        return 0

    estimated_size = (n_in * (148 if compressed else 180) +
                      len(int_to_unknown_bytes(n_in, byteorder='little')) +
                      n_out * 34 +
                      len(int_to_unknown_bytes(n_out, byteorder='little')) + 8)

    return estimated_size * satoshis
Exemplo n.º 4
0
def estimate_tx_fee(in_size, n_in, out_size, n_out, satoshis):

    if not satoshis:
        return 0

    estimated_size = (in_size +
                      len(int_to_unknown_bytes(n_in, byteorder='little')) +
                      out_size +
                      len(int_to_unknown_bytes(n_out, byteorder='little')) + 8)

    estimated_fee = estimated_size * satoshis

    logging.debug('Estimated fee: {} satoshis for {} bytes'.format(
        estimated_fee, estimated_size))

    return estimated_fee
Exemplo n.º 5
0
def b58decode(string):

    alphabet = BASE58_ALPHABET

    num = 0
    for char in string:
        num *= 58

        try:
            index = alphabet.index(char)
        except ValueError:
            raise ValueError('"{}" is an invalid base58 encoded '
                             'character.'.format(char)) from None
        num += index

    bytestr = int_to_unknown_bytes(num)

    pad = 0
    for char in string:
        if char == '1':
            pad += 1
        else:
            break

    return b'\x00' * pad + bytestr
Exemplo n.º 6
0
def construct_output_block(outputs):

    output_block = b''

    for data in outputs:
        dest, amount = data

        # Real recipient
        if amount:
            script = (OP_DUP + OP_HASH160 + OP_PUSH_20 +
                      address_to_public_key_hash(dest) + OP_EQUALVERIFY +
                      OP_CHECKSIG)

            output_block += amount.to_bytes(8, byteorder='little')

        # Blockchain storage
        else:
            script = (OP_RETURN + len(dest).to_bytes(1, byteorder='little') +
                      dest)

            output_block += b'\x00\x00\x00\x00\x00\x00\x00\x00'

        output_block += int_to_unknown_bytes(len(script), byteorder='little')
        output_block += script

    return output_block
Exemplo n.º 7
0
def estimate_tx_fee(n_in, n_out, satoshis, compressed):

    if not satoshis:
        return 0

    estimated_size = (n_in * (148 if compressed else 180) +
                      len(int_to_unknown_bytes(n_in, byteorder='little')) +
                      n_out * 34 +
                      len(int_to_unknown_bytes(n_out, byteorder='little')) + 8)

    estimated_fee = estimated_size * satoshis

    logging.debug('Estimated fee: {} satoshis for {} bytes'.format(
        estimated_fee, estimated_size))

    return estimated_fee
Exemplo n.º 8
0
def estimate_tx_fee(in_size, n_in, out_size, n_out, satoshis, segwit=False):

    if not satoshis:
        return 0

    estimated_size = math.ceil(
        in_size + len(int_to_unknown_bytes(n_in, byteorder='little')) +
        out_size + len(int_to_unknown_bytes(n_out, byteorder='little')) + 8
        # Accounting for magic header vBytes ('0001')
        + (0.5 if segwit else 0))

    estimated_fee = estimated_size * satoshis

    logging.debug('Estimated fee: {} satoshis for {} bytes'.format(
        estimated_fee, estimated_size))

    return estimated_fee
Exemplo n.º 9
0
def create_p2pkh_transaction(private_key, unspents, outputs):

    public_key = private_key.public_key
    public_key_len = len(public_key).to_bytes(1, byteorder='little')

    version = VERSION_1
    lock_time = LOCK_TIME
    sequence = SEQUENCE
    hash_type = HASH_TYPE
    input_count = int_to_unknown_bytes(len(unspents), byteorder='little')
    output_count = int_to_unknown_bytes(len(outputs), byteorder='little')
    output_block = construct_output_block(outputs)

    # Optimize for speed, not memory, by pre-computing values.
    inputs = []
    for unspent in unspents:
        script = hex_to_bytes(unspent.script)
        script_len = int_to_unknown_bytes(len(script), byteorder='little')
        txid = hex_to_bytes(unspent.txid)[::-1]
        txindex = unspent.txindex.to_bytes(4, byteorder='little')

        inputs.append(TxIn(script, script_len, txid, txindex))

    for i, txin in enumerate(inputs):

        hashed = sha256(version + input_count +
                        b''.join(ti.txid + ti.txindex + OP_0 + sequence
                                 for ti in islice(inputs, i)) + txin.txid +
                        txin.txindex + txin.script_len + txin.script +
                        sequence +
                        b''.join(ti.txid + ti.txindex + OP_0 + sequence
                                 for ti in islice(inputs, i + 1, None)) +
                        output_count + output_block + lock_time + hash_type)

        signature = private_key.sign(hashed) + b'\x01'

        script_sig = (len(signature).to_bytes(1, byteorder='little') +
                      signature + public_key_len + public_key)

        txin.script = script_sig
        txin.script_len = int_to_unknown_bytes(len(script_sig),
                                               byteorder='little')

    return bytes_to_hex(version + input_count + construct_input_block(inputs) +
                        output_count + output_block + lock_time)
Exemplo n.º 10
0
def make_compliant_sig(signature):
    """Adhere to BIP-62:
    https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki
    """

    r, s = decode_dss_signature(signature)
    s = GROUP_ORDER - s if s > GROUP_ORDER // 2 else s

    r = int_to_unknown_bytes(r)
    s = int_to_unknown_bytes(s)

    if r[0] & 0x80:
        r = b'\x00' + r

    if s[0] & 0x80:
        s = b'\x00' + s

    r = b'\x02' + int_to_unknown_bytes(len(r)) + r
    s = b'\x02' + int_to_unknown_bytes(len(s)) + s

    return b'\x30' + int_to_unknown_bytes(len(r) + len(s)) + r + s
Exemplo n.º 11
0
def b58decode(string):

    alphabet_index = BASE58_ALPHABET_INDEX

    num = 0

    try:
        for char in string:
            num *= 58
            num += alphabet_index[char]
    except KeyError:
        raise ValueError('"{}" is an invalid base58 encoded character.'.format(
            char)) from None

    bytestr = int_to_unknown_bytes(num)

    pad = 0
    for char in string:
        if char == '1':
            pad += 1
        else:
            break

    return b'\x00' * pad + bytestr
Exemplo n.º 12
0
 def test_zero(self):
     assert int_to_unknown_bytes(0) == b'\x00'
Exemplo n.º 13
0
 def test_little(self):
     assert int_to_unknown_bytes(BIG_INT, 'little') == BYTES_LITTLE
Exemplo n.º 14
0
 def test_default(self):
     assert int_to_unknown_bytes(BIG_INT) == BYTES_BIG
Exemplo n.º 15
0
def create_sweep_transaction(private_keys,
                             destination_address,
                             amount=None,
                             currency='satoshi',
                             fee=None,
                             leftover=None,
                             message=None,
                             compressed=True):

    private_key_map = {}
    unspents = []
    for key in private_keys:
        utxos = key.get_unspents()
        unspents += utxos
        for utx in utxos:
            private_key_map[utx.txid] = key

    version = VERSION_1
    lock_time = LOCK_TIME
    sequence = SEQUENCE
    hash_type = HASH_TYPE
    input_count = int_to_unknown_bytes(len(unspents), byteorder='little')

    # Construct the outputs, taking the fee into account
    sum_of_unspents = sum([int(x.amount) for x in unspents])
    amount = amount or sum_of_unspents
    outputs = [(destination_address, sum_of_unspents, currency)]

    unspents, outputs = sanitize_tx_data(unspents,
                                         outputs,
                                         fee or get_fee_cached(),
                                         leftover or private_keys[0].address,
                                         combine=True,
                                         message=message,
                                         compressed=compressed,
                                         sweep=True)

    output_count = int_to_unknown_bytes(len(outputs), byteorder='little')
    output_block = construct_output_block(outputs)

    # Optimize for speed, not memory, by pre-computing values.
    inputs = []
    for unspent in unspents:
        script = hex_to_bytes(unspent.script)
        script_len = int_to_unknown_bytes(len(script), byteorder='little')
        txid = hex_to_bytes(unspent.txid)[::-1]
        txindex = unspent.txindex.to_bytes(4, byteorder='little')

        inputs.append(TxIn(script, script_len, txid, txindex))

    for i, txin in enumerate(inputs):

        hashed = sha256(version + input_count +
                        b''.join(ti.txid + ti.txindex + OP_0 + sequence
                                 for ti in islice(inputs, i)) + txin.txid +
                        txin.txindex + txin.script_len + txin.script +
                        sequence +
                        b''.join(ti.txid + ti.txindex + OP_0 + sequence
                                 for ti in islice(inputs, i + 1, None)) +
                        output_count + output_block + lock_time + hash_type)

        private_key = private_key_map[unspents[i].txid]
        signature = private_key.sign(hashed) + b'\x01'
        public_key = private_key.public_key
        public_key_len = len(public_key).to_bytes(1, byteorder='little')

        script_sig = (len(signature).to_bytes(1, byteorder='little') +
                      signature + public_key_len + public_key)

        txin.script = script_sig
        txin.script_len = int_to_unknown_bytes(len(script_sig),
                                               byteorder='little')

    return bytes_to_hex(version + input_count + construct_input_block(inputs) +
                        output_count + output_block + lock_time)
Exemplo n.º 16
0
def sanitize_tx_data(unspents,
                     outputs,
                     fee,
                     leftover,
                     combine=True,
                     message=None,
                     compressed=True):
    """
    sanitize_tx_data()

    fee is in satoshis per byte.
    """

    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.')

    messages = []
    if message:
        if type(message) == int:
            messages.append((int_to_unknown_bytes(message), 0))
        else:
            messages.append((hex_to_bytes(message), 0))

    # Include return address in output count.
    num_outputs = len(outputs) + len(messages) + 1
    sum_outputs = sum(out[1] for out in outputs)

    total_in = 0

    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