Skip to content

Commit 8c9e3a3

Browse files
committed
lightningd: keep indexes updated for channel_htlcs table (aka listhtlcs).
Signed-off-by: Rusty Russell <[email protected]>
1 parent 733b03b commit 8c9e3a3

File tree

10 files changed

+230
-45
lines changed

10 files changed

+230
-45
lines changed

cln-grpc/proto/node.proto

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contrib/pyln-grpc-proto/pyln/grpc/node_pb2.py

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lightningd/channel.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ void delete_channel(struct channel *channel STEALS)
9494

9595
struct peer *peer = channel->peer;
9696
if (channel->dbid != 0)
97-
wallet_channel_close(channel->peer->ld->wallet, channel->dbid);
97+
wallet_channel_close(channel->peer->ld->wallet, channel);
9898

9999
/* Tell the hsm to forget the channel, needs to be after it's
100100
* been forgotten here */

lightningd/peer_htlcs.c

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,13 @@ static bool htlc_in_update_state(struct channel *channel,
6767
max_unsigned(channel->next_index[LOCAL],
6868
channel->next_index[REMOTE]),
6969
hin->badonion, hin->failonion, NULL,
70-
hin->we_filled);
70+
hin->we_filled,
71+
hin->key.id,
72+
hin->key.channel,
73+
REMOTE,
74+
&hin->payment_hash,
75+
hin->cltv_expiry,
76+
hin->msat);
7177

7278
hin->hstate = newstate;
7379
return true;
@@ -87,7 +93,13 @@ static bool htlc_out_update_state(struct channel *channel,
8793
max_unsigned(channel->next_index[LOCAL],
8894
channel->next_index[REMOTE]),
8995
0, hout->failonion,
90-
hout->failmsg, &we_filled);
96+
hout->failmsg, &we_filled,
97+
hout->key.id,
98+
hout->key.channel,
99+
LOCAL,
100+
&hout->payment_hash,
101+
hout->cltv_expiry,
102+
hout->msat);
91103

92104
hout->hstate = newstate;
93105
return true;
@@ -234,7 +246,13 @@ static void fail_in_htlc(struct htlc_in *hin,
234246
max_unsigned(hin->key.channel->next_index[LOCAL],
235247
hin->key.channel->next_index[REMOTE]),
236248
hin->badonion,
237-
hin->failonion, NULL, &we_filled);
249+
hin->failonion, NULL, &we_filled,
250+
hin->key.id,
251+
hin->key.channel,
252+
REMOTE,
253+
&hin->payment_hash,
254+
hin->cltv_expiry,
255+
hin->msat);
238256

239257
tell_channeld_htlc_failed(hin, failed_htlc);
240258
}
@@ -1500,7 +1518,14 @@ static void fulfill_our_htlc_out(struct channel *channel, struct htlc_out *hout,
15001518
max_unsigned(channel->next_index[LOCAL],
15011519
channel->next_index[REMOTE]),
15021520
0, hout->failonion,
1503-
hout->failmsg, &we_filled);
1521+
hout->failmsg, &we_filled,
1522+
hout->key.id,
1523+
hout->key.channel,
1524+
LOCAL,
1525+
&hout->payment_hash,
1526+
hout->cltv_expiry,
1527+
hout->msat);
1528+
15041529
/* Update channel stats */
15051530
channel_stats_incr_out_fulfilled(channel, hout->msat);
15061531

@@ -1796,7 +1821,13 @@ void onchain_failed_our_htlc(const struct channel *channel,
17961821
max_unsigned(channel->next_index[LOCAL],
17971822
channel->next_index[REMOTE]),
17981823
0, hout->failonion,
1799-
hout->failmsg, &we_filled);
1824+
hout->failmsg, &we_filled,
1825+
hout->key.id,
1826+
hout->key.channel,
1827+
LOCAL,
1828+
&hout->payment_hash,
1829+
hout->cltv_expiry,
1830+
hout->msat);
18001831

18011832
if (hout->am_origin) {
18021833
log_debug(channel->log, "HTLC id %"PRIu64" am origin",

lightningd/test/run-invoice-select-inchan.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -907,10 +907,6 @@ bool peer_start_channeld(struct channel *channel UNNEEDED,
907907
bool reconnected UNNEEDED,
908908
bool reestablish_only UNNEEDED)
909909
{ fprintf(stderr, "peer_start_channeld called!\n"); abort(); }
910-
/* Generated stub for peer_start_closingd */
911-
void peer_start_closingd(struct channel *channel UNNEEDED,
912-
struct peer_fd *peer_fd UNNEEDED)
913-
{ fprintf(stderr, "peer_start_closingd called!\n"); abort(); }
914910
/* Generated stub for peer_start_dualopend */
915911
bool peer_start_dualopend(struct peer *peer UNNEEDED, struct peer_fd *peer_fd UNNEEDED,
916912
struct channel *channel UNNEEDED)

tests/test_misc.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3424,6 +3424,85 @@ def test_listforwards_wait(node_factory, executor):
34243424
'status': 'failed'}}
34253425

34263426

3427+
def test_listhtlcs_wait(node_factory, bitcoind, executor):
3428+
l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True)
3429+
3430+
scid12 = first_scid(l1, l2)
3431+
scid23 = first_scid(l2, l3)
3432+
waitres = l1.rpc.wait(subsystem='htlcs', indexname='created', nextvalue=0)
3433+
assert waitres == {'subsystem': 'htlcs',
3434+
'created': 0}
3435+
3436+
# Now ask for 1.
3437+
waitcreate = executor.submit(l2.rpc.wait, subsystem='htlcs', indexname='created', nextvalue=1)
3438+
waitupdate = executor.submit(l2.rpc.wait, subsystem='htlcs', indexname='updated', nextvalue=1)
3439+
time.sleep(1)
3440+
3441+
amt1 = 1000
3442+
inv1 = l3.rpc.invoice(amt1, 'inv1', 'desc')
3443+
l1.rpc.pay(inv1['bolt11'])
3444+
3445+
waitres = waitcreate.result(TIMEOUT)
3446+
assert waitres == {'subsystem': 'htlcs',
3447+
'created': 1,
3448+
'details': {'short_channel_id': scid12,
3449+
'cltv_expiry': 120,
3450+
'direction': 'in',
3451+
'htlc_id': 0,
3452+
'payment_hash': inv1['payment_hash'],
3453+
'amount_msat': amt1 + 1,
3454+
'state': 'RCVD_ADD_COMMIT'}}
3455+
waitres = waitupdate.result(TIMEOUT)
3456+
assert waitres == {'subsystem': 'htlcs',
3457+
'updated': 1,
3458+
'details': {'short_channel_id': scid12,
3459+
'cltv_expiry': 120,
3460+
'direction': 'in',
3461+
'htlc_id': 0,
3462+
'payment_hash': inv1['payment_hash'],
3463+
'amount_msat': amt1 + 1,
3464+
'state': 'SENT_ADD_REVOCATION'}}
3465+
3466+
# There's a second new one too, for the outgoing, but we missed details
3467+
assert l2.rpc.wait(subsystem='htlcs', indexname='created', nextvalue=2) == {'created': 2, 'subsystem': 'htlcs'}
3468+
3469+
# Now check failure, and wait for OUTGOING.
3470+
amt2 = 42
3471+
inv2 = l3.rpc.invoice(amt2, 'inv2', 'invdesc2')
3472+
l3.rpc.delinvoice('inv2', 'unpaid')
3473+
3474+
waitcreate = executor.submit(l2.rpc.wait, subsystem='htlcs', indexname='created', nextvalue=4)
3475+
time.sleep(1)
3476+
3477+
with pytest.raises(RpcError, match="WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS"):
3478+
l1.rpc.pay(inv2['bolt11'])
3479+
3480+
waitres = waitcreate.result(TIMEOUT)
3481+
assert waitres == {'subsystem': 'htlcs',
3482+
'created': 4,
3483+
'details': {'short_channel_id': scid23,
3484+
'cltv_expiry': 114,
3485+
'direction': 'out',
3486+
'htlc_id': 1,
3487+
'payment_hash': inv2['payment_hash'],
3488+
'amount_msat': amt2,
3489+
'state': 'SENT_ADD_HTLC'}}
3490+
3491+
# Finally, check deletion (only when channel finally forgotten)
3492+
l1.rpc.close(l2.info['id'])
3493+
3494+
waitfut = executor.submit(l2.rpc.wait, subsystem='htlcs', indexname='deleted', nextvalue=1)
3495+
time.sleep(1)
3496+
3497+
bitcoind.generate_block(100, wait_for_mempool=1)
3498+
3499+
waitres = waitfut.result(TIMEOUT)
3500+
# Both will be deleted at once! We just get told the channel.
3501+
assert waitres == {'subsystem': 'htlcs',
3502+
'deleted': 2,
3503+
'details': {'short_channel_id': scid12}}
3504+
3505+
34273506
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "modifies database, which is assumed sqlite3")
34283507
def test_listforwards_ancient(node_factory, bitcoind):
34293508
"""Test listforwards command with old records."""

wallet/test/run-db.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,31 @@ struct htlc_in *htlc_in_check(const struct htlc_in *hin UNNEEDED, const char *ab
107107
/* Generated stub for htlc_out_connect_htlc_in */
108108
void htlc_out_connect_htlc_in(struct htlc_out *hout UNNEEDED, struct htlc_in *hin UNNEEDED)
109109
{ fprintf(stderr, "htlc_out_connect_htlc_in called!\n"); abort(); }
110+
/* Generated stub for htlcs_index_created */
111+
u64 htlcs_index_created(struct lightningd *ld UNNEEDED,
112+
u64 htlc_id UNNEEDED,
113+
const struct channel *channel UNNEEDED,
114+
const struct sha256 *payment_hash UNNEEDED,
115+
enum side owner UNNEEDED,
116+
u32 expiry UNNEEDED,
117+
struct amount_msat amount UNNEEDED,
118+
enum htlc_state hstate UNNEEDED)
119+
{ fprintf(stderr, "htlcs_index_created called!\n"); abort(); }
120+
/* Generated stub for htlcs_index_deleted */
121+
void htlcs_index_deleted(struct lightningd *ld UNNEEDED,
122+
const struct channel *channel UNNEEDED,
123+
u64 num_deleted UNNEEDED)
124+
{ fprintf(stderr, "htlcs_index_deleted called!\n"); abort(); }
125+
/* Generated stub for htlcs_index_update_status */
126+
u64 htlcs_index_update_status(struct lightningd *ld UNNEEDED,
127+
u64 htlc_id UNNEEDED,
128+
const struct channel *channel UNNEEDED,
129+
const struct sha256 *payment_hash UNNEEDED,
130+
enum side owner UNNEEDED,
131+
u32 expiry UNNEEDED,
132+
struct amount_msat amount UNNEEDED,
133+
enum htlc_state hstate UNNEEDED)
134+
{ fprintf(stderr, "htlcs_index_update_status called!\n"); abort(); }
110135
/* Generated stub for inflight_set_last_tx */
111136
void inflight_set_last_tx(struct channel_inflight *inflight UNNEEDED,
112137
struct bitcoin_tx *last_tx STEALS UNNEEDED,

wallet/test/run-wallet.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -929,10 +929,6 @@ bool peer_start_channeld(struct channel *channel UNNEEDED,
929929
bool reconnected UNNEEDED,
930930
bool reestablish_only UNNEEDED)
931931
{ fprintf(stderr, "peer_start_channeld called!\n"); abort(); }
932-
/* Generated stub for peer_start_closingd */
933-
void peer_start_closingd(struct channel *channel UNNEEDED,
934-
struct peer_fd *peer_fd UNNEEDED)
935-
{ fprintf(stderr, "peer_start_closingd called!\n"); abort(); }
936932
/* Generated stub for peer_start_dualopend */
937933
bool peer_start_dualopend(struct peer *peer UNNEEDED, struct peer_fd *peer_fd UNNEEDED,
938934
struct channel *channel UNNEEDED)
@@ -2170,19 +2166,23 @@ static bool test_htlc_crud(struct lightningd *ld, const tal_t *ctx)
21702166
chan->state = CHANNELD_NORMAL;
21712167
chan->peer = peer;
21722168
chan->next_index[LOCAL] = chan->next_index[REMOTE] = 1;
2169+
chan->scid = tal(chan, struct short_channel_id);
21732170

21742171
memset(&in, 0, sizeof(in));
21752172
memset(&out, 0, sizeof(out));
21762173
memset(&in.payment_hash, 'A', sizeof(struct sha256));
21772174
memset(&out.payment_hash, 'A', sizeof(struct sha256));
21782175
memset(&payment_key, 'B', sizeof(payment_key));
2176+
assert(mk_short_channel_id(chan->scid, 1, 2, 3));
21792177
in.key.id = 42;
21802178
in.key.channel = chan;
2179+
in.cltv_expiry = 42;
21812180
in.msat = AMOUNT_MSAT(42);
21822181

21832182
out.in = &in;
21842183
out.key.id = 1337;
21852184
out.key.channel = chan;
2185+
out.cltv_expiry = 41;
21862186
out.msat = AMOUNT_MSAT(41);
21872187

21882188
/* Store the htlc_in */
@@ -2196,17 +2196,17 @@ static bool test_htlc_crud(struct lightningd *ld, const tal_t *ctx)
21962196
wallet_err = tal_free(wallet_err);
21972197

21982198
/* Update */
2199-
CHECK_MSG(transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, RCVD_ADD_HTLC, NULL, 0, 0, NULL, NULL, &we_filled)),
2199+
CHECK_MSG(transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, RCVD_ADD_HTLC, NULL, 0, 0, NULL, NULL, &we_filled, in.key.id, in.key.channel, REMOTE, &in.payment_hash, in.cltv_expiry, in.msat)),
22002200
"Update HTLC with null payment_key failed");
22012201
CHECK_MSG(
2202-
transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, SENT_REMOVE_HTLC, &payment_key, 0, 0, NULL, NULL, &we_filled)),
2202+
transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, SENT_REMOVE_HTLC, &payment_key, 0, 0, NULL, NULL, &we_filled, in.key.id, in.key.channel, REMOTE, &in.payment_hash, in.cltv_expiry, in.msat)),
22032203
"Update HTLC with payment_key failed");
22042204
onionreply = new_onionreply(tmpctx, tal_arrz(tmpctx, u8, 100));
22052205
CHECK_MSG(
2206-
transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, SENT_REMOVE_HTLC, NULL, 0, 0, onionreply, NULL, &we_filled)),
2206+
transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, SENT_REMOVE_HTLC, NULL, 0, 0, onionreply, NULL, &we_filled, in.key.id, in.key.channel, REMOTE, &in.payment_hash, in.cltv_expiry, in.msat)),
22072207
"Update HTLC with failonion failed");
22082208
CHECK_MSG(
2209-
transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, SENT_REMOVE_HTLC, NULL, 0, WIRE_INVALID_ONION_VERSION, NULL, NULL, &we_filled)),
2209+
transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, SENT_REMOVE_HTLC, NULL, 0, WIRE_INVALID_ONION_VERSION, NULL, NULL, &we_filled, in.key.id, in.key.channel, REMOTE, &in.payment_hash, in.cltv_expiry, in.msat)),
22102210
"Update HTLC with failcode failed");
22112211

22122212
CHECK_MSG(transaction_wrap(w->db, wallet_htlc_save_out(w, chan, &out)),
@@ -2218,7 +2218,7 @@ static bool test_htlc_crud(struct lightningd *ld, const tal_t *ctx)
22182218
CHECK(wallet_err);
22192219
wallet_err = tal_free(wallet_err);
22202220
CHECK_MSG(
2221-
transaction_wrap(w->db, wallet_htlc_update(w, out.dbid, SENT_ADD_ACK_REVOCATION, NULL, 0, 0, NULL, tal_arrz(tmpctx, u8, 100), &we_filled)),
2221+
transaction_wrap(w->db, wallet_htlc_update(w, out.dbid, SENT_ADD_ACK_REVOCATION, NULL, 0, 0, NULL, tal_arrz(tmpctx, u8, 100), &we_filled, out.key.id, out.key.channel, REMOTE, &out.payment_hash, out.cltv_expiry, out.msat)),
22222222
"Update outgoing HTLC with failmsg failed");
22232223

22242224
/* Attempt to load them from the DB again */

0 commit comments

Comments
 (0)