mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-24 01:24:26 +01:00
Plugins/chanbackup: Add hook for receiving custommsg
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
#include <common/json_param.h>
|
#include <common/json_param.h>
|
||||||
#include <common/json_stream.h>
|
#include <common/json_stream.h>
|
||||||
#include <common/scb_wiregen.h>
|
#include <common/scb_wiregen.h>
|
||||||
|
#include <common/type_to_string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <plugins/libplugin.h>
|
#include <plugins/libplugin.h>
|
||||||
@@ -257,7 +258,7 @@ static struct command_result *json_emergencyrecover(struct command *cmd,
|
|||||||
|
|
||||||
if (version != VERSION) {
|
if (version != VERSION) {
|
||||||
plugin_err(cmd->plugin,
|
plugin_err(cmd->plugin,
|
||||||
"Incompatible version, Contact the admin!");
|
"Incompatible SCB file version on disk, contact the admin!");
|
||||||
}
|
}
|
||||||
|
|
||||||
req = jsonrpc_request_start(cmd->plugin, cmd, "recoverchannel",
|
req = jsonrpc_request_start(cmd->plugin, cmd, "recoverchannel",
|
||||||
@@ -315,6 +316,81 @@ static void update_scb(struct plugin *p, struct scb_chan **channels)
|
|||||||
rename("scb.tmp", FILENAME);
|
rename("scb.tmp", FILENAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct info {
|
||||||
|
size_t idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct command_result *after_send_scb_single(struct command *cmd,
|
||||||
|
const char *buf,
|
||||||
|
const jsmntok_t *params,
|
||||||
|
struct info *info)
|
||||||
|
{
|
||||||
|
plugin_log(cmd->plugin, LOG_INFORM, "Peer storage sent!");
|
||||||
|
if (--info->idx != 0)
|
||||||
|
return command_still_pending(cmd);
|
||||||
|
|
||||||
|
return notification_handled(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct command_result *after_send_scb_single_fail(struct command *cmd,
|
||||||
|
const char *buf,
|
||||||
|
const jsmntok_t *params,
|
||||||
|
struct info *info)
|
||||||
|
{
|
||||||
|
plugin_log(cmd->plugin, LOG_DBG, "Peer storage send failed!");
|
||||||
|
if (--info->idx != 0)
|
||||||
|
return command_still_pending(cmd);
|
||||||
|
|
||||||
|
return notification_handled(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct command_result *after_listpeers(struct command *cmd,
|
||||||
|
const char *buf,
|
||||||
|
const jsmntok_t *params,
|
||||||
|
void *cb_arg UNUSED)
|
||||||
|
{
|
||||||
|
const jsmntok_t *peers, *peer, *nodeid;
|
||||||
|
struct out_req *req;
|
||||||
|
size_t i;
|
||||||
|
struct info *info = tal(cmd, struct info);
|
||||||
|
struct node_id *node_id = tal(cmd, struct node_id);
|
||||||
|
bool is_connected;
|
||||||
|
|
||||||
|
u8 *scb = get_file_data(cmd->plugin);
|
||||||
|
|
||||||
|
u8 *serialise_scb = towire_peer_storage(cmd, scb);
|
||||||
|
|
||||||
|
peers = json_get_member(buf, params, "peers");
|
||||||
|
|
||||||
|
info->idx = 0;
|
||||||
|
json_for_each_arr(i, peer, peers) {
|
||||||
|
json_to_bool(buf, json_get_member(buf, peer, "connected"),
|
||||||
|
&is_connected);
|
||||||
|
|
||||||
|
if (is_connected) {
|
||||||
|
nodeid = json_get_member(buf, peer, "id");
|
||||||
|
json_to_node_id(buf, nodeid, node_id);
|
||||||
|
|
||||||
|
req = jsonrpc_request_start(cmd->plugin,
|
||||||
|
cmd,
|
||||||
|
"sendcustommsg",
|
||||||
|
after_send_scb_single,
|
||||||
|
after_send_scb_single_fail,
|
||||||
|
info);
|
||||||
|
|
||||||
|
json_add_node_id(req->js, "node_id", node_id);
|
||||||
|
json_add_hex(req->js, "msg", serialise_scb,
|
||||||
|
tal_bytelen(serialise_scb));
|
||||||
|
info->idx++;
|
||||||
|
send_outreq(cmd->plugin, req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->idx == 0)
|
||||||
|
return notification_handled(cmd);
|
||||||
|
return command_still_pending(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
static struct command_result *after_staticbackup(struct command *cmd,
|
static struct command_result *after_staticbackup(struct command *cmd,
|
||||||
const char *buf,
|
const char *buf,
|
||||||
const jsmntok_t *params,
|
const jsmntok_t *params,
|
||||||
@@ -322,11 +398,20 @@ static struct command_result *after_staticbackup(struct command *cmd,
|
|||||||
{
|
{
|
||||||
struct scb_chan **scb_chan;
|
struct scb_chan **scb_chan;
|
||||||
const jsmntok_t *scbs = json_get_member(buf, params, "scb");
|
const jsmntok_t *scbs = json_get_member(buf, params, "scb");
|
||||||
|
struct out_req *req;
|
||||||
json_to_scb_chan(buf, scbs, &scb_chan);
|
json_to_scb_chan(buf, scbs, &scb_chan);
|
||||||
plugin_log(cmd->plugin, LOG_INFORM, "Updating the SCB");
|
plugin_log(cmd->plugin, LOG_INFORM, "Updating the SCB");
|
||||||
|
|
||||||
update_scb(cmd->plugin, scb_chan);
|
update_scb(cmd->plugin, scb_chan);
|
||||||
return notification_handled(cmd);
|
struct info *info = tal(cmd, struct info);
|
||||||
|
info->idx = 0;
|
||||||
|
req = jsonrpc_request_start(cmd->plugin,
|
||||||
|
cmd,
|
||||||
|
"listpeers",
|
||||||
|
after_listpeers,
|
||||||
|
&forward_error,
|
||||||
|
info);
|
||||||
|
return send_outreq(cmd->plugin, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *json_state_changed(struct command *cmd,
|
static struct command_result *json_state_changed(struct command *cmd,
|
||||||
@@ -355,6 +440,179 @@ static struct command_result *json_state_changed(struct command *cmd,
|
|||||||
return notification_handled(cmd);
|
return notification_handled(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct command_result *failed_peer_restore(struct command *cmd,
|
||||||
|
struct node_id *node_id,
|
||||||
|
char *reason)
|
||||||
|
{
|
||||||
|
plugin_log(cmd->plugin, LOG_DBG, "PeerStorageFailed!: %s: %s",
|
||||||
|
type_to_string(tmpctx, struct node_id, node_id),
|
||||||
|
reason);
|
||||||
|
return command_hook_success(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct command_result *datastore_success(struct command *cmd,
|
||||||
|
const char *buf,
|
||||||
|
const jsmntok_t *result,
|
||||||
|
char *what)
|
||||||
|
{
|
||||||
|
plugin_log(cmd->plugin, LOG_DBG, "datastore succeeded for %s", what);
|
||||||
|
return command_hook_success(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct command_result *datastore_failed(struct command *cmd,
|
||||||
|
const char *buf,
|
||||||
|
const jsmntok_t *result,
|
||||||
|
char *what)
|
||||||
|
{
|
||||||
|
plugin_log(cmd->plugin, LOG_DBG, "datastore failed for %s: %.*s",
|
||||||
|
what, json_tok_full_len(result), json_tok_full(buf, result));
|
||||||
|
return command_hook_success(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct command_result *handle_your_peer_storage(struct command *cmd,
|
||||||
|
const char *buf,
|
||||||
|
const jsmntok_t *params)
|
||||||
|
{
|
||||||
|
struct node_id node_id;
|
||||||
|
u8 *payload, *payload_deserialise;
|
||||||
|
const char *err = json_scan(cmd, buf, params,
|
||||||
|
"{payload:%,peer_id:%}",
|
||||||
|
JSON_SCAN_TAL(cmd,
|
||||||
|
json_tok_bin_from_hex,
|
||||||
|
&payload),
|
||||||
|
JSON_SCAN(json_to_node_id,
|
||||||
|
&node_id));
|
||||||
|
if (err) {
|
||||||
|
plugin_err(cmd->plugin,
|
||||||
|
"`your_peer_storage` response did not scan %s: %.*s",
|
||||||
|
err, json_tok_full_len(params),
|
||||||
|
json_tok_full(buf, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromwire_peer_storage(cmd, payload, &payload_deserialise)) {
|
||||||
|
return jsonrpc_set_datastore_binary(cmd->plugin,
|
||||||
|
cmd,
|
||||||
|
tal_fmt(cmd,
|
||||||
|
"chanbackup/peers/%s",
|
||||||
|
type_to_string(tmpctx,
|
||||||
|
struct node_id,
|
||||||
|
&node_id)),
|
||||||
|
payload_deserialise,
|
||||||
|
"create-or-replace",
|
||||||
|
datastore_success,
|
||||||
|
datastore_failed,
|
||||||
|
"Saving chanbackup/peers/");
|
||||||
|
} else if (fromwire_your_peer_storage(cmd, payload, &payload_deserialise)) {
|
||||||
|
plugin_log(cmd->plugin, LOG_DBG,
|
||||||
|
"Received peer_storage from peer.");
|
||||||
|
|
||||||
|
crypto_secretstream_xchacha20poly1305_state crypto_state;
|
||||||
|
|
||||||
|
if (tal_bytelen(payload_deserialise) < ABYTES +
|
||||||
|
HEADER_LEN)
|
||||||
|
return failed_peer_restore(cmd, &node_id,
|
||||||
|
"Too short!");
|
||||||
|
|
||||||
|
u8 *decoded_bkp = tal_arr(tmpctx, u8,
|
||||||
|
tal_bytelen(payload_deserialise) -
|
||||||
|
ABYTES -
|
||||||
|
HEADER_LEN);
|
||||||
|
|
||||||
|
/* The header part */
|
||||||
|
if (crypto_secretstream_xchacha20poly1305_init_pull(&crypto_state,
|
||||||
|
payload_deserialise,
|
||||||
|
(&secret)->data) != 0)
|
||||||
|
return failed_peer_restore(cmd, &node_id,
|
||||||
|
"Peer altered our data");
|
||||||
|
|
||||||
|
if (crypto_secretstream_xchacha20poly1305_pull(&crypto_state,
|
||||||
|
decoded_bkp,
|
||||||
|
NULL, 0,
|
||||||
|
payload_deserialise +
|
||||||
|
HEADER_LEN,
|
||||||
|
tal_bytelen(payload_deserialise) -
|
||||||
|
HEADER_LEN,
|
||||||
|
NULL, 0) != 0)
|
||||||
|
return failed_peer_restore(cmd, &node_id,
|
||||||
|
"Peer altered our data");
|
||||||
|
|
||||||
|
|
||||||
|
return jsonrpc_set_datastore_binary(cmd->plugin,
|
||||||
|
cmd,
|
||||||
|
"chanbackup/latestscb",
|
||||||
|
decoded_bkp,
|
||||||
|
"create-or-replace",
|
||||||
|
datastore_success,
|
||||||
|
datastore_failed,
|
||||||
|
"Saving latestscb");
|
||||||
|
} else {
|
||||||
|
plugin_log(cmd->plugin, LOG_DBG,
|
||||||
|
"Peer sent bad custom message for chanbackup!");
|
||||||
|
return command_hook_success(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct command_result *after_latestscb(struct command *cmd,
|
||||||
|
const u8 *res,
|
||||||
|
void *cb_arg UNUSED)
|
||||||
|
{
|
||||||
|
u64 version;
|
||||||
|
u32 timestamp;
|
||||||
|
struct scb_chan **scb;
|
||||||
|
struct json_stream *response;
|
||||||
|
struct out_req *req;
|
||||||
|
|
||||||
|
if (tal_bytelen(res) == 0) {
|
||||||
|
response = jsonrpc_stream_success(cmd);
|
||||||
|
|
||||||
|
json_add_string(response, "result",
|
||||||
|
"No backup received from peers");
|
||||||
|
return command_finished(cmd, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fromwire_static_chan_backup(cmd,
|
||||||
|
res,
|
||||||
|
&version,
|
||||||
|
×tamp,
|
||||||
|
&scb)) {
|
||||||
|
plugin_err(cmd->plugin, "Corrupted SCB on disk!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version != VERSION) {
|
||||||
|
plugin_err(cmd->plugin,
|
||||||
|
"Incompatible version, Contact the admin!");
|
||||||
|
}
|
||||||
|
|
||||||
|
req = jsonrpc_request_start(cmd->plugin, cmd, "recoverchannel",
|
||||||
|
after_recover_rpc,
|
||||||
|
&forward_error, NULL);
|
||||||
|
|
||||||
|
json_array_start(req->js, "scb");
|
||||||
|
for (size_t i=0; i<tal_count(scb); i++) {
|
||||||
|
u8 *scb_hex = tal_arr(cmd, u8, 0);
|
||||||
|
towire_scb_chan(&scb_hex,scb[i]);
|
||||||
|
json_add_hex(req->js, NULL, scb_hex, tal_bytelen(scb_hex));
|
||||||
|
}
|
||||||
|
json_array_end(req->js);
|
||||||
|
|
||||||
|
return send_outreq(cmd->plugin, req);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct command_result *json_restorefrompeer(struct command *cmd,
|
||||||
|
const char *buf,
|
||||||
|
const jsmntok_t *params)
|
||||||
|
{
|
||||||
|
if (!param(cmd, buf, params, NULL))
|
||||||
|
return command_param_failed();
|
||||||
|
|
||||||
|
return jsonrpc_get_datastore_binary(cmd->plugin,
|
||||||
|
cmd,
|
||||||
|
"chanbackup/latestscb",
|
||||||
|
after_latestscb,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static const char *init(struct plugin *p,
|
static const char *init(struct plugin *p,
|
||||||
const char *buf UNUSED,
|
const char *buf UNUSED,
|
||||||
const jsmntok_t *config UNUSED)
|
const jsmntok_t *config UNUSED)
|
||||||
@@ -391,13 +649,29 @@ static const struct plugin_notification notifs[] = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct plugin_hook hooks[] = {
|
||||||
|
{
|
||||||
|
"custommsg",
|
||||||
|
handle_your_peer_storage,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static const struct plugin_command commands[] = { {
|
static const struct plugin_command commands[] = { {
|
||||||
"emergencyrecover",
|
"emergencyrecover",
|
||||||
"recovery",
|
"recovery",
|
||||||
"Populates the DB with stub channels",
|
"Populates the DB with stub channels",
|
||||||
"returns stub channel-id's on completion",
|
"returns stub channel-id's on completion",
|
||||||
json_emergencyrecover,
|
json_emergencyrecover,
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"restorefrompeer",
|
||||||
|
"recovery",
|
||||||
|
"Checks if i have got a backup from a peer, and if so, will stub "
|
||||||
|
"those channels in the database and if is successful, will return "
|
||||||
|
"list of channels that have been successfully stubbed",
|
||||||
|
"return channel-id's on completion",
|
||||||
|
json_restorefrompeer,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@@ -408,9 +682,9 @@ int main(int argc, char *argv[])
|
|||||||
take(feature_set_for_feature(NULL,
|
take(feature_set_for_feature(NULL,
|
||||||
YOUR_PEER_STORAGE_FEATURE)));
|
YOUR_PEER_STORAGE_FEATURE)));
|
||||||
|
|
||||||
plugin_main(argv, init, PLUGIN_STATIC, true, NULL,
|
plugin_main(argv, init, PLUGIN_STATIC, true, features,
|
||||||
commands, ARRAY_SIZE(commands),
|
commands, ARRAY_SIZE(commands),
|
||||||
notifs, ARRAY_SIZE(notifs), NULL, 0,
|
notifs, ARRAY_SIZE(notifs), hooks, ARRAY_SIZE(hooks),
|
||||||
NULL, 0, /* Notification topics we publish */
|
NULL, 0, /* Notification topics we publish */
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user