Beispiel #1
0
    async def find_change_idx(self, tx, change_idx=None):
        if change_idx is not None:
            return change_idx

        out_txs2 = await self.reformat_outs(tx.splitted_dsts)
        change_dts = await self.reformat_out(tx.change_dts) if tx.change_dts else None
        change_idx = addr.get_change_addr_idx(out_txs2, change_dts)
        return change_idx
Beispiel #2
0
    async def adjust_change(self, tx):
        logger.debug("Change addr adjust")
        out_txs2 = await self.reformat_outs(tx.splitted_dsts)
        change_dts = await self.reformat_out(tx.change_dts) if tx.change_dts else None
        change_idx = addr.get_change_addr_idx(out_txs2, change_dts)

        if change_idx is None:
            logger.warning('Change address not found in outputs, dts: %s' % (change_dts, ))
            for ii in out_txs2:
                logger.warning('Out: %s' % ii)

            # Find addr that matches and adapt value in change dst
            for idx, ii in enumerate(out_txs2):
                if addr.addr_eq(change_dts.addr, ii.addr):
                    logger.info('Found surrogate change addr: [%s] %s' % (idx, ii))
                    change_dts.amount = ii.amount
                    change_idx = idx
                    break

        if self.args.outs_subs:
            for ix, o in enumerate(tx.splitted_dsts):
                if change_idx is None or ix != change_idx:
                    o.is_subaddress = True

        if change_idx is None:
            logger.warning('Could not fix change addr')
            return

        change_addr = await self.primary_change_address(
            self.dest_keys, self.dest_sub_major
        )
        tx.change_dts.amount = change_dts.amount
        tx.change_dts.addr.m_spend_public_key = change_addr.spend_public_key
        tx.change_dts.addr.m_view_public_key = change_addr.view_public_key
        logger.debug("Change addr adjust @idx: %s, spend key: %s"
                     % (change_idx, binascii.hexlify(change_addr.spend_public_key)))

        tx.splitted_dsts[
            change_idx
        ].addr.m_spend_public_key = change_addr.spend_public_key
        tx.splitted_dsts[
            change_idx
        ].addr.m_view_public_key = change_addr.view_public_key

        return change_idx
Beispiel #3
0
    async def adjust_change(self, tx):
        logger.debug("Change addr adjust")
        out_txs2 = await self.reformat_outs(tx.splitted_dsts)
        change_dts = await self.reformat_out(tx.change_dts) if tx.change_dts else None
        change_idx = addr.get_change_addr_idx(out_txs2, change_dts)
        if change_idx is None:
            return

        change_addr = await self.primary_change_address(
            self.dest_keys, self.dest_sub_major
        )
        tx.change_dts.addr.m_spend_public_key = change_addr.spend_public_key
        tx.change_dts.addr.m_view_public_key = change_addr.view_public_key

        tx.splitted_dsts[
            change_idx
        ].addr.m_spend_public_key = change_addr.spend_public_key
        tx.splitted_dsts[
            change_idx
        ].addr.m_view_public_key = change_addr.view_public_key
    async def receive(self, tx, all_creds, con_data=None, exp_payment_id=None):
        """
        Test transaction receive with known view/spend keys of destinations.
        :param tx:
        :param all_creds:
        :param con_data:
        :param exp_payment_id:
        :return:
        """
        # Unserialize the transaction
        tx_obj = xmrtypes.Transaction()
        reader = xmrserialize.MemoryReaderWriter(bytearray(tx))
        ar1 = xmrserialize.Archive(reader, False)

        await ar1.message(tx_obj, msg_type=xmrtypes.Transaction)
        extras = await monero.parse_extra_fields(tx_obj.extra)
        tx_pub = monero.find_tx_extra_field_by_type(
            extras, xmrtypes.TxExtraPubKey
        ).pub_key
        additional_pub_keys = monero.find_tx_extra_field_by_type(
            extras, xmrtypes.TxExtraAdditionalPubKeys
        )
        num_outs = len(tx_obj.vout)
        num_received = 0

        # Try to receive tsx outputs with each account.
        tx_money_got_in_outs = collections.defaultdict(lambda: 0)
        outs = []

        change_idx = get_change_addr_idx(con_data.tsx_data.outputs, con_data.tsx_data.change_dts)

        for idx, creds in enumerate(all_creds):
            wallet_subs = {}
            for account in range(0, 5):
                monero.compute_subaddresses(creds, account, range(25), wallet_subs)

            derivation = crypto.generate_key_derivation(
                crypto.decodepoint(tx_pub), creds.view_key_private
            )
            additional_derivations = []
            if additional_pub_keys and additional_pub_keys.data:
                for x in additional_pub_keys.data:
                    additional_derivations.append(
                        crypto.generate_key_derivation(
                            crypto.decodepoint(x), creds.view_key_private
                        )
                    )

            for ti, to in enumerate(tx_obj.vout):
                tx_scan_info = monero.check_acc_out_precomp(
                    to, wallet_subs, derivation, additional_derivations, ti
                )
                if not tx_scan_info.received:
                    continue

                num_received += 1
                tx_scan_info = monero.scan_output(
                    creds, tx_obj, ti, tx_scan_info, tx_money_got_in_outs, outs, False
                )

                # Check spending private key correctness
                self.assertTrue(
                    crypto.point_eq(
                        crypto.decodepoint(tx_obj.rct_signatures.outPk[ti].mask),
                        crypto.gen_c(tx_scan_info.mask, tx_scan_info.amount),
                    )
                )

                self.assertTrue(
                    crypto.point_eq(
                        crypto.decodepoint(tx_obj.vout[ti].target.key),
                        crypto.scalarmult_base(tx_scan_info.in_ephemeral),
                    )
                )

                if exp_payment_id is not None:
                    payment_id = None
                    # Not checking payment id for change transaction
                    if exp_payment_id[0] == 1 and change_idx is not None and ti == change_idx:
                        continue

                    payment_id_type = None
                    extra_nonce = monero.find_tx_extra_field_by_type(extras, xmrtypes.TxExtraNonce)
                    if extra_nonce and monero.has_encrypted_payment_id(extra_nonce.nonce):
                        payment_id_type = 1
                        payment_id = monero.get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce)
                        payment_id = monero.encrypt_payment_id(payment_id, crypto.decodepoint(tx_pub), creds.view_key_private)

                    elif extra_nonce and monero.has_payment_id(extra_nonce.nonce):
                        payment_id_type = 0
                        payment_id = monero.get_payment_id_from_tx_extra_nonce(extra_nonce.nonce)

                    self.assertEqual(payment_id_type, exp_payment_id[0])
                    self.assertEqual(payment_id, exp_payment_id[1])

        # All outputs have to be successfully received
        self.assertEqual(num_outs, num_received)