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 create_pushdata(lst_of_pushdata):
    """
    Creates encoded OP_RETURN pushdata as bytes Returns binary encoded OP_RETURN pushdata (automatically adds
    intervening OP_CODES specifying number of bytes in each pushdata element) 0x6a (i.e. OP_RETURN) is added in
    other, auxiliary functions; only pushdata is returned here. Max 220 bytes of pushdata

    Parameters
    ----------
    lst_of_pushdata : a list of tuples (pushdata, encoding) where encoding is either "hex" or "utf-8"

    Returns
    -------
    pushdata : bytes

    Examples
    --------

    lst_of_pushdata =  [('6d01', 'hex'),
                        ('bitPUSHER', 'utf-8')]

    as per memo.cash protocol @ https://memo.cash/protocol this results in a "Set name" action to "bitPUSHER"

    raw OP_RETURN will be:

        0e 6a 02 6d01 09 626974505553484552

            0e                  - 14 bytes to follow (in hex)
            6a                  - OP_RETURN
            02                  - 2 bytes of pushdata to follow
            6d01                - "communication channel" for memo.cash - "set name" action
            09                  - 9 bytes to follow
            626974505553484552  - "bitPUSHER" utf-8 encoded bytes --> hex representation

    Currently (this module) only allows up to 220 bytes maximum - as multiple OP_RETURNS in one transaction is
    considered non-standard."""

    pushdata = b''

    for i in range(len(lst_of_pushdata)):

        encoding = lst_of_pushdata[i][1]
        if encoding == 'utf-8':
            pushdata += get_op_pushdata_code(
                lst_of_pushdata[i][0]) + lst_of_pushdata[i][0].encode('utf-8')

        elif encoding == 'hex' and len(lst_of_pushdata[i][0]) % 2 != 0:
            raise ValueError(
                "hex encoded pushdata must have length = a multiple of two")

        elif encoding == 'hex' and len(lst_of_pushdata[i][0]) % 2 == 0:
            hex_data_as_bytes = utils.hex_to_bytes(lst_of_pushdata[i][0])
            pushdata += get_op_pushdata_code(
                hex_data_as_bytes) + hex_data_as_bytes

    # check for size
    if len(pushdata) > 220:
        raise ValueError(
            "Total bytes in OP_RETURN cannot exceed 220 bytes at present - apologies"
        )

    return pushdata
Exemplo n.º 3
0
def calc_txid(tx_hex):
    return bytes_to_hex(double_sha256(hex_to_bytes(tx_hex))[::-1])
Exemplo n.º 4
0
def test_construct_input_block():
    assert construct_input_block(INPUTS) == hex_to_bytes(INPUT_BLOCK)
Exemplo n.º 5
0
 def test_pushdata_message(self):
     BYTES = len(b'hello').to_bytes(1, byteorder='little') + b'hello'
     assert construct_output_block(OUTPUTS + [(BYTES, 0)],
                                   custom_pushdata=True) == hex_to_bytes(
                                       OUTPUT_BLOCK_MESSAGE_PUSHDATA)
Exemplo n.º 6
0
 def test_message(self):
     assert construct_output_block(OUTPUTS + MESSAGES) == hex_to_bytes(
         OUTPUT_BLOCK_MESSAGES)
Exemplo n.º 7
0
 def test_no_message(self):
     assert construct_output_block(OUTPUTS) == hex_to_bytes(OUTPUT_BLOCK)
Exemplo n.º 8
0
def test_hex_to_bytes():
    assert hex_to_bytes(HEX) == BYTES_BIG
    assert hex_to_bytes(ODD_HEX) == ODD_HEX_BYTES