@profiler
def create_routes_for_payment(self, *, amount_msat: int, final_total_msat: int, invoice_pubkey, min_cltv_expiry, r_tags, invoice_features: int, payment_hash, payment_secret, trampoline_fee_level: int, use_two_trampolines: bool, fwd_trampoline_onion=None, full_path: LNPaymentPath=None) -> Sequence[Tuple[(LNPaymentRoute, int)]]:
    'Creates multiple routes for splitting a payment over the available\n        private channels.\n\n        We first try to conduct the payment over a single channel. If that fails\n        and mpp is supported by the receiver, we will split the payment.'
    invoice_features = LnFeatures(invoice_features)
    trampoline_features = LnFeatures.VAR_ONION_OPT
    local_height = self.network.get_local_height()
    active_channels = [chan for chan in self.channels.values() if (chan.is_active() and (not chan.is_frozen_for_sending()))]
    try:
        if (not self.channel_db):
            for chan in active_channels:
                if (not self.is_trampoline_peer(chan.node_id)):
                    continue
                if (chan.node_id == invoice_pubkey):
                    trampoline_onion = None
                    trampoline_payment_secret = payment_secret
                    trampoline_total_msat = final_total_msat
                    amount_with_fees = amount_msat
                    cltv_delta = min_cltv_expiry
                else:
                    (trampoline_onion, amount_with_fees, cltv_delta) = create_trampoline_route_and_onion(amount_msat=amount_msat, total_msat=final_total_msat, min_cltv_expiry=min_cltv_expiry, my_pubkey=self.node_keypair.pubkey, invoice_pubkey=invoice_pubkey, invoice_features=invoice_features, node_id=chan.node_id, r_tags=r_tags, payment_hash=payment_hash, payment_secret=payment_secret, local_height=local_height, trampoline_fee_level=trampoline_fee_level, use_two_trampolines=use_two_trampolines)
                    trampoline_payment_secret = os.urandom(32)
                    trampoline_total_msat = amount_with_fees
                if (chan.available_to_spend(LOCAL, strict=True) < amount_with_fees):
                    continue
                route = [RouteEdge(start_node=self.node_keypair.pubkey, end_node=chan.node_id, short_channel_id=chan.short_channel_id, fee_base_msat=0, fee_proportional_millionths=0, cltv_expiry_delta=0, node_features=trampoline_features)]
                routes = [(route, amount_with_fees, trampoline_total_msat, amount_msat, cltv_delta, trampoline_payment_secret, trampoline_onion)]
                break
            else:
                raise NoPathFound()
        else:
            route = self.create_route_for_payment(amount_msat=amount_msat, invoice_pubkey=invoice_pubkey, min_cltv_expiry=min_cltv_expiry, r_tags=r_tags, invoice_features=invoice_features, channels=active_channels, full_path=full_path)
            routes = [(route, amount_msat, final_total_msat, amount_msat, min_cltv_expiry, payment_secret, fwd_trampoline_onion)]
    except NoPathFound:
        if (not invoice_features.supports(LnFeatures.BASIC_MPP_OPT)):
            raise
        channels_with_funds = {(chan.channel_id, chan.node_id): int(chan.available_to_spend(HTLCOwner.LOCAL)) for chan in active_channels}
        self.logger.info(f'channels_with_funds: {channels_with_funds}')
        use_singe_node = ((not self.channel_db) and (constants.net is constants.BitcoinMainnet))
        split_configurations = suggest_splits(amount_msat, channels_with_funds, single_node=use_singe_node)
        self.logger.info(f'suggest_split {amount_msat} returned {len(split_configurations)} configurations')
        for s in split_configurations:
            self.logger.info(f'trying split configuration: {s[0].values()} rating: {s[1]}')
            routes = []
            try:
                if (not self.channel_db):
                    buckets = defaultdict(list)
                    for ((chan_id, _), part_amount_msat) in s[0].items():
                        chan = self.channels[chan_id]
                        if part_amount_msat:
                            buckets[chan.node_id].append((chan_id, part_amount_msat))
                    for (node_id, bucket) in buckets.items():
                        bucket_amount_msat = sum([x[1] for x in bucket])
                        (trampoline_onion, bucket_amount_with_fees, bucket_cltv_delta) = create_trampoline_route_and_onion(amount_msat=bucket_amount_msat, total_msat=final_total_msat, min_cltv_expiry=min_cltv_expiry, my_pubkey=self.node_keypair.pubkey, invoice_pubkey=invoice_pubkey, invoice_features=invoice_features, node_id=node_id, r_tags=r_tags, payment_hash=payment_hash, payment_secret=payment_secret, local_height=local_height, trampoline_fee_level=trampoline_fee_level, use_two_trampolines=use_two_trampolines)
                        bucket_payment_secret = os.urandom(32)
                        bucket_fees = (bucket_amount_with_fees - bucket_amount_msat)
                        self.logger.info(f'bucket_fees {bucket_fees}')
                        for (chan_id, part_amount_msat) in bucket:
                            chan = self.channels[chan_id]
                            margin = (chan.available_to_spend(LOCAL, strict=True) - part_amount_msat)
                            delta_fee = min(bucket_fees, margin)
                            part_amount_msat_with_fees = (part_amount_msat + delta_fee)
                            bucket_fees -= delta_fee
                            route = [RouteEdge(start_node=self.node_keypair.pubkey, end_node=node_id, short_channel_id=chan.short_channel_id, fee_base_msat=0, fee_proportional_millionths=0, cltv_expiry_delta=0, node_features=trampoline_features)]
                            self.logger.info(f'adding route {part_amount_msat} {delta_fee} {margin}')
                            routes.append((route, part_amount_msat_with_fees, bucket_amount_with_fees, part_amount_msat, bucket_cltv_delta, bucket_payment_secret, trampoline_onion))
                        if (bucket_fees != 0):
                            self.logger.info('not enough margin to pay trampoline fee')
                            raise NoPathFound()
                else:
                    for ((chan_id, _), part_amount_msat) in s[0].items():
                        if part_amount_msat:
                            channel = self.channels[chan_id]
                            route = self.create_route_for_payment(amount_msat=part_amount_msat, invoice_pubkey=invoice_pubkey, min_cltv_expiry=min_cltv_expiry, r_tags=r_tags, invoice_features=invoice_features, channels=[channel], full_path=None)
                            routes.append((route, part_amount_msat, final_total_msat, part_amount_msat, min_cltv_expiry, payment_secret, fwd_trampoline_onion))
                self.logger.info(f'found acceptable split configuration: {list(s[0].values())} rating: {s[1]}')
                break
            except NoPathFound:
                continue
        else:
            raise NoPathFound()
    return routes
Creates multiple routes for splitting a payment over the available
private channels.

We first try to conduct the payment over a single channel. If that fails
and mpp is supported by the receiver, we will split the payment.
@profiler
def create_routes_for_payment(self, *, amount_msat: int, final_total_msat: int, invoice_pubkey, min_cltv_expiry, r_tags, invoice_features: int, payment_hash, payment_secret, trampoline_fee_level: int, use_two_trampolines: bool, fwd_trampoline_onion=None, full_path: LNPaymentPath=None) -> Sequence[Tuple[(LNPaymentRoute, int)]]:
    'Creates multiple routes for splitting a payment over the available\n        private channels.\n\n        We first try to conduct the payment over a single channel. If that fails\n        and mpp is supported by the receiver, we will split the payment.'
    invoice_features = LnFeatures(invoice_features)
    trampoline_features = LnFeatures.VAR_ONION_OPT
    local_height = self.network.get_local_height()
    active_channels = [chan for chan in self.channels.values() if (chan.is_active() and (not chan.is_frozen_for_sending()))]
    try:
        if (not self.channel_db):
            for chan in active_channels:
                if (not self.is_trampoline_peer(chan.node_id)):
                    continue
                if (chan.node_id == invoice_pubkey):
                    trampoline_onion = None
                    trampoline_payment_secret = payment_secret
                    trampoline_total_msat = final_total_msat
                    amount_with_fees = amount_msat
                    cltv_delta = min_cltv_expiry
                else:
                    (trampoline_onion, amount_with_fees, cltv_delta) = create_trampoline_route_and_onion(amount_msat=amount_msat, total_msat=final_total_msat, min_cltv_expiry=min_cltv_expiry, my_pubkey=self.node_keypair.pubkey, invoice_pubkey=invoice_pubkey, invoice_features=invoice_features, node_id=chan.node_id, r_tags=r_tags, payment_hash=payment_hash, payment_secret=payment_secret, local_height=local_height, trampoline_fee_level=trampoline_fee_level, use_two_trampolines=use_two_trampolines)
                    trampoline_payment_secret = os.urandom(32)
                    trampoline_total_msat = amount_with_fees
                if (chan.available_to_spend(LOCAL, strict=True) < amount_with_fees):
                    continue
                route = [RouteEdge(start_node=self.node_keypair.pubkey, end_node=chan.node_id, short_channel_id=chan.short_channel_id, fee_base_msat=0, fee_proportional_millionths=0, cltv_expiry_delta=0, node_features=trampoline_features)]
                routes = [(route, amount_with_fees, trampoline_total_msat, amount_msat, cltv_delta, trampoline_payment_secret, trampoline_onion)]
                break
            else:
                raise NoPathFound()
        else:
            route = self.create_route_for_payment(amount_msat=amount_msat, invoice_pubkey=invoice_pubkey, min_cltv_expiry=min_cltv_expiry, r_tags=r_tags, invoice_features=invoice_features, channels=active_channels, full_path=full_path)
            routes = [(route, amount_msat, final_total_msat, amount_msat, min_cltv_expiry, payment_secret, fwd_trampoline_onion)]
    except NoPathFound:
        if (not invoice_features.supports(LnFeatures.BASIC_MPP_OPT)):
            raise
        channels_with_funds = {(chan.channel_id, chan.node_id): int(chan.available_to_spend(HTLCOwner.LOCAL)) for chan in active_channels}
        self.logger.info(f'channels_with_funds: {channels_with_funds}')
        use_singe_node = ((not self.channel_db) and (constants.net is constants.BitcoinMainnet))
        split_configurations = suggest_splits(amount_msat, channels_with_funds, single_node=use_singe_node)
        self.logger.info(f'suggest_split {amount_msat} returned {len(split_configurations)} configurations')
        for s in split_configurations:
            self.logger.info(f'trying split configuration: {s[0].values()} rating: {s[1]}')
            routes = []
            try:
                if (not self.channel_db):
                    buckets = defaultdict(list)
                    for ((chan_id, _), part_amount_msat) in s[0].items():
                        chan = self.channels[chan_id]
                        if part_amount_msat:
                            buckets[chan.node_id].append((chan_id, part_amount_msat))
                    for (node_id, bucket) in buckets.items():
                        bucket_amount_msat = sum([x[1] for x in bucket])
                        (trampoline_onion, bucket_amount_with_fees, bucket_cltv_delta) = create_trampoline_route_and_onion(amount_msat=bucket_amount_msat, total_msat=final_total_msat, min_cltv_expiry=min_cltv_expiry, my_pubkey=self.node_keypair.pubkey, invoice_pubkey=invoice_pubkey, invoice_features=invoice_features, node_id=node_id, r_tags=r_tags, payment_hash=payment_hash, payment_secret=payment_secret, local_height=local_height, trampoline_fee_level=trampoline_fee_level, use_two_trampolines=use_two_trampolines)
                        bucket_payment_secret = os.urandom(32)
                        bucket_fees = (bucket_amount_with_fees - bucket_amount_msat)
                        self.logger.info(f'bucket_fees {bucket_fees}')
                        for (chan_id, part_amount_msat) in bucket:
                            chan = self.channels[chan_id]
                            margin = (chan.available_to_spend(LOCAL, strict=True) - part_amount_msat)
                            delta_fee = min(bucket_fees, margin)
                            part_amount_msat_with_fees = (part_amount_msat + delta_fee)
                            bucket_fees -= delta_fee
                            route = [RouteEdge(start_node=self.node_keypair.pubkey, end_node=node_id, short_channel_id=chan.short_channel_id, fee_base_msat=0, fee_proportional_millionths=0, cltv_expiry_delta=0, node_features=trampoline_features)]
                            self.logger.info(f'adding route {part_amount_msat} {delta_fee} {margin}')
                            routes.append((route, part_amount_msat_with_fees, bucket_amount_with_fees, part_amount_msat, bucket_cltv_delta, bucket_payment_secret, trampoline_onion))
                        if (bucket_fees != 0):
                            self.logger.info('not enough margin to pay trampoline fee')
                            raise NoPathFound()
                else:
                    for ((chan_id, _), part_amount_msat) in s[0].items():
                        if part_amount_msat:
                            channel = self.channels[chan_id]
                            route = self.create_route_for_payment(amount_msat=part_amount_msat, invoice_pubkey=invoice_pubkey, min_cltv_expiry=min_cltv_expiry, r_tags=r_tags, invoice_features=invoice_features, channels=[channel], full_path=None)
                            routes.append((route, part_amount_msat, final_total_msat, part_amount_msat, min_cltv_expiry, payment_secret, fwd_trampoline_onion))
                self.logger.info(f'found acceptable split configuration: {list(s[0].values())} rating: {s[1]}')
                break
            except NoPathFound:
                continue
        else:
            raise NoPathFound()
    return routes