Beispiel #1
0
async def sign_tx(ctx, msg):
    keychain = await seed.get_keychain(ctx)

    progress.init(msg.transactions_count, "Loading data")

    try:
        attested = len(msg.inputs) * [False]
        input_coins_sum = 0
        # request transactions
        tx_req = CardanoTxRequest()

        for index in range(msg.transactions_count):
            progress.advance()
            tx_ack = await request_transaction(ctx, tx_req, index)
            tx_hash = hashlib.blake2b(data=bytes(tx_ack.transaction),
                                      outlen=32).digest()
            tx_decoded = cbor.decode(tx_ack.transaction)
            for i, input in enumerate(msg.inputs):
                if not attested[i] and input.prev_hash == tx_hash:
                    attested[i] = True
                    outputs = tx_decoded[1]
                    amount = outputs[input.prev_index][1]
                    input_coins_sum += amount

        if not all(attested):
            raise wire.ProcessError("No tx data sent for input " +
                                    str(attested.index(False)))

        transaction = Transaction(msg.inputs, msg.outputs, keychain,
                                  msg.protocol_magic, input_coins_sum)

        # clear progress bar
        display_homescreen()

        for i in msg.inputs:
            await validate_path(ctx, validate_full_path, keychain, i.address_n,
                                CURVE)

        # sign the transaction bundle and prepare the result
        tx_body, tx_hash = transaction.serialise_tx()
        tx = CardanoSignedTx(tx_body=tx_body, tx_hash=tx_hash)

    except ValueError as e:
        if __debug__:
            log.exception(__name__, e)
        raise wire.ProcessError("Signing failed")

    # display the transaction in UI
    if not await show_tx(
            ctx,
            transaction.output_addresses,
            transaction.outgoing_coins,
            transaction.fee,
            transaction.network_name,
            transaction.inputs,
            transaction.outputs,
    ):
        raise wire.ActionCancelled("Signing cancelled")

    return tx
Beispiel #2
0
def is_safe_output_address(address) -> bool:
    """
    Determines whether it is safe to include the address as-is as
    a tx output, preventing unintended side effects (e.g. CBOR injection)
    """
    try:
        address_hex = base58.decode(address)
        address_unpacked = cbor.decode(address_hex)
    except ValueError as e:
        if __debug__:
            log.exception(__name__, e)
        return False

    if not isinstance(address_unpacked, list) or len(address_unpacked) != 2:
        return False

    address_data_encoded = address_unpacked[0]

    if not isinstance(address_data_encoded, bytes):
        return False

    return _encode_address_raw(address_data_encoded) == address
Beispiel #3
0
    def _process_inputs(self):
        input_coins = []
        input_hashes = []
        output_indexes = []
        types = []
        tx_data = {}

        for raw_transaction in self.transactions:
            tx_hash = hashlib.blake2b(data=bytes(raw_transaction),
                                      outlen=32).digest()
            tx_data[tx_hash] = cbor.decode(raw_transaction)

        for input in self.inputs:
            input_hashes.append(input.prev_hash)
            output_indexes.append(input.prev_index)
            types.append(input.type or 0)

        nodes = []
        for input in self.inputs:
            _, node = derive_address_and_node(self.keychain, input.address_n)
            nodes.append(node)

        for index, output_index in enumerate(output_indexes):
            tx_hash = bytes(input_hashes[index])
            if tx_hash in tx_data:
                tx = tx_data[tx_hash]
                outputs = tx[1]
                amount = outputs[output_index][1]
                input_coins.append(amount)
            else:
                raise wire.ProcessError("No tx data sent for input " +
                                        str(index))

        self.input_coins = input_coins
        self.nodes = nodes
        self.types = types
        self.input_hashes = input_hashes
        self.output_indexes = output_indexes