-
Notifications
You must be signed in to change notification settings - Fork 901
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DB: Store the signatures of channel announcement sent from remote peer into DB #2619
Conversation
channeld/channeld.c
Outdated
type_to_string(peer, struct short_channel_id, | ||
remote_scid)); | ||
|
||
/* make sure new node signature and bitcoin signature equal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we just check that the signature is valid? Signatures change when re-signing (using different k value).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! You're right, and there shouldn't compare with the old sigs if the remote generate new sigs. Gossipd will verify the announcement, so I think we'd better update the new sigs here.
I think it would be nice to have some sort of (py)test to test the functionality. Also to get more clarity on what kind of behavior we actually want/expect. Related questions:
|
@SimonVrouwe I think the point is we want to get into the phase of announcement from the phase of waiting for remote signatures more quickly. |
eec96b9
to
55cca59
Compare
@SimonVrouwe Sorry. I find another change for the current PR: when we reenable the channel, we directly announce with the old sigs meanwhile sending remote peer our sigs. So we will announce once again when we receive the announcement reply. |
@cdecker hi, what do you think of these two ways? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quite a nice pull request, congratulation 👍 I went through and I found a
few pieces that are a bit strange though (some are a bit pedantic I'll admit
😉). In particular there are a few places where you are over-checking
(signatures may change, scids may also change), and the last commit is a bit
too much sync that was likely caused by trying to only send the signatures
once. Please remove the reply in the last commit, and relax some of the checks.
Minor comments:
WIRE_CHANNEL_GOT_ANNOUNCEMENT
is introduced in the first commit, but never
handled. This breaks rebaseability (each commit must compile on its own).- The same applies to commit 71dcf4b which
changes the signature ofnew_channel
but doesn't fix the callers.
lightningd/channel.c
Outdated
const u8 *remote_upfront_shutdown_script) | ||
const u8 *remote_upfront_shutdown_script, | ||
secp256k1_ecdsa_signature *remote_ann_node_sig, | ||
secp256k1_ecdsa_signature *remote_ann_bitcoin_sig) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rustyrussell should these be marked as TAKES
if we tal_steal
them below? I can never remember the semantics of TAKES
😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find we marked as TAKES
if we tal_dup
, and there's some similar cases in this function:
we didn't marked scid
, last_tx
, last_sent_commit
as TAKES
and we tal_steal them below,
but we marked transient_billboard
as TAKES
because we tal_strdup
it below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rusty replied me that tal_steal
doesn't need to be marked as TAKES
, and tal_dup
can be marked :)
wallet/db.c
Outdated
{ "ALTER TABLE forwarded_payments ADD resolved_time INTEGER", NULL }, | ||
{ "ALTER TABLE channel_htlcs ADD received_time INTEGER;", NULL }, | ||
{ "ALTER TABLE forwarded_payments ADD received_time INTEGER;", NULL }, | ||
{ "ALTER TABLE forwarded_payments ADD resolved_time INTEGER;", NULL }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't modify existing migrations. While this change may be harmless cosmetics, changing the migrations may end up corrupting deployed databases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I'll take care, too
lightningd/channel_control.c
Outdated
secp256k1_ecdsa_signature *remote_ann_bitcoin_sig; | ||
|
||
remote_ann_node_sig = tal(tmpctx, secp256k1_ecdsa_signature); | ||
remote_ann_bitcoin_sig = tal(tmpctx, secp256k1_ecdsa_signature); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can allocate them directly off of channel
if you tal_free
them on error as well (which should be rare anyway).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, now I don't allocate them directly.
lightningd/channel.h
Outdated
|
||
/* channel announcement sigs info from remote peer*/ | ||
secp256k1_ecdsa_signature *remote_ann_node_sig; | ||
secp256k1_ecdsa_signature *remote_ann_bitcoin_sig; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we keeping these in memory at all? We could just as well load them on demand when a new channeld
gets started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I replace it by a new load function, which is only called when we generate a channel_init message.
lightningd/channel_control.c
Outdated
* In this case, master may receive announcement more than once! | ||
*/ | ||
tal_free(channel->remote_ann_node_sig); | ||
tal_free(channel->remote_ann_bitcoin_sig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the master was shut down we're dead as well. No need to handle that case here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'll remove it.
@cdecker Sincerely thank you! I'll correct these days. Many points, detials to learn and I hope I can do better next time :) |
983414d
to
43e47fb
Compare
Hi, @cdecker I've correct the code. What do you think about it now? :-) |
43e47fb
to
08a5721
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent pull request @trueptolemy, I went through with a fine-toothed comb and commented all the minor things that came to mind.
@@ -595,6 +595,42 @@ wallet_htlc_sigs_load(const tal_t *ctx, struct wallet *w, u64 channelid) | |||
return htlc_sigs; | |||
} | |||
|
|||
bool wallet_remote_ann_sigs_load(struct wallet *w, u64 id, | |||
secp256k1_ecdsa_signature **remote_ann_node_sig, | |||
secp256k1_ecdsa_signature **remote_ann_bitcoin_sig) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are passing a pointer-to-pointer-of-sugnature we should also be in charge of allocating the signature, otherwise we need to allocate outside of the call, keep an alias, call the function and then free the alias in case of a failure. If however we allocate internally then the pointer will get populated correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Now I manage the allocation in this func!
wallet/wallet.c
Outdated
|
||
if (sqlite3_column_type(stmt, 0) != SQLITE_NULL) { | ||
if (!sqlite3_column_signature(stmt, 0, *remote_ann_node_sig)) { | ||
db_stmt_done(stmt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other parts of the code we use a fail:
label to clear and return if we have multiple similar failure paths in a single function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, now I use fail:
wallet/wallet.c
Outdated
@@ -1086,6 +1141,16 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) | |||
sqlite3_bind_null(stmt, 1); | |||
sqlite3_bind_int64(stmt, 2, chan->dbid); | |||
db_exec_prepared(w->db, stmt); | |||
|
|||
/* save announcement sigs only when we ge announcement*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ge
-> get
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also these fields ought to be initialized to null
anyway in the DB, so no need to do this additional initialization.
* @w: wallet containing the channel | ||
* @id: channel database id | ||
* @remote_ann_node_sig: location to load remote_ann_node_sig to | ||
* @remote_ann_bitcoin_sig: location to load remote_ann_bitcoin_sig to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like mentioned above, with this signature I would have expected the function to allocate the signatures on the heap. But in that case we're missing a ctx
to allocate from.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Now I add it.
lightningd/channel_control.c
Outdated
if(!(channel->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL)) { | ||
channel_internal_error(channel, | ||
"No ANNOUNCE flag, no announcemnt signatures! %s", | ||
tal_hex(tmpctx, msg)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check, while correct, may be a bit aggressive in the current network and might result in a lot of failures (nodes usually just spray you with the signatures without checking the announcement flags). We can still enforce that we don't announce by simply not sending sigs ourselves.
Please don't fail the channel over such a minor offence, but log it and we can tighten this later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Now I remove this check
channeld/channeld.c
Outdated
peer->have_sigs[REMOTE] = true; | ||
|
||
tal_steal(tmpctx, remote_ann_node_sig); | ||
tal_steal(tmpctx, remote_ann_bitcoin_sig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you stealing these onto tmpctx
? You could also pass the pointers to peer->announcement_node_sigs[REMOTE]
and peer->announcement_bitcoin_sigs[REMOTE]
into the fromwire_channel_init
call directly, which avoids having these temp variables and having to deal with intermediate allocations and ownership.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I find these tal_steal are extra. But I think fromwire_channel_init
needs these 2 pointer, because they can handle NULL
sigs:
channel_init,,remote_ann_node_sig,?secp256k1_ecdsa_signature
channel_init,,remote_ann_bitcoin_sig,?secp256k1_ecdsa_signature
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emm, after deleting tal_steal
,Travis CI tell me memory leak. So I tal_free
these directly.(I find other variables used in fromwire_channel_init
are freed directly, so I also do it.)
lightningd/channel_control.c
Outdated
secp256k1_ecdsa_signature *remote_ann_node_sig, *remote_ann_bitcoin_sig; | ||
|
||
remote_ann_node_sig = tal(tmpctx, secp256k1_ecdsa_signature); | ||
remote_ann_bitcoin_sig = tal(tmpctx, secp256k1_ecdsa_signature); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the weird ownership I was talking about before. Please have wallet_remote_ann_sigs_load
manage allocations. The only reason we aren't producing a memory leak here is that tmpctx
and all child allocations is cleared in the io_loop
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much! Now I pass ctx
to wallet_remote_ann_sigs_load
and let it manage allocations.
ab2371d
to
4bf51a3
Compare
|
||
fail: | ||
*remote_ann_node_sig = tal_free(*remote_ann_node_sig); | ||
*remote_ann_bitcoin_sig = tal_free(*remote_ann_bitcoin_sig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can easily lead to a double-free or freeing a random memory location since we do not allocate in all cases. It'd be better to check both fields for SQLITE_NULL
at the top, and set the out-args to NULL
and return immediately if either is SQLITE_NULL
. If both are not SQLITE_NULL
initialized both using tal
and then goto fail;
if either of the sqlite3_column_signature
calls fails. That way we either initialize all or none, and free only when both are actually initialized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! What you said is better, kinds of cases make sense easily.
4bf51a3
to
a8b927a
Compare
1. Add the fields of remote channel announcement signatures into TABLE channels 2. Add the related function
Channeld sends announcement signatures to Master by this message. When Channeld receive a new channel announcement msg, (After channel locking)it will sends announcement signatures to Master by this message.
1. Add remote_ann_node_sigs and remote_bitcoin_sigs fields in channel_init message; 2. Master add announcement signatures into channel_init message, and send this message to Channeld. Channeld will initial the channel with this signatures when it reenables the channel.
a8b927a
to
e884bc6
Compare
ACK e884bc6 |
Fixes #2409
Here I add a new wire type:
channel_got_announcement (1017)
When Channeld receives the remote channel announcement signatures, it will generate a msg1 like:
WIRE_CHANNEL_GOT_ANNOUNCEMENT + remote_ann_node_sig + remote_ann_bitcoin_sig
and send this msg to Master. (After sending signatures, Channeld will be holding until receive the reply from Master.)
Master resolves msg and stores the signatures into DB.
Like issue #2409 , the adventage is when we reenable our channel, you can init it with the remote announcement signatures from DB directly other than wasting your time to wait for remote peer's announce reply.