Exemplo n.º 1
0
def create_p2pkh_transaction(private_key,
                             unspents,
                             outputs,
                             custom_pushdata=False):

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

    scriptCode = private_key.scriptcode
    scriptCode_len = int_to_varint(len(scriptCode))

    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,
                                          custom_pushdata=custom_pushdata)

    # 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")
        amount = unspent.amount.to_bytes(8, byteorder="little")

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

    hashPrevouts = double_sha256(b"".join([i.txid + i.txindex
                                           for i in inputs]))
    hashSequence = double_sha256(b"".join([SEQUENCE for i in inputs]))
    hashOutputs = double_sha256(output_block)

    # scriptCode_len is part of the script.
    for i, txin in enumerate(inputs):
        to_be_hashed = (version + hashPrevouts + hashSequence + txin.txid +
                        txin.txindex + scriptCode_len + scriptCode +
                        txin.amount + SEQUENCE + hashOutputs + lock_time +
                        hash_type)
        hashed = sha256(to_be_hashed)  # BIP-143: Used for Bitcoin Cash

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

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

        inputs[i].script = script_sig
        inputs[i].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.º 2
0
def _tx_out_boilerplate(tx_in, unlocking_script, output_block):
    tx_in.script = unlocking_script
    tx_in.script_len = int_to_unknown_bytes(len(unlocking_script),
                                            byteorder='little')

    input_count = int_to_unknown_bytes(1, byteorder='little')
    output_count = int_to_unknown_bytes(1, byteorder='little')
    return bytes_to_hex(VERSION_1 + input_count +
                        construct_input_block([tx_in]) + output_count +
                        output_block + LOCK_TIME)
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(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.º 5
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.º 6
0
def arcula_locking_script(cold_storage_key: ecdsa.VerifyingKey,
                          identifier: bytes) -> bytes:
    """Create an Arcula locking script for `cold_storage_key` and `identifier`."""
    cold_storage_key = encode.verification_key_to_bytes_33(cold_storage_key)
    cold_storage_key = int_to_unknown_bytes(
        len(cold_storage_key)) + cold_storage_key
    identifier = int_to_unknown_bytes(len(identifier)) + identifier

    # Bitcoin OP codes
    OP_CHECKSIG = b'\xac'
    OP_DUP = b'\x76'
    OP_CAT = b'\x7e'
    OP_TOALTSTACK = b'\x6b'
    OP_FROMALTSTACK = b'\x6c'
    OP_CHECKDATASIGVERIFY = b'\xbb'

    return OP_DUP + OP_TOALTSTACK + identifier + OP_CAT + cold_storage_key + \
        OP_CHECKDATASIGVERIFY + OP_FROMALTSTACK + OP_CHECKSIG
Exemplo n.º 7
0
def estimate_tx_fee(n_in, n_out, satoshis, compressed, op_return_size=0):

    if not satoshis:
        return 0

    estimated_size = (
        4 + n_in * (148 if compressed else 180)  # version
        + len(int_to_unknown_bytes(n_in, byteorder="little")) +
        n_out * 34  # excluding op_return outputs, dealt with separately
        + len(int_to_unknown_bytes(n_out, byteorder="little")) +
        op_return_size  # grand total size of op_return outputs(s) and related field(s)
        + 4  # time lock
    )

    estimated_fee = estimated_size * satoshis

    logging.debug(
        f"Estimated fee: {estimated_fee} satoshis for {estimated_size} bytes")

    return estimated_fee
Exemplo n.º 8
0
def _create_pkh2apkh_transaction(private_key, unspent, output):
    """Create a PublicKeyHash2ArculaPublicKeyHash transaction."""
    script_code = private_key.scriptcode
    tx_in, hashed, output_block = _tx_in_boilerplate(
        unspent, output, script_code, _construct_arcula_output_block)
    signature = private_key.sign(hashed) + b'\x41'

    public_key = private_key.public_key
    public_key_len = len(public_key).to_bytes(1, byteorder='little')
    unlocking_script = (
        int_to_unknown_bytes(len(signature), byteorder='little') + signature +
        public_key_len + public_key)

    return _tx_out_boilerplate(tx_in, unlocking_script, output_block)
Exemplo n.º 9
0
def _construct_arcula_output_block(outputs):
    """Construct an Arcula output."""
    assert len(outputs) == 1
    output_block = b''

    for data in outputs:
        (dest, i), amount = data
        assert amount

        script = arcula_locking_script(dest, i)
        output_block += amount.to_bytes(8, byteorder='little')

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

    return output_block
Exemplo n.º 10
0
def _tx_in_boilerplate(unspent, output, script_code, construct_output_block_f):
    script = hex_to_bytes(unspent.script)
    script_len = int_to_unknown_bytes(len(script), byteorder='little')
    tx_id = hex_to_bytes(unspent.txid)[::-1]
    tx_index = unspent.txindex.to_bytes(4, byteorder='little')
    amount = unspent.amount.to_bytes(8, byteorder='little')
    tx_in = TxIn(script, script_len, tx_id, tx_index, amount)

    hash_previous_outputs = double_sha256(tx_id + tx_index)
    hash_sequence = double_sha256(SEQUENCE)

    output_block = construct_output_block_f([output])
    hash_outputs = double_sha256(output_block)

    to_be_hashed = (VERSION_1 + hash_previous_outputs + hash_sequence +
                    tx_in.txid + tx_in.txindex +
                    int_to_varint(len(script_code)) + script_code +
                    tx_in.amount + SEQUENCE + hash_outputs + LOCK_TIME +
                    HASH_TYPE)
    hashed = sha256(to_be_hashed)  # BIP-143: Used for Bitcoin Cash
    return tx_in, hashed, output_block
Exemplo n.º 11
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:
            values_bytes = b''
            split_length = 10
            info = [
                dest[i:i + split_length]
                for i in range(0, len(dest), split_length)
            ]
            for message in info:
                messagebytes = message.encode('utf-8')
                len_message_bytes = len(messagebytes).to_bytes(
                    1, byteorder='little')
                _values = (len_message_bytes + messagebytes).hex()
                values_bytes += bytes.fromhex(_values)

            data_bytes = values_bytes

            script = (OP_RETURN + data_bytes)

            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.º 12
0
def construct_output_block(outputs, custom_pushdata=False):

    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:
            if custom_pushdata is False:
                script = OP_RETURN + get_op_pushdata_code(dest) + dest

                output_block += b"\x00\x00\x00\x00\x00\x00\x00\x00"

            elif custom_pushdata is True:
                # manual control over number of bytes in each batch of pushdata
                if type(dest) != bytes:
                    raise TypeError("custom pushdata must be of type: bytes")
                else:
                    script = OP_RETURN + dest

                output_block += b"\x00\x00\x00\x00\x00\x00\x00\x00"

        # Script length in wiki is "Var_int" but there's a note of "modern BitcoinQT" using a more compact "CVarInt"
        # CVarInt is what I believe we have here - No changes made. If incorrect - only breaks if 220 byte limit is increased.
        output_block += int_to_unknown_bytes(len(script), byteorder="little")
        output_block += script

    return output_block
Exemplo n.º 13
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(f'"{char}" is an invalid base58 encoded '
                         "character.") 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.º 14
0
 def test_zero(self):
     assert int_to_unknown_bytes(0) == b"\x00"
Exemplo n.º 15
0
 def test_little(self):
     assert int_to_unknown_bytes(BIG_INT, "little") == BYTES_LITTLE
Exemplo n.º 16
0
 def test_default(self):
     assert int_to_unknown_bytes(BIG_INT) == BYTES_BIG