@ -10,6 +10,7 @@
# include <channeld/full_channel.h>
# include <channeld/full_channel.h>
# include <common/channel_config.h>
# include <common/channel_config.h>
# include <common/htlc.h>
# include <common/htlc.h>
# include <common/htlc_trim.h>
# include <common/htlc_tx.h>
# include <common/htlc_tx.h>
# include <common/htlc_wire.h>
# include <common/htlc_wire.h>
# include <common/key_derive.h>
# include <common/key_derive.h>
@ -291,6 +292,69 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx,
return txs ;
return txs ;
}
}
/* If @side is faced with these HTLCs, how much will it have left
* above reserve ( eg . to pay fees ) . Returns false if would be < 0. */
static bool get_room_above_reserve ( const struct channel * channel ,
const struct channel_view * view ,
const struct htlc * * adding ,
const struct htlc * * removing ,
enum side side ,
struct amount_msat * balance )
{
bool ok ;
/* Reserve is set by the *other* side */
struct amount_sat reserve = channel - > config [ ! side ] . channel_reserve ;
* balance = view - > owed [ side ] ;
ok = true ;
for ( size_t i = 0 ; i < tal_count ( removing ) ; i + + )
ok & = balance_remove_htlc ( balance , removing [ i ] , side ) ;
for ( size_t i = 0 ; i < tal_count ( adding ) ; i + + )
ok & = balance_add_htlc ( balance , adding [ i ] , side ) ;
/* Overflow shouldn't happen, but if it does, complain */
if ( ! ok ) {
status_broken ( " Failed to add %zu remove %zu htlcs " ,
tal_count ( adding ) , tal_count ( removing ) ) ;
return false ;
}
if ( ! amount_msat_sub_sat ( balance , * balance , reserve ) ) {
status_trace ( " %s cannot afford htlc: would make balance %s "
" below reserve %s " ,
side_to_str ( side ) ,
type_to_string ( tmpctx , struct amount_msat ,
balance ) ,
type_to_string ( tmpctx , struct amount_sat ,
& reserve ) ) ;
return false ;
}
return true ;
}
static struct amount_sat fee_for_htlcs ( const struct channel * channel ,
const struct channel_view * view ,
const struct htlc * * committed ,
const struct htlc * * adding ,
const struct htlc * * removing ,
enum side side )
{
u32 feerate = view - > feerate_per_kw ;
struct amount_sat dust_limit = channel - > config [ side ] . dust_limit ;
size_t untrimmed ;
untrimmed = commit_tx_num_untrimmed ( committed , feerate , dust_limit ,
side )
+ commit_tx_num_untrimmed ( adding , feerate , dust_limit ,
side )
- commit_tx_num_untrimmed ( removing , feerate , dust_limit ,
side ) ;
return commit_tx_base_fee ( feerate , untrimmed ) ;
}
static enum channel_add_err add_htlc ( struct channel * channel ,
static enum channel_add_err add_htlc ( struct channel * channel ,
enum htlc_state state ,
enum htlc_state state ,
u64 id ,
u64 id ,
@ -304,12 +368,9 @@ static enum channel_add_err add_htlc(struct channel *channel,
{
{
struct htlc * htlc , * old ;
struct htlc * htlc , * old ;
struct amount_msat msat_in_htlcs , committed_msat , adding_msat , removing_msat ;
struct amount_msat msat_in_htlcs , committed_msat , adding_msat , removing_msat ;
struct amount_sat fee ;
enum side sender = htlc_state_owner ( state ) , recipient = ! sender ;
enum side sender = htlc_state_owner ( state ) , recipient = ! sender ;
const struct htlc * * committed , * * adding , * * removing ;
const struct htlc * * committed , * * adding , * * removing ;
const struct channel_view * view ;
const struct channel_view * view ;
bool ok ;
size_t i ;
htlc = tal ( tmpctx , struct htlc ) ;
htlc = tal ( tmpctx , struct htlc ) ;
@ -432,71 +493,86 @@ static enum channel_add_err add_htlc(struct channel *channel,
* reserve ) :
* reserve ) :
* - SHOULD fail the channel .
* - SHOULD fail the channel .
*/
*/
if ( channel - > funder = = htlc_owner ( htlc ) ) {
u32 feerate = view - > feerate_per_kw ;
struct amount_sat dust_limit = channel - > config [ recipient ] . dust_limit ;
size_t untrimmed ;
untrimmed = commit_tx_num_untrimmed ( committed , feerate , dust_limit ,
recipient )
+ commit_tx_num_untrimmed ( adding , feerate , dust_limit ,
recipient )
- commit_tx_num_untrimmed ( removing , feerate , dust_limit ,
recipient ) ;
fee = commit_tx_base_fee ( feerate , untrimmed ) ;
} else
fee = AMOUNT_SAT ( 0 ) ;
assert ( ( s64 ) fee . satoshis > = 0 ) ; /* Raw: explicit signedness test */
if ( htlc_fee ) * htlc_fee = fee ; /* set fee output pointer if given */
if ( enforce_aggregate_limits ) {
if ( enforce_aggregate_limits ) {
/* Figure out what balance sender would have after applying all
struct amount_msat balance ;
* pending changes . */
struct amount_sat fee = fee_for_htlcs ( channel , view ,
struct amount_msat balance = view - > owed [ sender ] ;
committed ,
adding ,
removing ,
recipient ) ;
/* set fee output pointer if given */
if ( htlc_fee )
* htlc_fee = fee ;
/* This is a little subtle:
/* This is a little subtle:
*
*
* The change is being applied to the receiver but it will
* The change is being applied to the receiver but it will
* come back to the sender after revoke_and_ack . So the check
* come back to the sender after revoke_and_ack . So the check
* here is that the balance to the sender doesn ' t go below the
* here is that the balance to the sender doesn ' t go below the
* sender ' s reserve . */
* sender ' s reserve . */
const struct amount_sat reserve
if ( ! get_room_above_reserve ( channel , view ,
= channel - > config [ ! sender ] . channel_reserve ;
adding , removing , sender ,
& balance ) )
assert ( amount_msat_greater_eq ( balance , AMOUNT_MSAT ( 0 ) ) ) ;
ok = true ;
for ( i = 0 ; i < tal_count ( removing ) ; i + + )
ok & = balance_remove_htlc ( & balance , removing [ i ] , sender ) ;
assert ( amount_msat_greater_eq ( balance , AMOUNT_MSAT ( 0 ) ) ) ;
for ( i = 0 ; i < tal_count ( adding ) ; i + + )
ok & = balance_add_htlc ( & balance , adding [ i ] , sender ) ;
/* Overflow shouldn't happen, but if it does, complain */
if ( ! ok ) {
status_broken ( " Failed to add %zu remove %zu htlcs " ,
tal_count ( adding ) , tal_count ( removing ) ) ;
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED ;
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED ;
}
if ( ! amount_msat_sub_sat ( & balance , balance , fee ) ) {
if ( channel - > funder = = sender ) {
status_trace ( " Cannot afford fee %s with balance %s " ,
if ( amount_msat_less_sat ( balance , fee ) ) {
type_to_string ( tmpctx , struct amount_sat ,
status_trace ( " Cannot afford fee %s with %s above reserve " ,
& fee ) ,
type_to_string ( tmpctx , struct amount_sat ,
type_to_string ( tmpctx , struct amount_msat ,
& fee ) ,
& balance ) ) ;
type_to_string ( tmpctx , struct amount_msat ,
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED ;
& balance ) ) ;
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED ;
}
}
}
if ( ! amount_msat_greater_eq_sat ( balance , reserve ) ) {
status_trace ( " Cannot afford fee %s: would make balance %s "
/* Try not to add a payment which will take funder into fees
" below reserve %s " ,
* on either our side or theirs . */
type_to_string ( tmpctx , struct amount_sat ,
if ( sender = = LOCAL ) {
& fee ) ,
if ( ! get_room_above_reserve ( channel , view ,
type_to_string ( tmpctx , struct amount_msat ,
adding , removing ,
& balance ) ,
channel - > funder ,
type_to_string ( tmpctx , struct amount_sat ,
& balance ) )
& reserve ) ) ;
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED ;
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED ;
/* Should be able to afford both their own commit tx
* fee , and other ' s commit tx fee , which are subtly
* different ! */
fee = fee_for_htlcs ( channel , view ,
committed ,
adding ,
removing ,
channel - > funder ) ;
/* set fee output pointer if given */
if ( htlc_fee & & amount_sat_greater ( fee , * htlc_fee ) )
* htlc_fee = fee ;
if ( amount_msat_less_sat ( balance , fee ) ) {
status_trace ( " Funder could not afford own fee %s with %s above reserve " ,
type_to_string ( tmpctx ,
struct amount_sat ,
& fee ) ,
type_to_string ( tmpctx ,
struct amount_msat ,
& balance ) ) ;
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED ;
}
fee = fee_for_htlcs ( channel , view ,
committed ,
adding ,
removing ,
! channel - > funder ) ;
/* set fee output pointer if given */
if ( htlc_fee & & amount_sat_greater ( fee , * htlc_fee ) )
* htlc_fee = fee ;
if ( amount_msat_less_sat ( balance , fee ) ) {
status_trace ( " Funder could not afford peer's fee %s with %s above reserve " ,
type_to_string ( tmpctx ,
struct amount_sat ,
& fee ) ,
type_to_string ( tmpctx ,
struct amount_msat ,
& balance ) ) ;
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED ;
}
}
}
}
}
@ -832,6 +908,13 @@ bool can_funder_afford_feerate(const struct channel *channel, u32 feerate_per_kw
type_to_string ( tmpctx , struct amount_sat ,
type_to_string ( tmpctx , struct amount_sat ,
& channel - > config [ ! channel - > funder ] . channel_reserve ) ) ;
& channel - > config [ ! channel - > funder ] . channel_reserve ) ) ;
status_trace ( " We need %s at feerate %u for %zu untrimmed htlcs: we have %s/%s " ,
type_to_string ( tmpctx , struct amount_sat , & needed ) ,
feerate_per_kw , untrimmed ,
type_to_string ( tmpctx , struct amount_msat ,
& channel - > view [ LOCAL ] . owed [ channel - > funder ] ) ,
type_to_string ( tmpctx , struct amount_msat ,
& channel - > view [ REMOTE ] . owed [ channel - > funder ] ) ) ;
return amount_msat_greater_eq_sat ( channel - > view [ ! channel - > funder ] . owed [ channel - > funder ] ,
return amount_msat_greater_eq_sat ( channel - > view [ ! channel - > funder ] . owed [ channel - > funder ] ,
needed ) ;
needed ) ;
}
}