mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
df-rbf: validate that the candidate funding transaction is valid
We need to make sure that there's at least one input that's represented in every single RBF-attempt for this channel, to prevent "parallel" subsequent RBFs from succeeding/opening (the multi-channel backdoor?!)
This commit is contained in:
parent
b30489310b
commit
0d8351155e
@ -4,7 +4,9 @@
|
||||
|
||||
#include <bitcoin/psbt.h>
|
||||
#include <bitcoin/script.h>
|
||||
#include <ccan/ccan/mem/mem.h>
|
||||
#include <ccan/ccan/take/take.h>
|
||||
#include <ccan/ccan/tal/tal.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <common/amount.h>
|
||||
#include <common/channel_config.h>
|
||||
@ -1603,6 +1605,70 @@ static void handle_peer_tx_sigs_msg(struct subd *dualopend,
|
||||
channel->psbt);
|
||||
}
|
||||
|
||||
static void handle_validate_rbf(struct subd *dualopend,
|
||||
const u8 *msg)
|
||||
{
|
||||
struct wally_psbt *candidate_psbt;
|
||||
struct channel_inflight *inflight;
|
||||
struct channel *channel = dualopend->channel;
|
||||
bool *inputs_present;
|
||||
|
||||
if (!fromwire_dualopend_rbf_validate(tmpctx, msg,
|
||||
&candidate_psbt)) {
|
||||
channel_internal_error(channel,
|
||||
"Malformed dualopend_rbf_validate %s",
|
||||
tal_hex(tmpctx, msg));
|
||||
return;
|
||||
}
|
||||
|
||||
inputs_present = tal_arr(tmpctx, bool, candidate_psbt->num_inputs);
|
||||
memset(inputs_present, true, tal_bytelen(inputs_present));
|
||||
|
||||
/* Check all previous funding transactions */
|
||||
list_for_each(&channel->inflights, inflight, list) {
|
||||
/* Remove every non-matching input from set */
|
||||
for (size_t i = 0; i < candidate_psbt->num_inputs; i++) {
|
||||
struct wally_tx_input *input =
|
||||
&candidate_psbt->tx->inputs[i];
|
||||
struct bitcoin_txid in_txid;
|
||||
|
||||
wally_tx_input_get_txid(input, &in_txid);
|
||||
|
||||
if (!psbt_has_input(inflight->funding_psbt,
|
||||
&in_txid, input->index))
|
||||
inputs_present[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Are there any inputs that were present on all txs? */
|
||||
if (memeqzero(inputs_present, tal_bytelen(inputs_present))) {
|
||||
char *errmsg;
|
||||
|
||||
inflight = list_tail(&channel->inflights,
|
||||
struct channel_inflight,
|
||||
list);
|
||||
assert(inflight);
|
||||
|
||||
errmsg = tal_fmt(tmpctx, "No overlapping input"
|
||||
" present. New: %s, last: %s",
|
||||
type_to_string(tmpctx,
|
||||
struct wally_psbt,
|
||||
candidate_psbt),
|
||||
type_to_string(tmpctx,
|
||||
struct wally_psbt,
|
||||
inflight->funding_psbt));
|
||||
msg = towire_dualopend_fail(NULL, errmsg);
|
||||
goto send_msg;
|
||||
}
|
||||
|
||||
/* FIXME: check that total fee paid is greater than last */
|
||||
|
||||
msg = towire_dualopend_rbf_valid(NULL);
|
||||
|
||||
send_msg:
|
||||
subd_send_msg(channel->owner, take(msg));
|
||||
}
|
||||
|
||||
|
||||
static struct command_result *
|
||||
json_openchannel_signed(struct command *cmd,
|
||||
@ -1962,6 +2028,9 @@ static unsigned int dual_opend_msg(struct subd *dualopend,
|
||||
accepter_commit_received(dualopend,
|
||||
uc, fds, msg);
|
||||
return 0;
|
||||
case WIRE_DUALOPEND_RBF_VALIDATE:
|
||||
handle_validate_rbf(dualopend, msg);
|
||||
return 0;
|
||||
case WIRE_DUALOPEND_FUNDING_SIGS:
|
||||
handle_peer_tx_sigs_msg(dualopend, msg);
|
||||
return 0;
|
||||
@ -2002,6 +2071,7 @@ static unsigned int dual_opend_msg(struct subd *dualopend,
|
||||
case WIRE_DUALOPEND_OPENER_INIT:
|
||||
case WIRE_DUALOPEND_GOT_OFFER_REPLY:
|
||||
case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY:
|
||||
case WIRE_DUALOPEND_RBF_VALID:
|
||||
case WIRE_DUALOPEND_FAIL:
|
||||
case WIRE_DUALOPEND_PSBT_UPDATED:
|
||||
case WIRE_DUALOPEND_SEND_TX_SIGS:
|
||||
|
@ -2592,6 +2592,20 @@ static void rbf_start(struct state *state, const u8 *rbf_msg)
|
||||
&tx_state->psbt, state->our_role))
|
||||
return;
|
||||
|
||||
/* Is this an eligible RBF (at least one overlapping input) */
|
||||
msg = towire_dualopend_rbf_validate(NULL, tx_state->psbt);
|
||||
wire_sync_write(REQ_FD, take(msg));
|
||||
msg = wire_sync_read(tmpctx, REQ_FD);
|
||||
|
||||
if ((msg_type = fromwire_peektype(msg)) == WIRE_DUALOPEND_FAIL) {
|
||||
if (!fromwire_dualopend_fail(msg, msg, &err_reason))
|
||||
master_badmsg(msg_type, msg);
|
||||
rbf_failed(state, "%s", err_reason);
|
||||
}
|
||||
|
||||
if (!fromwire_dualopend_rbf_valid(msg))
|
||||
master_badmsg(WIRE_DUALOPEND_RBF_VALID, msg);
|
||||
|
||||
/* Find the funding transaction txid */
|
||||
psbt_txid(NULL, tx_state->psbt, &tx_state->funding_txid, NULL);
|
||||
|
||||
@ -2962,10 +2976,12 @@ static u8 *handle_master_in(struct state *state)
|
||||
case WIRE_DUALOPEND_PSBT_UPDATED:
|
||||
case WIRE_DUALOPEND_GOT_OFFER_REPLY:
|
||||
case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY:
|
||||
case WIRE_DUALOPEND_RBF_VALID:
|
||||
|
||||
/* Messages we send */
|
||||
case WIRE_DUALOPEND_GOT_OFFER:
|
||||
case WIRE_DUALOPEND_GOT_RBF_OFFER:
|
||||
case WIRE_DUALOPEND_RBF_VALIDATE:
|
||||
case WIRE_DUALOPEND_PSBT_CHANGED:
|
||||
case WIRE_DUALOPEND_COMMIT_RCVD:
|
||||
case WIRE_DUALOPEND_FUNDING_SIGS:
|
||||
|
@ -111,6 +111,13 @@ msgtype,dualopend_got_rbf_offer_reply,7505
|
||||
msgdata,dualopend_got_rbf_offer_reply,accepter_funding,amount_sat,
|
||||
msgdata,dualopend_got_rbf_offer_reply,psbt,wally_psbt,
|
||||
|
||||
# dualopend->master: is this a valid RBF candidate transaction?
|
||||
msgtype,dualopend_rbf_validate,7506
|
||||
msgdata,dualopend_rbf_validate,proposed_funding_psbt,wally_psbt,
|
||||
|
||||
# master->dualopend: this is a valid RBF candidate transaction
|
||||
msgtype,dualopend_rbf_valid,7507
|
||||
|
||||
# dualopend->master: ready to commit channel open to database and
|
||||
# get some signatures for the funding_tx.
|
||||
msgtype,dualopend_commit_rcvd,7007
|
||||
|
Can't render this file because it has a wrong number of fields in line 13.
|
48
openingd/dualopend_wiregen.c
generated
48
openingd/dualopend_wiregen.c
generated
@ -26,6 +26,8 @@ const char *dualopend_wire_name(int e)
|
||||
case WIRE_DUALOPEND_GOT_OFFER_REPLY: return "WIRE_DUALOPEND_GOT_OFFER_REPLY";
|
||||
case WIRE_DUALOPEND_GOT_RBF_OFFER: return "WIRE_DUALOPEND_GOT_RBF_OFFER";
|
||||
case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY: return "WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY";
|
||||
case WIRE_DUALOPEND_RBF_VALIDATE: return "WIRE_DUALOPEND_RBF_VALIDATE";
|
||||
case WIRE_DUALOPEND_RBF_VALID: return "WIRE_DUALOPEND_RBF_VALID";
|
||||
case WIRE_DUALOPEND_COMMIT_RCVD: return "WIRE_DUALOPEND_COMMIT_RCVD";
|
||||
case WIRE_DUALOPEND_PSBT_CHANGED: return "WIRE_DUALOPEND_PSBT_CHANGED";
|
||||
case WIRE_DUALOPEND_PSBT_UPDATED: return "WIRE_DUALOPEND_PSBT_UPDATED";
|
||||
@ -60,6 +62,8 @@ bool dualopend_wire_is_defined(u16 type)
|
||||
case WIRE_DUALOPEND_GOT_OFFER_REPLY:;
|
||||
case WIRE_DUALOPEND_GOT_RBF_OFFER:;
|
||||
case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY:;
|
||||
case WIRE_DUALOPEND_RBF_VALIDATE:;
|
||||
case WIRE_DUALOPEND_RBF_VALID:;
|
||||
case WIRE_DUALOPEND_COMMIT_RCVD:;
|
||||
case WIRE_DUALOPEND_PSBT_CHANGED:;
|
||||
case WIRE_DUALOPEND_PSBT_UPDATED:;
|
||||
@ -411,6 +415,48 @@ bool fromwire_dualopend_got_rbf_offer_reply(const tal_t *ctx, const void *p, str
|
||||
return cursor != NULL;
|
||||
}
|
||||
|
||||
/* WIRE: DUALOPEND_RBF_VALIDATE */
|
||||
/* dualopend->master: is this a valid RBF candidate transaction? */
|
||||
u8 *towire_dualopend_rbf_validate(const tal_t *ctx, const struct wally_psbt *proposed_funding_psbt)
|
||||
{
|
||||
u8 *p = tal_arr(ctx, u8, 0);
|
||||
|
||||
towire_u16(&p, WIRE_DUALOPEND_RBF_VALIDATE);
|
||||
towire_wally_psbt(&p, proposed_funding_psbt);
|
||||
|
||||
return memcheck(p, tal_count(p));
|
||||
}
|
||||
bool fromwire_dualopend_rbf_validate(const tal_t *ctx, const void *p, struct wally_psbt **proposed_funding_psbt)
|
||||
{
|
||||
const u8 *cursor = p;
|
||||
size_t plen = tal_count(p);
|
||||
|
||||
if (fromwire_u16(&cursor, &plen) != WIRE_DUALOPEND_RBF_VALIDATE)
|
||||
return false;
|
||||
*proposed_funding_psbt = fromwire_wally_psbt(ctx, &cursor, &plen);
|
||||
return cursor != NULL;
|
||||
}
|
||||
|
||||
/* WIRE: DUALOPEND_RBF_VALID */
|
||||
/* master->dualopend: this is a valid RBF candidate transaction */
|
||||
u8 *towire_dualopend_rbf_valid(const tal_t *ctx)
|
||||
{
|
||||
u8 *p = tal_arr(ctx, u8, 0);
|
||||
|
||||
towire_u16(&p, WIRE_DUALOPEND_RBF_VALID);
|
||||
|
||||
return memcheck(p, tal_count(p));
|
||||
}
|
||||
bool fromwire_dualopend_rbf_valid(const void *p)
|
||||
{
|
||||
const u8 *cursor = p;
|
||||
size_t plen = tal_count(p);
|
||||
|
||||
if (fromwire_u16(&cursor, &plen) != WIRE_DUALOPEND_RBF_VALID)
|
||||
return false;
|
||||
return cursor != NULL;
|
||||
}
|
||||
|
||||
/* WIRE: DUALOPEND_COMMIT_RCVD */
|
||||
/* dualopend->master: ready to commit channel open to database and */
|
||||
/* get some signatures for the funding_tx. */
|
||||
@ -920,4 +966,4 @@ bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak)
|
||||
*leak = fromwire_bool(&cursor, &plen);
|
||||
return cursor != NULL;
|
||||
}
|
||||
// SHA256STAMP:65a94b9b35802a6cd6c68f724e83ce4866adb3122a392d6741ec7c791ef1fd6c
|
||||
// SHA256STAMP:e514a16cf96dfcaf44217cf344ce75e2b8cbcb460901c610d9b75e22937636cd
|
||||
|
16
openingd/dualopend_wiregen.h
generated
16
openingd/dualopend_wiregen.h
generated
@ -31,6 +31,10 @@ enum dualopend_wire {
|
||||
WIRE_DUALOPEND_GOT_RBF_OFFER = 7500,
|
||||
/* master->dualopend: reply back with our funding info/contribs */
|
||||
WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY = 7505,
|
||||
/* dualopend->master: is this a valid RBF candidate transaction? */
|
||||
WIRE_DUALOPEND_RBF_VALIDATE = 7506,
|
||||
/* master->dualopend: this is a valid RBF candidate transaction */
|
||||
WIRE_DUALOPEND_RBF_VALID = 7507,
|
||||
/* dualopend->master: ready to commit channel open to database and */
|
||||
/* get some signatures for the funding_tx. */
|
||||
WIRE_DUALOPEND_COMMIT_RCVD = 7007,
|
||||
@ -112,6 +116,16 @@ bool fromwire_dualopend_got_rbf_offer(const void *p, struct channel_id *channel_
|
||||
u8 *towire_dualopend_got_rbf_offer_reply(const tal_t *ctx, struct amount_sat accepter_funding, const struct wally_psbt *psbt);
|
||||
bool fromwire_dualopend_got_rbf_offer_reply(const tal_t *ctx, const void *p, struct amount_sat *accepter_funding, struct wally_psbt **psbt);
|
||||
|
||||
/* WIRE: DUALOPEND_RBF_VALIDATE */
|
||||
/* dualopend->master: is this a valid RBF candidate transaction? */
|
||||
u8 *towire_dualopend_rbf_validate(const tal_t *ctx, const struct wally_psbt *proposed_funding_psbt);
|
||||
bool fromwire_dualopend_rbf_validate(const tal_t *ctx, const void *p, struct wally_psbt **proposed_funding_psbt);
|
||||
|
||||
/* WIRE: DUALOPEND_RBF_VALID */
|
||||
/* master->dualopend: this is a valid RBF candidate transaction */
|
||||
u8 *towire_dualopend_rbf_valid(const tal_t *ctx);
|
||||
bool fromwire_dualopend_rbf_valid(const void *p);
|
||||
|
||||
/* WIRE: DUALOPEND_COMMIT_RCVD */
|
||||
/* dualopend->master: ready to commit channel open to database and */
|
||||
/* get some signatures for the funding_tx. */
|
||||
@ -209,4 +223,4 @@ bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak);
|
||||
|
||||
|
||||
#endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */
|
||||
// SHA256STAMP:65a94b9b35802a6cd6c68f724e83ce4866adb3122a392d6741ec7c791ef1fd6c
|
||||
// SHA256STAMP:e514a16cf96dfcaf44217cf344ce75e2b8cbcb460901c610d9b75e22937636cd
|
||||
|
Loading…
Reference in New Issue
Block a user