Esempio 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)
Esempio n. 2
0
def estimate_tx_fee(n_in, n_out, satoshis, compressed, op_return_size=0):

    if not satoshis:
        return 0

    estimated_size = (
        4 +  # version
        n_in * (148 if compressed else 180) +
        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('Estimated fee: {} satoshis for {} bytes'.format(
        estimated_fee, estimated_size))

    return estimated_fee
Esempio n. 3
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
Esempio n. 4
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
Esempio n. 5
0
 def test_zero(self):
     assert int_to_unknown_bytes(0) == b'\x00'
Esempio n. 6
0
 def test_little(self):
     assert int_to_unknown_bytes(BIG_INT, 'little') == BYTES_LITTLE
Esempio n. 7
0
 def test_default(self):
     assert int_to_unknown_bytes(BIG_INT) == BYTES_BIG