mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
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>
This commit is contained in:
@@ -1,39 +1,156 @@
|
|||||||
#include <ccan/cast/cast.h>
|
#include <ccan/cast/cast.h>
|
||||||
#include <ccan/crypto/siphash24/siphash24.h>
|
#include <ccan/crypto/siphash24/siphash24.h>
|
||||||
|
#include <ccan/tal/str/str.h>
|
||||||
#include <ccan/tal/tal.h>
|
#include <ccan/tal/tal.h>
|
||||||
|
#include <daemon/htlc.h>
|
||||||
|
#include <daemon/log.h>
|
||||||
#include <daemon/pseudorand.h>
|
#include <daemon/pseudorand.h>
|
||||||
#include <lightningd/htlc_end.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;
|
struct siphash24_ctx ctx;
|
||||||
siphash24_init(&ctx, siphash_seed());
|
siphash24_init(&ctx, siphash_seed());
|
||||||
/* peer doesn't move while in this hash, so we just hash pointer. */
|
/* peer doesn't move while in this hash, so we just hash pointer. */
|
||||||
siphash24_update(&ctx, &e->peer, sizeof(e->peer));
|
siphash24_update(&ctx, &k->peer, sizeof(k->peer));
|
||||||
siphash24_u64(&ctx, e->htlc_id);
|
siphash24_u64(&ctx, k->id);
|
||||||
siphash24_u8(&ctx, e->which_end);
|
|
||||||
|
|
||||||
return siphash24_done(&ctx);
|
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,
|
const struct peer *peer,
|
||||||
u64 htlc_id,
|
u64 htlc_id)
|
||||||
enum htlc_end_type which_end)
|
|
||||||
{
|
{
|
||||||
const struct htlc_end key = { which_end, (struct peer *)peer, htlc_id,
|
const struct htlc_key key = { (struct peer *)peer, htlc_id };
|
||||||
0, NULL, NULL };
|
return htlc_in_map_get(map, &key);
|
||||||
|
|
||||||
return htlc_end_map_get(map, &key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_htlc_end(struct htlc_end *hend, struct htlc_end_map *map)
|
static void remove_htlc_in(struct htlc_in *hend, struct htlc_in_map *map)
|
||||||
{
|
{
|
||||||
htlc_end_map_del(map, hend);
|
htlc_in_map_del(map, hend);
|
||||||
}
|
}
|
||||||
|
|
||||||
void connect_htlc_end(struct htlc_end_map *map, struct htlc_end *hend)
|
void connect_htlc_in(struct htlc_in_map *map, struct htlc_in *hend)
|
||||||
{
|
{
|
||||||
tal_add_destructor2(hend, remove_htlc_end, map);
|
tal_add_destructor2(hend, remove_htlc_in, map);
|
||||||
htlc_end_map_add(map, hend);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct htlc_in *htlc_in_check(const struct htlc_in *hin, const char *abortstr)
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct htlc_out *htlc_out_check(const struct htlc_out *hout,
|
||||||
|
const char *abortstr)
|
||||||
|
{
|
||||||
|
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");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,69 +6,117 @@
|
|||||||
#include <daemon/htlc_state.h>
|
#include <daemon/htlc_state.h>
|
||||||
#include <lightningd/sphinx.h>
|
#include <lightningd/sphinx.h>
|
||||||
|
|
||||||
/* A HTLC has a source and destination: if other is NULL, it's this node.
|
/* We look up HTLCs by peer & id */
|
||||||
*
|
struct htlc_key {
|
||||||
* 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;
|
|
||||||
struct peer *peer;
|
struct peer *peer;
|
||||||
u64 htlc_id;
|
u64 id;
|
||||||
u64 msatoshis;
|
};
|
||||||
|
|
||||||
struct htlc_end *other_end;
|
/* Incoming HTLC */
|
||||||
/* If this is driven by a command. */
|
struct htlc_in {
|
||||||
struct pay_command *pay_command;
|
struct htlc_key key;
|
||||||
|
u64 msatoshi;
|
||||||
/* 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;
|
|
||||||
u32 cltv_expiry;
|
u32 cltv_expiry;
|
||||||
struct sha256 payment_hash;
|
struct sha256 payment_hash;
|
||||||
|
|
||||||
|
enum htlc_state hstate;
|
||||||
|
|
||||||
|
/* 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. */
|
/* If they failed HTLC, here's the message. */
|
||||||
const u8 *fail_msg;
|
const u8 *failuremsg;
|
||||||
|
|
||||||
/* If they succeeded, here's the preimage. */
|
/* If they fulfilled, here's the preimage. */
|
||||||
struct sha256 *preimage;
|
struct preimage *preimage;
|
||||||
|
|
||||||
/* If we are forwarding, remember the shared secret for an
|
|
||||||
* eventual reply */
|
|
||||||
struct secret *shared_secret;
|
|
||||||
|
|
||||||
/* If we are the origin, remember all shared secrets, so we
|
|
||||||
* can unwrap an eventual reply */
|
|
||||||
struct secret *path_secrets;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline const struct htlc_end *keyof_htlc_end(const struct htlc_end *e)
|
struct htlc_out {
|
||||||
|
struct htlc_key key;
|
||||||
|
u64 msatoshi;
|
||||||
|
u32 cltv_expiry;
|
||||||
|
struct sha256 payment_hash;
|
||||||
|
|
||||||
|
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 we fulfilled, here's the preimage. */
|
||||||
|
struct preimage *preimage;
|
||||||
|
|
||||||
|
/* Where it's from, if not going to us. */
|
||||||
|
struct htlc_in *in;
|
||||||
|
|
||||||
|
/* Otherwise, payment command which created it. */
|
||||||
|
struct pay_command *pay_command;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline const struct htlc_key *keyof_htlc_in(const struct htlc_in *in)
|
||||||
{
|
{
|
||||||
return e;
|
return &in->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t hash_htlc_end(const struct htlc_end *e);
|
static inline const struct htlc_key *keyof_htlc_out(const struct htlc_out *out)
|
||||||
|
|
||||||
static inline bool htlc_end_eq(const struct htlc_end *a,
|
|
||||||
const struct htlc_end *b)
|
|
||||||
{
|
{
|
||||||
return a->peer == b->peer
|
return &out->key;
|
||||||
&& a->htlc_id == b->htlc_id
|
|
||||||
&& a->which_end == b->which_end;
|
|
||||||
}
|
}
|
||||||
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,
|
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_out_eq(const struct htlc_out *out,
|
||||||
|
const struct htlc_key *k)
|
||||||
|
{
|
||||||
|
return out->key.peer == k->peer && out->key.id == k->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
const struct peer *peer,
|
||||||
u64 htlc_id,
|
u64 htlc_id);
|
||||||
enum htlc_end_type which_end);
|
|
||||||
|
|
||||||
void connect_htlc_end(struct htlc_end_map *map, struct htlc_end *hend);
|
/* 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);
|
||||||
|
|
||||||
|
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 */
|
#endif /* LIGHTNING_LIGHTNINGD_HTLC_END_H */
|
||||||
|
|||||||
@@ -108,7 +108,8 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
|
|||||||
list_head_init(&ld->peers);
|
list_head_init(&ld->peers);
|
||||||
ld->peer_counter = 0;
|
ld->peer_counter = 0;
|
||||||
ld->dev_debug_subdaemon = NULL;
|
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->dev_disconnect_fd = -1;
|
||||||
ld->dstate.log_book = new_log_book(&ld->dstate, 20*1024*1024,LOG_INFORM);
|
ld->dstate.log_book = new_log_book(&ld->dstate, 20*1024*1024,LOG_INFORM);
|
||||||
ld->log = ld->dstate.base_log = new_log(&ld->dstate,
|
ld->log = ld->dstate.base_log = new_log(&ld->dstate,
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ struct lightningd {
|
|||||||
int dev_disconnect_fd;
|
int dev_disconnect_fd;
|
||||||
|
|
||||||
/* HTLCs in flight. */
|
/* HTLCs in flight. */
|
||||||
struct htlc_end_map htlc_ends;
|
struct htlc_in_map htlcs_in;
|
||||||
|
struct htlc_out_map htlcs_out;
|
||||||
|
|
||||||
u32 broadcast_interval;
|
u32 broadcast_interval;
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,13 @@ struct pay_command {
|
|||||||
u64 msatoshi;
|
u64 msatoshi;
|
||||||
const struct pubkey *ids;
|
const struct pubkey *ids;
|
||||||
/* Set if this is in progress. */
|
/* Set if this is in progress. */
|
||||||
struct htlc_end *out;
|
struct htlc_out *out;
|
||||||
/* Preimage if this succeeded. */
|
/* Preimage if this succeeded. */
|
||||||
const struct preimage *rval;
|
const struct preimage *rval;
|
||||||
struct command *cmd;
|
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)
|
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;
|
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)
|
const struct preimage *rval)
|
||||||
{
|
{
|
||||||
assert(!dst->pay_command->rval);
|
assert(!hout->pay_command->rval);
|
||||||
dst->pay_command->rval = tal_dup(dst->pay_command,
|
hout->pay_command->rval = tal_dup(hout->pay_command,
|
||||||
struct preimage, rval);
|
struct preimage, rval);
|
||||||
json_pay_success(dst->pay_command->cmd, rval);
|
json_pay_success(hout->pay_command->cmd, rval);
|
||||||
dst->pay_command->out = NULL;
|
hout->pay_command->out = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: sender is NULL for now: need crypto! */
|
void payment_failed(struct lightningd *ld, const struct htlc_out *hout)
|
||||||
void payment_failed(struct lightningd *ld, struct htlc_end *dst,
|
|
||||||
const struct pubkey *sender,
|
|
||||||
enum onion_type failure_code)
|
|
||||||
{
|
{
|
||||||
|
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. */
|
/* FIXME: check for routing failure / perm fail. */
|
||||||
/* check_for_routing_failure(i, sender, failure_code); */
|
/* 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,
|
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;
|
u8 *failstr;
|
||||||
|
|
||||||
if (!fromwire_channel_offer_htlc_reply(msg, msg, NULL,
|
if (!fromwire_channel_offer_htlc_reply(msg, msg, NULL,
|
||||||
&pc->out->htlc_id,
|
&pc->out->key.id,
|
||||||
&failcode, &failstr)) {
|
&failcode, &failstr)) {
|
||||||
json_pay_failed(pc, &subd->ld->dstate.id, -1,
|
json_pay_failed(pc, &subd->ld->dstate.id, -1,
|
||||||
"daemon bad response");
|
"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. */
|
/* HTLC endpoint now owned by lightningd. */
|
||||||
tal_steal(subd->ld, pc->out);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,16 +351,10 @@ static void json_sendpay(struct command *cmd,
|
|||||||
pc->rval = NULL;
|
pc->rval = NULL;
|
||||||
pc->ids = tal_steal(pc, ids);
|
pc->ids = tal_steal(pc, ids);
|
||||||
pc->msatoshi = lastamount;
|
pc->msatoshi = lastamount;
|
||||||
|
pc->path_secrets = tal_steal(pc, path_secrets);
|
||||||
|
|
||||||
pc->out = tal(pc, struct htlc_end);
|
pc->out = new_htlc_out(pc, peer, amount, first_hop_data.outgoing_cltv,
|
||||||
pc->out->which_end = HTLC_DST;
|
&rhash, onion, NULL, pc);
|
||||||
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);
|
|
||||||
|
|
||||||
log_info(ld->log, "Sending %"PRIu64" over %zu hops to deliver %"PRIu64,
|
log_info(ld->log, "Sending %"PRIu64" over %zu hops to deliver %"PRIu64,
|
||||||
amount, n_hops, lastamount);
|
amount, n_hops, lastamount);
|
||||||
|
|||||||
@@ -3,16 +3,14 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <wire/gen_onion_wire.h>
|
#include <wire/gen_onion_wire.h>
|
||||||
|
|
||||||
struct htlc_end;
|
struct htlc_out;
|
||||||
struct lightningd;
|
struct lightningd;
|
||||||
struct preimage;
|
struct preimage;
|
||||||
struct pubkey;
|
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);
|
const struct preimage *rval);
|
||||||
|
|
||||||
void payment_failed(struct lightningd *ld, struct htlc_end *dst,
|
void payment_failed(struct lightningd *ld, const struct htlc_out *hout);
|
||||||
const struct pubkey *sender,
|
|
||||||
enum onion_type failure_code);
|
|
||||||
|
|
||||||
#endif /* LIGHTNING_LIGHTNINGD_PAY_H */
|
#endif /* LIGHTNING_LIGHTNINGD_PAY_H */
|
||||||
|
|||||||
@@ -21,28 +21,28 @@
|
|||||||
* required to do penalty transaction */
|
* required to do penalty transaction */
|
||||||
static void save_htlc_stub(struct lightningd *ld,
|
static void save_htlc_stub(struct lightningd *ld,
|
||||||
struct peer *peer,
|
struct peer *peer,
|
||||||
enum htlc_end_type htlc_end_type,
|
enum side owner,
|
||||||
u32 cltv_value,
|
u32 cltv_value,
|
||||||
const struct sha256 *payment_hash)
|
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. */
|
/* 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;
|
u8 *reply;
|
||||||
|
|
||||||
if (!hend->peer->owner)
|
if (!hin->key.peer->owner)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
reply = wrap_onionreply(hend, hend->shared_secret, hend->fail_msg);
|
reply = wrap_onionreply(hin, &hin->shared_secret, hin->failuremsg);
|
||||||
subd_send_msg(hend->peer->owner,
|
subd_send_msg(hin->key.peer->owner,
|
||||||
take(towire_channel_fail_htlc(hend, hend->htlc_id, reply)));
|
take(towire_channel_fail_htlc(hin, hin->key.id, reply)));
|
||||||
tal_free(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,
|
enum onion_type failcode,
|
||||||
const struct sha256 *onion_sha, const u8 *channel_update)
|
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:
|
case WIRE_UNKNOWN_NEXT_PEER:
|
||||||
return towire_unknown_next_peer(ctx);
|
return towire_unknown_next_peer(ctx);
|
||||||
case WIRE_AMOUNT_BELOW_MINIMUM:
|
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:
|
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:
|
case WIRE_INCORRECT_CLTV_EXPIRY:
|
||||||
/* FIXME: ctlv! */
|
/* FIXME: ctlv! */
|
||||||
return towire_incorrect_cltv_expiry(ctx, 0, channel_update);
|
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! */
|
/* FIXME: ctlv! */
|
||||||
return towire_final_incorrect_cltv_expiry(ctx, 0);
|
return towire_final_incorrect_cltv_expiry(ctx, 0);
|
||||||
case WIRE_FINAL_INCORRECT_HTLC_AMOUNT:
|
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();
|
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)
|
const struct sha256 *onion_sha)
|
||||||
{
|
{
|
||||||
u8 *msg;
|
u8 *msg;
|
||||||
|
|
||||||
log_broken(hend->peer->log, "failed htlc %"PRIu64" code 0x%04x (%s)",
|
log_broken(hin->key.peer->log, "failed htlc %"PRIu64" code 0x%04x (%s)",
|
||||||
hend->htlc_id, failcode, onion_type_name(failcode));
|
hin->key.id, failcode, onion_type_name(failcode));
|
||||||
|
|
||||||
if (failcode & UPDATE) {
|
if (failcode & UPDATE) {
|
||||||
/* FIXME: Ask gossip daemon for channel_update. */
|
/* FIXME: Ask gossip daemon for channel_update. */
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = make_failmsg(hend, hend, failcode, onion_sha, NULL);
|
msg = make_failmsg(hin, hin, failcode, onion_sha, NULL);
|
||||||
hend->fail_msg = create_onionreply(hend, hend->shared_secret, msg);
|
hin->failuremsg = create_onionreply(hin, &hin->shared_secret, msg);
|
||||||
tal_free(msg);
|
tal_free(msg);
|
||||||
|
|
||||||
relay_htlc_failmsg(hend);
|
relay_htlc_failmsg(hin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BOLT #4:
|
/* 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
|
* 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.
|
* 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)
|
u64 amt_to_forward, u64 amt_in_htlc, u64 fee)
|
||||||
{
|
{
|
||||||
if (amt_in_htlc - fee >= amt_to_forward)
|
if (amt_in_htlc - fee >= amt_to_forward)
|
||||||
return true;
|
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,
|
" %"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;
|
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
|
* `outgoing_cltv_value` whether it is the final hop or not, to avoid
|
||||||
* leaking that information.
|
* 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)
|
u32 ctlv_expiry, u32 outgoing_cltv_value, u32 delta)
|
||||||
{
|
{
|
||||||
if (ctlv_expiry - delta == outgoing_cltv_value)
|
if (ctlv_expiry - delta == outgoing_cltv_value)
|
||||||
return true;
|
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",
|
" %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;
|
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;
|
u8 *msg;
|
||||||
|
|
||||||
hend->peer->balance[LOCAL] += hend->msatoshis;
|
hin->key.peer->balance[LOCAL] += hin->msatoshi;
|
||||||
hend->peer->balance[REMOTE] -= hend->msatoshis;
|
hin->key.peer->balance[REMOTE] -= hin->msatoshi;
|
||||||
|
|
||||||
/* FIXME: fail the peer if it doesn't tell us that htlc fulfill is
|
/* FIXME: fail the peer if it doesn't tell us that htlc fulfill is
|
||||||
* committed before deadline.
|
* committed before deadline.
|
||||||
*/
|
*/
|
||||||
msg = towire_channel_fulfill_htlc(hend->peer, hend->htlc_id, preimage);
|
msg = towire_channel_fulfill_htlc(hin->key.peer, hin->key.id, preimage);
|
||||||
subd_send_msg(hend->peer->owner, take(msg));
|
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,
|
u32 cltv_expiry,
|
||||||
const struct sha256 *payment_hash,
|
const struct sha256 *payment_hash,
|
||||||
u64 amt_to_forward,
|
u64 amt_to_forward,
|
||||||
@@ -193,6 +193,7 @@ static void handle_localpay(struct htlc_end *hend,
|
|||||||
{
|
{
|
||||||
enum onion_type failcode;
|
enum onion_type failcode;
|
||||||
struct invoice *invoice;
|
struct invoice *invoice;
|
||||||
|
struct lightningd *ld = hin->key.peer->ld;
|
||||||
|
|
||||||
/* BOLT #4:
|
/* BOLT #4:
|
||||||
*
|
*
|
||||||
@@ -203,7 +204,7 @@ static void handle_localpay(struct htlc_end *hend,
|
|||||||
* 2. data:
|
* 2. data:
|
||||||
* * [`4`:`incoming_htlc_amt`]
|
* * [`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;
|
failcode = WIRE_FINAL_INCORRECT_HTLC_AMOUNT;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -217,12 +218,12 @@ static void handle_localpay(struct htlc_end *hend,
|
|||||||
* 2. data:
|
* 2. data:
|
||||||
* * [`4`:`cltv_expiry`]
|
* * [`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;
|
failcode = WIRE_FINAL_INCORRECT_CLTV_EXPIRY;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
invoice = find_unpaid(hend->peer->ld->dstate.invoices, payment_hash);
|
invoice = find_unpaid(ld->dstate.invoices, payment_hash);
|
||||||
if (!invoice) {
|
if (!invoice) {
|
||||||
failcode = WIRE_UNKNOWN_PAYMENT_HASH;
|
failcode = WIRE_UNKNOWN_PAYMENT_HASH;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -238,10 +239,10 @@ static void handle_localpay(struct htlc_end *hend,
|
|||||||
*
|
*
|
||||||
* 1. type: PERM|16 (`incorrect_payment_amount`)
|
* 1. type: PERM|16 (`incorrect_payment_amount`)
|
||||||
*/
|
*/
|
||||||
if (hend->msatoshis < invoice->msatoshi) {
|
if (hin->msatoshi < invoice->msatoshi) {
|
||||||
failcode = WIRE_INCORRECT_PAYMENT_AMOUNT;
|
failcode = WIRE_INCORRECT_PAYMENT_AMOUNT;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (hend->msatoshis > invoice->msatoshi * 2) {
|
} else if (hin->msatoshi > invoice->msatoshi * 2) {
|
||||||
failcode = WIRE_INCORRECT_PAYMENT_AMOUNT;
|
failcode = WIRE_INCORRECT_PAYMENT_AMOUNT;
|
||||||
goto fail;
|
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 the `cltv_expiry` is too low, the final node MUST fail the HTLC:
|
||||||
*/
|
*/
|
||||||
if (get_block_height(hend->peer->ld->topology)
|
if (get_block_height(ld->topology) + ld->dstate.config.deadline_blocks
|
||||||
+ hend->peer->ld->dstate.config.deadline_blocks >= cltv_expiry) {
|
>= cltv_expiry) {
|
||||||
log_debug(hend->peer->log,
|
log_debug(hin->key.peer->log,
|
||||||
"Expiry cltv %u too close to current %u + deadline %u",
|
"Expiry cltv %u too close to current %u + deadline %u",
|
||||||
cltv_expiry,
|
cltv_expiry,
|
||||||
get_block_height(hend->peer->ld->topology),
|
get_block_height(ld->topology),
|
||||||
hend->peer->ld->dstate.config.deadline_blocks);
|
ld->dstate.config.deadline_blocks);
|
||||||
failcode = WIRE_FINAL_EXPIRY_TOO_SOON;
|
failcode = WIRE_FINAL_EXPIRY_TOO_SOON;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info(hend->peer->ld->log, "Resolving invoice '%s' with HTLC %"PRIu64,
|
log_info(ld->log, "Resolving invoice '%s' with HTLC %"PRIu64,
|
||||||
invoice->label, hend->htlc_id);
|
invoice->label, hin->key.id);
|
||||||
fulfill_htlc(hend, &invoice->r);
|
fulfill_htlc(hin, &invoice->r);
|
||||||
resolve_invoice(&hend->peer->ld->dstate, invoice);
|
resolve_invoice(&ld->dstate, invoice);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fail:
|
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.
|
* 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",
|
"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
|
/* This is where channeld gives us the HTLC id, and also reports if it
|
||||||
* failed immediately. */
|
* failed immediately. */
|
||||||
static bool rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds,
|
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;
|
u16 failure_code;
|
||||||
u8 *failurestr;
|
u8 *failurestr;
|
||||||
|
|
||||||
if (!fromwire_channel_offer_htlc_reply(msg, msg, NULL,
|
if (!fromwire_channel_offer_htlc_reply(msg, msg, NULL,
|
||||||
&hend->htlc_id,
|
&hout->key.id,
|
||||||
&failure_code,
|
&failure_code,
|
||||||
&failurestr)) {
|
&failurestr)) {
|
||||||
log_broken(subd->log, "Bad channel_offer_htlc_reply");
|
log_broken(subd->log, "Bad channel_offer_htlc_reply");
|
||||||
tal_free(hend);
|
tal_free(hout);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (failure_code) {
|
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)",
|
"HTLC failed from other daemon: %s (%.*s)",
|
||||||
onion_type_name(failure_code),
|
onion_type_name(failure_code),
|
||||||
(int)tal_len(failurestr), (char *)failurestr);
|
(int)tal_len(failurestr), (char *)failurestr);
|
||||||
|
|
||||||
fail_htlc(hend->other_end, failure_code, NULL);
|
fail_htlc(hout->in, failure_code, NULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add it to lookup table now we know id. */
|
/* 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. */
|
/* When channeld includes it in commitment, we'll make it persistent. */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void forward_htlc(struct htlc_end *hend,
|
static void forward_htlc(struct htlc_in *hin,
|
||||||
u32 cltv_expiry,
|
u32 cltv_expiry,
|
||||||
const struct sha256 *payment_hash,
|
const struct sha256 *payment_hash,
|
||||||
u64 amt_to_forward,
|
u64 amt_to_forward,
|
||||||
@@ -330,8 +331,9 @@ static void forward_htlc(struct htlc_end *hend,
|
|||||||
u8 *msg;
|
u8 *msg;
|
||||||
enum onion_type failcode;
|
enum onion_type failcode;
|
||||||
u64 fee;
|
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 peer *next = peer_by_id(ld, next_hop);
|
||||||
|
struct htlc_out *out;
|
||||||
|
|
||||||
if (!next) {
|
if (!next) {
|
||||||
failcode = WIRE_UNKNOWN_NEXT_PEER;
|
failcode = WIRE_UNKNOWN_NEXT_PEER;
|
||||||
@@ -366,12 +368,12 @@ static void forward_htlc(struct htlc_end *hend,
|
|||||||
}
|
}
|
||||||
fee = ld->dstate.config.fee_base
|
fee = ld->dstate.config.fee_base
|
||||||
+ amt_to_forward * ld->dstate.config.fee_per_satoshi / 1000000;
|
+ 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;
|
failcode = WIRE_FEE_INSUFFICIENT;
|
||||||
goto fail;
|
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)) {
|
ld->dstate.config.deadline_blocks)) {
|
||||||
failcode = WIRE_INCORRECT_CLTV_EXPIRY;
|
failcode = WIRE_INCORRECT_CLTV_EXPIRY;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -388,7 +390,7 @@ static void forward_htlc(struct htlc_end *hend,
|
|||||||
*/
|
*/
|
||||||
if (get_block_height(next->ld->topology)
|
if (get_block_height(next->ld->topology)
|
||||||
+ next->ld->dstate.config.deadline_blocks >= outgoing_cltv_value) {
|
+ 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",
|
"Expiry cltv %u too close to current %u + deadline %u",
|
||||||
outgoing_cltv_value,
|
outgoing_cltv_value,
|
||||||
get_block_height(next->ld->topology),
|
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. */
|
/* Make sure daemon owns it, in case it fails. */
|
||||||
hend->other_end = tal(next->owner, struct htlc_end);
|
out = new_htlc_out(next->owner, next, amt_to_forward,
|
||||||
hend->other_end->hstate = SENT_ADD_HTLC;
|
outgoing_cltv_value, &hin->payment_hash,
|
||||||
hend->other_end->which_end = HTLC_DST;
|
next_onion, hin, NULL);
|
||||||
hend->other_end->peer = next;
|
tal_add_destructor(out, hend_subd_died);
|
||||||
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);
|
|
||||||
|
|
||||||
msg = towire_channel_offer_htlc(next, amt_to_forward,
|
msg = towire_channel_offer_htlc(next, amt_to_forward,
|
||||||
outgoing_cltv_value,
|
outgoing_cltv_value,
|
||||||
payment_hash, next_onion);
|
payment_hash, next_onion);
|
||||||
subd_req(next->owner, next->owner, take(msg), -1, 0,
|
subd_req(next->owner, next->owner, take(msg), -1, 0,
|
||||||
rcvd_htlc_reply, hend->other_end);
|
rcvd_htlc_reply, out);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fail:
|
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
|
/* We received a resolver reply, which gives us the node_ids of the
|
||||||
* channel we want to forward over */
|
* channel we want to forward over */
|
||||||
static bool channel_resolve_reply(struct subd *gossip, const u8 *msg,
|
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;
|
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) {
|
if (tal_count(nodes) == 0) {
|
||||||
fail_htlc(hend, WIRE_UNKNOWN_NEXT_PEER, NULL);
|
fail_htlc(gr->hin, WIRE_UNKNOWN_NEXT_PEER, NULL);
|
||||||
return true;
|
return true;
|
||||||
} else if (tal_count(nodes) != 2) {
|
} else if (tal_count(nodes) != 2) {
|
||||||
log_broken(gossip->log,
|
log_broken(gossip->log,
|
||||||
@@ -451,18 +456,18 @@ static bool channel_resolve_reply(struct subd *gossip, const u8 *msg,
|
|||||||
peer_id = &nodes[0];
|
peer_id = &nodes[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
forward_htlc(hend, hend->cltv_expiry, &hend->payment_hash,
|
forward_htlc(gr->hin, gr->hin->cltv_expiry, &gr->hin->payment_hash,
|
||||||
hend->amt_to_forward, hend->outgoing_cltv_value, peer_id,
|
gr->amt_to_forward, gr->outgoing_cltv_value, peer_id,
|
||||||
hend->next_onion);
|
gr->next_onion);
|
||||||
/* FIXME(cdecker) Cleanup things we stuffed into hend before (maybe?) */
|
tal_free(gr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hend_update_state(struct peer *peer,
|
static bool state_update_ok(struct peer *peer,
|
||||||
struct htlc_end *hend,
|
enum htlc_state oldstate, enum htlc_state newstate,
|
||||||
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
|
/* 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
|
* 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;
|
expected = SENT_REMOVE_COMMIT;
|
||||||
|
|
||||||
if (newstate != expected) {
|
if (newstate != expected) {
|
||||||
log_broken(peer->log, "HTLC %"PRIu64" invalid update %s->%s",
|
log_broken(peer->log, "HTLC %s %"PRIu64" invalid update %s->%s",
|
||||||
hend->htlc_id,
|
dir, htlc_id,
|
||||||
htlc_state_name(hend->hstate),
|
htlc_state_name(oldstate),
|
||||||
htlc_state_name(newstate));
|
htlc_state_name(newstate));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug(peer->log, "%s HTLC %"PRIu64" %s->%s",
|
log_debug(peer->log, "HTLC %s %"PRIu64" %s->%s",
|
||||||
hend->which_end == HTLC_SRC ? "Their" : "Our",
|
dir, htlc_id,
|
||||||
hend->htlc_id,
|
htlc_state_name(oldstate), htlc_state_name(newstate));
|
||||||
htlc_state_name(hend->hstate),
|
return true;
|
||||||
htlc_state_name(newstate));
|
}
|
||||||
|
|
||||||
|
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 */
|
/* FIXME: db commit */
|
||||||
hend->hstate = newstate;
|
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 */
|
||||||
|
hout->hstate = newstate;
|
||||||
|
htlc_out_check(hout, __func__);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,30 +523,34 @@ static bool peer_accepted_htlc(struct peer *peer,
|
|||||||
const struct secret *shared_secret,
|
const struct secret *shared_secret,
|
||||||
enum onion_type *failcode)
|
enum onion_type *failcode)
|
||||||
{
|
{
|
||||||
struct htlc_end *hend;
|
struct htlc_in *hin;
|
||||||
u8 *req;
|
u8 *req;
|
||||||
struct route_step *rs;
|
struct route_step *rs;
|
||||||
struct onionpacket *op;
|
struct onionpacket *op;
|
||||||
const tal_t *tmpctx = tal_tmpctx(peer);
|
const tal_t *tmpctx = tal_tmpctx(peer);
|
||||||
|
|
||||||
hend = find_htlc_end(&peer->ld->htlc_ends, peer, id, HTLC_SRC);
|
hin = find_htlc_in(&peer->ld->htlcs_in, peer, id);
|
||||||
if (!hend) {
|
if (!hin) {
|
||||||
log_broken(peer->log,
|
log_broken(peer->log,
|
||||||
"peer_got_revoke unknown htlc %"PRIu64, id);
|
"peer_got_revoke unknown htlc %"PRIu64, id);
|
||||||
return false;
|
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;
|
return false;
|
||||||
|
|
||||||
/* channeld tests this, so it should have set ss to zeroes. */
|
/* channeld tests this, so it should have set ss to zeroes. */
|
||||||
op = parse_onionpacket(tmpctx, hend->next_onion,
|
op = parse_onionpacket(tmpctx, hin->onion_routing_packet,
|
||||||
tal_len(hend->next_onion));
|
sizeof(hin->onion_routing_packet));
|
||||||
if (!op) {
|
if (!op) {
|
||||||
if (!memeqzero(shared_secret, sizeof(*shared_secret))) {
|
if (!memeqzero(shared_secret, sizeof(*shared_secret))) {
|
||||||
log_broken(peer->log,
|
log_broken(peer->log,
|
||||||
"bad onion in got_revoke: %s",
|
"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);
|
tal_free(tmpctx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -535,12 +565,10 @@ static bool peer_accepted_htlc(struct peer *peer,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
hend->shared_secret = tal_dup(hend, struct secret, shared_secret);
|
|
||||||
|
|
||||||
/* If it's crap, not channeld's fault, just fail it */
|
/* If it's crap, not channeld's fault, just fail it */
|
||||||
rs = process_onionpacket(tmpctx, op, hend->shared_secret->data,
|
rs = process_onionpacket(tmpctx, op, shared_secret->data,
|
||||||
hend->payment_hash.u.u8,
|
hin->payment_hash.u.u8,
|
||||||
sizeof(hend->payment_hash));
|
sizeof(hin->payment_hash));
|
||||||
if (!rs) {
|
if (!rs) {
|
||||||
*failcode = WIRE_INVALID_ONION_HMAC;
|
*failcode = WIRE_INVALID_ONION_HMAC;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -552,23 +580,26 @@ static bool peer_accepted_htlc(struct peer *peer,
|
|||||||
goto out;
|
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) {
|
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,
|
req = towire_gossip_resolve_channel_request(tmpctx,
|
||||||
&hend->next_channel);
|
&gr->next_channel);
|
||||||
log_debug(peer->log, "Asking gossip to resolve channel %s",
|
log_debug(peer->log, "Asking gossip to resolve channel %s",
|
||||||
type_to_string(tmpctx, struct short_channel_id,
|
type_to_string(tmpctx, struct short_channel_id,
|
||||||
&hend->next_channel));
|
&gr->next_channel));
|
||||||
subd_req(hend, peer->ld->gossip, req, -1, 0,
|
subd_req(hin, peer->ld->gossip, req, -1, 0,
|
||||||
channel_resolve_reply, hend);
|
channel_resolve_reply, gr);
|
||||||
/* FIXME(cdecker) Stuff all this info into hend */
|
|
||||||
} else
|
} else
|
||||||
handle_localpay(hend, hend->cltv_expiry, &hend->payment_hash,
|
handle_localpay(hin, hin->cltv_expiry, &hin->payment_hash,
|
||||||
hend->amt_to_forward, hend->outgoing_cltv_value);
|
rs->hop_data.amt_forward,
|
||||||
|
rs->hop_data.outgoing_cltv);
|
||||||
|
|
||||||
*failcode = 0;
|
*failcode = 0;
|
||||||
out:
|
out:
|
||||||
@@ -582,150 +613,145 @@ out:
|
|||||||
static bool peer_fulfilled_our_htlc(struct peer *peer,
|
static bool peer_fulfilled_our_htlc(struct peer *peer,
|
||||||
const struct fulfilled_htlc *fulfilled)
|
const struct fulfilled_htlc *fulfilled)
|
||||||
{
|
{
|
||||||
struct htlc_end *hend;
|
struct htlc_out *hout;
|
||||||
|
|
||||||
hend = find_htlc_end(&peer->ld->htlc_ends, peer, fulfilled->id,
|
hout = find_htlc_out(&peer->ld->htlcs_out, peer, fulfilled->id);
|
||||||
HTLC_DST);
|
if (!hout) {
|
||||||
if (!hend) {
|
|
||||||
log_broken(peer->log,
|
log_broken(peer->log,
|
||||||
"fulfilled_our_htlc unknown htlc %"PRIu64,
|
"fulfilled_our_htlc unknown htlc %"PRIu64,
|
||||||
fulfilled->id);
|
fulfilled->id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hend_update_state(peer, hend, RCVD_REMOVE_COMMIT))
|
if (!htlc_out_update_state(peer, hout, RCVD_REMOVE_COMMIT))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* FIXME: Type mismatch. */
|
hout->preimage = tal_dup(hout, struct preimage,
|
||||||
hend->preimage = tal(hend, struct sha256);
|
&fulfilled->payment_preimage);
|
||||||
memcpy(hend->preimage, &fulfilled->payment_preimage,
|
htlc_out_check(hout, __func__);
|
||||||
sizeof(fulfilled->payment_preimage));
|
|
||||||
BUILD_ASSERT(sizeof(*hend->preimage)
|
|
||||||
== sizeof(fulfilled->payment_preimage));
|
|
||||||
|
|
||||||
/* FIXME: Save to db */
|
/* FIXME: Save to db */
|
||||||
|
|
||||||
/* They fulfilled our HTLC. Credit them, forward immediately. */
|
/* They fulfilled our HTLC. Credit them, forward immediately. */
|
||||||
peer->balance[REMOTE] += hend->msatoshis;
|
peer->balance[REMOTE] += hout->msatoshi;
|
||||||
peer->balance[LOCAL] -= hend->msatoshis;
|
peer->balance[LOCAL] -= hout->msatoshi;
|
||||||
|
|
||||||
if (hend->other_end)
|
if (hout->in)
|
||||||
fulfill_htlc(hend->other_end, &fulfilled->payment_preimage);
|
fulfill_htlc(hout->in, &fulfilled->payment_preimage);
|
||||||
else
|
else
|
||||||
payment_succeeded(peer->ld, hend, &fulfilled->payment_preimage);
|
payment_succeeded(peer->ld, hout, &fulfilled->payment_preimage);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool peer_failed_our_htlc(struct peer *peer,
|
static bool peer_failed_our_htlc(struct peer *peer,
|
||||||
const struct failed_htlc *failed)
|
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);
|
hout = find_htlc_out(&peer->ld->htlcs_out, peer, failed->id);
|
||||||
if (!hend) {
|
if (!hout) {
|
||||||
log_broken(peer->log,
|
log_broken(peer->log,
|
||||||
"failed_our_htlc unknown htlc %"PRIu64,
|
"failed_our_htlc unknown htlc %"PRIu64,
|
||||||
failed->id);
|
failed->id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hend_update_state(peer, hend, RCVD_REMOVE_COMMIT))
|
if (!htlc_out_update_state(peer, hout, RCVD_REMOVE_COMMIT))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
log_debug(peer->log, "Our HTLC %"PRIu64" failed", failed->id);
|
log_debug(peer->log, "Our HTLC %"PRIu64" failed", failed->id);
|
||||||
hend->fail_msg = tal_dup_arr(hend, u8, failed->failreason,
|
hout->failuremsg = tal_dup_arr(hout, u8, failed->failreason,
|
||||||
tal_len(failed->failreason), 0);
|
tal_len(failed->failreason), 0);
|
||||||
|
htlc_out_check(hout, __func__);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void remove_htlc_in(struct peer *peer, struct htlc_in *hin)
|
||||||
static void remove_hend(struct peer *peer, struct htlc_end *hend)
|
|
||||||
{
|
{
|
||||||
log_debug(peer->log, "Removing %s hend %"PRIu64" state %s",
|
htlc_in_check(hin, __func__);
|
||||||
hend->which_end == HTLC_DST ? "outgoing" : "incoming",
|
log_debug(peer->log, "Removing in HTLC %"PRIu64" state %s",
|
||||||
hend->htlc_id,
|
hin->key.id, htlc_state_name(hin->hstate));
|
||||||
htlc_state_name(hend->hstate));
|
tal_free(hin);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_htlc_out(struct peer *peer, struct htlc_out *hout)
|
||||||
|
{
|
||||||
|
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 it's failed, now we can forward since it's completely locked-in */
|
||||||
if (hend->fail_msg && hend->which_end == HTLC_DST) {
|
if (hout->failuremsg) {
|
||||||
if (hend->other_end) {
|
if (hout->in) {
|
||||||
hend->other_end->fail_msg
|
hout->in->failuremsg
|
||||||
= tal_dup_arr(hend->other_end, u8,
|
= tal_dup_arr(hout->in, u8,
|
||||||
hend->fail_msg,
|
hout->failuremsg,
|
||||||
tal_len(hend->fail_msg), 0);
|
tal_len(hout->failuremsg), 0);
|
||||||
relay_htlc_failmsg(hend->other_end);
|
relay_htlc_failmsg(hout->in);
|
||||||
} else {
|
} else {
|
||||||
/* FIXME: Avoid copy here! */
|
payment_failed(peer->ld, hout);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tal_free(hend);
|
tal_free(hout);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool changed_htlc(struct peer *peer,
|
static bool update_in_htlc(struct peer *peer, u64 id, enum htlc_state newstate)
|
||||||
const struct changed_htlc *changed_htlc)
|
|
||||||
{
|
{
|
||||||
struct htlc_end *hend;
|
struct htlc_in *hin;
|
||||||
enum htlc_end_type end;
|
|
||||||
|
|
||||||
if (htlc_state_owner(changed_htlc->newstate) == LOCAL)
|
hin = find_htlc_in(&peer->ld->htlcs_in, peer, id);
|
||||||
end = HTLC_DST;
|
if (!hin) {
|
||||||
else
|
log_broken(peer->log, "Can't find in HTLC %"PRIu64, id);
|
||||||
end = HTLC_SRC;
|
|
||||||
|
|
||||||
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);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hend_update_state(peer, hend, changed_htlc->newstate))
|
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 (!htlc_out_update_state(peer, hout, newstate))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* First transition into commitment; now it outlives peer. */
|
/* First transition into commitment; now it outlives peer. */
|
||||||
if (changed_htlc->newstate == SENT_ADD_COMMIT) {
|
if (newstate == SENT_ADD_COMMIT) {
|
||||||
tal_del_destructor(hend, hend_subd_died);
|
tal_del_destructor(hout, hend_subd_died);
|
||||||
tal_steal(peer->ld, hend);
|
tal_steal(peer->ld, hout);
|
||||||
|
|
||||||
/* From now onwards, penalty tx might need this */
|
/* From now onwards, penalty tx might need this */
|
||||||
save_htlc_stub(peer->ld, peer, end, hend->outgoing_cltv_value,
|
save_htlc_stub(peer->ld, peer, LOCAL,
|
||||||
&hend->payment_hash);
|
hout->cltv_expiry,
|
||||||
} else if (changed_htlc->newstate == RCVD_REMOVE_ACK_REVOCATION
|
&hout->payment_hash);
|
||||||
|| changed_htlc->newstate == SENT_REMOVE_ACK_REVOCATION) {
|
} else if (newstate == RCVD_REMOVE_ACK_REVOCATION) {
|
||||||
remove_hend(peer, hend);
|
remove_htlc_out(peer, hout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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)
|
int peer_sending_commitsig(struct peer *peer, const u8 *msg)
|
||||||
{
|
{
|
||||||
u64 commitnum;
|
u64 commitnum;
|
||||||
@@ -756,53 +782,30 @@ int peer_sending_commitsig(struct peer *peer, const u8 *msg)
|
|||||||
|
|
||||||
static void added_their_htlc(struct peer *peer, const struct added_htlc *added)
|
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*
|
/* This stays around even if we fail it immediately: it *is*
|
||||||
* part of the current commitment. */
|
* part of the current commitment. */
|
||||||
hend = tal(peer, struct htlc_end);
|
hin = new_htlc_in(peer, peer, added->id, added->amount_msat,
|
||||||
hend->which_end = HTLC_SRC;
|
added->cltv_expiry, &added->payment_hash,
|
||||||
hend->hstate = RCVD_ADD_COMMIT;
|
/* FIXME: have user pass shared_secret now */
|
||||||
hend->peer = peer;
|
&dummy, added->onion_routing_packet);
|
||||||
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);
|
|
||||||
/* FIXME: Save to db */
|
/* FIXME: Save to db */
|
||||||
|
|
||||||
log_debug(peer->log, "Adding their HTLC %"PRIu64, added->id);
|
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
|
/* Technically this can't be needed for a penalty transaction until
|
||||||
* after we send revoke_and_ack, then commit, then receive their
|
* after we send revoke_and_ack, then commit, then receive their
|
||||||
* revoke_and_ack. But might as well record it while we have it:
|
* revoke_and_ack. But might as well record it while we have it:
|
||||||
* a few extra entries won't hurt */
|
* a few extra entries won't hurt */
|
||||||
save_htlc_stub(peer->ld, peer, HTLC_SRC, hend->cltv_expiry,
|
save_htlc_stub(peer->ld, peer, REMOTE, hin->cltv_expiry,
|
||||||
&hend->payment_hash);
|
&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
|
/* The peer doesn't tell us this separately, but logically it's a separate
|
||||||
* step to receiving commitsig */
|
* step to receiving commitsig */
|
||||||
static bool peer_sending_revocation(struct peer *peer,
|
static bool peer_sending_revocation(struct peer *peer,
|
||||||
@@ -814,28 +817,26 @@ static bool peer_sending_revocation(struct peer *peer,
|
|||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < tal_count(added); i++) {
|
for (i = 0; i < tal_count(added); i++) {
|
||||||
if (!update_by_id(peer, added[i].id, HTLC_SRC,
|
if (!update_in_htlc(peer, added[i].id, SENT_ADD_REVOCATION))
|
||||||
SENT_ADD_REVOCATION))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (i = 0; i < tal_count(fulfilled); i++) {
|
for (i = 0; i < tal_count(fulfilled); i++) {
|
||||||
if (!update_by_id(peer, fulfilled[i].id, HTLC_DST,
|
if (!update_out_htlc(peer, fulfilled[i].id,
|
||||||
SENT_REMOVE_REVOCATION))
|
SENT_REMOVE_REVOCATION))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (i = 0; i < tal_count(failed); i++) {
|
for (i = 0; i < tal_count(failed); i++) {
|
||||||
if (!update_by_id(peer, failed[i].id, HTLC_DST,
|
if (!update_out_htlc(peer, failed[i].id, SENT_REMOVE_REVOCATION))
|
||||||
SENT_REMOVE_REVOCATION))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (i = 0; i < tal_count(changed); i++) {
|
for (i = 0; i < tal_count(changed); i++) {
|
||||||
if (changed[i].newstate == RCVD_ADD_ACK_COMMIT) {
|
if (changed[i].newstate == RCVD_ADD_ACK_COMMIT) {
|
||||||
if (!update_by_id(peer, changed[i].id, HTLC_DST,
|
if (!update_out_htlc(peer, changed[i].id,
|
||||||
SENT_ADD_ACK_REVOCATION))
|
SENT_ADD_ACK_REVOCATION))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (!update_by_id(peer, changed[i].id, HTLC_SRC,
|
if (!update_in_htlc(peer, changed[i].id,
|
||||||
SENT_REMOVE_ACK_REVOCATION))
|
SENT_REMOVE_ACK_REVOCATION))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -890,7 +891,7 @@ int peer_got_commitsig(struct peer *peer, const u8 *msg)
|
|||||||
if (!peer_failed_our_htlc(peer, &failed[i]))
|
if (!peer_failed_our_htlc(peer, &failed[i]))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < tal_count(changed); i++) {
|
for (i = 0; i < tal_count(changed); i++) {
|
||||||
if (!changed_htlc(peer, &changed[i])) {
|
if (!changed_htlc(peer, &changed[i])) {
|
||||||
log_broken(peer->log,
|
log_broken(peer->log,
|
||||||
@@ -917,7 +918,7 @@ static shachain_index_t shachain_next_index(const struct shachain *chain)
|
|||||||
else
|
else
|
||||||
return chain->min_index - 1;
|
return chain->min_index - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int peer_got_revoke(struct peer *peer, const u8 *msg)
|
int peer_got_revoke(struct peer *peer, const u8 *msg)
|
||||||
{
|
{
|
||||||
u64 revokenum, shachainidx;
|
u64 revokenum, shachainidx;
|
||||||
@@ -997,17 +998,15 @@ int peer_got_revoke(struct peer *peer, const u8 *msg)
|
|||||||
/* Now, any HTLCs we need to immediately fail? */
|
/* Now, any HTLCs we need to immediately fail? */
|
||||||
for (i = 0; i < tal_count(added_ids); i++) {
|
for (i = 0; i < tal_count(added_ids); i++) {
|
||||||
struct sha256 bad_onion_sha;
|
struct sha256 bad_onion_sha;
|
||||||
struct htlc_end *hend;
|
struct htlc_in *hin;
|
||||||
|
|
||||||
if (!failcodes[i])
|
if (!failcodes[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
hend = find_htlc_end(&peer->ld->htlc_ends, peer, added_ids[i],
|
hin = find_htlc_in(&peer->ld->htlcs_in, peer, added_ids[i]);
|
||||||
HTLC_SRC);
|
sha256(&bad_onion_sha, hin->onion_routing_packet,
|
||||||
|
sizeof(hin->onion_routing_packet));
|
||||||
sha256(&bad_onion_sha, hend->next_onion,
|
fail_htlc(hin, failcodes[i], &bad_onion_sha);
|
||||||
tal_len(hend->next_onion));
|
|
||||||
fail_htlc(hend, failcodes[i], &bad_onion_sha);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user