You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1670 lines
47 KiB

#include <bitcoin/tx.h>
#include <ccan/build_assert/build_assert.h>
#include <ccan/crypto/ripemd160/ripemd160.h>
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <channeld/gen_channel_wire.h>
#include <common/json_escaped.h>
#include <common/overflows.h>
#include <common/sphinx.h>
#include <gossipd/gen_gossip_wire.h>
#include <lightningd/chaintopology.h>
#include <lightningd/htlc_end.h>
#include <lightningd/jsonrpc.h>
#include <lightningd/lightningd.h>
#include <lightningd/log.h>
#include <lightningd/pay.h>
#include <lightningd/peer_control.h>
#include <lightningd/peer_htlcs.h>
#include <lightningd/subd.h>
#include <onchaind/gen_onchain_wire.h>
#include <onchaind/onchain_wire.h>
#include <wallet/wallet.h>
#include <wire/gen_onion_wire.h>
static bool state_update_ok(struct channel *channel,
enum htlc_state oldstate, enum htlc_state newstate,
u64 htlc_id, const char *dir)
{
enum htlc_state expected = oldstate + 1;
/* We never get told about RCVD_REMOVE_HTLC, so skip over that
* (we initialize in SENT_ADD_HTLC / RCVD_ADD_COMMIT, so those
* work). */
if (expected == RCVD_REMOVE_HTLC)
expected = RCVD_REMOVE_COMMIT;
if (newstate != expected) {
channel_internal_error(channel,
"HTLC %s %"PRIu64" invalid update %s->%s",
dir, htlc_id,
htlc_state_name(oldstate),
htlc_state_name(newstate));
return false;
}
log_debug(channel->log, "HTLC %s %"PRIu64" %s->%s",
dir, htlc_id,
htlc_state_name(oldstate), htlc_state_name(newstate));
return true;
}
static bool htlc_in_update_state(struct channel *channel,
struct htlc_in *hin,
enum htlc_state newstate)
{
if (!state_update_ok(channel, hin->hstate, newstate, hin->key.id, "in"))
return false;
wallet_htlc_update(channel->peer->ld->wallet,
hin->dbid, newstate, hin->preimage);
hin->hstate = newstate;
htlc_in_check(hin, __func__);
return true;
}
static bool htlc_out_update_state(struct channel *channel,
struct htlc_out *hout,
enum htlc_state newstate)
{
if (!state_update_ok(channel, hout->hstate, newstate, hout->key.id,
"out"))
return false;
wallet_htlc_update(channel->peer->ld->wallet, hout->dbid, newstate,
NULL);
hout->hstate = newstate;
htlc_out_check(hout, __func__);
return true;
}
static void fail_in_htlc(struct htlc_in *hin,
enum onion_type failcode,
const u8 *failuremsg,
const struct short_channel_id *out_channelid)
{
assert(!hin->preimage);
assert(failcode || failuremsg);
hin->failcode = failcode;
if (failuremsg)
hin->failuremsg = tal_dup_arr(hin, u8, failuremsg, tal_len(failuremsg), 0);
/* We need this set, since we send it to channeld. */
if (hin->failcode & UPDATE)
hin->failoutchannel = *out_channelid;
else
memset(&hin->failoutchannel, 0, sizeof(hin->failoutchannel));
/* We update state now to signal it's in progress, for persistence. */
htlc_in_update_state(hin->key.channel, hin, SENT_REMOVE_HTLC);
/* Tell peer, if we can. */
if (!hin->key.channel->owner)
return;
/* onchaind doesn't care, it can't do anything but wait */
if (channel_on_chain(hin->key.channel))
return;
subd_send_msg(hin->key.channel->owner,
take(towire_channel_fail_htlc(hin,
hin->key.id,
hin->failuremsg,
hin->failcode,
&hin->failoutchannel)));
}
/* This is used for cases where we can immediately fail the HTLC. */
static void local_fail_htlc(struct htlc_in *hin, enum onion_type failcode,
const struct short_channel_id *out_channel)
{
log_info(hin->key.channel->log, "failed htlc %"PRIu64" code 0x%04x (%s)",
hin->key.id, failcode, onion_type_name(failcode));
fail_in_htlc(hin, failcode, NULL, out_channel);
}
/* localfail are for handing to the local payer if it's local. */
static void fail_out_htlc(struct htlc_out *hout, const char *localfail)
{
htlc_out_check(hout, __func__);
assert(hout->failcode || hout->failuremsg);
if (hout->in) {
fail_in_htlc(hout->in, hout->failcode, hout->failuremsg,
hout->key.channel->scid);
} else {
payment_failed(hout->key.channel->peer->ld, hout, localfail);
}
}
/* BOLT #4:
*
* * `amt_to_forward` - The amount in milli-satoshi to forward to the next
* (outgoing) hop specified within the routing information.
*
* This value MUST factor in the computed fee for this particular hop. When
* processing an incoming Sphinx packet along with the HTLC message it's
* encapsulated within, if the following inequality doesn't hold, then the
* HTLC should be rejected as it indicates a prior node in the path has
* deviated from the specified parameters:
*
* incoming_htlc_amt - fee >= amt_to_forward
*
* Where `fee` is calculated according to the receiving node's advertised fee
* schema as described in [BOLT 7](https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md#htlc-fees), or 0 if this node is the
* final hop.
*/
static bool check_amount(struct htlc_in *hin,
u64 amt_to_forward, u64 amt_in_htlc, u64 fee)
{
if (amt_in_htlc - fee >= amt_to_forward)
return true;
log_debug(hin->key.channel->log, "HTLC %"PRIu64" incorrect amount:"
" %"PRIu64" in, %"PRIu64" out, fee reqd %"PRIu64,
hin->key.id, amt_in_htlc, amt_to_forward, fee);
return false;
}
/* BOLT #4:
*
* * `outgoing_cltv_value` - The CLTV value that the _outgoing_ HTLC carrying
* the packet should have.
*
* cltv_expiry - cltv_expiry_delta >= outgoing_cltv_value
*
* Inclusion of this field allows a node to both authenticate the information
* specified by the original sender and the parameters of the HTLC forwarded,
* and ensure the original sender is using the current `cltv_expiry_delta` value.
* If there is no next hop, `cltv_expiry_delta` is zero.
* If the values don't correspond, then the HTLC should be failed+rejected as
* this indicates the incoming node has tampered with the intended HTLC
* values, or the origin has an obsolete `cltv_expiry_delta` value.
* The node MUST be consistent in responding to an unexpected
* `outgoing_cltv_value` whether it is the final hop or not, to avoid
* leaking that information.
*/
static bool check_cltv(struct htlc_in *hin,
u32 cltv_expiry, u32 outgoing_cltv_value, u32 delta)
{
if (cltv_expiry - delta >= outgoing_cltv_value)
return true;
log_debug(hin->key.channel->log, "HTLC %"PRIu64" incorrect CLTV:"
" %u in, %u out, delta reqd %u",
hin->key.id, cltv_expiry, outgoing_cltv_value, delta);
return false;
}
static void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage)
{
u8 *msg;
struct channel *channel = hin->key.channel;
struct wallet *wallet = channel->peer->ld->wallet;
hin->preimage = tal_dup(hin, struct preimage, preimage);
htlc_in_check(hin, __func__);
/* We update state now to signal it's in progress, for persistence. */
htlc_in_update_state(channel, hin, SENT_REMOVE_HTLC);
/* Update channel stats */
wallet_channel_stats_incr_in_fulfilled(wallet,
channel->dbid,
hin->msatoshi);
/* No owner? We'll either send to channeld in peer_htlcs, or
* onchaind in onchaind_tell_fulfill. */
if (!channel->owner) {
log_debug(channel->log, "HTLC fulfilled, but no owner.");
return;
}
if (channel_on_chain(channel)) {
msg = towire_onchain_known_preimage(hin, preimage);
} else {
msg = towire_channel_fulfill_htlc(hin, hin->key.id, preimage);
}
subd_send_msg(channel->owner, take(msg));
}
static void handle_localpay(struct htlc_in *hin,
u32 cltv_expiry,
const struct sha256 *payment_hash,
u64 amt_to_forward,
u32 outgoing_cltv_value)
{
enum onion_type failcode;
struct invoice invoice;
struct invoice_details details;
struct lightningd *ld = hin->key.channel->peer->ld;
/* BOLT #4:
*
* If the `amt_to_forward` is higher than `incoming_htlc_amt` of
* the HTLC at the final hop:
*
* 1. type: 19 (`final_incorrect_htlc_amount`)
* 2. data:
* * [`4`:`incoming_htlc_amt`]
*/
if (!check_amount(hin, amt_to_forward, hin->msatoshi, 0)) {
failcode = WIRE_FINAL_INCORRECT_HTLC_AMOUNT;
goto fail;
}
/* BOLT #4:
*
* If the `outgoing_cltv_value` does not match the `cltv_expiry` of
* the HTLC at the final hop:
*
* 1. type: 18 (`final_incorrect_cltv_expiry`)
* 2. data:
* * [`4`:`cltv_expiry`]
*/
if (!check_cltv(hin, cltv_expiry, outgoing_cltv_value, 0)) {
failcode = WIRE_FINAL_INCORRECT_CLTV_EXPIRY;
goto fail;
}
if (!wallet_invoice_find_unpaid(ld->wallet, &invoice, payment_hash)) {
failcode = WIRE_UNKNOWN_PAYMENT_HASH;
goto fail;
}
wallet_invoice_details(tmpctx, ld->wallet, invoice, &details);
/* BOLT #4:
*
* If the amount paid is less than the amount expected, the final node
* MUST fail the HTLC. If the amount paid is more than twice the
* amount expected, the final node SHOULD fail the HTLC. This allows
* the sender to reduce information leakage by altering the amount,
* without allowing accidental gross overpayment:
*
* 1. type: PERM|16 (`incorrect_payment_amount`)
*/
if (details.msatoshi != NULL && hin->msatoshi < *details.msatoshi) {
failcode = WIRE_INCORRECT_PAYMENT_AMOUNT;
goto fail;
} else if (details.msatoshi != NULL && hin->msatoshi > *details.msatoshi * 2) {
failcode = WIRE_INCORRECT_PAYMENT_AMOUNT;
goto fail;
}
/* BOLT #4:
*
* If the `cltv_expiry` is too low, the final node MUST fail the HTLC:
*/
if (get_block_height(ld->topology) + ld->config.cltv_final
> cltv_expiry) {
log_debug(hin->key.channel->log,
"Expiry cltv too soon %u < %u + %u",
cltv_expiry,
get_block_height(ld->topology),
ld->config.cltv_final);
failcode = WIRE_FINAL_EXPIRY_TOO_SOON;
goto fail;
}
log_info(ld->log, "Resolving invoice '%s' with HTLC %"PRIu64,
details.label->s, hin->key.id);
log_debug(ld->log, "%s: Actual amount %"PRIu64"msat, HTLC expiry %u",
details.label->s, hin->msatoshi, cltv_expiry);
fulfill_htlc(hin, &details.r);
wallet_invoice_resolve(ld->wallet, invoice, hin->msatoshi);
return;
fail:
/* Final hop never sends an UPDATE. */
assert(!(failcode & UPDATE));
local_fail_htlc(hin, failcode, NULL);
}
/*
* A catchall in case outgoing peer disconnects before getting fwd.
*
* We could queue this and wait for it to come back, but this is simple.
*/
static void destroy_hout_subd_died(struct htlc_out *hout)
{
log_debug(hout->key.channel->log,
"Failing HTLC %"PRIu64" due to peer death",
hout->key.id);
hout->failcode = WIRE_TEMPORARY_CHANNEL_FAILURE;
fail_out_htlc(hout, "Outgoing subdaemon died");
}
/* This is where channeld gives us the HTLC id, and also reports if it
* failed immediately. */
static void rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds UNUSED,
struct htlc_out *hout)
{
u16 failure_code;
u8 *failurestr;
struct lightningd *ld = subd->ld;
if (!fromwire_channel_offer_htlc_reply(msg, msg,
&hout->key.id,
&failure_code,
&failurestr)) {
channel_internal_error(subd->channel,
"Bad channel_offer_htlc_reply");
tal_free(hout);
return;
}
if (failure_code) {
hout->failcode = (enum onion_type) failure_code;
if (!hout->in) {
char *localfail = tal_fmt(msg, "%s: %.*s",
onion_type_name(failure_code),
(int)tal_len(failurestr),
(const char *)failurestr);
payment_failed(ld, hout, localfail);
} else
local_fail_htlc(hout->in, failure_code,
hout->key.channel->scid);
/* Prevent hout from being failed twice. */
tal_del_destructor(hout, destroy_hout_subd_died);
tal_free(hout);
return;
}
if (find_htlc_out(&subd->ld->htlcs_out, hout->key.channel, hout->key.id)
|| hout->key.id == HTLC_INVALID_ID) {
channel_internal_error(subd->channel,
"Bad offer_htlc_reply HTLC id %"PRIu64
" is a duplicate",
hout->key.id);
tal_free(hout);
return;
}
/* Add it to lookup table now we know id. */
connect_htlc_out(&subd->ld->htlcs_out, hout);
/* When channeld includes it in commitment, we'll make it persistent. */
}
enum onion_type send_htlc_out(struct channel *out, u64 amount, u32 cltv,
const struct sha256 *payment_hash,
const u8 *onion_routing_packet,
struct htlc_in *in,
struct htlc_out **houtp)
{
struct htlc_out *hout;
u8 *msg;
if (!channel_can_add_htlc(out)) {
log_info(out->log, "Attempt to send HTLC but not ready (%s)",
channel_state_name(out));
return WIRE_UNKNOWN_NEXT_PEER;
}
if (!out->owner) {
log_info(out->log, "Attempt to send HTLC but unowned (%s)",
channel_state_name(out));
return WIRE_TEMPORARY_CHANNEL_FAILURE;
}
/* Make peer's daemon own it, catch if it dies. */
hout = new_htlc_out(out->owner, out, amount, cltv,
pay: remove cmd pointer from htlc_out. Maintaining it was always fraught, since the command could go away if the JSON RPC died. Most recently, it was broken again on shutdown (see below). In future we may allow pay commands to block on previous payments, so it won&#39;t even be a 1:1 mapping. Generalize it: keep commands in a simple list and do a lookup when a payment fails/succeeds. Valgrind error file: valgrind-errors.5732 ==5732== Invalid read of size 8 ==5732== at 0x4149FD: remove_cmd_from_hout (pay.c:292) ==5732== by 0x468BAB: notify (tal.c:237) ==5732== by 0x469077: del_tree (tal.c:400) ==5732== by 0x4690C7: del_tree (tal.c:410) ==5732== by 0x46948A: tal_free (tal.c:509) ==5732== by 0x40F1EA: main (lightningd.c:362) ==5732== Address 0x69df148 is 1,512 bytes inside a block of size 1,544 free&#39;d ==5732== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==5732== by 0x469150: del_tree (tal.c:421) ==5732== by 0x46948A: tal_free (tal.c:509) ==5732== by 0x4198F2: free_htlcs (peer_control.c:1281) ==5732== by 0x40EBA9: shutdown_subdaemons (lightningd.c:209) ==5732== by 0x40F1DE: main (lightningd.c:360) ==5732== Block was alloc&#39;d at ==5732== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==5732== by 0x468C30: allocate (tal.c:250) ==5732== by 0x4691F7: tal_alloc_ (tal.c:448) ==5732== by 0x40A279: new_htlc_out (htlc_end.c:143) ==5732== by 0x41FD64: send_htlc_out (peer_htlcs.c:397) ==5732== by 0x41511C: send_payment (pay.c:388) ==5732== by 0x41589E: json_sendpay (pay.c:513) ==5732== by 0x40D9B1: parse_request (jsonrpc.c:600) ==5732== by 0x40DCAC: read_json (jsonrpc.c:667) ==5732== by 0x45C706: next_plan (io.c:59) ==5732== by 0x45D1DD: do_plan (io.c:387) ==5732== by 0x45D21B: io_ready (io.c:397) Signed-off-by: Rusty Russell &lt;rusty@rustcorp.com.au&gt;
7 years ago
payment_hash, onion_routing_packet, in);
tal_add_destructor(hout, destroy_hout_subd_died);
msg = towire_channel_offer_htlc(out, amount, cltv, payment_hash,
onion_routing_packet);
subd_req(out->peer->ld, out->owner, take(msg), -1, 0, rcvd_htlc_reply, hout);
if (houtp)
*houtp = hout;
return 0;
}
static void forward_htlc(struct htlc_in *hin,
u32 cltv_expiry,
u64 amt_to_forward,
u32 outgoing_cltv_value,
const struct pubkey *next_hop,
const u8 next_onion[TOTAL_PACKET_SIZE])
{
enum onion_type failcode;
u64 fee;
struct lightningd *ld = hin->key.channel->peer->ld;
struct channel *next = active_channel_by_id(ld, next_hop, NULL);
/* Unknown peer, or peer not ready. */
if (!next || !next->scid) {
local_fail_htlc(hin, WIRE_UNKNOWN_NEXT_PEER, NULL);
return;
}
/* BOLT #7:
*
* The node creating `channel_update` SHOULD accept HTLCs which pay a
* fee equal or greater than:
*
* fee_base_msat + amount_msat * fee_proportional_millionths / 1000000
*/
if (mul_overflows_u64(amt_to_forward,
ld->config.fee_per_satoshi)) {
failcode = WIRE_FEE_INSUFFICIENT;
goto fail;
}
fee = ld->config.fee_base
+ amt_to_forward * ld->config.fee_per_satoshi / 1000000;
if (!check_amount(hin, amt_to_forward, hin->msatoshi, fee)) {
failcode = WIRE_FEE_INSUFFICIENT;
goto fail;
}
if (!check_cltv(hin, cltv_expiry, outgoing_cltv_value,
ld->config.cltv_expiry_delta)) {
failcode = WIRE_INCORRECT_CLTV_EXPIRY;
goto fail;
}
/* BOLT #2:
*
* A node MUST estimate a timeout deadline for each HTLC it offers. A
* node MUST NOT offer an HTLC with a timeout deadline before its
* `cltv_expiry`
*/
/* In our case, G = 1, so we need to expire it one after it's expiration.
* But never offer an expired HTLC; that's dumb. */
if (get_block_height(ld->topology) >= outgoing_cltv_value) {
log_debug(hin->key.channel->log,
"Expiry cltv %u too close to current %u",
outgoing_cltv_value,
get_block_height(ld->topology));
failcode = WIRE_EXPIRY_TOO_SOON;
goto fail;
}
/* BOLT #4:
*
* If the `cltv_expiry` is unreasonably far, we can also report an error:
*
* 1. type: 21 (`expiry_too_far`)
*/
if (get_block_height(ld->topology)
+ ld->config.max_htlc_expiry < outgoing_cltv_value) {
log_debug(hin->key.channel->log,
"Expiry cltv %u too far from current %u + max %u",
outgoing_cltv_value,
get_block_height(ld->topology),
ld->config.max_htlc_expiry);
failcode = WIRE_EXPIRY_TOO_FAR;
goto fail;
}
failcode = send_htlc_out(next, amt_to_forward,
outgoing_cltv_value, &hin->payment_hash,
pay: remove cmd pointer from htlc_out. Maintaining it was always fraught, since the command could go away if the JSON RPC died. Most recently, it was broken again on shutdown (see below). In future we may allow pay commands to block on previous payments, so it won&#39;t even be a 1:1 mapping. Generalize it: keep commands in a simple list and do a lookup when a payment fails/succeeds. Valgrind error file: valgrind-errors.5732 ==5732== Invalid read of size 8 ==5732== at 0x4149FD: remove_cmd_from_hout (pay.c:292) ==5732== by 0x468BAB: notify (tal.c:237) ==5732== by 0x469077: del_tree (tal.c:400) ==5732== by 0x4690C7: del_tree (tal.c:410) ==5732== by 0x46948A: tal_free (tal.c:509) ==5732== by 0x40F1EA: main (lightningd.c:362) ==5732== Address 0x69df148 is 1,512 bytes inside a block of size 1,544 free&#39;d ==5732== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==5732== by 0x469150: del_tree (tal.c:421) ==5732== by 0x46948A: tal_free (tal.c:509) ==5732== by 0x4198F2: free_htlcs (peer_control.c:1281) ==5732== by 0x40EBA9: shutdown_subdaemons (lightningd.c:209) ==5732== by 0x40F1DE: main (lightningd.c:360) ==5732== Block was alloc&#39;d at ==5732== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==5732== by 0x468C30: allocate (tal.c:250) ==5732== by 0x4691F7: tal_alloc_ (tal.c:448) ==5732== by 0x40A279: new_htlc_out (htlc_end.c:143) ==5732== by 0x41FD64: send_htlc_out (peer_htlcs.c:397) ==5732== by 0x41511C: send_payment (pay.c:388) ==5732== by 0x41589E: json_sendpay (pay.c:513) ==5732== by 0x40D9B1: parse_request (jsonrpc.c:600) ==5732== by 0x40DCAC: read_json (jsonrpc.c:667) ==5732== by 0x45C706: next_plan (io.c:59) ==5732== by 0x45D1DD: do_plan (io.c:387) ==5732== by 0x45D21B: io_ready (io.c:397) Signed-off-by: Rusty Russell &lt;rusty@rustcorp.com.au&gt;
7 years ago
next_onion, hin, NULL);
if (!failcode)
return;
fail:
local_fail_htlc(hin, failcode, next->scid);
}
/* Temporary information, while we resolve the next hop */
struct gossip_resolve {
struct short_channel_id next_channel;
u64 amt_to_forward;
u32 outgoing_cltv_value;
u8 *next_onion;
struct htlc_in *hin;
};
/* We received a resolver reply, which gives us the node_ids of the
* channel we want to forward over */
static void channel_resolve_reply(struct subd *gossip, const u8 *msg,
const int *fds UNUSED, struct gossip_resolve *gr)
{
struct pubkey *nodes, *peer_id;
if (!fromwire_gossip_resolve_channel_reply(msg, msg, &nodes)) {
log_broken(gossip->log,
"bad fromwire_gossip_resolve_channel_reply %s",
tal_hex(msg, msg));
return;
}
if (tal_count(nodes) == 0) {
local_fail_htlc(gr->hin, WIRE_UNKNOWN_NEXT_PEER, NULL);
return;
} else if (tal_count(nodes) != 2) {
log_broken(gossip->log,
"fromwire_gossip_resolve_channel_reply has %zu nodes",
tal_count(nodes));
return;
}
/* Get the other peer matching the id that is not us */
if (pubkey_cmp(&nodes[0], &gossip->ld->id) == 0) {
peer_id = &nodes[1];
} else {
peer_id = &nodes[0];
}
forward_htlc(gr->hin, gr->hin->cltv_expiry,
gr->amt_to_forward, gr->outgoing_cltv_value, peer_id,
gr->next_onion);
tal_free(gr);
}
/* Everyone is committed to this htlc of theirs */
static bool peer_accepted_htlc(struct channel *channel,
u64 id,
enum onion_type *failcode)
{
struct htlc_in *hin;
u8 *req;
struct route_step *rs;
struct onionpacket *op;
struct lightningd *ld = channel->peer->ld;
hin = find_htlc_in(&ld->htlcs_in, channel, id);
if (!hin) {
channel_internal_error(channel,
"peer_got_revoke unknown htlc %"PRIu64, id);
return false;
}
if (!htlc_in_update_state(channel, hin, RCVD_ADD_ACK_REVOCATION))
return false;
#if DEVELOPER
if (channel->peer->ignore_htlcs) {
log_debug(channel->log, "their htlc %"PRIu64" dev_ignore_htlcs",
id);
return true;
}
#endif
/* BOLT #2:
*
* A sending node SHOULD fail to route any HTLC added after it
* sent `shutdown`. */
if (channel->state == CHANNELD_SHUTTING_DOWN) {
*failcode = WIRE_PERMANENT_CHANNEL_FAILURE;
goto out;
}
/* BOLT #2:
*
* A node MUST estimate a fulfillment deadline for each HTLC it is
* attempting to fulfill. A node MUST fail (and not forward) an HTLC
* whose fulfillment deadline is already past
*/
/* Our deadline is half the cltv_delta we insist on, so this check is
* a subset of the cltv check done in handle_localpay and
* forward_htlc. */
/* channeld tests this, so it should have set ss to zeroes. */
op = parse_onionpacket(tmpctx, hin->onion_routing_packet,
sizeof(hin->onion_routing_packet));
if (!op) {
if (!memeqzero(&hin->shared_secret, sizeof(hin->shared_secret))){
channel_internal_error(channel,
"bad onion in got_revoke: %s",
tal_hexstr(channel, hin->onion_routing_packet,
sizeof(hin->onion_routing_packet)));
return false;
}
/* FIXME: could be bad version, bad key. */
*failcode = WIRE_INVALID_ONION_VERSION;
goto out;
}
/* Channeld sets this to zero if HSM won't ecdh it */
if (memeqzero(&hin->shared_secret, sizeof(hin->shared_secret))) {
*failcode = WIRE_INVALID_ONION_KEY;
goto out;
}
/* If it's crap, not channeld's fault, just fail it */
rs = process_onionpacket(tmpctx, op, hin->shared_secret.data,
hin->payment_hash.u.u8,
sizeof(hin->payment_hash));
if (!rs) {
*failcode = WIRE_INVALID_ONION_HMAC;
goto out;
}
/* Unknown realm isn't a bad onion, it's a normal failure. */
if (rs->hop_data.realm != 0) {
*failcode = WIRE_INVALID_REALM;
goto out;
}
if (rs->nextcase == ONION_FORWARD) {
struct gossip_resolve *gr = tal(ld, struct gossip_resolve);
gr->next_onion = serialize_onionpacket(gr, rs->next);
gr->next_channel = rs->hop_data.channel_id;
gr->amt_to_forward = rs->hop_data.amt_forward;
gr->outgoing_cltv_value = rs->hop_data.outgoing_cltv;
gr->hin = hin;
req = towire_gossip_resolve_channel_request(tmpctx,
&gr->next_channel);
log_debug(channel->log, "Asking gossip to resolve channel %s",
type_to_string(tmpctx, struct short_channel_id,
&gr->next_channel));
subd_req(hin, ld->gossip, req, -1, 0,
channel_resolve_reply, gr);
} else
handle_localpay(hin, hin->cltv_expiry, &hin->payment_hash,
rs->hop_data.amt_forward,
rs->hop_data.outgoing_cltv);
*failcode = 0;
out:
log_debug(channel->log, "their htlc %"PRIu64" %s",
id, *failcode ? onion_type_name(*failcode) : "locked");
return true;
}
static void fulfill_our_htlc_out(struct channel *channel, struct htlc_out *hout,
const struct preimage *preimage)
{
struct lightningd *ld = channel->peer->ld;
assert(!hout->preimage);
hout->preimage = tal_dup(hout, struct preimage, preimage);
htlc_out_check(hout, __func__);
wallet_htlc_update(ld->wallet, hout->dbid, hout->hstate, preimage);
/* Update channel stats */
wallet_channel_stats_incr_out_fulfilled(ld->wallet,
channel->dbid,
hout->msatoshi);
if (hout->in)
fulfill_htlc(hout->in, preimage);
else
payment_succeeded(ld, hout, preimage);
}
static bool peer_fulfilled_our_htlc(struct channel *channel,
const struct fulfilled_htlc *fulfilled)
{
struct lightningd *ld = channel->peer->ld;
struct htlc_out *hout;
hout = find_htlc_out(&ld->htlcs_out, channel, fulfilled->id);
if (!hout) {
channel_internal_error(channel,
"fulfilled_our_htlc unknown htlc %"PRIu64,
fulfilled->id);
return false;
}
if (!htlc_out_update_state(channel, hout, RCVD_REMOVE_COMMIT))
return false;
fulfill_our_htlc_out(channel, hout, &fulfilled->payment_preimage);
return true;
}
void onchain_fulfilled_htlc(struct channel *channel,
const struct preimage *preimage)
{
struct htlc_out_map_iter outi;
struct htlc_out *hout;
struct sha256 payment_hash;
struct lightningd *ld = channel->peer->ld;
sha256(&payment_hash, preimage, sizeof(*preimage));
/* FIXME: use db to look this up! */
for (hout = htlc_out_map_first(&ld->htlcs_out, &outi);
hout;
hout = htlc_out_map_next(&ld->htlcs_out, &outi)) {
if (hout->key.channel != channel)
continue;
/* It's possible that we failed some and succeeded one,
* if we got multiple errors. */
if (hout->failcode != 0 || hout->failuremsg)
continue;
if (!structeq(&hout->payment_hash, &payment_hash))
continue;
/* We may have already fulfilled before going onchain, or
* we can fulfill onchain multiple times. */
if (!hout->preimage)
fulfill_our_htlc_out(channel, hout, preimage);
/* We keep going: this is something of a leak, but onchain
* we have no real way of distinguishing HTLCs anyway */
}
}
static bool peer_failed_our_htlc(struct channel *channel,
const struct failed_htlc *failed)
{
struct htlc_out *hout;
struct lightningd *ld = channel->peer->ld;
hout = find_htlc_out(&ld->htlcs_out, channel, failed->id);
if (!hout) {
channel_internal_error(channel,
"failed_our_htlc unknown htlc %"PRIu64,
failed->id);
return false;
}
if (!htlc_out_update_state(channel, hout, RCVD_REMOVE_COMMIT))
return false;
hout->failcode = failed->malformed;
if (!failed->malformed)
hout->failuremsg = tal_dup_arr(hout, u8, failed->failreason,
tal_len(failed->failreason), 0);
else
hout->failuremsg = NULL;
log_debug(channel->log, "Our HTLC %"PRIu64" failed (%u)", failed->id,
hout->failcode);
htlc_out_check(hout, __func__);
return true;
}
/* FIXME: Crazy slow! */
struct htlc_out *find_htlc_out_by_ripemd(const struct channel *channel,
const struct ripemd160 *ripemd)
{
struct htlc_out_map_iter outi;
struct htlc_out *hout;
struct lightningd *ld = channel->peer->ld;
for (hout = htlc_out_map_first(&ld->htlcs_out, &outi);
hout;
hout = htlc_out_map_next(&ld->htlcs_out, &outi)) {
struct ripemd160 hash;
if (hout->key.channel != channel)
continue;
ripemd160(&hash,
&hout->payment_hash, sizeof(hout->payment_hash));
if (structeq(&hash, ripemd))
return hout;
}
return NULL;
}
void onchain_failed_our_htlc(const struct channel *channel,
const struct htlc_stub *htlc,
const char *why)
{
struct lightningd *ld = channel->peer->ld;
struct htlc_out *hout = find_htlc_out_by_ripemd(channel, &htlc->ripemd);
/* Don't fail twice! */
if (hout->failuremsg || hout->failcode)
return;
hout->failcode = WIRE_PERMANENT_CHANNEL_FAILURE;
if (!hout->in) {
assert(why != NULL);
char *localfail = tal_fmt(channel, "%s: %s",
onion_type_name(WIRE_PERMANENT_CHANNEL_FAILURE),
why);
payment_failed(ld, hout, localfail);
tal_free(localfail);
} else
local_fail_htlc(hout->in, WIRE_PERMANENT_CHANNEL_FAILURE,
hout->key.channel->scid);
}
static void remove_htlc_in(struct channel *channel, struct htlc_in *hin)
{
htlc_in_check(hin, __func__);
assert(hin->failuremsg || hin->preimage || hin->failcode);
log_debug(channel->log, "Removing in HTLC %"PRIu64" state %s %s",
hin->key.id, htlc_state_name(hin->hstate),
hin->preimage ? "FULFILLED"
: hin->failcode ? onion_type_name(hin->failcode)
: "REMOTEFAIL");
/* If we fulfilled their HTLC, credit us. */
if (hin->preimage) {
log_debug(channel->log, "Balance %"PRIu64" -> %"PRIu64,
channel->our_msatoshi,
channel->our_msatoshi + hin->msatoshi);
channel->our_msatoshi += hin->msatoshi;
if (channel->our_msatoshi > channel->msatoshi_to_us_max)
channel->msatoshi_to_us_max = channel->our_msatoshi;
}
tal_free(hin);
}
static void remove_htlc_out(struct channel *channel, struct htlc_out *hout)
{
htlc_out_check(hout, __func__);
assert(hout->failuremsg || hout->preimage || hout->failcode);
log_debug(channel->log, "Removing out HTLC %"PRIu64" state %s %s",
hout->key.id, htlc_state_name(hout->hstate),
hout->preimage ? "FULFILLED"
: hout->failcode ? onion_type_name(hout->failcode)
: "REMOTEFAIL");
/* If it's failed, now we can forward since it's completely locked-in */
if (!hout->preimage) {
fail_out_htlc(hout, NULL);
} else {
/* We paid for this HTLC, so deduct balance. */
log_debug(channel->log, "Balance %"PRIu64" -> %"PRIu64,
channel->our_msatoshi,
channel->our_msatoshi - hout->msatoshi);
channel->our_msatoshi -= hout->msatoshi;
if (channel->our_msatoshi < channel->msatoshi_to_us_min)
channel->msatoshi_to_us_min = channel->our_msatoshi;
}
tal_free(hout);
}
static bool update_in_htlc(struct channel *channel,
u64 id, enum htlc_state newstate)
{
struct htlc_in *hin;
struct lightningd *ld = channel->peer->ld;
hin = find_htlc_in(&ld->htlcs_in, channel, id);
if (!hin) {
channel_internal_error(channel, "Can't find in HTLC %"PRIu64, id);
return false;
}
if (!htlc_in_update_state(channel, hin, newstate))
return false;
if (newstate == SENT_REMOVE_ACK_REVOCATION)
remove_htlc_in(channel, hin);
return true;
}
static bool update_out_htlc(struct channel *channel,
u64 id, enum htlc_state newstate)
{
struct lightningd *ld = channel->peer->ld;
struct htlc_out *hout;
hout = find_htlc_out(&ld->htlcs_out, channel, id);
if (!hout) {
channel_internal_error(channel, "Can't find out HTLC %"PRIu64, id);
return false;
}
if (!hout->dbid) {
wallet_htlc_save_out(ld->wallet, channel, hout);
/* Update channel stats */
wallet_channel_stats_incr_out_offered(ld->wallet,
channel->dbid,
hout->msatoshi);
/* For our own HTLCs, we commit payment to db lazily */
if (hout->origin_htlc_id == 0)
payment_store(ld,
&hout->payment_hash);
}
if (!htlc_out_update_state(channel, hout, newstate))
return false;
/* First transition into commitment; now it outlives peer. */
if (newstate == SENT_ADD_COMMIT) {
tal_del_destructor(hout, destroy_hout_subd_died);
tal_steal(ld, hout);
} else if (newstate == RCVD_REMOVE_ACK_REVOCATION) {
remove_htlc_out(channel, hout);
}
return true;
}
static bool changed_htlc(struct channel *channel,
const struct changed_htlc *changed)
{
if (htlc_state_owner(changed->newstate) == LOCAL)
return update_out_htlc(channel, changed->id, changed->newstate);
else
return update_in_htlc(channel, changed->id, changed->newstate);
}
static bool peer_save_commitsig_received(struct channel *channel, u64 commitnum,
struct bitcoin_tx *tx,
const secp256k1_ecdsa_signature *commit_sig)
{
if (commitnum != channel->next_index[LOCAL]) {
channel_internal_error(channel,
"channel_got_commitsig: expected commitnum %"PRIu64
" got %"PRIu64,
channel->next_index[LOCAL], commitnum);
return false;
}
channel->next_index[LOCAL]++;
/* Update channel->last_sig and channel->last_tx before saving to db */
channel_set_last_tx(channel, tx, commit_sig);
return true;
}
static bool peer_save_commitsig_sent(struct channel *channel, u64 commitnum)
{
struct lightningd *ld = channel->peer->ld;
if (commitnum != channel->next_index[REMOTE]) {
channel_internal_error(channel,
"channel_sent_commitsig: expected commitnum %"PRIu64
" got %"PRIu64,
channel->next_index[REMOTE], commitnum);
return false;
}
channel->next_index[REMOTE]++;
/* FIXME: Save to database, with sig and HTLCs. */
wallet_channel_save(ld->wallet, channel);
return true;
}
void peer_sending_commitsig(struct channel *channel, const u8 *msg)
{
u64 commitnum;
u32 feerate;
struct changed_htlc *changed_htlcs;
size_t i, maxid = 0, num_local_added = 0;
secp256k1_ecdsa_signature commit_sig;
secp256k1_ecdsa_signature *htlc_sigs;
struct lightningd *ld = channel->peer->ld;
if (!fromwire_channel_sending_commitsig(msg, msg,
&commitnum,
&feerate,
&changed_htlcs,
&commit_sig, &htlc_sigs)) {
channel_internal_error(channel, "bad channel_sending_commitsig %s",
tal_hex(channel, msg));
return;
}
for (i = 0; i < tal_count(changed_htlcs); i++) {
if (!changed_htlc(channel, changed_htlcs + i)) {
channel_internal_error(channel,
"channel_sending_commitsig: update failed");
return;
}
/* While we're here, sanity check added ones are in
* ascending order. */
if (changed_htlcs[i].newstate == SENT_ADD_COMMIT) {
num_local_added++;
if (changed_htlcs[i].id > maxid)
maxid = changed_htlcs[i].id;
}
}
if (num_local_added != 0) {
if (maxid != channel->next_htlc_id + num_local_added - 1) {
channel_internal_error(channel,
"channel_sending_commitsig:"
" Added %"PRIu64", maxid now %"PRIu64
" from %"PRIu64,
num_local_added, maxid, channel->next_htlc_id);
return;
}
channel->next_htlc_id += num_local_added;
}
/* Update their feerate. */
channel->channel_info.feerate_per_kw[REMOTE] = feerate;
if (feerate > channel->max_possible_feerate)
channel->max_possible_feerate = feerate;
if (feerate < channel->min_possible_feerate)
channel->min_possible_feerate = feerate;
if (!peer_save_commitsig_sent(channel, commitnum))
return;
/* Last was commit. */
channel->last_was_revoke = false;
tal_free(channel->last_sent_commit);
channel->last_sent_commit = tal_steal(channel, changed_htlcs);
wallet_channel_save(ld->wallet, channel);
/* Tell it we've got it, and to go ahead with commitment_signed. */
subd_send_msg(channel->owner,
take(towire_channel_sending_commitsig_reply(msg)));
}
static bool channel_added_their_htlc(struct channel *channel,
const struct added_htlc *added,
const struct secret *shared_secret)
{
struct lightningd *ld = channel->peer->ld;
struct htlc_in *hin;
/* BOLT #2:
*
* - receiving an `amount_msat` equal to 0, OR less than its own `htlc_minimum_msat`:
* - SHOULD fail the channel.
*/
if (added->amount_msat == 0
|| added->amount_msat < channel->our_config.htlc_minimum_msat) {
channel_internal_error(channel,
"trying to add HTLC msat %"PRIu64
" but minimum is %"PRIu64,
added->amount_msat,
channel->our_config.htlc_minimum_msat);
return false;
}
/* This stays around even if we fail it immediately: it *is*
* part of the current commitment. */
hin = new_htlc_in(channel, channel, added->id, added->amount_msat,
added->cltv_expiry, &added->payment_hash,
shared_secret, added->onion_routing_packet);
/* Save an incoming htlc to the wallet */
wallet_htlc_save_in(ld->wallet, channel, hin);
/* Update channel stats */
wallet_channel_stats_incr_in_offered(ld->wallet, channel->dbid,
added->amount_msat);
log_debug(channel->log, "Adding their HTLC %"PRIu64, added->id);
connect_htlc_in(&channel->peer->ld->htlcs_in, hin);
return true;
}
/* The peer doesn't tell us this separately, but logically it's a separate
* step to receiving commitsig */
static bool peer_sending_revocation(struct channel *channel,
struct added_htlc *added,
struct fulfilled_htlc *fulfilled,
struct failed_htlc **failed,
struct changed_htlc *changed)
{
size_t i;
for (i = 0; i < tal_count(added); i++) {
if (!update_in_htlc(channel, added[i].id, SENT_ADD_REVOCATION))
return false;
}
for (i = 0; i < tal_count(fulfilled); i++) {
if (!update_out_htlc(channel, fulfilled[i].id,
SENT_REMOVE_REVOCATION))
return false;
}
for (i = 0; i < tal_count(failed); i++) {
if (!update_out_htlc(channel, failed[i]->id, SENT_REMOVE_REVOCATION))
return false;
}
for (i = 0; i < tal_count(changed); i++) {
if (changed[i].newstate == RCVD_ADD_ACK_COMMIT) {
if (!update_out_htlc(channel, changed[i].id,
SENT_ADD_ACK_REVOCATION))
return false;
} else {
if (!update_in_htlc(channel, changed[i].id,
SENT_REMOVE_ACK_REVOCATION))
return false;
}
}
channel->last_was_revoke = true;
return true;
}
/* This also implies we're sending revocation */
void peer_got_commitsig(struct channel *channel, const u8 *msg)
{
u64 commitnum;
u32 feerate;
secp256k1_ecdsa_signature commit_sig;
secp256k1_ecdsa_signature *htlc_sigs;
struct added_htlc *added;
struct secret *shared_secrets;
struct fulfilled_htlc *fulfilled;
struct failed_htlc **failed;
struct changed_htlc *changed;
struct bitcoin_tx *tx;
size_t i;
struct lightningd *ld = channel->peer->ld;
if (!fromwire_channel_got_commitsig(msg, msg,
&commitnum,
&feerate,
&commit_sig,
&htlc_sigs,
&added,
&shared_secrets,
&fulfilled,
&failed,
&changed,
&tx)) {
channel_internal_error(channel,
"bad fromwire_channel_got_commitsig %s",
tal_hex(channel, msg));
return;
}
log_debug(channel->log,
"got commitsig %"PRIu64
": feerate %u, %zu added, %zu fulfilled, %zu failed, %zu changed",
commitnum, feerate, tal_count(added), tal_count(fulfilled),
tal_count(failed), tal_count(changed));
/* New HTLCs */
for (i = 0; i < tal_count(added); i++) {
if (!channel_added_their_htlc(channel, &added[i], &shared_secrets[i]))
return;
}
/* Save information now for fulfilled & failed HTLCs */
for (i = 0; i < tal_count(fulfilled); i++) {
if (!peer_fulfilled_our_htlc(channel, &fulfilled[i]))
return;
}
for (i = 0; i < tal_count(failed); i++) {
if (!peer_failed_our_htlc(channel, failed[i]))
return;
}
for (i = 0; i < tal_count(changed); i++) {
if (!changed_htlc(channel, &changed[i])) {
channel_internal_error(channel,
"got_commitsig: update failed");
return;
}
}
/* Update both feerates: if we're funder, REMOTE should already be
* that feerate, if we're not, we're about to ACK anyway. */
channel->channel_info.feerate_per_kw[LOCAL]
= channel->channel_info.feerate_per_kw[REMOTE]
= feerate;
if (feerate > channel->max_possible_feerate)
channel->max_possible_feerate = feerate;
if (feerate < channel->min_possible_feerate)
channel->min_possible_feerate = feerate;
/* Since we're about to send revoke, bump state again. */
if (!peer_sending_revocation(channel, added, fulfilled, failed, changed))
return;
if (!peer_save_commitsig_received(channel, commitnum, tx, &commit_sig))
return;
wallet_channel_save(ld->wallet, channel);
tal_free(channel->last_htlc_sigs);
channel->last_htlc_sigs = tal_steal(channel, htlc_sigs);
wallet_htlc_sigs_save(ld->wallet, channel->dbid,
channel->last_htlc_sigs);
/* Tell it we've committed, and to go ahead with revoke. */
msg = towire_channel_got_commitsig_reply(msg);
subd_send_msg(channel->owner, take(msg));
}
/* Shuffle them over, forgetting the ancient one. */
void update_per_commit_point(struct channel *channel,
const struct pubkey *per_commitment_point)
{
struct channel_info *ci = &channel->channel_info;
ci->old_remote_per_commit = ci->remote_per_commit;
ci->remote_per_commit = *per_commitment_point;
}
void peer_got_revoke(struct channel *channel, const u8 *msg)
{
u64 revokenum;
struct sha256 per_commitment_secret;
struct pubkey next_per_commitment_point;
struct changed_htlc *changed;
enum onion_type *failcodes;
size_t i;
struct lightningd *ld = channel->peer->ld;
if (!fromwire_channel_got_revoke(msg, msg,
&revokenum, &per_commitment_secret,
&next_per_commitment_point,
&changed)) {
channel_internal_error(channel, "bad fromwire_channel_got_revoke %s",
tal_hex(channel, msg));
return;
}
log_debug(channel->log,
"got revoke %"PRIu64": %zu changed",
revokenum, tal_count(changed));
/* Save any immediate failures for after we reply. */
failcodes = tal_arrz(msg, enum onion_type, tal_count(changed));
for (i = 0; i < tal_count(changed); i++) {
/* If we're doing final accept, we need to forward */
if (changed[i].newstate == RCVD_ADD_ACK_REVOCATION) {
if (!peer_accepted_htlc(channel, changed[i].id,
&failcodes[i]))
return;
} else {
if (!changed_htlc(channel, &changed[i])) {
channel_internal_error(channel,
"got_revoke: update failed");
return;
}
}
}
if (revokenum >= (1ULL << 48)) {
channel_internal_error(channel, "got_revoke: too many txs %"PRIu64,
revokenum);
return;
}
if (revokenum != revocations_received(&channel->their_shachain.chain)) {
channel_internal_error(channel, "got_revoke: expected %"PRIu64
" got %"PRIu64,
revocations_received(&channel->their_shachain.chain), revokenum);
return;
}
/* BOLT #2:
*
* A receiving node MAY fail if the `per_commitment_secret` was not
* generated by the protocol in [BOLT #3]
*/
if (!wallet_shachain_add_hash(ld->wallet,
&channel->their_shachain,
shachain_index(revokenum),
&per_commitment_secret)) {
channel_fail_permanent(channel,
"Bad per_commitment_secret %s for %"PRIu64,
type_to_string(msg, struct sha256,
&per_commitment_secret),
revokenum);
return;
}
/* FIXME: Check per_commitment_secret -> per_commit_point */
update_per_commit_point(channel, &next_per_commitment_point);
/* Tell it we've committed, and to go ahead with revoke. */
msg = towire_channel_got_revoke_reply(msg);
subd_send_msg(channel->owner, take(msg));
/* Now, any HTLCs we need to immediately fail? */
for (i = 0; i < tal_count(changed); i++) {
struct htlc_in *hin;
if (!failcodes[i])
continue;
/* These are all errors before finding next hop. */
assert(!(failcodes[i] & UPDATE));
hin = find_htlc_in(&ld->htlcs_in, channel, changed[i].id);
local_fail_htlc(hin, failcodes[i], NULL);
}
wallet_channel_save(ld->wallet, channel);
}
static void *tal_arr_append_(void **p, size_t size)
{
size_t n = tal_len(*p) / size;
tal_resize_(p, size, n+1, false);
return (char *)(*p) + n * size;
}
#define tal_arr_append(p) tal_arr_append_((void **)(p), sizeof(**(p)))
static void add_htlc(struct added_htlc **htlcs,
enum htlc_state **htlc_states,
u64 id,
u64 amount_msat,
const struct sha256 *payment_hash,
u32 cltv_expiry,
const u8 onion_routing_packet[TOTAL_PACKET_SIZE],
enum htlc_state state)
{
struct added_htlc *a;
enum htlc_state *h;
a = tal_arr_append(htlcs);
h = tal_arr_append(htlc_states);
a->id = id;
a->amount_msat = amount_msat;
a->payment_hash = *payment_hash;
a->cltv_expiry = cltv_expiry;
memcpy(a->onion_routing_packet, onion_routing_packet,
sizeof(a->onion_routing_packet));
*h = state;
}
static void add_fulfill(u64 id, enum side side,
const struct preimage *payment_preimage,
struct fulfilled_htlc **fulfilled_htlcs,
enum side **fulfilled_sides)
{
struct fulfilled_htlc *f;
enum side *s;
f = tal_arr_append(fulfilled_htlcs);
s = tal_arr_append(fulfilled_sides);
f->id = id;
f->payment_preimage = *payment_preimage;
*s = side;
}
static void add_fail(u64 id, enum side side,
const u8 *failuremsg,
const struct failed_htlc ***failed_htlcs,
enum side **failed_sides)
{
struct failed_htlc **f;
enum side *s;
f = tal_arr_append(failed_htlcs);
s = tal_arr_append(failed_sides);
*f = tal(*failed_htlcs, struct failed_htlc);
(*f)->id = id;
(*f)->failreason
= tal_dup_arr(*f, u8, failuremsg, tal_len(failuremsg), 0);
*s = side;
}
/* FIXME: Load direct from db. */
void peer_htlcs(const tal_t *ctx,
const struct channel *channel,
struct added_htlc **htlcs,
enum htlc_state **htlc_states,
struct fulfilled_htlc **fulfilled_htlcs,
enum side **fulfilled_sides,
const struct failed_htlc ***failed_htlcs,
enum side **failed_sides)
{
struct htlc_in_map_iter ini;
struct htlc_out_map_iter outi;
struct htlc_in *hin;
struct htlc_out *hout;
struct lightningd *ld = channel->peer->ld;
*htlcs = tal_arr(ctx, struct added_htlc, 0);
*htlc_states = tal_arr(ctx, enum htlc_state, 0);
*fulfilled_htlcs = tal_arr(ctx, struct fulfilled_htlc, 0);
*fulfilled_sides = tal_arr(ctx, enum side, 0);
*failed_htlcs = tal_arr(ctx, const struct failed_htlc *, 0);
*failed_sides = tal_arr(ctx, enum side, 0);
for (hin = htlc_in_map_first(&ld->htlcs_in, &ini);
hin;
hin = htlc_in_map_next(&ld->htlcs_in, &ini)) {
if (hin->key.channel != channel)
continue;
add_htlc(htlcs, htlc_states,
hin->key.id, hin->msatoshi, &hin->payment_hash,
hin->cltv_expiry, hin->onion_routing_packet,
hin->hstate);
if (hin->failuremsg)
add_fail(hin->key.id, REMOTE, hin->failuremsg,
failed_htlcs, failed_sides);
if (hin->preimage)
add_fulfill(hin->key.id, REMOTE, hin->preimage,
fulfilled_htlcs, fulfilled_sides);
}
for (hout = htlc_out_map_first(&ld->htlcs_out, &outi);
hout;
hout = htlc_out_map_next(&ld->htlcs_out, &outi)) {
if (hout->key.channel != channel)
continue;
add_htlc(htlcs, htlc_states,
hout->key.id, hout->msatoshi, &hout->payment_hash,
hout->cltv_expiry, hout->onion_routing_packet,
hout->hstate);
if (hout->failuremsg)
add_fail(hout->key.id, LOCAL, hout->failuremsg,
failed_htlcs, failed_sides);
if (hout->preimage)
add_fulfill(hout->key.id, LOCAL, hout->preimage,
fulfilled_htlcs, fulfilled_sides);
}
}
/* If channel is NULL, free them all (for shutdown) */
void free_htlcs(struct lightningd *ld, const struct channel *channel)
{
struct htlc_out_map_iter outi;
struct htlc_out *hout;
struct htlc_in_map_iter ini;
struct htlc_in *hin;
bool deleted;
/* FIXME: Implement check_htlcs to ensure no dangling hout->in ptrs! */
do {
deleted = false;
for (hout = htlc_out_map_first(&ld->htlcs_out, &outi);
hout;
hout = htlc_out_map_next(&ld->htlcs_out, &outi)) {
if (channel && hout->key.channel != channel)
continue;
tal_free(hout);
deleted = true;
}
for (hin = htlc_in_map_first(&ld->htlcs_in, &ini);
hin;
hin = htlc_in_map_next(&ld->htlcs_in, &ini)) {
if (channel && hin->key.channel != channel)
continue;
tal_free(hin);
deleted = true;
}
/* Can skip over elements due to iterating while deleting. */
} while (deleted);
}
/* BOLT #2:
*
* For HTLCs we offer: the timeout deadline when we have to fail the channel
* and time it out on-chain. This is `G` blocks after the HTLC
* `cltv_expiry`; 1 block is reasonable.
*/
static u32 htlc_out_deadline(const struct htlc_out *hout)
{
return hout->cltv_expiry + 1;
}
/* BOLT #2:
*
* For HTLCs we accept and have a preimage: the fulfillment deadline when we
* have to fail the channel and fulfill the HTLC onchain before its
* `cltv_expiry`. This is steps 4-7 above, which means a deadline of `2R+G+S`
* blocks before `cltv_expiry`; 7 blocks is reasonable.
*/
/* We approximate this, by using half the cltv_expiry_delta (3R+2G+2S),
* rounded up. */
static u32 htlc_in_deadline(const struct lightningd *ld,
const struct htlc_in *hin)
{
return hin->cltv_expiry - (ld->config.cltv_expiry_delta + 1)/2;
}
void notify_new_block(struct lightningd *ld, u32 height)
{
bool removed;
/* BOLT #2:
*
* A node ... MUST fail the channel if an HTLC which it offered is in
* either node's current commitment transaction past this timeout
* deadline.
*/
/* FIXME: use db to look this up in one go (earliest deadline per-peer) */
do {
struct htlc_out *hout;
struct htlc_out_map_iter outi;
removed = false;
for (hout = htlc_out_map_first(&ld->htlcs_out, &outi);
hout;
hout = htlc_out_map_next(&ld->htlcs_out, &outi)) {
/* Not timed out yet? */
if (height < htlc_out_deadline(hout))
continue;
/* Peer on chain already? */
if (channel_on_chain(hout->key.channel))
continue;
/* Peer already failed, or we hit it? */
if (hout->key.channel->error)
continue;
channel_fail_permanent(hout->key.channel,
"Offered HTLC %"PRIu64
" %s cltv %u hit deadline",
hout->key.id,
htlc_state_name(hout->hstate),
hout->cltv_expiry);
removed = true;
}
/* Iteration while removing is safe, but can skip entries! */
} while (removed);
/* BOLT #2:
*
* A node MUST estimate a fulfillment deadline for each HTLC it is
* attempting to fulfill. A node ... MUST fail the connection if a
* HTLC it has fulfilled is in either node's current commitment
* transaction past this fulfillment deadline.
*/
do {
struct htlc_in *hin;
struct htlc_in_map_iter ini;
removed = false;
for (hin = htlc_in_map_first(&ld->htlcs_in, &ini);
hin;
hin = htlc_in_map_next(&ld->htlcs_in, &ini)) {
struct channel *channel = hin->key.channel;
/* Not fulfilled? If overdue, that's their problem... */
if (!hin->preimage)
continue;
/* Not timed out yet? */
if (height < htlc_in_deadline(ld, hin))
continue;
/* Peer on chain already? */
if (channel_on_chain(channel))
continue;
/* Peer already failed, or we hit it? */
if (channel->error)
continue;
channel_fail_permanent(channel,
"Fulfilled HTLC %"PRIu64
" %s cltv %u hit deadline",
hin->key.id,
htlc_state_name(hin->hstate),
hin->cltv_expiry);
removed = true;
}
/* Iteration while removing is safe, but can skip entries! */
} while (removed);
}
void notify_feerate_change(struct lightningd *ld)
{
struct peer *peer;
/* FIXME: We should notify onchaind about NORMAL fee change in case
* it's going to generate more txs. */
list_for_each(&ld->peers, peer, list) {
struct channel *channel = peer_active_channel(peer);
u8 *msg;
if (!channel || !channel_fees_can_change(channel))
continue;
/* FIXME: We choose not to drop to chain if we can't contact
* peer. We *could* do so, however. */
if (!channel->owner)
continue;
msg = towire_channel_feerates(channel,
get_feerate(ld->topology,
FEERATE_IMMEDIATE),
feerate_min(ld),
feerate_max(ld));
subd_send_msg(channel->owner, take(msg));
}
}
#if DEVELOPER
static void json_dev_ignore_htlcs(struct command *cmd, const char *buffer,
const jsmntok_t *params)
{
jsmntok_t *nodeidtok, *ignoretok;
struct peer *peer;
if (!json_get_params(cmd, buffer, params,
"id", &nodeidtok,
"ignore", &ignoretok,
NULL)) {
return;
}
peer = peer_from_json(cmd->ld, buffer, nodeidtok);
if (!peer) {
command_fail(cmd, "Could not find channel with that peer");
return;
}
if (!json_tok_bool(buffer, ignoretok, &peer->ignore_htlcs)) {
command_fail(cmd, "Invalid boolean '%.*s'",
ignoretok->end - ignoretok->start,
buffer + ignoretok->start);
return;
}
command_success(cmd, null_response(cmd));
}
static const struct json_command dev_ignore_htlcs = {
"dev-ignore-htlcs", json_dev_ignore_htlcs,
"Set ignoring incoming HTLCs for peer {id} to {ignore}", false,
"Set/unset ignoring of all incoming HTLCs. For testing only."
};
AUTODATA(json_command, &dev_ignore_htlcs);
#endif /* DEVELOPER */