Browse Source

lightningd: explictly split htlc_in and htlc_out.

They share some fields, but they're basically different, and it's clearest
to treat them differently in most places.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 8 years ago
parent
commit
207eeae1f7
  1. 147
      lightningd/htlc_end.c
  2. 134
      lightningd/htlc_end.h
  3. 3
      lightningd/lightningd.c
  4. 3
      lightningd/lightningd.h
  5. 66
      lightningd/pay.c
  6. 8
      lightningd/pay.h
  7. 497
      lightningd/peer_htlcs.c

147
lightningd/htlc_end.c

@ -1,39 +1,156 @@
#include <ccan/cast/cast.h>
#include <ccan/crypto/siphash24/siphash24.h>
#include <ccan/tal/str/str.h>
#include <ccan/tal/tal.h>
#include <daemon/htlc.h>
#include <daemon/log.h>
#include <daemon/pseudorand.h>
#include <lightningd/htlc_end.h>
#include <stdio.h>
size_t hash_htlc_end(const struct htlc_end *e)
size_t hash_htlc_key(const struct htlc_key *k)
{
struct siphash24_ctx ctx;
siphash24_init(&ctx, siphash_seed());
/* peer doesn't move while in this hash, so we just hash pointer. */
siphash24_update(&ctx, &e->peer, sizeof(e->peer));
siphash24_u64(&ctx, e->htlc_id);
siphash24_u8(&ctx, e->which_end);
siphash24_update(&ctx, &k->peer, sizeof(k->peer));
siphash24_u64(&ctx, k->id);
return siphash24_done(&ctx);
}
struct htlc_end *find_htlc_end(const struct htlc_end_map *map,
struct htlc_in *find_htlc_in(const struct htlc_in_map *map,
const struct peer *peer,
u64 htlc_id,
enum htlc_end_type which_end)
u64 htlc_id)
{
const struct htlc_end key = { which_end, (struct peer *)peer, htlc_id,
0, NULL, NULL };
const struct htlc_key key = { (struct peer *)peer, htlc_id };
return htlc_in_map_get(map, &key);
}
static void remove_htlc_in(struct htlc_in *hend, struct htlc_in_map *map)
{
htlc_in_map_del(map, hend);
}
void connect_htlc_in(struct htlc_in_map *map, struct htlc_in *hend)
{
tal_add_destructor2(hend, remove_htlc_in, map);
htlc_in_map_add(map, hend);
}
struct htlc_out *find_htlc_out(const struct htlc_out_map *map,
const struct peer *peer,
u64 htlc_id)
{
const struct htlc_key key = { (struct peer *)peer, htlc_id };
return htlc_out_map_get(map, &key);
}
static void remove_htlc_out(struct htlc_out *hend, struct htlc_out_map *map)
{
htlc_out_map_del(map, hend);
}
void connect_htlc_out(struct htlc_out_map *map, struct htlc_out *hend)
{
tal_add_destructor2(hend, remove_htlc_out, map);
htlc_out_map_add(map, hend);
}
return htlc_end_map_get(map, &key);
static void *PRINTF_FMT(3,4)
corrupt(const void *ptr, const char *abortstr, const char *fmt, ...)
{
if (abortstr) {
char *p;
va_list ap;
va_start(ap, fmt);
p = tal_vfmt(NULL, fmt, ap);
fatal("%s:%s\n", abortstr, p);
va_end(ap);
}
return NULL;
}
static void remove_htlc_end(struct htlc_end *hend, struct htlc_end_map *map)
struct htlc_in *htlc_in_check(const struct htlc_in *hin, const char *abortstr)
{
htlc_end_map_del(map, hend);
if (hin->msatoshi == 0)
return corrupt(hin, abortstr, "zero msatoshi");
else if (htlc_state_owner(hin->hstate) != REMOTE)
return corrupt(hin, abortstr, "invalid state %s",
htlc_state_name(hin->hstate));
else if (hin->failuremsg && hin->preimage)
return corrupt(hin, abortstr, "Both failed and succeeded");
return cast_const(struct htlc_in *, hin);
}
struct htlc_in *new_htlc_in(const tal_t *ctx,
struct peer *peer, u64 id,
u64 msatoshi, u32 cltv_expiry,
const struct sha256 *payment_hash,
const struct secret *shared_secret,
const u8 *onion_routing_packet)
{
struct htlc_in *hin = tal(ctx, struct htlc_in);
hin->key.peer = peer;
hin->key.id = id;
hin->msatoshi = msatoshi;
hin->cltv_expiry = cltv_expiry;
hin->payment_hash = *payment_hash;
hin->shared_secret = *shared_secret;
memcpy(hin->onion_routing_packet, onion_routing_packet,
sizeof(hin->onion_routing_packet));
hin->hstate = RCVD_ADD_COMMIT;
hin->failuremsg = NULL;
hin->preimage = NULL;
return htlc_in_check(hin, "new_htlc_in");
}
void connect_htlc_end(struct htlc_end_map *map, struct htlc_end *hend)
struct htlc_out *htlc_out_check(const struct htlc_out *hout,
const char *abortstr)
{
tal_add_destructor2(hend, remove_htlc_end, map);
htlc_end_map_add(map, hend);
if (hout->msatoshi == 0)
return corrupt(hout, abortstr, "zero msatoshi");
else if (htlc_state_owner(hout->hstate) != LOCAL)
return corrupt(hout, abortstr, "invalid state %s",
htlc_state_name(hout->hstate));
else if (hout->failuremsg && hout->preimage)
return corrupt(hout, abortstr, "Both failed and succeeded");
else if (!hout->in && !hout->pay_command)
return corrupt(hout, abortstr,
"Neither hout->in nor paycommand");
return cast_const(struct htlc_out *, hout);
}
/* You need to set the ID, then connect_htlc_out this! */
struct htlc_out *new_htlc_out(const tal_t *ctx,
struct peer *peer,
u64 msatoshi, u32 cltv_expiry,
const struct sha256 *payment_hash,
const u8 *onion_routing_packet,
struct htlc_in *in,
struct pay_command *pc)
{
struct htlc_out *hout = tal(ctx, struct htlc_out);
hout->key.peer = peer;
hout->msatoshi = msatoshi;
hout->cltv_expiry = cltv_expiry;
hout->payment_hash = *payment_hash;
memcpy(hout->onion_routing_packet, onion_routing_packet,
sizeof(hout->onion_routing_packet));
hout->hstate = SENT_ADD_HTLC;
hout->failuremsg = NULL;
hout->preimage = NULL;
hout->in = in;
hout->pay_command = pc;
return htlc_out_check(hout, "new_htlc_out");
}

134
lightningd/htlc_end.h

@ -6,69 +6,117 @@
#include <daemon/htlc_state.h>
#include <lightningd/sphinx.h>
/* A HTLC has a source and destination: if other is NULL, it's this node.
*
* The main daemon simply shuffles them back and forth.
*/
enum htlc_end_type { HTLC_SRC, HTLC_DST };
struct htlc_end {
enum htlc_end_type which_end;
/* We look up HTLCs by peer & id */
struct htlc_key {
struct peer *peer;
u64 htlc_id;
u64 msatoshis;
u64 id;
};
struct htlc_end *other_end;
/* If this is driven by a command. */
struct pay_command *pay_command;
/* Incoming HTLC */
struct htlc_in {
struct htlc_key key;
u64 msatoshi;
u32 cltv_expiry;
struct sha256 payment_hash;
/* FIXME: We really only need this in the database. */
enum htlc_state hstate;
/* Temporary information, while we resolve the next hop */
u8 *next_onion;
struct short_channel_id next_channel;
u64 amt_to_forward;
u32 outgoing_cltv_value;
/* Onion information */
u8 onion_routing_packet[TOTAL_PACKET_SIZE];
/* Shared secret for us to send any failure message. */
struct secret shared_secret;
/* If they failed HTLC, here's the message. */
const u8 *failuremsg;
/* If they fulfilled, here's the preimage. */
struct preimage *preimage;
};
struct htlc_out {
struct htlc_key key;
u64 msatoshi;
u32 cltv_expiry;
struct sha256 payment_hash;
/* If they failed HTLC, here's the message. */
const u8 *fail_msg;
enum htlc_state hstate;
/* Onion information */
u8 onion_routing_packet[TOTAL_PACKET_SIZE];
/* If we failed HTLC, here's the message. */
const u8 *failuremsg;
/* If they succeeded, here's the preimage. */
struct sha256 *preimage;
/* If we fulfilled, here's the preimage. */
struct preimage *preimage;
/* If we are forwarding, remember the shared secret for an
* eventual reply */
struct secret *shared_secret;
/* Where it's from, if not going to us. */
struct htlc_in *in;
/* If we are the origin, remember all shared secrets, so we
* can unwrap an eventual reply */
struct secret *path_secrets;
/* Otherwise, payment command which created it. */
struct pay_command *pay_command;
};
static inline const struct htlc_end *keyof_htlc_end(const struct htlc_end *e)
static inline const struct htlc_key *keyof_htlc_in(const struct htlc_in *in)
{
return &in->key;
}
static inline const struct htlc_key *keyof_htlc_out(const struct htlc_out *out)
{
return e;
return &out->key;
}
size_t hash_htlc_end(const struct htlc_end *e);
size_t hash_htlc_key(const struct htlc_key *htlc_key);
static inline bool htlc_in_eq(const struct htlc_in *in, const struct htlc_key *k)
{
return in->key.peer == k->peer && in->key.id == k->id;
}
static inline bool htlc_end_eq(const struct htlc_end *a,
const struct htlc_end *b)
static inline bool htlc_out_eq(const struct htlc_out *out,
const struct htlc_key *k)
{
return a->peer == b->peer
&& a->htlc_id == b->htlc_id
&& a->which_end == b->which_end;
return out->key.peer == k->peer && out->key.id == k->id;
}
HTABLE_DEFINE_TYPE(struct htlc_end, keyof_htlc_end, hash_htlc_end, htlc_end_eq,
htlc_end_map);
struct htlc_end *find_htlc_end(const struct htlc_end_map *map,
HTABLE_DEFINE_TYPE(struct htlc_in, keyof_htlc_in, hash_htlc_key, htlc_in_eq,
htlc_in_map);
HTABLE_DEFINE_TYPE(struct htlc_out, keyof_htlc_out, hash_htlc_key, htlc_out_eq,
htlc_out_map);
struct htlc_in *find_htlc_in(const struct htlc_in_map *map,
const struct peer *peer,
u64 htlc_id);
struct htlc_out *find_htlc_out(const struct htlc_out_map *map,
const struct peer *peer,
u64 htlc_id,
enum htlc_end_type which_end);
u64 htlc_id);
/* You still need to connect_htlc_in this! */
struct htlc_in *new_htlc_in(const tal_t *ctx,
struct peer *peer, u64 id,
u64 msatoshi, u32 cltv_expiry,
const struct sha256 *payment_hash,
const struct secret *shared_secret,
const u8 *onion_routing_packet);
/* You need to set the ID, then connect_htlc_out this! */
struct htlc_out *new_htlc_out(const tal_t *ctx,
struct peer *peer,
u64 msatoshi, u32 cltv_expiry,
const struct sha256 *payment_hash,
const u8 *onion_routing_packet,
struct htlc_in *in,
struct pay_command *pc);
void connect_htlc_in(struct htlc_in_map *map, struct htlc_in *hin);
void connect_htlc_out(struct htlc_out_map *map, struct htlc_out *hout);
void connect_htlc_end(struct htlc_end_map *map, struct htlc_end *hend);
struct htlc_out *htlc_out_check(const struct htlc_out *hout,
const char *abortstr);
struct htlc_in *htlc_in_check(const struct htlc_in *hin, const char *abortstr);
#endif /* LIGHTNING_LIGHTNINGD_HTLC_END_H */

3
lightningd/lightningd.c

@ -108,7 +108,8 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
list_head_init(&ld->peers);
ld->peer_counter = 0;
ld->dev_debug_subdaemon = NULL;
htlc_end_map_init(&ld->htlc_ends);
htlc_in_map_init(&ld->htlcs_in);
htlc_out_map_init(&ld->htlcs_out);
ld->dev_disconnect_fd = -1;
ld->dstate.log_book = new_log_book(&ld->dstate, 20*1024*1024,LOG_INFORM);
ld->log = ld->dstate.base_log = new_log(&ld->dstate,

3
lightningd/lightningd.h

@ -54,7 +54,8 @@ struct lightningd {
int dev_disconnect_fd;
/* HTLCs in flight. */
struct htlc_end_map htlc_ends;
struct htlc_in_map htlcs_in;
struct htlc_out_map htlcs_out;
u32 broadcast_interval;

66
lightningd/pay.c

@ -20,10 +20,13 @@ struct pay_command {
u64 msatoshi;
const struct pubkey *ids;
/* Set if this is in progress. */
struct htlc_end *out;
struct htlc_out *out;
/* Preimage if this succeeded. */
const struct preimage *rval;
struct command *cmd;
/* Remember all shared secrets, so we can unwrap an eventual failure */
struct secret *path_secrets;
};
static void json_pay_success(struct command *cmd, const struct preimage *rval)
@ -57,25 +60,46 @@ static void json_pay_failed(struct pay_command *pc,
pc->out = NULL;
}
void payment_succeeded(struct lightningd *ld, struct htlc_end *dst,
void payment_succeeded(struct lightningd *ld, struct htlc_out *hout,
const struct preimage *rval)
{
assert(!dst->pay_command->rval);
dst->pay_command->rval = tal_dup(dst->pay_command,
struct preimage, rval);
json_pay_success(dst->pay_command->cmd, rval);
dst->pay_command->out = NULL;
assert(!hout->pay_command->rval);
hout->pay_command->rval = tal_dup(hout->pay_command,
struct preimage, rval);
json_pay_success(hout->pay_command->cmd, rval);
hout->pay_command->out = NULL;
}
/* FIXME: sender is NULL for now: need crypto! */
void payment_failed(struct lightningd *ld, struct htlc_end *dst,
const struct pubkey *sender,
enum onion_type failure_code)
void payment_failed(struct lightningd *ld, const struct htlc_out *hout)
{
struct pay_command *pc = hout->pay_command;
enum onion_type failcode;
struct onionreply *reply;
reply = unwrap_onionreply(pc, pc->path_secrets,
tal_count(pc->path_secrets),
hout->failuremsg);
if (!reply) {
log_info(hout->key.peer->log,
"htlc %"PRIu64" failed with bad reply (%s)",
hout->key.id,
tal_hex(pc, hout->failuremsg));
failcode = WIRE_PERMANENT_NODE_FAILURE;
} else {
failcode = fromwire_peektype(reply->msg);
log_info(hout->key.peer->log,
"htlc %"PRIu64" failed from %ith node with code 0x%04x (%s)",
hout->key.id,
reply->origin_index,
failcode, onion_type_name(failcode));
}
/* FIXME: save ids we can turn reply->origin_index into sender. */
/* FIXME: check for routing failure / perm fail. */
/* check_for_routing_failure(i, sender, failure_code); */
json_pay_failed(dst->pay_command, sender, failure_code,
"reply from remote");
json_pay_failed(pc, NULL, failcode, "reply from remote");
}
static bool rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds,
@ -85,7 +109,7 @@ static bool rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds,
u8 *failstr;
if (!fromwire_channel_offer_htlc_reply(msg, msg, NULL,
&pc->out->htlc_id,
&pc->out->key.id,
&failcode, &failstr)) {
json_pay_failed(pc, &subd->ld->dstate.id, -1,
"daemon bad response");
@ -103,7 +127,7 @@ static bool rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds,
/* HTLC endpoint now owned by lightningd. */
tal_steal(subd->ld, pc->out);
connect_htlc_end(&subd->ld->htlc_ends, pc->out);
connect_htlc_out(&subd->ld->htlcs_out, pc->out);
return true;
}
@ -327,16 +351,10 @@ static void json_sendpay(struct command *cmd,
pc->rval = NULL;
pc->ids = tal_steal(pc, ids);
pc->msatoshi = lastamount;
pc->path_secrets = tal_steal(pc, path_secrets);
pc->out = tal(pc, struct htlc_end);
pc->out->which_end = HTLC_DST;
pc->out->hstate = SENT_ADD_HTLC;
pc->out->peer = peer;
pc->out->fail_msg = NULL;
pc->out->msatoshis = amount;
pc->out->other_end = NULL;
pc->out->pay_command = pc;
pc->out->path_secrets = tal_steal(pc->out, path_secrets);
pc->out = new_htlc_out(pc, peer, amount, first_hop_data.outgoing_cltv,
&rhash, onion, NULL, pc);
log_info(ld->log, "Sending %"PRIu64" over %zu hops to deliver %"PRIu64,
amount, n_hops, lastamount);

8
lightningd/pay.h

@ -3,16 +3,14 @@
#include "config.h"
#include <wire/gen_onion_wire.h>
struct htlc_end;
struct htlc_out;
struct lightningd;
struct preimage;
struct pubkey;
void payment_succeeded(struct lightningd *ld, struct htlc_end *dst,
void payment_succeeded(struct lightningd *ld, struct htlc_out *hout,
const struct preimage *rval);
void payment_failed(struct lightningd *ld, struct htlc_end *dst,
const struct pubkey *sender,
enum onion_type failure_code);
void payment_failed(struct lightningd *ld, const struct htlc_out *hout);
#endif /* LIGHTNING_LIGHTNINGD_PAY_H */

497
lightningd/peer_htlcs.c

@ -21,28 +21,28 @@
* required to do penalty transaction */
static void save_htlc_stub(struct lightningd *ld,
struct peer *peer,
enum htlc_end_type htlc_end_type,
enum side owner,
u32 cltv_value,
const struct sha256 *payment_hash)
{
/* FIXME: remember peer, direction, cltv and RIPEMD160(hash) */
/* FIXME: remember peer, side, cltv and RIPEMD160(hash) */
}
/* This obfuscates the message, whether local or forwarded. */
static void relay_htlc_failmsg(struct htlc_end *hend)
static void relay_htlc_failmsg(struct htlc_in *hin)
{
u8 *reply;
if (!hend->peer->owner)
if (!hin->key.peer->owner)
return;
reply = wrap_onionreply(hend, hend->shared_secret, hend->fail_msg);
subd_send_msg(hend->peer->owner,
take(towire_channel_fail_htlc(hend, hend->htlc_id, reply)));
reply = wrap_onionreply(hin, &hin->shared_secret, hin->failuremsg);
subd_send_msg(hin->key.peer->owner,
take(towire_channel_fail_htlc(hin, hin->key.id, reply)));
tal_free(reply);
}
static u8 *make_failmsg(const tal_t *ctx, const struct htlc_end *hend,
static u8 *make_failmsg(const tal_t *ctx, const struct htlc_in *hin,
enum onion_type failcode,
const struct sha256 *onion_sha, const u8 *channel_update)
{
@ -72,9 +72,9 @@ static u8 *make_failmsg(const tal_t *ctx, const struct htlc_end *hend,
case WIRE_UNKNOWN_NEXT_PEER:
return towire_unknown_next_peer(ctx);
case WIRE_AMOUNT_BELOW_MINIMUM:
return towire_amount_below_minimum(ctx, hend->msatoshis, channel_update);
return towire_amount_below_minimum(ctx, hin->msatoshi, channel_update);
case WIRE_FEE_INSUFFICIENT:
return towire_fee_insufficient(ctx, hend->msatoshis, channel_update);
return towire_fee_insufficient(ctx, hin->msatoshi, channel_update);
case WIRE_INCORRECT_CLTV_EXPIRY:
/* FIXME: ctlv! */
return towire_incorrect_cltv_expiry(ctx, 0, channel_update);
@ -90,28 +90,28 @@ static u8 *make_failmsg(const tal_t *ctx, const struct htlc_end *hend,
/* FIXME: ctlv! */
return towire_final_incorrect_cltv_expiry(ctx, 0);
case WIRE_FINAL_INCORRECT_HTLC_AMOUNT:
return towire_final_incorrect_htlc_amount(ctx, hend->msatoshis);
return towire_final_incorrect_htlc_amount(ctx, hin->msatoshi);
}
abort();
}
static void fail_htlc(struct htlc_end *hend, enum onion_type failcode,
static void fail_htlc(struct htlc_in *hin, enum onion_type failcode,
const struct sha256 *onion_sha)
{
u8 *msg;
log_broken(hend->peer->log, "failed htlc %"PRIu64" code 0x%04x (%s)",
hend->htlc_id, failcode, onion_type_name(failcode));
log_broken(hin->key.peer->log, "failed htlc %"PRIu64" code 0x%04x (%s)",
hin->key.id, failcode, onion_type_name(failcode));
if (failcode & UPDATE) {
/* FIXME: Ask gossip daemon for channel_update. */
}
msg = make_failmsg(hend, hend, failcode, onion_sha, NULL);
hend->fail_msg = create_onionreply(hend, hend->shared_secret, msg);
msg = make_failmsg(hin, hin, failcode, onion_sha, NULL);
hin->failuremsg = create_onionreply(hin, &hin->shared_secret, msg);
tal_free(msg);
relay_htlc_failmsg(hend);
relay_htlc_failmsg(hin);
}
/* BOLT #4:
@ -131,14 +131,14 @@ static void fail_htlc(struct htlc_end *hend, enum onion_type failcode,
* 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_end *hend,
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(hend->peer->ld->log, "HTLC %"PRIu64" incorrect amount:"
log_debug(hin->key.peer->ld->log, "HTLC %"PRIu64" incorrect amount:"
" %"PRIu64" in, %"PRIu64" out, fee reqd %"PRIu64,
hend->htlc_id, amt_in_htlc, amt_to_forward, fee);
hin->key.id, amt_in_htlc, amt_to_forward, fee);
return false;
}
@ -160,32 +160,32 @@ static bool check_amount(struct htlc_end *hend,
* `outgoing_cltv_value` whether it is the final hop or not, to avoid
* leaking that information.
*/
static bool check_ctlv(struct htlc_end *hend,
static bool check_ctlv(struct htlc_in *hin,
u32 ctlv_expiry, u32 outgoing_cltv_value, u32 delta)
{
if (ctlv_expiry - delta == outgoing_cltv_value)
return true;
log_debug(hend->peer->ld->log, "HTLC %"PRIu64" incorrect CLTV:"
log_debug(hin->key.peer->ld->log, "HTLC %"PRIu64" incorrect CLTV:"
" %u in, %u out, delta reqd %u",
hend->htlc_id, ctlv_expiry, outgoing_cltv_value, delta);
hin->key.id, ctlv_expiry, outgoing_cltv_value, delta);
return false;
}
static void fulfill_htlc(struct htlc_end *hend, const struct preimage *preimage)
static void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage)
{
u8 *msg;
hend->peer->balance[LOCAL] += hend->msatoshis;
hend->peer->balance[REMOTE] -= hend->msatoshis;
hin->key.peer->balance[LOCAL] += hin->msatoshi;
hin->key.peer->balance[REMOTE] -= hin->msatoshi;
/* FIXME: fail the peer if it doesn't tell us that htlc fulfill is
* committed before deadline.
*/
msg = towire_channel_fulfill_htlc(hend->peer, hend->htlc_id, preimage);
subd_send_msg(hend->peer->owner, take(msg));
msg = towire_channel_fulfill_htlc(hin->key.peer, hin->key.id, preimage);
subd_send_msg(hin->key.peer->owner, take(msg));
}
static void handle_localpay(struct htlc_end *hend,
static void handle_localpay(struct htlc_in *hin,
u32 cltv_expiry,
const struct sha256 *payment_hash,
u64 amt_to_forward,
@ -193,6 +193,7 @@ static void handle_localpay(struct htlc_end *hend,
{
enum onion_type failcode;
struct invoice *invoice;
struct lightningd *ld = hin->key.peer->ld;
/* BOLT #4:
*
@ -203,7 +204,7 @@ static void handle_localpay(struct htlc_end *hend,
* 2. data:
* * [`4`:`incoming_htlc_amt`]
*/
if (!check_amount(hend, amt_to_forward, hend->msatoshis, 0)) {
if (!check_amount(hin, amt_to_forward, hin->msatoshi, 0)) {
failcode = WIRE_FINAL_INCORRECT_HTLC_AMOUNT;
goto fail;
}
@ -217,12 +218,12 @@ static void handle_localpay(struct htlc_end *hend,
* 2. data:
* * [`4`:`cltv_expiry`]
*/
if (!check_ctlv(hend, cltv_expiry, outgoing_cltv_value, 0)) {
if (!check_ctlv(hin, cltv_expiry, outgoing_cltv_value, 0)) {
failcode = WIRE_FINAL_INCORRECT_CLTV_EXPIRY;
goto fail;
}
invoice = find_unpaid(hend->peer->ld->dstate.invoices, payment_hash);
invoice = find_unpaid(ld->dstate.invoices, payment_hash);
if (!invoice) {
failcode = WIRE_UNKNOWN_PAYMENT_HASH;
goto fail;
@ -238,10 +239,10 @@ static void handle_localpay(struct htlc_end *hend,
*
* 1. type: PERM|16 (`incorrect_payment_amount`)
*/
if (hend->msatoshis < invoice->msatoshi) {
if (hin->msatoshi < invoice->msatoshi) {
failcode = WIRE_INCORRECT_PAYMENT_AMOUNT;
goto fail;
} else if (hend->msatoshis > invoice->msatoshi * 2) {
} else if (hin->msatoshi > invoice->msatoshi * 2) {
failcode = WIRE_INCORRECT_PAYMENT_AMOUNT;
goto fail;
}
@ -250,25 +251,25 @@ static void handle_localpay(struct htlc_end *hend,
*
* If the `cltv_expiry` is too low, the final node MUST fail the HTLC:
*/
if (get_block_height(hend->peer->ld->topology)
+ hend->peer->ld->dstate.config.deadline_blocks >= cltv_expiry) {
log_debug(hend->peer->log,
if (get_block_height(ld->topology) + ld->dstate.config.deadline_blocks
>= cltv_expiry) {
log_debug(hin->key.peer->log,
"Expiry cltv %u too close to current %u + deadline %u",
cltv_expiry,
get_block_height(hend->peer->ld->topology),
hend->peer->ld->dstate.config.deadline_blocks);
get_block_height(ld->topology),
ld->dstate.config.deadline_blocks);
failcode = WIRE_FINAL_EXPIRY_TOO_SOON;
goto fail;
}
log_info(hend->peer->ld->log, "Resolving invoice '%s' with HTLC %"PRIu64,
invoice->label, hend->htlc_id);
fulfill_htlc(hend, &invoice->r);
resolve_invoice(&hend->peer->ld->dstate, invoice);
log_info(ld->log, "Resolving invoice '%s' with HTLC %"PRIu64,
invoice->label, hin->key.id);
fulfill_htlc(hin, &invoice->r);
resolve_invoice(&ld->dstate, invoice);
return;
fail:
fail_htlc(hend, failcode, NULL);
fail_htlc(hin, failcode, NULL);
}
/*
@ -276,50 +277,50 @@ fail:
*
* We could queue this and wait for it to come back, but this is simple.
*/
static void hend_subd_died(struct htlc_end *hend)
static void hend_subd_died(struct htlc_out *hout)
{
log_debug(hend->other_end->peer->owner->log,
log_debug(hout->in->key.peer->owner->log,
"Failing HTLC %"PRIu64" due to peer death",
hend->other_end->htlc_id);
hout->in->key.id);
fail_htlc(hend->other_end, WIRE_TEMPORARY_CHANNEL_FAILURE, NULL);
fail_htlc(hout->in, WIRE_TEMPORARY_CHANNEL_FAILURE, NULL);
}
/* This is where channeld gives us the HTLC id, and also reports if it
* failed immediately. */
static bool rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds,
struct htlc_end *hend)
struct htlc_out *hout)
{
u16 failure_code;
u8 *failurestr;
if (!fromwire_channel_offer_htlc_reply(msg, msg, NULL,
&hend->htlc_id,
&hout->key.id,
&failure_code,
&failurestr)) {
log_broken(subd->log, "Bad channel_offer_htlc_reply");
tal_free(hend);
tal_free(hout);
return false;
}
if (failure_code) {
log_debug(hend->other_end->peer->owner->log,
log_debug(hout->in->key.peer->owner->log,
"HTLC failed from other daemon: %s (%.*s)",
onion_type_name(failure_code),
(int)tal_len(failurestr), (char *)failurestr);
fail_htlc(hend->other_end, failure_code, NULL);
fail_htlc(hout->in, failure_code, NULL);
return true;
}
/* Add it to lookup table now we know id. */
connect_htlc_end(&subd->ld->htlc_ends, hend);
connect_htlc_out(&subd->ld->htlcs_out, hout);
/* When channeld includes it in commitment, we'll make it persistent. */
return true;
}
static void forward_htlc(struct htlc_end *hend,
static void forward_htlc(struct htlc_in *hin,
u32 cltv_expiry,
const struct sha256 *payment_hash,
u64 amt_to_forward,
@ -330,8 +331,9 @@ static void forward_htlc(struct htlc_end *hend,
u8 *msg;
enum onion_type failcode;
u64 fee;
struct lightningd *ld = hend->peer->ld;
struct lightningd *ld = hin->key.peer->ld;
struct peer *next = peer_by_id(ld, next_hop);
struct htlc_out *out;
if (!next) {
failcode = WIRE_UNKNOWN_NEXT_PEER;
@ -366,12 +368,12 @@ static void forward_htlc(struct htlc_end *hend,
}
fee = ld->dstate.config.fee_base
+ amt_to_forward * ld->dstate.config.fee_per_satoshi / 1000000;
if (!check_amount(hend, amt_to_forward, hend->msatoshis, fee)) {
if (!check_amount(hin, amt_to_forward, hin->msatoshi, fee)) {
failcode = WIRE_FEE_INSUFFICIENT;
goto fail;
}
if (!check_ctlv(hend, cltv_expiry, outgoing_cltv_value,
if (!check_ctlv(hin, cltv_expiry, outgoing_cltv_value,
ld->dstate.config.deadline_blocks)) {
failcode = WIRE_INCORRECT_CLTV_EXPIRY;
goto fail;
@ -388,7 +390,7 @@ static void forward_htlc(struct htlc_end *hend,
*/
if (get_block_height(next->ld->topology)
+ next->ld->dstate.config.deadline_blocks >= outgoing_cltv_value) {
log_debug(hend->peer->log,
log_debug(hin->key.peer->log,
"Expiry cltv %u too close to current %u + deadline %u",
outgoing_cltv_value,
get_block_height(next->ld->topology),
@ -398,32 +400,35 @@ static void forward_htlc(struct htlc_end *hend,
}
/* Make sure daemon owns it, in case it fails. */
hend->other_end = tal(next->owner, struct htlc_end);
hend->other_end->hstate = SENT_ADD_HTLC;
hend->other_end->which_end = HTLC_DST;
hend->other_end->peer = next;
hend->other_end->other_end = hend;
hend->other_end->pay_command = NULL;
hend->other_end->msatoshis = amt_to_forward;
hend->other_end->outgoing_cltv_value = outgoing_cltv_value;
hend->other_end->payment_hash = hend->payment_hash;
tal_add_destructor(hend->other_end, hend_subd_died);
out = new_htlc_out(next->owner, next, amt_to_forward,
outgoing_cltv_value, &hin->payment_hash,
next_onion, hin, NULL);
tal_add_destructor(out, hend_subd_died);
msg = towire_channel_offer_htlc(next, amt_to_forward,
outgoing_cltv_value,
payment_hash, next_onion);
subd_req(next->owner, next->owner, take(msg), -1, 0,
rcvd_htlc_reply, hend->other_end);
rcvd_htlc_reply, out);
return;
fail:
fail_htlc(hend, failcode, NULL);
fail_htlc(hin, failcode, NULL);
}
/* 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 bool channel_resolve_reply(struct subd *gossip, const u8 *msg,
const int *fds, struct htlc_end *hend)
const int *fds, struct gossip_resolve *gr)
{
struct pubkey *nodes, *peer_id;
@ -435,7 +440,7 @@ static bool channel_resolve_reply(struct subd *gossip, const u8 *msg,
}
if (tal_count(nodes) == 0) {
fail_htlc(hend, WIRE_UNKNOWN_NEXT_PEER, NULL);
fail_htlc(gr->hin, WIRE_UNKNOWN_NEXT_PEER, NULL);
return true;
} else if (tal_count(nodes) != 2) {
log_broken(gossip->log,
@ -451,18 +456,18 @@ static bool channel_resolve_reply(struct subd *gossip, const u8 *msg,
peer_id = &nodes[0];
}
forward_htlc(hend, hend->cltv_expiry, &hend->payment_hash,
hend->amt_to_forward, hend->outgoing_cltv_value, peer_id,
hend->next_onion);
/* FIXME(cdecker) Cleanup things we stuffed into hend before (maybe?) */
forward_htlc(gr->hin, gr->hin->cltv_expiry, &gr->hin->payment_hash,
gr->amt_to_forward, gr->outgoing_cltv_value, peer_id,
gr->next_onion);
tal_free(gr);
return true;
}
static bool hend_update_state(struct peer *peer,
struct htlc_end *hend,
enum htlc_state newstate)
static bool state_update_ok(struct peer *peer,
enum htlc_state oldstate, enum htlc_state newstate,
u64 htlc_id, const char *dir)
{
enum htlc_state expected = hend->hstate + 1;
enum htlc_state expected = oldstate + 1;
/* We never get told about RCVD_REMOVE_HTLC or SENT_REMOVE_HTLC, so
* skip over those (we initialize in SENT_ADD_HTLC / RCVD_ADD_COMMIT, so
@ -473,21 +478,42 @@ static bool hend_update_state(struct peer *peer,
expected = SENT_REMOVE_COMMIT;
if (newstate != expected) {
log_broken(peer->log, "HTLC %"PRIu64" invalid update %s->%s",
hend->htlc_id,
htlc_state_name(hend->hstate),
log_broken(peer->log, "HTLC %s %"PRIu64" invalid update %s->%s",
dir, htlc_id,
htlc_state_name(oldstate),
htlc_state_name(newstate));
return false;
}
log_debug(peer->log, "%s HTLC %"PRIu64" %s->%s",
hend->which_end == HTLC_SRC ? "Their" : "Our",
hend->htlc_id,
htlc_state_name(hend->hstate),
htlc_state_name(newstate));
log_debug(peer->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 peer *peer,
struct htlc_in *hin,
enum htlc_state newstate)
{
if (!state_update_ok(peer, hin->hstate, newstate, hin->key.id, "in"))
return false;
/* FIXME: db commit */
hin->hstate = newstate;
htlc_in_check(hin, __func__);
return true;
}
static bool htlc_out_update_state(struct peer *peer,
struct htlc_out *hout,
enum htlc_state newstate)
{
if (!state_update_ok(peer, hout->hstate, newstate, hout->key.id, "out"))
return false;
/* FIXME: db commit */
hend->hstate = newstate;
hout->hstate = newstate;
htlc_out_check(hout, __func__);
return true;
}
@ -497,30 +523,34 @@ static bool peer_accepted_htlc(struct peer *peer,
const struct secret *shared_secret,
enum onion_type *failcode)
{
struct htlc_end *hend;
struct htlc_in *hin;
u8 *req;
struct route_step *rs;
struct onionpacket *op;
const tal_t *tmpctx = tal_tmpctx(peer);
hend = find_htlc_end(&peer->ld->htlc_ends, peer, id, HTLC_SRC);
if (!hend) {
hin = find_htlc_in(&peer->ld->htlcs_in, peer, id);
if (!hin) {
log_broken(peer->log,
"peer_got_revoke unknown htlc %"PRIu64, id);
return false;
}
if (!hend_update_state(peer, hend, RCVD_ADD_ACK_REVOCATION))
/* We need to keep this to encrypt failure message replies anyway */
hin->shared_secret = *shared_secret;
if (!htlc_in_update_state(peer, hin, RCVD_ADD_ACK_REVOCATION))
return false;
/* channeld tests this, so it should have set ss to zeroes. */
op = parse_onionpacket(tmpctx, hend->next_onion,
tal_len(hend->next_onion));
op = parse_onionpacket(tmpctx, hin->onion_routing_packet,
sizeof(hin->onion_routing_packet));
if (!op) {
if (!memeqzero(shared_secret, sizeof(*shared_secret))) {
log_broken(peer->log,
"bad onion in got_revoke: %s",
tal_hex(peer, hend->next_onion));
tal_hexstr(peer, hin->onion_routing_packet,
sizeof(hin->onion_routing_packet)));
tal_free(tmpctx);
return false;
}
@ -535,12 +565,10 @@ static bool peer_accepted_htlc(struct peer *peer,
goto out;
}
hend->shared_secret = tal_dup(hend, struct secret, shared_secret);
/* If it's crap, not channeld's fault, just fail it */
rs = process_onionpacket(tmpctx, op, hend->shared_secret->data,
hend->payment_hash.u.u8,
sizeof(hend->payment_hash));
rs = process_onionpacket(tmpctx, op, shared_secret->data,
hin->payment_hash.u.u8,
sizeof(hin->payment_hash));
if (!rs) {
*failcode = WIRE_INVALID_ONION_HMAC;
goto out;
@ -552,23 +580,26 @@ static bool peer_accepted_htlc(struct peer *peer,
goto out;
}
hend->amt_to_forward = rs->hop_data.amt_forward;
hend->outgoing_cltv_value = rs->hop_data.outgoing_cltv;
hend->next_channel = rs->hop_data.channel_id;
if (rs->nextcase == ONION_FORWARD) {
hend->next_onion = serialize_onionpacket(hend, rs->next);
struct gossip_resolve *gr = tal(peer->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,
&hend->next_channel);
&gr->next_channel);
log_debug(peer->log, "Asking gossip to resolve channel %s",
type_to_string(tmpctx, struct short_channel_id,
&hend->next_channel));
subd_req(hend, peer->ld->gossip, req, -1, 0,
channel_resolve_reply, hend);
/* FIXME(cdecker) Stuff all this info into hend */
&gr->next_channel));
subd_req(hin, peer->ld->gossip, req, -1, 0,
channel_resolve_reply, gr);
} else
handle_localpay(hend, hend->cltv_expiry, &hend->payment_hash,
hend->amt_to_forward, hend->outgoing_cltv_value);
handle_localpay(hin, hin->cltv_expiry, &hin->payment_hash,
rs->hop_data.amt_forward,
rs->hop_data.outgoing_cltv);
*failcode = 0;
out:
@ -582,150 +613,145 @@ out:
static bool peer_fulfilled_our_htlc(struct peer *peer,
const struct fulfilled_htlc *fulfilled)
{
struct htlc_end *hend;
struct htlc_out *hout;
hend = find_htlc_end(&peer->ld->htlc_ends, peer, fulfilled->id,
HTLC_DST);
if (!hend) {
hout = find_htlc_out(&peer->ld->htlcs_out, peer, fulfilled->id);
if (!hout) {
log_broken(peer->log,
"fulfilled_our_htlc unknown htlc %"PRIu64,
fulfilled->id);
return false;
}
if (!hend_update_state(peer, hend, RCVD_REMOVE_COMMIT))
if (!htlc_out_update_state(peer, hout, RCVD_REMOVE_COMMIT))
return false;
/* FIXME: Type mismatch. */
hend->preimage = tal(hend, struct sha256);
memcpy(hend->preimage, &fulfilled->payment_preimage,
sizeof(fulfilled->payment_preimage));
BUILD_ASSERT(sizeof(*hend->preimage)
== sizeof(fulfilled->payment_preimage));
hout->preimage = tal_dup(hout, struct preimage,
&fulfilled->payment_preimage);
htlc_out_check(hout, __func__);
/* FIXME: Save to db */
/* They fulfilled our HTLC. Credit them, forward immediately. */
peer->balance[REMOTE] += hend->msatoshis;
peer->balance[LOCAL] -= hend->msatoshis;
peer->balance[REMOTE] += hout->msatoshi;
peer->balance[LOCAL] -= hout->msatoshi;
if (hend->other_end)
fulfill_htlc(hend->other_end, &fulfilled->payment_preimage);
if (hout->in)
fulfill_htlc(hout->in, &fulfilled->payment_preimage);
else
payment_succeeded(peer->ld, hend, &fulfilled->payment_preimage);
payment_succeeded(peer->ld, hout, &fulfilled->payment_preimage);
return true;
}
static bool peer_failed_our_htlc(struct peer *peer,
const struct failed_htlc *failed)
{
struct htlc_end *hend;
struct htlc_out *hout;
hend = find_htlc_end(&peer->ld->htlc_ends, peer, failed->id, HTLC_DST);
if (!hend) {
hout = find_htlc_out(&peer->ld->htlcs_out, peer, failed->id);
if (!hout) {
log_broken(peer->log,
"failed_our_htlc unknown htlc %"PRIu64,
failed->id);
return false;
}
if (!hend_update_state(peer, hend, RCVD_REMOVE_COMMIT))
if (!htlc_out_update_state(peer, hout, RCVD_REMOVE_COMMIT))
return false;
log_debug(peer->log, "Our HTLC %"PRIu64" failed", failed->id);
hend->fail_msg = tal_dup_arr(hend, u8, failed->failreason,
tal_len(failed->failreason), 0);
hout->failuremsg = tal_dup_arr(hout, u8, failed->failreason,
tal_len(failed->failreason), 0);
htlc_out_check(hout, __func__);
return true;
}
static void remove_htlc_in(struct peer *peer, struct htlc_in *hin)
{
htlc_in_check(hin, __func__);
log_debug(peer->log, "Removing in HTLC %"PRIu64" state %s",
hin->key.id, htlc_state_name(hin->hstate));
tal_free(hin);
}
static void remove_hend(struct peer *peer, struct htlc_end *hend)
static void remove_htlc_out(struct peer *peer, struct htlc_out *hout)
{
log_debug(peer->log, "Removing %s hend %"PRIu64" state %s",
hend->which_end == HTLC_DST ? "outgoing" : "incoming",
hend->htlc_id,
htlc_state_name(hend->hstate));
htlc_out_check(hout, __func__);
log_debug(peer->log, "Removing out HTLC %"PRIu64" state %s",
hout->key.id, htlc_state_name(hout->hstate));
/* If it's failed, now we can forward since it's completely locked-in */
if (hend->fail_msg && hend->which_end == HTLC_DST) {
if (hend->other_end) {
hend->other_end->fail_msg
= tal_dup_arr(hend->other_end, u8,
hend->fail_msg,
tal_len(hend->fail_msg), 0);
relay_htlc_failmsg(hend->other_end);
if (hout->failuremsg) {
if (hout->in) {
hout->in->failuremsg
= tal_dup_arr(hout->in, u8,
hout->failuremsg,
tal_len(hout->failuremsg), 0);
relay_htlc_failmsg(hout->in);
} else {
/* FIXME: Avoid copy here! */
enum onion_type failcode;
struct onionreply *reply;
size_t numhops = tal_count(hend->path_secrets);
struct secret *shared_secrets = tal_arr(hend, struct secret, numhops);
for (size_t i=0; i<numhops; i++) {
shared_secrets[i] = hend->path_secrets[i];
}
reply = unwrap_onionreply(hend, shared_secrets, numhops,
hend->fail_msg);
if (!reply) {
log_info(peer->log, "htlc %"PRIu64
" failed with bad reply (%s)",
hend->htlc_id,
tal_hex(hend, hend->fail_msg));
failcode = WIRE_PERMANENT_NODE_FAILURE;
} else {
failcode = fromwire_peektype(reply->msg);
log_info(peer->log, "htlc %"PRIu64
" failed from %ith node with code 0x%04x (%s)",
hend->htlc_id,
reply->origin_index, failcode,
onion_type_name(failcode));
}
/* FIXME: Apply update if it contains it, etc */
payment_failed(peer->ld, hend, NULL, failcode);
payment_failed(peer->ld, hout);
}
}
tal_free(hend);
tal_free(hout);
}
static bool changed_htlc(struct peer *peer,
const struct changed_htlc *changed_htlc)
static bool update_in_htlc(struct peer *peer, u64 id, enum htlc_state newstate)
{
struct htlc_end *hend;
enum htlc_end_type end;
struct htlc_in *hin;
if (htlc_state_owner(changed_htlc->newstate) == LOCAL)
end = HTLC_DST;
else
end = HTLC_SRC;
hin = find_htlc_in(&peer->ld->htlcs_in, peer, id);
if (!hin) {
log_broken(peer->log, "Can't find in HTLC %"PRIu64, id);
return false;
}
hend = find_htlc_end(&peer->ld->htlc_ends, peer, changed_htlc->id, end);
if (!hend) {
log_broken(peer->log,
"Can't find %s HTLC %"PRIu64,
side_to_str(htlc_state_owner(changed_htlc->newstate)),
changed_htlc->id);
if (!htlc_in_update_state(peer, hin, newstate))
return false;
if (newstate == SENT_REMOVE_ACK_REVOCATION)
remove_htlc_in(peer, hin);
return true;
}
static bool update_out_htlc(struct peer *peer, u64 id, enum htlc_state newstate)
{
struct htlc_out *hout;
hout = find_htlc_out(&peer->ld->htlcs_out, peer, id);
if (!hout) {
log_broken(peer->log, "Can't find out HTLC %"PRIu64, id);
return false;
}
if (!hend_update_state(peer, hend, changed_htlc->newstate))
if (!htlc_out_update_state(peer, hout, newstate))
return false;
/* First transition into commitment; now it outlives peer. */
if (changed_htlc->newstate == SENT_ADD_COMMIT) {
tal_del_destructor(hend, hend_subd_died);
tal_steal(peer->ld, hend);
if (newstate == SENT_ADD_COMMIT) {
tal_del_destructor(hout, hend_subd_died);
tal_steal(peer->ld, hout);
/* From now onwards, penalty tx might need this */
save_htlc_stub(peer->ld, peer, end, hend->outgoing_cltv_value,
&hend->payment_hash);
} else if (changed_htlc->newstate == RCVD_REMOVE_ACK_REVOCATION
|| changed_htlc->newstate == SENT_REMOVE_ACK_REVOCATION) {
remove_hend(peer, hend);
save_htlc_stub(peer->ld, peer, LOCAL,
hout->cltv_expiry,
&hout->payment_hash);
} else if (newstate == RCVD_REMOVE_ACK_REVOCATION) {
remove_htlc_out(peer, hout);
}
return true;
}
static bool changed_htlc(struct peer *peer,
const struct changed_htlc *changed)
{
if (htlc_state_owner(changed->newstate) == LOCAL)
return update_out_htlc(peer, changed->id, changed->newstate);
else
return update_in_htlc(peer, changed->id, changed->newstate);
}
int peer_sending_commitsig(struct peer *peer, const u8 *msg)
{
u64 commitnum;
@ -756,51 +782,28 @@ int peer_sending_commitsig(struct peer *peer, const u8 *msg)
static void added_their_htlc(struct peer *peer, const struct added_htlc *added)
{
struct htlc_end *hend;
struct htlc_in *hin;
static struct secret dummy;
/* This stays around even if we fail it immediately: it *is*
* part of the current commitment. */
hend = tal(peer, struct htlc_end);
hend->which_end = HTLC_SRC;
hend->hstate = RCVD_ADD_COMMIT;
hend->peer = peer;
hend->other_end = NULL;
hend->pay_command = NULL;
hend->fail_msg = NULL;
hend->htlc_id = added->id;
hend->msatoshis = added->amount_msat;
hend->payment_hash = added->payment_hash;
hend->cltv_expiry = added->cltv_expiry;
hend->next_onion = tal_dup_arr(hend, u8, added->onion_routing_packet,
sizeof(added->onion_routing_packet),
0);
hin = new_htlc_in(peer, peer, added->id, added->amount_msat,
added->cltv_expiry, &added->payment_hash,
/* FIXME: have user pass shared_secret now */
&dummy, added->onion_routing_packet);
/* FIXME: Save to db */
log_debug(peer->log, "Adding their HTLC %"PRIu64, added->id);
connect_htlc_end(&peer->ld->htlc_ends, hend);
connect_htlc_in(&peer->ld->htlcs_in, hin);
/* Technically this can't be needed for a penalty transaction until
* after we send revoke_and_ack, then commit, then receive their
* revoke_and_ack. But might as well record it while we have it:
* a few extra entries won't hurt */
save_htlc_stub(peer->ld, peer, HTLC_SRC, hend->cltv_expiry,
&hend->payment_hash);
}
save_htlc_stub(peer->ld, peer, REMOTE, hin->cltv_expiry,
&hin->payment_hash);
static bool update_by_id(struct peer *peer, u64 id, enum htlc_end_type end,
enum htlc_state newstate)
{
struct htlc_end *hend;
hend = find_htlc_end(&peer->ld->htlc_ends, peer, id, end);
if (!hend) {
log_broken(peer->log, "Could not find id %"PRIu64
" to update to %s", id, htlc_state_name(newstate));
return false;
}
return hend_update_state(peer, hend, newstate);
}
/* The peer doesn't tell us this separately, but logically it's a separate
@ -814,28 +817,26 @@ static bool peer_sending_revocation(struct peer *peer,
size_t i;
for (i = 0; i < tal_count(added); i++) {
if (!update_by_id(peer, added[i].id, HTLC_SRC,
SENT_ADD_REVOCATION))
if (!update_in_htlc(peer, added[i].id, SENT_ADD_REVOCATION))
return false;
}
for (i = 0; i < tal_count(fulfilled); i++) {
if (!update_by_id(peer, fulfilled[i].id, HTLC_DST,
SENT_REMOVE_REVOCATION))
if (!update_out_htlc(peer, fulfilled[i].id,
SENT_REMOVE_REVOCATION))
return false;
}
for (i = 0; i < tal_count(failed); i++) {
if (!update_by_id(peer, failed[i].id, HTLC_DST,
SENT_REMOVE_REVOCATION))
if (!update_out_htlc(peer, 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_by_id(peer, changed[i].id, HTLC_DST,
SENT_ADD_ACK_REVOCATION))
if (!update_out_htlc(peer, changed[i].id,
SENT_ADD_ACK_REVOCATION))
return false;
} else {
if (!update_by_id(peer, changed[i].id, HTLC_SRC,
SENT_REMOVE_ACK_REVOCATION))
if (!update_in_htlc(peer, changed[i].id,
SENT_REMOVE_ACK_REVOCATION))
return false;
}
}
@ -997,17 +998,15 @@ int peer_got_revoke(struct peer *peer, const u8 *msg)
/* Now, any HTLCs we need to immediately fail? */
for (i = 0; i < tal_count(added_ids); i++) {
struct sha256 bad_onion_sha;
struct htlc_end *hend;
struct htlc_in *hin;
if (!failcodes[i])
continue;
hend = find_htlc_end(&peer->ld->htlc_ends, peer, added_ids[i],
HTLC_SRC);
sha256(&bad_onion_sha, hend->next_onion,
tal_len(hend->next_onion));
fail_htlc(hend, failcodes[i], &bad_onion_sha);
hin = find_htlc_in(&peer->ld->htlcs_in, peer, added_ids[i]);
sha256(&bad_onion_sha, hin->onion_routing_packet,
sizeof(hin->onion_routing_packet));
fail_htlc(hin, failcodes[i], &bad_onion_sha);
}
return 0;
}

Loading…
Cancel
Save