Example #1
0
    def deserialize_message_header(cls, header):
        global checksum
        stream = io.BytesIO(header)

        magic = ut.bytes_to_hex(stream.read(4))
        command = stream.read(12).decode('ascii').strip('\x00')
        length = bitcoinx.read_le_uint32(stream.read)
        try:
            checksum = ut.bytes_to_hex(stream.read(4))
            decoded_header = {'magic': magic,
                              'command': command,
                              'length': length,
                              'checksum': checksum, }
            return decoded_header
        except Exception as e:
            print(e)
            print('reading in checksum failed...')
Example #2
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)
Example #3
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)
Example #4
0
    def deserialize_reject(cls, f):
        message = bitcoinx.packing.read_varbytes(f.read)
        ccode = f.read(1)
        reason = bitcoinx.packing.read_varbytes(f.read)
        # TODO different ccodes will / won't have "extra data" add mapping to CCODES in simple_spv.constants
        # data = bitcoinx.packing.read_varbytes(f.read) # no data

        ccode_translation = CCODES['0x' + ut.bytes_to_hex(ccode)]

        return message, ccode_translation, reason
Example #5
0
def calc_txid(tx_hex):
    return bytes_to_hex(double_sha256(hex_to_bytes(tx_hex))[::-1])
Example #6
0
def test_flip_hex_byte_order():
    assert flip_hex_byte_order(bytes_to_hex(BYTES_LITTLE)) == HEX
Example #7
0
 def test_upper(self):
     assert bytes_to_hex(BYTES_BIG, upper=True) == HEX.upper()
Example #8
0
 def test_default(self):
     assert bytes_to_hex(BYTES_BIG) == HEX
Example #9
0
 def test_correct(self):
     assert bytes.fromhex(bytes_to_hex(BYTES_BIG)) == BYTES_BIG
Example #10
0
    def deserialize_all_messages(self):
        """This method is called inside the main spv_daemon loop and
        deserializes all messages in self.buffer and will independently
        recv the rest of the buffer if needed for long messages. For
        example "headers" with up to 2000 headers in a single message."""

        messages = []

        # deserialize all messages in buffer and if incomplete messages remain, recv more buffer until complete
        while self.buffer.getbuffer().nbytes > 0:

            # Calculate the size of the buffer
            self.buffer.seek(0, os.SEEK_END)
            buffer_size = self.buffer.tell()

            # Check if a complete message header is present
            if buffer_size < struct.calcsize("i 12s i i"):
                print("incomplete header")
                self.buffer.seek(0, os.SEEK_END)
                self.buffer.write(self.receive_raw_bytes(1024 * 8))
                continue  # return to top of loop to try again with hopefully complete header

            # check if message begins with network magic as expected
            self.buffer.seek(0)
            if self.buffer.read(4) == BITCOIN_SV_MAGIC:
                pass
            else:
                raise ValueError(
                    "message does not begin with bitcoin SV network magic: 0xe3e1f3e8")  # should never happen

            # Go to the beginning of the buffer
            self.buffer.seek(0)

            # Deserialize header
            try:
                header_bytes = self.buffer.read(struct.calcsize("i 12s i i"))
                message_header = Deserialize.deserialize_message_header(header_bytes)
            except Exception as e:
                print(e)
                print("couldn't deserialize message header")

            total_length = len(header_bytes) + message_header['length']

            # Check if complete message is present
            if buffer_size < total_length:
                # print('buffer size less than total length of message')
                self.buffer.seek(0, os.SEEK_END)  # puts buffer to end so that recv(1024*8) is appended to the end
                self.buffer.write(self.receive_raw_bytes(1024 * 8))
                continue  # go directly to top of loop to try again with hopefully complete message

            # Read in payload
            payload = self.buffer.read(message_header['length'])

            # Re-initialise self.buffer with remainder only (clips away processed message)
            self.buffer = io.BytesIO(self.buffer.read())

            payload_checksum = ut.bytes_to_hex(simple_spv.tools.checksum(payload))
            # Check if the checksum is valid

            if payload_checksum == message_header['checksum']:
                with open('logger.txt', 'a') as outfile:
                    outfile.write('checksums match for: ' + str(message_header['command']) + "\n")

                    # Call appropriate deserialization function from deserializers class
                message_header_command = message_header['command']
                deser_func_name = "deserialize_" + message_header_command
                if deser_func_name == "deserialize_pong":
                    pass
                else:
                    print(deser_func_name)
                deser_func = getattr(Deserialize, deser_func_name, None)

                f = io.BytesIO(payload)
                message = deser_func(f)
                # print(message)
            else:
                raise ValueError("something went wrong with deserialization of payload")

            messages.append((message_header, message))
        # Success
        # Return messages for handling in main loop
        return messages