Browse Source

state: trim unused states.

Now we never enter the state machine if we're dealing with on-chain
transactions.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 9 years ago
parent
commit
0f9889f2c6
  1. 233
      daemon/peer.c
  2. 521
      state.c
  3. 146
      state.h
  4. 161
      state_types.h

233
daemon/peer.c

@ -119,6 +119,21 @@ static void set_current_command(struct peer *peer,
peer->curr_cmd.jsoncmd = jsoncmd;
}
static void peer_breakdown(struct peer *peer)
{
/* If we have a closing tx, use it. */
if (peer->closing.their_sig) {
log_unusual(peer->log, "Peer breakdown: sending close tx");
broadcast_tx(peer, bitcoin_close(peer));
/* If we have a signed commit tx (maybe not if we just offered
* anchor), use it. */
} else if (peer->us.commit->sig) {
log_unusual(peer->log, "Peer breakdown: sending commit tx");
broadcast_tx(peer, bitcoin_commit(peer));
} else
log_info(peer->log, "Peer breakdown: nothing to do");
}
static void state_single(struct peer *peer,
const enum state_input input,
const union input *idata)
@ -157,8 +172,11 @@ static void state_single(struct peer *peer,
if (peer->cond == PEER_CLOSED)
io_wake(peer);
if (peer->state == STATE_ERR_BREAKDOWN)
peer_breakdown(peer);
/* FIXME: Some of these should just result in this peer being killed? */
if (state_is_error(peer->state)) {
else if (state_is_error(peer->state)) {
log_broken(peer->log, "Entered error state %s",
state_name(peer->state));
fatal("Peer entered error state");
@ -223,7 +241,7 @@ static void queue_input(struct peer *peer,
}
/* All unrevoked commit txs must have no HTLCs in them. */
bool committed_to_htlcs(const struct peer *peer)
static bool committed_to_htlcs(const struct peer *peer)
{
const struct commit_info *i;
@ -358,21 +376,6 @@ static void destroy_peer(struct peer *peer)
list_del_from(&peer->dstate->peers, &peer->list);
}
static void peer_breakdown(struct peer *peer)
{
/* If we have a closing tx, use it. */
if (peer->closing.their_sig) {
log_unusual(peer->log, "Peer breakdown: sending close tx");
broadcast_tx(peer, bitcoin_close(peer));
/* If we have a signed commit tx (maybe not if we just offered
* anchor), use it. */
} else if (peer->us.commit->sig) {
log_unusual(peer->log, "Peer breakdown: sending commit tx");
broadcast_tx(peer, bitcoin_commit(peer));
} else
log_info(peer->log, "Peer breakdown: nothing to do");
}
static void peer_disconnect(struct io_conn *conn, struct peer *peer)
{
log_info(peer->log, "Disconnected");
@ -397,7 +400,8 @@ static void peer_disconnect(struct io_conn *conn, struct peer *peer)
if (peer->cond == PEER_CLOSED)
return;
peer_breakdown(peer);
if (peer->state != STATE_ERR_BREAKDOWN)
peer_breakdown(peer);
}
static struct peer *new_peer(struct lightningd_state *dstate,
@ -674,9 +678,6 @@ struct anchor_watch {
struct peer *peer;
enum state_input depthok;
enum state_input timeout;
enum state_input unspent;
enum state_input theyspent;
enum state_input otherspent;
/* If timeout != INPUT_NONE, this is the timer. */
struct oneshot *timer;
@ -687,6 +688,7 @@ static void anchor_depthchange(struct peer *peer, unsigned int depth,
void *unused)
{
struct anchor_watch *w = peer->anchor.watches;
/* Still waiting for it to reach depth? */
if (w->depthok != INPUT_NONE) {
if (depth >= peer->us.mindepth) {
@ -696,13 +698,9 @@ static void anchor_depthchange(struct peer *peer, unsigned int depth,
w->timer = tal_free(w->timer);
state_event(peer, in, NULL);
}
} else {
if (depth == 0 && w->unspent != INPUT_NONE) {
enum state_input in = w->unspent;
w->unspent = INPUT_NONE;
state_event(peer, in, NULL);
}
}
} else if (depth == 0)
/* FIXME: Report losses! */
fatal("Funding transaction was unspent!");
}
/* Yay, segwit! We can just compare txids, even though we don't have both
@ -1347,8 +1345,6 @@ static void anchor_spent(struct peer *peer,
/* No longer call into the state machine. */
peer->anchor.watches->depthok = INPUT_NONE;
/* FIXME: Catch unspending of anchor, report issue. */
peer->anchor.watches->unspent = INPUT_NONE;
}
static void anchor_timeout(struct anchor_watch *w)
@ -1362,10 +1358,7 @@ static void anchor_timeout(struct anchor_watch *w)
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)
enum state_input timeout)
{
struct anchor_watch *w;
@ -1374,9 +1367,6 @@ void peer_watch_anchor(struct peer *peer,
w->peer = peer;
w->depthok = depthok;
w->timeout = timeout;
w->unspent = unspent;
w->theyspent = theyspent;
w->otherspent = otherspent;
watch_txid(w, peer, &peer->anchor.txid, anchor_depthchange, NULL);
watch_txo(w, peer, &peer->anchor.txid, 0, anchor_spent, NULL);
@ -1418,78 +1408,6 @@ void peer_unwatch_anchor_depth(struct peer *peer,
peer->anchor.watches = tal_free(peer->anchor.watches);
}
static void commit_tx_depth(struct peer *peer, unsigned int depth,
const struct sha256_double *txid,
ptrint_t *canspend)
{
u32 mediantime;
log_debug(peer->log, "Commit tx reached depth %i", depth);
/* FIXME: Handle locktime in blocks, as well as seconds! */
/* Fell out of a block? */
if (depth == 0)
return;
mediantime = get_tx_mediantime(peer->dstate, txid);
assert(mediantime);
if (get_tip_mediantime(peer->dstate) > mediantime
+ rel_locktime_to_seconds(&peer->them.locktime)) {
/* Free this watch; we're done */
peer->cur_commit.watch = tal_free(peer->cur_commit.watch);
state_event(peer, ptr2int(canspend), NULL);
} else
log_debug(peer->log, "... still CSV locked (mediantime %u, need %u + %u)",
get_tip_mediantime(peer->dstate),
mediantime,
rel_locktime_to_seconds(&peer->them.locktime));
}
/* We should map back from commit_tx permutation to figure out what happened. */
static void our_commit_spent(struct peer *peer,
const struct bitcoin_tx *commit_tx,
size_t input_num,
struct commit_info *info)
{
/* FIXME: do something useful here, if HTLCs spent */
}
/* FIXME: We tell bitcoind to watch all the outputs, which is overkill */
static void watch_commit_outputs(struct peer *peer, const struct bitcoin_tx *tx)
{
varint_t i;
struct sha256_double txid;
bitcoin_txid(tx, &txid);
for (i = 0; i < tx->output_count; i++) {
watch_txo(peer, peer, &txid, i, our_commit_spent,
peer->us.commit);
}
}
/* Watch the commit tx until our side is spendable. */
void peer_watch_delayed(struct peer *peer,
const struct bitcoin_tx *tx,
enum state_input canspend)
{
/* We only ever spend the last one. */
assert(tx == peer->us.commit->tx);
peer->cur_commit.watch = watch_tx(tx, peer, tx, commit_tx_depth,
int2ptr(canspend));
watch_commit_outputs(peer, tx);
}
static void spend_tx_done(struct peer *peer, unsigned int depth,
const struct sha256_double *txid,
ptrint_t *done)
{
log_debug(peer->log, "tx reached depth %u", depth);
if (depth >= peer->dstate->config.forever_confirms)
state_event(peer, ptr2int(done), NULL);
}
uint64_t commit_tx_fee(const struct bitcoin_tx *commit, uint64_t anchor_satoshis)
{
uint64_t i, total = 0;
@ -1501,14 +1419,6 @@ uint64_t commit_tx_fee(const struct bitcoin_tx *commit, uint64_t anchor_satoshis
return anchor_satoshis - total;
}
/* Watch this tx until it's buried enough to be forgotten. */
void peer_watch_tx(struct peer *peer,
const struct bitcoin_tx *tx,
enum state_input done)
{
watch_tx(tx, peer, tx, spend_tx_done, int2ptr(done));
}
struct bitcoin_tx *peer_create_close_tx(struct peer *peer, u64 fee)
{
struct channel_state cstate;
@ -1576,99 +1486,11 @@ void peer_calculate_close_fee(struct peer *peer)
assert(!(peer->closing.our_fee & 1));
}
bool peer_has_close_sig(const struct peer *peer)
{
return peer->closing.their_sig;
}
static void send_close_timeout(struct peer *peer)
{
/* FIXME: Remove any close_tx watches! */
state_event(peer, INPUT_CLOSE_COMPLETE_TIMEOUT, NULL);
}
void peer_watch_close(struct peer *peer,
enum state_input done, enum state_input timedout)
{
/* We save some work by assuming these. */
assert(done == BITCOIN_CLOSE_DONE);
/* FIXME: We can't send CLOSE, so timeout immediately */
if (!peer->conn) {
assert(timedout == INPUT_CLOSE_COMPLETE_TIMEOUT);
oneshot_timeout(peer->dstate, peer, 0,
send_close_timeout, peer);
return;
}
/* Give them a reasonable time to respond. */
/* FIXME: config? */
if (timedout != INPUT_NONE) {
assert(timedout == INPUT_CLOSE_COMPLETE_TIMEOUT);
peer->close_watch_timeout
= oneshot_timeout(peer->dstate, peer, 120,
send_close_timeout, peer);
}
/* anchor_spent will get called, we match against close_tx there. */
}
void peer_unwatch_close_timeout(struct peer *peer, enum state_input timedout)
{
assert(peer->close_watch_timeout);
peer->close_watch_timeout = tal_free(peer->close_watch_timeout);
}
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)
{
if (committed_to_htlcs(peer))
FIXME_STUB(peer);
return false;
}
bool peer_watch_their_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_STUB(peer);
}
void peer_unwatch_htlc_output(struct peer *peer,
const struct htlc_onchain *htlc_onchain,
enum state_input all_done)
{
FIXME_STUB(peer);
}
void peer_unwatch_all_htlc_outputs(struct peer *peer)
{
FIXME_STUB(peer);
}
void peer_watch_htlc_spend(struct peer *peer,
const struct bitcoin_tx *tx,
const struct htlc_onchain *htlc_onchain,
enum state_input done)
{
/* FIXME! */
}
void peer_unwatch_htlc_spend(struct peer *peer,
const struct htlc_onchain *htlc_onchain,
enum state_input all_done)
{
FIXME_STUB(peer);
}
void peer_unexpected_pkt(struct peer *peer, const Pkt *pkt)
{
FIXME_STUB(peer);
}
/* An on-chain transaction revealed an R value. */
void peer_tx_revealed_r_value(struct peer *peer, const struct htlc_onchain *htlc_onchain)
{
FIXME_STUB(peer);
}
void peer_watch_htlcs_cleared(struct peer *peer,
enum state_input all_done)
{
@ -2477,6 +2299,7 @@ static void json_disconnect(struct command *cmd,
* one side to freak out. We just ensure we ignore it. */
log_debug(peer->log, "Pretending connection is closed");
peer->fake_close = true;
peer->state = STATE_ERR_BREAKDOWN;
peer_breakdown(peer);
command_success(cmd, null_response(cmd));

521
state.c

@ -39,14 +39,6 @@ static enum command_status unchanged_state(enum command_status cstatus)
return cstatus;
}
/* This may not actually change the state. */
static enum command_status next_state_bits(struct peer *peer,
enum command_status cstatus,
unsigned int bits)
{
return next_state_nocheck(peer, cstatus, BITS_TO_STATE(bits));
}
static void set_peer_cond(struct peer *peer, enum state_peercond cond)
{
assert(peer->cond != cond);
@ -91,7 +83,6 @@ enum command_status state(struct peer *peer,
const union input *idata,
const struct bitcoin_tx **broadcast)
{
const struct bitcoin_tx *tx;
Pkt *err;
enum command_status cstatus = CMD_NONE;
@ -121,16 +112,15 @@ enum command_status state(struct peer *peer,
err = accept_pkt_open(peer, idata->pkt);
if (err) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto err_close_nocleanup;
goto err_breakdown;
}
return next_state(peer, cstatus, STATE_OPEN_WAIT_FOR_ANCHOR);
} else if (input_is(input, CMD_CLOSE)
|| input_is(input, INPUT_CONNECTION_LOST)) {
} else if (input_is(input, CMD_CLOSE)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto instant_close;
goto breakdown;
} else if (input_is_pkt(input)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto unexpected_pkt_nocleanup;
goto unexpected_pkt;
}
break;
case STATE_OPEN_WAIT_FOR_OPEN_WITHANCHOR:
@ -138,18 +128,17 @@ enum command_status state(struct peer *peer,
err = accept_pkt_open(peer, idata->pkt);
if (err) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto err_close_nocleanup;
goto err_breakdown;
}
bitcoin_create_anchor(peer, BITCOIN_ANCHOR_CREATED);
return next_state(peer, cstatus,
STATE_OPEN_WAIT_FOR_ANCHOR_CREATE);
} else if (input_is(input, CMD_CLOSE)
|| input_is(input, INPUT_CONNECTION_LOST)) {
} else if (input_is(input, CMD_CLOSE)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto instant_close;
goto breakdown;
} else if (input_is_pkt(input)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto unexpected_pkt_nocleanup;
goto unexpected_pkt;
}
break;
case STATE_OPEN_WAIT_FOR_ANCHOR_CREATE:
@ -157,15 +146,14 @@ enum command_status state(struct peer *peer,
queue_pkt_anchor(peer);
return next_state(peer, cstatus,
STATE_OPEN_WAIT_FOR_COMMIT_SIG);
} else if (input_is(input, CMD_CLOSE)
|| input_is(input, INPUT_CONNECTION_LOST)) {
} else if (input_is(input, CMD_CLOSE)) {
bitcoin_release_anchor(peer, BITCOIN_ANCHOR_CREATED);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto instant_close;
goto breakdown;
} else if (input_is_pkt(input)) {
bitcoin_release_anchor(peer, BITCOIN_ANCHOR_CREATED);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto unexpected_pkt_nocleanup;
goto unexpected_pkt;
}
break;
case STATE_OPEN_WAIT_FOR_ANCHOR:
@ -173,25 +161,21 @@ enum command_status state(struct peer *peer,
err = accept_pkt_anchor(peer, idata->pkt);
if (err) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto err_close_nocleanup;
goto err_breakdown;
}
queue_pkt_open_commit_sig(peer);
peer_watch_anchor(peer,
BITCOIN_ANCHOR_DEPTHOK,
BITCOIN_ANCHOR_TIMEOUT,
BITCOIN_ANCHOR_UNSPENT,
BITCOIN_ANCHOR_THEIRSPEND,
BITCOIN_ANCHOR_OTHERSPEND);
BITCOIN_ANCHOR_TIMEOUT);
return next_state(peer, cstatus,
STATE_OPEN_WAITING_THEIRANCHOR);
} else if (input_is(input, CMD_CLOSE)
|| input_is(input, INPUT_CONNECTION_LOST)) {
} else if (input_is(input, CMD_CLOSE)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto instant_close;
goto breakdown;
} else if (input_is_pkt(input)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto unexpected_pkt_nocleanup;
goto unexpected_pkt;
}
break;
case STATE_OPEN_WAIT_FOR_COMMIT_SIG:
@ -200,26 +184,22 @@ enum command_status state(struct peer *peer,
if (err) {
bitcoin_release_anchor(peer, INPUT_NONE);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto err_start_unilateral_close;
goto err_breakdown;
}
queue_tx_broadcast(broadcast, bitcoin_anchor(peer));
peer_watch_anchor(peer,
BITCOIN_ANCHOR_DEPTHOK,
INPUT_NONE,
BITCOIN_ANCHOR_UNSPENT,
BITCOIN_ANCHOR_THEIRSPEND,
BITCOIN_ANCHOR_OTHERSPEND);
INPUT_NONE);
return next_state(peer, cstatus,
STATE_OPEN_WAITING_OURANCHOR);
} else if (input_is(input, CMD_CLOSE)
|| input_is(input, INPUT_CONNECTION_LOST)) {
} else if (input_is(input, CMD_CLOSE)) {
bitcoin_release_anchor(peer, INPUT_NONE);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto instant_close;
goto breakdown;
} else if (input_is_pkt(input)) {
bitcoin_release_anchor(peer, INPUT_NONE);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto unexpected_pkt_nocleanup;
goto unexpected_pkt;
}
break;
case STATE_OPEN_WAITING_OURANCHOR:
@ -231,7 +211,7 @@ enum command_status state(struct peer *peer,
peer_unwatch_anchor_depth(peer,
BITCOIN_ANCHOR_DEPTHOK,
INPUT_NONE);
goto err_start_unilateral_close;
goto err_breakdown;
}
return next_state(peer, cstatus,
STATE_OPEN_WAITING_OURANCHOR_THEYCOMPLETED);
@ -246,19 +226,6 @@ enum command_status state(struct peer *peer,
}
return next_state(peer, cstatus,
STATE_OPEN_WAIT_FOR_COMPLETE_OURANCHOR);
} else if (input_is(input, BITCOIN_ANCHOR_UNSPENT)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto anchor_unspent;
} else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) {
/* We no longer care about anchor depth. */
peer_unwatch_anchor_depth(peer,
BITCOIN_ANCHOR_DEPTHOK,
INPUT_NONE);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto them_unilateral;
} else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) {
/* This should be impossible. */
return next_state(peer, cstatus, STATE_ERR_INFORMATION_LEAK);
} else if (input_is(input, CMD_CLOSE)) {
/* We no longer care about anchor depth. */
peer_unwatch_anchor_depth(peer,
@ -266,13 +233,6 @@ enum command_status state(struct peer *peer,
INPUT_NONE);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto start_clearing;
} else if (input_is(input, INPUT_CONNECTION_LOST)) {
/* We no longer care about anchor depth. */
peer_unwatch_anchor_depth(peer,
BITCOIN_ANCHOR_DEPTHOK,
INPUT_NONE);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto start_unilateral_close;
} else if (input_is(input, PKT_CLOSE_CLEARING)) {
/* We no longer care about anchor depth. */
peer_unwatch_anchor_depth(peer,
@ -298,7 +258,7 @@ enum command_status state(struct peer *peer,
peer_unwatch_anchor_depth(peer,
BITCOIN_ANCHOR_DEPTHOK,
BITCOIN_ANCHOR_TIMEOUT);
goto err_start_unilateral_close;
goto err_breakdown;
}
return next_state(peer, cstatus,
STATE_OPEN_WAITING_THEIRANCHOR_THEYCOMPLETED);
@ -317,20 +277,6 @@ enum command_status state(struct peer *peer,
}
return next_state(peer, cstatus,
STATE_OPEN_WAIT_FOR_COMPLETE_THEIRANCHOR);
} else if (input_is(input, BITCOIN_ANCHOR_UNSPENT)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto anchor_unspent;
} else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) {
/* This should be impossible. */
return next_state(peer, cstatus,
STATE_ERR_INFORMATION_LEAK);
} else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) {
/* We no longer care about anchor depth. */
peer_unwatch_anchor_depth(peer,
BITCOIN_ANCHOR_DEPTHOK,
BITCOIN_ANCHOR_TIMEOUT);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto them_unilateral;
} else if (input_is(input, CMD_CLOSE)) {
/* We no longer care about anchor depth. */
peer_unwatch_anchor_depth(peer,
@ -338,13 +284,6 @@ enum command_status state(struct peer *peer,
BITCOIN_ANCHOR_TIMEOUT);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto start_clearing;
} else if (input_is(input, INPUT_CONNECTION_LOST)) {
/* We no longer care about anchor depth. */
peer_unwatch_anchor_depth(peer,
BITCOIN_ANCHOR_DEPTHOK,
BITCOIN_ANCHOR_TIMEOUT);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto start_unilateral_close;
} else if (input_is(input, PKT_CLOSE_CLEARING)) {
/* We no longer care about anchor depth. */
peer_unwatch_anchor_depth(peer,
@ -372,23 +311,9 @@ enum command_status state(struct peer *peer,
complete_cmd(peer, &cstatus, CMD_SUCCESS);
return next_state(peer, cstatus, STATE_NORMAL);
}
} else if (input_is(input, BITCOIN_ANCHOR_UNSPENT)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto anchor_unspent;
/* Nobody should be able to spend anchor, except via the
* commit txs. */
} else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) {
return next_state(peer, cstatus,
STATE_ERR_INFORMATION_LEAK);
} else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto them_unilateral;
} else if (input_is(input, CMD_CLOSE)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto start_clearing;
} else if (input_is(input, INPUT_CONNECTION_LOST)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto start_unilateral_close;
} else if (input_is(input, PKT_CLOSE_CLEARING)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto accept_clearing;
@ -433,7 +358,7 @@ enum command_status state(struct peer *peer,
err = accept_pkt_revocation(peer, idata->pkt);
if (err) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto err_start_unilateral_close;
goto err_breakdown;
}
complete_cmd(peer, &cstatus, CMD_SUCCESS);
return next_state(peer, cstatus, STATE_NORMAL);
@ -444,32 +369,24 @@ enum command_status state(struct peer *peer,
} else if (input_is(input, PKT_UPDATE_ADD_HTLC)) {
err = accept_pkt_htlc_add(peer, idata->pkt);
if (err)
goto err_start_unilateral_close;
goto err_breakdown;
return unchanged_state(cstatus);
} else if (input_is(input, PKT_UPDATE_FULFILL_HTLC)) {
err = accept_pkt_htlc_fulfill(peer, idata->pkt);
if (err)
goto err_start_unilateral_close;
goto err_breakdown;
return unchanged_state(cstatus);
} else if (input_is(input, PKT_UPDATE_FAIL_HTLC)) {
err = accept_pkt_htlc_fail(peer, idata->pkt);
if (err)
goto err_start_unilateral_close;
goto err_breakdown;
return unchanged_state(cstatus);
} else if (input_is(input, PKT_UPDATE_COMMIT)) {
err = accept_pkt_commit(peer, idata->pkt);
if (err)
goto err_start_unilateral_close;
goto err_breakdown;
queue_pkt_revocation(peer);
return unchanged_state(cstatus);
} else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) {
goto them_unilateral;
} else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) {
goto old_commit_spotted;
} else if (input_is(input, BITCOIN_ANCHOR_UNSPENT)) {
goto anchor_unspent;
} else if (input_is(input, INPUT_CONNECTION_LOST)) {
goto start_unilateral_close;
} else if (input_is(input, PKT_CLOSE_CLEARING)) {
goto accept_clearing;
} else if (input_is_pkt(input)) {
@ -481,7 +398,7 @@ enum command_status state(struct peer *peer,
if (input_is(input, PKT_CLOSE_CLEARING)) {
err = accept_pkt_close_clearing(peer, idata->pkt);
if (err)
goto err_start_unilateral_close;
goto err_breakdown;
/* Notify us when there are no more htlcs in
* either commit tx */
@ -492,9 +409,7 @@ enum command_status state(struct peer *peer,
} else if (input_is(input, CMD_SEND_HTLC_FAIL)
|| input_is(input, CMD_SEND_HTLC_FULFILL)) {
err = pkt_err(peer, "FIXME: cmd during clearing.");
goto err_start_unilateral_close;
} else if (input_is(input, INPUT_CONNECTION_LOST)) {
goto start_unilateral_close;
goto err_breakdown;
} else if (input_is_pkt(input)) {
/* FIXME: We must continue to allow add, fulfill & fail packets */
goto unexpected_pkt;
@ -506,9 +421,7 @@ enum command_status state(struct peer *peer,
} else if (input_is(input, CMD_SEND_HTLC_FAIL)
|| input_is(input, CMD_SEND_HTLC_FULFILL)) {
err = pkt_err(peer, "FIXME: cmd during clearing.");
goto err_start_unilateral_close;
} else if (input_is(input, INPUT_CONNECTION_LOST)) {
goto start_unilateral_close;
goto err_breakdown;
} else if (input_is_pkt(input)) {
/* FIXME: We must continue to allow fulfill & fail packets */
goto unexpected_pkt;
@ -520,7 +433,7 @@ enum command_status state(struct peer *peer,
err = accept_pkt_close_sig(peer, idata->pkt,
&acked, &we_agree);
if (err)
goto err_start_unilateral_close;
goto err_breakdown;
/* Are we about to offer the same fee they did? */
if (we_agree) {
@ -531,9 +444,6 @@ enum command_status state(struct peer *peer,
/* Do fees now match? */
if (acked) {
peer_unwatch_close_timeout(peer,
INPUT_CLOSE_COMPLETE_TIMEOUT);
/* Send close TX. */
queue_tx_broadcast(broadcast,
bitcoin_close(peer));
@ -546,245 +456,21 @@ enum command_status state(struct peer *peer,
/* Offer the new fee. */
queue_pkt_close_signature(peer);
return unchanged_state(cstatus);
} else if (input_is(input, INPUT_CONNECTION_LOST)) {
goto start_unilateral_close;
} else if (input_is(input, INPUT_CLOSE_COMPLETE_TIMEOUT)) {
err = pkt_err(peer, "Close timed out");
goto err_start_unilateral_close;
goto err_breakdown;
} else if (input_is_pkt(input)) {
goto unexpected_pkt;
}
break;
/* Close states are regular: handle as a group. */
case STATE_CLOSE_WAIT_HTLCS:
case STATE_CLOSE_WAIT_STEAL:
case STATE_CLOSE_WAIT_THEIRCOMMIT:
case STATE_CLOSE_WAIT_THEIRCOMMIT_WITH_HTLCS:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_WITH_HTLCS:
case STATE_CLOSE_WAIT_CLOSE:
case STATE_CLOSE_WAIT_STEAL_CLOSE:
case STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE:
case STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE_WITH_HTLCS:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_WITH_HTLCS:
case STATE_CLOSE_WAIT_STEAL_OURCOMMIT:
case STATE_CLOSE_WAIT_STEAL_OURCOMMIT_WITH_HTLCS:
case STATE_CLOSE_WAIT_THEIRCOMMIT_OURCOMMIT:
case STATE_CLOSE_WAIT_THEIRCOMMIT_OURCOMMIT_WITH_HTLCS:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_OURCOMMIT:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_OURCOMMIT_WITH_HTLCS:
case STATE_CLOSE_WAIT_CLOSE_OURCOMMIT:
case STATE_CLOSE_WAIT_STEAL_CLOSE_OURCOMMIT:
case STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE_OURCOMMIT:
case STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE_OURCOMMIT_WITH_HTLCS:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_OURCOMMIT:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_OURCOMMIT_WITH_HTLCS:
case STATE_CLOSE_WAIT_STEAL_SPENDOURS:
case STATE_CLOSE_WAIT_STEAL_SPENDOURS_WITH_HTLCS:
case STATE_CLOSE_WAIT_THEIRCOMMIT_SPENDOURS:
case STATE_CLOSE_WAIT_THEIRCOMMIT_SPENDOURS_WITH_HTLCS:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_SPENDOURS:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_SPENDOURS_WITH_HTLCS:
case STATE_CLOSE_WAIT_CLOSE_SPENDOURS:
case STATE_CLOSE_WAIT_STEAL_CLOSE_SPENDOURS:
case STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE_SPENDOURS:
case STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE_SPENDOURS_WITH_HTLCS:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_SPENDOURS:
case STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_SPENDOURS_WITH_HTLCS:
case STATE_CLOSE_WAIT_OURCOMMIT:
case STATE_CLOSE_WAIT_OURCOMMIT_WITH_HTLCS:
case STATE_CLOSE_WAIT_SPENDOURS:
case STATE_CLOSE_WAIT_SPENDOURS_WITH_HTLCS: {
unsigned int bits;
enum state_input closed;
bits = STATE_TO_BITS(peer->state);
/* Once we see a steal or spend completely buried, we
* close unless we're still waiting for htlcs*/
if (bits & STATE_CLOSE_HTLCS_BIT)
closed = STATE_CLOSE_WAIT_HTLCS;
else
closed = STATE_CLOSED;
/* Our steal is deep enough to forget? */
if ((bits & STATE_CLOSE_STEAL_BIT)
&& input_is(input, BITCOIN_STEAL_DONE)) {
/* One a steal is complete, we don't care about htlcs
* (we stole them all) */
if (bits & STATE_CLOSE_HTLCS_BIT)
peer_unwatch_all_htlc_outputs(peer);
return next_state(peer, cstatus, STATE_CLOSED);
}
/* Their commit is buried deep enough to forget? */
if ((bits & STATE_CLOSE_THEIRCOMMIT_BIT)
&& input_is(input, BITCOIN_THEIRCOMMIT_DONE)) {
BUILD_ASSERT(!(STATE_TO_BITS(STATE_CLOSE_WAIT_HTLCS)
& STATE_CLOSE_THEIRCOMMIT_BIT));
return next_state(peer, cstatus, closed);
}
/* Mutual close deep enough to forget? */
if ((bits & STATE_CLOSE_CLOSE_BIT)
&& input_is(input, BITCOIN_CLOSE_DONE)) {
BUILD_ASSERT(!(STATE_TO_BITS(STATE_CLOSE_WAIT_HTLCS)
& STATE_CLOSE_CLOSE_BIT));
return next_state(peer, cstatus, closed);
}
/* Our commit deep enough to spend our output? */
if ((bits & STATE_CLOSE_OURCOMMIT_BIT)
&& input_is(input, BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED)) {
BUILD_ASSERT(!(STATE_TO_BITS(STATE_CLOSE_WAIT_HTLCS)
& STATE_CLOSE_OURCOMMIT_BIT));
/* FIXME: If our output was dust, just fire when
* ourcommit deep enough to forget. */
tx = bitcoin_spend_ours(peer);
/* Now we need to wait for our commit to be done. */
queue_tx_broadcast(broadcast, tx);
peer_watch_tx(peer, tx, BITCOIN_SPEND_OURS_DONE);
bits &= ~STATE_CLOSE_OURCOMMIT_BIT;
bits |= STATE_CLOSE_SPENDOURS_BIT;
return next_state(peer, cstatus, BITS_TO_STATE(bits));
}
/* Our spend of ourcommit is deep enough to forget? */
if ((bits & STATE_CLOSE_SPENDOURS_BIT)
&& input_is(input, BITCOIN_SPEND_OURS_DONE)) {
BUILD_ASSERT(!(STATE_TO_BITS(STATE_CLOSE_WAIT_HTLCS)
& STATE_CLOSE_SPENDOURS_BIT));
return next_state(peer, cstatus, closed);
}
/* If we have htlcs, we can get other inputs... */
if (bits & STATE_CLOSE_HTLCS_BIT) {
if (input_is(input, INPUT_NO_MORE_HTLCS)) {
/* Clear bit, might lead to STATE_CLOSED. */
BUILD_ASSERT((BITS_TO_STATE(STATE_TO_BITS(STATE_CLOSE_WAIT_HTLCS) & ~STATE_CLOSE_HTLCS_BIT)) == STATE_CLOSED);
bits &= ~STATE_CLOSE_HTLCS_BIT;
return next_state(peer, cstatus,
BITS_TO_STATE(bits));
} else if (input_is(input, BITCOIN_HTLC_TOTHEM_SPENT)) {
/* They revealed R value. */
peer_tx_revealed_r_value(peer,
idata->htlc_onchain);
/* We don't care any more. */
peer_unwatch_htlc_output(peer,
idata->htlc_onchain,
INPUT_NO_MORE_HTLCS);
return unchanged_state(cstatus);
} else if (input_is(input, BITCOIN_HTLC_TOTHEM_TIMEOUT)){
tx = bitcoin_htlc_timeout(peer,
idata->htlc_onchain);
/* HTLC timed out, spend it back to us. */
queue_tx_broadcast(broadcast, tx);
/* Don't unwatch yet; they could yet
* try to spend, revealing rvalue. */
/* We're done when that gets buried. */
peer_watch_htlc_spend(peer, tx,
idata->htlc_onchain,
BITCOIN_HTLC_RETURN_SPEND_DONE);
return unchanged_state(cstatus);
} else if (input_is(input, INPUT_RVALUE)) {
tx = bitcoin_htlc_spend(peer,
idata->htlc_onchain);
/* Spend it... */
queue_tx_broadcast(broadcast, tx);
/* We're done when it gets buried. */
peer_watch_htlc_spend(peer, tx,
idata->htlc_onchain,
BITCOIN_HTLC_FULFILL_SPEND_DONE);
/* Don't care about this one any more. */
peer_unwatch_htlc_output(peer,
idata->htlc_onchain,
INPUT_NO_MORE_HTLCS);
return unchanged_state(cstatus);
} else if (input_is(input, BITCOIN_HTLC_FULFILL_SPEND_DONE)) {
/* Stop watching spend, send
* INPUT_NO_MORE_HTLCS when done. */
peer_unwatch_htlc_spend(peer,
idata->htlc_onchain,
INPUT_NO_MORE_HTLCS);
return unchanged_state(cstatus);
} else if (input_is(input, BITCOIN_HTLC_RETURN_SPEND_DONE)) {
/* Stop watching spend, send
* INPUT_NO_MORE_HTLCS when done. */
peer_unwatch_htlc_spend(peer,
idata->htlc_onchain,
INPUT_NO_MORE_HTLCS);
/* Don't need to watch the HTLC output any more,
* either. */
peer_unwatch_htlc_output(peer,
idata->htlc_onchain,
INPUT_NO_MORE_HTLCS);
return unchanged_state(cstatus);
} else if (input_is(input, BITCOIN_HTLC_TOUS_TIMEOUT)) {
/* They can spend, we no longer care
* about this HTLC. */
peer_unwatch_htlc_output(peer,
idata->htlc_onchain,
INPUT_NO_MORE_HTLCS);
return unchanged_state(cstatus);
}
}
/* If we're just waiting for HTLCs, anything else is an error */
if (peer->state == STATE_CLOSE_WAIT_HTLCS)
break;
/*
* Now, other side can always spring a commit transaction on
* us (they might have two valid ones, if they didn't send
* revocation preimage yet, so always allow it).
*/
if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) {
peer_watch_tx(peer, idata->tx, BITCOIN_THEIRCOMMIT_DONE);
/* HTLC watches: if any, set HTLCs bit. */
if (peer_watch_their_htlc_outputs(peer, idata->tx,
BITCOIN_HTLC_TOUS_TIMEOUT,
BITCOIN_HTLC_TOTHEM_SPENT,
BITCOIN_HTLC_TOTHEM_TIMEOUT))
bits |= STATE_CLOSE_HTLCS_BIT;
bits |= STATE_CLOSE_THEIRCOMMIT_BIT;
return next_state_bits(peer, cstatus, bits);
/* This can happen multiple times: need to steal ALL */
} else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) {
tx = bitcoin_steal(peer, idata->ci);
if (!tx)
return next_state(peer, cstatus,
STATE_ERR_INFORMATION_LEAK);
queue_tx_broadcast(broadcast, tx);
peer_watch_tx(peer, tx, BITCOIN_STEAL_DONE);
bits |= STATE_CLOSE_STEAL_BIT;
return next_state_bits(peer, cstatus, bits);
} else if (input_is(input, BITCOIN_ANCHOR_UNSPENT))
goto anchor_unspent;
break;
}
/* Should never happen. */
case STATE_ERR_INTERNAL:
case STATE_ERR_INFORMATION_LEAK:
case STATE_ERR_ANCHOR_TIMEOUT:
case STATE_ERR_ANCHOR_LOST:
case STATE_ERR_BREAKDOWN:
case STATE_CLOSE_WAIT_CLOSE:
case STATE_CLOSED:
case STATE_MAX:
case STATE_UNUSED_CLOSE_WAIT_STEAL_WITH_HTLCS:
case STATE_UNUSED_CLOSE_WAIT_CLOSE_WITH_HTLCS:
case STATE_UNUSED_CLOSE_WAIT_STEAL_CLOSE_WITH_HTLCS:
case STATE_UNUSED_CLOSE_WAIT_CLOSE_OURCOMMIT_WITH_HTLCS:
case STATE_UNUSED_CLOSE_WAIT_STEAL_CLOSE_OURCOMMIT_WITH_HTLCS:
case STATE_UNUSED_CLOSE_WAIT_CLOSE_SPENDOURS_WITH_HTLCS:
case STATE_UNUSED_CLOSE_WAIT_STEAL_CLOSE_SPENDOURS_WITH_HTLCS:
case STATE_CLOSE_ONCHAIN_CHEATED:
case STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL:
case STATE_CLOSE_ONCHAIN_OUR_UNILATERAL:
@ -796,108 +482,18 @@ enum command_status state(struct peer *peer,
return next_state(peer, cstatus, STATE_ERR_INTERNAL);
unexpected_pkt:
/*
* We got a weird packet, so we need to close unilaterally.
*/
peer_unexpected_pkt(peer, idata->pkt);
/* Don't reply to an error with an error. */
if (input_is(input, PKT_ERROR)) {
goto start_unilateral_close;
}
err = pkt_err_unexpected(peer, idata->pkt);
goto err_start_unilateral_close;
unexpected_pkt_nocleanup:
/*
* Unexpected packet, but nothing sent to chain yet, so no cleanup.
*/
/* Don't reply to an error with an error. */
if (input_is(input, PKT_ERROR)) {
goto close_nocleanup;
if (!input_is(input, PKT_ERROR)) {
goto breakdown;
}
err = pkt_err_unexpected(peer, idata->pkt);
goto err_close_nocleanup;
anchor_unspent:
/*
* Bitcoind tells us anchor got double-spent. If we double-spent it
* then we're malfunctioning. If they double-spent it, then they
* managed to cheat us: post_to_reddit();
*/
return next_state(peer, cstatus, STATE_ERR_ANCHOR_LOST);
err_close_nocleanup:
/*
* Something went wrong, but we haven't sent anything to the blockchain
* so there's nothing to clean up.
*/
queue_pkt_err(peer, err);
close_nocleanup:
change_peer_cond(peer, PEER_CMD_OK, PEER_CLOSED);
return next_state(peer, cstatus, STATE_CLOSED);
err_start_unilateral_close:
/*
* They timed out, or were broken; we are going to close unilaterally.
*/
err_breakdown:
queue_pkt_err(peer, err);
start_unilateral_close:
/*
* Close unilaterally.
*/
/* No more inputs, no more commands. */
set_peer_cond(peer, PEER_CLOSED);
/*
* If they sent us a close tx, that's always cheaper than
* broadcasting our last commit tx, and our funds are not
* timelocked.
*/
if (peer_has_close_sig(peer)) {
queue_tx_broadcast(broadcast, bitcoin_close(peer));
return next_state(peer, cstatus, STATE_CLOSE_WAIT_CLOSE);
}
tx = bitcoin_commit(peer);
queue_tx_broadcast(broadcast, tx);
peer_watch_delayed(peer, tx, BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED);
/* HTLC watches. */
if (peer_watch_our_htlc_outputs(peer, tx,
BITCOIN_HTLC_TOUS_TIMEOUT,
BITCOIN_HTLC_TOTHEM_SPENT,
BITCOIN_HTLC_TOTHEM_TIMEOUT))
return next_state(peer, cstatus,
STATE_CLOSE_WAIT_OURCOMMIT_WITH_HTLCS);
return next_state(peer, cstatus, STATE_CLOSE_WAIT_OURCOMMIT);
them_unilateral:
assert(input == BITCOIN_ANCHOR_THEIRSPEND);
/*
* Bitcoind tells us they did unilateral close.
*/
queue_pkt_err(peer, pkt_err(peer, "Commit tx noticed"));
/* No more inputs, no more commands. */
set_peer_cond(peer, PEER_CLOSED);
peer_watch_tx(peer, idata->tx, BITCOIN_THEIRCOMMIT_DONE);
/* HTLC watches (based on what they broadcast, which *may* be out
* of step with our current state by +/- 1 htlc. */
if (peer_watch_their_htlc_outputs(peer, idata->tx,
BITCOIN_HTLC_TOUS_TIMEOUT,
BITCOIN_HTLC_TOTHEM_SPENT,
BITCOIN_HTLC_TOTHEM_TIMEOUT))
return next_state(peer, cstatus,
STATE_CLOSE_WAIT_THEIRCOMMIT_WITH_HTLCS);
return next_state(peer, cstatus, STATE_CLOSE_WAIT_THEIRCOMMIT);
breakdown:
return next_state(peer, cstatus, STATE_ERR_BREAKDOWN);
start_clearing:
/*
@ -913,14 +509,13 @@ start_clearing:
start_closing_cleared:
/* As soon as we send packet, they could close. */
peer_calculate_close_fee(peer);
peer_watch_close(peer, BITCOIN_CLOSE_DONE, INPUT_CLOSE_COMPLETE_TIMEOUT);
queue_pkt_close_signature(peer);
return next_state(peer, cstatus, STATE_WAIT_FOR_CLOSE_SIG);
accept_clearing:
err = accept_pkt_close_clearing(peer, idata->pkt);
if (err)
goto err_start_unilateral_close;
goto err_breakdown;
/* Notify us when there are no more htlcs in either commit tx */
peer_watch_htlcs_cleared(peer, INPUT_HTLCS_CLEARED);
@ -932,36 +527,4 @@ accept_clearing:
queue_pkt_close_clearing(peer);
return next_state(peer, cstatus, STATE_BOTH_CLEARING);
instant_close:
/*
* Closing, but we haven't sent anything to the blockchain so
* there's nothing to clean up.
*/
/* FIXME: Should we tell other side we're going? */
set_peer_cond(peer, PEER_CLOSED);
/* We can't have any HTLCs, since we haven't started. */
if (committed_to_htlcs(peer))
return next_state(peer, cstatus, STATE_ERR_INTERNAL);
return next_state(peer, cstatus, STATE_CLOSED);
old_commit_spotted:
/*
* bitcoind reported a broadcast of the not-latest commit tx.
*/
queue_pkt_err(peer, pkt_err(peer, "Otherspend noticed"));
/* No more packets, no more commands. */
set_peer_cond(peer, PEER_CLOSED);
/* If we can't find it, we're lost. */
tx = bitcoin_steal(peer, idata->ci);
if (!tx)
return next_state(peer, cstatus,
STATE_ERR_INFORMATION_LEAK);
queue_tx_broadcast(broadcast, tx);
peer_watch_tx(peer, tx, BITCOIN_STEAL_DONE);
return next_state(peer, cstatus, STATE_CLOSE_WAIT_STEAL);
}

146
state.h

@ -121,41 +121,18 @@ Pkt *accept_pkt_close_clearing(struct peer *peer, const Pkt *pkt);
Pkt *accept_pkt_close_sig(struct peer *peer, const Pkt *pkt,
bool *acked, bool *we_agree);
/**
* committed_to_htlcs: do we have any locked-in HTLCs?
* @peer: the state data for this peer.
*
* If we were to generate a commit tx now, would it have HTLCs in it?
*/
bool committed_to_htlcs(const struct peer *peer);
/**
* peer_has_close_sig: do we have a valid close_sig from them?
* @peer: the state data for this peer.
*
* We use any acceptable close tx, if we have one, in preference to a commit tx.
*/
bool peer_has_close_sig(const struct peer *peer);
/**
* peer_watch_anchor: create a watch for the anchor transaction.
* @peer: the state data for this peer.
* @depthok: the input to give when anchor reaches expected depth.
* @timeout: the input to give if anchor doesn't reach depth in time.
* @unspent: the input to give if anchor is unspent after @depthok.
* @theyspent: the input to give if they spend anchor with their commit tx.
* @otherspent: the input to give if they spend anchor otherwise.
*
* @depthok can be INPUT_NONE if it's our anchor (we don't time
* ourselves out).
*/
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);
enum state_input timeout);
/**
* peer_unwatch_anchor_depth: remove depth watch for the anchor.
* @peer: the state data for this peer.
@ -168,127 +145,6 @@ void peer_unwatch_anchor_depth(struct peer *peer,
enum state_input depthok,
enum state_input timeout);
/**
* peer_watch_delayed: watch this (commit) tx, tell me when I can spend it
* @peer: the state data for this peer.
* @tx: the tx we're watching.
* @canspend: the input to give when commit reaches spendable depth.
*
* Note that this tx may be malleated, as it's dual-signed.
*/
void peer_watch_delayed(struct peer *peer,
const struct bitcoin_tx *tx,
enum state_input canspend);
/**
* peer_watch_tx: watch this tx until it's "irreversible"
* @peer: the state data for this peer.
* @tx: the tx we're watching.
* @done: the input to give when tx is completely buried.
*
* Once this fires we consider the channel completely closed and stop
* watching (eg 100 txs down).
*
* This is used for watching a transaction we sent (such as a steal,
* or spend of their close, etc).
*/
void peer_watch_tx(struct peer *peer,
const struct bitcoin_tx *tx,
enum state_input done);
/**
* peer_watch_close: watch for close tx until it's "irreversible" (or timedout)
* @peer: the state data for this peer.
* @done: the input to give when tx is completely buried.
* @timedout: the input to give if we time out (they don't provide sig).
*
* Once this fires we consider the channel completely closed and stop
* watching (eg 100 txs down).
*
* This is used for watching a mutual close.
*/
void peer_watch_close(struct peer *peer,
enum state_input done, enum state_input timedout);
/**
* peer_unwatch_close_timeout: remove timeout for the close transaction
* @peer: the state data for this peer.
* @timeout: the input to give if anchor doesn't reach depth in time.
*
* This is called once we have successfully received their signature.
*/
void peer_unwatch_close_timeout(struct peer *peer, enum state_input timedout);
/**
* peer_watch_our_htlc_outputs: HTLC outputs from our commit tx to watch.
* @peer: the state data for this peer.
* @tx: the commitment tx
* @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_timeout: input to give when a HTLC output to them times out.
*
* Returns true if there were any htlc outputs to watch.
*/
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);
/**
* peer_watch_their_htlc_outputs: HTLC outputs from their commit tx to watch.
* @peer: the state data for this peer.
* @tx: the commitment tx
* @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_timeout: input to give when a HTLC output to them times out.
*
* Returns true if there were any htlc outputs to watch.
*/
bool peer_watch_their_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);
/**
* peer_unwatch_htlc_output: stop watching an HTLC
* @peer: the state data for this peer.
* @htlc_onchain: the htlc to stop watching
* @all_done: input to give if we're not watching any outputs anymore.
*/
void peer_unwatch_htlc_output(struct peer *peer,
const struct htlc_onchain *htlc_onchain,
enum state_input all_done);
/**
* peer_unwatch_all_htlc_outputs: stop watching all HTLCs
* @peer: the state data for this peer.
*/
void peer_unwatch_all_htlc_outputs(struct peer *peer);
/**
* peer_watch_htlc_spend: watch our spend of an HTLC output
* @peer: the state data for this peer.
* @tx: the commitment tx
* @htlc_onchain: the htlc the tx is spending an output of
* @done: input to give when it's completely buried.
*/
void peer_watch_htlc_spend(struct peer *peer,
const struct bitcoin_tx *tx,
const struct htlc_onchain *htlc_onchain,
enum state_input done);
/**
* peer_unwatch_htlc_spend: stop watching our HTLC spend
* @peer: the state data for this peer.
* @htlc_onchain: the htlc to stop watching the spend for.
* @all_done: input to give if we're not watching anything anymore.
*/
void peer_unwatch_htlc_spend(struct peer *peer,
const struct htlc_onchain *htlc_onchain,
enum state_input all_done);
/**
* peer_watch_htlcs_cleared: tell us when no HTLCs are in commit txs.
* @peer: the state data for this peer.

161
state_types.h

@ -4,13 +4,6 @@
/* FIXME: cdump is really dumb, so we put these in their own header. */
#include "lightning.pb-c.h"
#define STATE_CLOSE_HTLCS_BIT 1
#define STATE_CLOSE_STEAL_BIT 2
#define STATE_CLOSE_THEIRCOMMIT_BIT 4
#define STATE_CLOSE_CLOSE_BIT 8
#define STATE_CLOSE_OURCOMMIT_BIT 16
#define STATE_CLOSE_SPENDOURS_BIT 32
enum state {
STATE_INIT,
@ -44,112 +37,11 @@ enum state {
STATE_BOTH_CLEARING,
/* We're cleared, waiting for close signature / negotiation */
STATE_WAIT_FOR_CLOSE_SIG,
/* We've broadcast the mutual close, waiting for onchain. */
STATE_CLOSE_WAIT_CLOSE,
/* All closed. */
STATE_CLOSED,
/* Just waiting for HTLCs to resolve. */
STATE_CLOSE_WAIT_HTLCS,
/*
* They can broadcast one or more revoked commit tx, or their latest
* commit tx at any time. We respond to revoked commit txs by stealing
* their funds (steal). We also track their latest commit tx (no need
* to spend our output, it's just a P2WPKH for us) (their_commit).
* They can also (with our help) broadcast a mutual close tx
* (mutual_close).
*
* We can also broadcast one of the following:
* 1) Our latest commit tx (our_commit).
* 2) After delay has passed, spend of our tx (spend_ours).
* 3) Mutual close tx (mutual_close), already covered above.
*
* Thus, we could be waiting for the following combinations:
* - steal
* - their_commit
* - steal + their_commit
* - mutual_close
* - steal + mutual_close
* - their_commit + mutual_close
* - steal + their_commit + mutual_close
*
* - our_commit
* - steal + our_commit
* - their_commit + our_commit
* - steal + their_commit + our_commit
* - mutual_close + our_commit
* - steal + mutual_close + our_commit
* - their_commit + mutual_close + our_commit
* - steal + their_commit + mutual_close + our_commit
*
* - spend_ours
* - steal + spend_ours
* - their_commit + spend_ours
* - steal + their_commit + spend_ours
* - mutual_close + spend_ours
* - steal + mutual_close + spend_ours
* - their_commit + mutual_close + spend_ours
* - steal + their_commit + mutual_close + spend_ours
*
* Each of these has with-HTLC and without-HTLC variants, except:
*
* 1) We never agree to close with HTLCs,
* 2) We don't care about htlcs if we steal (we steal all outputs).
*
* Now, it is possible for us to CLOSE and them to have an HTLC,
* because we could close partway through negotiation. So, any
* commit tx they publish could introduce HTLCs.
*
* Thus, HTLC variants are only possible with THEIRCOMMIT, OR
* OURCOMMIT/SPENDOURS, and only no CLOSE (since CLOSE implies no HTLCs).
*/
STATE_CLOSE_WAIT_STEAL,
STATE_UNUSED_CLOSE_WAIT_STEAL_WITH_HTLCS,
STATE_CLOSE_WAIT_THEIRCOMMIT,
STATE_CLOSE_WAIT_THEIRCOMMIT_WITH_HTLCS,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_WITH_HTLCS,
STATE_CLOSE_WAIT_CLOSE,
STATE_UNUSED_CLOSE_WAIT_CLOSE_WITH_HTLCS,
STATE_CLOSE_WAIT_STEAL_CLOSE,
STATE_UNUSED_CLOSE_WAIT_STEAL_CLOSE_WITH_HTLCS,
STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE,
STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE_WITH_HTLCS,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_WITH_HTLCS,
STATE_CLOSE_WAIT_OURCOMMIT,
STATE_CLOSE_WAIT_OURCOMMIT_WITH_HTLCS,
STATE_CLOSE_WAIT_STEAL_OURCOMMIT,
STATE_CLOSE_WAIT_STEAL_OURCOMMIT_WITH_HTLCS,
STATE_CLOSE_WAIT_THEIRCOMMIT_OURCOMMIT,
STATE_CLOSE_WAIT_THEIRCOMMIT_OURCOMMIT_WITH_HTLCS,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_OURCOMMIT,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_OURCOMMIT_WITH_HTLCS,
STATE_CLOSE_WAIT_CLOSE_OURCOMMIT,
STATE_UNUSED_CLOSE_WAIT_CLOSE_OURCOMMIT_WITH_HTLCS,
STATE_CLOSE_WAIT_STEAL_CLOSE_OURCOMMIT,
STATE_UNUSED_CLOSE_WAIT_STEAL_CLOSE_OURCOMMIT_WITH_HTLCS,
STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE_OURCOMMIT,
STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE_OURCOMMIT_WITH_HTLCS,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_OURCOMMIT,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_OURCOMMIT_WITH_HTLCS,
STATE_CLOSE_WAIT_SPENDOURS,
STATE_CLOSE_WAIT_SPENDOURS_WITH_HTLCS,
STATE_CLOSE_WAIT_STEAL_SPENDOURS,
STATE_CLOSE_WAIT_STEAL_SPENDOURS_WITH_HTLCS,
STATE_CLOSE_WAIT_THEIRCOMMIT_SPENDOURS,
STATE_CLOSE_WAIT_THEIRCOMMIT_SPENDOURS_WITH_HTLCS,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_SPENDOURS,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_SPENDOURS_WITH_HTLCS,
STATE_CLOSE_WAIT_CLOSE_SPENDOURS,
STATE_UNUSED_CLOSE_WAIT_CLOSE_SPENDOURS_WITH_HTLCS,
STATE_CLOSE_WAIT_STEAL_CLOSE_SPENDOURS,
STATE_UNUSED_CLOSE_WAIT_STEAL_CLOSE_SPENDOURS_WITH_HTLCS,
STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE_SPENDOURS,
STATE_CLOSE_WAIT_THEIRCOMMIT_CLOSE_SPENDOURS_WITH_HTLCS,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_SPENDOURS,
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_SPENDOURS_WITH_HTLCS,
/* Four states to represent closing onchain (for getpeers) */
STATE_CLOSE_ONCHAIN_CHEATED,
@ -160,12 +52,11 @@ enum state {
/*
* Where angels fear to tread.
*/
/* Bad packet from them / protocol breakdown. */
STATE_ERR_BREAKDOWN,
/* Their anchor didn't reach blockchain in reasonable time. */
STATE_ERR_ANCHOR_TIMEOUT,
/* Anchor was double-spent, after both considered it sufficient depth. */
STATE_ERR_ANCHOR_LOST,
/* A commitment tx we didn't recognise spent the anchor (impossible) */
STATE_ERR_INFORMATION_LEAK,
/* We ended up in an unexpected state. */
STATE_ERR_INTERNAL,
@ -213,37 +104,6 @@ enum state_input {
BITCOIN_ANCHOR_DEPTHOK,
/* It didn't reach the required depth in time. */
BITCOIN_ANCHOR_TIMEOUT,
/* It reached the required depth, then was forked off. */
BITCOIN_ANCHOR_UNSPENT,
/* Anchor was spent by our commit, and we can now spend it. */
BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED,
/* Anchor was spent by their commit tx. */
BITCOIN_ANCHOR_THEIRSPEND,
/* Anchor was spent by another commit tx (eg. expired). */
BITCOIN_ANCHOR_OTHERSPEND,
/* They spent an HTLC to them (revealing R value). */
BITCOIN_HTLC_TOTHEM_SPENT,
/* HTLC to them timed out, we can get funds now. */
BITCOIN_HTLC_TOTHEM_TIMEOUT,
/* HTLC to us timed out. */
BITCOIN_HTLC_TOUS_TIMEOUT,
/* Their commit tx is completely buried. */
BITCOIN_THEIRCOMMIT_DONE,
/* Our spend of our own tx is completely buried. */
BITCOIN_SPEND_OURS_DONE,
/* Our spend of their revoked tx is completely buried. */
BITCOIN_STEAL_DONE,
/* Bitcoin close transaction considered completely buried. */
BITCOIN_CLOSE_DONE,
/* Our HTLC spend is completely buried. */
BITCOIN_HTLC_FULFILL_SPEND_DONE,
/* Our HTLC refund spend has is completely buried. */
BITCOIN_HTLC_RETURN_SPEND_DONE,
/* We are not watching any HTLCs any more. */
INPUT_NO_MORE_HTLCS,
/* No more HTLCs in either commitment tx. */
INPUT_HTLCS_CLEARED,
@ -252,14 +112,6 @@ enum state_input {
*/
INPUT_CLOSE_COMPLETE_TIMEOUT,
/*
* Inject a known R value.
*
* In normal operation, use CMD_SEND_HTLC_FULFILL; this is for
* after a unilateral close.
*/
INPUT_RVALUE,
/* Commands */
CMD_OPEN_WITH_ANCHOR,
CMD_OPEN_WITHOUT_ANCHOR,
@ -269,9 +121,6 @@ enum state_input {
CMD_SEND_COMMIT,
CMD_CLOSE,
/* Connection lost/timedout with other node. */
INPUT_CONNECTION_LOST,
INPUT_MAX
};

Loading…
Cancel
Save