Skip to content

Commit cefb692

Browse files
rustyrussellcdecker
authored andcommitted
db: save and restore last_sent_commit correctly.
It's an array: we were only saving the single element; if there was more than one changed HTLC we'd get a bad signature! The report in #1907 is probably caused by the other side re-requesting something we considered already finalized; to avoid this particular error, we should set the field to NULL if there's no last_sent_commit. I'm increasingly of the opinion we want to just save all the update packets to the db and blast them out, instead of doing this second-guessing dance. Fixes: #1907 Signed-off-by: Rusty Russell <[email protected]>
1 parent db12a14 commit cefb692

File tree

6 files changed

+48
-23
lines changed

6 files changed

+48
-23
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ endif
3535

3636
ifeq ($(COMPAT),1)
3737
# We support compatibility with pre-0.6.
38-
COMPAT_CFLAGS=-DCOMPAT_V052=1
38+
COMPAT_CFLAGS=-DCOMPAT_V052=1 -DCOMPAT_V060=1
3939
endif
4040

4141
PYTEST_OPTS := -v -x

tests/test_connection.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1297,7 +1297,6 @@ def test_dataloss_protection(node_factory, bitcoind):
12971297
assert (closetxid, "confirmed") in set([(o['txid'], o['status']) for o in l2.rpc.listfunds()['outputs']])
12981298

12991299

1300-
@pytest.mark.xfail(strict=True)
13011300
@unittest.skipIf(not DEVELOPER, "needs dev_disconnect")
13021301
def test_restart_multi_htlc_rexmit(node_factory, bitcoind, executor):
13031302
# l1 disables commit timer once we send first htlc, dies on commit

wallet/db.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ char *dbmigrations[] = {
337337
"ALTER TABLE payments ADD description TEXT;",
338338
/* future_per_commitment_point if other side proves we're out of date -- */
339339
"ALTER TABLE channels ADD future_per_commitment_point BLOB;",
340+
/* last_sent_commit array fix */
341+
"ALTER TABLE channels ADD last_sent_commit BLOB;",
340342
NULL,
341343
};
342344

wallet/test/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ WALLET_TEST_COMMON_OBJS := \
66
common/base32.o \
77
common/derive_basepoints.o \
88
common/htlc_state.o \
9+
common/htlc_wire.o \
910
common/type_to_string.o \
1011
common/memleak.o \
1112
common/key_derive.o \

wallet/test/run-wallet.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -747,9 +747,10 @@ static bool channelseq(struct channel *c1, struct channel *c2)
747747

748748
CHECK(c1->our_config.id != 0 && c1->our_config.id == c2->our_config.id);
749749
CHECK((lc1 != NULL) == (lc2 != NULL));
750-
if(lc1) {
751-
CHECK(lc1->newstate == lc2->newstate);
752-
CHECK(lc1->id == lc2->id);
750+
CHECK(tal_count(lc1) == tal_count(lc2));
751+
for (size_t i = 0; i < tal_count(lc1); i++) {
752+
CHECK(lc1[i].newstate == lc2[i].newstate);
753+
CHECK(lc1[i].id == lc2[i].id);
753754
}
754755

755756
CHECK((c1->last_tx != NULL) == (c2->last_tx != NULL));
@@ -795,7 +796,7 @@ static bool test_channel_crud(struct lightningd *ld, const tal_t *ctx)
795796
struct channel_info *ci = &c1.channel_info;
796797
struct bitcoin_txid *hash = tal(w, struct bitcoin_txid);
797798
struct pubkey pk;
798-
struct changed_htlc last_commit;
799+
struct changed_htlc *last_commit;
799800
secp256k1_ecdsa_signature *sig = tal(w, secp256k1_ecdsa_signature);
800801
u8 *scriptpubkey = tal_arr(ctx, u8, 100);
801802

@@ -804,7 +805,8 @@ static bool test_channel_crud(struct lightningd *ld, const tal_t *ctx)
804805
memset(ci, 3, sizeof(*ci));
805806
mempat(hash, sizeof(*hash));
806807
mempat(sig, sizeof(*sig));
807-
mempat(&last_commit, sizeof(last_commit));
808+
last_commit = tal_arr(w, struct changed_htlc, 2);
809+
mempat(last_commit, tal_bytelen(last_commit));
808810
pubkey_from_der(tal_hexdata(w, "02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc", 66), 33, &pk);
809811
ci->feerate_per_kw[LOCAL] = ci->feerate_per_kw[REMOTE] = 31337;
810812
mempat(scriptpubkey, tal_count(scriptpubkey));
@@ -864,7 +866,7 @@ static bool test_channel_crud(struct lightningd *ld, const tal_t *ctx)
864866
CHECK(c1.their_shachain.id == 1);
865867

866868
/* Variant 3: update with last_commit_sent */
867-
c1.last_sent_commit = &last_commit;
869+
c1.last_sent_commit = last_commit;
868870
wallet_channel_save(w, &c1);
869871
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", wallet_err));
870872
CHECK_MSG(c2 = wallet_channel_load(w, c1.dbid), tal_fmt(w, "Load from DB"));

wallet/wallet.c

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -609,13 +609,26 @@ static struct channel *wallet_stmt2channel(const tal_t *ctx, struct wallet *w, s
609609
remote_shutdown_scriptpubkey = sqlite3_column_arr(tmpctx, stmt, 28, u8);
610610

611611
/* Do we have a last_sent_commit, if yes, populate */
612-
if (sqlite3_column_type(stmt, 30) != SQLITE_NULL) {
612+
if (sqlite3_column_type(stmt, 41) != SQLITE_NULL) {
613+
const u8 *cursor = sqlite3_column_blob(stmt, 41);
614+
size_t len = sqlite3_column_bytes(stmt, 41);
615+
size_t n = 0;
616+
last_sent_commit = tal_arr(tmpctx, struct changed_htlc, n);
617+
while (len) {
618+
tal_resize(&last_sent_commit, n+1);
619+
fromwire_changed_htlc(&cursor, &len,
620+
&last_sent_commit[n++]);
621+
}
622+
} else
623+
last_sent_commit = NULL;
624+
625+
#ifdef COMPAT_V060
626+
if (!last_sent_commit && sqlite3_column_type(stmt, 30) != SQLITE_NULL) {
613627
last_sent_commit = tal(tmpctx, struct changed_htlc);
614628
last_sent_commit->newstate = sqlite3_column_int64(stmt, 30);
615629
last_sent_commit->id = sqlite3_column_int64(stmt, 31);
616-
} else {
617-
last_sent_commit = NULL;
618630
}
631+
#endif
619632

620633
if (sqlite3_column_type(stmt, 40) != SQLITE_NULL) {
621634
future_per_commitment_point = tal(tmpctx, struct pubkey);
@@ -715,7 +728,8 @@ static const char *channel_fields =
715728
/*30*/ "last_sent_commit_state, last_sent_commit_id, "
716729
/*32*/ "last_tx, last_sig, last_was_revoke, first_blocknum, "
717730
/*36*/ "min_possible_feerate, max_possible_feerate, "
718-
/*38*/ "msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point ";
731+
/*38*/ "msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, "
732+
/*41*/ "last_sent_commit";
719733

720734
bool wallet_channels_load_active(const tal_t *ctx, struct wallet *w)
721735
{
@@ -893,6 +907,7 @@ u64 wallet_get_channel_dbid(struct wallet *wallet)
893907
void wallet_channel_save(struct wallet *w, struct channel *chan)
894908
{
895909
sqlite3_stmt *stmt;
910+
u8 *last_sent_commit;
896911
assert(chan->first_blocknum);
897912

898913
wallet_channel_config_save(w, &chan->our_config);
@@ -996,17 +1011,23 @@ void wallet_channel_save(struct wallet *w, struct channel *chan)
9961011
db_exec_prepared(w->db, stmt);
9971012

9981013
/* If we have a last_sent_commit, store it */
999-
if (chan->last_sent_commit) {
1000-
stmt = db_prepare(w->db,
1001-
"UPDATE channels SET"
1002-
" last_sent_commit_state=?,"
1003-
" last_sent_commit_id=?"
1004-
" WHERE id=?");
1005-
sqlite3_bind_int(stmt, 1, chan->last_sent_commit->newstate);
1006-
sqlite3_bind_int64(stmt, 2, chan->last_sent_commit->id);
1007-
sqlite3_bind_int64(stmt, 3, chan->dbid);
1008-
db_exec_prepared(w->db, stmt);
1009-
}
1014+
last_sent_commit = tal_arr(tmpctx, u8, 0);
1015+
for (size_t i = 0; i < tal_count(chan->last_sent_commit); i++)
1016+
towire_changed_htlc(&last_sent_commit,
1017+
&chan->last_sent_commit[i]);
1018+
1019+
stmt = db_prepare(w->db,
1020+
"UPDATE channels SET"
1021+
" last_sent_commit=?"
1022+
" WHERE id=?");
1023+
if (tal_count(last_sent_commit))
1024+
sqlite3_bind_blob(stmt, 1,
1025+
last_sent_commit, tal_count(last_sent_commit),
1026+
SQLITE_TRANSIENT);
1027+
else
1028+
sqlite3_bind_null(stmt, 1);
1029+
sqlite3_bind_int64(stmt, 2, chan->dbid);
1030+
db_exec_prepared(w->db, stmt);
10101031
}
10111032

10121033
void wallet_channel_insert(struct wallet *w, struct channel *chan)

0 commit comments

Comments
 (0)