diff --git a/db/bindings.c b/db/bindings.c index be1cf14a6..e8b83785b 100644 --- a/db/bindings.c +++ b/db/bindings.c @@ -601,6 +601,18 @@ struct secret *db_col_secret_arr(const tal_t *ctx, return db_col_arr(ctx, stmt, colname, struct secret); } +struct wireaddr *db_col_wireaddr(const tal_t *ctx, + struct db_stmt *stmt, + const char *colname) +{ + struct wireaddr *waddr = tal(ctx, struct wireaddr); + const u8 *wire = db_col_arr(tmpctx, stmt, colname, u8); + size_t len = tal_bytelen(wire); + if (!fromwire_wireaddr(&wire, &len, waddr)) + return tal_free(waddr); + return waddr; +} + void db_col_txid(struct db_stmt *stmt, const char *colname, struct bitcoin_txid *t) { db_col_sha256d(stmt, colname, &t->shad); diff --git a/db/bindings.h b/db/bindings.h index e78e45868..c4cbe707d 100644 --- a/db/bindings.h +++ b/db/bindings.h @@ -103,6 +103,9 @@ struct bitcoin_tx *db_col_psbt_to_tx(const tal_t *ctx, struct db_stmt *stmt, con struct onionreply *db_col_onionreply(const tal_t *ctx, struct db_stmt *stmt, const char *colname); +struct wireaddr *db_col_wireaddr(const tal_t *ctx, + struct db_stmt *stmt, + const char *colname); #define db_col_arr(ctx, stmt, colname, type) \ ((type *)db_col_arr_((ctx), (stmt), (colname), \ diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index e8b6168fd..3dd2e028f 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1496,6 +1496,7 @@ static struct channel *stub_chan(struct command *cmd, &nodeid, &wint, NULL, + NULL, false); } diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index d80f98e50..07641ae83 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -91,6 +91,7 @@ void peer_set_dbid(struct peer *peer, u64 dbid) struct peer *new_peer(struct lightningd *ld, u64 dbid, const struct node_id *id, const struct wireaddr_internal *addr, + const struct wireaddr *last_known_addr, const u8 *their_features, bool connected_incoming) { @@ -102,6 +103,7 @@ struct peer *new_peer(struct lightningd *ld, u64 dbid, peer->id = *id; peer->uncommitted_channel = NULL; peer->addr = *addr; + peer->last_known_addr = tal_dup_or_null(peer, struct wireaddr, last_known_addr); peer->connected_incoming = connected_incoming; peer->remote_addr = NULL; list_head_init(&peer->channels); @@ -1673,6 +1675,7 @@ void peer_connected(struct lightningd *ld, const u8 *msg) struct peer_connected_hook_payload *hook_payload; u64 connectd_counter; const char *cmd_id; + struct wireaddr *last_known_addr; hook_payload = tal(NULL, struct peer_connected_hook_payload); hook_payload->ld = ld; @@ -1691,15 +1694,31 @@ void peer_connected(struct lightningd *ld, const u8 *msg) * now it's reconnected, we've gotta force them out. */ peer_channels_cleanup(ld, &id); + /* If we connected, and it's a normal address */ + if (!hook_payload->incoming + && hook_payload->addr.itype == ADDR_INTERNAL_WIREADDR + && !hook_payload->addr.u.wireaddr.is_websocket) { + last_known_addr = &hook_payload->addr.u.wireaddr.wireaddr; + } else { + last_known_addr = NULL; + } + /* If we're already dealing with this peer, hand off to correct * subdaemon. Otherwise, we'll hand to openingd to wait there. */ peer = peer_by_id(ld, &id); - if (!peer) + if (!peer) { + /* If we connected to them, we know this is a good address. */ peer = new_peer(ld, 0, &id, &hook_payload->addr, + last_known_addr, take(their_features), hook_payload->incoming); - else { + } else { tal_free(peer->their_features); peer->their_features = tal_steal(peer, their_features); + + /* Update known address. */ + tal_free(peer->last_known_addr); + peer->last_known_addr = tal_dup_or_null(peer, struct wireaddr, + last_known_addr); } /* We track this, because messages can race between connectd and us. diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index face71198..c8015cbad 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -53,6 +53,9 @@ struct peer { struct wireaddr_internal addr; bool connected_incoming; + /* If we ever successfully connected out to an address, this is non-NULL */ + struct wireaddr *last_known_addr; + /* They send what they see as our address as remote_addr */ struct wireaddr *remote_addr; @@ -71,6 +74,7 @@ struct peer *find_peer_by_dbid(struct lightningd *ld, u64 dbid); struct peer *new_peer(struct lightningd *ld, u64 dbid, const struct node_id *id, const struct wireaddr_internal *addr, + const struct wireaddr *last_known_addr, const u8 *their_features TAKES, bool connected_incoming); diff --git a/plugins/bkpr/test/run-bkpr_db.c b/plugins/bkpr/test/run-bkpr_db.c index 308110548..91d4e0271 100644 --- a/plugins/bkpr/test/run-bkpr_db.c +++ b/plugins/bkpr/test/run-bkpr_db.c @@ -92,6 +92,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } +/* Generated stub for fromwire_wireaddr */ +bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) +{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } /* Generated stub for fromwire_wirestring */ char *fromwire_wirestring(const tal_t *ctx UNNEEDED, const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_wirestring called!\n"); abort(); } diff --git a/plugins/bkpr/test/run-recorder.c b/plugins/bkpr/test/run-recorder.c index 85c901200..25774f44b 100644 --- a/plugins/bkpr/test/run-recorder.c +++ b/plugins/bkpr/test/run-recorder.c @@ -98,6 +98,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } +/* Generated stub for fromwire_wireaddr */ +bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) +{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } /* Generated stub for fromwire_wirestring */ char *fromwire_wirestring(const tal_t *ctx UNNEEDED, const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_wirestring called!\n"); abort(); } diff --git a/wallet/db.c b/wallet/db.c index 161d67c44..963e8c535 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -1028,6 +1028,7 @@ static struct migration dbmigrations[] = { " addrtype INTEGER)"), NULL}, {NULL, insert_addrtype_to_addresses}, {SQL("ALTER TABLE channel_funding_inflights ADD remote_funding BLOB DEFAULT NULL;"), NULL}, + {SQL("ALTER TABLE peers ADD last_known_address BLOB DEFAULT NULL;"), NULL}, }; /** diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index cb346dba1..824b9197e 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -239,6 +239,7 @@ struct logger *new_logger(const tal_t *ctx UNNEEDED, struct log_book *record UNN struct peer *new_peer(struct lightningd *ld UNNEEDED, u64 dbid UNNEEDED, const struct node_id *id UNNEEDED, const struct wireaddr_internal *addr UNNEEDED, + const struct wireaddr *last_known_addr UNNEEDED, const u8 *their_features TAKES UNNEEDED, bool connected_incoming UNNEEDED) { fprintf(stderr, "new_peer called!\n"); abort(); } diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index e21585083..091b0d4e6 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1441,7 +1441,7 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) /* Add another utxo that's CSV-locked for 5 blocks */ assert(parse_wireaddr_internal(tmpctx, "localhost:1234", 0, false, &addr) == NULL); - channel.peer = new_peer(ld, 0, &id, &addr, NULL, false); + channel.peer = new_peer(ld, 0, &id, &addr, NULL, NULL, false); channel.dbid = 1; channel.type = channel_type_anchors_zero_fee_htlc(tmpctx); memset(&u.outpoint, 3, sizeof(u.outpoint)); @@ -1767,7 +1767,7 @@ static bool test_channel_crud(struct lightningd *ld, const tal_t *ctx) c1.first_blocknum = 1; assert(parse_wireaddr_internal(tmpctx, "localhost:1234", 0, false, &addr) == NULL); c1.final_key_idx = 1337; - p = new_peer(ld, 0, &id, &addr, NULL, false); + p = new_peer(ld, 0, &id, &addr, NULL, NULL, false); c1.peer = p; c1.dbid = wallet_get_channel_dbid(w); c1.state = CHANNELD_NORMAL; @@ -1935,7 +1935,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) assert(parse_wireaddr_internal(tmpctx, "localhost:1234", 0, false, &addr) == NULL); /* new channel! */ - p = new_peer(ld, 0, &id, &addr, NULL, false); + p = new_peer(ld, 0, &id, &addr, NULL, NULL, false); funding_sats = AMOUNT_SAT(4444444); our_sats = AMOUNT_SAT(3333333); diff --git a/wallet/wallet.c b/wallet/wallet.c index cb79c32cc..bba5479f0 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1011,10 +1011,11 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid) struct peer *peer = NULL; struct node_id id; struct wireaddr_internal addr; + struct wireaddr *last_known_addr; struct db_stmt *stmt; stmt = db_prepare_v2( - w->db, SQL("SELECT id, node_id, address, feature_bits FROM peers WHERE id=?;")); + w->db, SQL("SELECT id, node_id, address, feature_bits, last_known_address FROM peers WHERE id=?;")); db_bind_u64(stmt, dbid); db_query_prepared(stmt); @@ -1025,6 +1026,7 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid) db_col_ignore(stmt, "address"); db_col_ignore(stmt, "id"); db_col_ignore(stmt, "feature_bits"); + db_col_ignore(stmt, "last_known_address"); goto done; } @@ -1041,8 +1043,18 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid) assert(!err); } - /* FIXME: save incoming in db! */ - peer = new_peer(w->ld, db_col_u64(stmt, "id"), &id, &addr, db_col_arr(stmt, stmt, "feature_bits", u8), false); + if (db_col_is_null(stmt, "last_known_address")) { + last_known_addr = NULL; + } else { + last_known_addr = db_col_wireaddr(tmpctx, stmt, "last_known_address"); + if (!last_known_addr) { + log_broken(w->log, "Unparsable lastknown address %s: ignoring", + tal_hex(tmpctx, db_col_arr(tmpctx, stmt, "last_known_address", u8))); + } + } + + peer = new_peer(w->ld, db_col_u64(stmt, "id"), &id, &addr, last_known_addr, + db_col_arr(stmt, stmt, "feature_bits", u8), false); done: tal_free(stmt); @@ -2583,6 +2595,16 @@ static void wallet_peer_save(struct wallet *w, struct peer *peer) db_exec_prepared_v2(stmt); peer_set_dbid(peer, db_last_insert_id_v2(take(stmt))); } + + if (peer->last_known_addr) { + u8 *wire = tal_arr(tmpctx, u8, 0); + towire_wireaddr(&wire, peer->last_known_addr); + stmt = db_prepare_v2(w->db, + SQL("UPDATE peers SET last_known_address = ? WHERE id = ?;")); + db_bind_talarr(stmt, wire); + db_bind_u64(stmt, peer->dbid); + db_exec_prepared_v2(take(stmt)); + } } bool channel_exists_by_id(struct wallet *w, u64 dbid) {