diff --git a/CHANGELOG.md b/CHANGELOG.md index 46d450019..5f3ab43a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - JSON API: `newaddr` outputs `bech32` or `p2sh-segwit`, or both with new `all` parameter (#2390) - JSON API: `listpeers` status now shows how many confirmations until channel is open (#2405) - Config: Adds parameter `min-capacity-sat` to reject tiny channels. +- JSON API: `listforwards` now includes the time an HTLC was received and when it was resolved. Both are expressed as UNIX timestamps to facilitate parsing (Issue [#2491](https://github.com/ElementsProject/lightning/issues/2491), PR [#2528](https://github.com/ElementsProject/lightning/pull/2528)) ### Changed diff --git a/Makefile b/Makefile index b72c98f7b..7e23e8a2a 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ endif ifeq ($(COMPAT),1) # We support compatibility with pre-0.6. -COMPAT_CFLAGS=-DCOMPAT_V052=1 -DCOMPAT_V060=1 -DCOMPAT_V061=1 -DCOMPAT_V062=1 +COMPAT_CFLAGS=-DCOMPAT_V052=1 -DCOMPAT_V060=1 -DCOMPAT_V061=1 -DCOMPAT_V062=1 -DCOMPAT_V070=1 endif # Timeout shortly before the 600 second travis silence timeout diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index b9306e7f7..d3cff6483 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -1902,6 +1902,19 @@ static void listforwardings_add_forwardings(struct json_stream *response, struct cur->fee, "fee", "fee_msat"); json_add_string(response, "status", forward_status_name(cur->status)); +#ifdef COMPAT_V070 + /* If a forwarding doesn't have received_time it was created + * before we added the tracking, do not include it here. */ + if (cur->received_time.ts.tv_sec) { + json_add_timeabs(response, "received_time", cur->received_time); + if (cur->resolved_time) + json_add_timeabs(response, "resolved_time", *cur->resolved_time); + } +#else + json_add_timeabs(response, "received_time", cur->received_time); + if (cur->resolved_time) + json_add_timeabs(response, "resolved_time", *cur->resolved_time); +#endif json_object_end(response); } json_array_end(response); diff --git a/tests/test_pay.py b/tests/test_pay.py index ff8640942..8d0c3f14b 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -1052,7 +1052,7 @@ def test_forward_stats(node_factory, bitcoind): We wire up the network to have l1 as payment initiator, l2 as forwarded (the one we check) and l3-l5 as payment recipients. l3 - accepts correctly, l4 refects (because it doesn't know the payment + accepts correctly, l4 rejects (because it doesn't know the payment hash) and l5 will keep the HTLC dangling by disconnecting. """ @@ -1119,6 +1119,9 @@ def test_forward_stats(node_factory, bitcoind): assert l2.rpc.getinfo()['msatoshi_fees_collected'] == 1 + amount // 100000 assert l1.rpc.getinfo()['msatoshi_fees_collected'] == 0 assert l3.rpc.getinfo()['msatoshi_fees_collected'] == 0 + assert stats['forwards'][0]['received_time'] <= stats['forwards'][0]['resolved_time'] + assert stats['forwards'][1]['received_time'] <= stats['forwards'][1]['resolved_time'] + assert 'received_time' in stats['forwards'][2] and 'resolved_time' not in stats['forwards'][2] @unittest.skipIf(not DEVELOPER or SLOW_MACHINE, "needs DEVELOPER=1 for dev_ignore_htlcs, and temporarily disabled on Travis") diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 7a667c009..9b1fa8272 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -251,6 +251,10 @@ void json_add_short_channel_id(struct json_stream *response UNNEEDED, /* Generated stub for json_add_string */ void json_add_string(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, const char *value UNNEEDED) { fprintf(stderr, "json_add_string called!\n"); abort(); } +/* Generated stub for json_add_timeabs */ +void json_add_timeabs(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, + struct timeabs t UNNEEDED) +{ fprintf(stderr, "json_add_timeabs called!\n"); abort(); } /* Generated stub for json_add_txid */ void json_add_txid(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, const struct bitcoin_txid *txid UNNEEDED) diff --git a/wallet/wallet.c b/wallet/wallet.c index d6c3cef7f..e07b3141c 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -2547,7 +2547,9 @@ const struct forwarding *wallet_forwarded_payments_get(struct wallet *w, ", out_msatoshi" ", hin.payment_hash as payment_hash" ", in_channel_scid" - ", out_channel_scid " + ", out_channel_scid" + ", f.received_time" + ", f.resolved_time " "FROM forwarded_payments f " "LEFT JOIN channel_htlcs hin ON (f.in_htlc_id == hin.id)"); @@ -2575,6 +2577,15 @@ const struct forwarding *wallet_forwarded_payments_get(struct wallet *w, cur->channel_in.u64 = sqlite3_column_int64(stmt, 4); cur->channel_out.u64 = sqlite3_column_int64(stmt, 5); + + cur->received_time = sqlite3_column_timeabs(stmt, 6); + if (sqlite3_column_type(stmt, 7) != SQLITE_NULL) { + cur->resolved_time = tal(ctx, struct timeabs); + *cur->resolved_time = sqlite3_column_timeabs(stmt, 7); + } else { + cur->resolved_time = NULL; + } + } return results; diff --git a/wallet/wallet.h b/wallet/wallet.h index 14e710d2a..7a80eab99 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -165,6 +165,9 @@ struct forwarding { struct amount_msat msat_in, msat_out, fee; struct sha256_double *payment_hash; enum forward_status status; + struct timeabs received_time; + /* May not be present if the HTLC was not resolved yet. */ + struct timeabs *resolved_time; }; /* A database backed shachain struct. The datastructure is