lightningd: Add RPC for populating DB with stub channels and set an error on reconnecting

This commit is contained in:
adi2011
2022-06-24 06:44:11 +05:30
committed by neil saitug
parent 286d6c3165
commit 6ba8abb0de
6 changed files with 253 additions and 7 deletions

View File

@@ -37,6 +37,13 @@ static inline u32 short_channel_id_blocknum(const struct short_channel_id *scid)
return scid->u64 >> 40;
}
static inline bool is_stub_scid(const struct short_channel_id *scid)
{
return scid ? scid->u64 >> 40 == 1 &&
((scid->u64 >> 16) & 0x00FFFFFF) == 1 &&
(scid->u64 & 0xFFFF) == 1 : false;
}
static inline u32 short_channel_id_txnum(const struct short_channel_id *scid)
{
return (scid->u64 >> 16) & 0x00FFFFFF;

View File

@@ -534,6 +534,12 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
txfilter_add_scriptpubkey(peer->ld->owned_txfilter,
take(p2wpkh_for_keyidx(NULL, peer->ld,
channel->final_key_idx)));
/* scid is NULL when opening a new channel so we don't
* need to set error in that case as well */
if (is_stub_scid(scid))
channel->error = towire_errorfmt(peer->ld,
&channel->cid,
"We can't be together anymore.");
return channel;
}
@@ -779,6 +785,11 @@ void channel_fail_permanent(struct channel *channel,
const char *fmt,
...)
{
/* Don't do anything if it's an stub channel because
* peer has already closed it unilatelrally. */
if (is_stub_scid(channel->scid))
return;
struct lightningd *ld = channel->peer->ld;
va_list ap;
char *why;

View File

@@ -669,8 +669,17 @@ enum watch_result onchaind_funding_spent(struct channel *channel,
channel->final_key_idx);
return KEEP_WATCHING;
}
/* This could be a mutual close, but it doesn't matter. */
/* This could be a mutual close, but it doesn't matter.
* We don't need this for stub channels as well */
if (!is_stub_scid(channel->scid))
bitcoin_txid(channel->last_tx, &our_last_txid);
else
/* Dummy txid for stub channel to make valgrind happy. */
bitcoin_txid_from_hex("80cea306607b708a03a1854520729d"
"a884e4317b7b51f3d4a622f88176f5e034",
64,
&our_last_txid);
/* We try to get the feerate for each transaction type, 0 if estimation
* failed. */

View File

@@ -13,6 +13,7 @@
#include <common/json_tok.h>
#include <common/memleak.h>
#include <common/param.h>
#include <common/scb_wiregen.h>
#include <common/type_to_string.h>
#include <connectd/connectd_wiregen.h>
#include <errno.h>
@@ -1229,6 +1230,208 @@ static struct command_result *json_fundchannel_start(struct command *cmd,
return command_still_pending(cmd);
}
static struct channel *stub_chan(struct command *cmd,
u64 id,
struct node_id nodeid,
struct channel_id cid,
struct bitcoin_outpoint funding,
struct wireaddr_internal addr,
struct amount_sat funding_sats,
struct channel_type *type)
{
struct basepoints basepoints;
struct bitcoin_signature *sig;
struct channel *channel;
struct channel_config *our_config;
struct channel_config *their_config;
struct channel_info *channel_info;
struct lightningd *ld;
struct peer *peer;
struct pubkey localFundingPubkey;
struct pubkey pk;
struct short_channel_id *scid;
u32 blockht;
u32 feerate;
u8 *dummy_sig = tal_hexdata(cmd,
"30450221009b2e0eef267b94c3899fb0dc73750"
"12e2cee4c10348a068fe78d1b82b4b1403602207"
"7c3fad3adac2ddf33f415e45f0daf6658b7a0b09"
"647de4443938ae2dbafe2b9" "01",
144);
peer = new_peer(cmd->ld,
0,
&nodeid,
&addr,
false);
ld = cmd->ld;
feerate = FEERATE_FLOOR;
sig = tal(cmd, struct bitcoin_signature);
signature_from_der(dummy_sig,
tal_bytelen(dummy_sig)
,sig);
if (!pubkey_from_der(tal_hexdata(cmd,
type_to_string(tmpctx,
struct node_id,
&nodeid),
66),
33,
&pk))
{
fatal("Invalid node id!");
}
get_channel_basepoints(ld,
&nodeid,
id,
&basepoints,
&localFundingPubkey);
channel_info = tal(cmd,
struct channel_info);
our_config = tal(cmd, struct channel_config);
their_config = tal(cmd, struct channel_config);
/* FIXME: Makeake these a pointer, so they could be NULL */
memset(our_config, 0, sizeof(struct channel_config));
memset(their_config, 0, sizeof(struct channel_config));
channel_info->their_config = *their_config;
channel_info->theirbase = basepoints;
channel_info->remote_fundingkey = pk;
channel_info->remote_per_commit = pk;
channel_info->old_remote_per_commit = pk;
blockht = 100;
scid = tal(cmd, struct short_channel_id);
/*To indicate this is an stub channel we keep it's scid to 1x1x1.*/
if (!mk_short_channel_id(scid, 1, 1, 1))
fatal("Failed to make short channel 1x1x1!");
/* Channel Shell with Dummy data(mostly) */
channel = new_channel(peer, id,
NULL, /* No shachain yet */
CHANNELD_NORMAL,
LOCAL,
NULL,
"restored from static channel backup",
0, our_config,
0,
1, 1, 1,
&funding,
funding_sats,
AMOUNT_MSAT(0),
AMOUNT_SAT(0),
true, /* !remote_funding_locked */
scid,
scid,
scid,
&cid,
/* The three arguments below are msatoshi_to_us,
* msatoshi_to_us_min, and msatoshi_to_us_max.
* Because, this is a newly-funded channel,
* all three are same value. */
AMOUNT_MSAT(0),
AMOUNT_MSAT(0), /* msat_to_us_min */
AMOUNT_MSAT(0), /* msat_to_us_max */
NULL,
sig,
NULL, /* No HTLC sigs */
channel_info,
new_fee_states(cmd, LOCAL, &feerate),
NULL, /* No shutdown_scriptpubkey[REMOTE] */
NULL,
1, false,
NULL, /* No commit sent */
/* If we're fundee, could be a little before this
* in theory, but it's only used for timing out. */
get_network_blockheight(ld->topology),
FEERATE_FLOOR,
funding_sats.satoshis / MINIMUM_TX_WEIGHT * 1000 /* Raw: convert to feerate */,
false,
&basepoints,
&localFundingPubkey,
NULL,
ld->config.fee_base,
ld->config.fee_per_satoshi,
NULL,
0, 0,
type,
NUM_SIDES, /* closer not yet known */
REASON_REMOTE,
NULL,
take(new_height_states(ld->wallet, LOCAL,
&blockht)),
0, NULL, 0, 0, /* No leases on v1s */
ld->config.htlc_minimum_msat,
ld->config.htlc_maximum_msat);
return channel;
}
static struct command_result *json_recoverchannel(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
const jsmntok_t *scb, *t;
size_t i;
struct json_stream *response;
struct scb_chan *scb_chan = tal(cmd, struct scb_chan);
if (!param(cmd, buffer, params,
p_req("scb", param_array, &scb),
NULL))
return command_param_failed();
response = json_stream_success(cmd);
json_array_start(response, "stubs");
json_for_each_arr(i,t,scb){
char *token = json_strdup(tmpctx, buffer, t);
const u8 *scb_arr = tal_hexdata(cmd, token, strlen(token));
size_t scblen = tal_count(scb_arr);
scb_chan = fromwire_scb_chan(cmd ,&scb_arr, &scblen);
if (scb_chan == NULL) {
log_broken(cmd->ld->log, "SCB is invalid!");
continue;
}
struct lightningd *ld = cmd->ld;
struct channel *channel= stub_chan(cmd,
scb_chan->id,
scb_chan->node_id,
scb_chan->cid,
scb_chan->funding,
scb_chan->addr,
scb_chan->funding_sats,
scb_chan->type);
/* Now we put this in the database. */
wallet_channel_insert(ld->wallet, channel);
/* Watch the Funding */
channel_watch_funding(ld, channel);
json_add_channel_id(response, NULL, &scb_chan->cid);
}
/* This will try to reconnect to the peers and start
* initiating the process */
setup_peers(cmd->ld);
json_array_end(response);
return command_success(cmd, response);
}
static const struct json_command fundchannel_start_command = {
"fundchannel_start",
"channels",
@@ -1254,3 +1457,13 @@ static const struct json_command fundchannel_complete_command = {
"with {psbt}. Returns true on success, false otherwise."
};
AUTODATA(json_command, &fundchannel_complete_command);
static const struct json_command json_commitchan_command = {
"recoverchannel",
"channels",
json_recoverchannel,
"Populate the DB with a channel and peer"
"Used for recovering the channel using DLP."
"This needs param in the form of an array [scb1,scb2,...]"
};
AUTODATA(json_command, &json_commitchan_command);

View File

@@ -1536,8 +1536,9 @@ static enum watch_result funding_depth_cb(struct lightningd *ld,
const char *txidstr;
struct short_channel_id scid;
/* Sanity check */
if (!check_funding_tx(tx, channel)) {
/* Sanity check, but we'll have to make an exception
* for stub channels(1x1x1) */
if (!check_funding_tx(tx, channel) && !is_stub_scid(channel->scid)) {
channel_internal_error(channel, "Bad tx %s: %s",
type_to_string(tmpctx,
struct bitcoin_txid, txid),
@@ -1592,13 +1593,15 @@ static enum watch_result funding_depth_cb(struct lightningd *ld,
return DELETE_WATCH;
}
/* If we restart, we could already have peer->scid from database */
/* 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);
*channel->scid = scid;
wallet_channel_save(ld->wallet, channel);
} else if (!short_channel_id_eq(channel->scid, &scid)) {
} else if (!short_channel_id_eq(channel->scid, &scid) &&
!is_stub_scid(channel->scid)) {
/* This normally restarts channeld, initialized with updated scid
* and also adds it (at least our halve_chan) to rtable. */
channel_fail_reconnect(channel,

View File

@@ -1930,7 +1930,10 @@ void wallet_channel_save(struct wallet *w, struct channel *chan)
db_bind_talarr(stmt, 17, chan->shutdown_scriptpubkey[REMOTE]);
db_bind_u64(stmt, 18, chan->final_key_idx);
db_bind_u64(stmt, 19, chan->our_config.id);
if (chan->last_tx)
db_bind_psbt(stmt, 20, chan->last_tx->psbt);
else
db_bind_null(stmt, 20);
db_bind_signature(stmt, 21, &chan->last_sig.s);
db_bind_int(stmt, 22, chan->last_was_revoke);
db_bind_int(stmt, 23, chan->min_possible_feerate);