mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-23 15:00:34 +01:00
state: add callbacks for adding/removing watches.
This lets us eliminate struct state_effect altogether (the next patch removes the now-unused arguments). Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
1a20e8094f
commit
63ea6bfd7a
3 changed files with 447 additions and 686 deletions
221
state.c
221
state.c
|
@ -12,15 +12,6 @@ static inline bool high_priority(enum state state)
|
||||||
#define toggle_prio(state, name) \
|
#define toggle_prio(state, name) \
|
||||||
(!high_priority(state) ? name##_HIGHPRIO : name##_LOWPRIO)
|
(!high_priority(state) ? name##_HIGHPRIO : name##_LOWPRIO)
|
||||||
|
|
||||||
#define add_effect(e, field, val) \
|
|
||||||
do { \
|
|
||||||
struct state_effect *_e = tal(ctx, struct state_effect); \
|
|
||||||
_e->etype = STATE_EFFECT_##field; \
|
|
||||||
_e->u.field = (val); \
|
|
||||||
_e->next = (*e); \
|
|
||||||
(*e) = _e; \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
/* STATE_CLOSE* can be treated as a bitset offset from STATE_CLOSED */
|
/* STATE_CLOSE* can be treated as a bitset offset from STATE_CLOSED */
|
||||||
#define BITS_TO_STATE(bits) (STATE_CLOSED + (bits))
|
#define BITS_TO_STATE(bits) (STATE_CLOSED + (bits))
|
||||||
#define STATE_TO_BITS(state) ((state) - STATE_CLOSED)
|
#define STATE_TO_BITS(state) ((state) - STATE_CLOSED)
|
||||||
|
@ -110,7 +101,6 @@ enum command_status state(const tal_t *ctx,
|
||||||
Pkt *decline;
|
Pkt *decline;
|
||||||
struct bitcoin_tx *tx;
|
struct bitcoin_tx *tx;
|
||||||
Pkt *err;
|
Pkt *err;
|
||||||
struct htlc_watch *htlcs;
|
|
||||||
enum command_status cstatus = CMD_NONE;
|
enum command_status cstatus = CMD_NONE;
|
||||||
|
|
||||||
*out = NULL;
|
*out = NULL;
|
||||||
|
@ -183,13 +173,12 @@ enum command_status state(const tal_t *ctx,
|
||||||
}
|
}
|
||||||
queue_pkt(out,
|
queue_pkt(out,
|
||||||
pkt_open_commit_sig(ctx, peer));
|
pkt_open_commit_sig(ctx, peer));
|
||||||
add_effect(effect, watch,
|
peer_watch_anchor(peer,
|
||||||
bitcoin_watch_anchor(ctx, peer,
|
BITCOIN_ANCHOR_DEPTHOK,
|
||||||
BITCOIN_ANCHOR_DEPTHOK,
|
BITCOIN_ANCHOR_TIMEOUT,
|
||||||
BITCOIN_ANCHOR_TIMEOUT,
|
BITCOIN_ANCHOR_UNSPENT,
|
||||||
BITCOIN_ANCHOR_UNSPENT,
|
BITCOIN_ANCHOR_THEIRSPEND,
|
||||||
BITCOIN_ANCHOR_THEIRSPEND,
|
BITCOIN_ANCHOR_OTHERSPEND);
|
||||||
BITCOIN_ANCHOR_OTHERSPEND));
|
|
||||||
|
|
||||||
return next_state(peer, cstatus,
|
return next_state(peer, cstatus,
|
||||||
STATE_OPEN_WAITING_THEIRANCHOR);
|
STATE_OPEN_WAITING_THEIRANCHOR);
|
||||||
|
@ -210,13 +199,12 @@ enum command_status state(const tal_t *ctx,
|
||||||
goto err_start_unilateral_close;
|
goto err_start_unilateral_close;
|
||||||
}
|
}
|
||||||
queue_tx_broadcast(broadcast, bitcoin_anchor(ctx, peer));
|
queue_tx_broadcast(broadcast, bitcoin_anchor(ctx, peer));
|
||||||
add_effect(effect, watch,
|
peer_watch_anchor(peer,
|
||||||
bitcoin_watch_anchor(ctx, peer,
|
BITCOIN_ANCHOR_DEPTHOK,
|
||||||
BITCOIN_ANCHOR_DEPTHOK,
|
INPUT_NONE,
|
||||||
INPUT_NONE,
|
BITCOIN_ANCHOR_UNSPENT,
|
||||||
BITCOIN_ANCHOR_UNSPENT,
|
BITCOIN_ANCHOR_THEIRSPEND,
|
||||||
BITCOIN_ANCHOR_THEIRSPEND,
|
BITCOIN_ANCHOR_OTHERSPEND);
|
||||||
BITCOIN_ANCHOR_OTHERSPEND));
|
|
||||||
return next_state(peer, cstatus,
|
return next_state(peer, cstatus,
|
||||||
STATE_OPEN_WAITING_OURANCHOR);
|
STATE_OPEN_WAITING_OURANCHOR);
|
||||||
} else if (input_is(input, CMD_CLOSE)) {
|
} else if (input_is(input, CMD_CLOSE)) {
|
||||||
|
@ -249,10 +237,9 @@ enum command_status state(const tal_t *ctx,
|
||||||
goto anchor_unspent;
|
goto anchor_unspent;
|
||||||
} else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) {
|
} else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) {
|
||||||
/* We no longer care about anchor depth. */
|
/* We no longer care about anchor depth. */
|
||||||
add_effect(effect, unwatch,
|
peer_unwatch_anchor_depth(peer,
|
||||||
bitcoin_unwatch_anchor_depth(ctx, peer,
|
BITCOIN_ANCHOR_DEPTHOK,
|
||||||
BITCOIN_ANCHOR_DEPTHOK,
|
INPUT_NONE);
|
||||||
INPUT_NONE));
|
|
||||||
complete_cmd(peer, &cstatus, CMD_FAIL);
|
complete_cmd(peer, &cstatus, CMD_FAIL);
|
||||||
goto them_unilateral;
|
goto them_unilateral;
|
||||||
} else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) {
|
} else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) {
|
||||||
|
@ -260,26 +247,23 @@ enum command_status state(const tal_t *ctx,
|
||||||
return next_state(peer, cstatus, STATE_ERR_INFORMATION_LEAK);
|
return next_state(peer, cstatus, STATE_ERR_INFORMATION_LEAK);
|
||||||
} else if (input_is(input, CMD_CLOSE)) {
|
} else if (input_is(input, CMD_CLOSE)) {
|
||||||
/* We no longer care about anchor depth. */
|
/* We no longer care about anchor depth. */
|
||||||
add_effect(effect, unwatch,
|
peer_unwatch_anchor_depth(peer,
|
||||||
bitcoin_unwatch_anchor_depth(ctx, peer,
|
BITCOIN_ANCHOR_DEPTHOK,
|
||||||
BITCOIN_ANCHOR_DEPTHOK,
|
INPUT_NONE);
|
||||||
INPUT_NONE));
|
|
||||||
complete_cmd(peer, &cstatus, CMD_FAIL);
|
complete_cmd(peer, &cstatus, CMD_FAIL);
|
||||||
goto start_closing;
|
goto start_closing;
|
||||||
} else if (input_is(input, PKT_CLOSE)) {
|
} else if (input_is(input, PKT_CLOSE)) {
|
||||||
/* We no longer care about anchor depth. */
|
/* We no longer care about anchor depth. */
|
||||||
add_effect(effect, unwatch,
|
peer_unwatch_anchor_depth(peer,
|
||||||
bitcoin_unwatch_anchor_depth(ctx, peer,
|
BITCOIN_ANCHOR_DEPTHOK,
|
||||||
BITCOIN_ANCHOR_DEPTHOK,
|
INPUT_NONE);
|
||||||
INPUT_NONE));
|
|
||||||
complete_cmd(peer, &cstatus, CMD_FAIL);
|
complete_cmd(peer, &cstatus, CMD_FAIL);
|
||||||
goto accept_closing;
|
goto accept_closing;
|
||||||
} else if (input_is_pkt(input)) {
|
} else if (input_is_pkt(input)) {
|
||||||
/* We no longer care about anchor depth. */
|
/* We no longer care about anchor depth. */
|
||||||
add_effect(effect, unwatch,
|
peer_unwatch_anchor_depth(peer,
|
||||||
bitcoin_unwatch_anchor_depth(ctx, peer,
|
BITCOIN_ANCHOR_DEPTHOK,
|
||||||
BITCOIN_ANCHOR_DEPTHOK,
|
INPUT_NONE);
|
||||||
INPUT_NONE));
|
|
||||||
complete_cmd(peer, &cstatus, CMD_FAIL);
|
complete_cmd(peer, &cstatus, CMD_FAIL);
|
||||||
goto unexpected_pkt_nocleanup;
|
goto unexpected_pkt_nocleanup;
|
||||||
}
|
}
|
||||||
|
@ -315,34 +299,30 @@ enum command_status state(const tal_t *ctx,
|
||||||
STATE_ERR_INFORMATION_LEAK);
|
STATE_ERR_INFORMATION_LEAK);
|
||||||
} else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) {
|
} else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) {
|
||||||
/* We no longer care about anchor depth. */
|
/* We no longer care about anchor depth. */
|
||||||
add_effect(effect, unwatch,
|
peer_unwatch_anchor_depth(peer,
|
||||||
bitcoin_unwatch_anchor_depth(ctx, peer,
|
BITCOIN_ANCHOR_DEPTHOK,
|
||||||
BITCOIN_ANCHOR_DEPTHOK,
|
BITCOIN_ANCHOR_TIMEOUT);
|
||||||
BITCOIN_ANCHOR_TIMEOUT));
|
|
||||||
complete_cmd(peer, &cstatus, CMD_FAIL);
|
complete_cmd(peer, &cstatus, CMD_FAIL);
|
||||||
goto them_unilateral;
|
goto them_unilateral;
|
||||||
} else if (input_is(input, CMD_CLOSE)) {
|
} else if (input_is(input, CMD_CLOSE)) {
|
||||||
/* We no longer care about anchor depth. */
|
/* We no longer care about anchor depth. */
|
||||||
add_effect(effect, unwatch,
|
peer_unwatch_anchor_depth(peer,
|
||||||
bitcoin_unwatch_anchor_depth(ctx, peer,
|
BITCOIN_ANCHOR_DEPTHOK,
|
||||||
BITCOIN_ANCHOR_DEPTHOK,
|
BITCOIN_ANCHOR_TIMEOUT);
|
||||||
BITCOIN_ANCHOR_TIMEOUT));
|
|
||||||
complete_cmd(peer, &cstatus, CMD_FAIL);
|
complete_cmd(peer, &cstatus, CMD_FAIL);
|
||||||
goto start_closing;
|
goto start_closing;
|
||||||
} else if (input_is(input, PKT_CLOSE)) {
|
} else if (input_is(input, PKT_CLOSE)) {
|
||||||
/* We no longer care about anchor depth. */
|
/* We no longer care about anchor depth. */
|
||||||
add_effect(effect, unwatch,
|
peer_unwatch_anchor_depth(peer,
|
||||||
bitcoin_unwatch_anchor_depth(ctx, peer,
|
BITCOIN_ANCHOR_DEPTHOK,
|
||||||
BITCOIN_ANCHOR_DEPTHOK,
|
BITCOIN_ANCHOR_TIMEOUT);
|
||||||
BITCOIN_ANCHOR_TIMEOUT));
|
|
||||||
complete_cmd(peer, &cstatus, CMD_FAIL);
|
complete_cmd(peer, &cstatus, CMD_FAIL);
|
||||||
goto accept_closing;
|
goto accept_closing;
|
||||||
} else if (input_is_pkt(input)) {
|
} else if (input_is_pkt(input)) {
|
||||||
/* We no longer care about anchor depth. */
|
/* We no longer care about anchor depth. */
|
||||||
add_effect(effect, unwatch,
|
peer_unwatch_anchor_depth(peer,
|
||||||
bitcoin_unwatch_anchor_depth(ctx, peer,
|
BITCOIN_ANCHOR_DEPTHOK,
|
||||||
BITCOIN_ANCHOR_DEPTHOK,
|
BITCOIN_ANCHOR_TIMEOUT);
|
||||||
BITCOIN_ANCHOR_TIMEOUT));
|
|
||||||
complete_cmd(peer, &cstatus, CMD_FAIL);
|
complete_cmd(peer, &cstatus, CMD_FAIL);
|
||||||
goto unexpected_pkt;
|
goto unexpected_pkt;
|
||||||
}
|
}
|
||||||
|
@ -738,8 +718,7 @@ enum command_status state(const tal_t *ctx,
|
||||||
/* One a steal is complete, we don't care about htlcs
|
/* One a steal is complete, we don't care about htlcs
|
||||||
* (we stole them all) */
|
* (we stole them all) */
|
||||||
if (bits & STATE_CLOSE_HTLCS_BIT)
|
if (bits & STATE_CLOSE_HTLCS_BIT)
|
||||||
add_effect(effect, unwatch_htlc,
|
peer_unwatch_all_htlc_outputs(peer);
|
||||||
htlc_unwatch_all(ctx, peer));
|
|
||||||
return next_state(peer, cstatus, STATE_CLOSED);
|
return next_state(peer, cstatus, STATE_CLOSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,9 +743,7 @@ enum command_status state(const tal_t *ctx,
|
||||||
tx = bitcoin_spend_ours(ctx, peer);
|
tx = bitcoin_spend_ours(ctx, peer);
|
||||||
/* Now we need to wait for our commit to be done. */
|
/* Now we need to wait for our commit to be done. */
|
||||||
queue_tx_broadcast(broadcast, tx);
|
queue_tx_broadcast(broadcast, tx);
|
||||||
add_effect(effect, watch,
|
peer_watch_tx(peer, tx, BITCOIN_SPEND_OURS_DONE);
|
||||||
bitcoin_watch(ctx, tx,
|
|
||||||
BITCOIN_SPEND_OURS_DONE));
|
|
||||||
bits &= ~STATE_CLOSE_OURCOMMIT_BIT;
|
bits &= ~STATE_CLOSE_OURCOMMIT_BIT;
|
||||||
bits |= STATE_CLOSE_SPENDOURS_BIT;
|
bits |= STATE_CLOSE_SPENDOURS_BIT;
|
||||||
return next_state(peer, cstatus, BITS_TO_STATE(bits));
|
return next_state(peer, cstatus, BITS_TO_STATE(bits));
|
||||||
|
@ -791,9 +768,8 @@ enum command_status state(const tal_t *ctx,
|
||||||
/* They revealed R value. */
|
/* They revealed R value. */
|
||||||
peer_tx_revealed_r_value(peer, idata->btc);
|
peer_tx_revealed_r_value(peer, idata->btc);
|
||||||
/* We don't care any more. */
|
/* We don't care any more. */
|
||||||
add_effect(effect, unwatch_htlc,
|
peer_unwatch_htlc_output(peer, idata->htlc,
|
||||||
htlc_unwatch(ctx, idata->htlc,
|
INPUT_NO_MORE_HTLCS);
|
||||||
INPUT_NO_MORE_HTLCS));
|
|
||||||
return unchanged_state(cstatus);
|
return unchanged_state(cstatus);
|
||||||
} else if (input_is(input, BITCOIN_HTLC_TOTHEM_TIMEOUT)){
|
} else if (input_is(input, BITCOIN_HTLC_TOTHEM_TIMEOUT)){
|
||||||
tx = bitcoin_htlc_timeout(ctx,
|
tx = bitcoin_htlc_timeout(ctx,
|
||||||
|
@ -805,11 +781,8 @@ enum command_status state(const tal_t *ctx,
|
||||||
* try to spend, revealing rvalue. */
|
* try to spend, revealing rvalue. */
|
||||||
|
|
||||||
/* We're done when that gets buried. */
|
/* We're done when that gets buried. */
|
||||||
add_effect(effect, watch_htlc_spend,
|
peer_watch_htlc_spend(peer, tx, idata->htlc,
|
||||||
htlc_spend_watch(ctx,
|
BITCOIN_HTLC_RETURN_SPEND_DONE);
|
||||||
tx,
|
|
||||||
idata->cmd,
|
|
||||||
BITCOIN_HTLC_RETURN_SPEND_DONE));
|
|
||||||
return unchanged_state(cstatus);
|
return unchanged_state(cstatus);
|
||||||
} else if (input_is(input, INPUT_RVALUE)) {
|
} else if (input_is(input, INPUT_RVALUE)) {
|
||||||
tx = bitcoin_htlc_spend(ctx, peer,
|
tx = bitcoin_htlc_spend(ctx, peer,
|
||||||
|
@ -818,44 +791,34 @@ enum command_status state(const tal_t *ctx,
|
||||||
/* Spend it... */
|
/* Spend it... */
|
||||||
queue_tx_broadcast(broadcast, tx);
|
queue_tx_broadcast(broadcast, tx);
|
||||||
/* We're done when it gets buried. */
|
/* We're done when it gets buried. */
|
||||||
add_effect(effect, watch_htlc_spend,
|
peer_watch_htlc_spend(peer, tx, idata->htlc,
|
||||||
htlc_spend_watch(ctx,
|
BITCOIN_HTLC_FULFILL_SPEND_DONE);
|
||||||
tx,
|
|
||||||
idata->cmd,
|
|
||||||
BITCOIN_HTLC_FULFILL_SPEND_DONE));
|
|
||||||
/* Don't care about this one any more. */
|
/* Don't care about this one any more. */
|
||||||
add_effect(effect, unwatch_htlc,
|
peer_unwatch_htlc_output(peer, idata->htlc,
|
||||||
htlc_unwatch(ctx, idata->htlc,
|
INPUT_NO_MORE_HTLCS);
|
||||||
INPUT_NO_MORE_HTLCS));
|
|
||||||
return unchanged_state(cstatus);
|
return unchanged_state(cstatus);
|
||||||
} else if (input_is(input, BITCOIN_HTLC_FULFILL_SPEND_DONE)) {
|
} else if (input_is(input, BITCOIN_HTLC_FULFILL_SPEND_DONE)) {
|
||||||
/* Stop watching spend, send
|
/* Stop watching spend, send
|
||||||
* INPUT_NO_MORE_HTLCS when done. */
|
* INPUT_NO_MORE_HTLCS when done. */
|
||||||
add_effect(effect, unwatch_htlc_spend,
|
peer_unwatch_htlc_spend(peer, idata->htlc,
|
||||||
htlc_spend_unwatch(ctx,
|
INPUT_NO_MORE_HTLCS);
|
||||||
idata->htlc,
|
|
||||||
INPUT_NO_MORE_HTLCS));
|
|
||||||
return unchanged_state(cstatus);
|
return unchanged_state(cstatus);
|
||||||
} else if (input_is(input, BITCOIN_HTLC_RETURN_SPEND_DONE)) {
|
} else if (input_is(input, BITCOIN_HTLC_RETURN_SPEND_DONE)) {
|
||||||
/* Stop watching spend, send
|
/* Stop watching spend, send
|
||||||
* INPUT_NO_MORE_HTLCS when done. */
|
* INPUT_NO_MORE_HTLCS when done. */
|
||||||
add_effect(effect, unwatch_htlc_spend,
|
peer_unwatch_htlc_spend(peer, idata->htlc,
|
||||||
htlc_spend_unwatch(ctx,
|
INPUT_NO_MORE_HTLCS);
|
||||||
idata->htlc,
|
|
||||||
INPUT_NO_MORE_HTLCS));
|
|
||||||
|
|
||||||
/* Don't need to watch the HTLC output any more,
|
/* Don't need to watch the HTLC output any more,
|
||||||
* either. */
|
* either. */
|
||||||
add_effect(effect, unwatch_htlc,
|
peer_unwatch_htlc_output(peer, idata->htlc,
|
||||||
htlc_unwatch(ctx, idata->htlc,
|
INPUT_NO_MORE_HTLCS);
|
||||||
INPUT_NO_MORE_HTLCS));
|
|
||||||
return unchanged_state(cstatus);
|
return unchanged_state(cstatus);
|
||||||
} else if (input_is(input, BITCOIN_HTLC_TOUS_TIMEOUT)) {
|
} else if (input_is(input, BITCOIN_HTLC_TOUS_TIMEOUT)) {
|
||||||
/* They can spend, we no longer care
|
/* They can spend, we no longer care
|
||||||
* about this HTLC. */
|
* about this HTLC. */
|
||||||
add_effect(effect, unwatch_htlc,
|
peer_unwatch_htlc_output(peer, idata->htlc,
|
||||||
htlc_unwatch(ctx, idata->htlc,
|
INPUT_NO_MORE_HTLCS);
|
||||||
INPUT_NO_MORE_HTLCS));
|
|
||||||
return unchanged_state(cstatus);
|
return unchanged_state(cstatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -871,19 +834,14 @@ enum command_status state(const tal_t *ctx,
|
||||||
if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) {
|
if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) {
|
||||||
tx = bitcoin_spend_theirs(ctx, peer, idata->btc);
|
tx = bitcoin_spend_theirs(ctx, peer, idata->btc);
|
||||||
queue_tx_broadcast(broadcast, tx);
|
queue_tx_broadcast(broadcast, tx);
|
||||||
add_effect(effect, watch,
|
peer_watch_tx(peer, tx, BITCOIN_SPEND_THEIRS_DONE);
|
||||||
bitcoin_watch(ctx, tx,
|
/* HTLC watches: if any, set HTLCs bit. */
|
||||||
BITCOIN_SPEND_THEIRS_DONE));
|
if (peer_watch_their_htlc_outputs(peer, idata->btc,
|
||||||
/* HTLC watches. */
|
|
||||||
htlcs = htlc_outputs_their_commit(ctx, peer,
|
|
||||||
idata->btc,
|
|
||||||
BITCOIN_HTLC_TOUS_TIMEOUT,
|
BITCOIN_HTLC_TOUS_TIMEOUT,
|
||||||
BITCOIN_HTLC_TOTHEM_SPENT,
|
BITCOIN_HTLC_TOTHEM_SPENT,
|
||||||
BITCOIN_HTLC_TOTHEM_TIMEOUT);
|
BITCOIN_HTLC_TOTHEM_TIMEOUT))
|
||||||
if (htlcs) {
|
|
||||||
add_effect(effect, watch_htlcs, htlcs);
|
|
||||||
bits |= STATE_CLOSE_HTLCS_BIT;
|
bits |= STATE_CLOSE_HTLCS_BIT;
|
||||||
}
|
|
||||||
bits |= STATE_CLOSE_SPENDTHEM_BIT;
|
bits |= STATE_CLOSE_SPENDTHEM_BIT;
|
||||||
return next_state_bits(peer, cstatus, bits);
|
return next_state_bits(peer, cstatus, bits);
|
||||||
/* This can happen multiple times: need to steal ALL */
|
/* This can happen multiple times: need to steal ALL */
|
||||||
|
@ -893,9 +851,7 @@ enum command_status state(const tal_t *ctx,
|
||||||
return next_state(peer, cstatus,
|
return next_state(peer, cstatus,
|
||||||
STATE_ERR_INFORMATION_LEAK);
|
STATE_ERR_INFORMATION_LEAK);
|
||||||
queue_tx_broadcast(broadcast, tx);
|
queue_tx_broadcast(broadcast, tx);
|
||||||
add_effect(effect, watch,
|
peer_watch_tx(peer, tx, BITCOIN_STEAL_DONE);
|
||||||
bitcoin_watch(ctx, tx,
|
|
||||||
BITCOIN_STEAL_DONE));
|
|
||||||
bits |= STATE_CLOSE_STEAL_BIT;
|
bits |= STATE_CLOSE_STEAL_BIT;
|
||||||
return next_state_bits(peer, cstatus, bits);
|
return next_state_bits(peer, cstatus, bits);
|
||||||
} else if (input_is(input, BITCOIN_ANCHOR_UNSPENT))
|
} else if (input_is(input, BITCOIN_ANCHOR_UNSPENT))
|
||||||
|
@ -981,20 +937,16 @@ start_unilateral_close:
|
||||||
set_peer_cond(peer, PEER_CLOSED);
|
set_peer_cond(peer, PEER_CLOSED);
|
||||||
tx = bitcoin_commit(ctx, peer);
|
tx = bitcoin_commit(ctx, peer);
|
||||||
queue_tx_broadcast(broadcast, tx);
|
queue_tx_broadcast(broadcast, tx);
|
||||||
add_effect(effect, watch,
|
peer_watch_delayed(peer, tx, BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED);
|
||||||
bitcoin_watch_delayed(ctx, tx,
|
|
||||||
BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED));
|
|
||||||
|
|
||||||
/* HTLC watches. */
|
/* HTLC watches. */
|
||||||
htlcs = htlc_outputs_our_commit(ctx, peer, tx,
|
if (peer_watch_our_htlc_outputs(peer, tx,
|
||||||
BITCOIN_HTLC_TOUS_TIMEOUT,
|
BITCOIN_HTLC_TOUS_TIMEOUT,
|
||||||
BITCOIN_HTLC_TOTHEM_SPENT,
|
BITCOIN_HTLC_TOTHEM_SPENT,
|
||||||
BITCOIN_HTLC_TOTHEM_TIMEOUT);
|
BITCOIN_HTLC_TOTHEM_TIMEOUT))
|
||||||
if (htlcs) {
|
|
||||||
add_effect(effect, watch_htlcs, htlcs);
|
|
||||||
return next_state(peer, cstatus,
|
return next_state(peer, cstatus,
|
||||||
STATE_CLOSE_WAIT_OURCOMMIT_WITH_HTLCS);
|
STATE_CLOSE_WAIT_OURCOMMIT_WITH_HTLCS);
|
||||||
}
|
|
||||||
return next_state(peer, cstatus, STATE_CLOSE_WAIT_OURCOMMIT);
|
return next_state(peer, cstatus, STATE_CLOSE_WAIT_OURCOMMIT);
|
||||||
|
|
||||||
err_start_unilateral_close_already_closing:
|
err_start_unilateral_close_already_closing:
|
||||||
|
@ -1011,9 +963,7 @@ start_unilateral_close_already_closing:
|
||||||
set_peer_cond(peer, PEER_CLOSED);
|
set_peer_cond(peer, PEER_CLOSED);
|
||||||
tx = bitcoin_commit(ctx, peer);
|
tx = bitcoin_commit(ctx, peer);
|
||||||
queue_tx_broadcast(broadcast, tx);
|
queue_tx_broadcast(broadcast, tx);
|
||||||
add_effect(effect, watch,
|
peer_watch_delayed(peer, tx, BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED);
|
||||||
bitcoin_watch_delayed(ctx, tx,
|
|
||||||
BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED));
|
|
||||||
|
|
||||||
/* We agreed to close: shouldn't have any HTLCs */
|
/* We agreed to close: shouldn't have any HTLCs */
|
||||||
if (committed_to_htlcs(peer))
|
if (committed_to_htlcs(peer))
|
||||||
|
@ -1033,21 +983,17 @@ them_unilateral:
|
||||||
set_peer_cond(peer, PEER_CLOSED);
|
set_peer_cond(peer, PEER_CLOSED);
|
||||||
tx = bitcoin_spend_theirs(ctx, peer, idata->btc);
|
tx = bitcoin_spend_theirs(ctx, peer, idata->btc);
|
||||||
queue_tx_broadcast(broadcast, tx);
|
queue_tx_broadcast(broadcast, tx);
|
||||||
add_effect(effect, watch,
|
peer_watch_tx(peer, tx, BITCOIN_SPEND_THEIRS_DONE);
|
||||||
bitcoin_watch(ctx, tx,
|
|
||||||
BITCOIN_SPEND_THEIRS_DONE));
|
|
||||||
|
|
||||||
/* HTLC watches (based on what they broadcast, which *may* be out
|
/* HTLC watches (based on what they broadcast, which *may* be out
|
||||||
* of step with our current state by +/- 1 htlc. */
|
* of step with our current state by +/- 1 htlc. */
|
||||||
htlcs = htlc_outputs_their_commit(ctx, peer, idata->btc,
|
if (peer_watch_their_htlc_outputs(peer, idata->btc,
|
||||||
BITCOIN_HTLC_TOUS_TIMEOUT,
|
BITCOIN_HTLC_TOUS_TIMEOUT,
|
||||||
BITCOIN_HTLC_TOTHEM_SPENT,
|
BITCOIN_HTLC_TOTHEM_SPENT,
|
||||||
BITCOIN_HTLC_TOTHEM_TIMEOUT);
|
BITCOIN_HTLC_TOTHEM_TIMEOUT))
|
||||||
if (htlcs) {
|
|
||||||
add_effect(effect, watch_htlcs, htlcs);
|
|
||||||
return next_state(peer, cstatus,
|
return next_state(peer, cstatus,
|
||||||
STATE_CLOSE_WAIT_SPENDTHEM_WITH_HTLCS);
|
STATE_CLOSE_WAIT_SPENDTHEM_WITH_HTLCS);
|
||||||
}
|
|
||||||
return next_state(peer, cstatus, STATE_CLOSE_WAIT_SPENDTHEM);
|
return next_state(peer, cstatus, STATE_CLOSE_WAIT_SPENDTHEM);
|
||||||
|
|
||||||
accept_htlc_update:
|
accept_htlc_update:
|
||||||
|
@ -1100,10 +1046,7 @@ start_closing:
|
||||||
err = pkt_err(ctx, "Close forced due to HTLCs");
|
err = pkt_err(ctx, "Close forced due to HTLCs");
|
||||||
goto err_start_unilateral_close;
|
goto err_start_unilateral_close;
|
||||||
}
|
}
|
||||||
add_effect(effect, close_timeout, INPUT_CLOSE_COMPLETE_TIMEOUT);
|
peer_watch_close(peer, BITCOIN_CLOSE_DONE, INPUT_CLOSE_COMPLETE_TIMEOUT);
|
||||||
|
|
||||||
add_effect(effect, watch,
|
|
||||||
bitcoin_watch_close(ctx, peer, BITCOIN_CLOSE_DONE));
|
|
||||||
|
|
||||||
/* No more commands, we're already closing. */
|
/* No more commands, we're already closing. */
|
||||||
set_peer_cond(peer, PEER_CLOSING);
|
set_peer_cond(peer, PEER_CLOSING);
|
||||||
|
@ -1116,9 +1059,9 @@ accept_closing:
|
||||||
err = accept_pkt_close(ctx, peer, idata->pkt, effect);
|
err = accept_pkt_close(ctx, peer, idata->pkt, effect);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_start_unilateral_close;
|
goto err_start_unilateral_close;
|
||||||
/* As soon as we send packet, they could close. */
|
peer_watch_close(peer, BITCOIN_CLOSE_DONE, INPUT_NONE);
|
||||||
add_effect(effect, watch,
|
/* Send close TX. */
|
||||||
bitcoin_watch_close(ctx, peer, BITCOIN_CLOSE_DONE));
|
queue_tx_broadcast(broadcast, bitcoin_close(ctx, peer));
|
||||||
queue_pkt(out, pkt_close_complete(ctx, peer));
|
queue_pkt(out, pkt_close_complete(ctx, peer));
|
||||||
/* No more commands, we're already closing. */
|
/* No more commands, we're already closing. */
|
||||||
set_peer_cond(peer, PEER_CLOSING);
|
set_peer_cond(peer, PEER_CLOSING);
|
||||||
|
@ -1151,18 +1094,14 @@ fail_during_close:
|
||||||
/* A reorganization could make this happen. */
|
/* A reorganization could make this happen. */
|
||||||
tx = bitcoin_spend_theirs(ctx, peer, idata->btc);
|
tx = bitcoin_spend_theirs(ctx, peer, idata->btc);
|
||||||
queue_tx_broadcast(broadcast, tx);
|
queue_tx_broadcast(broadcast, tx);
|
||||||
add_effect(effect, watch,
|
peer_watch_tx(peer, tx, BITCOIN_SPEND_THEIRS_DONE);
|
||||||
bitcoin_watch(ctx, tx,
|
if (peer_watch_their_htlc_outputs(peer, idata->btc,
|
||||||
BITCOIN_SPEND_THEIRS_DONE));
|
|
||||||
htlcs = htlc_outputs_their_commit(ctx, peer, idata->btc,
|
|
||||||
BITCOIN_HTLC_TOUS_TIMEOUT,
|
BITCOIN_HTLC_TOUS_TIMEOUT,
|
||||||
BITCOIN_HTLC_TOTHEM_SPENT,
|
BITCOIN_HTLC_TOTHEM_SPENT,
|
||||||
BITCOIN_HTLC_TOTHEM_TIMEOUT);
|
BITCOIN_HTLC_TOTHEM_TIMEOUT)) {
|
||||||
/* Expect either close or spendthem to complete */
|
/* Expect either close or spendthem to complete */
|
||||||
if (htlcs) {
|
|
||||||
/* FIXME: Make sure caller uses INPUT_RVAL
|
/* FIXME: Make sure caller uses INPUT_RVAL
|
||||||
* if they were in the middle of FULFILL! */
|
* if they were in the middle of FULFILL! */
|
||||||
add_effect(effect, watch_htlcs, htlcs);
|
|
||||||
return next_state(peer, cstatus,
|
return next_state(peer, cstatus,
|
||||||
STATE_CLOSE_WAIT_SPENDTHEM_CLOSE_WITH_HTLCS);
|
STATE_CLOSE_WAIT_SPENDTHEM_CLOSE_WITH_HTLCS);
|
||||||
}
|
}
|
||||||
|
@ -1174,8 +1113,7 @@ fail_during_close:
|
||||||
return next_state(peer, cstatus,
|
return next_state(peer, cstatus,
|
||||||
STATE_ERR_INFORMATION_LEAK);
|
STATE_ERR_INFORMATION_LEAK);
|
||||||
queue_tx_broadcast(broadcast, tx);
|
queue_tx_broadcast(broadcast, tx);
|
||||||
add_effect(effect, watch,
|
peer_watch_tx(peer, tx, BITCOIN_STEAL_DONE);
|
||||||
bitcoin_watch(ctx, tx, BITCOIN_STEAL_DONE));
|
|
||||||
/* Expect either close or steal to complete */
|
/* Expect either close or steal to complete */
|
||||||
return next_state(peer, cstatus,
|
return next_state(peer, cstatus,
|
||||||
STATE_CLOSE_WAIT_STEAL_CLOSE);
|
STATE_CLOSE_WAIT_STEAL_CLOSE);
|
||||||
|
@ -1199,7 +1137,6 @@ old_commit_spotted:
|
||||||
return next_state(peer, cstatus,
|
return next_state(peer, cstatus,
|
||||||
STATE_ERR_INFORMATION_LEAK);
|
STATE_ERR_INFORMATION_LEAK);
|
||||||
queue_tx_broadcast(broadcast, tx);
|
queue_tx_broadcast(broadcast, tx);
|
||||||
add_effect(effect, watch,
|
peer_watch_tx(peer, tx, BITCOIN_STEAL_DONE);
|
||||||
bitcoin_watch(ctx, tx, BITCOIN_STEAL_DONE));
|
|
||||||
return next_state(peer, cstatus, STATE_CLOSE_WAIT_STEAL);
|
return next_state(peer, cstatus, STATE_CLOSE_WAIT_STEAL);
|
||||||
}
|
}
|
||||||
|
|
190
state.h
190
state.h
|
@ -6,51 +6,13 @@
|
||||||
#include <state_types.h>
|
#include <state_types.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
enum state_effect_type {
|
|
||||||
STATE_EFFECT_watch,
|
|
||||||
STATE_EFFECT_unwatch,
|
|
||||||
/* FIXME: Use a watch for this?. */
|
|
||||||
STATE_EFFECT_close_timeout,
|
|
||||||
/* FIXME: Combine into watches? */
|
|
||||||
STATE_EFFECT_watch_htlcs,
|
|
||||||
STATE_EFFECT_unwatch_htlc,
|
|
||||||
STATE_EFFECT_watch_htlc_spend,
|
|
||||||
STATE_EFFECT_unwatch_htlc_spend
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the core state machine.
|
* This is the core state machine.
|
||||||
*
|
*
|
||||||
* Calling the state machine with an input simply returns the new state,
|
* Calling the state machine updates updates peer->state, and may call
|
||||||
* and populates the "effect" struct with what it wants done.
|
* various peer_ callbacks. It also returns the status of the current
|
||||||
|
* command.
|
||||||
*/
|
*/
|
||||||
struct state_effect {
|
|
||||||
struct state_effect *next;
|
|
||||||
|
|
||||||
enum state_effect_type etype;
|
|
||||||
union {
|
|
||||||
/* Event to watch for. */
|
|
||||||
struct watch *watch;
|
|
||||||
|
|
||||||
/* Events to no longer watch for. */
|
|
||||||
struct watch *unwatch;
|
|
||||||
|
|
||||||
/* Set a timeout for close tx. */
|
|
||||||
enum state_input close_timeout;
|
|
||||||
|
|
||||||
/* HTLC outputs to watch. */
|
|
||||||
const struct htlc_watch *watch_htlcs;
|
|
||||||
|
|
||||||
/* HTLC output to unwatch. */
|
|
||||||
const struct htlc_unwatch *unwatch_htlc;
|
|
||||||
|
|
||||||
/* HTLC spends to watch/unwatch. */
|
|
||||||
const struct htlc_spend_watch *watch_htlc_spend;
|
|
||||||
const struct htlc_spend_watch *unwatch_htlc_spend;
|
|
||||||
|
|
||||||
/* FIXME: More to come (for accept_*) */
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline bool state_is_error(enum state s)
|
static inline bool state_is_error(enum state s)
|
||||||
{
|
{
|
||||||
|
@ -59,6 +21,7 @@ static inline bool state_is_error(enum state s)
|
||||||
|
|
||||||
struct peer;
|
struct peer;
|
||||||
struct bitcoin_tx;
|
struct bitcoin_tx;
|
||||||
|
struct state_effect;
|
||||||
|
|
||||||
static inline bool input_is_pkt(enum state_input input)
|
static inline bool input_is_pkt(enum state_input input)
|
||||||
{
|
{
|
||||||
|
@ -226,8 +189,7 @@ Pkt *accept_pkt_close_ack(const tal_t *ctx,
|
||||||
bool committed_to_htlcs(const struct peer *peer);
|
bool committed_to_htlcs(const struct peer *peer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bitcoin_watch_anchor: create a watch for the anchor.
|
* peer_watch_anchor: create a watch for the anchor transaction.
|
||||||
* @ctx: context to tal the watch struct off.
|
|
||||||
* @peer: the state data for this peer.
|
* @peer: the state data for this peer.
|
||||||
* @depthok: the input to give when anchor reaches expected depth.
|
* @depthok: the input to give when anchor reaches expected depth.
|
||||||
* @timeout: the input to give if anchor doesn't reach depth in time.
|
* @timeout: the input to give if anchor doesn't reach depth in time.
|
||||||
|
@ -238,136 +200,138 @@ bool committed_to_htlcs(const struct peer *peer);
|
||||||
* @depthok can be INPUT_NONE if it's our anchor (we don't time
|
* @depthok can be INPUT_NONE if it's our anchor (we don't time
|
||||||
* ourselves out).
|
* ourselves out).
|
||||||
*/
|
*/
|
||||||
struct watch *bitcoin_watch_anchor(const tal_t *ctx,
|
void peer_watch_anchor(struct peer *peer,
|
||||||
const struct peer *peer,
|
enum state_input depthok,
|
||||||
enum state_input depthok,
|
enum state_input timeout,
|
||||||
enum state_input timeout,
|
enum state_input unspent,
|
||||||
enum state_input unspent,
|
enum state_input theyspent,
|
||||||
enum state_input theyspent,
|
enum state_input otherspent);
|
||||||
enum state_input otherspent);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bitcoin_unwatch_anchor_depth: remove depth watch for the anchor.
|
* peer_unwatch_anchor_depth: remove depth watch for the anchor.
|
||||||
* @ctx: context to tal the watch struct off.
|
|
||||||
* @peer: the state data for this peer.
|
* @peer: the state data for this peer.
|
||||||
* @depthok: the input to give when anchor reaches expected depth.
|
* @depthok: the input to give when anchor reaches expected depth.
|
||||||
* @timeout: the input to give if anchor doesn't reach depth in time.
|
* @timeout: the input to give if anchor doesn't reach depth in time.
|
||||||
*
|
*
|
||||||
* @depthok and @timeout must match bitcoin_watch_anchor() call.
|
* @depthok and @timeout must match bitcoin_watch_anchor() call.
|
||||||
*/
|
*/
|
||||||
struct watch *bitcoin_unwatch_anchor_depth(const tal_t *ctx,
|
void peer_unwatch_anchor_depth(struct peer *peer,
|
||||||
const struct peer *peer,
|
enum state_input depthok,
|
||||||
enum state_input depthok,
|
enum state_input timeout);
|
||||||
enum state_input timeout);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bitcoin_watch_delayed: watch this (commit) tx, tell me when I can spend it
|
* peer_watch_delayed: watch this (commit) tx, tell me when I can spend it
|
||||||
* @ctx: the context to tal the watch off
|
* @peer: the state data for this peer.
|
||||||
* @tx: the tx we're watching.
|
* @tx: the tx we're watching.
|
||||||
* @canspend: the input to give when commit reaches spendable depth.
|
* @canspend: the input to give when commit reaches spendable depth.
|
||||||
*
|
*
|
||||||
* Note that this tx may be malleated, as it's dual-signed.
|
* Note that this tx may be malleated, as it's dual-signed.
|
||||||
*/
|
*/
|
||||||
struct watch *bitcoin_watch_delayed(const tal_t *ctx,
|
void peer_watch_delayed(struct peer *peer,
|
||||||
const struct bitcoin_tx *tx,
|
const struct bitcoin_tx *tx,
|
||||||
enum state_input canspend);
|
enum state_input canspend);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bitcoin_watch: watch this tx until it's "irreversible"
|
* peer_watch_tx: watch this tx until it's "irreversible"
|
||||||
* @ctx: the context to tal the watch off
|
* @peer: the state data for this peer.
|
||||||
* @tx: the tx we're watching.
|
* @tx: the tx we're watching.
|
||||||
* @done: the input to give when tx is completely buried.
|
* @done: the input to give when tx is completely buried.
|
||||||
*
|
*
|
||||||
* The tx should be immalleable by BIP62; once this fires we consider
|
* Once this fires we consider the channel completely closed and stop
|
||||||
* the channel completely closed and stop watching (eg 100 txs down).
|
* watching (eg 100 txs down).
|
||||||
|
*
|
||||||
|
* This is used for watching a transaction we sent (such as a steal,
|
||||||
|
* or spend of their close, etc).
|
||||||
*/
|
*/
|
||||||
struct watch *bitcoin_watch(const tal_t *ctx,
|
void peer_watch_tx(struct peer *peer,
|
||||||
const struct bitcoin_tx *tx,
|
const struct bitcoin_tx *tx,
|
||||||
enum state_input done);
|
enum state_input done);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bitcoin_watch_close: watch close tx until it's "irreversible"
|
* peer_watch_close: watch for close tx until it's "irreversible" (or timedout)
|
||||||
* @ctx: context to tal the watch struct off.
|
|
||||||
* @peer: the state data for this peer.
|
* @peer: the state data for this peer.
|
||||||
* @done: the input to give when tx is completely buried.
|
* @done: the input to give when tx is completely buried.
|
||||||
|
* @timedout: the input to give if we time out.
|
||||||
*
|
*
|
||||||
* This tx *is* malleable, since the other side can transmit theirs.
|
* Once this fires we consider the channel completely closed and stop
|
||||||
|
* watching (eg 100 txs down).
|
||||||
|
*
|
||||||
|
* This is used for watching a mutual close, or for a transaction we sent
|
||||||
|
* (such as a steal, or spend of their close, etc).
|
||||||
*/
|
*/
|
||||||
struct watch *bitcoin_watch_close(const tal_t *ctx,
|
void peer_watch_close(struct peer *peer,
|
||||||
const struct peer *peer,
|
enum state_input done, enum state_input timedout);
|
||||||
enum state_input done);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* htlc_outputs_our_commit: HTLC outputs from our commit tx to watch.
|
* peer_watch_our_htlc_outputs: HTLC outputs from our commit tx to watch.
|
||||||
* @ctx: context to tal the watch struct off.
|
|
||||||
* @peer: the state data for this peer.
|
* @peer: the state data for this peer.
|
||||||
* @tx: the commitment tx
|
* @tx: the commitment tx
|
||||||
* @tous_timeout: input to give when a HTLC output to us times out.
|
* @tous_timeout: input to give when a HTLC output to us times out.
|
||||||
* @tothem_spent: input to give when a HTLC output to them is spent.
|
* @tothem_spent: input to give when a HTLC output to them is spent.
|
||||||
* @tothem_timeout: input to give when a HTLC output to them times out.
|
* @tothem_timeout: input to give when a HTLC output to them times out.
|
||||||
|
*
|
||||||
|
* Returns true if there were any htlc outputs to watch.
|
||||||
*/
|
*/
|
||||||
struct htlc_watch *htlc_outputs_our_commit(const tal_t *ctx,
|
bool peer_watch_our_htlc_outputs(struct peer *peer,
|
||||||
const struct peer *peer,
|
const struct bitcoin_tx *tx,
|
||||||
const struct bitcoin_tx *tx,
|
enum state_input tous_timeout,
|
||||||
enum state_input tous_timeout,
|
enum state_input tothem_spent,
|
||||||
enum state_input tothem_spent,
|
enum state_input tothem_timeout);
|
||||||
enum state_input tothem_timeout);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* htlc_outputs_their_commit: HTLC outputs from their commit tx to watch.
|
* peer_watch_their_htlc_outputs: HTLC outputs from their commit tx to watch.
|
||||||
* @ctx: context to tal the watch struct off.
|
|
||||||
* @peer: the state data for this peer.
|
* @peer: the state data for this peer.
|
||||||
* @tx: the commitment tx
|
* @tx: the commitment tx
|
||||||
* @tous_timeout: input to give when a HTLC output to us times out.
|
* @tous_timeout: input to give when a HTLC output to us times out.
|
||||||
* @tothem_spent: input to give when a HTLC output to them is spent.
|
* @tothem_spent: input to give when a HTLC output to them is spent.
|
||||||
* @tothem_timeout: input to give when a HTLC output to them times out.
|
* @tothem_timeout: input to give when a HTLC output to them times out.
|
||||||
|
*
|
||||||
|
* Returns true if there were any htlc outputs to watch.
|
||||||
*/
|
*/
|
||||||
struct htlc_watch *htlc_outputs_their_commit(const tal_t *ctx,
|
bool peer_watch_their_htlc_outputs(struct peer *peer,
|
||||||
const struct peer *peer,
|
const struct bitcoin_event *tx,
|
||||||
const struct bitcoin_event *tx,
|
enum state_input tous_timeout,
|
||||||
enum state_input tous_timeout,
|
enum state_input tothem_spent,
|
||||||
enum state_input tothem_spent,
|
enum state_input tothem_timeout);
|
||||||
enum state_input tothem_timeout);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* htlc_unwatch: stop watching an HTLC
|
* peer_unwatch_htlc_output: stop watching an HTLC
|
||||||
* @ctx: context to tal the watch struct off.
|
* @peer: the state data for this peer.
|
||||||
* @htlc: the htlc to stop watching
|
* @htlc: the htlc to stop watching
|
||||||
* @all_done: input to give if we're not watching any anymore.
|
* @all_done: input to give if we're not watching any outputs anymore.
|
||||||
*/
|
*/
|
||||||
struct htlc_unwatch *htlc_unwatch(const tal_t *ctx,
|
void peer_unwatch_htlc_output(struct peer *peer,
|
||||||
const struct htlc *htlc,
|
const struct htlc *htlc,
|
||||||
enum state_input all_done);
|
enum state_input all_done);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* htlc_unwatch_all: stop watching all HTLCs
|
* peer_unwatch_all_htlc_outputs: stop watching all HTLCs
|
||||||
* @ctx: context to tal the watch struct off.
|
|
||||||
* @peer: the state data for this peer.
|
* @peer: the state data for this peer.
|
||||||
*/
|
*/
|
||||||
struct htlc_unwatch *htlc_unwatch_all(const tal_t *ctx,
|
void peer_unwatch_all_htlc_outputs(struct peer *peer);
|
||||||
const struct peer *peer);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* htlc_spend_watch: watch our spend of an HTLC
|
* peer_watch_htlc_spend: watch our spend of an HTLC output
|
||||||
* @ctx: context to tal the watch struct off.
|
* @peer: the state data for this peer.
|
||||||
* @tx: the commitment tx
|
* @tx: the commitment tx
|
||||||
* @cmd: the command data.
|
* @htlc: the htlc the tx is spending an output of
|
||||||
* @done: input to give when it's completely buried.
|
* @done: input to give when it's completely buried.
|
||||||
*/
|
*/
|
||||||
struct htlc_spend_watch *htlc_spend_watch(const tal_t *ctx,
|
void peer_watch_htlc_spend(struct peer *peer,
|
||||||
const struct bitcoin_tx *tx,
|
const struct bitcoin_tx *tx,
|
||||||
const struct command *cmd,
|
const struct htlc *htlc,
|
||||||
enum state_input done);
|
enum state_input done);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* htlc_spend_unwatch: stop watching an HTLC spend
|
* peer_unwatch_htlc_spend: stop watching our HTLC spend
|
||||||
* @ctx: context to tal the watch struct off.
|
* @peer: the state data for this peer.
|
||||||
* @htlc: the htlc to stop watching
|
* @htlc: the htlc to stop watching the spend for.
|
||||||
* @all_done: input to give if we're not watching anything anymore.
|
* @all_done: input to give if we're not watching anything anymore.
|
||||||
*/
|
*/
|
||||||
struct htlc_spend_watch *htlc_spend_unwatch(const tal_t *ctx,
|
void peer_unwatch_htlc_spend(struct peer *peer,
|
||||||
const struct htlc *htlc,
|
const struct htlc *htlc,
|
||||||
enum state_input all_done);
|
enum state_input all_done);
|
||||||
|
|
||||||
/* Create a bitcoin anchor tx. */
|
/* Create a bitcoin anchor tx. */
|
||||||
struct bitcoin_tx *bitcoin_anchor(const tal_t *ctx,
|
struct bitcoin_tx *bitcoin_anchor(const tal_t *ctx,
|
||||||
const struct peer *peer);
|
const struct peer *peer);
|
||||||
|
|
|
@ -871,134 +871,6 @@ struct bitcoin_tx *bitcoin_anchor(const tal_t *ctx,
|
||||||
return bitcoin_tx("anchor");
|
return bitcoin_tx("anchor");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool have_event(uint64_t events, enum state_input input)
|
|
||||||
{
|
|
||||||
return events & (1ULL << input);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool add_event_(uint64_t *events, enum state_input input)
|
|
||||||
{
|
|
||||||
/* This is how they say "no event please" */
|
|
||||||
if (input == INPUT_NONE)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
assert(input < 64);
|
|
||||||
if (have_event(*events, input))
|
|
||||||
return false;
|
|
||||||
*events |= (1ULL << input);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool remove_event_(uint64_t *events, enum state_input input)
|
|
||||||
{
|
|
||||||
/* This is how they say "no event please" */
|
|
||||||
if (input == INPUT_NONE)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
assert(input < 64);
|
|
||||||
if (!have_event(*events, input))
|
|
||||||
return false;
|
|
||||||
*events &= ~(1ULL << input);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void remove_event(uint64_t *events, enum state_input input)
|
|
||||||
{
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#error "Don't run tests with NDEBUG"
|
|
||||||
#endif
|
|
||||||
assert(remove_event_(events, input));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_event(uint64_t *events, enum state_input input)
|
|
||||||
{
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#error "Don't run tests with NDEBUG"
|
|
||||||
#endif
|
|
||||||
assert(add_event_(events, input));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct watch {
|
|
||||||
uint64_t events;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct watch *bitcoin_watch_anchor(const tal_t *ctx,
|
|
||||||
const struct peer *peer,
|
|
||||||
enum state_input depthok,
|
|
||||||
enum state_input timeout,
|
|
||||||
enum state_input unspent,
|
|
||||||
enum state_input theyspent,
|
|
||||||
enum state_input otherspent)
|
|
||||||
{
|
|
||||||
struct watch *watch = talz(ctx, struct watch);
|
|
||||||
|
|
||||||
add_event(&watch->events, depthok);
|
|
||||||
add_event(&watch->events, timeout);
|
|
||||||
add_event(&watch->events, unspent);
|
|
||||||
add_event(&watch->events, theyspent);
|
|
||||||
add_event(&watch->events, otherspent);
|
|
||||||
|
|
||||||
/* We assume these values in activate_event. */
|
|
||||||
assert(timeout == BITCOIN_ANCHOR_TIMEOUT
|
|
||||||
|| timeout == INPUT_NONE);
|
|
||||||
assert(depthok == BITCOIN_ANCHOR_DEPTHOK);
|
|
||||||
return watch;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct watch *bitcoin_unwatch_anchor_depth(const tal_t *ctx,
|
|
||||||
const struct peer *peer,
|
|
||||||
enum state_input depthok,
|
|
||||||
enum state_input timeout)
|
|
||||||
{
|
|
||||||
struct watch *watch = talz(ctx, struct watch);
|
|
||||||
|
|
||||||
add_event(&watch->events, depthok);
|
|
||||||
add_event(&watch->events, timeout);
|
|
||||||
return watch;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for our commit to be spendable. */
|
|
||||||
struct watch *bitcoin_watch_delayed(const tal_t *ctx,
|
|
||||||
const struct bitcoin_tx *tx,
|
|
||||||
enum state_input canspend)
|
|
||||||
{
|
|
||||||
struct watch *watch = talz(ctx, struct watch);
|
|
||||||
|
|
||||||
assert(bitcoin_tx_is(tx, "our commit"));
|
|
||||||
add_event(&watch->events, canspend);
|
|
||||||
return watch;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for commit to be very deeply buried (so we no longer need to
|
|
||||||
* even watch) */
|
|
||||||
struct watch *bitcoin_watch(const tal_t *ctx,
|
|
||||||
const struct bitcoin_tx *tx,
|
|
||||||
enum state_input done)
|
|
||||||
{
|
|
||||||
struct watch *watch = talz(ctx, struct watch);
|
|
||||||
|
|
||||||
if (done == BITCOIN_STEAL_DONE)
|
|
||||||
assert(bitcoin_tx_is(tx, "steal"));
|
|
||||||
else if (done == BITCOIN_SPEND_THEIRS_DONE)
|
|
||||||
assert(bitcoin_tx_is(tx, "spend their commit"));
|
|
||||||
else if (done == BITCOIN_SPEND_OURS_DONE)
|
|
||||||
assert(bitcoin_tx_is(tx, "spend our commit"));
|
|
||||||
else
|
|
||||||
errx(1, "Unknown watch effect %s", input_name(done));
|
|
||||||
add_event(&watch->events, done);
|
|
||||||
return watch;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Other side should drop close tx; watch for it. */
|
|
||||||
struct watch *bitcoin_watch_close(const tal_t *ctx,
|
|
||||||
const struct peer *peer,
|
|
||||||
enum state_input done)
|
|
||||||
{
|
|
||||||
struct watch *watch = talz(ctx, struct watch);
|
|
||||||
add_event(&watch->events, done);
|
|
||||||
return watch;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct bitcoin_tx *bitcoin_close(const tal_t *ctx,
|
struct bitcoin_tx *bitcoin_close(const tal_t *ctx,
|
||||||
const struct peer *peer)
|
const struct peer *peer)
|
||||||
{
|
{
|
||||||
|
@ -1054,143 +926,6 @@ bool committed_to_htlcs(const struct peer *peer)
|
||||||
return peer->num_htlcs_to_them != 0 || peer->num_htlcs_to_us != 0;
|
return peer->num_htlcs_to_them != 0 || peer->num_htlcs_to_us != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct htlc_watch
|
|
||||||
{
|
|
||||||
enum state_input tous_timeout;
|
|
||||||
enum state_input tothem_spent;
|
|
||||||
enum state_input tothem_timeout;
|
|
||||||
unsigned int num_htlcs_to_us, num_htlcs_to_them;
|
|
||||||
struct htlc htlcs_to_us[MAX_HTLCS], htlcs_to_them[MAX_HTLCS];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct htlc_unwatch
|
|
||||||
{
|
|
||||||
unsigned int id;
|
|
||||||
enum state_input all_done;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct htlc_watch *htlc_outputs_our_commit(const tal_t *ctx,
|
|
||||||
const struct peer *peer,
|
|
||||||
const struct bitcoin_tx *tx,
|
|
||||||
enum state_input tous_timeout,
|
|
||||||
enum state_input tothem_spent,
|
|
||||||
enum state_input tothem_timeout)
|
|
||||||
{
|
|
||||||
struct htlc_watch *w = tal(ctx, struct htlc_watch);
|
|
||||||
|
|
||||||
/* We assume these. */
|
|
||||||
assert(tous_timeout == BITCOIN_HTLC_TOUS_TIMEOUT);
|
|
||||||
assert(tothem_spent == BITCOIN_HTLC_TOTHEM_SPENT);
|
|
||||||
assert(tothem_timeout == BITCOIN_HTLC_TOTHEM_TIMEOUT);
|
|
||||||
|
|
||||||
w->tous_timeout = tous_timeout;
|
|
||||||
w->tothem_spent = tothem_spent;
|
|
||||||
w->tothem_timeout = tothem_timeout;
|
|
||||||
|
|
||||||
w->num_htlcs_to_us = peer->num_htlcs_to_us;
|
|
||||||
w->num_htlcs_to_them = peer->num_htlcs_to_them;
|
|
||||||
BUILD_ASSERT(sizeof(peer->htlcs_to_us) == sizeof(w->htlcs_to_us));
|
|
||||||
BUILD_ASSERT(sizeof(peer->htlcs_to_them) == sizeof(w->htlcs_to_them));
|
|
||||||
memcpy(w->htlcs_to_us, peer->htlcs_to_us, sizeof(peer->htlcs_to_us));
|
|
||||||
memcpy(w->htlcs_to_them, peer->htlcs_to_them,
|
|
||||||
sizeof(peer->htlcs_to_them));
|
|
||||||
|
|
||||||
if (!w->num_htlcs_to_us && !w->num_htlcs_to_them)
|
|
||||||
return tal_free(w);
|
|
||||||
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct htlc_watch *htlc_outputs_their_commit(const tal_t *ctx,
|
|
||||||
const struct peer *peer,
|
|
||||||
const struct bitcoin_event *tx,
|
|
||||||
enum state_input tous_timeout,
|
|
||||||
enum state_input tothem_spent,
|
|
||||||
enum state_input tothem_timeout)
|
|
||||||
{
|
|
||||||
struct htlc_watch *w = tal(ctx, struct htlc_watch);
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
/* We assume these. */
|
|
||||||
assert(tous_timeout == BITCOIN_HTLC_TOUS_TIMEOUT);
|
|
||||||
assert(tothem_spent == BITCOIN_HTLC_TOTHEM_SPENT);
|
|
||||||
assert(tothem_timeout == BITCOIN_HTLC_TOTHEM_TIMEOUT);
|
|
||||||
|
|
||||||
w->tous_timeout = tous_timeout;
|
|
||||||
w->tothem_spent = tothem_spent;
|
|
||||||
w->tothem_timeout = tothem_timeout;
|
|
||||||
|
|
||||||
/* It's what our peer thinks is current... */
|
|
||||||
w->num_htlcs_to_us = peer->other->num_htlcs_to_them;
|
|
||||||
w->num_htlcs_to_them = peer->other->num_htlcs_to_us;
|
|
||||||
BUILD_ASSERT(sizeof(peer->other->htlcs_to_them) == sizeof(w->htlcs_to_us));
|
|
||||||
BUILD_ASSERT(sizeof(peer->other->htlcs_to_us) == sizeof(w->htlcs_to_them));
|
|
||||||
memcpy(w->htlcs_to_us, peer->other->htlcs_to_them, sizeof(w->htlcs_to_us));
|
|
||||||
memcpy(w->htlcs_to_them, peer->other->htlcs_to_us,
|
|
||||||
sizeof(w->htlcs_to_them));
|
|
||||||
|
|
||||||
if (!w->num_htlcs_to_us && !w->num_htlcs_to_them)
|
|
||||||
return tal_free(w);
|
|
||||||
|
|
||||||
/* Reverse perspective, mark rvalue unknown */
|
|
||||||
for (i = 0; i < w->num_htlcs_to_us; i++) {
|
|
||||||
assert(w->htlcs_to_us[i].to_them);
|
|
||||||
w->htlcs_to_us[i].to_them = false;
|
|
||||||
}
|
|
||||||
for (i = 0; i < w->num_htlcs_to_them; i++) {
|
|
||||||
assert(!w->htlcs_to_them[i].to_them);
|
|
||||||
w->htlcs_to_them[i].to_them = true;
|
|
||||||
}
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct htlc_unwatch *htlc_unwatch(const tal_t *ctx,
|
|
||||||
const struct htlc *htlc,
|
|
||||||
enum state_input all_done)
|
|
||||||
{
|
|
||||||
struct htlc_unwatch *w = tal(ctx, struct htlc_unwatch);
|
|
||||||
|
|
||||||
w->id = htlc->id;
|
|
||||||
assert(w->id != -1U);
|
|
||||||
w->all_done = all_done;
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct htlc_unwatch *htlc_unwatch_all(const tal_t *ctx,
|
|
||||||
const struct peer *peer)
|
|
||||||
{
|
|
||||||
struct htlc_unwatch *w = tal(ctx, struct htlc_unwatch);
|
|
||||||
|
|
||||||
w->id = -1U;
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct htlc_spend_watch *htlc_spend_watch(const tal_t *ctx,
|
|
||||||
const struct bitcoin_tx *tx,
|
|
||||||
const struct command *cmd,
|
|
||||||
enum state_input done)
|
|
||||||
{
|
|
||||||
struct htlc_spend_watch *w = tal(ctx, struct htlc_spend_watch);
|
|
||||||
w->id = htlc_id_from_tx(tx);
|
|
||||||
w->done = done;
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct htlc_spend_watch *htlc_spend_unwatch(const tal_t *ctx,
|
|
||||||
const struct htlc *htlc,
|
|
||||||
enum state_input all_done)
|
|
||||||
{
|
|
||||||
struct htlc_spend_watch *w = tal(ctx, struct htlc_spend_watch);
|
|
||||||
|
|
||||||
w->id = htlc->id;
|
|
||||||
w->done = all_done;
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct htlc_rval {
|
|
||||||
unsigned int id;
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "state.c"
|
#include "state.c"
|
||||||
#include <ccan/tal/tal.h>
|
#include <ccan/tal/tal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -1401,6 +1136,282 @@ static bool outstanding_htlc_watches(const struct peer *peer)
|
||||||
|| peer->num_htlc_spends_to_them;
|
|| peer->num_htlc_spends_to_them;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool have_event(uint64_t events, enum state_input input)
|
||||||
|
{
|
||||||
|
return events & (1ULL << input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool add_event_(struct peer *peer, enum state_input input)
|
||||||
|
{
|
||||||
|
/* This is how they say "no event please" */
|
||||||
|
if (input == INPUT_NONE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
assert(input < 64);
|
||||||
|
if (have_event(peer->core.event_notifies, input))
|
||||||
|
return false;
|
||||||
|
peer->core.event_notifies |= (1ULL << input);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool remove_event_(uint64_t *events, enum state_input input)
|
||||||
|
{
|
||||||
|
/* This is how they say "no event please" */
|
||||||
|
if (input == INPUT_NONE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
assert(input < 64);
|
||||||
|
if (!have_event(*events, input))
|
||||||
|
return false;
|
||||||
|
*events &= ~(1ULL << input);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_event(struct peer *peer, enum state_input input)
|
||||||
|
{
|
||||||
|
if (!remove_event_(&peer->core.event_notifies, input))
|
||||||
|
report_trail(peer->trail, "Removing event we don't have?");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_event(struct peer *peer, enum state_input input)
|
||||||
|
{
|
||||||
|
if (!add_event_(peer, input))
|
||||||
|
report_trail(peer->trail, "Adding event we already have?");
|
||||||
|
}
|
||||||
|
|
||||||
|
void peer_watch_anchor(struct peer *peer,
|
||||||
|
enum state_input depthok,
|
||||||
|
enum state_input timeout,
|
||||||
|
enum state_input unspent,
|
||||||
|
enum state_input theyspent,
|
||||||
|
enum state_input otherspent)
|
||||||
|
{
|
||||||
|
/* We assume these values in activate_event. */
|
||||||
|
assert(timeout == BITCOIN_ANCHOR_TIMEOUT
|
||||||
|
|| timeout == INPUT_NONE);
|
||||||
|
assert(depthok == BITCOIN_ANCHOR_DEPTHOK);
|
||||||
|
|
||||||
|
add_event(peer, depthok);
|
||||||
|
add_event(peer, timeout);
|
||||||
|
add_event(peer, unspent);
|
||||||
|
add_event(peer, theyspent);
|
||||||
|
add_event(peer, otherspent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void peer_unwatch_anchor_depth(struct peer *peer,
|
||||||
|
enum state_input depthok,
|
||||||
|
enum state_input timeout)
|
||||||
|
{
|
||||||
|
/* We assume these values in activate_event. */
|
||||||
|
assert(timeout == BITCOIN_ANCHOR_TIMEOUT
|
||||||
|
|| timeout == INPUT_NONE);
|
||||||
|
assert(depthok == BITCOIN_ANCHOR_DEPTHOK);
|
||||||
|
|
||||||
|
remove_event(peer, depthok);
|
||||||
|
remove_event(peer, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for our commit to be spendable. */
|
||||||
|
void peer_watch_delayed(struct peer *peer,
|
||||||
|
const struct bitcoin_tx *tx, enum state_input canspend)
|
||||||
|
{
|
||||||
|
assert(bitcoin_tx_is(tx, "our commit"));
|
||||||
|
add_event(peer, canspend);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for commit to be very deeply buried (so we no longer need to
|
||||||
|
* even watch) */
|
||||||
|
void peer_watch_tx(struct peer *peer,
|
||||||
|
const struct bitcoin_tx *tx,
|
||||||
|
enum state_input done)
|
||||||
|
{
|
||||||
|
/* We can have multiple steals or spendtheirs in flight, so
|
||||||
|
* allow repeats for
|
||||||
|
* BITCOIN_STEAL_DONE/BITCOIN_SPEND_THEIRS_DONE */
|
||||||
|
if (done == BITCOIN_STEAL_DONE) {
|
||||||
|
assert(bitcoin_tx_is(tx, "steal"));
|
||||||
|
add_event_(peer, done);
|
||||||
|
} else if (done == BITCOIN_SPEND_THEIRS_DONE) {
|
||||||
|
assert(bitcoin_tx_is(tx, "spend their commit"));
|
||||||
|
add_event_(peer, done);
|
||||||
|
} else if (done == BITCOIN_SPEND_OURS_DONE) {
|
||||||
|
assert(bitcoin_tx_is(tx, "spend our commit"));
|
||||||
|
add_event(peer, done);
|
||||||
|
} else
|
||||||
|
report_trail(peer->trail, "Unknown watch effect");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Other side should drop close tx; watch for it. */
|
||||||
|
void peer_watch_close(struct peer *peer,
|
||||||
|
enum state_input done, enum state_input timedout)
|
||||||
|
{
|
||||||
|
add_event(peer, done);
|
||||||
|
|
||||||
|
/* We assume this. */
|
||||||
|
assert(timedout == INPUT_CLOSE_COMPLETE_TIMEOUT || timedout == INPUT_NONE);
|
||||||
|
add_event(peer, timedout);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool peer_watch_our_htlc_outputs(struct peer *peer,
|
||||||
|
const struct bitcoin_tx *tx,
|
||||||
|
enum state_input tous_timeout,
|
||||||
|
enum state_input tothem_spent,
|
||||||
|
enum state_input tothem_timeout)
|
||||||
|
{
|
||||||
|
/* FIXME: We assume these. */
|
||||||
|
assert(tous_timeout == BITCOIN_HTLC_TOUS_TIMEOUT);
|
||||||
|
assert(tothem_spent == BITCOIN_HTLC_TOTHEM_SPENT);
|
||||||
|
assert(tothem_timeout == BITCOIN_HTLC_TOTHEM_TIMEOUT);
|
||||||
|
|
||||||
|
if (!peer->num_htlcs_to_us && !peer->num_htlcs_to_them)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
assert(peer->num_live_htlcs_to_us + peer->num_htlcs_to_us
|
||||||
|
<= ARRAY_SIZE(peer->live_htlcs_to_us));
|
||||||
|
assert(peer->num_live_htlcs_to_them + peer->num_htlcs_to_them
|
||||||
|
<= ARRAY_SIZE(peer->live_htlcs_to_them));
|
||||||
|
memcpy(peer->live_htlcs_to_us + peer->num_live_htlcs_to_us,
|
||||||
|
peer->htlcs_to_us,
|
||||||
|
peer->num_htlcs_to_us * sizeof(peer->htlcs_to_us[0]));
|
||||||
|
memcpy(peer->live_htlcs_to_them + peer->num_live_htlcs_to_them,
|
||||||
|
peer->htlcs_to_them,
|
||||||
|
peer->num_htlcs_to_them * sizeof(peer->htlcs_to_them[0]));
|
||||||
|
peer->num_live_htlcs_to_us += peer->num_htlcs_to_us;
|
||||||
|
peer->num_live_htlcs_to_them += peer->num_htlcs_to_them;
|
||||||
|
/* Can happen if we were finished, then new commit tx */
|
||||||
|
remove_event_(&peer->core.event_notifies, INPUT_NO_MORE_HTLCS);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool peer_watch_their_htlc_outputs(struct peer *peer,
|
||||||
|
const struct bitcoin_event *tx,
|
||||||
|
enum state_input tous_timeout,
|
||||||
|
enum state_input tothem_spent,
|
||||||
|
enum state_input tothem_timeout)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
struct htlc *htlcs;
|
||||||
|
|
||||||
|
/* We assume these. */
|
||||||
|
assert(tous_timeout == BITCOIN_HTLC_TOUS_TIMEOUT);
|
||||||
|
assert(tothem_spent == BITCOIN_HTLC_TOTHEM_SPENT);
|
||||||
|
assert(tothem_timeout == BITCOIN_HTLC_TOTHEM_TIMEOUT);
|
||||||
|
|
||||||
|
/* It's what our peer thinks is current... */
|
||||||
|
if (!peer->other->num_htlcs_to_them && !peer->other->num_htlcs_to_us)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
assert(peer->num_live_htlcs_to_us + peer->other->num_htlcs_to_them
|
||||||
|
<= ARRAY_SIZE(peer->live_htlcs_to_us));
|
||||||
|
assert(peer->num_live_htlcs_to_them + peer->other->num_htlcs_to_us
|
||||||
|
<= ARRAY_SIZE(peer->live_htlcs_to_them));
|
||||||
|
|
||||||
|
/* Copy from other peer, but reverse perspective */
|
||||||
|
htlcs = peer->live_htlcs_to_us + peer->num_live_htlcs_to_us;
|
||||||
|
memcpy(htlcs, peer->other->htlcs_to_them,
|
||||||
|
peer->other->num_htlcs_to_them * sizeof(peer->htlcs_to_us[0]));
|
||||||
|
for (i = 0; i < peer->other->num_htlcs_to_them; i++) {
|
||||||
|
assert(htlcs[i].to_them);
|
||||||
|
htlcs[i].to_them = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
htlcs = peer->live_htlcs_to_them + peer->num_live_htlcs_to_them;
|
||||||
|
memcpy(htlcs,
|
||||||
|
peer->other->htlcs_to_us,
|
||||||
|
peer->other->num_htlcs_to_us * sizeof(peer->htlcs_to_them[0]));
|
||||||
|
for (i = 0; i < peer->other->num_htlcs_to_us; i++) {
|
||||||
|
assert(!htlcs[i].to_them);
|
||||||
|
htlcs[i].to_them = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
peer->num_live_htlcs_to_us += peer->other->num_htlcs_to_them;
|
||||||
|
peer->num_live_htlcs_to_them += peer->other->num_htlcs_to_us;
|
||||||
|
/* Can happen if we were finished, then new commit tx */
|
||||||
|
remove_event_(&peer->core.event_notifies, INPUT_NO_MORE_HTLCS);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void peer_unwatch_htlc_output(struct peer *peer,
|
||||||
|
const struct htlc *htlc,
|
||||||
|
enum state_input all_done)
|
||||||
|
{
|
||||||
|
const struct htlc *h;
|
||||||
|
|
||||||
|
/* We assume this. */
|
||||||
|
assert(all_done == INPUT_NO_MORE_HTLCS);
|
||||||
|
|
||||||
|
h = find_live_htlc(peer, htlc->id);
|
||||||
|
|
||||||
|
/* That can fail, when we see them spend (and thus stop
|
||||||
|
* watching) after we've timed out, then our return tx wins
|
||||||
|
* and gets buried. */
|
||||||
|
if (h) {
|
||||||
|
remove_htlc(peer->live_htlcs_to_us,
|
||||||
|
&peer->num_live_htlcs_to_us,
|
||||||
|
peer->live_htlcs_to_them,
|
||||||
|
&peer->num_live_htlcs_to_them,
|
||||||
|
ARRAY_SIZE(peer->live_htlcs_to_us),
|
||||||
|
h);
|
||||||
|
|
||||||
|
/* If that was last, fire INPUT_NO_MORE_HTLCS */
|
||||||
|
if (!outstanding_htlc_watches(peer))
|
||||||
|
add_event(peer, all_done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void peer_unwatch_all_htlc_outputs(struct peer *peer)
|
||||||
|
{
|
||||||
|
/* This can happen if we get in front of INPUT_NO_MORE_HTLCS */
|
||||||
|
if (!outstanding_htlc_watches(peer)
|
||||||
|
&& !have_event(peer->core.event_notifies, INPUT_NO_MORE_HTLCS))
|
||||||
|
report_trail(peer->trail, "unwatching all with no htlcs?");
|
||||||
|
|
||||||
|
peer->num_htlc_spends_to_us = 0;
|
||||||
|
peer->num_htlc_spends_to_them = 0;
|
||||||
|
peer->num_live_htlcs_to_us = 0;
|
||||||
|
peer->num_live_htlcs_to_them = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void peer_watch_htlc_spend(struct peer *peer,
|
||||||
|
const struct bitcoin_tx *tx,
|
||||||
|
const struct htlc *htlc,
|
||||||
|
enum state_input done)
|
||||||
|
{
|
||||||
|
struct htlc *h = find_live_htlc(peer, htlc_id_from_tx(tx));
|
||||||
|
|
||||||
|
add_htlc(peer->htlc_spends_to_us, &peer->num_htlc_spends_to_us,
|
||||||
|
peer->htlc_spends_to_them,
|
||||||
|
&peer->num_htlc_spends_to_them,
|
||||||
|
ARRAY_SIZE(peer->htlc_spends_to_us),
|
||||||
|
h);
|
||||||
|
|
||||||
|
/* We assume this */
|
||||||
|
if (h->to_them)
|
||||||
|
assert(done == BITCOIN_HTLC_RETURN_SPEND_DONE);
|
||||||
|
else
|
||||||
|
assert(done == BITCOIN_HTLC_FULFILL_SPEND_DONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void peer_unwatch_htlc_spend(struct peer *peer,
|
||||||
|
const struct htlc *htlc,
|
||||||
|
enum state_input all_done)
|
||||||
|
{
|
||||||
|
struct htlc *h = find_htlc_spend(peer, htlc->id);
|
||||||
|
|
||||||
|
assert(all_done == INPUT_NO_MORE_HTLCS);
|
||||||
|
remove_htlc(peer->htlc_spends_to_us,
|
||||||
|
&peer->num_htlc_spends_to_us,
|
||||||
|
peer->htlc_spends_to_them,
|
||||||
|
&peer->num_htlc_spends_to_them,
|
||||||
|
ARRAY_SIZE(peer->htlc_spends_to_us),
|
||||||
|
h);
|
||||||
|
|
||||||
|
if (!outstanding_htlc_watches(peer))
|
||||||
|
add_event(peer, all_done);
|
||||||
|
}
|
||||||
|
|
||||||
void peer_unexpected_pkt(struct peer *peer, const Pkt *pkt)
|
void peer_unexpected_pkt(struct peer *peer, const Pkt *pkt)
|
||||||
{
|
{
|
||||||
const char *str = (const char *)pkt;
|
const char *str = (const char *)pkt;
|
||||||
|
@ -1471,159 +1482,6 @@ void peer_tx_revealed_r_value(struct peer *peer,
|
||||||
add_rval(peer, htlc->id);
|
add_rval(peer, htlc->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We apply them backwards, which helps our assertions. It's not actually
|
|
||||||
* required. */
|
|
||||||
static const char *apply_effects(struct peer *peer,
|
|
||||||
const struct state_effect *effect,
|
|
||||||
uint64_t *effects)
|
|
||||||
{
|
|
||||||
const struct htlc *h;
|
|
||||||
|
|
||||||
if (!effect)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (effect->next) {
|
|
||||||
const char *problem = apply_effects(peer, effect->next,
|
|
||||||
effects);
|
|
||||||
if (problem)
|
|
||||||
return problem;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*effects & (1ULL << effect->etype))
|
|
||||||
return tal_fmt(NULL, "Effect %u twice", effect->etype);
|
|
||||||
*effects |= (1ULL << effect->etype);
|
|
||||||
|
|
||||||
switch (effect->etype) {
|
|
||||||
case STATE_EFFECT_watch:
|
|
||||||
/* We can have multiple steals or spendtheirs
|
|
||||||
in flight, so make exceptions for
|
|
||||||
BITCOIN_STEAL_DONE/BITCOIN_SPEND_THEIRS_DONE */
|
|
||||||
if (peer->core.event_notifies & (1ULL << BITCOIN_STEAL_DONE)
|
|
||||||
& effect->u.watch->events)
|
|
||||||
remove_event(&effect->u.watch->events, BITCOIN_STEAL_DONE);
|
|
||||||
|
|
||||||
if (peer->core.event_notifies
|
|
||||||
& (1ULL << BITCOIN_SPEND_THEIRS_DONE)
|
|
||||||
& effect->u.watch->events)
|
|
||||||
remove_event(&effect->u.watch->events,
|
|
||||||
BITCOIN_SPEND_THEIRS_DONE);
|
|
||||||
|
|
||||||
if (peer->core.event_notifies & effect->u.watch->events)
|
|
||||||
return "event set twice";
|
|
||||||
peer->core.event_notifies |= effect->u.watch->events;
|
|
||||||
break;
|
|
||||||
case STATE_EFFECT_unwatch:
|
|
||||||
if ((peer->core.event_notifies & effect->u.unwatch->events)
|
|
||||||
!= effect->u.unwatch->events)
|
|
||||||
return "unset event unwatched";
|
|
||||||
peer->core.event_notifies &= ~effect->u.unwatch->events;
|
|
||||||
break;
|
|
||||||
case STATE_EFFECT_close_timeout:
|
|
||||||
add_event(&peer->core.event_notifies,
|
|
||||||
effect->u.close_timeout);
|
|
||||||
/* We assume this. */
|
|
||||||
assert(effect->u.close_timeout
|
|
||||||
== INPUT_CLOSE_COMPLETE_TIMEOUT);
|
|
||||||
break;
|
|
||||||
case STATE_EFFECT_watch_htlcs:
|
|
||||||
assert(peer->num_live_htlcs_to_us
|
|
||||||
+ effect->u.watch_htlcs->num_htlcs_to_us
|
|
||||||
<= ARRAY_SIZE(peer->live_htlcs_to_us));
|
|
||||||
assert(peer->num_live_htlcs_to_them
|
|
||||||
+ effect->u.watch_htlcs->num_htlcs_to_them
|
|
||||||
<= ARRAY_SIZE(peer->live_htlcs_to_them));
|
|
||||||
memcpy(peer->live_htlcs_to_us + peer->num_live_htlcs_to_us,
|
|
||||||
effect->u.watch_htlcs->htlcs_to_us,
|
|
||||||
effect->u.watch_htlcs->num_htlcs_to_us
|
|
||||||
* sizeof(effect->u.watch_htlcs->htlcs_to_us[0]));
|
|
||||||
memcpy(peer->live_htlcs_to_them + peer->num_live_htlcs_to_them,
|
|
||||||
effect->u.watch_htlcs->htlcs_to_them,
|
|
||||||
effect->u.watch_htlcs->num_htlcs_to_them
|
|
||||||
* sizeof(effect->u.watch_htlcs->htlcs_to_them[0]));
|
|
||||||
peer->num_live_htlcs_to_us
|
|
||||||
+= effect->u.watch_htlcs->num_htlcs_to_us;
|
|
||||||
peer->num_live_htlcs_to_them
|
|
||||||
+= effect->u.watch_htlcs->num_htlcs_to_them;
|
|
||||||
/* Can happen if we were finished, then new commit tx */
|
|
||||||
remove_event_(&peer->core.event_notifies, INPUT_NO_MORE_HTLCS);
|
|
||||||
break;
|
|
||||||
case STATE_EFFECT_unwatch_htlc:
|
|
||||||
/* Unwatch all? */
|
|
||||||
if (effect->u.unwatch_htlc->id == -1) {
|
|
||||||
/* This can happen if we get in front of
|
|
||||||
* INPUT_NO_MORE_HTLCS */
|
|
||||||
if (!outstanding_htlc_watches(peer)
|
|
||||||
&& !have_event(peer->core.event_notifies,
|
|
||||||
INPUT_NO_MORE_HTLCS))
|
|
||||||
return "unwatching all with no htlcs?";
|
|
||||||
peer->num_htlc_spends_to_us = 0;
|
|
||||||
peer->num_htlc_spends_to_them = 0;
|
|
||||||
peer->num_live_htlcs_to_us = 0;
|
|
||||||
peer->num_live_htlcs_to_them = 0;
|
|
||||||
} else {
|
|
||||||
const struct htlc *h;
|
|
||||||
|
|
||||||
h = find_live_htlc(peer, effect->u.unwatch_htlc->id);
|
|
||||||
|
|
||||||
/* That can fail, when we see them spend (and
|
|
||||||
* thus stop watching) after we've timed out,
|
|
||||||
* then our return tx wins and gets buried. */
|
|
||||||
if (h) {
|
|
||||||
remove_htlc(peer->live_htlcs_to_us,
|
|
||||||
&peer->num_live_htlcs_to_us,
|
|
||||||
peer->live_htlcs_to_them,
|
|
||||||
&peer->num_live_htlcs_to_them,
|
|
||||||
ARRAY_SIZE(peer->live_htlcs_to_us),
|
|
||||||
h);
|
|
||||||
|
|
||||||
/* If that was last, fire INPUT_NO_MORE_HTLCS */
|
|
||||||
if (!outstanding_htlc_watches(peer)) {
|
|
||||||
assert(effect->u.unwatch_htlc->all_done
|
|
||||||
== INPUT_NO_MORE_HTLCS);
|
|
||||||
add_event(&peer->core.event_notifies,
|
|
||||||
effect->u.unwatch_htlc->all_done);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STATE_EFFECT_watch_htlc_spend:
|
|
||||||
h = find_live_htlc(peer, effect->u.watch_htlc_spend->id);
|
|
||||||
add_htlc(peer->htlc_spends_to_us, &peer->num_htlc_spends_to_us,
|
|
||||||
peer->htlc_spends_to_them,
|
|
||||||
&peer->num_htlc_spends_to_them,
|
|
||||||
ARRAY_SIZE(peer->htlc_spends_to_us),
|
|
||||||
h);
|
|
||||||
|
|
||||||
/* We assume this */
|
|
||||||
if (h->to_them)
|
|
||||||
assert(effect->u.watch_htlc_spend->done
|
|
||||||
== BITCOIN_HTLC_RETURN_SPEND_DONE);
|
|
||||||
else
|
|
||||||
assert(effect->u.watch_htlc_spend->done
|
|
||||||
== BITCOIN_HTLC_FULFILL_SPEND_DONE);
|
|
||||||
break;
|
|
||||||
case STATE_EFFECT_unwatch_htlc_spend:
|
|
||||||
h = find_htlc_spend(peer, effect->u.unwatch_htlc_spend->id);
|
|
||||||
remove_htlc(peer->htlc_spends_to_us,
|
|
||||||
&peer->num_htlc_spends_to_us,
|
|
||||||
peer->htlc_spends_to_them,
|
|
||||||
&peer->num_htlc_spends_to_them,
|
|
||||||
ARRAY_SIZE(peer->htlc_spends_to_us),
|
|
||||||
h);
|
|
||||||
if (!outstanding_htlc_watches(peer)) {
|
|
||||||
assert(effect->u.unwatch_htlc_spend->done
|
|
||||||
== INPUT_NO_MORE_HTLCS);
|
|
||||||
add_event(&peer->core.event_notifies,
|
|
||||||
effect->u.unwatch_htlc_spend->done);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return tal_fmt(NULL, "Unknown effect %u", effect->etype);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *check_changes(const struct peer *old, struct peer *new,
|
static const char *check_changes(const struct peer *old, struct peer *new,
|
||||||
enum state_input input)
|
enum state_input input)
|
||||||
{
|
{
|
||||||
|
@ -1661,16 +1519,12 @@ static const char *check_changes(const struct peer *old, struct peer *new,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *apply_all_effects(const struct peer *old,
|
static const char *check_all_effects(const struct peer *old,
|
||||||
enum command_status cstatus,
|
enum command_status cstatus,
|
||||||
enum state_input input,
|
enum state_input input,
|
||||||
struct peer *peer,
|
struct peer *peer,
|
||||||
const struct state_effect *effect,
|
|
||||||
Pkt *output)
|
Pkt *output)
|
||||||
{
|
{
|
||||||
const char *problem;
|
|
||||||
uint64_t effects = 0;
|
|
||||||
|
|
||||||
if (cstatus != CMD_NONE) {
|
if (cstatus != CMD_NONE) {
|
||||||
assert(peer->core.current_command != INPUT_NONE);
|
assert(peer->core.current_command != INPUT_NONE);
|
||||||
/* We should only requeue HTLCs if we're lowprio */
|
/* We should only requeue HTLCs if we're lowprio */
|
||||||
|
@ -1718,10 +1572,16 @@ static const char *apply_all_effects(const struct peer *old,
|
||||||
= htlc_id_from_pkt(output);
|
= htlc_id_from_pkt(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
problem = apply_effects(peer, effect, &effects);
|
if (peer->state >= STATE_CLOSE_WAIT_STEAL
|
||||||
if (!problem)
|
&& peer->state <= STATE_CLOSE_WAIT_STEAL_SPENDTHEM_CLOSE_SPENDOURS_WITH_HTLCS) {
|
||||||
problem = check_changes(old, peer, input);
|
if (STATE_TO_BITS(peer->state) & STATE_CLOSE_HTLCS_BIT) {
|
||||||
return problem;
|
if (!outstanding_htlc_watches(peer)
|
||||||
|
&& !have_event(peer->core.event_notifies, INPUT_NO_MORE_HTLCS))
|
||||||
|
return "CLOSE_HTLCS with no outstanding watches?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return check_changes(old, peer, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eliminate_input(enum state_input **inputs, enum state_input in)
|
static void eliminate_input(enum state_input **inputs, enum state_input in)
|
||||||
|
@ -1958,7 +1818,7 @@ static void try_input(const struct peer *peer,
|
||||||
add_dot(&hist->edges, oldstr, newstr, i, output);
|
add_dot(&hist->edges, oldstr, newstr, i, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
problem = apply_all_effects(peer, cstatus, i, ©, effect, output);
|
problem = check_all_effects(peer, cstatus, i, ©, output);
|
||||||
update_trail(&t, ©, output);
|
update_trail(&t, ©, output);
|
||||||
if (problem)
|
if (problem)
|
||||||
report_trail(&t, problem);
|
report_trail(&t, problem);
|
||||||
|
@ -2069,7 +1929,7 @@ static void activate_event(struct peer *peer, enum state_input i)
|
||||||
break;
|
break;
|
||||||
case BITCOIN_ANCHOR_TIMEOUT:
|
case BITCOIN_ANCHOR_TIMEOUT:
|
||||||
/* Can't sent DEPTHOK */
|
/* Can't sent DEPTHOK */
|
||||||
remove_event(&peer->core.event_notifies, BITCOIN_ANCHOR_DEPTHOK);
|
remove_event(peer, BITCOIN_ANCHOR_DEPTHOK);
|
||||||
break;
|
break;
|
||||||
/* And of the "done" cases means we won't give the others. */
|
/* And of the "done" cases means we won't give the others. */
|
||||||
case BITCOIN_SPEND_THEIRS_DONE:
|
case BITCOIN_SPEND_THEIRS_DONE:
|
||||||
|
@ -2160,7 +2020,7 @@ static void run_peer(const struct peer *peer,
|
||||||
|
|
||||||
/* Don't re-fire most events */
|
/* Don't re-fire most events */
|
||||||
if (!can_refire(i))
|
if (!can_refire(i))
|
||||||
remove_event(©.core.event_notifies, i);
|
remove_event(©, i);
|
||||||
activate_event(©, i);
|
activate_event(©, i);
|
||||||
try_input(©, i, idata, normalpath, errorpath,
|
try_input(©, i, idata, normalpath, errorpath,
|
||||||
prev_trail, hist);
|
prev_trail, hist);
|
||||||
|
|
Loading…
Add table
Reference in a new issue