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;
|
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)
|
static inline u32 short_channel_id_txnum(const struct short_channel_id *scid)
|
||||||
{
|
{
|
||||||
return (scid->u64 >> 16) & 0x00FFFFFF;
|
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,
|
txfilter_add_scriptpubkey(peer->ld->owned_txfilter,
|
||||||
take(p2wpkh_for_keyidx(NULL, peer->ld,
|
take(p2wpkh_for_keyidx(NULL, peer->ld,
|
||||||
channel->final_key_idx)));
|
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;
|
return channel;
|
||||||
}
|
}
|
||||||
@@ -779,6 +785,11 @@ void channel_fail_permanent(struct channel *channel,
|
|||||||
const char *fmt,
|
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;
|
struct lightningd *ld = channel->peer->ld;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char *why;
|
char *why;
|
||||||
|
|||||||
@@ -669,8 +669,17 @@ enum watch_result onchaind_funding_spent(struct channel *channel,
|
|||||||
channel->final_key_idx);
|
channel->final_key_idx);
|
||||||
return KEEP_WATCHING;
|
return KEEP_WATCHING;
|
||||||
}
|
}
|
||||||
/* This could be a mutual close, but it doesn't matter. */
|
|
||||||
bitcoin_txid(channel->last_tx, &our_last_txid);
|
/* 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
|
/* We try to get the feerate for each transaction type, 0 if estimation
|
||||||
* failed. */
|
* failed. */
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <common/json_tok.h>
|
#include <common/json_tok.h>
|
||||||
#include <common/memleak.h>
|
#include <common/memleak.h>
|
||||||
#include <common/param.h>
|
#include <common/param.h>
|
||||||
|
#include <common/scb_wiregen.h>
|
||||||
#include <common/type_to_string.h>
|
#include <common/type_to_string.h>
|
||||||
#include <connectd/connectd_wiregen.h>
|
#include <connectd/connectd_wiregen.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -1229,6 +1230,208 @@ static struct command_result *json_fundchannel_start(struct command *cmd,
|
|||||||
return command_still_pending(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 = {
|
static const struct json_command fundchannel_start_command = {
|
||||||
"fundchannel_start",
|
"fundchannel_start",
|
||||||
"channels",
|
"channels",
|
||||||
@@ -1254,3 +1457,13 @@ static const struct json_command fundchannel_complete_command = {
|
|||||||
"with {psbt}. Returns true on success, false otherwise."
|
"with {psbt}. Returns true on success, false otherwise."
|
||||||
};
|
};
|
||||||
AUTODATA(json_command, &fundchannel_complete_command);
|
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;
|
const char *txidstr;
|
||||||
struct short_channel_id scid;
|
struct short_channel_id scid;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check, but we'll have to make an exception
|
||||||
if (!check_funding_tx(tx, channel)) {
|
* for stub channels(1x1x1) */
|
||||||
|
if (!check_funding_tx(tx, channel) && !is_stub_scid(channel->scid)) {
|
||||||
channel_internal_error(channel, "Bad tx %s: %s",
|
channel_internal_error(channel, "Bad tx %s: %s",
|
||||||
type_to_string(tmpctx,
|
type_to_string(tmpctx,
|
||||||
struct bitcoin_txid, txid),
|
struct bitcoin_txid, txid),
|
||||||
@@ -1592,13 +1593,15 @@ static enum watch_result funding_depth_cb(struct lightningd *ld,
|
|||||||
return DELETE_WATCH;
|
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) {
|
if (!channel->scid) {
|
||||||
channel->scid = tal(channel, struct short_channel_id);
|
channel->scid = tal(channel, struct short_channel_id);
|
||||||
*channel->scid = scid;
|
*channel->scid = scid;
|
||||||
wallet_channel_save(ld->wallet, channel);
|
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
|
/* This normally restarts channeld, initialized with updated scid
|
||||||
* and also adds it (at least our halve_chan) to rtable. */
|
* and also adds it (at least our halve_chan) to rtable. */
|
||||||
channel_fail_reconnect(channel,
|
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_talarr(stmt, 17, chan->shutdown_scriptpubkey[REMOTE]);
|
||||||
db_bind_u64(stmt, 18, chan->final_key_idx);
|
db_bind_u64(stmt, 18, chan->final_key_idx);
|
||||||
db_bind_u64(stmt, 19, chan->our_config.id);
|
db_bind_u64(stmt, 19, chan->our_config.id);
|
||||||
db_bind_psbt(stmt, 20, chan->last_tx->psbt);
|
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_signature(stmt, 21, &chan->last_sig.s);
|
||||||
db_bind_int(stmt, 22, chan->last_was_revoke);
|
db_bind_int(stmt, 22, chan->last_was_revoke);
|
||||||
db_bind_int(stmt, 23, chan->min_possible_feerate);
|
db_bind_int(stmt, 23, chan->min_possible_feerate);
|
||||||
|
|||||||
Reference in New Issue
Block a user