Browse Source
This object is basically the embodyment of BOLT #2. Each HTLC already knows its own state; this moves them between states and keeps them consistent. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
5 changed files with 1450 additions and 1 deletions
@ -0,0 +1,592 @@ |
|||||
|
#include "channel.h" |
||||
|
#include "commit_tx.h" |
||||
|
#include "type_to_string.h" |
||||
|
#include <assert.h> |
||||
|
#include <bitcoin/preimage.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/key_derive.h> |
||||
|
#include <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; |
||||
|
} |
||||
|
|
||||
|
/* 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 pubkey *local_revocation_basepoint, |
||||
|
const struct pubkey *remote_revocation_basepoint, |
||||
|
const struct pubkey *local_payment_basepoint, |
||||
|
const struct pubkey *remote_payment_basepoint, |
||||
|
const struct pubkey *local_delayed_payment_basepoint, |
||||
|
const struct pubkey *remote_delayed_payment_basepoint, |
||||
|
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; |
||||
|
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->revocation_basepoint[LOCAL] = *local_revocation_basepoint; |
||||
|
channel->revocation_basepoint[REMOTE] = *remote_revocation_basepoint; |
||||
|
channel->payment_basepoint[LOCAL] = *local_payment_basepoint; |
||||
|
channel->payment_basepoint[REMOTE] = *remote_payment_basepoint; |
||||
|
channel->delayed_payment_basepoint[LOCAL] |
||||
|
= *local_delayed_payment_basepoint; |
||||
|
channel->delayed_payment_basepoint[REMOTE] |
||||
|
= *remote_delayed_payment_basepoint; |
||||
|
|
||||
|
channel->commitment_number_obscurer |
||||
|
= commit_number_obscurer(&channel->payment_basepoint[funder], |
||||
|
&channel->payment_basepoint[!funder]); |
||||
|
|
||||
|
tal_add_destructor(channel, destroy_htlc_map); |
||||
|
return channel; |
||||
|
} |
||||
|
|
||||
|
/* FIXME: We could cache this. */ |
||||
|
struct bitcoin_tx *channel_tx(const tal_t *ctx, |
||||
|
const struct channel *channel, |
||||
|
const struct pubkey *per_commitment_point, |
||||
|
const struct htlc ***htlcmap, |
||||
|
enum side side) |
||||
|
{ |
||||
|
struct bitcoin_tx *tx; |
||||
|
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->payment_basepoint[side], |
||||
|
per_commitment_point, |
||||
|
&side_payment_key)) |
||||
|
return NULL; |
||||
|
|
||||
|
if (!derive_simple_key(&channel->payment_basepoint[!side], |
||||
|
per_commitment_point, |
||||
|
&other_payment_key)) |
||||
|
return NULL; |
||||
|
|
||||
|
if (!derive_simple_key(&channel->delayed_payment_basepoint[side], |
||||
|
per_commitment_point, |
||||
|
&side_delayed_payment_key)) |
||||
|
return NULL; |
||||
|
|
||||
|
if (!derive_revocation_key(&channel->revocation_basepoint[side], |
||||
|
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); |
||||
|
|
||||
|
tx = 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); |
||||
|
|
||||
|
tal_free(committed); |
||||
|
return tx; |
||||
|
} |
||||
|
|
||||
|
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 expiry, |
||||
|
const struct sha256 *payment_hash, |
||||
|
const u8 routing[1254]) |
||||
|
{ |
||||
|
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; |
||||
|
if (!blocks_to_abs_locktime(expiry, &htlc->expiry)) |
||||
|
return CHANNEL_ERR_INVALID_EXPIRY; |
||||
|
htlc->rhash = *payment_hash; |
||||
|
htlc->r = NULL; |
||||
|
|
||||
|
/* BOLT #2:
|
||||
|
* |
||||
|
* 1. type: 128 (`update_add_htlc`) |
||||
|
* 2. data: |
||||
|
* * [8:channel-id] |
||||
|
* * [8:id] |
||||
|
* * [4:amount-msat] |
||||
|
* * [4:cltv-expiry] |
||||
|
* * [32:payment-hash] |
||||
|
* * [1254:onion-routing-packet] |
||||
|
*/ |
||||
|
htlc->routing = tal_dup_arr(htlc, u8, routing, 1254, 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-sat` 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; |
||||
|
} |
||||
|
|
||||
|
/* 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 |
||||
|
* adds more than `max-htlc-value-in-flight-msat` in 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 `fee-rate` |
||||
|
* 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); |
||||
|
assert(balance_msat >= 0); |
||||
|
|
||||
|
/* 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; |
||||
|
} |
||||
|
|
||||
|
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 sender, |
||||
|
u64 id, |
||||
|
const struct preimage *preimage) |
||||
|
{ |
||||
|
struct sha256 hash; |
||||
|
struct htlc *htlc; |
||||
|
|
||||
|
/* Fulfill is done by !creator of HTLC */ |
||||
|
htlc = channel_get_htlc(channel, !sender, 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; |
||||
|
} |
||||
|
|
||||
|
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); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* FIXME: Commit to storage when this happens. */ |
||||
|
static bool change_htlcs(struct channel *channel, |
||||
|
enum side sidechanged, |
||||
|
const enum htlc_state *htlc_states, |
||||
|
size_t n_hstates) |
||||
|
{ |
||||
|
struct htlc_map_iter it; |
||||
|
struct htlc *h; |
||||
|
bool changed = false; |
||||
|
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); |
||||
|
changed = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return changed; |
||||
|
} |
||||
|
|
||||
|
/* FIXME: Handle fee changes too. */ |
||||
|
bool channel_sent_commit(struct channel *channel) |
||||
|
{ |
||||
|
const enum htlc_state states[] = { SENT_ADD_HTLC, |
||||
|
SENT_REMOVE_REVOCATION, |
||||
|
SENT_ADD_REVOCATION, |
||||
|
SENT_REMOVE_HTLC }; |
||||
|
status_trace("sent commit"); |
||||
|
return change_htlcs(channel, REMOTE, states, ARRAY_SIZE(states)); |
||||
|
} |
||||
|
|
||||
|
bool channel_rcvd_revoke_and_ack(struct channel *channel) |
||||
|
{ |
||||
|
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"); |
||||
|
return change_htlcs(channel, LOCAL, states, ARRAY_SIZE(states)); |
||||
|
} |
||||
|
|
||||
|
/* FIXME: We can actually merge these two... */ |
||||
|
bool channel_rcvd_commit(struct channel *channel) |
||||
|
{ |
||||
|
const enum htlc_state states[] = { RCVD_ADD_REVOCATION, |
||||
|
RCVD_REMOVE_HTLC, |
||||
|
RCVD_ADD_HTLC, |
||||
|
RCVD_REMOVE_REVOCATION }; |
||||
|
|
||||
|
status_trace("received commit"); |
||||
|
return change_htlcs(channel, LOCAL, states, ARRAY_SIZE(states)); |
||||
|
} |
||||
|
|
||||
|
bool channel_sent_revoke_and_ack(struct channel *channel) |
||||
|
{ |
||||
|
const enum htlc_state states[] = { RCVD_ADD_ACK_COMMIT, |
||||
|
RCVD_REMOVE_COMMIT, |
||||
|
RCVD_ADD_COMMIT, |
||||
|
RCVD_REMOVE_ACK_COMMIT }; |
||||
|
status_trace("sent revoke_and_ack"); |
||||
|
return change_htlcs(channel, REMOTE, states, ARRAY_SIZE(states)); |
||||
|
} |
||||
|
|
||||
|
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); |
@ -0,0 +1,353 @@ |
|||||
|
#ifndef LIGHTNING_LIGHTNINGD_CHANNEL_H |
||||
|
#define LIGHTNING_LIGHTNINGD_CHANNEL_H |
||||
|
#include "config.h" |
||||
|
#include <bitcoin/pubkey.h> |
||||
|
#include <bitcoin/shadouble.h> |
||||
|
#include <ccan/short_types/short_types.h> |
||||
|
#include <ccan/tal/tal.h> |
||||
|
#include <daemon/htlc.h> |
||||
|
#include <lightningd/channel_config.h> |
||||
|
#include <stdbool.h> |
||||
|
|
||||
|
struct signature; |
||||
|
|
||||
|
/* View from each side */ |
||||
|
struct channel_view { |
||||
|
/* Current feerate in satoshis per 1000 weight. */ |
||||
|
u64 feerate_per_kw; |
||||
|
|
||||
|
/* What commitment number are we up to */ |
||||
|
u64 commitment_number; |
||||
|
|
||||
|
/* How much is owed to each side (includes pending changes) */ |
||||
|
u64 owed_msat[NUM_SIDES]; |
||||
|
}; |
||||
|
|
||||
|
struct channel { |
||||
|
/* Funding txid and output. */ |
||||
|
struct sha256_double funding_txid; |
||||
|
unsigned int funding_txout; |
||||
|
|
||||
|
/* Millisatoshis in from commitment tx */ |
||||
|
u64 funding_msat; |
||||
|
|
||||
|
/* Who is paying fees. */ |
||||
|
enum side funder; |
||||
|
|
||||
|
/* Limits and settings on this channel. */ |
||||
|
const struct channel_config *config[NUM_SIDES]; |
||||
|
|
||||
|
/* Basepoints for deriving keys. */ |
||||
|
struct pubkey revocation_basepoint[NUM_SIDES]; |
||||
|
struct pubkey payment_basepoint[NUM_SIDES]; |
||||
|
struct pubkey delayed_payment_basepoint[NUM_SIDES]; |
||||
|
|
||||
|
/* Mask for obscuring the encoding of the commitment number. */ |
||||
|
u64 commitment_number_obscurer; |
||||
|
|
||||
|
/* All live HTLCs for this channel */ |
||||
|
struct htlc_map htlcs; |
||||
|
|
||||
|
/* What it looks like to each side. */ |
||||
|
struct channel_view view[NUM_SIDES]; |
||||
|
}; |
||||
|
|
||||
|
/* Some requirements are self-specified (eg. my dust limit), others
|
||||
|
* are force upon the other side (eg. minimum htlc you can add). |
||||
|
* |
||||
|
* These values are also universally in msatsoshi. These avoid |
||||
|
* confusion: use them! */ |
||||
|
|
||||
|
/* BOLT #2:
|
||||
|
* |
||||
|
* `dust-limit-satoshis` is the threshold below which output should be |
||||
|
* generated for this node's commitment or HTLC transaction */ |
||||
|
static inline u64 dust_limit_satoshis(const struct channel *channel, |
||||
|
enum side side) |
||||
|
{ |
||||
|
return channel->config[side]->dust_limit_satoshis; |
||||
|
} |
||||
|
/* BOLT #2:
|
||||
|
* |
||||
|
* `max-htlc-value-in-inflight-msat` is a cap on total value of |
||||
|
* outstanding HTLCs, which allows a node to limit its exposure to |
||||
|
* HTLCs */ |
||||
|
static inline u64 max_htlc_value_in_flight_msat(const struct channel *channel, |
||||
|
enum side recipient) |
||||
|
{ |
||||
|
return channel->config[recipient]->max_htlc_value_in_flight_msat; |
||||
|
} |
||||
|
/* BOLT #2:
|
||||
|
* |
||||
|
* similarly `max-accepted-htlcs` limits the number of outstanding |
||||
|
* HTLCs the other node can offer. */ |
||||
|
static inline u16 max_accepted_htlcs(const struct channel *channel, |
||||
|
enum side recipient) |
||||
|
{ |
||||
|
return channel->config[recipient]->max_accepted_htlcs; |
||||
|
} |
||||
|
/* BOLT #2:
|
||||
|
* |
||||
|
* `channel-reserve-satoshis` is the minimum amount that the other |
||||
|
* node is to keep as a direct payment. */ |
||||
|
static inline u64 channel_reserve_msat(const struct channel *channel, |
||||
|
enum side side) |
||||
|
{ |
||||
|
return channel->config[!side]->channel_reserve_satoshis * 1000; |
||||
|
} |
||||
|
/* BOLT #2:
|
||||
|
* |
||||
|
* `htlc-minimum-msat` indicates the smallest value HTLC this node will accept. |
||||
|
*/ |
||||
|
static inline u32 htlc_minimum_msat(const struct channel *channel, |
||||
|
enum side recipient) |
||||
|
{ |
||||
|
return channel->config[recipient]->htlc_minimum_msat; |
||||
|
} |
||||
|
/* BOLT #2:
|
||||
|
* |
||||
|
* `to-self-delay` is the number of blocks that the other nodes |
||||
|
* to-self outputs must be delayed, using `OP_CHECKSEQUENCEVERIFY` |
||||
|
* delays */ |
||||
|
static inline u16 to_self_delay(const struct channel *channel, enum side side) |
||||
|
{ |
||||
|
return channel->config[!side]->to_self_delay; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
* new_channel: Given initial fees and funding, what is initial state? |
||||
|
* @ctx: tal context to allocate return value from. |
||||
|
* @funding_txid: The commitment transaction id. |
||||
|
* @funding_txout: The commitment transaction output number. |
||||
|
* @funding_satoshis: The commitment transaction amount. |
||||
|
* @funding_satoshis: The commitment transaction amount. |
||||
|
* @push_msat: The amount the initator gives to the other side. |
||||
|
* @feerate_per_kw: feerate per kiloweight (satoshis) |
||||
|
* @local: local channel configuration |
||||
|
* @remote: remote channel configuration |
||||
|
* @local_revocation_basepoint: local basepoint for revocations. |
||||
|
* @remote_revocation_basepoint: remote basepoint for revocations. |
||||
|
* @local_payment_basepoint: local basepoint for payments. |
||||
|
* @remote_payment_basepoint: remote basepoint for payments. |
||||
|
* @local_delayed_payment_basepoint: local basepoint for delayed payments. |
||||
|
* @remote_delayed_payment_basepoint: remote basepoint for delayed payments. |
||||
|
* @funder: which side initiated it. |
||||
|
* |
||||
|
* Returns state, or NULL if malformed. |
||||
|
*/ |
||||
|
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 pubkey *local_revocation_basepoint, |
||||
|
const struct pubkey *remote_revocation_basepoint, |
||||
|
const struct pubkey *local_payment_basepoint, |
||||
|
const struct pubkey *remote_payment_basepoint, |
||||
|
const struct pubkey *local_delayed_payment_basepoint, |
||||
|
const struct pubkey *remote_delayed_payment_basepoint, |
||||
|
enum side funder); |
||||
|
/**
|
||||
|
* channel_tx: Get the current commitment transaction for the channel. |
||||
|
* @ctx: tal context to allocate return value from. |
||||
|
* @channel: The channel to evaluate |
||||
|
* @per_commitment_point: Per-commitment point to determine keys |
||||
|
* @htlc_map: Pointer to htlcs for each tx output (allocated off @ctx) or NULL. |
||||
|
* @side: which side to get the commitment transaction for |
||||
|
* |
||||
|
* Returns the unsigned commitment transaction for the committed state |
||||
|
* for @side and fills in @htlc_map (if not NULL), or NULL on key |
||||
|
* derivation failure. |
||||
|
*/ |
||||
|
struct bitcoin_tx *channel_tx(const tal_t *ctx, |
||||
|
const struct channel *channel, |
||||
|
const struct pubkey *per_commitment_point, |
||||
|
const struct htlc ***htlcmap, |
||||
|
enum side side); |
||||
|
|
||||
|
/**
|
||||
|
* actual_feerate: what is the actual feerate for the local side. |
||||
|
* @channel: The channel state |
||||
|
* @theirsig: The other side's signature |
||||
|
* |
||||
|
* The fee calculated on a commitment transaction is a worst-case |
||||
|
* approximation. It's also possible that the desired feerate is not |
||||
|
* met, because the initiator sets it while the other side is adding many |
||||
|
* htlcs. |
||||
|
* |
||||
|
* This is the fee rate we actually care about, if we're going to check |
||||
|
* whether it's actually too low. |
||||
|
*/ |
||||
|
uint32_t actual_feerate(const struct channel *channel, |
||||
|
const struct signature *theirsig); |
||||
|
|
||||
|
/**
|
||||
|
* copy_channel: Make a deep copy of channel |
||||
|
* @ctx: tal context to allocate return value from. |
||||
|
* @channel: channel to copy. |
||||
|
*/ |
||||
|
struct channel *copy_channel(const tal_t *ctx, const struct channel *channel); |
||||
|
|
||||
|
enum channel_add_err { |
||||
|
/* All OK! */ |
||||
|
CHANNEL_ERR_ADD_OK, |
||||
|
/* Bad expiry value */ |
||||
|
CHANNEL_ERR_INVALID_EXPIRY, |
||||
|
/* Not really a failure, if expected: it's an exact duplicate. */ |
||||
|
CHANNEL_ERR_DUPLICATE, |
||||
|
/* Same ID, but otherwise different. */ |
||||
|
CHANNEL_ERR_DUPLICATE_ID_DIFFERENT, |
||||
|
/* Would exceed the specified max_htlc_value_in_flight_msat */ |
||||
|
CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED, |
||||
|
/* Can't afford it */ |
||||
|
CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED, |
||||
|
/* HTLC is below htlc_minimum_msat */ |
||||
|
CHANNEL_ERR_HTLC_BELOW_MINIMUM, |
||||
|
/* HTLC would push past max_accepted_htlcs */ |
||||
|
CHANNEL_ERR_TOO_MANY_HTLCS, |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
* channel_add_htlc: append an HTLC to channel if it can afford it |
||||
|
* @channel: The channel |
||||
|
* @offerer: the side offering the HTLC (to the other side). |
||||
|
* @id: unique HTLC id. |
||||
|
* @msatoshi: amount in millisatoshi. |
||||
|
* @expiry: block number when HTLC can no longer be redeemed. |
||||
|
* @payment_hash: hash whose preimage can redeem HTLC. |
||||
|
* @routing: routing information (copied) |
||||
|
* |
||||
|
* If this returns CHANNEL_ERR_NONE, the fee htlc was added and |
||||
|
* the output amounts adjusted accordingly. Otherwise nothing |
||||
|
* is changed. |
||||
|
*/ |
||||
|
enum channel_add_err channel_add_htlc(struct channel *channel, |
||||
|
enum side sender, |
||||
|
u64 id, |
||||
|
u64 msatoshi, |
||||
|
u32 expiry, |
||||
|
const struct sha256 *payment_hash, |
||||
|
const u8 routing[1254]); |
||||
|
|
||||
|
/**
|
||||
|
* channel_get_htlc: find an HTLC |
||||
|
* @channel: The channel |
||||
|
* @offerer: the side offering the HTLC. |
||||
|
* @id: unique HTLC id. |
||||
|
*/ |
||||
|
struct htlc *channel_get_htlc(struct channel *channel, enum side sender, u64 id); |
||||
|
|
||||
|
enum channel_remove_err { |
||||
|
/* All OK! */ |
||||
|
CHANNEL_ERR_REMOVE_OK, |
||||
|
/* No such HTLC. */ |
||||
|
CHANNEL_ERR_NO_SUCH_ID, |
||||
|
/* Already have fulfilled it */ |
||||
|
CHANNEL_ERR_ALREADY_FULFILLED, |
||||
|
/* Preimage doesn't hash to value. */ |
||||
|
CHANNEL_ERR_BAD_PREIMAGE, |
||||
|
/* HTLC is not committed */ |
||||
|
CHANNEL_ERR_HTLC_UNCOMMITTED, |
||||
|
/* HTLC is not committed and prior revoked on both sides */ |
||||
|
CHANNEL_ERR_HTLC_NOT_IRREVOCABLE |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
* channel_fail_htlc: remove an HTLC, funds to the side which offered it. |
||||
|
* @channel: The channel state |
||||
|
* @sender: the side fulfilling the HTLC (opposite to side which sent it) |
||||
|
* @id: unique HTLC id. |
||||
|
* |
||||
|
* This will remove the htlc and credit the value of the HTLC (back) |
||||
|
* to its offerer. |
||||
|
*/ |
||||
|
enum channel_remove_err channel_fail_htlc(struct channel *channel, |
||||
|
enum side sender, u64 id); |
||||
|
|
||||
|
/**
|
||||
|
* channel_fulfill_htlc: remove an HTLC, funds to side which accepted it. |
||||
|
* @channel: The channel state |
||||
|
* @sender: the side fulfilling the HTLC (opposite to side which sent it) |
||||
|
* @id: unique HTLC id. |
||||
|
* |
||||
|
* If the htlc exists, is not already fulfilled, the preimage is correct and |
||||
|
* HTLC committed at the recipient, this will add a pending change to |
||||
|
* remove the htlc and give the value of the HTLC to its recipient, |
||||
|
* and return CHANNEL_ERR_FULFILL_OK. Otherwise, it will return another error. |
||||
|
*/ |
||||
|
enum channel_remove_err channel_fulfill_htlc(struct channel *channel, |
||||
|
enum side sender, |
||||
|
u64 id, |
||||
|
const struct preimage *preimage); |
||||
|
|
||||
|
/**
|
||||
|
* approx_max_feerate: what's the we (initiator) could raise fee rate to? |
||||
|
* @channel: The channel state |
||||
|
* |
||||
|
* This is not exact! To check if their offer is valid, use can_afford_feerate. |
||||
|
*/ |
||||
|
u64 approx_max_feerate(const struct channel *channel); |
||||
|
|
||||
|
/**
|
||||
|
* can_afford_feerate: could the initiator pay for the fee at fee_rate? |
||||
|
* @channel: The channel state |
||||
|
* @feerate_per_kw: the new fee rate proposed |
||||
|
*/ |
||||
|
bool can_afford_feerate(const struct channel *channel, u64 feerate_per_kw); |
||||
|
|
||||
|
/**
|
||||
|
* adjust_fee: Change fee rate. |
||||
|
* @channel: The channel state |
||||
|
* @feerate_per_kw: fee in satoshi per 1000 bytes. |
||||
|
* @side: which side to adjust. |
||||
|
*/ |
||||
|
void adjust_fee(struct channel *channel, u64 feerate_per_kw, enum side side); |
||||
|
|
||||
|
/**
|
||||
|
* force_fee: Change fees to a specific value. |
||||
|
* @channel: The channel state |
||||
|
* @fee: fee in satoshi. |
||||
|
* |
||||
|
* This is used for the close transaction, which specifies an exact fee. |
||||
|
* If the fee cannot be paid in full, this return false (but cstate will |
||||
|
* still be altered). |
||||
|
*/ |
||||
|
bool force_fee(struct channel *channel, u64 fee); |
||||
|
|
||||
|
/**
|
||||
|
* channel_sent_commit: commit all remote outstanding changes. |
||||
|
* @channel: the channel |
||||
|
* |
||||
|
* This is where we commit to pending changes we've added; returns true if |
||||
|
* anything changed. */ |
||||
|
bool channel_sent_commit(struct channel *channel); |
||||
|
|
||||
|
/**
|
||||
|
* channel_rcvd_revoke_and_ack: accept ack on remote committed changes. |
||||
|
* @channel: the channel |
||||
|
* |
||||
|
* This is where we commit to pending changes we've added; returns true if |
||||
|
* anything changed. */ |
||||
|
bool channel_rcvd_revoke_and_ack(struct channel *channel); |
||||
|
|
||||
|
/**
|
||||
|
* channel_rcvd_commit: commit all local outstanding changes. |
||||
|
* @channel: the channel |
||||
|
* |
||||
|
* This is where we commit to pending changes we've added; returns true if |
||||
|
* anything changed. */ |
||||
|
bool channel_rcvd_commit(struct channel *channel); |
||||
|
|
||||
|
/**
|
||||
|
* channel_sent_revoke_and_ack: sent ack on local committed changes. |
||||
|
* @channel: the channel |
||||
|
* |
||||
|
* This is where we commit to pending changes we've added; returns true if |
||||
|
* anything changed. */ |
||||
|
bool channel_sent_revoke_and_ack(struct channel *channel); |
||||
|
|
||||
|
#endif /* LIGHTNING_DAEMON_CHANNEL_H */ |
@ -0,0 +1,501 @@ |
|||||
|
#include <status.h> |
||||
|
#include <stdio.h> |
||||
|
#define status_trace(fmt , ...) \ |
||||
|
printf(fmt "\n" , ## __VA_ARGS__) |
||||
|
|
||||
|
#include "../key_derive.c" |
||||
|
#include "../channel.c" |
||||
|
#include "../commit_tx.c" |
||||
|
#include "../htlc_tx.c" |
||||
|
#include <bitcoin/preimage.h> |
||||
|
#include <bitcoin/privkey.h> |
||||
|
#include <bitcoin/pubkey.h> |
||||
|
#include <ccan/err/err.h> |
||||
|
#include <ccan/str/hex/hex.h> |
||||
|
#include <type_to_string.h> |
||||
|
|
||||
|
static struct sha256 sha256_from_hex(const char *hex) |
||||
|
{ |
||||
|
struct sha256 sha256; |
||||
|
if (strstarts(hex, "0x")) |
||||
|
hex += 2; |
||||
|
if (!hex_decode(hex, strlen(hex), &sha256, sizeof(sha256))) |
||||
|
abort(); |
||||
|
return sha256; |
||||
|
} |
||||
|
|
||||
|
/* bitcoind loves its backwards txids! */ |
||||
|
static struct sha256_double txid_from_hex(const char *hex) |
||||
|
{ |
||||
|
struct sha256_double sha256; |
||||
|
struct sha256 rev = sha256_from_hex(hex); |
||||
|
size_t i; |
||||
|
|
||||
|
for (i = 0; i < sizeof(rev); i++) |
||||
|
sha256.sha.u.u8[sizeof(sha256) - 1 - i] = rev.u.u8[i]; |
||||
|
return sha256; |
||||
|
} |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* local_feerate_per_kw: 0 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 678 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 679 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 2168 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 2169 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 2294 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 2295 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 3872 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 3873 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 5149 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 5150 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 9651180 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 9651181 |
||||
|
* ... |
||||
|
* local_feerate_per_kw: 9651936 |
||||
|
*/ |
||||
|
static u64 feerates[] = { |
||||
|
0, |
||||
|
678, |
||||
|
679, |
||||
|
2168, |
||||
|
2169, |
||||
|
2294, |
||||
|
2295, |
||||
|
3872, |
||||
|
3873, |
||||
|
5149, |
||||
|
5150, |
||||
|
9651180, |
||||
|
9651181, |
||||
|
9651936 |
||||
|
}; |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* htlc 0 direction: remote->local |
||||
|
* htlc 0 amount_msat: 1000000 |
||||
|
* htlc 0 expiry: 500 |
||||
|
* htlc 0 payment_preimage: 0000000000000000000000000000000000000000000000000000000000000000 |
||||
|
* htlc 1 direction: remote->local |
||||
|
* htlc 1 amount_msat: 2000000 |
||||
|
* htlc 1 expiry: 501 |
||||
|
* htlc 1 payment_preimage: 0101010101010101010101010101010101010101010101010101010101010101 |
||||
|
* htlc 2 direction: local->remote |
||||
|
* htlc 2 amount_msat: 2000000 |
||||
|
* htlc 2 expiry: 502 |
||||
|
* htlc 2 payment_preimage: 0202020202020202020202020202020202020202020202020202020202020202 |
||||
|
* htlc 3 direction: local->remote |
||||
|
* htlc 3 amount_msat: 3000000 |
||||
|
* htlc 3 expiry: 503 |
||||
|
* htlc 3 payment_preimage: 0303030303030303030303030303030303030303030303030303030303030303 |
||||
|
* htlc 4 direction: remote->local |
||||
|
* htlc 4 amount_msat: 4000000 |
||||
|
* htlc 4 expiry: 504 |
||||
|
* htlc 4 payment_preimage: 0404040404040404040404040404040404040404040404040404040404040404 |
||||
|
*/ |
||||
|
static const struct htlc **add_htlcs(struct channel *channel, enum side side) |
||||
|
{ |
||||
|
int i; |
||||
|
const struct htlc **htlcs = tal_arr(channel, const struct htlc *, 5); |
||||
|
u8 *dummy_routing = tal_arr(htlcs, u8, 1254); |
||||
|
|
||||
|
for (i = 0; i < 5; i++) { |
||||
|
struct preimage preimage; |
||||
|
struct sha256 hash; |
||||
|
enum channel_add_err e; |
||||
|
enum side sender; |
||||
|
u64 msatoshi; |
||||
|
|
||||
|
switch (i) { |
||||
|
case 0: |
||||
|
sender = !side; |
||||
|
msatoshi = 1000000; |
||||
|
break; |
||||
|
case 1: |
||||
|
sender = !side; |
||||
|
msatoshi = 2000000; |
||||
|
break; |
||||
|
case 2: |
||||
|
sender = side; |
||||
|
msatoshi = 2000000; |
||||
|
break; |
||||
|
case 3: |
||||
|
sender = side; |
||||
|
msatoshi = 3000000; |
||||
|
break; |
||||
|
case 4: |
||||
|
sender = !side; |
||||
|
msatoshi = 4000000; |
||||
|
break; |
||||
|
} |
||||
|
memset(&preimage, i, sizeof(preimage)); |
||||
|
sha256(&hash, &preimage, sizeof(preimage)); |
||||
|
e = channel_add_htlc(channel, sender, i, msatoshi, 500+i, &hash, |
||||
|
dummy_routing); |
||||
|
assert(e == CHANNEL_ERR_ADD_OK); |
||||
|
htlcs[i] = channel_get_htlc(channel, sender, i); |
||||
|
} |
||||
|
tal_free(dummy_routing); |
||||
|
|
||||
|
/* Now make HTLCs fully committed. */ |
||||
|
channel_sent_commit(channel); |
||||
|
channel_rcvd_revoke_and_ack(channel); |
||||
|
channel_rcvd_commit(channel); |
||||
|
channel_sent_revoke_and_ack(channel); |
||||
|
channel_sent_commit(channel); |
||||
|
channel_rcvd_revoke_and_ack(channel); |
||||
|
return htlcs; |
||||
|
} |
||||
|
|
||||
|
static struct pubkey pubkey_from_hex(const char *hex) |
||||
|
{ |
||||
|
struct pubkey pubkey; |
||||
|
|
||||
|
if (strstarts(hex, "0x")) |
||||
|
hex += 2; |
||||
|
if (!pubkey_from_hexstr(hex, strlen(hex), &pubkey)) |
||||
|
abort(); |
||||
|
return pubkey; |
||||
|
} |
||||
|
|
||||
|
static void tx_must_be_eq(const struct bitcoin_tx *a, |
||||
|
const struct bitcoin_tx *b) |
||||
|
{ |
||||
|
tal_t *tmpctx = tal_tmpctx(NULL); |
||||
|
u8 *lina, *linb; |
||||
|
size_t i, len; |
||||
|
|
||||
|
lina = linearize_tx(tmpctx, a); |
||||
|
linb = linearize_tx(tmpctx, b); |
||||
|
|
||||
|
len = tal_len(lina); |
||||
|
if (tal_len(linb) < len) |
||||
|
len = tal_len(linb); |
||||
|
|
||||
|
for (i = 0; i < tal_len(lina); i++) { |
||||
|
if (i >= tal_len(linb)) |
||||
|
errx(1, "Second tx is truncated:\n" |
||||
|
"%s\n" |
||||
|
"%s", |
||||
|
tal_hex(tmpctx, lina), |
||||
|
tal_hex(tmpctx, linb)); |
||||
|
if (lina[i] != linb[i]) |
||||
|
errx(1, "tx differ at offset %zu:\n" |
||||
|
"%s\n" |
||||
|
"%s", |
||||
|
i, |
||||
|
tal_hex(tmpctx, lina), |
||||
|
tal_hex(tmpctx, linb)); |
||||
|
} |
||||
|
if (i != tal_len(linb)) |
||||
|
errx(1, "First tx is truncated:\n" |
||||
|
"%s\n" |
||||
|
"%s", |
||||
|
tal_hex(tmpctx, lina), |
||||
|
tal_hex(tmpctx, linb)); |
||||
|
tal_free(tmpctx); |
||||
|
} |
||||
|
|
||||
|
static void send_and_fulfill_htlc(struct channel *channel, |
||||
|
enum side sender, |
||||
|
u64 msatoshi) |
||||
|
{ |
||||
|
struct preimage r; |
||||
|
struct sha256 rhash; |
||||
|
u8 *dummy_routing = tal_arr(channel, u8, 1254); |
||||
|
|
||||
|
memset(&r, 0, sizeof(r)); |
||||
|
sha256(&rhash, &r, sizeof(r)); |
||||
|
|
||||
|
assert(channel_add_htlc(channel, sender, 1337, msatoshi, 900, &rhash, |
||||
|
dummy_routing) == CHANNEL_ERR_ADD_OK); |
||||
|
|
||||
|
if (sender == LOCAL) { |
||||
|
/* Step through a complete cycle. */ |
||||
|
channel_sent_commit(channel); |
||||
|
channel_rcvd_revoke_and_ack(channel); |
||||
|
channel_rcvd_commit(channel); |
||||
|
channel_sent_revoke_and_ack(channel); |
||||
|
assert(channel_fulfill_htlc(channel, REMOTE, 1337, &r) |
||||
|
== CHANNEL_ERR_REMOVE_OK); |
||||
|
channel_rcvd_commit(channel); |
||||
|
channel_sent_revoke_and_ack(channel); |
||||
|
channel_sent_commit(channel); |
||||
|
channel_rcvd_revoke_and_ack(channel); |
||||
|
assert(channel_get_htlc(channel, sender, 1337)->state |
||||
|
== RCVD_REMOVE_ACK_REVOCATION); |
||||
|
} else { |
||||
|
channel_rcvd_commit(channel); |
||||
|
channel_sent_revoke_and_ack(channel); |
||||
|
channel_sent_commit(channel); |
||||
|
channel_rcvd_revoke_and_ack(channel); |
||||
|
assert(channel_fulfill_htlc(channel, LOCAL, 1337, &r) |
||||
|
== CHANNEL_ERR_REMOVE_OK); |
||||
|
channel_sent_commit(channel); |
||||
|
channel_rcvd_revoke_and_ack(channel); |
||||
|
channel_rcvd_commit(channel); |
||||
|
channel_sent_revoke_and_ack(channel); |
||||
|
assert(channel_get_htlc(channel, sender, 1337)->state |
||||
|
== SENT_REMOVE_ACK_REVOCATION); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
tal_t *tmpctx = tal_tmpctx(NULL); |
||||
|
struct sha256_double funding_txid; |
||||
|
/* We test from both sides. */ |
||||
|
struct channel *lchannel, *rchannel; |
||||
|
u64 funding_amount_satoshi, feerate_per_kw; |
||||
|
unsigned int funding_output_index; |
||||
|
struct pubkey localkey, remotekey; |
||||
|
struct pubkey local_delayedkey; |
||||
|
struct pubkey local_revocation_key; |
||||
|
struct pubkey local_revocation_basepoint, local_delayed_payment_basepoint, |
||||
|
local_payment_basepoint, remote_payment_basepoint, |
||||
|
local_per_commitment_point; |
||||
|
struct pubkey *unknown = tal(tmpctx, struct pubkey); |
||||
|
struct bitcoin_tx *raw_tx, *tx; |
||||
|
struct channel_config *local_config = tal(tmpctx, struct channel_config); |
||||
|
struct channel_config *remote_config = tal(tmpctx, struct channel_config); |
||||
|
u64 to_local_msat, to_remote_msat; |
||||
|
const struct htlc **htlc_map, **htlcs; |
||||
|
size_t i; |
||||
|
|
||||
|
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY |
||||
|
| SECP256K1_CONTEXT_SIGN); |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* # Appendix C: Commitment and HTLC Transaction Test Vectors |
||||
|
* |
||||
|
* In the following: |
||||
|
* - we consider *local* transactions, which implies that all payments |
||||
|
* to *local* are delayed |
||||
|
* - we assume that *local* is the funder |
||||
|
* - private keys are displayed as 32 bytes plus a trailing 1 |
||||
|
* (bitcoin's convention for "compressed" private keys, i.e. keys |
||||
|
* for which the public key is compressed) |
||||
|
* |
||||
|
* - transaction signatures are all deterministic, using |
||||
|
* RFC6979 (using HMAC-SHA256) |
||||
|
* |
||||
|
* We start by defining common basic parameters for each test vector: |
||||
|
* the HTLCs are not used for the first "simple commitment tx with no |
||||
|
* HTLCs" test. |
||||
|
* |
||||
|
* funding_tx_id: 8984484a580b825b9972d7adb15050b3ab624ccd731946b3eeddb92f4e7ef6be |
||||
|
* funding_output_index: 0 |
||||
|
* funding_amount_satoshi: 10000000 |
||||
|
*... |
||||
|
* local_delay: 144 |
||||
|
* local_dust_limit_satoshi: 546 |
||||
|
*/ |
||||
|
funding_txid = txid_from_hex("8984484a580b825b9972d7adb15050b3ab624ccd731946b3eeddb92f4e7ef6be"); |
||||
|
funding_output_index = 0; |
||||
|
funding_amount_satoshi = 10000000; |
||||
|
|
||||
|
remote_config->to_self_delay = 144; |
||||
|
local_config->dust_limit_satoshis = 546; |
||||
|
/* This matters only because we check if added HTLC will create new
|
||||
|
* output, for fee considerations. */ |
||||
|
remote_config->dust_limit_satoshis = 546; |
||||
|
|
||||
|
local_config->max_htlc_value_in_flight_msat = -1ULL; |
||||
|
remote_config->max_htlc_value_in_flight_msat = -1ULL; |
||||
|
local_config->channel_reserve_satoshis = 0; |
||||
|
remote_config->channel_reserve_satoshis = 0; |
||||
|
local_config->htlc_minimum_msat = 0; |
||||
|
remote_config->htlc_minimum_msat = 0; |
||||
|
local_config->max_accepted_htlcs = 0xFFFF; |
||||
|
remote_config->max_accepted_htlcs = 0xFFFF; |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* # From local_revocation_basepoint_secret |
||||
|
* INTERNAL: local_revocation_basepoint: 02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27 |
||||
|
* # From local_delayed_payment_basepoint_secret |
||||
|
* INTERNAL: local_delayed_payment_basepoint: 023c72addb4fdf09af94f0c94d7fe92a386a7e70cf8a1d85916386bb2535c7b1b1 |
||||
|
*/ |
||||
|
local_revocation_basepoint = pubkey_from_hex("02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27"); |
||||
|
local_delayed_payment_basepoint = pubkey_from_hex("023c72addb4fdf09af94f0c94d7fe92a386a7e70cf8a1d85916386bb2535c7b1b1"); |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* local_payment_basepoint: 034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa |
||||
|
* remote_payment_basepoint: 032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991 |
||||
|
* # obscured commitment transaction number = 0x2bb038521914 ^ 42 |
||||
|
*/ |
||||
|
local_payment_basepoint = pubkey_from_hex("034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa"); |
||||
|
remote_payment_basepoint = pubkey_from_hex("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991"); |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* name: simple commitment tx with no HTLCs |
||||
|
* to_local_msat: 7000000000 |
||||
|
* to_remote_msat: 3000000000 |
||||
|
* feerate_per_kw: 15000 |
||||
|
*/ |
||||
|
|
||||
|
/* We put unknown in for some things; valgrind will warn if used. */ |
||||
|
to_local_msat = 7000000000; |
||||
|
to_remote_msat = 3000000000; |
||||
|
feerate_per_kw = 15000; |
||||
|
lchannel = new_channel(tmpctx, &funding_txid, funding_output_index, |
||||
|
funding_amount_satoshi, to_remote_msat, |
||||
|
feerate_per_kw, |
||||
|
local_config, |
||||
|
remote_config, |
||||
|
&local_revocation_basepoint, |
||||
|
unknown, |
||||
|
&local_payment_basepoint, |
||||
|
&remote_payment_basepoint, |
||||
|
&local_delayed_payment_basepoint, |
||||
|
unknown, |
||||
|
LOCAL); |
||||
|
|
||||
|
rchannel = new_channel(tmpctx, &funding_txid, funding_output_index, |
||||
|
funding_amount_satoshi, to_remote_msat, |
||||
|
feerate_per_kw, |
||||
|
remote_config, |
||||
|
local_config, |
||||
|
unknown, |
||||
|
&local_revocation_basepoint, |
||||
|
&remote_payment_basepoint, |
||||
|
&local_payment_basepoint, |
||||
|
unknown, |
||||
|
&local_delayed_payment_basepoint, |
||||
|
REMOTE); |
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* commitment_number: 42 |
||||
|
*/ |
||||
|
lchannel->view[LOCAL].commitment_number |
||||
|
= rchannel->view[REMOTE].commitment_number = 42; |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* INTERNAL: local_per_commitment_point: 025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486 |
||||
|
*/ |
||||
|
local_per_commitment_point = pubkey_from_hex("025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486"); |
||||
|
/* BOLT #3:
|
||||
|
* localkey: 030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e7 |
||||
|
* remotekey: 0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b |
||||
|
* local_delayedkey: 03fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c |
||||
|
* local_revocation_key: 0212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b19 |
||||
|
*/ |
||||
|
localkey = pubkey_from_hex("030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e7"); |
||||
|
remotekey = pubkey_from_hex("0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b"); |
||||
|
local_delayedkey = pubkey_from_hex("03fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c"); |
||||
|
local_revocation_key = pubkey_from_hex("0212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b19"); |
||||
|
|
||||
|
raw_tx = commit_tx(tmpctx, &funding_txid, funding_output_index, |
||||
|
funding_amount_satoshi, |
||||
|
LOCAL, remote_config->to_self_delay, |
||||
|
&local_revocation_key, |
||||
|
&local_delayedkey, |
||||
|
&localkey, |
||||
|
&remotekey, |
||||
|
feerate_per_kw, |
||||
|
local_config->dust_limit_satoshis, |
||||
|
to_local_msat, |
||||
|
to_remote_msat, |
||||
|
NULL, &htlc_map, 0x2bb038521914 ^ 42, LOCAL); |
||||
|
|
||||
|
tx = channel_tx(tmpctx, lchannel, &local_per_commitment_point, |
||||
|
&htlc_map, LOCAL); |
||||
|
tx_must_be_eq(tx, raw_tx); |
||||
|
|
||||
|
tx = channel_tx(tmpctx, rchannel, &local_per_commitment_point, |
||||
|
&htlc_map, REMOTE); |
||||
|
tx_must_be_eq(tx, raw_tx); |
||||
|
|
||||
|
/* BOLT #3:
|
||||
|
* |
||||
|
* name: commitment tx with all 5 htlcs untrimmed (minimum feerate) |
||||
|
* to_local_msat: 6988000000 |
||||
|
* to_remote_msat: 3000000000 |
||||
|
* local_feerate_per_kw: 0 |
||||
|
*/ |
||||
|
to_local_msat = 6988000000; |
||||
|
to_remote_msat = 3000000000; |
||||
|
feerate_per_kw = 0; |
||||
|
|
||||
|
/* Now, BOLT doesn't adjust owed amounts the same way we do
|
||||
|
* here: it's as if local side paid for all the HTLCs. We can |
||||
|
* fix this by having local side offer an HTLC, and having |
||||
|
* remote side accept it */ |
||||
|
send_and_fulfill_htlc(lchannel, LOCAL, 7000000); |
||||
|
send_and_fulfill_htlc(rchannel, REMOTE, 7000000); |
||||
|
|
||||
|
assert(lchannel->view[LOCAL].owed_msat[LOCAL] |
||||
|
== rchannel->view[REMOTE].owed_msat[REMOTE]); |
||||
|
assert(lchannel->view[REMOTE].owed_msat[REMOTE] |
||||
|
== rchannel->view[LOCAL].owed_msat[LOCAL]); |
||||
|
|
||||
|
raw_tx = channel_tx(tmpctx, lchannel, &local_per_commitment_point, |
||||
|
&htlc_map, LOCAL); |
||||
|
tx = channel_tx(tmpctx, rchannel, &local_per_commitment_point, |
||||
|
&htlc_map, REMOTE); |
||||
|
tx_must_be_eq(tx, raw_tx); |
||||
|
|
||||
|
/* FIXME: Adjust properly! */ |
||||
|
lchannel->view[LOCAL].feerate_per_kw = feerate_per_kw; |
||||
|
rchannel->view[REMOTE].feerate_per_kw = feerate_per_kw; |
||||
|
htlcs = add_htlcs(lchannel, LOCAL); |
||||
|
add_htlcs(rchannel, REMOTE); |
||||
|
|
||||
|
assert(lchannel->view[LOCAL].owed_msat[LOCAL] |
||||
|
== rchannel->view[REMOTE].owed_msat[REMOTE]); |
||||
|
assert(lchannel->view[REMOTE].owed_msat[REMOTE] |
||||
|
== rchannel->view[LOCAL].owed_msat[LOCAL]); |
||||
|
|
||||
|
for (i = 0; i < ARRAY_SIZE(feerates); i++) { |
||||
|
feerate_per_kw = feerates[i]; |
||||
|
|
||||
|
lchannel->view[LOCAL].feerate_per_kw = feerate_per_kw; |
||||
|
rchannel->view[REMOTE].feerate_per_kw = feerate_per_kw; |
||||
|
|
||||
|
raw_tx = commit_tx(tmpctx, &funding_txid, funding_output_index, |
||||
|
funding_amount_satoshi, |
||||
|
LOCAL, remote_config->to_self_delay, |
||||
|
&local_revocation_key, |
||||
|
&local_delayedkey, |
||||
|
&localkey, |
||||
|
&remotekey, |
||||
|
feerate_per_kw, |
||||
|
local_config->dust_limit_satoshis, |
||||
|
to_local_msat, |
||||
|
to_remote_msat, |
||||
|
htlcs, &htlc_map, |
||||
|
0x2bb038521914 ^ 42, LOCAL); |
||||
|
|
||||
|
tx = channel_tx(tmpctx, lchannel, &local_per_commitment_point, |
||||
|
&htlc_map, LOCAL); |
||||
|
tx_must_be_eq(tx, raw_tx); |
||||
|
|
||||
|
tx = channel_tx(tmpctx, rchannel, &local_per_commitment_point, |
||||
|
&htlc_map, REMOTE); |
||||
|
tx_must_be_eq(tx, raw_tx); |
||||
|
} |
||||
|
|
||||
|
/* No memory leaks please */ |
||||
|
secp256k1_context_destroy(secp256k1_ctx); |
||||
|
tal_free(tmpctx); |
||||
|
|
||||
|
/* FIXME: Do BOLT comparison! */ |
||||
|
return 0; |
||||
|
} |
Loading…
Reference in new issue