Skip to content

Commit 1007056

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

File tree

7 files changed

+220
-27
lines changed

7 files changed

+220
-27
lines changed

lightningd/channel.c

+1-1
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

+36-5
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

@@ -1761,7 +1786,13 @@ void onchain_failed_our_htlc(const struct channel *channel,
17611786
max_unsigned(channel->next_index[LOCAL],
17621787
channel->next_index[REMOTE]),
17631788
0, hout->failonion,
1764-
hout->failmsg, &we_filled);
1789+
hout->failmsg, &we_filled,
1790+
hout->key.id,
1791+
hout->key.channel,
1792+
LOCAL,
1793+
&hout->payment_hash,
1794+
hout->cltv_expiry,
1795+
hout->msat);
17651796

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

tests/test_misc.py

+79
Original file line numberDiff line numberDiff line change
@@ -3426,6 +3426,85 @@ def test_listforwards_wait(node_factory, executor):
34263426
'status': 'failed'}}
34273427

34283428

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

wallet/test/run-db.c

+25
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,31 @@ struct htlc_in *htlc_in_check(const struct htlc_in *hin UNNEEDED, const char *ab
118118
/* Generated stub for htlc_out_connect_htlc_in */
119119
void htlc_out_connect_htlc_in(struct htlc_out *hout UNNEEDED, struct htlc_in *hin UNNEEDED)
120120
{ fprintf(stderr, "htlc_out_connect_htlc_in called!\n"); abort(); }
121+
/* Generated stub for htlcs_index_created */
122+
u64 htlcs_index_created(struct lightningd *ld UNNEEDED,
123+
u64 htlc_id UNNEEDED,
124+
const struct channel *channel UNNEEDED,
125+
const struct sha256 *payment_hash UNNEEDED,
126+
enum side owner UNNEEDED,
127+
u32 expiry UNNEEDED,
128+
struct amount_msat amount UNNEEDED,
129+
enum htlc_state hstate UNNEEDED)
130+
{ fprintf(stderr, "htlcs_index_created called!\n"); abort(); }
131+
/* Generated stub for htlcs_index_deleted */
132+
void htlcs_index_deleted(struct lightningd *ld UNNEEDED,
133+
const struct channel *channel UNNEEDED,
134+
u64 num_deleted UNNEEDED)
135+
{ fprintf(stderr, "htlcs_index_deleted called!\n"); abort(); }
136+
/* Generated stub for htlcs_index_update_status */
137+
u64 htlcs_index_update_status(struct lightningd *ld UNNEEDED,
138+
u64 htlc_id UNNEEDED,
139+
const struct channel *channel UNNEEDED,
140+
const struct sha256 *payment_hash UNNEEDED,
141+
enum side owner UNNEEDED,
142+
u32 expiry UNNEEDED,
143+
struct amount_msat amount UNNEEDED,
144+
enum htlc_state hstate UNNEEDED)
145+
{ fprintf(stderr, "htlcs_index_update_status called!\n"); abort(); }
121146
/* Generated stub for inflight_set_last_tx */
122147
void inflight_set_last_tx(struct channel_inflight *inflight UNNEEDED,
123148
struct bitcoin_tx *last_tx STEALS UNNEEDED,

wallet/test/run-wallet.c

+9-5
Original file line numberDiff line numberDiff line change
@@ -2174,19 +2174,23 @@ static bool test_htlc_crud(struct lightningd *ld, const tal_t *ctx)
21742174
chan->state = CHANNELD_NORMAL;
21752175
chan->peer = peer;
21762176
chan->next_index[LOCAL] = chan->next_index[REMOTE] = 1;
2177+
chan->scid = tal(chan, struct short_channel_id);
21772178

21782179
memset(&in, 0, sizeof(in));
21792180
memset(&out, 0, sizeof(out));
21802181
memset(&in.payment_hash, 'A', sizeof(struct sha256));
21812182
memset(&out.payment_hash, 'A', sizeof(struct sha256));
21822183
memset(&payment_key, 'B', sizeof(payment_key));
2184+
assert(mk_short_channel_id(chan->scid, 1, 2, 3));
21832185
in.key.id = 42;
21842186
in.key.channel = chan;
2187+
in.cltv_expiry = 42;
21852188
in.msat = AMOUNT_MSAT(42);
21862189

21872190
out.in = &in;
21882191
out.key.id = 1337;
21892192
out.key.channel = chan;
2193+
out.cltv_expiry = 41;
21902194
out.msat = AMOUNT_MSAT(41);
21912195

21922196
/* Store the htlc_in */
@@ -2200,17 +2204,17 @@ static bool test_htlc_crud(struct lightningd *ld, const tal_t *ctx)
22002204
wallet_err = tal_free(wallet_err);
22012205

22022206
/* Update */
2203-
CHECK_MSG(transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, RCVD_ADD_HTLC, NULL, 0, 0, NULL, NULL, &we_filled)),
2207+
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)),
22042208
"Update HTLC with null payment_key failed");
22052209
CHECK_MSG(
2206-
transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, SENT_REMOVE_HTLC, &payment_key, 0, 0, NULL, NULL, &we_filled)),
2210+
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)),
22072211
"Update HTLC with payment_key failed");
22082212
onionreply = new_onionreply(tmpctx, tal_arrz(tmpctx, u8, 100));
22092213
CHECK_MSG(
2210-
transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, SENT_REMOVE_HTLC, NULL, 0, 0, onionreply, NULL, &we_filled)),
2214+
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)),
22112215
"Update HTLC with failonion failed");
22122216
CHECK_MSG(
2213-
transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, SENT_REMOVE_HTLC, NULL, 0, WIRE_INVALID_ONION_VERSION, NULL, NULL, &we_filled)),
2217+
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)),
22142218
"Update HTLC with failcode failed");
22152219

22162220
CHECK_MSG(transaction_wrap(w->db, wallet_htlc_save_out(w, chan, &out)),
@@ -2222,7 +2226,7 @@ static bool test_htlc_crud(struct lightningd *ld, const tal_t *ctx)
22222226
CHECK(wallet_err);
22232227
wallet_err = tal_free(wallet_err);
22242228
CHECK_MSG(
2225-
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)),
2229+
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)),
22262230
"Update outgoing HTLC with failmsg failed");
22272231

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

0 commit comments

Comments
 (0)