mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 07:04:22 +01:00
lightningd: Add RPC for populating DB with stub channels and set an error on reconnecting
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user