mirror of
https://github.com/aljazceru/lightning.git
synced 2026-01-03 22:34:21 +01:00
channeld: Code to implement splicing
Update the lightningd <-> channeld interface with lots of new commands to needed to facilitate spicing. Implement the channeld splicing protocol leveraging the interactivetx protocol. Implement lightningd’s channel_control to support channeld in its splicing efforts. Changelog-Added: Added the features to enable splicing & resizing of active channels.
This commit is contained in:
committed by
Rusty Russell
parent
ebd0a3fd69
commit
4628e3ace8
@@ -37,6 +37,14 @@ struct amount_sat amount_msat_to_sat_round_down(struct amount_msat msat)
|
||||
return sat;
|
||||
}
|
||||
|
||||
struct amount_msat amount_msat_to_sat_remainder(struct amount_msat msat)
|
||||
{
|
||||
struct amount_msat res;
|
||||
|
||||
res.millisatoshis = msat.millisatoshis % MSAT_PER_SAT;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Different formatting by amounts: btc, sat and msat */
|
||||
const char *fmt_amount_msat_btc(const tal_t *ctx,
|
||||
struct amount_msat msat,
|
||||
@@ -360,6 +368,27 @@ WARN_UNUSED_RESULT bool amount_sat_scale(struct amount_sat *val,
|
||||
return true;
|
||||
}
|
||||
|
||||
WARN_UNUSED_RESULT bool amount_msat_add_sat_s64(struct amount_msat *val,
|
||||
struct amount_msat a,
|
||||
s64 b)
|
||||
{
|
||||
if (b < 0)
|
||||
return amount_msat_sub_sat(val, a, amount_sat(-b));
|
||||
else
|
||||
return amount_msat_add_sat(val, a, amount_sat(b));
|
||||
}
|
||||
|
||||
|
||||
WARN_UNUSED_RESULT bool amount_sat_add_sat_s64(struct amount_sat *val,
|
||||
struct amount_sat a,
|
||||
s64 b)
|
||||
{
|
||||
if (b < 0)
|
||||
return amount_sat_sub(val, a, amount_sat(-b));
|
||||
else
|
||||
return amount_sat_add(val, a, amount_sat(b));
|
||||
}
|
||||
|
||||
bool amount_sat_eq(struct amount_sat a, struct amount_sat b)
|
||||
{
|
||||
return a.satoshis == b.satoshis;
|
||||
|
||||
@@ -60,6 +60,9 @@ WARN_UNUSED_RESULT bool amount_msat_to_sat(struct amount_sat *sat,
|
||||
/* You can always truncate millisatoshis->satoshis. */
|
||||
struct amount_sat amount_msat_to_sat_round_down(struct amount_msat msat);
|
||||
|
||||
/* The msats truncated by `amount_msat_to_sat_round_down` */
|
||||
struct amount_msat amount_msat_to_sat_remainder(struct amount_msat msat);
|
||||
|
||||
/* Simple operations: val = a + b, val = a - b. */
|
||||
WARN_UNUSED_RESULT bool amount_msat_add(struct amount_msat *val,
|
||||
struct amount_msat a,
|
||||
@@ -89,6 +92,14 @@ WARN_UNUSED_RESULT bool amount_sat_scale(struct amount_sat *val,
|
||||
struct amount_sat sat,
|
||||
double scale);
|
||||
|
||||
WARN_UNUSED_RESULT bool amount_msat_add_sat_s64(struct amount_msat *val,
|
||||
struct amount_msat a,
|
||||
s64 b);
|
||||
|
||||
WARN_UNUSED_RESULT bool amount_sat_add_sat_s64(struct amount_sat *val,
|
||||
struct amount_sat a,
|
||||
s64 b);
|
||||
|
||||
struct amount_msat amount_msat_div(struct amount_msat msat, u64 div);
|
||||
struct amount_sat amount_sat_div(struct amount_sat sat, u64 div);
|
||||
|
||||
|
||||
@@ -142,6 +142,10 @@ static const struct feature_style feature_styles[] = {
|
||||
{ OPT_PROVIDE_PEER_BACKUP_STORAGE,
|
||||
.copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT,
|
||||
[NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT } },
|
||||
{ OPT_SPLICE,
|
||||
.copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT,
|
||||
[NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT,
|
||||
[CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT} },
|
||||
};
|
||||
|
||||
struct dependency {
|
||||
@@ -467,7 +471,7 @@ const char *feature_name(const tal_t *ctx, size_t f)
|
||||
"option_trampoline_routing", /* https://github.com/lightning/bolts/pull/836 */
|
||||
NULL,
|
||||
NULL, /* 60/61 */
|
||||
NULL,
|
||||
"option_splice",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -99,7 +99,7 @@ struct feature_set *feature_set_dup(const tal_t *ctx,
|
||||
#define COMPULSORY_FEATURE(x) ((x) & 0xFFFFFFFE)
|
||||
#define OPTIONAL_FEATURE(x) ((x) | 1)
|
||||
|
||||
/* BOLT #9:
|
||||
/* BOLT-a526652801a541ed33b34d000a3b686a857c811f #9:
|
||||
*
|
||||
* | Bits | Name |...
|
||||
* | 0/1 | `option_data_loss_protect` |... IN ...
|
||||
@@ -118,6 +118,7 @@ struct feature_set *feature_set_dup(const tal_t *ctx,
|
||||
* | 26/27 | `option_shutdown_anysegwit` |... IN ...
|
||||
* | 44/45 | `option_channel_type` |... IN ...
|
||||
* | 48/49 | `option_payment_metadata` |... 9 ...
|
||||
* | 62/63 | `option_splice` |... IN ...
|
||||
*/
|
||||
#define OPT_DATA_LOSS_PROTECT 0
|
||||
#define OPT_INITIAL_ROUTING_SYNC 2
|
||||
@@ -135,6 +136,7 @@ struct feature_set *feature_set_dup(const tal_t *ctx,
|
||||
#define OPT_SHUTDOWN_ANYSEGWIT 26
|
||||
#define OPT_CHANNEL_TYPE 44
|
||||
#define OPT_PAYMENT_METADATA 48
|
||||
#define OPT_SPLICE 62
|
||||
|
||||
/* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #9:
|
||||
* | 28/29 | `option_dual_fund` | ... IN9 ...
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* only onion tlv payloads. */
|
||||
#define ROUTING_MAX_HOPS 20
|
||||
|
||||
/* BOLT #7:
|
||||
/* BOLT-f3a9f7f4e9e7a5a2997f3129e13d94090091846a #7:
|
||||
*
|
||||
* The `channel_flags` bitfield...individual bits:
|
||||
*...
|
||||
|
||||
@@ -65,6 +65,11 @@ struct channel *new_initial_channel(const tal_t *ctx,
|
||||
= channel->view[LOCAL].owed[REMOTE]
|
||||
= remote_msatoshi;
|
||||
|
||||
channel->view[LOCAL].lowest_splice_amnt[LOCAL] = 0;
|
||||
channel->view[LOCAL].lowest_splice_amnt[REMOTE] = 0;
|
||||
channel->view[REMOTE].lowest_splice_amnt[LOCAL] = 0;
|
||||
channel->view[REMOTE].lowest_splice_amnt[REMOTE] = 0;
|
||||
|
||||
channel->basepoints[LOCAL] = *local_basepoints;
|
||||
channel->basepoints[REMOTE] = *remote_basepoints;
|
||||
|
||||
@@ -147,6 +152,34 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx,
|
||||
return init_tx;
|
||||
}
|
||||
|
||||
const char *channel_update_funding(struct channel *channel,
|
||||
const struct bitcoin_outpoint *funding,
|
||||
struct amount_sat funding_sats,
|
||||
s64 splice_amnt)
|
||||
{
|
||||
s64 funding_diff = (s64)funding_sats.satoshis - (s64)channel->funding_sats.satoshis; /* Raw: splicing */
|
||||
s64 remote_splice_amnt = funding_diff - splice_amnt;
|
||||
|
||||
channel->funding = *funding;
|
||||
channel->funding_sats = funding_sats;
|
||||
|
||||
if (splice_amnt * 1000 + channel->view[LOCAL].owed[LOCAL].millisatoshis < 0) /* Raw: splicing */
|
||||
return tal_fmt(tmpctx, "Channel funding update would make local"
|
||||
" balance negative.");
|
||||
|
||||
channel->view[LOCAL].owed[LOCAL].millisatoshis += splice_amnt * 1000; /* Raw: splicing */
|
||||
channel->view[REMOTE].owed[LOCAL].millisatoshis += splice_amnt * 1000; /* Raw: splicing */
|
||||
|
||||
if (remote_splice_amnt * 1000 + channel->view[LOCAL].owed[REMOTE].millisatoshis < 0) /* Raw: splicing */
|
||||
return tal_fmt(tmpctx, "Channel funding update would make"
|
||||
" remote balance negative.");
|
||||
|
||||
channel->view[LOCAL].owed[REMOTE].millisatoshis += remote_splice_amnt * 1000; /* Raw: splicing */
|
||||
channel->view[REMOTE].owed[REMOTE].millisatoshis += remote_splice_amnt * 1000; /* Raw: splicing */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u32 channel_feerate(const struct channel *channel, enum side side)
|
||||
{
|
||||
return get_feerate(channel->fee_states, channel->opener, side);
|
||||
|
||||
@@ -16,8 +16,19 @@ struct fulfilled_htlc;
|
||||
|
||||
/* View from each side */
|
||||
struct channel_view {
|
||||
/* How much is owed to each side (includes pending changes) */
|
||||
/* How much is owed to each side (includes pending changes).
|
||||
* The index of `owed` array is always relative to the machine
|
||||
* this code is running on, so REMOTE is always the other machine
|
||||
* and LOCAL is always this machine (regardless of view).
|
||||
*
|
||||
* For example:
|
||||
* view[REMOTE].owed[REMOTE] == view[LOCAL].owed[REMOTE]
|
||||
* view[REMOTE].owed[LOCAL] == view[LOCAL].owed[LOCAL]
|
||||
*/
|
||||
struct amount_msat owed[NUM_SIDES];
|
||||
/* Lowest splice relative change amount of all candidate splices.
|
||||
* This will be 0 or negative -- never positive. */
|
||||
s64 lowest_splice_amnt[NUM_SIDES];
|
||||
};
|
||||
|
||||
struct channel {
|
||||
@@ -135,6 +146,17 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx,
|
||||
struct wally_tx_output *direct_outputs[NUM_SIDES],
|
||||
char** err_reason);
|
||||
|
||||
/* channel_update_funding: Changes the funding for the channel and updates the
|
||||
* balance by the difference between `old_local_funding_msatoshi` and
|
||||
* `new_local_funding_msatoshi`.
|
||||
*
|
||||
* Returns NULL on success or an error on failure.
|
||||
*/
|
||||
const char *channel_update_funding(struct channel *channel,
|
||||
const struct bitcoin_outpoint *funding,
|
||||
struct amount_sat funding_sats,
|
||||
s64 splice_amnt);
|
||||
|
||||
/**
|
||||
* channel_feerate: Get fee rate for this side of channel.
|
||||
* @channel: The channel
|
||||
|
||||
@@ -503,6 +503,18 @@ struct command_result *param_u64(struct command *cmd, const char *name,
|
||||
"should be an unsigned 64 bit integer");
|
||||
}
|
||||
|
||||
struct command_result *param_s64(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
int64_t **num)
|
||||
{
|
||||
*num = tal(cmd, int64_t);
|
||||
if (json_to_s64(buffer, tok, *num))
|
||||
return NULL;
|
||||
|
||||
return command_fail_badparam(cmd, name, buffer, tok,
|
||||
"should be an sign 64 bit integer");
|
||||
}
|
||||
|
||||
struct command_result *param_msat(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
struct amount_msat **msat)
|
||||
|
||||
@@ -212,6 +212,11 @@ struct command_result *param_u64(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
uint64_t **num);
|
||||
|
||||
/* Extract number from this (may be a string, or a number literal) */
|
||||
struct command_result *param_s64(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
int64_t **num);
|
||||
|
||||
/* Extract msatoshi amount from this string */
|
||||
struct command_result *param_msat(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
|
||||
@@ -71,6 +71,8 @@ enum jsonrpc_errcode {
|
||||
SPLICE_UNKNOWN_CHANNEL = 352,
|
||||
SPLICE_INVALID_CHANNEL_STATE = 353,
|
||||
SPLICE_NOT_SUPPORTED = 354,
|
||||
SPLICE_BUSY_ERROR = 355,
|
||||
SPLICE_INPUT_ERROR = 356,
|
||||
|
||||
/* `connect` errors */
|
||||
CONNECT_NO_KNOWN_ADDRESS = 400,
|
||||
|
||||
@@ -165,32 +165,3 @@ psbt_to_witnesses(const tal_t *ctx,
|
||||
|
||||
return witnesses;
|
||||
}
|
||||
|
||||
size_t psbt_input_weight(struct wally_psbt *psbt,
|
||||
size_t in)
|
||||
{
|
||||
size_t weight;
|
||||
const struct wally_map_item *redeem_script;
|
||||
|
||||
redeem_script = wally_map_get_integer(&psbt->inputs[in].psbt_fields, /* PSBT_IN_REDEEM_SCRIPT */ 0x04);
|
||||
|
||||
/* txid + txout + sequence */
|
||||
weight = (32 + 4 + 4) * 4;
|
||||
if (redeem_script) {
|
||||
weight +=
|
||||
(redeem_script->value_len +
|
||||
(varint_t) varint_size(redeem_script->value_len)) * 4;
|
||||
} else {
|
||||
/* zero scriptSig length */
|
||||
weight += (varint_t) varint_size(0) * 4;
|
||||
}
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
size_t psbt_output_weight(struct wally_psbt *psbt,
|
||||
size_t outnum)
|
||||
{
|
||||
return (8 + psbt->outputs[outnum].script_len +
|
||||
varint_size(psbt->outputs[outnum].script_len)) * 4;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ void psbt_finalize_input(const tal_t *ctx,
|
||||
struct wally_psbt_input *in,
|
||||
const struct witness *witness);
|
||||
|
||||
/* psbt_to_witness_stacks - Take a side's sigs from a PSBT and copy to a
|
||||
/* psbt_to_witnesses - Take a side's sigs from a PSBT and copy to a
|
||||
* wire witness
|
||||
*
|
||||
* @ctx - allocation context
|
||||
@@ -35,12 +35,4 @@ psbt_to_witnesses(const tal_t *ctx,
|
||||
enum tx_role side_to_stack,
|
||||
int input_index_to_ignore);
|
||||
|
||||
/* psbt_input_weight - Calculate the tx weight for input index `in` */
|
||||
size_t psbt_input_weight(struct wally_psbt *psbt,
|
||||
size_t in);
|
||||
|
||||
/* psbt_output_weight - Calculate the tx weight for output index `outnum` */
|
||||
size_t psbt_output_weight(struct wally_psbt *psbt,
|
||||
size_t outnum);
|
||||
|
||||
#endif /* LIGHTNING_COMMON_PSBT_INTERNAL_H */
|
||||
|
||||
@@ -45,9 +45,6 @@ void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id U
|
||||
/* Generated stub for towire_node_id */
|
||||
void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED)
|
||||
{ fprintf(stderr, "towire_node_id called!\n"); abort(); }
|
||||
/* Generated stub for towire_s64 */
|
||||
void towire_s64(u8 **pptr UNNEEDED, s64 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_s64 called!\n"); abort(); }
|
||||
/* Generated stub for towire_secp256k1_ecdsa_signature */
|
||||
void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED,
|
||||
const secp256k1_ecdsa_signature *signature UNNEEDED)
|
||||
@@ -70,6 +67,9 @@ void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
|
||||
/* Generated stub for towire_u64 */
|
||||
void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u64 called!\n"); abort(); }
|
||||
/* Generated stub for towire_s64 */
|
||||
void towire_s64(u8 **pptr UNNEEDED, s64 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_s64 called!\n"); abort(); }
|
||||
/* Generated stub for towire_u8 */
|
||||
void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u8 called!\n"); abort(); }
|
||||
|
||||
@@ -87,6 +87,9 @@ u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
/* Generated stub for fromwire_u64 */
|
||||
u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_s64 */
|
||||
s64 fromwire_s64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_s64 called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_u8 */
|
||||
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
|
||||
@@ -184,6 +187,9 @@ void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
|
||||
/* Generated stub for towire_u64 */
|
||||
void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u64 called!\n"); abort(); }
|
||||
/* Generated stub for towire_s64 */
|
||||
void towire_s64(u8 **pptr UNNEEDED, s64 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_s64 called!\n"); abort(); }
|
||||
/* Generated stub for towire_u8 */
|
||||
void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u8 called!\n"); abort(); }
|
||||
|
||||
Reference in New Issue
Block a user