mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-21 14:24:09 +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:
parent
ebd0a3fd69
commit
4628e3ace8
88 changed files with 4560 additions and 644 deletions
10
.github/workflows/ci.yaml
vendored
10
.github/workflows/ci.yaml
vendored
|
@ -263,6 +263,15 @@ jobs:
|
|||
TEST_NETWORK: regtest
|
||||
DEVELOPER: 1
|
||||
EXPERIMENTAL_DUAL_FUND: 1
|
||||
# And splicing!
|
||||
- NAME: splicing
|
||||
CFG: gcc-dev1
|
||||
TEST_DB_PROVIDER: sqlite3
|
||||
COMPILER: gcc
|
||||
TEST_NETWORK: regtest
|
||||
DEVELOPER: 1
|
||||
EXPERIMENTAL_DUAL_FUND: 1
|
||||
EXPERIMENTAL_SPLICING: 1
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
@ -290,6 +299,7 @@ jobs:
|
|||
DEVELOPER: ${{ matrix.DEVELOPER }}
|
||||
COMPILER: ${{ matrix.COMPILER }}
|
||||
EXPERIMENTAL_DUAL_FUND: ${{ matrix.EXPERIMENTAL_DUAL_FUND }}
|
||||
EXPERIMENTAL_SPLICING: ${{ matrix.EXPERIMENTAL_SPLICING }}
|
||||
COMPAT: 1
|
||||
CFG: ${{ matrix.CFG }}
|
||||
SLOW_MACHINE: 1
|
||||
|
|
11
.msggen.json
11
.msggen.json
|
@ -182,6 +182,7 @@
|
|||
"ListpeerchannelsChannelsState": {
|
||||
"AWAITING_UNILATERAL": 6,
|
||||
"CHANNELD_AWAITING_LOCKIN": 1,
|
||||
"CHANNELD_AWAITING_SPLICE": 11,
|
||||
"CHANNELD_NORMAL": 2,
|
||||
"CHANNELD_SHUTTING_DOWN": 3,
|
||||
"CLOSINGD_COMPLETE": 5,
|
||||
|
@ -1131,6 +1132,7 @@
|
|||
"ListPeerChannels.channels[].inflight[].funding_txid": 1,
|
||||
"ListPeerChannels.channels[].inflight[].our_funding_msat": 5,
|
||||
"ListPeerChannels.channels[].inflight[].scratch_txid": 6,
|
||||
"ListPeerChannels.channels[].inflight[].splice_amount": 7,
|
||||
"ListPeerChannels.channels[].inflight[].total_funding_msat": 4
|
||||
},
|
||||
"ListpeerchannelsChannelsState_changes": {
|
||||
|
@ -1241,6 +1243,7 @@
|
|||
"ListPeers.peers[].channels[].inflight[].funding_txid": 1,
|
||||
"ListPeers.peers[].channels[].inflight[].our_funding_msat": 5,
|
||||
"ListPeers.peers[].channels[].inflight[].scratch_txid": 6,
|
||||
"ListPeers.peers[].channels[].inflight[].splice_amount": 7,
|
||||
"ListPeers.peers[].channels[].inflight[].total_funding_msat": 4
|
||||
},
|
||||
"ListpeersPeersLog": {
|
||||
|
@ -4078,6 +4081,10 @@
|
|||
"added": "v23.02",
|
||||
"deprecated": false
|
||||
},
|
||||
"ListPeerChannels.channels[].inflight[].splice_amount": {
|
||||
"added": "v23.08",
|
||||
"deprecated": false
|
||||
},
|
||||
"ListPeerChannels.channels[].inflight[].total_funding_msat": {
|
||||
"added": "v23.02",
|
||||
"deprecated": false
|
||||
|
@ -4422,6 +4429,10 @@
|
|||
"added": "pre-v0.10.1",
|
||||
"deprecated": false
|
||||
},
|
||||
"ListPeers.peers[].channels[].inflight[].splice_amount": {
|
||||
"added": "v23.08",
|
||||
"deprecated": false
|
||||
},
|
||||
"ListPeers.peers[].channels[].inflight[].total_funding_msat": {
|
||||
"added": "pre-v0.10.1",
|
||||
"deprecated": false
|
||||
|
|
|
@ -322,6 +322,15 @@ void psbt_input_set_utxo(struct wally_psbt *psbt, size_t in,
|
|||
assert(wally_err == WALLY_OK);
|
||||
}
|
||||
|
||||
void psbt_input_set_outpoint(struct wally_psbt *psbt, size_t in,
|
||||
struct bitcoin_outpoint outpoint)
|
||||
{
|
||||
assert(in < psbt->num_inputs);
|
||||
psbt->inputs[in].index = outpoint.n;
|
||||
memcpy(psbt->inputs[in].txhash, &outpoint.txid,
|
||||
sizeof(struct bitcoin_txid));
|
||||
}
|
||||
|
||||
void psbt_input_set_witscript(struct wally_psbt *psbt, size_t in, const u8 *wscript)
|
||||
{
|
||||
int wally_err;
|
||||
|
@ -446,6 +455,28 @@ struct amount_sat psbt_input_get_amount(const struct wally_psbt *psbt,
|
|||
return val;
|
||||
}
|
||||
|
||||
size_t psbt_input_get_weight(const 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_size(redeem_script->value_len)) * 4;
|
||||
} else {
|
||||
/* zero scriptSig length */
|
||||
weight += varint_size(0) * 4;
|
||||
}
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
struct amount_sat psbt_output_get_amount(const struct wally_psbt *psbt,
|
||||
size_t out)
|
||||
{
|
||||
|
@ -456,6 +487,13 @@ struct amount_sat psbt_output_get_amount(const struct wally_psbt *psbt,
|
|||
return amount_asset_to_sat(&asset);
|
||||
}
|
||||
|
||||
size_t psbt_output_get_weight(const struct wally_psbt *psbt,
|
||||
size_t outnum)
|
||||
{
|
||||
return (8 /* amount*/ + varint_size(psbt->outputs[outnum].script_len) +
|
||||
psbt->outputs[outnum].script_len) * 4;
|
||||
}
|
||||
|
||||
static void add(u8 **key, const void *mem, size_t len)
|
||||
{
|
||||
size_t oldlen = tal_count(*key);
|
||||
|
@ -733,6 +771,12 @@ const u8 *psbt_get_bytes(const tal_t *ctx, const struct wally_psbt *psbt,
|
|||
return bytes;
|
||||
}
|
||||
|
||||
bool validate_psbt(const struct wally_psbt *psbt)
|
||||
{
|
||||
size_t len;
|
||||
return wally_psbt_get_length(psbt, 0, &len) == WALLY_OK;
|
||||
}
|
||||
|
||||
struct wally_psbt *psbt_from_bytes(const tal_t *ctx, const u8 *bytes,
|
||||
size_t byte_len)
|
||||
{
|
||||
|
|
|
@ -127,6 +127,9 @@ void psbt_input_set_wit_utxo(struct wally_psbt *psbt, size_t in,
|
|||
void psbt_input_set_utxo(struct wally_psbt *psbt, size_t in,
|
||||
const struct wally_tx *prev_tx);
|
||||
|
||||
void psbt_input_set_outpoint(struct wally_psbt *psbt, size_t in,
|
||||
struct bitcoin_outpoint outpoint);
|
||||
|
||||
/* psbt_elements_input_set_asset - Set the asset/value fields for an
|
||||
* Elements PSBT (PSET, technically */
|
||||
void psbt_elements_input_set_asset(struct wally_psbt *psbt, size_t in,
|
||||
|
@ -211,6 +214,10 @@ void psbt_output_set_unknown(const tal_t *ctx,
|
|||
struct amount_sat psbt_input_get_amount(const struct wally_psbt *psbt,
|
||||
size_t in);
|
||||
|
||||
/* psbt_input_get_weight - Calculate the tx weight for input index `in` */
|
||||
size_t psbt_input_get_weight(const struct wally_psbt *psbt,
|
||||
size_t in);
|
||||
|
||||
/* psbt_output_get_amount - Returns the value of this output
|
||||
*
|
||||
* @psbt - psbt
|
||||
|
@ -219,6 +226,10 @@ struct amount_sat psbt_input_get_amount(const struct wally_psbt *psbt,
|
|||
struct amount_sat psbt_output_get_amount(const struct wally_psbt *psbt,
|
||||
size_t out);
|
||||
|
||||
/* psbt_output_get_weight - Calculate the tx weight for output index `outnum` */
|
||||
size_t psbt_output_get_weight(const struct wally_psbt *psbt,
|
||||
size_t outnum);
|
||||
|
||||
/* psbt_compute_fee - Returns value of fee for PSBT
|
||||
*
|
||||
* @psbt -psbt
|
||||
|
@ -266,6 +277,7 @@ struct wally_psbt *psbt_from_b64(const tal_t *ctx,
|
|||
char *psbt_to_b64(const tal_t *ctx, const struct wally_psbt *psbt);
|
||||
const u8 *psbt_get_bytes(const tal_t *ctx, const struct wally_psbt *psbt,
|
||||
size_t *bytes_written);
|
||||
bool validate_psbt(const struct wally_psbt *psbt);
|
||||
struct wally_psbt *psbt_from_bytes(const tal_t *ctx, const u8 *bytes,
|
||||
size_t byte_len);
|
||||
void towire_wally_psbt(u8 **pptr, const struct wally_psbt *psbt);
|
||||
|
|
|
@ -13,6 +13,8 @@ CHANNELD_HEADERS := \
|
|||
CHANNELD_SRC := channeld/channeld.c \
|
||||
channeld/commit_tx.c \
|
||||
channeld/full_channel.c \
|
||||
channeld/splice.c \
|
||||
channeld/inflight.c \
|
||||
channeld/channeld_wiregen.c \
|
||||
channeld/watchtower.c
|
||||
|
||||
|
@ -25,8 +27,13 @@ ALL_C_HEADERS += $(CHANNELD_HEADERS)
|
|||
ALL_PROGRAMS += lightningd/lightning_channeld
|
||||
|
||||
# Here's what lightningd depends on
|
||||
LIGHTNINGD_CONTROL_HEADERS += channeld/channeld_wiregen.h
|
||||
LIGHTNINGD_CONTROL_OBJS += channeld/channeld_wiregen.o
|
||||
LIGHTNINGD_CONTROL_HEADERS += \
|
||||
channeld/channeld_wiregen.h \
|
||||
channeld/inflight.h
|
||||
LIGHTNINGD_CONTROL_OBJS += \
|
||||
channeld/channeld_wiregen.o \
|
||||
channeld/inflight.o
|
||||
|
||||
|
||||
# Common source we use.
|
||||
CHANNELD_COMMON_OBJS := \
|
||||
|
@ -53,6 +60,7 @@ CHANNELD_COMMON_OBJS := \
|
|||
common/status_wiregen.o \
|
||||
common/gossip_store.o \
|
||||
common/hmac.o \
|
||||
common/interactivetx.o \
|
||||
common/htlc_state.o \
|
||||
common/htlc_trim.o \
|
||||
common/htlc_tx.o \
|
||||
|
@ -73,6 +81,7 @@ CHANNELD_COMMON_OBJS := \
|
|||
common/ping.o \
|
||||
common/psbt_keypath.o \
|
||||
common/psbt_open.o \
|
||||
common/psbt_internal.o \
|
||||
common/private_channel_announcement.o \
|
||||
common/pseudorand.o \
|
||||
common/read_peer_msg.o \
|
||||
|
|
2212
channeld/channeld.c
2212
channeld/channeld.c
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,6 @@
|
|||
#include <bitcoin/psbt.h>
|
||||
#include <bitcoin/tx.h>
|
||||
#include <channeld/inflight.h>
|
||||
#include <common/bip32.h>
|
||||
#include <common/blockheight_states.h>
|
||||
#include <common/cryptomsg.h>
|
||||
|
@ -83,6 +84,8 @@ msgdata,channeld_init,reestablish_only,bool,
|
|||
msgdata,channeld_init,channel_update_len,u16,
|
||||
msgdata,channeld_init,channel_update,u8,channel_update_len
|
||||
msgdata,channeld_init,experimental_upgrade,bool,
|
||||
msgdata,channeld_init,num_inflights,u16,
|
||||
msgdata,channeld_init,inflights,inflight,num_inflights
|
||||
|
||||
# master->channeld funding hit new depth(funding locked if >= lock depth)
|
||||
# alias != NULL if zeroconf and short_channel_id == NULL
|
||||
|
@ -91,6 +94,8 @@ msgtype,channeld_funding_depth,1002
|
|||
msgdata,channeld_funding_depth,short_channel_id,?short_channel_id,
|
||||
msgdata,channeld_funding_depth,alias_local,?short_channel_id,
|
||||
msgdata,channeld_funding_depth,depth,u32,
|
||||
msgdata,channeld_funding_depth,splicing,bool,
|
||||
msgdata,channeld_funding_depth,txid,bitcoin_txid,
|
||||
|
||||
# Tell channel to offer this htlc
|
||||
msgtype,channeld_offer_htlc,1004
|
||||
|
@ -122,6 +127,12 @@ msgtype,channeld_got_channel_ready,1019
|
|||
msgdata,channeld_got_channel_ready,next_per_commit_point,pubkey,
|
||||
msgdata,channeld_got_channel_ready,alias,?short_channel_id,
|
||||
|
||||
# When we receive funding_locked.
|
||||
msgtype,channeld_got_splice_locked,1119
|
||||
msgdata,channeld_got_splice_locked,funding_sats,amount_sat,
|
||||
msgdata,channeld_got_splice_locked,splice_amnt,s64,
|
||||
msgdata,channeld_got_splice_locked,locked_txid,bitcoin_txid,
|
||||
|
||||
#include <common/penalty_base.h>
|
||||
|
||||
# When we send a commitment_signed message, tell master.
|
||||
|
@ -160,6 +171,14 @@ msgdata,channeld_got_commitsig,failed,failed_htlc,num_failed
|
|||
msgdata,channeld_got_commitsig,num_changed,u16,
|
||||
msgdata,channeld_got_commitsig,changed,changed_htlc,num_changed
|
||||
msgdata,channeld_got_commitsig,tx,bitcoin_tx,
|
||||
# Inflight splice commitments
|
||||
msgdata,channeld_got_commitsig,num_inflight_commitsigs,u16,
|
||||
msgdata,channeld_got_commitsig,inflight_commitsigs,commitsig,num_inflight_commitsigs
|
||||
subtype,commitsig
|
||||
subtypedata,commitsig,tx,bitcoin_tx,
|
||||
subtypedata,commitsig,commit_signature,bitcoin_signature,
|
||||
subtypedata,commitsig,num_htlcs,u16,
|
||||
subtypedata,commitsig,htlc_signatures,bitcoin_signature,num_htlcs
|
||||
|
||||
# Wait for reply, to make sure it's on disk before we send revocation.
|
||||
msgtype,channeld_got_commitsig_reply,1121
|
||||
|
@ -182,6 +201,79 @@ msgdata,channeld_got_revoke,penalty_tx,?bitcoin_tx,
|
|||
msgtype,channeld_got_revoke_reply,1122
|
||||
|
||||
#include <wally_bip32.h>
|
||||
|
||||
# master->channeld: hello, I'd like to start a channel splice open
|
||||
msgtype,channeld_splice_init,7204
|
||||
msgdata,channeld_splice_init,psbt,wally_psbt,
|
||||
msgdata,channeld_splice_init,relative_amount,s64,
|
||||
msgdata,channeld_splice_init,feerate_per_kw,u32,
|
||||
msgdata,channeld_splice_init,force_feerate,bool,
|
||||
|
||||
# channeld->master: hello, I started a channel splice open
|
||||
msgtype,channeld_splice_confirmed_init,7205
|
||||
msgdata,channeld_splice_confirmed_init,psbt,wally_psbt,
|
||||
|
||||
# master->channeld: Update an active splice
|
||||
msgtype,channeld_splice_update,7206
|
||||
msgdata,channeld_splice_update,psbt,wally_psbt,
|
||||
|
||||
# channeld->master: Splice update complete
|
||||
msgtype,channeld_splice_confirmed_update,7207
|
||||
msgdata,channeld_splice_confirmed_update,psbt,wally_psbt,
|
||||
msgdata,channeld_splice_confirmed_update,commitments_secured,bool,
|
||||
|
||||
# channeld->master: Lookup a transaction
|
||||
msgtype,channeld_splice_lookup_tx,7208
|
||||
msgdata,channeld_splice_lookup_tx,txid,bitcoin_txid,
|
||||
|
||||
# master->channeld: Retrieved transaction
|
||||
msgtype,channeld_splice_lookup_tx_result,7209
|
||||
msgdata,channeld_splice_lookup_tx_result,tx,bitcoin_tx,
|
||||
|
||||
# master->channeld: User has signed psbt and it's ready to complete
|
||||
msgtype,channeld_splice_signed,7212
|
||||
msgdata,channeld_splice_signed,psbt,wally_psbt,
|
||||
msgdata,channeld_splice_signed,force_sign_first,bool,
|
||||
|
||||
# channeld->master: Signed psbt is completed
|
||||
msgtype,channeld_splice_confirmed_signed,7213
|
||||
msgdata,channeld_splice_confirmed_signed,tx,bitcoin_tx,
|
||||
msgdata,channeld_splice_confirmed_signed,output_index,u32,
|
||||
|
||||
# channeld->master: A feerate error has occured
|
||||
msgtype,channeld_splice_feerate_error,7215
|
||||
msgdata,channeld_splice_feerate_error,fee,amount_msat,
|
||||
msgdata,channeld_splice_feerate_error,too_high,bool,
|
||||
|
||||
# channeld->master: Add an inflight to the DB
|
||||
msgtype,channeld_add_inflight,7216
|
||||
msgdata,channeld_add_inflight,tx_id,bitcoin_txid,
|
||||
msgdata,channeld_add_inflight,tx_outnum,u32,
|
||||
msgdata,channeld_add_inflight,feerate,u32,
|
||||
msgdata,channeld_add_inflight,satoshis,amount_sat,
|
||||
msgdata,channeld_add_inflight,splice_amount,s64,
|
||||
msgdata,channeld_add_inflight,psbt,wally_psbt,
|
||||
msgdata,channeld_add_inflight,i_am_initiator,bool,
|
||||
|
||||
# master->channeld: Inflight saved successfully
|
||||
msgtype,channeld_got_inflight,7217
|
||||
|
||||
# channeld->master: Update inflight with sigs
|
||||
msgtype,channeld_update_inflight,7219
|
||||
msgdata,channeld_update_inflight,psbt,wally_psbt,
|
||||
msgdata,channeld_update_inflight,last_tx,?bitcoin_tx,
|
||||
msgdata,channeld_update_inflight,last_sig,?bitcoin_signature,
|
||||
|
||||
# channeld->master: A funding error has occured
|
||||
msgtype,channeld_splice_funding_error,7220
|
||||
msgdata,channeld_splice_funding_error,funding,amount_msat,
|
||||
msgdata,channeld_splice_funding_error,req_funding,amount_msat,
|
||||
msgdata,channeld_splice_funding_error,opener_error,bool,
|
||||
|
||||
# channeld->master: A splice state error has occured
|
||||
msgtype,channeld_splice_state_error,7221
|
||||
msgdata,channeld_splice_state_error,state_error,wirestring,
|
||||
|
||||
# Tell peer to shut down channel.
|
||||
msgtype,channeld_send_shutdown,1023
|
||||
msgdata,channeld_send_shutdown,final_index,?u32,
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 15.
|
|
@ -308,10 +308,30 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx,
|
|||
const struct pubkey *per_commitment_point,
|
||||
u64 commitment_number,
|
||||
enum side side)
|
||||
{
|
||||
return channel_splice_txs(ctx, &channel->funding, channel->funding_sats,
|
||||
htlcmap, direct_outputs, funding_wscript,
|
||||
channel, per_commitment_point,
|
||||
commitment_number, side, 0, 0);
|
||||
}
|
||||
|
||||
struct bitcoin_tx **channel_splice_txs(const tal_t *ctx,
|
||||
const struct bitcoin_outpoint *funding,
|
||||
struct amount_sat funding_sats,
|
||||
const struct htlc ***htlcmap,
|
||||
struct wally_tx_output *direct_outputs[NUM_SIDES],
|
||||
const u8 **funding_wscript,
|
||||
const struct channel *channel,
|
||||
const struct pubkey *per_commitment_point,
|
||||
u64 commitment_number,
|
||||
enum side side,
|
||||
s64 splice_amnt,
|
||||
s64 remote_splice_amnt)
|
||||
{
|
||||
struct bitcoin_tx **txs;
|
||||
const struct htlc **committed;
|
||||
struct keyset keyset;
|
||||
struct amount_msat side_pay, other_side_pay;
|
||||
|
||||
if (!derive_keyset(per_commitment_point,
|
||||
&channel->basepoints[side],
|
||||
|
@ -329,10 +349,25 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx,
|
|||
&channel->funding_pubkey[side],
|
||||
&channel->funding_pubkey[!side]);
|
||||
|
||||
side_pay = channel->view[side].owed[side];
|
||||
other_side_pay = channel->view[side].owed[!side];
|
||||
|
||||
if (side == LOCAL) {
|
||||
if (!amount_msat_add_sat_s64(&side_pay, side_pay, splice_amnt))
|
||||
return NULL;
|
||||
if (!amount_msat_add_sat_s64(&other_side_pay, other_side_pay, remote_splice_amnt))
|
||||
return NULL;
|
||||
} else if (side == REMOTE) {
|
||||
if (!amount_msat_add_sat_s64(&side_pay, side_pay, remote_splice_amnt))
|
||||
return NULL;
|
||||
if (!amount_msat_add_sat_s64(&other_side_pay, other_side_pay, splice_amnt))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
txs = tal_arr(ctx, struct bitcoin_tx *, 1);
|
||||
txs[0] = commit_tx(
|
||||
ctx, &channel->funding,
|
||||
channel->funding_sats,
|
||||
txs, funding,
|
||||
funding_sats,
|
||||
&channel->funding_pubkey[side],
|
||||
&channel->funding_pubkey[!side],
|
||||
channel->opener,
|
||||
|
@ -340,8 +375,8 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx,
|
|||
channel->lease_expiry,
|
||||
channel_blockheight(channel, side),
|
||||
&keyset, channel_feerate(channel, side),
|
||||
channel->config[side].dust_limit, channel->view[side].owed[side],
|
||||
channel->view[side].owed[!side], committed, htlcmap, direct_outputs,
|
||||
channel->config[side].dust_limit, side_pay,
|
||||
other_side_pay, committed, htlcmap, direct_outputs,
|
||||
commitment_number ^ channel->commitment_number_obscurer,
|
||||
channel_has(channel, OPT_ANCHOR_OUTPUTS),
|
||||
channel_has(channel, OPT_ANCHORS_ZERO_FEE_HTLC_TX),
|
||||
|
@ -371,8 +406,22 @@ static bool get_room_above_reserve(const struct channel *channel,
|
|||
/* Reserve is set by the *other* side */
|
||||
struct amount_sat reserve = channel->config[!side].channel_reserve;
|
||||
struct balance balance;
|
||||
struct amount_msat owed = view->owed[side];
|
||||
|
||||
to_balance(&balance, view->owed[side]);
|
||||
/* `lowest_splice_amnt` will always be negative or 0 */
|
||||
if (amount_msat_less_eq_sat(owed, amount_sat(-view->lowest_splice_amnt[side]))) {
|
||||
status_debug("Relative splice balance invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* `lowest_splice_amnt` is a relative amount */
|
||||
if (!amount_msat_sub_sat(&owed, owed,
|
||||
amount_sat(-view->lowest_splice_amnt[side]))) {
|
||||
status_debug("Owed amount should not wrap around from splice");
|
||||
return false;
|
||||
}
|
||||
|
||||
to_balance(&balance, owed);
|
||||
|
||||
for (size_t i = 0; i < tal_count(removing); i++)
|
||||
balance_remove_htlc(&balance, removing[i], side);
|
||||
|
|
|
@ -76,6 +76,22 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx,
|
|||
u64 commitment_number,
|
||||
enum side side);
|
||||
|
||||
/* Version of `channel_txs` that lets you specify a custom funding outpoint
|
||||
* and funding_sats.
|
||||
*/
|
||||
struct bitcoin_tx **channel_splice_txs(const tal_t *ctx,
|
||||
const struct bitcoin_outpoint *funding,
|
||||
struct amount_sat funding_sats,
|
||||
const struct htlc ***htlcmap,
|
||||
struct wally_tx_output *direct_outputs[NUM_SIDES],
|
||||
const u8 **funding_wscript,
|
||||
const struct channel *channel,
|
||||
const struct pubkey *per_commitment_point,
|
||||
u64 commitment_number,
|
||||
enum side side,
|
||||
s64 splice_amnt,
|
||||
s64 remote_splice_amnt);
|
||||
|
||||
/**
|
||||
* actual_feerate: what is the actual feerate for the local side.
|
||||
* @channel: The channel state
|
||||
|
|
42
channeld/inflight.c
Normal file
42
channeld/inflight.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/psbt.h>
|
||||
#include <channeld/inflight.h>
|
||||
#include <wire/wire.h>
|
||||
|
||||
struct inflight *fromwire_inflight(const tal_t *ctx, const u8 **cursor, size_t *max)
|
||||
{
|
||||
struct inflight *inflight = tal(ctx, struct inflight);
|
||||
|
||||
fromwire_bitcoin_outpoint(cursor, max, &inflight->outpoint);
|
||||
inflight->amnt = fromwire_amount_sat(cursor, max);
|
||||
inflight->psbt = fromwire_wally_psbt(inflight, cursor, max);
|
||||
inflight->splice_amnt = fromwire_s64(cursor, max);
|
||||
inflight->last_tx = fromwire_bitcoin_tx(inflight, cursor, max);
|
||||
fromwire_bitcoin_signature(cursor, max, &inflight->last_sig);
|
||||
inflight->i_am_initiator = fromwire_bool(cursor, max);
|
||||
|
||||
return inflight;
|
||||
}
|
||||
|
||||
void towire_inflight(u8 **pptr, const struct inflight *inflight)
|
||||
{
|
||||
towire_bitcoin_outpoint(pptr, &inflight->outpoint);
|
||||
towire_amount_sat(pptr, inflight->amnt);
|
||||
towire_wally_psbt(pptr, inflight->psbt);
|
||||
towire_s64(pptr, inflight->splice_amnt);
|
||||
towire_bitcoin_tx(pptr, inflight->last_tx);
|
||||
towire_bitcoin_signature(pptr, &inflight->last_sig);
|
||||
towire_bool(pptr, inflight->i_am_initiator);
|
||||
}
|
||||
|
||||
void copy_inflight(struct inflight *dest, struct inflight *src)
|
||||
{
|
||||
dest->outpoint = src->outpoint;
|
||||
dest->amnt = src->amnt;
|
||||
dest->psbt = src->psbt ? clone_psbt(dest, src->psbt): NULL;
|
||||
dest->splice_amnt = src->splice_amnt;
|
||||
dest->last_tx = src->last_tx ? clone_bitcoin_tx(dest, src->last_tx) : NULL;
|
||||
dest->last_sig = src->last_sig;
|
||||
dest->i_am_initiator = src->i_am_initiator;
|
||||
}
|
24
channeld/inflight.h
Normal file
24
channeld/inflight.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef LIGHTNING_CHANNELD_INFLIGHT_H
|
||||
#define LIGHTNING_CHANNELD_INFLIGHT_H
|
||||
|
||||
#include "config.h"
|
||||
#include <bitcoin/tx.h>
|
||||
#include <common/amount.h>
|
||||
|
||||
struct inflight {
|
||||
struct bitcoin_outpoint outpoint;
|
||||
struct amount_sat amnt;
|
||||
struct wally_psbt *psbt;
|
||||
s64 splice_amnt;
|
||||
struct bitcoin_tx *last_tx;
|
||||
/* last_sig is assumed valid if last_tx is set */
|
||||
struct bitcoin_signature last_sig;
|
||||
bool i_am_initiator;
|
||||
};
|
||||
|
||||
struct inflight *fromwire_inflight(const tal_t *ctx, const u8 **cursor, size_t *max);
|
||||
void towire_inflight(u8 **pptr, const struct inflight *inflight);
|
||||
|
||||
void copy_inflight(struct inflight *dest, struct inflight *src);
|
||||
|
||||
#endif /* LIGHTNING_CHANNELD_INFLIGHT_H */
|
37
channeld/splice.c
Normal file
37
channeld/splice.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
#include "config.h"
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <channeld/splice.h>
|
||||
|
||||
struct splice_state *splice_state_new(const tal_t *ctx)
|
||||
{
|
||||
struct splice_state *splice_state = tal(ctx, struct splice_state);
|
||||
|
||||
splice_state->committed_count = 0;
|
||||
splice_state->revoked_count = 0;
|
||||
splice_state->count = 0;
|
||||
splice_state->locked_ready[LOCAL] = false;
|
||||
splice_state->locked_ready[REMOTE] = false;
|
||||
splice_state->await_commitment_succcess = false;
|
||||
splice_state->inflights = NULL;
|
||||
|
||||
return splice_state;
|
||||
}
|
||||
|
||||
struct splice *splice_new(const tal_t *ctx)
|
||||
{
|
||||
struct splice *splice = tal(ctx, struct splice);
|
||||
|
||||
splice->opener_relative = 0;
|
||||
splice->accepter_relative = 0;
|
||||
splice->feerate_per_kw = 0;
|
||||
splice->force_feerate = false;
|
||||
splice->force_sign_first = false;
|
||||
splice->mode = false;
|
||||
splice->tx_add_input_count = 0;
|
||||
splice->tx_add_output_count = 0;
|
||||
splice->current_psbt = NULL;
|
||||
splice->received_tx_complete = false;
|
||||
splice->sent_tx_complete = false;
|
||||
|
||||
return splice;
|
||||
}
|
63
channeld/splice.h
Normal file
63
channeld/splice.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
#ifndef LIGHTNING_CHANNELD_SPLICE_H
|
||||
#define LIGHTNING_CHANNELD_SPLICE_H
|
||||
|
||||
#include "config.h"
|
||||
#include <bitcoin/short_channel_id.h>
|
||||
#include <channeld/inflight.h>
|
||||
#include <common/amount.h>
|
||||
#include <common/htlc.h>
|
||||
|
||||
/* The channel's general splice state for tracking splice candidates */
|
||||
struct splice_state {
|
||||
/* The active inflights */
|
||||
struct inflight **inflights;
|
||||
/* The pending short channel id for a splice. Set when mutual lock. */
|
||||
struct short_channel_id short_channel_id;
|
||||
/* Set to old short channel id when mutual lock occurs. */
|
||||
struct short_channel_id last_short_channel_id;
|
||||
/* Tally of which sides are locked, or not */
|
||||
bool locked_ready[NUM_SIDES];
|
||||
/* Set to true when commitment cycle completes successfully */
|
||||
bool await_commitment_succcess;
|
||||
/* The txid of which splice inflight was confirmed */
|
||||
struct bitcoin_txid locked_txid;
|
||||
/* The number of splices that have been signed & committed */
|
||||
u32 committed_count;
|
||||
/* the number of splices that have been revoke_and_ack'ed */
|
||||
u32 revoked_count;
|
||||
/* The number of splices that are active (awaiting confirmation) */
|
||||
u32 count;
|
||||
};
|
||||
|
||||
/* Sets `splice_state` items to default values */
|
||||
struct splice_state *splice_state_new(const tal_t *ctx);
|
||||
|
||||
/* An active splice negotiation. Born when splice beings and dies when a splice
|
||||
* negotation has finished */
|
||||
struct splice {
|
||||
/* The opener side's relative balance change */
|
||||
s64 opener_relative;
|
||||
/* The accepter side's relative balance change */
|
||||
s64 accepter_relative;
|
||||
/* The feerate for the splice (on set for the initiator) */
|
||||
u32 feerate_per_kw;
|
||||
/* If the feerate is higher than max, don't abort the splice */
|
||||
bool force_feerate;
|
||||
/* Make our side sign first */
|
||||
bool force_sign_first;
|
||||
/* After `splice` and `splice_ack` occur, we are in splice mode */
|
||||
bool mode;
|
||||
/* Track how many of each tx collab msg we receive */
|
||||
u16 tx_add_input_count, tx_add_output_count;
|
||||
/* Current negoitated psbt */
|
||||
struct wally_psbt *current_psbt;
|
||||
/* If, in the last splice_update, was tx_complete was received */
|
||||
bool received_tx_complete;
|
||||
/* If, in the last splice_update, we sent tx_complete */
|
||||
bool sent_tx_complete;
|
||||
};
|
||||
|
||||
/* Sets `splice` items to default values */
|
||||
struct splice *splice_new(const tal_t *ctx);
|
||||
|
||||
#endif /* LIGHTNING_CHANNELD_SPLICE_H */
|
3
cln-grpc/proto/node.proto
generated
3
cln-grpc/proto/node.proto
generated
|
@ -243,6 +243,7 @@ message ListpeersPeersChannelsInflight {
|
|||
string feerate = 3;
|
||||
Amount total_funding_msat = 4;
|
||||
Amount our_funding_msat = 5;
|
||||
optional sint64 splice_amount = 7;
|
||||
bytes scratch_txid = 6;
|
||||
}
|
||||
|
||||
|
@ -1122,6 +1123,7 @@ message ListpeerchannelsChannels {
|
|||
ONCHAIN = 8;
|
||||
DUALOPEND_OPEN_INIT = 9;
|
||||
DUALOPEND_AWAITING_LOCKIN = 10;
|
||||
CHANNELD_AWAITING_SPLICE = 11;
|
||||
}
|
||||
optional bytes peer_id = 1;
|
||||
optional bool peer_connected = 2;
|
||||
|
@ -1186,6 +1188,7 @@ message ListpeerchannelsChannelsInflight {
|
|||
optional uint32 funding_outnum = 2;
|
||||
optional string feerate = 3;
|
||||
optional Amount total_funding_msat = 4;
|
||||
optional sint64 splice_amount = 7;
|
||||
optional Amount our_funding_msat = 5;
|
||||
optional bytes scratch_txid = 6;
|
||||
}
|
||||
|
|
2
cln-grpc/src/convert.rs
generated
2
cln-grpc/src/convert.rs
generated
|
@ -108,6 +108,7 @@ impl From<responses::ListpeersPeersChannelsInflight> for pb::ListpeersPeersChann
|
|||
feerate: c.feerate, // Rule #2 for type string
|
||||
total_funding_msat: Some(c.total_funding_msat.into()), // Rule #2 for type msat
|
||||
our_funding_msat: Some(c.our_funding_msat.into()), // Rule #2 for type msat
|
||||
splice_amount: c.splice_amount, // Rule #2 for type integer?
|
||||
scratch_txid: hex::decode(&c.scratch_txid).unwrap(), // Rule #2 for type txid
|
||||
}
|
||||
}
|
||||
|
@ -960,6 +961,7 @@ impl From<responses::ListpeerchannelsChannelsInflight> for pb::ListpeerchannelsC
|
|||
funding_outnum: c.funding_outnum, // Rule #2 for type u32?
|
||||
feerate: c.feerate, // Rule #2 for type string?
|
||||
total_funding_msat: c.total_funding_msat.map(|f| f.into()), // Rule #2 for type msat?
|
||||
splice_amount: c.splice_amount, // Rule #2 for type integer?
|
||||
our_funding_msat: c.our_funding_msat.map(|f| f.into()), // Rule #2 for type msat?
|
||||
scratch_txid: c.scratch_txid.map(|v| hex::decode(v).unwrap()), // Rule #2 for type txid?
|
||||
}
|
||||
|
|
8
cln-rpc/src/model.rs
generated
8
cln-rpc/src/model.rs
generated
|
@ -1866,6 +1866,8 @@ pub mod responses {
|
|||
pub feerate: String,
|
||||
pub total_funding_msat: Amount,
|
||||
pub our_funding_msat: Amount,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub splice_amount: Option<i64>,
|
||||
pub scratch_txid: String,
|
||||
}
|
||||
|
||||
|
@ -3629,6 +3631,8 @@ pub mod responses {
|
|||
DUALOPEND_OPEN_INIT,
|
||||
#[serde(rename = "DUALOPEND_AWAITING_LOCKIN")]
|
||||
DUALOPEND_AWAITING_LOCKIN,
|
||||
#[serde(rename = "CHANNELD_AWAITING_SPLICE")]
|
||||
CHANNELD_AWAITING_SPLICE,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for ListpeerchannelsChannelsState {
|
||||
|
@ -3646,6 +3650,7 @@ pub mod responses {
|
|||
8 => Ok(ListpeerchannelsChannelsState::ONCHAIN),
|
||||
9 => Ok(ListpeerchannelsChannelsState::DUALOPEND_OPEN_INIT),
|
||||
10 => Ok(ListpeerchannelsChannelsState::DUALOPEND_AWAITING_LOCKIN),
|
||||
11 => Ok(ListpeerchannelsChannelsState::CHANNELD_AWAITING_SPLICE),
|
||||
o => Err(anyhow::anyhow!("Unknown variant {} for enum ListpeerchannelsChannelsState", o)),
|
||||
}
|
||||
}
|
||||
|
@ -3665,6 +3670,7 @@ pub mod responses {
|
|||
ListpeerchannelsChannelsState::ONCHAIN => "ONCHAIN",
|
||||
ListpeerchannelsChannelsState::DUALOPEND_OPEN_INIT => "DUALOPEND_OPEN_INIT",
|
||||
ListpeerchannelsChannelsState::DUALOPEND_AWAITING_LOCKIN => "DUALOPEND_AWAITING_LOCKIN",
|
||||
ListpeerchannelsChannelsState::CHANNELD_AWAITING_SPLICE => "CHANNELD_AWAITING_SPLICE",
|
||||
}.to_string()
|
||||
}
|
||||
}
|
||||
|
@ -3688,6 +3694,8 @@ pub mod responses {
|
|||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub total_funding_msat: Option<Amount>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub splice_amount: Option<i64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub our_funding_msat: Option<Amount>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub scratch_txid: Option<String>,
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -92,6 +92,9 @@ static bool is_msg_gossip_broadcast(const u8 *cursor)
|
|||
case WIRE_OPEN_CHANNEL2:
|
||||
case WIRE_ACCEPT_CHANNEL2:
|
||||
case WIRE_STFU:
|
||||
case WIRE_SPLICE:
|
||||
case WIRE_SPLICE_ACK:
|
||||
case WIRE_SPLICE_LOCKED:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -95,6 +95,9 @@ static bool public_msg_type(enum peer_wire type)
|
|||
case WIRE_PEER_STORAGE:
|
||||
case WIRE_YOUR_PEER_STORAGE:
|
||||
case WIRE_STFU:
|
||||
case WIRE_SPLICE:
|
||||
case WIRE_SPLICE_ACK:
|
||||
case WIRE_SPLICE_LOCKED:
|
||||
return false;
|
||||
case WIRE_CHANNEL_ANNOUNCEMENT:
|
||||
case WIRE_NODE_ANNOUNCEMENT:
|
||||
|
|
|
@ -390,6 +390,9 @@ static bool is_urgent(enum peer_wire type)
|
|||
case WIRE_PEER_STORAGE:
|
||||
case WIRE_YOUR_PEER_STORAGE:
|
||||
case WIRE_STFU:
|
||||
case WIRE_SPLICE:
|
||||
case WIRE_SPLICE_ACK:
|
||||
case WIRE_SPLICE_LOCKED:
|
||||
return false;
|
||||
|
||||
/* These are time-sensitive, and so send without delay. */
|
||||
|
|
|
@ -35,6 +35,7 @@ typemap = {
|
|||
'outputdesc': 'OutputDesc',
|
||||
'hash': 'Sha256',
|
||||
'secret': 'Secret',
|
||||
'integer': 'i64',
|
||||
}
|
||||
|
||||
header = f"""#![allow(non_camel_case_types)]
|
||||
|
|
|
@ -1212,6 +1212,32 @@ class LightningRpc(UnixDomainSocketRpc):
|
|||
}
|
||||
return self.call("openchannel_abort", payload)
|
||||
|
||||
def splice_init(self, chan_id, amount, initialpsbt=None, feerate_per_kw=None):
|
||||
""" Initiate a splice """
|
||||
payload = {
|
||||
"channel_id": chan_id,
|
||||
"relative_amount": amount,
|
||||
"initialpsbt": initialpsbt,
|
||||
"feerate_per_kw": feerate_per_kw,
|
||||
}
|
||||
return self.call("splice_init", payload)
|
||||
|
||||
def splice_update(self, chan_id, psbt):
|
||||
""" Update a splice """
|
||||
payload = {
|
||||
"channel_id": chan_id,
|
||||
"psbt": psbt
|
||||
}
|
||||
return self.call("splice_update", payload)
|
||||
|
||||
def splice_signed(self, chan_id, psbt):
|
||||
""" Initiate a splice """
|
||||
payload = {
|
||||
"channel_id": chan_id,
|
||||
"psbt": psbt
|
||||
}
|
||||
return self.call("splice_signed", payload)
|
||||
|
||||
def paystatus(self, bolt11=None):
|
||||
"""Detail status of attempts to pay {bolt11} or any."""
|
||||
payload = {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -91,6 +91,7 @@ def listpeers_peers_channels_inflight2py(m):
|
|||
"feerate": m.feerate, # PrimitiveField in generate_composite
|
||||
"total_funding_msat": amount2msat(m.total_funding_msat), # PrimitiveField in generate_composite
|
||||
"our_funding_msat": amount2msat(m.our_funding_msat), # PrimitiveField in generate_composite
|
||||
"splice_amount": m.splice_amount, # PrimitiveField in generate_composite
|
||||
"scratch_txid": hexlify(m.scratch_txid), # PrimitiveField in generate_composite
|
||||
})
|
||||
|
||||
|
@ -749,6 +750,7 @@ def listpeerchannels_channels_inflight2py(m):
|
|||
"funding_outnum": m.funding_outnum, # PrimitiveField in generate_composite
|
||||
"feerate": m.feerate, # PrimitiveField in generate_composite
|
||||
"total_funding_msat": amount2msat(m.total_funding_msat), # PrimitiveField in generate_composite
|
||||
"splice_amount": m.splice_amount, # PrimitiveField in generate_composite
|
||||
"our_funding_msat": amount2msat(m.our_funding_msat), # PrimitiveField in generate_composite
|
||||
"scratch_txid": hexlify(m.scratch_txid), # PrimitiveField in generate_composite
|
||||
})
|
||||
|
|
|
@ -80,6 +80,7 @@ SLOW_MACHINE = env("SLOW_MACHINE", "0") == "1"
|
|||
DEPRECATED_APIS = env("DEPRECATED_APIS", "0") == "1"
|
||||
TIMEOUT = int(env("TIMEOUT", 180 if SLOW_MACHINE else 60))
|
||||
EXPERIMENTAL_DUAL_FUND = env("EXPERIMENTAL_DUAL_FUND", "0") == "1"
|
||||
EXPERIMENTAL_SPLICING = env("EXPERIMENTAL_SPLICING", "0") == "1"
|
||||
|
||||
|
||||
def wait_for(success, timeout=TIMEOUT):
|
||||
|
@ -787,6 +788,8 @@ class LightningNode(object):
|
|||
self.daemon.opts["dev-no-reconnect"] = None
|
||||
if EXPERIMENTAL_DUAL_FUND:
|
||||
self.daemon.opts["experimental-dual-fund"] = None
|
||||
if EXPERIMENTAL_SPLICING:
|
||||
self.daemon.opts["experimental-splicing"] = None
|
||||
|
||||
if options is not None:
|
||||
self.daemon.opts.update(options)
|
||||
|
|
|
@ -100,6 +100,7 @@ start_nodes() {
|
|||
dev-fast-gossip
|
||||
dev-bitcoind-poll=5
|
||||
experimental-dual-fund
|
||||
experimental-splicing
|
||||
experimental-offers
|
||||
funder-policy=match
|
||||
funder-policy-mod=100
|
||||
|
|
|
@ -81,6 +81,12 @@ void db_bind_u64(struct db_stmt *stmt, u64 val)
|
|||
stmt->bindings[pos].v.u64 = val;
|
||||
}
|
||||
|
||||
void db_bind_s64(struct db_stmt *stmt, s64 val)
|
||||
{
|
||||
u64 uval = val;
|
||||
db_bind_u64(stmt, uval);
|
||||
}
|
||||
|
||||
void db_bind_blob(struct db_stmt *stmt, const u8 *val, size_t len)
|
||||
{
|
||||
size_t pos = check_bind_pos(stmt);
|
||||
|
@ -277,6 +283,11 @@ u64 db_col_u64(struct db_stmt *stmt, const char *colname)
|
|||
return stmt->db->config->column_u64_fn(stmt, col);
|
||||
}
|
||||
|
||||
u64 db_col_s64(struct db_stmt *stmt, const char *colname)
|
||||
{
|
||||
return db_col_u64(stmt, colname);
|
||||
}
|
||||
|
||||
int db_col_int_or_default(struct db_stmt *stmt, const char *colname, int def)
|
||||
{
|
||||
size_t col = db_query_colnum(stmt, colname);
|
||||
|
|
|
@ -21,6 +21,7 @@ struct wally_tx;
|
|||
void db_bind_null(struct db_stmt *stmt);
|
||||
void db_bind_int(struct db_stmt *stmt, int val);
|
||||
void db_bind_u64(struct db_stmt *stmt, u64 val);
|
||||
void db_bind_s64(struct db_stmt *stmt, s64 val);
|
||||
void db_bind_blob(struct db_stmt *stmt, const u8 *val, size_t len);
|
||||
void db_bind_text(struct db_stmt *stmt, const char *val);
|
||||
void db_bind_preimage(struct db_stmt *stmt, const struct preimage *p);
|
||||
|
@ -62,6 +63,7 @@ size_t db_query_colnum(const struct db_stmt *stmt, const char *colname);
|
|||
int db_col_is_null(struct db_stmt *stmt, const char *colname);
|
||||
int db_col_int(struct db_stmt *stmt, const char *colname);
|
||||
u64 db_col_u64(struct db_stmt *stmt, const char *colname);
|
||||
u64 db_col_s64(struct db_stmt *stmt, const char *colname);
|
||||
size_t db_col_bytes(struct db_stmt *stmt, const char *colname);
|
||||
const void* db_col_blob(struct db_stmt *stmt, const char *colname);
|
||||
char *db_col_strdup(const tal_t *ctx,
|
||||
|
|
|
@ -59,7 +59,8 @@ TEST_CHECK_DBSTMTS=[0|1] - When running blackbox tests, this will
|
|||
Note: Only SQLite3.
|
||||
TEST_DB_PROVIDER=[sqlite3|postgres] - Selects the database to use when running
|
||||
blackbox tests.
|
||||
EXPERIMENTAL_DUAL_FUND=[0|1] - Enable dual-funding tests.
|
||||
EXPERIMENTAL_DUAL_FUND=[0|1] - Enable dual-funding tests.
|
||||
EXPERIMENTAL_SPLICING=[0|1] - Enable splicing tests.
|
||||
```
|
||||
|
||||
#### Troubleshooting
|
||||
|
|
|
@ -131,6 +131,7 @@ Core Lightning Documentation
|
|||
lightning-signinvoice <lightning-signinvoice.7.md>
|
||||
lightning-signmessage <lightning-signmessage.7.md>
|
||||
lightning-signpsbt <lightning-signpsbt.7.md>
|
||||
lightning-splice_init <lightning-splice_init.7.md>
|
||||
lightning-sql <lightning-sql.7.md>
|
||||
lightning-staticbackup <lightning-staticbackup.7.md>
|
||||
lightning-stop <lightning-stop.7.md>
|
||||
|
|
|
@ -120,6 +120,9 @@ On success, an object is returned, containing:
|
|||
- **experimental-dual-fund** (object, optional):
|
||||
- **set** (boolean): `true` if set in config or cmdline
|
||||
- **source** (string): source of configuration setting
|
||||
- **experimental-splicing** (object, optional) *(added v23.08)*:
|
||||
- **set** (boolean): `true` if set in config or cmdline
|
||||
- **source** (string): source of configuration setting
|
||||
- **experimental-onion-messages** (object, optional):
|
||||
- **set** (boolean): `true` if set in config or cmdline
|
||||
- **source** (string): source of configuration setting
|
||||
|
@ -298,6 +301,7 @@ On success, an object is returned, containing:
|
|||
- **wallet** (string, optional): `wallet` field from config or cmdline default **deprecated, removal in v24.05**
|
||||
- **large-channels** (boolean, optional): `large-channels` field from config or cmdline, or default **deprecated, removal in v24.05**
|
||||
- **experimental-dual-fund** (boolean, optional): `experimental-dual-fund` field from config or cmdline, or default **deprecated, removal in v24.05**
|
||||
- **experimental-splicing** (boolean, optional): `experimental-splicing` field from config or cmdline, or default **deprecated, removal in v24.05**
|
||||
- **experimental-onion-messages** (boolean, optional): `experimental-onion-messages` field from config or cmdline, or default **deprecated, removal in v24.05**
|
||||
- **experimental-offers** (boolean, optional): `experimental-offers` field from config or cmdline, or default **deprecated, removal in v24.05**
|
||||
- **experimental-shutdown-wrong-funding** (boolean, optional): `experimental-shutdown-wrong-funding` field from config or cmdline, or default **deprecated, removal in v24.05**
|
||||
|
@ -467,4 +471,4 @@ RESOURCES
|
|||
|
||||
Main web site: <https://github.com/ElementsProject/lightning>
|
||||
|
||||
[comment]: # ( SHA256STAMP:a40882cad0d889aa736a2932250102be43ae7e62b3d2429b26e0961e4c315f7b)
|
||||
[comment]: # ( SHA256STAMP:8e7ec36b820cb17ecfc3066802bb07e159fffdd8dfe049d092b8f3b804e05588)
|
||||
|
|
|
@ -26,7 +26,7 @@ On success, an object containing **channels** is returned. It is an array of ob
|
|||
|
||||
- **peer\_id** (pubkey): Node Public key
|
||||
- **peer\_connected** (boolean): A boolean flag that is set to true if the peer is online
|
||||
- **state** (string): the channel state, in particular "CHANNELD\_NORMAL" means the channel can be used normally (one of "OPENINGD", "CHANNELD\_AWAITING\_LOCKIN", "CHANNELD\_NORMAL", "CHANNELD\_SHUTTING\_DOWN", "CLOSINGD\_SIGEXCHANGE", "CLOSINGD\_COMPLETE", "AWAITING\_UNILATERAL", "FUNDING\_SPEND\_SEEN", "ONCHAIN", "DUALOPEND\_OPEN\_INIT", "DUALOPEND\_AWAITING\_LOCKIN")
|
||||
- **state** (string): the channel state, in particular "CHANNELD\_NORMAL" means the channel can be used normally (one of "OPENINGD", "CHANNELD\_AWAITING\_LOCKIN", "CHANNELD\_NORMAL", "CHANNELD\_SHUTTING\_DOWN", "CLOSINGD\_SIGEXCHANGE", "CLOSINGD\_COMPLETE", "AWAITING\_UNILATERAL", "FUNDING\_SPEND\_SEEN", "ONCHAIN", "DUALOPEND\_OPEN\_INIT", "DUALOPEND\_AWAITING\_LOCKIN", "CHANNELD\_AWAITING\_SPLICE")
|
||||
- **opener** (string): Who initiated the channel (one of "local", "remote")
|
||||
- **features** (array of strings):
|
||||
- BOLT #9 features which apply to this channel (one of "option\_static\_remotekey", "option\_anchor\_outputs", "option\_anchors\_zero\_fee\_htlc\_tx", "option\_scid\_alias", "option\_zeroconf")
|
||||
|
@ -49,11 +49,12 @@ On success, an object containing **channels** is returned. It is an array of ob
|
|||
- **last\_feerate** (string, optional): For inflight opens, the most recent feerate used on the channel open
|
||||
- **next\_feerate** (string, optional): For inflight opens, the next feerate we'll use for the channel open
|
||||
- **next\_fee\_step** (u32, optional): For inflight opens, the next feerate step we'll use for the channel open
|
||||
- **inflight** (array of objects, optional): Current candidate funding transactions (only for dual-funding):
|
||||
- **inflight** (array of objects, optional): Current candidate funding transactions:
|
||||
- **funding\_txid** (txid): ID of the funding transaction
|
||||
- **funding\_outnum** (u32): The 0-based output number of the funding transaction which opens the channel
|
||||
- **feerate** (string): The feerate for this funding transaction in per-1000-weight, with "kpw" appended
|
||||
- **total\_funding\_msat** (msat): total amount in the channel
|
||||
- **splice\_amount** (integer): The amouont of sats we're splicing in or out *(added v23.08)*
|
||||
- **our\_funding\_msat** (msat): amount we have in the channel
|
||||
- **scratch\_txid** (txid): The commitment transaction txid we would use if we went onchain now
|
||||
- **close\_to** (hex, optional): scriptPubkey which we have to close to if we mutual close
|
||||
|
@ -195,4 +196,4 @@ Main web site: <https://github.com/ElementsProject/lightning> Lightning
|
|||
RFC site (BOLT \#9):
|
||||
<https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md>
|
||||
|
||||
[comment]: # ( SHA256STAMP:c530e39c9144b5fbef0f6474170865095bd7b4c48e6378fdb7f9a7697b909473)
|
||||
[comment]: # ( SHA256STAMP:dade32248bd309f2514a237cb71be6ddbe12220e1b6899693a032b45b7980a01)
|
||||
|
|
|
@ -89,6 +89,7 @@ On success, an object containing **peers** is returned. It is an array of objec
|
|||
- **feerate** (string): The feerate for this funding transaction in per-1000-weight, with "kpw" appended
|
||||
- **total\_funding\_msat** (msat): total amount in the channel
|
||||
- **our\_funding\_msat** (msat): amount we have in the channel
|
||||
- **splice\_amount** (integer): The amouont of sats we're splicing in or out *(added v23.08)*
|
||||
- **scratch\_txid** (txid): The commitment transaction txid we would use if we went onchain now
|
||||
- **close\_to** (hex, optional): scriptPubkey which we have to close to if we mutual close
|
||||
- **private** (boolean, optional): if False, we will not announce this channel
|
||||
|
@ -398,4 +399,4 @@ Main web site: <https://github.com/ElementsProject/lightning> Lightning
|
|||
RFC site (BOLT \#9):
|
||||
<https://github.com/lightning/bolts/blob/master/09-features.md>
|
||||
|
||||
[comment]: # ( SHA256STAMP:c0d0cc8f083168fd76caa2430a7c7d27d72a5273c55fb14b0efcbcb7a87274f4)
|
||||
[comment]: # ( SHA256STAMP:d75b5070288f26a39df39831212f40c397f1389e7c1765f22829d3f3389a56aa)
|
||||
|
|
82
doc/lightning-splice_init.7.md
Normal file
82
doc/lightning-splice_init.7.md
Normal file
|
@ -0,0 +1,82 @@
|
|||
lightning-splice\_init -- Command to initiate a channel to a peer
|
||||
=====================================================================
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
**(WARNING: experimental-splicing only)**
|
||||
|
||||
**splice\_init** *channel\_id* *relative\_amount* [*initalpsbt*] [*feerate\_per\_kw*] [*force\_feerate*]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
`splice_init` is a low level RPC command which initiates a channel splice for a
|
||||
given channel specified by `channel_id`.
|
||||
|
||||
*channel\_id* is the channel id of the channel to be spliced.
|
||||
|
||||
*relative\_amount* is a positive or negative amount of satoshis to add or
|
||||
subtract from the channel.
|
||||
|
||||
*initalpsbt* is the (optional) base 64 encoded PSBT to begin with. If not
|
||||
specified, one will be generated automatically.
|
||||
|
||||
*feerate\_per\_kw* is the miner fee we promise our peer to pay for our side of
|
||||
the splice transaction. It is calculated by `feerate_per_kw` *
|
||||
our\_bytes\_in\_splice\_tx / 1000.
|
||||
|
||||
*force\_feerate* is a boolean flag. By default splices will fail if the fee
|
||||
provided looks too high. This is to protect against accidentally setting your
|
||||
fee higher than intended. Set `force_feerate` to true to skip this saftey check.
|
||||
|
||||
Here is an example set of splice commands that will splice in 100,000 sats to
|
||||
the first channel that comes out of `listpeerchannels`. The example assumes
|
||||
you already have at least one confirmed channel.
|
||||
```shell
|
||||
RESULT=$(lightning-cli listpeerchannels)
|
||||
CHANNEL_ID=$(echo $RESULT| jq -r ".channels[0].channel_id")
|
||||
echo $RESULT
|
||||
|
||||
RESULT=$(lightning-cli fundpsbt -k satoshi=100000sat feerate=urgent startweight=800 excess_as_change=true)
|
||||
INITIALPSBT=$(echo $RESULT | jq -r ".psbt")
|
||||
echo $RESULT
|
||||
|
||||
RESULT=$(lightning-cli splice_init $CHANNEL_ID 100000 $INITIALPSBT)
|
||||
PSBT=$(echo $RESULT | jq -r ".psbt")
|
||||
echo $RESULT
|
||||
|
||||
RESULT=$(lightning-cli splice_update $CHANNEL_ID $PSBT)
|
||||
PSBT=$(echo $RESULT | jq -r ".psbt")
|
||||
echo $RESULT
|
||||
|
||||
RESULT=$(lightning-cli signpsbt $PSBT)
|
||||
PSBT=$(echo $RESULT | jq -r ".signed_psbt")
|
||||
echo $RESULT
|
||||
|
||||
lightning-cli splice_signed $CHANNEL_ID $PSBT
|
||||
```
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
|
||||
[comment]: # (GENERATE-FROM-SCHEMA-START)
|
||||
On success, an object is returned, containing:
|
||||
|
||||
- **psbt** (string): the (incomplete) PSBT of the splice transaction
|
||||
|
||||
[comment]: # (GENERATE-FROM-SCHEMA-END)
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
AUTHOR
|
||||
------
|
||||
|
||||
@dusty\_daemon
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
|
||||
Main web site: <https://github.com/ElementsProject/lightning>
|
||||
|
||||
[comment]: # ( SHA256STAMP:40121e2e7b0db8c99de12b4fd086f58f63e0d6643b9da1c1697a34dd5057454e)
|
|
@ -271,6 +271,7 @@ The following tables are currently supported:
|
|||
- `funding_outnum` (type `u32`, sqltype `INTEGER`)
|
||||
- `feerate` (type `string`, sqltype `TEXT`)
|
||||
- `total_funding_msat` (type `msat`, sqltype `INTEGER`)
|
||||
- `splice_amount` (type `integer`, sqltype `INTEGER`)
|
||||
- `our_funding_msat` (type `msat`, sqltype `INTEGER`)
|
||||
- `scratch_txid` (type `txid`, sqltype `BLOB`)
|
||||
- `close_to` (type `hex`, sqltype `BLOB`)
|
||||
|
@ -513,4 +514,4 @@ RESOURCES
|
|||
---------
|
||||
|
||||
Main web site: <https://github.com/ElementsProject/lightning>
|
||||
[comment]: # ( SHA256STAMP:094d94f4d2cfd8e8bdc99be8b692100d3cbd70ab3c297ed8e191c8d4a0f9b6a7)
|
||||
[comment]: # ( SHA256STAMP:2f77078555f16a9dbee5f068d4d0ba18727aeb378be674cd96bf7c1554a74ce5)
|
||||
|
|
|
@ -712,6 +712,16 @@ about whether to add funds or not to a proposed channel is handled
|
|||
automatically by a plugin that implements the appropriate logic for
|
||||
your needs. The default behavior is to not contribute funds.
|
||||
|
||||
* **experimental-splicing**
|
||||
|
||||
Specifying this enables support for the splicing protocol ([bolt][bolt] #863),
|
||||
allowing both parties to dynamically adjust the size a channel. These changes
|
||||
can be built interactively using PSBT and combined with other channel actions
|
||||
including dual fund, additional channel splices, or generic transaction activity.
|
||||
The operations will be bundled into a single transaction. The channel will remain
|
||||
active while awaiting splice confirmation, however you can only spend the smaller
|
||||
of the prior channel balance and the new one.
|
||||
|
||||
* **experimental-websocket-port**=*PORT*
|
||||
|
||||
Specifying this enables support for accepting incoming WebSocket
|
||||
|
|
|
@ -402,6 +402,25 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"experimental-splicing": {
|
||||
"added": "v23.08",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"set",
|
||||
"source"
|
||||
],
|
||||
"properties": {
|
||||
"set": {
|
||||
"type": "boolean",
|
||||
"description": "`true` if set in config or cmdline"
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"description": "source of configuration setting"
|
||||
}
|
||||
}
|
||||
},
|
||||
"experimental-onion-messages": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
|
@ -1449,6 +1468,11 @@
|
|||
"type": "boolean",
|
||||
"description": "`experimental-dual-fund` field from config or cmdline, or default"
|
||||
},
|
||||
"experimental-splicing": {
|
||||
"deprecated": "v23.08",
|
||||
"type": "boolean",
|
||||
"description": "`experimental-splicing` field from config or cmdline, or default"
|
||||
},
|
||||
"experimental-onion-messages": {
|
||||
"deprecated": "v23.08",
|
||||
"type": "boolean",
|
||||
|
|
|
@ -41,7 +41,8 @@
|
|||
"FUNDING_SPEND_SEEN",
|
||||
"ONCHAIN",
|
||||
"DUALOPEND_OPEN_INIT",
|
||||
"DUALOPEND_AWAITING_LOCKIN"
|
||||
"DUALOPEND_AWAITING_LOCKIN",
|
||||
"CHANNELD_AWAITING_SPLICE"
|
||||
],
|
||||
"description": "the channel state, in particular \"CHANNELD_NORMAL\" means the channel can be used normally"
|
||||
},
|
||||
|
@ -146,7 +147,7 @@
|
|||
},
|
||||
"inflight": {
|
||||
"type": "array",
|
||||
"description": "Current candidate funding transactions (only for dual-funding)",
|
||||
"description": "Current candidate funding transactions",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
|
@ -155,6 +156,7 @@
|
|||
"funding_outnum",
|
||||
"feerate",
|
||||
"total_funding_msat",
|
||||
"splice_amount",
|
||||
"our_funding_msat",
|
||||
"scratch_txid"
|
||||
],
|
||||
|
@ -175,6 +177,11 @@
|
|||
"type": "msat",
|
||||
"description": "total amount in the channel"
|
||||
},
|
||||
"splice_amount": {
|
||||
"type": "integer",
|
||||
"added": "v23.08",
|
||||
"description": "The amouont of sats we're splicing in or out"
|
||||
},
|
||||
"our_funding_msat": {
|
||||
"type": "msat",
|
||||
"description": "amount we have in the channel"
|
||||
|
|
|
@ -273,6 +273,7 @@
|
|||
"feerate",
|
||||
"total_funding_msat",
|
||||
"our_funding_msat",
|
||||
"splice_amount",
|
||||
"scratch_txid"
|
||||
],
|
||||
"properties": {
|
||||
|
@ -296,6 +297,11 @@
|
|||
"type": "msat",
|
||||
"description": "amount we have in the channel"
|
||||
},
|
||||
"splice_amount": {
|
||||
"type": "integer",
|
||||
"added": "v23.08",
|
||||
"description": "The amouont of sats we're splicing in or out"
|
||||
},
|
||||
"scratch_txid": {
|
||||
"type": "txid",
|
||||
"description": "The commitment transaction txid we would use if we went onchain now"
|
||||
|
|
|
@ -534,7 +534,7 @@ static u8 *create_unsigned_update(const tal_t *ctx,
|
|||
/* So valgrind doesn't complain */
|
||||
memset(&dummy_sig, 0, sizeof(dummy_sig));
|
||||
|
||||
/* BOLT #7:
|
||||
/* BOLT-f3a9f7f4e9e7a5a2997f3129e13d94090091846a #7:
|
||||
*
|
||||
* The `channel_flags` bitfield is used to indicate the direction of
|
||||
* the channel: it identifies the node that this update originated
|
||||
|
@ -760,7 +760,7 @@ void refresh_local_channel(struct daemon *daemon,
|
|||
return;
|
||||
}
|
||||
|
||||
/* BOLT #7:
|
||||
/* BOLT-f3a9f7f4e9e7a5a2997f3129e13d94090091846a #7:
|
||||
*
|
||||
* The `channel_flags` bitfield is used to indicate the direction of
|
||||
* the channel: it identifies the node that this update originated
|
||||
|
|
|
@ -641,6 +641,9 @@ static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg)
|
|||
case WIRE_PEER_STORAGE:
|
||||
case WIRE_YOUR_PEER_STORAGE:
|
||||
case WIRE_STFU:
|
||||
case WIRE_SPLICE:
|
||||
case WIRE_SPLICE_ACK:
|
||||
case WIRE_SPLICE_LOCKED:
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client,
|
|||
return (client->capabilities & HSM_CAP_SIGN_CLOSING_TX) != 0;
|
||||
|
||||
case WIRE_HSMD_SIGN_SPLICE_TX:
|
||||
return (client->capabilities & HSM_CAP_SIGN_CLOSING_TX) != 0;
|
||||
return (client->capabilities & WIRE_HSMD_SIGN_SPLICE_TX) != 0;
|
||||
|
||||
case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER:
|
||||
return (client->capabilities & HSM_CAP_SIGN_WILL_FUND_OFFER) != 0;
|
||||
|
@ -2024,6 +2024,7 @@ u8 *hsmd_init(struct secret hsm_secret,
|
|||
WIRE_HSMD_SIGN_ANY_DELAYED_PAYMENT_TO_US,
|
||||
WIRE_HSMD_SIGN_ANCHORSPEND,
|
||||
WIRE_HSMD_SIGN_HTLC_TX_MINGLE,
|
||||
WIRE_HSMD_SIGN_SPLICE_TX,
|
||||
};
|
||||
|
||||
/*~ Don't swap this. */
|
||||
|
|
|
@ -133,7 +133,9 @@ new_inflight(struct channel *channel,
|
|||
const u32 lease_chan_max_msat, const u16 lease_chan_max_ppt,
|
||||
const u32 lease_blockheight_start,
|
||||
const struct amount_msat lease_fee,
|
||||
const struct amount_sat lease_amt)
|
||||
const struct amount_sat lease_amt,
|
||||
s64 splice_amnt,
|
||||
bool i_am_initiator)
|
||||
{
|
||||
struct wally_psbt *last_tx_psbt_clone;
|
||||
struct channel_inflight *inflight
|
||||
|
@ -145,6 +147,7 @@ new_inflight(struct channel *channel,
|
|||
funding->total_funds = total_funds;
|
||||
funding->feerate = funding_feerate;
|
||||
funding->our_funds = our_funds;
|
||||
funding->splice_amnt = splice_amnt;
|
||||
|
||||
inflight->funding = funding;
|
||||
inflight->channel = channel;
|
||||
|
@ -172,6 +175,8 @@ new_inflight(struct channel *channel,
|
|||
inflight->lease_fee = lease_fee;
|
||||
inflight->lease_amt = lease_amt;
|
||||
|
||||
inflight->i_am_initiator = i_am_initiator;
|
||||
|
||||
list_add_tail(&channel->inflights, &inflight->list);
|
||||
tal_add_destructor(inflight, destroy_inflight);
|
||||
|
||||
|
@ -595,6 +600,11 @@ bool channel_state_awaitish(const struct channel *channel)
|
|||
|| channel->state == CHANNELD_AWAITING_SPLICE;
|
||||
}
|
||||
|
||||
bool channel_state_closish(enum channel_state channel_state)
|
||||
{
|
||||
return channel_state > CHANNELD_NORMAL && channel_state <= CLOSED;
|
||||
}
|
||||
|
||||
struct channel *peer_any_active_channel(struct peer *peer, bool *others)
|
||||
{
|
||||
struct channel *channel, *ret = NULL;
|
||||
|
@ -808,8 +818,7 @@ void channel_set_state(struct channel *channel,
|
|||
struct timeabs timestamp;
|
||||
|
||||
/* set closer, if known */
|
||||
if (!(state == CHANNELD_AWAITING_SPLICE)
|
||||
&& state > CHANNELD_NORMAL && channel->closer == NUM_SIDES) {
|
||||
if (channel_state_closish(state) && channel->closer == NUM_SIDES) {
|
||||
if (reason == REASON_LOCAL) channel->closer = LOCAL;
|
||||
if (reason == REASON_USER) channel->closer = LOCAL;
|
||||
if (reason == REASON_REMOTE) channel->closer = REMOTE;
|
||||
|
|
|
@ -25,6 +25,9 @@ struct funding_info {
|
|||
|
||||
/* Our original funds, in funding amount */
|
||||
struct amount_sat our_funds;
|
||||
|
||||
/* Relative splicing balance change */
|
||||
s64 splice_amnt;
|
||||
};
|
||||
|
||||
struct channel_inflight {
|
||||
|
@ -57,6 +60,9 @@ struct channel_inflight {
|
|||
|
||||
/* Amount requested to lease for this open */
|
||||
struct amount_sat lease_amt;
|
||||
|
||||
/* Did I initate this splice attempt? */
|
||||
bool i_am_initiator;
|
||||
};
|
||||
|
||||
struct open_attempt {
|
||||
|
@ -366,7 +372,9 @@ struct channel_inflight *new_inflight(struct channel *channel,
|
|||
const u16 lease_chan_max_ppt,
|
||||
const u32 lease_blockheight_start,
|
||||
const struct amount_msat lease_fee,
|
||||
const struct amount_sat lease_amt);
|
||||
const struct amount_sat lease_amt,
|
||||
s64 splice_amnt,
|
||||
bool i_am_initiator);
|
||||
|
||||
/* Given a txid, find an inflight channel stub. Returns NULL if none found */
|
||||
struct channel_inflight *channel_inflight_find(struct channel *channel,
|
||||
|
@ -390,6 +398,9 @@ bool channel_state_normalish(const struct channel *channel);
|
|||
/* Is the channel in AWAITING_*? */
|
||||
bool channel_state_awaitish(const struct channel *channel);
|
||||
|
||||
/* Is the channel in one of the CLOSING or CLOSED like states? */
|
||||
bool channel_state_closish(enum channel_state channel_state);
|
||||
|
||||
void channel_set_owner(struct channel *channel, struct subd *owner);
|
||||
|
||||
/* Channel has failed, but can try again. */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1186,7 +1186,9 @@ wallet_update_channel(struct lightningd *ld,
|
|||
channel->lease_chan_max_ppt,
|
||||
lease_blockheight_start,
|
||||
channel->push,
|
||||
lease_amt);
|
||||
lease_amt,
|
||||
0,
|
||||
false);
|
||||
wallet_inflight_add(ld->wallet, inflight);
|
||||
|
||||
return inflight;
|
||||
|
@ -1338,7 +1340,9 @@ wallet_commit_channel(struct lightningd *ld,
|
|||
channel->lease_chan_max_ppt,
|
||||
lease_blockheight_start,
|
||||
channel->push,
|
||||
lease_amt);
|
||||
lease_amt,
|
||||
0,
|
||||
false);
|
||||
wallet_inflight_add(ld->wallet, inflight);
|
||||
|
||||
/* We might have disconnected and decided we didn't need to
|
||||
|
|
|
@ -166,6 +166,12 @@ struct ext_key *hsm_init(struct lightningd *ld)
|
|||
fatal("--experimental-anchors needs HSM capable of signing anchors!");
|
||||
}
|
||||
|
||||
if (feature_offered(ld->our_features->bits[INIT_FEATURE],
|
||||
WIRE_HSMD_SIGN_SPLICE_TX)
|
||||
&& !hsm_capable(ld, WIRE_HSMD_SIGN_SPLICE_TX)) {
|
||||
fatal("--experimental-splicing needs HSM capable of signing splices!");
|
||||
}
|
||||
|
||||
/* This is equivalent to makesecret("bolt12-invoice-base") */
|
||||
msg = towire_hsmd_derive_secret(NULL, tal_dup_arr(tmpctx, u8,
|
||||
(const u8 *)INVOICE_PATH_BASE_STRING,
|
||||
|
|
|
@ -217,6 +217,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
|
|||
list_head_init(&ld->close_commands);
|
||||
list_head_init(&ld->ping_commands);
|
||||
list_head_init(&ld->disconnect_commands);
|
||||
list_head_init(&ld->splice_commands);
|
||||
list_head_init(&ld->waitblockheight_commands);
|
||||
list_head_init(&ld->wait_commands);
|
||||
|
||||
|
|
|
@ -241,6 +241,9 @@ struct lightningd {
|
|||
/* Outstanding wait commands */
|
||||
struct list_head wait_commands;
|
||||
|
||||
/* Outstanding splice commands. */
|
||||
struct list_head splice_commands;
|
||||
|
||||
/* Maintained by invoices.c */
|
||||
struct invoices *invoices;
|
||||
|
||||
|
|
|
@ -1188,6 +1188,20 @@ static char *opt_set_dual_fund(struct lightningd *ld)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static char *opt_set_splicing(struct lightningd *ld)
|
||||
{
|
||||
/* Splicing requires STFU to be enabled */
|
||||
feature_set_or(ld->our_features,
|
||||
take(feature_set_for_feature(NULL,
|
||||
OPTIONAL_FEATURE(OPT_QUIESCE))));
|
||||
feature_set_or(ld->our_features,
|
||||
take(feature_set_for_feature(NULL,
|
||||
OPTIONAL_FEATURE(OPT_SPLICE))));
|
||||
/* Splicing requires dual-fund to be enabled */
|
||||
opt_set_dual_fund(ld);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *opt_set_onion_messages(struct lightningd *ld)
|
||||
{
|
||||
feature_set_or(ld->our_features,
|
||||
|
@ -1390,6 +1404,11 @@ static void register_opts(struct lightningd *ld)
|
|||
" and allow peers to establish channels"
|
||||
" via v2 channel open protocol.");
|
||||
|
||||
opt_register_early_noarg("--experimental-splicing",
|
||||
opt_set_splicing, ld,
|
||||
"experimental: Enables the ability to resize"
|
||||
" channels using splicing");
|
||||
|
||||
/* This affects our features, so set early. */
|
||||
opt_register_early_noarg("--experimental-onion-messages",
|
||||
opt_set_onion_messages, ld,
|
||||
|
@ -1890,6 +1909,11 @@ void add_config_deprecated(struct lightningd *ld,
|
|||
feature_offered(ld->our_features
|
||||
->bits[INIT_FEATURE],
|
||||
OPT_DUAL_FUND));
|
||||
} else if (opt->cb == (void *)opt_set_splicing) {
|
||||
json_add_bool(response, name0,
|
||||
feature_offered(ld->our_features
|
||||
->bits[INIT_FEATURE],
|
||||
OPT_SPLICE));
|
||||
} else if (opt->cb == (void *)opt_set_onion_messages) {
|
||||
json_add_bool(response, name0,
|
||||
feature_offered(ld->our_features
|
||||
|
|
|
@ -270,7 +270,7 @@ bool invalid_last_tx(const struct bitcoin_tx *tx)
|
|||
* 0.7.1 release. */
|
||||
#ifdef COMPAT_V070
|
||||
/* Old bug had commitment txs with no outputs; bitcoin_txid asserts. */
|
||||
return tx->wtx->num_outputs == 0;
|
||||
return !tx || !tx->wtx || tx->wtx->num_outputs == 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
@ -841,6 +841,9 @@ static void json_add_channel(struct lightningd *ld,
|
|||
json_add_amount_sat_msat(response,
|
||||
"our_funding_msat",
|
||||
inflight->funding->our_funds);
|
||||
json_add_s64(response,
|
||||
"splice_amount",
|
||||
inflight->funding->splice_amnt);
|
||||
/* Add the expected commitment tx id also */
|
||||
bitcoin_txid(inflight->last_tx, &txid);
|
||||
json_add_txid(response, "scratch_txid", &txid);
|
||||
|
@ -1764,16 +1767,33 @@ static bool check_funding_tx(const struct bitcoin_tx *tx,
|
|||
return false;
|
||||
}
|
||||
|
||||
static void update_channel_from_inflight(struct lightningd *ld,
|
||||
struct channel *channel,
|
||||
const struct channel_inflight *inflight)
|
||||
void update_channel_from_inflight(struct lightningd *ld,
|
||||
struct channel *channel,
|
||||
const struct channel_inflight *inflight)
|
||||
{
|
||||
struct wally_psbt *psbt_copy;
|
||||
|
||||
channel->funding = inflight->funding->outpoint;
|
||||
channel->funding_sats = inflight->funding->total_funds;
|
||||
|
||||
channel->our_funds = inflight->funding->our_funds;
|
||||
|
||||
if (!amount_sat_add_sat_s64(&channel->our_funds, channel->our_funds,
|
||||
inflight->funding->splice_amnt)) {
|
||||
|
||||
channel_fail_permanent(channel,
|
||||
REASON_LOCAL,
|
||||
"Updaing channel view for splice causes"
|
||||
" an invalid satoshi amount wrapping,"
|
||||
" channel: %s, initial funds: %s, splice"
|
||||
" banace change: %s",
|
||||
type_to_string(tmpctx, struct channel_id,
|
||||
&channel->cid),
|
||||
type_to_string(tmpctx, struct amount_sat,
|
||||
&channel->our_funds),
|
||||
inflight->funding->splice_amnt);
|
||||
}
|
||||
|
||||
/* Lease infos ! */
|
||||
channel->lease_expiry = inflight->lease_expiry;
|
||||
channel->push = inflight->lease_fee;
|
||||
|
@ -1829,23 +1849,22 @@ static enum watch_result funding_depth_cb(struct lightningd *ld,
|
|||
|
||||
bool min_depth_reached = depth >= channel->minimum_depth;
|
||||
bool min_depth_no_scid = min_depth_reached && !channel->scid;
|
||||
bool some_depth_has_scid = depth && channel->scid;
|
||||
bool some_depth_has_scid = depth != 0 && channel->scid;
|
||||
|
||||
/* Reorg can change scid, so always update/save scid when possible (depth=0
|
||||
* means the stale block with our funding tx was removed) */
|
||||
if (channel->state != CHANNELD_AWAITING_SPLICE
|
||||
&& (min_depth_no_scid || some_depth_has_scid)) {
|
||||
if (min_depth_no_scid || some_depth_has_scid) {
|
||||
struct txlocator *loc;
|
||||
struct channel_inflight *inf;
|
||||
|
||||
/* Update the channel's info to the correct tx, if needed to
|
||||
* It's possible an 'inflight' has reached depth */
|
||||
if (!list_empty(&channel->inflights)) {
|
||||
if (channel->state != CHANNELD_AWAITING_SPLICE
|
||||
&& !list_empty(&channel->inflights)) {
|
||||
inf = channel_inflight_find(channel, txid);
|
||||
if (!inf) {
|
||||
channel_fail_permanent(channel,
|
||||
REASON_LOCAL,
|
||||
"Txid %s for channel"
|
||||
log_debug(channel->log,
|
||||
"Ignoring event for txid %s for channel"
|
||||
" not found in inflights. (peer %s)",
|
||||
type_to_string(tmpctx,
|
||||
struct bitcoin_txid,
|
||||
|
@ -1874,8 +1893,9 @@ static enum watch_result funding_depth_cb(struct lightningd *ld,
|
|||
|
||||
/* If we restart, we could already have peer->scid from database,
|
||||
* we don't need to update scid for stub channels(1x1x1) */
|
||||
if (!channel->scid) {
|
||||
channel->scid = tal(channel, struct short_channel_id);
|
||||
if (!channel->scid || channel->state == CHANNELD_AWAITING_SPLICE) {
|
||||
if(!channel->scid)
|
||||
channel->scid = tal(channel, struct short_channel_id);
|
||||
*channel->scid = scid;
|
||||
wallet_channel_save(ld->wallet, channel);
|
||||
|
||||
|
@ -1926,10 +1946,22 @@ static enum watch_result funding_spent(struct channel *channel,
|
|||
const struct block *block)
|
||||
{
|
||||
struct bitcoin_txid txid;
|
||||
struct channel_inflight *inflight;
|
||||
|
||||
bitcoin_txid(tx, &txid);
|
||||
|
||||
wallet_channeltxs_add(channel->peer->ld->wallet, channel,
|
||||
WIRE_ONCHAIND_INIT, &txid, 0, block->height);
|
||||
|
||||
/* If we're doing a splice, we expect the funding transaction to be
|
||||
* spent, so don't freak out and just keep watching in that case */
|
||||
list_for_each(&channel->inflights, inflight, list) {
|
||||
if (bitcoin_txid_eq(&txid,
|
||||
&inflight->funding->outpoint.txid)) {
|
||||
return KEEP_WATCHING;
|
||||
}
|
||||
}
|
||||
|
||||
return onchaind_funding_spent(channel, tx, block->height);
|
||||
}
|
||||
|
||||
|
@ -1957,7 +1989,7 @@ void channel_watch_funding(struct lightningd *ld, struct channel *channel)
|
|||
channel_watch_wrong_funding(ld, channel);
|
||||
}
|
||||
|
||||
static void channel_watch_inflight(struct lightningd *ld,
|
||||
void channel_watch_inflight(struct lightningd *ld,
|
||||
struct channel *channel,
|
||||
struct channel_inflight *inflight)
|
||||
{
|
||||
|
|
|
@ -114,7 +114,14 @@ void resend_closing_transactions(struct lightningd *ld);
|
|||
|
||||
void drop_to_chain(struct lightningd *ld, struct channel *channel, bool cooperative);
|
||||
|
||||
void update_channel_from_inflight(struct lightningd *ld,
|
||||
struct channel *channel,
|
||||
const struct channel_inflight *inflight);
|
||||
|
||||
void channel_watch_funding(struct lightningd *ld, struct channel *channel);
|
||||
void channel_watch_inflight(struct lightningd *ld,
|
||||
struct channel *channel,
|
||||
struct channel_inflight *inflight);
|
||||
/* If this channel has a "wrong funding" shutdown, watch that too. */
|
||||
void channel_watch_wrong_funding(struct lightningd *ld, struct channel *channel);
|
||||
|
||||
|
|
|
@ -2009,6 +2009,8 @@ static bool peer_save_commitsig_received(struct channel *channel, u64 commitnum,
|
|||
|
||||
channel->next_index[LOCAL]++;
|
||||
|
||||
/* DTODO: Add inflight_commit_sigs to the DB */
|
||||
|
||||
/* Update channel->last_sig and channel->last_tx before saving to db */
|
||||
channel_set_last_tx(channel, tx, commit_sig);
|
||||
|
||||
|
@ -2022,7 +2024,7 @@ static bool peer_save_commitsig_sent(struct channel *channel, u64 commitnum)
|
|||
if (commitnum != channel->next_index[REMOTE]) {
|
||||
channel_internal_error(channel,
|
||||
"channel_sent_commitsig: expected commitnum %"PRIu64
|
||||
" got %"PRIu64,
|
||||
" got %"PRIu64" (while sending commitsig)",
|
||||
channel->next_index[REMOTE], commitnum);
|
||||
return false;
|
||||
}
|
||||
|
@ -2252,6 +2254,8 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg)
|
|||
struct failed_htlc **failed;
|
||||
struct changed_htlc *changed;
|
||||
struct bitcoin_tx *tx;
|
||||
struct commitsig **inflight_commit_sigs;
|
||||
struct channel_inflight *inflight;
|
||||
size_t i;
|
||||
struct lightningd *ld = channel->peer->ld;
|
||||
|
||||
|
@ -2265,7 +2269,8 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg)
|
|||
&fulfilled,
|
||||
&failed,
|
||||
&changed,
|
||||
&tx)
|
||||
&tx,
|
||||
&inflight_commit_sigs)
|
||||
|| !fee_states_valid(fee_states, channel->opener)
|
||||
|| !height_states_valid(blockheight_states, channel->opener)) {
|
||||
channel_internal_error(channel,
|
||||
|
@ -2296,11 +2301,25 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg)
|
|||
|
||||
log_debug(channel->log,
|
||||
"got commitsig %"PRIu64
|
||||
": feerate %u, blockheight: %u, %zu added, %zu fulfilled, %zu failed, %zu changed",
|
||||
": feerate %u, blockheight: %u, %zu added, %zu fulfilled, "
|
||||
"%zu failed, %zu changed. %zu splice commitments.",
|
||||
commitnum, get_feerate(fee_states, channel->opener, LOCAL),
|
||||
get_blockheight(blockheight_states, channel->opener, LOCAL),
|
||||
tal_count(added), tal_count(fulfilled),
|
||||
tal_count(failed), tal_count(changed));
|
||||
tal_count(failed), tal_count(changed),
|
||||
tal_count(inflight_commit_sigs));
|
||||
|
||||
i = 0;
|
||||
list_for_each(&channel->inflights, inflight, list) {
|
||||
i++;
|
||||
}
|
||||
if (i != tal_count(inflight_commit_sigs)) {
|
||||
channel_internal_error(channel, "Got commitsig with incorrect "
|
||||
"number of splice commitments. "
|
||||
"lightningd expects %zu but got %zu.",
|
||||
i, tal_count(inflight_commit_sigs));
|
||||
return;
|
||||
}
|
||||
|
||||
/* New HTLCs */
|
||||
for (i = 0; i < tal_count(added); i++) {
|
||||
|
@ -2347,8 +2366,24 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg)
|
|||
|
||||
tal_free(channel->last_htlc_sigs);
|
||||
channel->last_htlc_sigs = tal_steal(channel, htlc_sigs);
|
||||
/* Delete all HTLCs and add last_htlc_sigs back in */
|
||||
wallet_htlc_sigs_save(ld->wallet, channel->dbid,
|
||||
channel->last_htlc_sigs);
|
||||
/* Now append htlc sigs for inflights */
|
||||
i = 0;
|
||||
list_for_each(&channel->inflights, inflight, list) {
|
||||
struct commitsig *commit = inflight_commit_sigs[i];
|
||||
|
||||
inflight->last_tx = tal_steal(inflight, commit->tx);
|
||||
inflight->last_tx->chainparams = chainparams;
|
||||
inflight->last_sig = commit->commit_signature;
|
||||
wallet_inflight_save(ld->wallet, inflight);
|
||||
|
||||
wallet_htlc_sigs_add(ld->wallet, channel->dbid,
|
||||
inflight->funding->outpoint,
|
||||
commit->htlc_signatures);
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Tell it we've committed, and to go ahead with revoke. */
|
||||
msg = towire_channeld_got_commitsig_reply(msg);
|
||||
|
|
|
@ -104,14 +104,14 @@ routehint_candidates(const tal_t *ctx,
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Check channel is in CHANNELD_NORMAL */
|
||||
/* Check channel is in CHANNELD_NORMAL or CHANNELD_AWAITING_SPLICE */
|
||||
candidate.c = find_channel_by_scid(peer, &r->short_channel_id);
|
||||
|
||||
/* Try seeing if we should be using a remote alias
|
||||
* instead. The `listpeers` result may have returned
|
||||
* the REMOTE alias, because it is the only scid we
|
||||
* have, and it is mandatory once the channel is in
|
||||
* CHANNELD_NORMAL. */
|
||||
* CHANNELD_NORMAL or CHANNELD_AWAITING_SPLICE. */
|
||||
if (!candidate.c)
|
||||
candidate.c = find_channel_by_alias(peer, &r->short_channel_id, REMOTE);
|
||||
|
||||
|
@ -126,7 +126,8 @@ routehint_candidates(const tal_t *ctx,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (candidate.c->state != CHANNELD_NORMAL) {
|
||||
if (candidate.c->state != CHANNELD_NORMAL
|
||||
&& candidate.c->state != CHANNELD_AWAITING_SPLICE) {
|
||||
log_debug(ld->log, "%s: abnormal channel",
|
||||
type_to_string(tmpctx,
|
||||
struct short_channel_id,
|
||||
|
|
|
@ -540,6 +540,10 @@ void json_add_u32(struct json_stream *result UNNEEDED, const char *fieldname UNN
|
|||
void json_add_u64(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
|
||||
uint64_t value UNNEEDED)
|
||||
{ fprintf(stderr, "json_add_u64 called!\n"); abort(); }
|
||||
/* Generated stub for json_add_s64 */
|
||||
void json_add_s64(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
|
||||
int64_t value UNNEEDED)
|
||||
{ fprintf(stderr, "json_add_s64 called!\n"); abort(); }
|
||||
/* Generated stub for json_add_uncommitted_channel */
|
||||
void json_add_uncommitted_channel(struct json_stream *response UNNEEDED,
|
||||
const struct uncommitted_channel *uc UNNEEDED,
|
||||
|
@ -790,6 +794,12 @@ struct command_result *param_u64(struct command *cmd UNNEEDED, const char *name
|
|||
const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
|
||||
uint64_t **num UNNEEDED)
|
||||
{ fprintf(stderr, "param_u64 called!\n"); abort(); }
|
||||
/* Generated stub for channel_state_normalish */
|
||||
bool channel_state_normalish(const struct channel *channel UNNEEDED)
|
||||
{ fprintf(stderr, "channel_state_normalish called!\n"); abort(); }
|
||||
/* Generated stub for channel_state_awaitish */
|
||||
bool channel_state_awaitish(const struct channel *channel UNNEEDED)
|
||||
{ fprintf(stderr, "channel_state_awaitish called!\n"); abort(); }
|
||||
/* Generated stub for peer_any_active_channel */
|
||||
struct channel *peer_any_active_channel(struct peer *peer UNNEEDED, bool *others UNNEEDED)
|
||||
{ fprintf(stderr, "peer_any_active_channel called!\n"); abort(); }
|
||||
|
|
|
@ -760,14 +760,14 @@ static char *check_balances(const tal_t *ctx,
|
|||
assert(ok);
|
||||
|
||||
initiator_weight +=
|
||||
psbt_input_weight(psbt, i);
|
||||
psbt_input_get_weight(psbt, i);
|
||||
} else {
|
||||
ok = amount_sat_add(&accepter_inputs,
|
||||
accepter_inputs, amt);
|
||||
assert(ok);
|
||||
|
||||
accepter_weight +=
|
||||
psbt_input_weight(psbt, i);
|
||||
psbt_input_get_weight(psbt, i);
|
||||
}
|
||||
}
|
||||
tot_output_amt = AMOUNT_SAT(0);
|
||||
|
@ -826,13 +826,13 @@ static char *check_balances(const tal_t *ctx,
|
|||
}
|
||||
|
||||
initiator_weight +=
|
||||
psbt_output_weight(psbt, i);
|
||||
psbt_output_get_weight(psbt, i);
|
||||
} else {
|
||||
ok = amount_sat_add(&accepter_outs,
|
||||
accepter_outs, amt);
|
||||
assert(ok);
|
||||
accepter_weight +=
|
||||
psbt_output_weight(psbt, i);
|
||||
psbt_output_get_weight(psbt, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -997,7 +997,8 @@ static u8 *psbt_to_tx_sigs_msg(const tal_t *ctx,
|
|||
|
||||
return towire_tx_signatures(ctx, &state->channel_id,
|
||||
&state->tx_state->funding.txid,
|
||||
ws);
|
||||
ws,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void handle_tx_sigs(struct state *state, const u8 *msg)
|
||||
|
@ -1009,10 +1010,12 @@ static void handle_tx_sigs(struct state *state, const u8 *msg)
|
|||
enum tx_role their_role = state->our_role == TX_INITIATOR ?
|
||||
TX_ACCEPTER : TX_INITIATOR;
|
||||
|
||||
struct tlv_txsigs_tlvs *txsig_tlvs = tlv_txsigs_tlvs_new(tmpctx);
|
||||
if (!fromwire_tx_signatures(tmpctx, msg, &cid, &txid,
|
||||
cast_const3(
|
||||
struct witness ***,
|
||||
&witnesses)))
|
||||
&witnesses),
|
||||
&txsig_tlvs))
|
||||
open_err_fatal(state, "Bad tx_signatures %s",
|
||||
tal_hex(msg, msg));
|
||||
|
||||
|
@ -1418,6 +1421,9 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state)
|
|||
case WIRE_PEER_STORAGE:
|
||||
case WIRE_YOUR_PEER_STORAGE:
|
||||
case WIRE_STFU:
|
||||
case WIRE_SPLICE:
|
||||
case WIRE_SPLICE_ACK:
|
||||
case WIRE_SPLICE_LOCKED:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1792,6 +1798,9 @@ static bool run_tx_interactive(struct state *state,
|
|||
case WIRE_PEER_STORAGE:
|
||||
case WIRE_YOUR_PEER_STORAGE:
|
||||
case WIRE_STFU:
|
||||
case WIRE_SPLICE:
|
||||
case WIRE_SPLICE_ACK:
|
||||
case WIRE_SPLICE_LOCKED:
|
||||
open_abort(state, "Unexpected wire message %s",
|
||||
tal_hex(tmpctx, msg));
|
||||
return false;
|
||||
|
@ -1873,7 +1882,7 @@ static u8 *accepter_commits(struct state *state,
|
|||
struct amount_msat our_msats;
|
||||
struct channel_id cid;
|
||||
const u8 *wscript;
|
||||
u8 *msg;
|
||||
u8 *msg, *commit_msg;
|
||||
char *error;
|
||||
|
||||
/* Find the funding transaction txid */
|
||||
|
@ -1911,9 +1920,12 @@ static u8 *accepter_commits(struct state *state,
|
|||
}
|
||||
|
||||
remote_sig.sighash_type = SIGHASH_ALL;
|
||||
|
||||
struct tlv_commitment_signed_tlvs *cs_tlv
|
||||
= tlv_commitment_signed_tlvs_new(tmpctx);
|
||||
if (!fromwire_commitment_signed(tmpctx, msg, &cid,
|
||||
&remote_sig.s,
|
||||
&htlc_sigs))
|
||||
&htlc_sigs, &cs_tlv))
|
||||
open_err_fatal(state, "Parsing commitment signed %s",
|
||||
tal_hex(tmpctx, msg));
|
||||
|
||||
|
@ -2111,10 +2123,10 @@ static u8 *accepter_commits(struct state *state,
|
|||
master_badmsg(WIRE_DUALOPEND_SEND_TX_SIGS, msg);
|
||||
|
||||
/* Send our commitment sigs over now */
|
||||
peer_write(state->pps,
|
||||
take(towire_commitment_signed(NULL,
|
||||
&state->channel_id,
|
||||
&local_sig.s, NULL)));
|
||||
commit_msg = towire_commitment_signed(NULL, &state->channel_id,
|
||||
&local_sig.s, NULL, NULL);
|
||||
|
||||
peer_write(state->pps, take(commit_msg));
|
||||
tal_free(local_commit);
|
||||
return msg;
|
||||
}
|
||||
|
@ -2757,7 +2769,7 @@ static u8 *opener_commits(struct state *state,
|
|||
assert(local_sig.sighash_type == SIGHASH_ALL);
|
||||
msg = towire_commitment_signed(tmpctx, &state->channel_id,
|
||||
&local_sig.s,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
peer_write(state->pps, msg);
|
||||
peer_billboard(false, "channel open: commitment sent, waiting for reply");
|
||||
|
||||
|
@ -2770,9 +2782,12 @@ static u8 *opener_commits(struct state *state,
|
|||
}
|
||||
|
||||
remote_sig.sighash_type = SIGHASH_ALL;
|
||||
|
||||
struct tlv_commitment_signed_tlvs *cs_tlv
|
||||
= tlv_commitment_signed_tlvs_new(tmpctx);
|
||||
if (!fromwire_commitment_signed(tmpctx, msg, &cid,
|
||||
&remote_sig.s,
|
||||
&htlc_sigs))
|
||||
&htlc_sigs, &cs_tlv))
|
||||
open_err_fatal(state, "Parsing commitment signed %s",
|
||||
tal_hex(tmpctx, msg));
|
||||
|
||||
|
@ -4184,6 +4199,9 @@ static u8 *handle_peer_in(struct state *state)
|
|||
case WIRE_PEER_STORAGE:
|
||||
case WIRE_YOUR_PEER_STORAGE:
|
||||
case WIRE_STFU:
|
||||
case WIRE_SPLICE:
|
||||
case WIRE_SPLICE_ACK:
|
||||
case WIRE_SPLICE_LOCKED:
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -160,6 +160,9 @@ bool json_to_u32(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, u32
|
|||
/* Generated stub for json_to_u64 */
|
||||
bool json_to_u64(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, u64 *num UNNEEDED)
|
||||
{ fprintf(stderr, "json_to_u64 called!\n"); abort(); }
|
||||
/* Generated stub for json_to_s64 */
|
||||
bool json_to_s64(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, s64 *num UNNEEDED)
|
||||
{ fprintf(stderr, "json_to_s64 called!\n"); abort(); }
|
||||
/* Generated stub for json_tok_bin_from_hex */
|
||||
u8 *json_tok_bin_from_hex(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED)
|
||||
{ fprintf(stderr, "json_tok_bin_from_hex called!\n"); abort(); }
|
||||
|
|
|
@ -1016,8 +1016,10 @@ def test_reconnect_remote_sends_no_sigs(node_factory):
|
|||
l2.daemon.wait_for_logs([r'peer_out WIRE_ANNOUNCEMENT_SIGNATURES',
|
||||
r'peer_out WIRE_ANNOUNCEMENT_SIGNATURES'])
|
||||
|
||||
count = ''.join(l1.daemon.logs).count(r'peer_out WIRE_ANNOUNCEMENT_SIGNATURES')
|
||||
|
||||
# l1 only did send them the first time
|
||||
assert(''.join(l1.daemon.logs).count(r'peer_out WIRE_ANNOUNCEMENT_SIGNATURES') == 1)
|
||||
assert(count == 1 or count == 2)
|
||||
|
||||
|
||||
@pytest.mark.openchannel('v1')
|
||||
|
|
|
@ -2225,8 +2225,9 @@ def test_list_features_only(node_factory):
|
|||
'option_shutdown_anysegwit/odd',
|
||||
'option_channel_type/odd',
|
||||
'option_scid_alias/odd',
|
||||
'option_zeroconf/odd',
|
||||
'supports_open_accept_channel_type']
|
||||
'option_zeroconf/odd']
|
||||
expected += ['supports_open_accept_channel_type']
|
||||
|
||||
assert features == expected
|
||||
|
||||
|
||||
|
|
|
@ -3886,6 +3886,8 @@ def test_sql(node_factory, bitcoind):
|
|||
'type': 'string'},
|
||||
{'name': 'total_funding_msat',
|
||||
'type': 'msat'},
|
||||
{'name': 'splice_amount',
|
||||
'type': 's64'},
|
||||
{'name': 'our_funding_msat',
|
||||
'type': 'msat'},
|
||||
{'name': 'scratch_txid',
|
||||
|
@ -4023,6 +4025,7 @@ def test_sql(node_factory, bitcoind):
|
|||
'u16': 'INTEGER',
|
||||
'u32': 'INTEGER',
|
||||
'u64': 'INTEGER',
|
||||
's64': 'INTEGER',
|
||||
'msat': 'INTEGER',
|
||||
'hex': 'BLOB',
|
||||
'hash': 'BLOB',
|
||||
|
@ -4093,7 +4096,7 @@ def test_sql(node_factory, bitcoind):
|
|||
assert len(bytes.fromhex(val)) == 32
|
||||
elif col['type'] == "pubkey":
|
||||
assert len(bytes.fromhex(val)) == 33
|
||||
elif col['type'] in ("msat", "integer", "u64", "u32", "u16", "u8", "boolean"):
|
||||
elif col['type'] in ("msat", "integer", "s64", "u64", "u32", "u16", "u8", "boolean"):
|
||||
int(val)
|
||||
elif col['type'] == "number":
|
||||
float(val)
|
||||
|
|
35
tests/test_splicing.py
Normal file
35
tests/test_splicing.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
from fixtures import * # noqa: F401,F403
|
||||
import os
|
||||
import pytest
|
||||
import unittest
|
||||
|
||||
|
||||
@unittest.skipIf(os.environ.get("EXPERIMENTAL_SPLICING", '0') != '1', "Need experimental splicing turned on")
|
||||
@pytest.mark.openchannel('v2')
|
||||
def test_splice(node_factory, bitcoind):
|
||||
l1, l2 = node_factory.line_graph(2, fundamount=1000000, wait_for_announce=True)
|
||||
|
||||
chan_id = l1.get_channel_id(l2)
|
||||
|
||||
# add extra sats to pay fee
|
||||
funds_result = l1.rpc.fundpsbt("109000sat", "slow", 166, excess_as_change=True)
|
||||
|
||||
result = l1.rpc.splice_init(chan_id, 100000, funds_result['psbt'])
|
||||
result = l1.rpc.splice_update(chan_id, result['psbt'])
|
||||
result = l1.rpc.signpsbt(result['psbt'])
|
||||
result = l1.rpc.splice_signed(chan_id, result['signed_psbt'])
|
||||
|
||||
l2.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE')
|
||||
l1.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE')
|
||||
|
||||
mempool = bitcoind.rpc.getrawmempool(True)
|
||||
assert len(list(mempool.keys())) == 1
|
||||
assert result['txid'] in list(mempool.keys())
|
||||
|
||||
bitcoind.generate_block(6, wait_for_mempool=1)
|
||||
|
||||
l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
|
||||
l1.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
|
||||
|
||||
inv = l2.rpc.invoice(10**2, '3', 'no_3')
|
||||
l1.rpc.pay(inv['bolt11'])
|
|
@ -2,7 +2,7 @@ from pyln.testing.utils import TEST_NETWORK, TIMEOUT, VALGRIND, DEVELOPER, DEPRE
|
|||
from pyln.testing.utils import env, only_one, wait_for, write_config, TailableProc, sync_blockheight, wait_channel_quiescent, get_tx_p2wsh_outnum, mine_funding_to_announce, scid_to_int # noqa: F401
|
||||
import bitstring
|
||||
from pyln.client import Millisatoshi
|
||||
from pyln.testing.utils import EXPERIMENTAL_DUAL_FUND
|
||||
from pyln.testing.utils import EXPERIMENTAL_DUAL_FUND, EXPERIMENTAL_SPLICING
|
||||
import time
|
||||
|
||||
COMPAT = env("COMPAT", "1") == "1"
|
||||
|
@ -42,6 +42,10 @@ def expected_peer_features(wumbo_channels=False, extra=[]):
|
|||
if EXPERIMENTAL_DUAL_FUND:
|
||||
# option_dual_fund
|
||||
features += [29]
|
||||
if EXPERIMENTAL_SPLICING:
|
||||
features += [29] # option_dual_fund
|
||||
features += [35] # option_quiesce
|
||||
features += [63] # option_splice
|
||||
return hex_bits(features + extra)
|
||||
|
||||
|
||||
|
@ -55,6 +59,10 @@ def expected_node_features(wumbo_channels=False, extra=[]):
|
|||
if EXPERIMENTAL_DUAL_FUND:
|
||||
# option_dual_fund
|
||||
features += [29]
|
||||
if EXPERIMENTAL_SPLICING:
|
||||
features += [29] # option_dual_fund
|
||||
features += [35] # option_quiesce
|
||||
features += [63] # option_splice
|
||||
return hex_bits(features + extra)
|
||||
|
||||
|
||||
|
|
|
@ -231,6 +231,7 @@ class Type(FieldSet):
|
|||
'failed_htlc',
|
||||
'existing_htlc',
|
||||
'simple_htlc',
|
||||
'inflight',
|
||||
'utxo',
|
||||
'bitcoin_tx',
|
||||
'wirestring',
|
||||
|
|
|
@ -973,6 +973,8 @@ static struct migration dbmigrations[] = {
|
|||
/* Splicing requires us to store HTLC sigs for inflight splices and allows us to discard old sigs after splice confirmation. */
|
||||
{SQL("ALTER TABLE htlc_sigs ADD inflight_tx_id BLOB"), NULL},
|
||||
{SQL("ALTER TABLE htlc_sigs ADD inflight_tx_outnum INTEGER"), NULL},
|
||||
{SQL("ALTER TABLE channel_funding_inflights ADD splice_amnt BIGINT DEFAULT 0"), NULL},
|
||||
{SQL("ALTER TABLE channel_funding_inflights ADD i_am_initiator INTEGER DEFAULT 0"), NULL},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -172,7 +172,9 @@ struct channel_inflight *new_inflight(struct channel *channel UNNEEDED,
|
|||
const u16 lease_chan_max_ppt UNNEEDED,
|
||||
const u32 lease_blockheight_start UNNEEDED,
|
||||
const struct amount_msat lease_fee UNNEEDED,
|
||||
const struct amount_sat lease_amt UNNEEDED)
|
||||
const struct amount_sat lease_amt UNNEEDED,
|
||||
s64 splice_amnt UNNEEDED,
|
||||
bool i_am_initiator UNNEEDED)
|
||||
{ fprintf(stderr, "new_inflight called!\n"); abort(); }
|
||||
/* Generated stub for new_logger */
|
||||
struct logger *new_logger(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED,
|
||||
|
|
|
@ -158,7 +158,7 @@ void fatal_vfmt(const char *fmt UNNEEDED, va_list ap UNNEEDED)
|
|||
bool fromwire_channeld_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_channeld_dev_memleak_reply called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_channeld_got_commitsig */
|
||||
bool fromwire_channeld_got_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct bitcoin_signature *signature UNNEEDED, struct bitcoin_signature **htlc_signature UNNEEDED, struct added_htlc **added UNNEEDED, struct fulfilled_htlc **fulfilled UNNEEDED, struct failed_htlc ***failed UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_tx **tx UNNEEDED)
|
||||
bool fromwire_channeld_got_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct bitcoin_signature *signature UNNEEDED, struct bitcoin_signature **htlc_signature UNNEEDED, struct added_htlc **added UNNEEDED, struct fulfilled_htlc **fulfilled UNNEEDED, struct failed_htlc ***failed UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_tx **tx UNNEEDED, struct commitsig ***inflight_commitsigs UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_channeld_got_commitsig called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_channeld_got_revoke */
|
||||
bool fromwire_channeld_got_revoke(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *revokenum UNNEEDED, struct secret *per_commitment_secret UNNEEDED, struct pubkey *next_per_commit_point UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct changed_htlc **changed UNNEEDED, struct penalty_base **pbase UNNEEDED, struct bitcoin_tx **penalty_tx UNNEEDED)
|
||||
|
@ -350,6 +350,10 @@ void json_add_u32(struct json_stream *result UNNEEDED, const char *fieldname UNN
|
|||
void json_add_u64(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
|
||||
uint64_t value UNNEEDED)
|
||||
{ fprintf(stderr, "json_add_u64 called!\n"); abort(); }
|
||||
/* Generated stub for json_add_s64 */
|
||||
void json_add_s64(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
|
||||
int64_t value UNNEEDED)
|
||||
{ fprintf(stderr, "json_add_s64 called!\n"); abort(); }
|
||||
/* Generated stub for json_add_uncommitted_channel */
|
||||
void json_add_uncommitted_channel(struct json_stream *response UNNEEDED,
|
||||
const struct uncommitted_channel *uc UNNEEDED,
|
||||
|
@ -1713,7 +1717,9 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx)
|
|||
sig,
|
||||
1, lease_commit_sig, 2, 4, 22,
|
||||
AMOUNT_MSAT(10),
|
||||
AMOUNT_SAT(1111));
|
||||
AMOUNT_SAT(1111),
|
||||
0,
|
||||
false);
|
||||
|
||||
/* do inflights get correctly added to the channel? */
|
||||
wallet_inflight_add(w, inflight);
|
||||
|
@ -1737,7 +1743,9 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx)
|
|||
sig,
|
||||
0, NULL, 0, 0, 0,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_SAT(0));
|
||||
AMOUNT_SAT(0),
|
||||
0,
|
||||
false);
|
||||
wallet_inflight_add(w, inflight);
|
||||
CHECK_MSG(c2 = wallet_channel_load(w, chan->dbid),
|
||||
tal_fmt(w, "Load from DB"));
|
||||
|
|
|
@ -1150,8 +1150,10 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight)
|
|||
", lease_blockheight_start"
|
||||
", lease_fee"
|
||||
", lease_satoshi"
|
||||
", splice_amnt"
|
||||
", i_am_initiator"
|
||||
") VALUES ("
|
||||
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"));
|
||||
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"));
|
||||
|
||||
db_bind_u64(stmt, inflight->channel->dbid);
|
||||
db_bind_txid(stmt, &inflight->funding->outpoint.txid);
|
||||
|
@ -1185,6 +1187,9 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight)
|
|||
db_bind_int(stmt, 0);
|
||||
}
|
||||
|
||||
db_bind_s64(stmt, inflight->funding->splice_amnt);
|
||||
db_bind_int(stmt, inflight->i_am_initiator);
|
||||
|
||||
db_exec_prepared_v2(stmt);
|
||||
assert(!stmt->error);
|
||||
tal_free(stmt);
|
||||
|
@ -1249,6 +1254,8 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt,
|
|||
struct bitcoin_signature last_sig;
|
||||
struct bitcoin_tx *last_tx;
|
||||
struct channel_inflight *inflight;
|
||||
s64 splice_amnt;
|
||||
bool i_am_initiator;
|
||||
|
||||
secp256k1_ecdsa_signature *lease_commit_sig;
|
||||
u32 lease_blockheight_start;
|
||||
|
@ -1299,6 +1306,9 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt,
|
|||
} else
|
||||
last_tx = NULL;
|
||||
|
||||
splice_amnt = db_col_s64(stmt, "splice_amnt");
|
||||
i_am_initiator = db_col_int(stmt, "i_am_initiator");
|
||||
|
||||
inflight = new_inflight(chan, &funding,
|
||||
db_col_int(stmt, "funding_feerate"),
|
||||
funding_sat,
|
||||
|
@ -1312,7 +1322,9 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt,
|
|||
lease_chan_max_ppt,
|
||||
lease_blockheight_start,
|
||||
lease_fee,
|
||||
lease_amt);
|
||||
lease_amt,
|
||||
splice_amnt,
|
||||
i_am_initiator);
|
||||
|
||||
/* Pull out the serialized tx-sigs-received-ness */
|
||||
inflight->remote_tx_sigs = db_col_int(stmt, "funding_tx_remote_sigs_received");
|
||||
|
@ -1342,6 +1354,8 @@ static bool wallet_channel_load_inflights(struct wallet *w,
|
|||
", lease_blockheight_start"
|
||||
", lease_fee"
|
||||
", lease_satoshi"
|
||||
", splice_amnt"
|
||||
", i_am_initiator"
|
||||
" FROM channel_funding_inflights"
|
||||
" WHERE channel_id = ?"
|
||||
" ORDER BY funding_feerate"));
|
||||
|
@ -2064,7 +2078,7 @@ void wallet_announcement_save(struct wallet *w, u64 id,
|
|||
|
||||
|
||||
void wallet_htlcsigs_confirm_inflight(struct wallet *w, struct channel *chan,
|
||||
struct bitcoin_outpoint confirmed_outpoint)
|
||||
const struct bitcoin_outpoint *confirmed_outpoint)
|
||||
{
|
||||
struct db_stmt *stmt;
|
||||
|
||||
|
@ -2079,15 +2093,15 @@ void wallet_htlcsigs_confirm_inflight(struct wallet *w, struct channel *chan,
|
|||
" inflight_tx_outnum!=?"
|
||||
")"
|
||||
")"));
|
||||
db_bind_u64(stmt, 0, chan->dbid);
|
||||
db_bind_txid(stmt, 1, &confirmed_outpoint.txid);
|
||||
db_bind_int(stmt, 2, confirmed_outpoint.n);
|
||||
db_bind_u64(stmt, chan->dbid);
|
||||
db_bind_txid(stmt, &confirmed_outpoint->txid);
|
||||
db_bind_int(stmt, confirmed_outpoint->n);
|
||||
db_exec_prepared_v2(take(stmt));
|
||||
|
||||
stmt = db_prepare_v2(w->db, SQL("UPDATE htlc_sigs"
|
||||
" SET inflight_tx_id=NULL"
|
||||
" WHERE channelid=?"));
|
||||
db_bind_u64(stmt, 0, chan->dbid);
|
||||
db_bind_u64(stmt, chan->dbid);
|
||||
db_exec_prepared_v2(take(stmt));
|
||||
}
|
||||
|
||||
|
@ -3850,10 +3864,10 @@ void wallet_htlc_sigs_add(struct wallet *w, u64 channel_id,
|
|||
SQL("INSERT INTO htlc_sigs (channelid,"
|
||||
" inflight_tx_id, inflight_tx_outnum,"
|
||||
" signature) VALUES (?, ?, ?)"));
|
||||
db_bind_u64(stmt, 0, channel_id);
|
||||
db_bind_txid(stmt, 1, &inflight_outpoint.txid);
|
||||
db_bind_int(stmt, 2, inflight_outpoint.n);
|
||||
db_bind_signature(stmt, 3, &htlc_sigs[i].s);
|
||||
db_bind_u64(stmt, channel_id);
|
||||
db_bind_txid(stmt, &inflight_outpoint.txid);
|
||||
db_bind_int(stmt, inflight_outpoint.n);
|
||||
db_bind_signature(stmt, &htlc_sigs[i].s);
|
||||
db_exec_prepared_v2(take(stmt));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -608,7 +608,7 @@ bool wallet_shachain_add_hash(struct wallet *wallet,
|
|||
u64 wallet_get_channel_dbid(struct wallet *wallet);
|
||||
|
||||
void wallet_htlcsigs_confirm_inflight(struct wallet *w, struct channel *chan,
|
||||
struct bitcoin_outpoint confirmed_outpoint);
|
||||
const struct bitcoin_outpoint *confirmed_outpoint);
|
||||
|
||||
/**
|
||||
* wallet_channel_save -- Upsert the channel into the database
|
||||
|
@ -638,9 +638,6 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight);
|
|||
void wallet_inflight_save(struct wallet *w,
|
||||
struct channel_inflight *inflight);
|
||||
|
||||
void wallet_promote_splice_candidate(struct wallet *w,
|
||||
struct channel *chan);
|
||||
|
||||
/**
|
||||
* Remove all the inflights from a channel. Also cleans up
|
||||
* the channel's inflight list
|
||||
|
|
18
wire/extracted_peer_06_funding_outpoint_sigs.patch
Normal file
18
wire/extracted_peer_06_funding_outpoint_sigs.patch
Normal file
|
@ -0,0 +1,18 @@
|
|||
--- wire/peer_exp_wire.csv 2022-06-22 19:07:24.000000000 -0500
|
||||
+++ - 2022-06-30 16:00:51.000000000 -0500
|
||||
@@ -65,12 +57,15 @@
|
||||
msgdata,tx_signatures,txid,sha256,
|
||||
msgdata,tx_signatures,num_witnesses,u16,
|
||||
msgdata,tx_signatures,witness_stack,witness_stack,num_witnesses
|
||||
+msgdata,tx_signatures,tlvs,txsigs_tlvs,
|
||||
subtype,witness_stack
|
||||
subtypedata,witness_stack,num_input_witness,u16,
|
||||
subtypedata,witness_stack,witness_element,witness_element,num_input_witness
|
||||
subtype,witness_element
|
||||
subtypedata,witness_element,len,u16,
|
||||
subtypedata,witness_element,witness,byte,len
|
||||
+tlvtype,txsigs_tlvs,funding_outpoint_sig,0
|
||||
+tlvdata,txsigs_tlvs,funding_outpoint_sig,sig,byte,...
|
||||
msgtype,tx_init_rbf,72
|
||||
msgdata,tx_init_rbf,channel_id,channel_id,
|
||||
msgdata,tx_init_rbf,locktime,u32,
|
|
@ -1,10 +1,12 @@
|
|||
--- wire/peer_wire.csv 2021-05-09 15:44:59.166135652 +0930
|
||||
+++ wire/peer_wire.csv.raw 2021-05-11 09:59:31.695459756 +0930
|
||||
@@ -244,6 +140,15 @@
|
||||
@@ -244,6 +140,17 @@
|
||||
msgdata,channel_reestablish,next_revocation_number,u64,
|
||||
msgdata,channel_reestablish,your_last_per_commitment_secret,byte,32
|
||||
msgdata,channel_reestablish,my_current_per_commitment_point,point,
|
||||
+msgdata,channel_reestablish,tlvs,channel_reestablish_tlvs,
|
||||
+tlvtype,channel_reestablish_tlvs,next_funding,0
|
||||
+tlvdata,channel_reestablish_tlvs,next_funding,next_funding_txid,sha256,
|
||||
+tlvtype,channel_reestablish_tlvs,next_to_send,1
|
||||
+tlvdata,channel_reestablish_tlvs,next_to_send,commitment_number,tu64,
|
||||
+tlvtype,channel_reestablish_tlvs,desired_channel_type,3
|
||||
|
|
|
@ -280,3 +280,4 @@ void fromwire_siphash_seed(const u8 **cursor, size_t *max,
|
|||
{
|
||||
fromwire(cursor, max, seed, sizeof(*seed));
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,9 @@ static bool unknown_type(enum peer_wire t)
|
|||
case WIRE_OPEN_CHANNEL2:
|
||||
case WIRE_ACCEPT_CHANNEL2:
|
||||
case WIRE_STFU:
|
||||
case WIRE_SPLICE:
|
||||
case WIRE_SPLICE_ACK:
|
||||
case WIRE_SPLICE_LOCKED:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -104,6 +107,9 @@ bool is_msg_for_gossipd(const u8 *cursor)
|
|||
case WIRE_PEER_STORAGE:
|
||||
case WIRE_YOUR_PEER_STORAGE:
|
||||
case WIRE_STFU:
|
||||
case WIRE_SPLICE:
|
||||
case WIRE_SPLICE_ACK:
|
||||
case WIRE_SPLICE_LOCKED:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
|
@ -365,6 +371,30 @@ bool extract_channel_id(const u8 *in_pkt, struct channel_id *channel_id)
|
|||
* 2. data:
|
||||
* * [`channel_id`:`channel_id`]
|
||||
*/
|
||||
case WIRE_SPLICE:
|
||||
/* BOLT-splice #2:
|
||||
* 1. type: 74 (`splice`)
|
||||
* 2. data:
|
||||
* * [`chain_hash`:`chain_hash`]
|
||||
* * [`channel_id`:`channel_id`]
|
||||
* * [`u32`:`funding_feerate_perkw`]
|
||||
* * [`point`:`funding_pubkey`]
|
||||
*/
|
||||
case WIRE_SPLICE_ACK:
|
||||
/* BOLT-splice #2:
|
||||
* 1. type: 76 (`splice_ack`)
|
||||
* 2. data:
|
||||
* * [`chain_hash`:`chain_hash`]
|
||||
* * [`channel_id`:`channel_id`]
|
||||
* * [`point`:`funding_pubkey`]
|
||||
*/
|
||||
case WIRE_SPLICE_LOCKED:
|
||||
/* BOLT-splice #2:
|
||||
* 1. type: 78 (`splice_locked`)
|
||||
* 2. data:
|
||||
* * [`chain_hash`:`chain_hash`]
|
||||
* * [`channel_id`:`channel_id`]
|
||||
*/
|
||||
return fromwire_channel_id(&cursor, &max, channel_id);
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -66,6 +66,9 @@ msgdata,tx_signatures,witnesses,witness,num_witnesses
|
|||
subtype,witness
|
||||
subtypedata,witness,len,u16,
|
||||
subtypedata,witness,witness_data,byte,len
|
||||
msgdata,tx_signatures,tlvs,txsigs_tlvs,
|
||||
tlvtype,txsigs_tlvs,funding_outpoint_sig,0
|
||||
tlvdata,txsigs_tlvs,funding_outpoint_sig,sig,byte,...
|
||||
msgtype,tx_init_rbf,72
|
||||
msgdata,tx_init_rbf,channel_id,channel_id,
|
||||
msgdata,tx_init_rbf,locktime,u32,
|
||||
|
@ -203,6 +206,20 @@ subtypedata,lease_rates,channel_fee_max_base_msat,tu32,
|
|||
msgtype,stfu,2
|
||||
msgdata,stfu,channel_id,channel_id,
|
||||
msgdata,stfu,initiator,u8,
|
||||
msgtype,splice,75
|
||||
msgdata,splice,channel_id,channel_id,
|
||||
msgdata,splice,chain_hash,chain_hash,
|
||||
msgdata,splice,relative_satoshis,s64,
|
||||
msgdata,splice,funding_feerate_perkw,u32,
|
||||
msgdata,splice,locktime,u32,
|
||||
msgdata,splice,funding_pubkey,point,
|
||||
msgtype,splice_ack,76
|
||||
msgdata,splice_ack,channel_id,channel_id,
|
||||
msgdata,splice_ack,chain_hash,chain_hash,
|
||||
msgdata,splice_ack,relative_satoshis,s64,
|
||||
msgdata,splice_ack,funding_pubkey,point,
|
||||
msgtype,splice_locked,77,
|
||||
msgdata,splice_locked,channel_id,channel_id,
|
||||
msgtype,shutdown,38
|
||||
msgdata,shutdown,channel_id,channel_id,
|
||||
msgdata,shutdown,len,u16,
|
||||
|
@ -247,6 +264,9 @@ msgdata,commitment_signed,channel_id,channel_id,
|
|||
msgdata,commitment_signed,signature,signature,
|
||||
msgdata,commitment_signed,num_htlcs,u16,
|
||||
msgdata,commitment_signed,htlc_signature,signature,num_htlcs
|
||||
msgdata,commitment_signed,splice_channel_id,commitment_signed_tlvs,
|
||||
tlvtype,commitment_signed_tlvs,splice_info,0
|
||||
tlvdata,commitment_signed_tlvs,splice_info,splice_channel_id,channel_id,
|
||||
msgtype,revoke_and_ack,133
|
||||
msgdata,revoke_and_ack,channel_id,channel_id,
|
||||
msgdata,revoke_and_ack,per_commitment_secret,byte,32
|
||||
|
|
|
|
@ -40,6 +40,11 @@ static void set_scid(struct short_channel_id *scid)
|
|||
memset(scid, 2, sizeof(struct short_channel_id));
|
||||
}
|
||||
|
||||
static void set_cid(struct channel_id *cid)
|
||||
{
|
||||
memset(cid, 2, sizeof(struct channel_id));
|
||||
}
|
||||
|
||||
/* Size up to field. */
|
||||
#define upto_field(p, field) \
|
||||
((char *)&(p)->field - (char *)(p))
|
||||
|
@ -160,6 +165,7 @@ struct msg_commitment_signed {
|
|||
struct channel_id channel_id;
|
||||
secp256k1_ecdsa_signature signature;
|
||||
secp256k1_ecdsa_signature *htlc_signature;
|
||||
struct tlv_commitment_signed_tlvs *tlvs;
|
||||
};
|
||||
struct msg_node_announcement {
|
||||
secp256k1_ecdsa_signature signature;
|
||||
|
@ -525,17 +531,20 @@ static void *towire_struct_commitment_signed(const tal_t *ctx,
|
|||
return towire_commitment_signed(ctx,
|
||||
&s->channel_id,
|
||||
&s->signature,
|
||||
s->htlc_signature);
|
||||
s->htlc_signature,
|
||||
s->tlvs);
|
||||
}
|
||||
|
||||
static struct msg_commitment_signed *fromwire_struct_commitment_signed(const tal_t *ctx, const void *p)
|
||||
{
|
||||
struct msg_commitment_signed *s = tal(ctx, struct msg_commitment_signed);
|
||||
s->tlvs = tlv_commitment_signed_tlvs_new(ctx);
|
||||
|
||||
if (!fromwire_commitment_signed(s, p,
|
||||
&s->channel_id,
|
||||
&s->signature,
|
||||
&s->htlc_signature))
|
||||
&s->htlc_signature,
|
||||
&s->tlvs))
|
||||
return tal_free(s);
|
||||
return s;
|
||||
}
|
||||
|
@ -781,7 +790,8 @@ static bool commitment_signed_eq(const struct msg_commitment_signed *a,
|
|||
const struct msg_commitment_signed *b)
|
||||
{
|
||||
return eq_upto(a, b, htlc_signature)
|
||||
&& eq_var(a, b, htlc_signature);
|
||||
&& eq_var(a, b, htlc_signature)
|
||||
&& eq_tlv(a, b, splice_info, channel_id_eq);
|
||||
}
|
||||
|
||||
static bool funding_signed_eq(const struct msg_funding_signed *a,
|
||||
|
@ -1007,11 +1017,14 @@ int main(int argc, char *argv[])
|
|||
memset(&cs, 2, sizeof(cs));
|
||||
cs.htlc_signature = tal_arr(ctx, secp256k1_ecdsa_signature, 2);
|
||||
memset(cs.htlc_signature, 2, sizeof(secp256k1_ecdsa_signature)*2);
|
||||
cs.tlvs = tlv_commitment_signed_tlvs_new(tmpctx);
|
||||
cs.tlvs->splice_info = tal(ctx, struct channel_id);
|
||||
set_cid(cs.tlvs->splice_info);
|
||||
|
||||
msg = towire_struct_commitment_signed(ctx, &cs);
|
||||
cs2 = fromwire_struct_commitment_signed(ctx, msg);
|
||||
assert(commitment_signed_eq(&cs, cs2));
|
||||
test_corruption(&cs, cs2, commitment_signed);
|
||||
test_corruption_tlv(&cs, cs2, commitment_signed);
|
||||
|
||||
memset(&fs, 2, sizeof(fs));
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <ccan/crypto/siphash24/siphash24.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <channeld/inflight.h>
|
||||
#include <common/utils.h>
|
||||
|
||||
void towire(u8 **pptr, const void *data, size_t len)
|
||||
|
|
Loading…
Add table
Reference in a new issue