async def pay_to_node(self, *, node_pubkey: bytes, payment_hash: bytes, payment_secret: Optional[bytes], amount_to_pay: int, min_cltv_expiry: int, r_tags, invoice_features: int, attempts: int=1, full_path: LNPaymentPath=None, fwd_trampoline_onion=None, fwd_trampoline_fee=None, fwd_trampoline_cltv_delta=None) -> None:
    if fwd_trampoline_onion:
        if (fwd_trampoline_fee < 1000):
            raise OnionRoutingFailure(code=OnionFailureCode.TRAMPOLINE_FEE_INSUFFICIENT, data=b'')
        if (fwd_trampoline_cltv_delta < 576):
            raise OnionRoutingFailure(code=OnionFailureCode.TRAMPOLINE_EXPIRY_TOO_SOON, data=b'')
    self.logs[payment_hash.hex()] = log = []
    trampoline_fee_level = self.INITIAL_TRAMPOLINE_FEE_LEVEL
    use_two_trampolines = True
    amount_inflight = 0
    while True:
        amount_to_send = (amount_to_pay - amount_inflight)
        if (amount_to_send > 0):
            routes = (await run_in_thread(partial(self.create_routes_for_payment, amount_msat=amount_to_send, final_total_msat=amount_to_pay, invoice_pubkey=node_pubkey, min_cltv_expiry=min_cltv_expiry, r_tags=r_tags, invoice_features=invoice_features, full_path=full_path, payment_hash=payment_hash, payment_secret=payment_secret, trampoline_fee_level=trampoline_fee_level, use_two_trampolines=use_two_trampolines, fwd_trampoline_onion=fwd_trampoline_onion)))
            for (route, amount_msat, total_msat, amount_receiver_msat, cltv_delta, bucket_payment_secret, trampoline_onion) in routes:
                amount_inflight += amount_receiver_msat
                if (amount_inflight > amount_to_pay):
                    raise Exception(f'amount_inflight={amount_inflight} > amount_to_pay={amount_to_pay}')
                (await self.pay_to_route(route=route, amount_msat=amount_msat, total_msat=total_msat, amount_receiver_msat=amount_receiver_msat, payment_hash=payment_hash, payment_secret=bucket_payment_secret, min_cltv_expiry=cltv_delta, trampoline_onion=trampoline_onion))
            util.trigger_callback('invoice_status', self.wallet, payment_hash.hex())
        self.logger.info(f'amount inflight {amount_inflight}')
        htlc_log = (await self.sent_htlcs[payment_hash].get())
        amount_inflight -= htlc_log.amount_msat
        if (amount_inflight < 0):
            raise Exception(f'amount_inflight={amount_inflight} < 0')
        log.append(htlc_log)
        if htlc_log.success:
            if self.network.path_finder:
                self.network.path_finder.update_liquidity_hints(htlc_log.route, htlc_log.amount_msat)
            return
        if (len(log) >= attempts):
            raise PaymentFailure(('Giving up after %d attempts' % len(log)))
        route = htlc_log.route
        sender_idx = htlc_log.sender_idx
        failure_msg = htlc_log.failure_msg
        (code, data) = (failure_msg.code, failure_msg.data)
        self.logger.info(f'UPDATE_FAIL_HTLC. code={repr(code)}. decoded_data={failure_msg.decode_data()}. data={data.hex()!r}')
        self.logger.info(f'error reported by {bh2u(route[sender_idx].node_id)}')
        if (code == OnionFailureCode.MPP_TIMEOUT):
            raise PaymentFailure(failure_msg.code_name())
        if (not self.channel_db):
            if (code == OnionFailureCode.TRAMPOLINE_FEE_INSUFFICIENT):
                trampoline_fee_level += 1
                continue
            elif use_two_trampolines:
                use_two_trampolines = False
            else:
                raise PaymentFailure(failure_msg.code_name())
        else:
            self.handle_error_code_from_failed_htlc(route=route, sender_idx=sender_idx, failure_msg=failure_msg, amount=htlc_log.amount_msat)
async def pay_to_node(self, *, node_pubkey: bytes, payment_hash: bytes, payment_secret: Optional[bytes], amount_to_pay: int, min_cltv_expiry: int, r_tags, invoice_features: int, attempts: int=1, full_path: LNPaymentPath=None, fwd_trampoline_onion=None, fwd_trampoline_fee=None, fwd_trampoline_cltv_delta=None) -> None:
    if fwd_trampoline_onion:
        if (fwd_trampoline_fee < 1000):
            raise OnionRoutingFailure(code=OnionFailureCode.TRAMPOLINE_FEE_INSUFFICIENT, data=b)
        if (fwd_trampoline_cltv_delta < 576):
            raise OnionRoutingFailure(code=OnionFailureCode.TRAMPOLINE_EXPIRY_TOO_SOON, data=b)
    self.logs[payment_hash.hex()] = log = []
    trampoline_fee_level = self.INITIAL_TRAMPOLINE_FEE_LEVEL
    use_two_trampolines = True
    amount_inflight = 0
    while True:
        amount_to_send = (amount_to_pay - amount_inflight)
        if (amount_to_send > 0):
            routes = (await run_in_thread(partial(self.create_routes_for_payment, amount_msat=amount_to_send, final_total_msat=amount_to_pay, invoice_pubkey=node_pubkey, min_cltv_expiry=min_cltv_expiry, r_tags=r_tags, invoice_features=invoice_features, full_path=full_path, payment_hash=payment_hash, payment_secret=payment_secret, trampoline_fee_level=trampoline_fee_level, use_two_trampolines=use_two_trampolines, fwd_trampoline_onion=fwd_trampoline_onion)))
            for (route, amount_msat, total_msat, amount_receiver_msat, cltv_delta, bucket_payment_secret, trampoline_onion) in routes:
                amount_inflight += amount_receiver_msat
                if (amount_inflight > amount_to_pay):
                    raise Exception(f'amount_inflight={amount_inflight} > amount_to_pay={amount_to_pay}')
                (await self.pay_to_route(route=route, amount_msat=amount_msat, total_msat=total_msat, amount_receiver_msat=amount_receiver_msat, payment_hash=payment_hash, payment_secret=bucket_payment_secret, min_cltv_expiry=cltv_delta, trampoline_onion=trampoline_onion))
            util.trigger_callback('invoice_status', self.wallet, payment_hash.hex())
        self.logger.info(f'amount inflight {amount_inflight}')
        htlc_log = (await self.sent_htlcs[payment_hash].get())
        amount_inflight -= htlc_log.amount_msat
        if (amount_inflight < 0):
            raise Exception(f'amount_inflight={amount_inflight} < 0')
        log.append(htlc_log)
        if htlc_log.success:
            if self.network.path_finder:
                self.network.path_finder.update_liquidity_hints(htlc_log.route, htlc_log.amount_msat)
            return
        if (len(log) >= attempts):
            raise PaymentFailure(('Giving up after %d attempts' % len(log)))
        route = htlc_log.route
        sender_idx = htlc_log.sender_idx
        failure_msg = htlc_log.failure_msg
        (code, data) = (failure_msg.code, failure_msg.data)
        self.logger.info(f'UPDATE_FAIL_HTLC. code={repr(code)}. decoded_data={failure_msg.decode_data()}. data={data.hex()!r}')
        self.logger.info(f'error reported by {bh2u(route[sender_idx].node_id)}')
        if (code == OnionFailureCode.MPP_TIMEOUT):
            raise PaymentFailure(failure_msg.code_name())
        if (not self.channel_db):
            if (code == OnionFailureCode.TRAMPOLINE_FEE_INSUFFICIENT):
                trampoline_fee_level += 1
                continue
            elif use_two_trampolines:
                use_two_trampolines = False
            else:
                raise PaymentFailure(failure_msg.code_name())
        else:
            self.handle_error_code_from_failed_htlc(route=route, sender_idx=sender_idx, failure_msg=failure_msg, amount=htlc_log.amount_msat)