def create_p2pkh_transaction(utxosets, outputs, custom_pushdata=False):

    version = VERSION_1
    lock_time = LOCK_TIME
    # sequence = SEQUENCE
    hash_type = HASH_TYPE
    unspents = [Unspent.from_dict(utxo) for utxo in utxosets]
    input_count = int_to_varint(len(unspents))
    output_count = int_to_varint(len(outputs))

    output_block = construct_output_block(outputs,
                                          custom_pushdata=custom_pushdata)

    # Optimize for speed, not memory, by pre-computing values.
    inputs = []
    for unspent in unspents:
        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('', 0, 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):
        private_key = bsv(wif=utxosets[i]['PrivateKey'])
        public_key = bytes.fromhex(private_key.public_key)
        public_key_len = len(public_key).to_bytes(1, byteorder='little')

        scriptCode = (OP_DUP + OP_HASH160 + OP_PUSH_20 +
                      address_to_public_key_hash(private_key.address) +
                      OP_EQUALVERIFY + OP_CHECKSIG)
        scriptCode_len = int_to_varint(len(scriptCode))
        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 SV

        # 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_varint(len(script_sig))

    return bytes_to_hex(version + input_count + construct_input_block(inputs) +
                        output_count + output_block + lock_time)
def get_rawtx_to_pay(sighash_single_rawtx, pay_to_address):
    est_size_of_rawHex = len(sighash_single_rawtx['version']) +\
                         len(sighash_single_rawtx['input']) + \
                        len(int_to_varint(2).hex()) + \
                        len(sighash_single_rawtx["output"]) + \
                        len(sighash_single_rawtx['lock_time']) + \
                        16 + 2 + 50   # amount: 8 bytes  script_len: 1 byte  script: 25bytes
    rawtx_single_json = deserialize_input(sighash_single_rawtx['input'])

    input_amount = 0
    for item in rawtx_single_json:
        result = get_tx_by_txid(item['txid'])
        input_amount += int(result['vout'][item['txindex']]['value'] *
                            100000000)
    output_amount = int.from_bytes(
        bytes.fromhex(sighash_single_rawtx['output'][:8]), 'little')

    amount = int(input_amount - output_amount -
                 est_size_of_rawHex / 4)  #fee rate: 0.5sat/B

    output_count = int_to_varint(2)
    output_block = bytes.fromhex(sighash_single_rawtx["output"])
    output_script = (OP_DUP + OP_HASH160 + OP_PUSH_20 +
                     address_to_public_key_hash(pay_to_address) +
                     OP_EQUALVERIFY + OP_CHECKSIG)
    output_block += (amount).to_bytes(8, byteorder='little')  #satoshi
    output_block += int_to_varint(len(output_script))
    output_block += output_script
    rawtx = ''
    rawtx += sighash_single_rawtx['version']
    rawtx += sighash_single_rawtx['input']
    rawtx += output_count.hex()
    rawtx += output_block.hex()
    rawtx += sighash_single_rawtx['lock_time']

    utxoset = {}
    utxoset['txid'] = calc_txid(rawtx)
    utxoset['txindex'] = 1
    utxoset['amount'] = amount
    utxoset['confirmations'] = 0

    return {
        'rawtx': rawtx,
        'utxoset': utxoset,
        'txid': calc_txid(rawtx),
        'amount': amount
    }.copy()
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_varint(n_in)) +
        n_out * 34  # excluding op_return outputs, dealt with separately
        + len(int_to_varint(n_out)) +
        op_return_size  # grand total size of op_return outputs(s) and related field(s)
        + 4  # time lock
    )

    estimated_fee = math.ceil(estimated_size * satoshis)

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

    return estimated_fee
def get_op_return_size(message, custom_pushdata=False):
    # calculate op_return size for each individual message
    if custom_pushdata is False:
        op_return_size = (
            8  # int64_t amount 0x00000000
            + len(OP_FALSE + OP_RETURN)  # 2 bytes
            + len(get_op_pushdata_code(
                message))  # 1 byte if <75 bytes, 2 bytes if OP_PUSHDATA1...
            + len(message)  # Max 220 bytes at present
        )

    if custom_pushdata is True:
        op_return_size = (
            8  # int64_t amount 0x00000000
            + len(OP_FALSE + OP_RETURN)  # 2 bytes
            + len(
                message
            )  # Unsure if Max size will be >220 bytes due to extra OP_PUSHDATA codes...
        )

    # "Var_Int" that preceeds OP_RETURN - 0xdf is max value with current 220 byte limit (so only adds 1 byte)
    op_return_size += len(int_to_varint(op_return_size))
    return op_return_size
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_FALSE + 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_FALSE + 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"
        output_block += int_to_varint(len(script))
        output_block += script

    return output_block
def generate_sighash_single_rawtx(utxosets, changeaddress, authrized_amount):
    unspents = [Unspent.from_dict(utxo) for utxo in utxosets]
    version = VERSION_1
    lock_time = LOCK_TIME
    #sequence = SEQUENCE

    input_count = int_to_varint(len(unspents))

    inputs = []
    total_input_amount = 0
    for unspent in unspents:
        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('', 0, txid, txindex, amount))
        total_input_amount += unspent.amount  #satoshi

    output_count = int_to_varint(1)
    output_block = b''
    output_script = (OP_DUP + OP_HASH160 + OP_PUSH_20 +
                     address_to_public_key_hash(changeaddress) +
                     OP_EQUALVERIFY + OP_CHECKSIG)
    output_block += (total_input_amount - authrized_amount).to_bytes(
        8, byteorder='little')  #satoshi
    output_block += int_to_varint(len(output_script))
    output_block += output_script

    hashPrevouts = double_sha256(b''.join([i.txid + i.txindex
                                           for i in inputs]))
    hashSequence = bytes.fromhex(
        '0000000000000000000000000000000000000000000000000000000000000000')
    # scriptCode_len is part of the script.
    for i, txin in enumerate(inputs):
        if i == 0:
            hashOutputs = double_sha256(output_block)
            hash_type = 0x43.to_bytes(4, byteorder='little')  #sighash single
        else:
            hashOutputs = bytes.fromhex(
                '0000000000000000000000000000000000000000000000000000000000000000'
            )
            hash_type = 0x42.to_bytes(4, byteorder='little')  #sighash none

        private_key = bsv(utxosets[i]['PrivateKey'])
        public_key = bytes.fromhex(private_key.public_key)
        public_key_len = len(public_key).to_bytes(1, byteorder='little')
        scriptCode = (OP_DUP + OP_HASH160 + OP_PUSH_20 +
                      address_to_public_key_hash(private_key.address) +
                      OP_EQUALVERIFY + OP_CHECKSIG)
        scriptCode_len = int_to_varint(len(scriptCode))
        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 SV

        # signature = private_key.sign(hashed) + b'\x01'   sighash ALL  ; single b'\x03' ,NONE b'\x02'
        if i == 0:
            signature = private_key.sign(hashed) + b'\x43'
        else:
            signature = private_key.sign(hashed) + b'\x42'

        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_varint(len(script_sig))

    return {
        "version": bytes_to_hex(version),
        "input": bytes_to_hex(input_count + construct_input_block(inputs)),
        "output": bytes_to_hex(output_block),
        "lock_time": bytes_to_hex(lock_time)
    }