def _edge_cost(
            self,
            *,
            short_channel_id: ShortChannelID,
            start_node: bytes,
            end_node: bytes,
            payment_amt_msat: int,
            ignore_costs=False,
            is_mine=False,
            my_channels: Dict[ShortChannelID, 'Channel'] = None,
            private_route_edges: Dict[ShortChannelID, RouteEdge] = None,
            now: int,  # unix ts
    ) -> Tuple[float, int]:
        """Heuristic cost (distance metric) of going through a channel.
        Returns (heuristic_cost, fee_for_edge_msat).
        """
        if self._is_edge_blacklisted(short_channel_id, now=now):
            return float('inf'), 0
        if private_route_edges is None:
            private_route_edges = {}
        channel_info = self.channel_db.get_channel_info(
            short_channel_id, my_channels=my_channels, private_route_edges=private_route_edges)
        if channel_info is None:
            return float('inf'), 0
        channel_policy = self.channel_db.get_policy_for_node(
            short_channel_id, start_node, my_channels=my_channels, private_route_edges=private_route_edges, now=now)
        if channel_policy is None:
            return float('inf'), 0
        # channels that did not publish both policies often return temporary channel failure
        channel_policy_backwards = self.channel_db.get_policy_for_node(
            short_channel_id, end_node, my_channels=my_channels, private_route_edges=private_route_edges, now=now)
        if (channel_policy_backwards is None
                and not is_mine
                and short_channel_id not in private_route_edges):
            return float('inf'), 0
        if channel_policy.is_disabled():
            return float('inf'), 0
        if payment_amt_msat < channel_policy.htlc_minimum_msat:
            return float('inf'), 0  # payment amount too little
        if channel_info.capacity_sat is not None and \
                payment_amt_msat // 1000 > channel_info.capacity_sat:
            return float('inf'), 0  # payment amount too large
        if channel_policy.htlc_maximum_msat is not None and \
                payment_amt_msat > channel_policy.htlc_maximum_msat:
            return float('inf'), 0  # payment amount too large
        route_edge = private_route_edges.get(short_channel_id, None)
        if route_edge is None:
            node_info = self.channel_db.get_node_info_for_node_id(node_id=end_node)
            if node_info:
                # it's ok if we are missing the node_announcement (node_info) for this node,
                # but if we have it, we enforce that they support var_onion_optin
                node_features = LnFeatures(node_info.features)
                if not node_features.supports(LnFeatures.VAR_ONION_OPT):  # note: this is kind of slow. could be cached.
                    return float('inf'), 0
            route_edge = RouteEdge.from_channel_policy(
                channel_policy=channel_policy,
                short_channel_id=short_channel_id,
                start_node=start_node,
                end_node=end_node,
                node_info=node_info)
        # Cap cltv of any given edge at 2 weeks (the cost function would not work well for extreme cases)
        if route_edge.cltv_delta > 14 * 144:
            return float('inf'), 0
        # Distance metric notes:  # TODO constants are ad-hoc
        # ( somewhat based on https://github.com/lightningnetwork/lnd/pull/1358 )
        # - Edges have a base cost. (more edges -> less likely none will fail)
        # - The larger the payment amount, and the longer the CLTV,
        #   the more irritating it is if the HTLC gets stuck.
        # - Paying lower fees is better. :)
        if ignore_costs:
            return DEFAULT_PENALTY_BASE_MSAT, 0
        fee_msat = route_edge.fee_for_edge(payment_amt_msat)
        cltv_cost = route_edge.cltv_delta * payment_amt_msat * 15 / 1_000_000_000
        # the liquidty penalty takes care we favor edges that should be able to forward
        # the payment and penalize edges that cannot
        liquidity_penalty = self.liquidity_hints.penalty(start_node, end_node, short_channel_id, payment_amt_msat)
        overall_cost = fee_msat + cltv_cost + liquidity_penalty
        return overall_cost, fee_msat
Heuristic cost (distance metric) of going through a channel.
        Returns (heuristic_cost, fee_for_edge_msat).
        
electrum/lnrouter.py