mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 18:11:28 +01:00
4a161b710d
When adding their HTLCs, it needs all the information. When failing, it needs the id as key and the failure reason. When fulfilling, it needs the id and payment preimage. It also needs to know when we have received an revoke_and_ack or a commitment_signed, to place in the database. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
807 lines
23 KiB
C
807 lines
23 KiB
C
#include "channel.h"
|
|
#include "commit_tx.h"
|
|
#include "type_to_string.h"
|
|
#include <assert.h>
|
|
#include <bitcoin/preimage.h>
|
|
#include <bitcoin/script.h>
|
|
#include <bitcoin/tx.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
#include <ccan/mem/mem.h>
|
|
#include <ccan/structeq/structeq.h>
|
|
#include <ccan/tal/str/str.h>
|
|
#include <daemon/htlc.h>
|
|
#include <inttypes.h>
|
|
#include <lightningd/channel_config.h>
|
|
#include <lightningd/htlc_tx.h>
|
|
#include <lightningd/key_derive.h>
|
|
#include <lightningd/status.h>
|
|
#include <string.h>
|
|
|
|
static void htlc_arr_append(const struct htlc ***arr, const struct htlc *htlc)
|
|
{
|
|
size_t n;
|
|
if (!arr)
|
|
return;
|
|
n = tal_count(*arr);
|
|
tal_resize(arr, n+1);
|
|
(*arr)[n] = htlc;
|
|
}
|
|
|
|
/* What does adding the HTLC do to the balance for this side */
|
|
static s64 balance_adding_htlc(const struct htlc *htlc, enum side side)
|
|
{
|
|
if (htlc_owner(htlc) == side)
|
|
return -htlc->msatoshi;
|
|
return 0;
|
|
}
|
|
|
|
/* What does removing the HTLC do to the balance for this side */
|
|
static s64 balance_removing_htlc(const struct htlc *htlc, enum side side)
|
|
{
|
|
enum side paid_to;
|
|
|
|
/* Fulfilled HTLCs are paid to recipient, otherwise returns to owner */
|
|
if (htlc->r)
|
|
paid_to = !htlc_owner(htlc);
|
|
else
|
|
paid_to = htlc_owner(htlc);
|
|
|
|
if (side == paid_to)
|
|
return htlc->msatoshi;
|
|
return 0;
|
|
}
|
|
|
|
static void dump_htlc(const struct htlc *htlc, const char *prefix)
|
|
{
|
|
enum htlc_state remote_state;
|
|
|
|
if (htlc->state <= RCVD_REMOVE_ACK_REVOCATION)
|
|
remote_state = htlc->state + 10;
|
|
else
|
|
remote_state = htlc->state - 10;
|
|
|
|
status_trace("%s: HTLC %s %"PRIu64" = %s/%s %s",
|
|
prefix,
|
|
htlc_owner(htlc) == LOCAL ? "LOCAL" : "REMOTE",
|
|
htlc->id,
|
|
htlc_state_name(htlc->state),
|
|
htlc_state_name(remote_state),
|
|
htlc->r ? "FULFILLED" : htlc->fail ? "FAILED" : "");
|
|
}
|
|
|
|
void dump_htlcs(const struct channel *channel, const char *prefix)
|
|
{
|
|
struct htlc_map_iter it;
|
|
const struct htlc *htlc;
|
|
|
|
for (htlc = htlc_map_first(&channel->htlcs, &it);
|
|
htlc;
|
|
htlc = htlc_map_next(&channel->htlcs, &it)) {
|
|
dump_htlc(htlc, prefix);
|
|
}
|
|
}
|
|
|
|
/* Returns up to three arrays:
|
|
* committed: HTLCs currently committed.
|
|
* pending_removal: HTLCs pending removal (subset of committed)
|
|
* pending_addition: HTLCs pending addition (no overlap with committed)
|
|
*/
|
|
static void gather_htlcs(const tal_t *ctx,
|
|
const struct channel *channel,
|
|
enum side side,
|
|
const struct htlc ***committed,
|
|
const struct htlc ***pending_removal,
|
|
const struct htlc ***pending_addition)
|
|
{
|
|
struct htlc_map_iter it;
|
|
const struct htlc *htlc;
|
|
const int committed_flag = HTLC_FLAG(side, HTLC_F_COMMITTED);
|
|
const int pending_flag = HTLC_FLAG(side, HTLC_F_PENDING);
|
|
|
|
*committed = tal_arr(ctx, const struct htlc *, 0);
|
|
if (pending_removal)
|
|
*pending_removal = tal_arr(ctx, const struct htlc *, 0);
|
|
if (pending_addition)
|
|
*pending_addition = tal_arr(ctx, const struct htlc *, 0);
|
|
|
|
for (htlc = htlc_map_first(&channel->htlcs, &it);
|
|
htlc;
|
|
htlc = htlc_map_next(&channel->htlcs, &it)) {
|
|
if (htlc_has(htlc, committed_flag)) {
|
|
htlc_arr_append(committed, htlc);
|
|
if (htlc_has(htlc, pending_flag))
|
|
htlc_arr_append(pending_removal, htlc);
|
|
} else if (htlc_has(htlc, pending_flag))
|
|
htlc_arr_append(pending_addition, htlc);
|
|
}
|
|
}
|
|
|
|
static u64 total_offered_msatoshis(const struct htlc **htlcs, enum side side)
|
|
{
|
|
size_t i;
|
|
u64 total = 0;
|
|
|
|
for (i = 0; i < tal_count(htlcs); i++) {
|
|
if (htlc_owner(htlcs[i]) == side)
|
|
total += htlcs[i]->msatoshi;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
static void destroy_htlc_map(struct channel *channel)
|
|
{
|
|
htlc_map_clear(&channel->htlcs);
|
|
}
|
|
|
|
struct channel *new_channel(const tal_t *ctx,
|
|
const struct sha256_double *funding_txid,
|
|
unsigned int funding_txout,
|
|
u64 funding_satoshis,
|
|
u64 push_msat,
|
|
u32 feerate_per_kw,
|
|
const struct channel_config *local,
|
|
const struct channel_config *remote,
|
|
const struct basepoints *local_basepoints,
|
|
const struct basepoints *remote_basepoints,
|
|
const struct pubkey *local_funding_pubkey,
|
|
const struct pubkey *remote_funding_pubkey,
|
|
enum side funder)
|
|
{
|
|
struct channel *channel = tal(ctx, struct channel);
|
|
|
|
channel->funding_txid = *funding_txid;
|
|
channel->funding_txout = funding_txout;
|
|
if (funding_satoshis > UINT64_MAX / 1000)
|
|
return tal_free(channel);
|
|
|
|
channel->funding_msat = funding_satoshis * 1000;
|
|
if (push_msat > channel->funding_msat)
|
|
return tal_free(channel);
|
|
|
|
channel->funder = funder;
|
|
channel->config[LOCAL] = local;
|
|
channel->config[REMOTE] = remote;
|
|
channel->funding_pubkey[LOCAL] = *local_funding_pubkey;
|
|
channel->funding_pubkey[REMOTE] = *remote_funding_pubkey;
|
|
htlc_map_init(&channel->htlcs);
|
|
|
|
channel->view[LOCAL].feerate_per_kw
|
|
= channel->view[REMOTE].feerate_per_kw
|
|
= feerate_per_kw;
|
|
|
|
channel->view[funder].owed_msat[funder]
|
|
= channel->view[!funder].owed_msat[funder]
|
|
= channel->funding_msat - push_msat;
|
|
channel->view[funder].owed_msat[!funder]
|
|
= channel->view[!funder].owed_msat[!funder]
|
|
= push_msat;
|
|
|
|
channel->view[LOCAL].commitment_number
|
|
= channel->view[REMOTE].commitment_number
|
|
= 0;
|
|
|
|
channel->basepoints[LOCAL] = *local_basepoints;
|
|
channel->basepoints[REMOTE] = *remote_basepoints;
|
|
|
|
channel->commitment_number_obscurer
|
|
= commit_number_obscurer(&channel->basepoints[funder].payment,
|
|
&channel->basepoints[!funder].payment);
|
|
|
|
tal_add_destructor(channel, destroy_htlc_map);
|
|
return channel;
|
|
}
|
|
|
|
static void add_htlcs(struct bitcoin_tx ***txs,
|
|
const u8 ***wscripts,
|
|
const struct htlc **htlcmap,
|
|
const struct channel *channel,
|
|
const struct pubkey *side_payment_key,
|
|
const struct pubkey *other_payment_key,
|
|
const struct pubkey *side_revocation_key,
|
|
const struct pubkey *side_delayed_payment_key,
|
|
enum side side)
|
|
{
|
|
size_t i, n;
|
|
struct sha256_double txid;
|
|
u32 feerate_per_kw = channel->view[side].feerate_per_kw;
|
|
|
|
/* Get txid of commitment transaction */
|
|
bitcoin_txid((*txs)[0], &txid);
|
|
|
|
for (i = 0; i < tal_count(htlcmap); i++) {
|
|
const struct htlc *htlc = htlcmap[i];
|
|
struct bitcoin_tx *tx;
|
|
u8 *wscript;
|
|
|
|
if (!htlc)
|
|
continue;
|
|
|
|
if (htlc_owner(htlc) == side) {
|
|
tx = htlc_timeout_tx(*txs, &txid, i,
|
|
htlc,
|
|
to_self_delay(channel, side),
|
|
side_revocation_key,
|
|
side_delayed_payment_key,
|
|
feerate_per_kw);
|
|
wscript = bitcoin_wscript_htlc_offer(*wscripts,
|
|
side_payment_key,
|
|
other_payment_key,
|
|
&htlc->rhash,
|
|
side_revocation_key);
|
|
} else {
|
|
tx = htlc_success_tx(*txs, &txid, i,
|
|
htlc,
|
|
to_self_delay(channel, side),
|
|
side_revocation_key,
|
|
side_delayed_payment_key,
|
|
feerate_per_kw);
|
|
wscript = bitcoin_wscript_htlc_receive(*wscripts,
|
|
&htlc->expiry,
|
|
side_payment_key,
|
|
other_payment_key,
|
|
&htlc->rhash,
|
|
side_revocation_key);
|
|
}
|
|
|
|
/* Append to array. */
|
|
n = tal_count(*txs);
|
|
assert(n == tal_count(*wscripts));
|
|
|
|
tal_resize(wscripts, n+1);
|
|
tal_resize(txs, n+1);
|
|
(*wscripts)[n] = wscript;
|
|
(*txs)[n] = tx;
|
|
}
|
|
}
|
|
|
|
/* FIXME: We could cache these. */
|
|
struct bitcoin_tx **channel_txs(const tal_t *ctx,
|
|
const struct htlc ***htlcmap,
|
|
const u8 ***wscripts,
|
|
const struct channel *channel,
|
|
const struct pubkey *per_commitment_point,
|
|
enum side side)
|
|
{
|
|
struct bitcoin_tx **txs;
|
|
const struct htlc **committed;
|
|
/* Payment keys for @side and !@side */
|
|
struct pubkey side_payment_key, other_payment_key;
|
|
/* Delayed payment key for @side */
|
|
struct pubkey side_delayed_payment_key;
|
|
/* Revocation payment key for @side */
|
|
struct pubkey side_revocation_key;
|
|
|
|
if (!derive_simple_key(&channel->basepoints[side].payment,
|
|
per_commitment_point,
|
|
&side_payment_key))
|
|
return NULL;
|
|
|
|
if (!derive_simple_key(&channel->basepoints[!side].payment,
|
|
per_commitment_point,
|
|
&other_payment_key))
|
|
return NULL;
|
|
|
|
if (!derive_simple_key(&channel->basepoints[side].delayed_payment,
|
|
per_commitment_point,
|
|
&side_delayed_payment_key))
|
|
return NULL;
|
|
|
|
if (!derive_revocation_key(&channel->basepoints[!side].revocation,
|
|
per_commitment_point,
|
|
&side_revocation_key))
|
|
return NULL;
|
|
|
|
/* Figure out what @side will already be committed to. */
|
|
gather_htlcs(ctx, channel, side, &committed, NULL, NULL);
|
|
|
|
/* NULL map only allowed at beginning, when we know no HTLCs */
|
|
if (!htlcmap)
|
|
assert(tal_count(committed) == 0);
|
|
|
|
txs = tal_arr(ctx, struct bitcoin_tx *, 1);
|
|
txs[0] = commit_tx(ctx, &channel->funding_txid,
|
|
channel->funding_txout,
|
|
channel->funding_msat / 1000,
|
|
channel->funder,
|
|
to_self_delay(channel, side),
|
|
&side_revocation_key,
|
|
&side_delayed_payment_key,
|
|
&side_payment_key,
|
|
&other_payment_key,
|
|
channel->view[side].feerate_per_kw,
|
|
dust_limit_satoshis(channel, side),
|
|
channel->view[side].owed_msat[side],
|
|
channel->view[side].owed_msat[!side],
|
|
committed,
|
|
htlcmap,
|
|
channel->view[side].commitment_number
|
|
^ channel->commitment_number_obscurer,
|
|
side);
|
|
|
|
*wscripts = tal_arr(ctx, const u8 *, 1);
|
|
(*wscripts)[0] = bitcoin_redeem_2of2(*wscripts,
|
|
&channel->funding_pubkey[side],
|
|
&channel->funding_pubkey[!side]);
|
|
|
|
if (htlcmap)
|
|
add_htlcs(&txs, wscripts, *htlcmap, channel,
|
|
&side_payment_key, &other_payment_key,
|
|
&side_revocation_key, &side_delayed_payment_key,
|
|
side);
|
|
|
|
tal_free(committed);
|
|
return txs;
|
|
}
|
|
|
|
struct channel *copy_channel(const tal_t *ctx, const struct channel *old)
|
|
{
|
|
struct channel *new = tal_dup(ctx, struct channel, old);
|
|
htlc_map_copy(&new->htlcs, &old->htlcs);
|
|
return new;
|
|
}
|
|
|
|
enum channel_add_err channel_add_htlc(struct channel *channel,
|
|
enum side sender,
|
|
u64 id,
|
|
u64 msatoshi,
|
|
u32 cltv_expiry,
|
|
const struct sha256 *payment_hash,
|
|
const u8 routing[TOTAL_PACKET_SIZE])
|
|
{
|
|
const tal_t *tmpctx = tal_tmpctx(channel);
|
|
struct htlc *htlc, *old;
|
|
s64 msat_in_htlcs, fee_msat, balance_msat;
|
|
enum side recipient = !sender;
|
|
const struct htlc **committed, **adding, **removing;
|
|
enum channel_add_err e;
|
|
const struct channel_view *view;
|
|
size_t i;
|
|
|
|
htlc = tal(tmpctx, struct htlc);
|
|
|
|
if (sender == LOCAL)
|
|
htlc->state = SENT_ADD_HTLC;
|
|
else
|
|
htlc->state = RCVD_ADD_HTLC;
|
|
htlc->id = id;
|
|
htlc->msatoshi = msatoshi;
|
|
/* BOLT #2:
|
|
*
|
|
* A receiving node SHOULD fail the channel if a sending node... sets
|
|
* `cltv_expiry` to greater or equal to 500000000.
|
|
*/
|
|
if (!blocks_to_abs_locktime(cltv_expiry, &htlc->expiry))
|
|
return CHANNEL_ERR_INVALID_EXPIRY;
|
|
htlc->rhash = *payment_hash;
|
|
htlc->fail = NULL;
|
|
htlc->r = NULL;
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* 1. type: 128 (`update_add_htlc`)
|
|
* 2. data:
|
|
* * [`32`:`channel_id`]
|
|
* * [`8`:`id`]
|
|
* * [`8`:`amount_msat`]
|
|
* * [`32`:`payment_hash`]
|
|
* * [`4`:`cltv_expiry`]
|
|
* * [`1366`:`onion_routing_packet`]
|
|
*/
|
|
htlc->routing = tal_dup_arr(htlc, u8, routing, TOTAL_PACKET_SIZE, 0);
|
|
|
|
/* FIXME: check expiry etc. against config. */
|
|
/* FIXME: set deadline */
|
|
|
|
old = htlc_get(&channel->htlcs, htlc->id, htlc_owner(htlc));
|
|
if (old) {
|
|
if (old->state != htlc->state
|
|
|| old->msatoshi != htlc->msatoshi
|
|
|| old->expiry.locktime != htlc->expiry.locktime
|
|
|| !structeq(&old->rhash, &htlc->rhash))
|
|
e = CHANNEL_ERR_DUPLICATE_ID_DIFFERENT;
|
|
else
|
|
e = CHANNEL_ERR_DUPLICATE;
|
|
goto out;
|
|
}
|
|
|
|
/* We're always considering the recipient's view of the channel here */
|
|
view = &channel->view[recipient];
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* A receiving node SHOULD fail the channel if it receives an
|
|
* `amount_msat` equal to zero, below its own `htlc_minimum_msat`,
|
|
* or...
|
|
*/
|
|
if (htlc->msatoshi == 0) {
|
|
e = CHANNEL_ERR_HTLC_BELOW_MINIMUM;
|
|
goto out;
|
|
}
|
|
if (htlc->msatoshi < htlc_minimum_msat(channel, recipient)) {
|
|
e = CHANNEL_ERR_HTLC_BELOW_MINIMUM;
|
|
goto out;
|
|
}
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* For channels with `chain_hash` identifying the Bitcoin blockchain,
|
|
* the sending node MUST set the 4 most significant bytes of
|
|
* `amount_msat` to zero.
|
|
*/
|
|
if (htlc->msatoshi & 0xFFFFFFFF00000000ULL) {
|
|
e = CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED;
|
|
goto out;
|
|
}
|
|
|
|
/* Figure out what receiver will already be committed to. */
|
|
gather_htlcs(tmpctx, channel, recipient, &committed, &removing, &adding);
|
|
htlc_arr_append(&adding, htlc);
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* A receiving node SHOULD fail the channel if a sending node
|
|
* adds more than its `max_accepted_htlcs` HTLCs to its local
|
|
* commitment transaction */
|
|
if (tal_count(committed) - tal_count(removing) + tal_count(adding)
|
|
> max_accepted_htlcs(channel, recipient)) {
|
|
e = CHANNEL_ERR_TOO_MANY_HTLCS;
|
|
goto out;
|
|
}
|
|
|
|
msat_in_htlcs = total_offered_msatoshis(committed, htlc_owner(htlc))
|
|
- total_offered_msatoshis(removing, htlc_owner(htlc))
|
|
+ total_offered_msatoshis(adding, htlc_owner(htlc));
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* A receiving node SHOULD fail the channel if a sending node ... or
|
|
* adds more than its `max_htlc_value_in_flight_msat` worth of offered
|
|
* HTLCs to its local commitment transaction */
|
|
if (msat_in_htlcs > max_htlc_value_in_flight_msat(channel, recipient)) {
|
|
e = CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED;
|
|
goto out;
|
|
}
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* or which the sending node cannot afford at the current
|
|
* `feerate_per_kw` while maintaining its channel reserve.
|
|
*/
|
|
if (channel->funder == htlc_owner(htlc)) {
|
|
u64 feerate = view->feerate_per_kw;
|
|
u64 dust = dust_limit_satoshis(channel, recipient);
|
|
size_t untrimmed;
|
|
|
|
assert(feerate >= 1);
|
|
assert(dust >= 1);
|
|
untrimmed = commit_tx_num_untrimmed(committed, feerate, dust,
|
|
recipient)
|
|
+ commit_tx_num_untrimmed(adding, feerate, dust,
|
|
recipient)
|
|
- commit_tx_num_untrimmed(removing, feerate, dust,
|
|
recipient);
|
|
|
|
fee_msat = commit_tx_base_fee(feerate, untrimmed);
|
|
} else
|
|
fee_msat = 0;
|
|
|
|
assert(fee_msat >= 0);
|
|
|
|
/* Figure out what balance sender would have after applying all
|
|
* pending changes. */
|
|
balance_msat = view->owed_msat[sender];
|
|
|
|
assert(balance_msat >= 0);
|
|
for (i = 0; i < tal_count(removing); i++)
|
|
balance_msat += balance_removing_htlc(removing[i], sender);
|
|
assert(balance_msat >= 0);
|
|
for (i = 0; i < tal_count(adding); i++)
|
|
balance_msat += balance_adding_htlc(adding[i], sender);
|
|
|
|
/* This is a little subtle:
|
|
*
|
|
* The change is being applied to the receiver but it will
|
|
* come back to the sender after revoke_and_ack. So the check
|
|
* here is that the balance to the sender doesn't go below the
|
|
* sender's reserve. */
|
|
if (balance_msat - fee_msat < (s64)channel_reserve_msat(channel, sender)) {
|
|
e = CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED;
|
|
goto out;
|
|
}
|
|
|
|
dump_htlc(htlc, "NEW:");
|
|
htlc_map_add(&channel->htlcs, tal_steal(channel, htlc));
|
|
e = CHANNEL_ERR_ADD_OK;
|
|
|
|
out:
|
|
tal_free(tmpctx);
|
|
return e;
|
|
}
|
|
|
|
struct htlc *channel_get_htlc(struct channel *channel, enum side sender, u64 id)
|
|
{
|
|
return htlc_get(&channel->htlcs, id, sender);
|
|
}
|
|
|
|
enum channel_remove_err channel_fulfill_htlc(struct channel *channel,
|
|
enum side owner,
|
|
u64 id,
|
|
const struct preimage *preimage)
|
|
{
|
|
struct sha256 hash;
|
|
struct htlc *htlc;
|
|
|
|
htlc = channel_get_htlc(channel, owner, id);
|
|
if (!htlc)
|
|
return CHANNEL_ERR_NO_SUCH_ID;
|
|
|
|
if (htlc->r)
|
|
return CHANNEL_ERR_ALREADY_FULFILLED;
|
|
|
|
sha256(&hash, preimage, sizeof(*preimage));
|
|
/* BOLT #2:
|
|
*
|
|
* A receiving node MUST check that the `payment_preimage` value in
|
|
* `update_fulfill_htlc` SHA256 hashes to the corresponding HTLC
|
|
* `payment_hash`, and MUST fail the channel if it does not.
|
|
*/
|
|
if (!structeq(&hash, &htlc->rhash))
|
|
return CHANNEL_ERR_BAD_PREIMAGE;
|
|
|
|
htlc->r = tal_dup(htlc, struct preimage, preimage);
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* A receiving node MUST check that `id` corresponds to an HTLC in its
|
|
* current commitment transaction, and MUST fail the channel if it
|
|
* does not.
|
|
*/
|
|
if (!htlc_has(htlc, HTLC_FLAG(!htlc_owner(htlc), HTLC_F_COMMITTED))) {
|
|
status_trace("channel_fulfill_htlc: %"PRIu64" in state %s",
|
|
htlc->id, htlc_state_name(htlc->state));
|
|
return CHANNEL_ERR_HTLC_UNCOMMITTED;
|
|
}
|
|
|
|
/* We enforce a stricter check, forcing state machine to be linear,
|
|
* based on: */
|
|
/* BOLT #2:
|
|
*
|
|
* A node MUST NOT send `update_fulfill_htlc` until an HTLC is
|
|
* irrevocably committed in both sides' commitment transactions.
|
|
*/
|
|
if (htlc->state == SENT_ADD_ACK_REVOCATION)
|
|
htlc->state = RCVD_REMOVE_HTLC;
|
|
else if (htlc->state == RCVD_ADD_ACK_REVOCATION)
|
|
htlc->state = SENT_REMOVE_HTLC;
|
|
else {
|
|
status_trace("channel_fulfill_htlc: %"PRIu64" in state %s",
|
|
htlc->id, htlc_state_name(htlc->state));
|
|
return CHANNEL_ERR_HTLC_NOT_IRREVOCABLE;
|
|
}
|
|
dump_htlc(htlc, "FULFILL:");
|
|
|
|
return CHANNEL_ERR_REMOVE_OK;
|
|
}
|
|
|
|
enum channel_remove_err channel_fail_htlc(struct channel *channel,
|
|
enum side owner, u64 id)
|
|
{
|
|
struct htlc *htlc;
|
|
|
|
htlc = channel_get_htlc(channel, owner, id);
|
|
if (!htlc)
|
|
return CHANNEL_ERR_NO_SUCH_ID;
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* A receiving node MUST check that `id` corresponds to an HTLC in its
|
|
* current commitment transaction, and MUST fail the channel if it
|
|
* does not.
|
|
*/
|
|
if (!htlc_has(htlc, HTLC_FLAG(!htlc_owner(htlc), HTLC_F_COMMITTED))) {
|
|
status_trace("channel_fail_htlc: %"PRIu64" in state %s",
|
|
htlc->id, htlc_state_name(htlc->state));
|
|
return CHANNEL_ERR_HTLC_UNCOMMITTED;
|
|
}
|
|
|
|
/* FIXME: Technically, they can fail this before we're committed to
|
|
* it. This implies a non-linear state machine. */
|
|
if (htlc->state == SENT_ADD_ACK_REVOCATION)
|
|
htlc->state = RCVD_REMOVE_HTLC;
|
|
else if (htlc->state == RCVD_ADD_ACK_REVOCATION)
|
|
htlc->state = SENT_REMOVE_HTLC;
|
|
else {
|
|
status_trace("channel_fail_htlc: %"PRIu64" in state %s",
|
|
htlc->id, htlc_state_name(htlc->state));
|
|
return CHANNEL_ERR_HTLC_NOT_IRREVOCABLE;
|
|
}
|
|
dump_htlc(htlc, "FAIL:");
|
|
|
|
return CHANNEL_ERR_REMOVE_OK;
|
|
}
|
|
|
|
static void htlc_incstate(struct channel *channel,
|
|
struct htlc *htlc,
|
|
enum side sidechanged)
|
|
{
|
|
int preflags, postflags;
|
|
const int committed_f = HTLC_FLAG(sidechanged, HTLC_F_COMMITTED);
|
|
|
|
status_trace("htlc %"PRIu64": %s->%s", htlc->id,
|
|
htlc_state_name(htlc->state),
|
|
htlc_state_name(htlc->state+1));
|
|
|
|
preflags = htlc_state_flags(htlc->state);
|
|
postflags = htlc_state_flags(htlc->state + 1);
|
|
/* You can't change sides. */
|
|
assert((preflags & (HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER))
|
|
== (postflags & (HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER)));
|
|
|
|
htlc->state++;
|
|
|
|
/* If we've added or removed, adjust balances. */
|
|
if (!(preflags & committed_f) && (postflags & committed_f)) {
|
|
status_trace("htlc added %s: local %+"PRIi64" remote %+"PRIi64,
|
|
side_to_str(sidechanged),
|
|
balance_adding_htlc(htlc, LOCAL),
|
|
balance_adding_htlc(htlc, REMOTE));
|
|
channel->view[sidechanged].owed_msat[LOCAL]
|
|
+= balance_adding_htlc(htlc, LOCAL);
|
|
channel->view[sidechanged].owed_msat[REMOTE]
|
|
+= balance_adding_htlc(htlc, REMOTE);
|
|
} else if ((preflags & committed_f) && !(postflags & committed_f)) {
|
|
status_trace("htlc removed %s: local %+"PRIi64" remote %+"PRIi64,
|
|
side_to_str(sidechanged),
|
|
balance_removing_htlc(htlc, LOCAL),
|
|
balance_removing_htlc(htlc, REMOTE));
|
|
channel->view[sidechanged].owed_msat[LOCAL]
|
|
+= balance_removing_htlc(htlc, LOCAL);
|
|
channel->view[sidechanged].owed_msat[REMOTE]
|
|
+= balance_removing_htlc(htlc, REMOTE);
|
|
}
|
|
}
|
|
|
|
static void append_htlc(const struct htlc ***htlcs, const struct htlc *h)
|
|
{
|
|
size_t n;
|
|
|
|
if (!htlcs)
|
|
return;
|
|
|
|
n = tal_count(*htlcs);
|
|
tal_resize(htlcs, n+1);
|
|
(*htlcs)[n] = h;
|
|
}
|
|
|
|
/* Returns flags which were changed. */
|
|
static int change_htlcs(struct channel *channel,
|
|
enum side sidechanged,
|
|
const enum htlc_state *htlc_states,
|
|
size_t n_hstates,
|
|
const struct htlc ***htlcs,
|
|
const char *prefix)
|
|
{
|
|
struct htlc_map_iter it;
|
|
struct htlc *h;
|
|
int cflags = 0;
|
|
size_t i;
|
|
|
|
for (h = htlc_map_first(&channel->htlcs, &it);
|
|
h;
|
|
h = htlc_map_next(&channel->htlcs, &it)) {
|
|
for (i = 0; i < n_hstates; i++) {
|
|
if (h->state == htlc_states[i]) {
|
|
htlc_incstate(channel, h, sidechanged);
|
|
dump_htlc(h, prefix);
|
|
append_htlc(htlcs, h);
|
|
cflags |= (htlc_state_flags(htlc_states[i])
|
|
^ htlc_state_flags(h->state));
|
|
}
|
|
}
|
|
}
|
|
return cflags;
|
|
}
|
|
|
|
/* FIXME: Handle fee changes too. */
|
|
bool channel_sending_commit(struct channel *channel,
|
|
const struct htlc ***htlcs)
|
|
{
|
|
int change;
|
|
const enum htlc_state states[] = { SENT_ADD_HTLC,
|
|
SENT_REMOVE_REVOCATION,
|
|
SENT_ADD_REVOCATION,
|
|
SENT_REMOVE_HTLC };
|
|
status_trace("Trying commit");
|
|
change = change_htlcs(channel, REMOTE, states, ARRAY_SIZE(states),
|
|
htlcs, "sending_commit");
|
|
return change & HTLC_REMOTE_F_COMMITTED;
|
|
}
|
|
|
|
bool channel_rcvd_revoke_and_ack(struct channel *channel,
|
|
const struct htlc ***htlcs)
|
|
{
|
|
int change;
|
|
const enum htlc_state states[] = { SENT_ADD_COMMIT,
|
|
SENT_REMOVE_ACK_COMMIT,
|
|
SENT_ADD_ACK_COMMIT,
|
|
SENT_REMOVE_COMMIT };
|
|
|
|
status_trace("Received revoke_and_ack");
|
|
change = change_htlcs(channel, LOCAL, states, ARRAY_SIZE(states),
|
|
htlcs, "rcvd_revoke_and_ack");
|
|
return change & HTLC_LOCAL_F_COMMITTED;
|
|
}
|
|
|
|
/* FIXME: We can actually merge these two... */
|
|
bool channel_rcvd_commit(struct channel *channel, const struct htlc ***htlcs)
|
|
{
|
|
int change;
|
|
const enum htlc_state states[] = { RCVD_ADD_REVOCATION,
|
|
RCVD_REMOVE_HTLC,
|
|
RCVD_ADD_HTLC,
|
|
RCVD_REMOVE_REVOCATION };
|
|
|
|
status_trace("Received commit");
|
|
change = change_htlcs(channel, LOCAL, states, ARRAY_SIZE(states), htlcs,
|
|
"rcvd_commit");
|
|
return change & HTLC_LOCAL_F_COMMITTED;
|
|
}
|
|
|
|
bool channel_sending_revoke_and_ack(struct channel *channel)
|
|
{
|
|
int change;
|
|
const enum htlc_state states[] = { RCVD_ADD_ACK_COMMIT,
|
|
RCVD_REMOVE_COMMIT,
|
|
RCVD_ADD_COMMIT,
|
|
RCVD_REMOVE_ACK_COMMIT };
|
|
status_trace("Sending revoke_and_ack");
|
|
change = change_htlcs(channel, REMOTE, states, ARRAY_SIZE(states), NULL,
|
|
"sending_revoke_and_ack");
|
|
return change & HTLC_REMOTE_F_PENDING;
|
|
}
|
|
|
|
/* FIXME: Trivial to optimize: set flag on channel_sending_commit,
|
|
* clear in channel_rcvd_revoke_and_ack. */
|
|
bool channel_awaiting_revoke_and_ack(const struct channel *channel)
|
|
{
|
|
const enum htlc_state states[] = { SENT_ADD_COMMIT,
|
|
SENT_REMOVE_ACK_COMMIT,
|
|
SENT_ADD_ACK_COMMIT,
|
|
SENT_REMOVE_COMMIT };
|
|
struct htlc_map_iter it;
|
|
struct htlc *h;
|
|
size_t i;
|
|
|
|
for (h = htlc_map_first(&channel->htlcs, &it);
|
|
h;
|
|
h = htlc_map_next(&channel->htlcs, &it)) {
|
|
for (i = 0; i < ARRAY_SIZE(states); i++)
|
|
if (h->state == states[i])
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static char *fmt_channel_view(const tal_t *ctx, const struct channel_view *view)
|
|
{
|
|
return tal_fmt(ctx, "{ feerate_per_kw=%"PRIu64","
|
|
" owed_local=%"PRIu64","
|
|
" owed_remote=%"PRIu64" }",
|
|
view->feerate_per_kw,
|
|
view->owed_msat[LOCAL],
|
|
view->owed_msat[REMOTE]);
|
|
}
|
|
|
|
static char *fmt_channel(const tal_t *ctx, const struct channel *channel)
|
|
{
|
|
return tal_fmt(ctx, "{ funding_msat=%"PRIu64","
|
|
" funder=%s,"
|
|
" local=%s,"
|
|
" remote=%s }",
|
|
channel->funding_msat,
|
|
side_to_str(channel->funder),
|
|
fmt_channel_view(ctx, &channel->view[LOCAL]),
|
|
fmt_channel_view(ctx, &channel->view[REMOTE]));
|
|
}
|
|
REGISTER_TYPE_TO_STRING(channel, fmt_channel);
|