UncertaintyChannel Class

class UncertaintyChannel.UncertaintyChannel(channel: Channel.Channel)

Bases: Channel.Channel

The channel class contains basic information of a channel that will be used to create the UncertaintyNetwork.

Since we optimize for reliability via a probability estimate for liquidity that is based on the capacity of the channel, the class contains the capacity as seen in the funding tx output.

As we also optimize for fees and want to be able to compute the fees of a flow ,the class contains information for the fee rate (ppm) and the base_fee (base).

Most importantly the class stores our belief about the liquidity information of a channel. This is done by reducing the uncertainty interval from [0,`capacity`] to [min_liquidity, max_liquidity]. Additionally, we need to know how many sats we currently have allocated via outstanding onions to the channel which is stored in in_flight.

The most important API call is the get_piecewise_linearized_costs function that computes the piecewise linearized cost for a channel rising from uncertainty as well as routing fees.

MAX_CHANNEL_SIZE = 15000000000
TOTAL_NUMBER_OF_SATS = 2100000000000000
allocate_inflights(amt: int)

assign or remove amount that is assigned to be in_flight.

combined_linearized_unit_cost(mu: int = 1)

Builds the weighted sum between our two unit costs.

Not being used in the code. Just here to describe the theory.

property conditional_capacity

Conditional Capacity is the capacity in the channel after we applied our knowledge about minimum liquidity and maximum liquidity. This is done by reducing the uncertainty interval from [0,`capacity`] to [min_liquidity, max_liquidity].


respect_inflight – are in_flight amounts considered when calculating the conditional capacity?


returns the uncertainty that we have about the channel

this respects our belief about the channel’s liquidity and thus is just the log of the conditional capacity.

FIXME: This respects inflight information? I assume it shouldn’t.


resets the information that we believe to have about the channel.

get_piecewise_linearized_costs(number_of_pieces: int = 5, mu: int = 1)
property in_flight

The amount currently allocated for potential payments through this channel. This resembles the concept of an HTLC.


in_flight amount on the UncertaintyChannel

learn_n_bits(oracle: OracleLightningNetwork.OracleLightningNetwork, n: int = 1)

conducts n probes of channel via binary search starting from our belief

This of course only learns n bits if we use a uniform success probability as a prior thus this method will not work if a different prior success probability is assumed


Note that the ppm is natively an integer and can just be taken as a unit cost for the solver


estimates the linearized integer uncertainty cost

FIXME: Instead of using the maximum capacity on the network it just assumes 150BTC to be max

linearized_routing_cost_msat(amt: int)

Linearizing the routing cost by ignoring the base fee.

Note that one can still include channels with small base fees to the computation the base will just be excluded in the computation and has to be paid later anyway. If as developers we go down this road this will allow routing node operators to game us with the base fee thus it seems reasonable in routing computations to just ignore channels that charge a base fee.

There are other ways of achieving this by overestimating the fee as ZmnSCPxj suggested at: https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-August/003206.html

linearized_uncertainty_cost(amt: int)

the linearized uncertainty cost is just amt/(capacity+1). Using this is most likely not what one wants as this tends to saturate channels. The API is included to explain the theory.

Warning: This API does not respect our belief about the channels liquidity or allocated in_flight HTLCs

property max_liquidity
property min_liquidity
routing_cost_msat(amt: int)

Routing cost a routing node will earn to forward a payment along this channel in msats

success_probability(amt: Optional[int] = None)

returns the estimated success probability for a payment based on our belief about the channel using a uniform distribution.

While this is the core of the theory it is only used for evaluation and not for the actual min cost flow computation as we linearize this to an integer unit cost

In particular the conditional probability P(X>=a | min_liquidity < X < max_liquidity) is computed based on our belief also respecting how many satoshis we have currently outstanding and allocated. Thus it is possible that testing for the amt=0 that the success probability is zero and in particular not 1.

It also accounts for the number of satoshis we have already outstanding but have not received information about

FIXME: Potentially test other prior distributions like mixedmodels where most funds are on one side of the channel

uncertainty_cost(amt: int)

Returns the uncertainty cost associated to sending the amount amt respecting our current belief about the channel’s liquidity and the in_flight HTLC’s that we have allocated and outstanding.

update_knowledge(amount: int, return_channel, probing_successful: bool)

Updates our knowledge about the channel after probing with ‘send_onion’.

‘send_onion’ already placed the amount as inflight on the UncertaintyChannel. Because we currently don’t konw if the payment will be settled successfully, we can only incorporate current knowledge. Any change because of settlement will have to be considered at another location.

What can we learn from a successfully sent onion? * If we knew that there was a minimum liquidity greater than the in_flights on the channel, than this is fine.

Nothing done.

  • If there was no knowledge about the minimum liquidity, then we now know that it is at least the in_flights.

  • We learnt nothing about the maximum liquidity in this channel.

  • Regarding the return channel: We now know that the confirmed inflight amount of this channel cannot be in the return channel. Thus, maximum liquidity needs to be lower than capacity minus in_flight amount.

What can we learn from a failing onion? * In the channel, the maximum liquidity needs to be lower than the in_flights.

We have no further information about the minimum amount that can be sent.

  • If this amount fails, then we know that at least this amount of liquidity is in the return channel.

# This API works only if we have an Oracle that allows to ask the actual liquidity of a channel # In mainnet Lightning our oracle will not work on a per_channel level. This will change the data # flow. Here for simplicity of the simulation we make use of the Oracle on a per channel level

  • amount – The amount that went through when probing the channel, usually in_flight amount plus attempt amount!

  • return_channel – The UncertaintyChannel in the return direction, needed to adjust knowledge there.

  • probing_successful – Could the amount be sent?