diff --git a/Makefile b/Makefile index 1bcf91dfc..7257f3014 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,7 @@ CCAN_OBJS := \ ccan-isaac.o \ ccan-isaac64.o \ ccan-list.o \ + ccan-mem.o \ ccan-noerr.o \ ccan-opt-helpers.o \ ccan-opt-parse.o \ @@ -378,3 +379,5 @@ ccan-io-poll.o: $(CCANDIR)/ccan/io/poll.c $(CC) $(CFLAGS) -c -o $@ $< ccan-pipecmd.o: $(CCANDIR)/ccan/pipecmd/pipecmd.c $(CC) $(CFLAGS) -c -o $@ $< +ccan-mem.o: $(CCANDIR)/ccan/mem/mem.c + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/daemon/peer.c b/daemon/peer.c index fb4eb5611..cc09330a6 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -285,9 +286,12 @@ static struct io_plan *pkt_out(struct io_conn *conn, struct peer *peer) struct out_pkt out; size_t n = tal_count(peer->outpkt); + if (peer->fake_close) + return io_out_wait(conn, peer, pkt_out, peer); + if (n == 0) { /* We close the connection once we've sent everything. */ - if (!peer->fake_close && peer->cond == PEER_CLOSED) + if (peer->cond == PEER_CLOSED) return io_close(conn); return io_out_wait(conn, peer, pkt_out, peer); } @@ -354,6 +358,21 @@ 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"); @@ -378,7 +397,7 @@ static void peer_disconnect(struct io_conn *conn, struct peer *peer) if (peer->cond == PEER_CLOSED) return; - state_single(peer, INPUT_CONNECTION_LOST, NULL); + peer_breakdown(peer); } static struct peer *new_peer(struct lightningd_state *dstate, @@ -416,6 +435,9 @@ static struct peer *new_peer(struct lightningd_state *dstate, peer->closing.our_script = NULL; peer->closing.their_script = NULL; peer->cleared = INPUT_NONE; + peer->closing_onchain.tx = NULL; + peer->closing_onchain.resolved = NULL; + peer->closing_onchain.ci = NULL; /* Make it different from other node (to catch bugs!), but a * round number for simple eyeballing. */ peer->htlc_id_counter = pseudorand(1ULL << 32) * 1000; @@ -735,15 +757,6 @@ static bool is_mutual_close(const struct peer *peer, return false; } -static void close_depth_cb(struct peer *peer, unsigned int depth, - const struct sha256_double *txid, - void *unused) -{ - if (depth >= peer->dstate->config.forever_confirms) { - state_event(peer, BITCOIN_CLOSE_DONE, NULL); - } -} - static struct channel_htlc *htlc_by_index(const struct commit_info *ci, size_t index) { @@ -771,7 +784,7 @@ static UNNEEDED bool htlc_a_offered(struct commit_info *ci, size_t index) } /* Create a HTLC refund collection */ -static UNNEEDED const struct bitcoin_tx *htlc_timeout_tx(const struct peer *peer, +static const struct bitcoin_tx *htlc_timeout_tx(const struct peer *peer, const struct commit_info *ci, unsigned int i) { @@ -834,6 +847,444 @@ static UNNEEDED const struct bitcoin_tx *htlc_timeout_tx(const struct peer *peer return tx; } +static void reset_onchain_closing(struct peer *peer) +{ + if (peer->closing_onchain.tx) { + /* FIXME: Log old txid */ + log_unusual(peer->log, "New anchor spend, forgetting old"); + peer->closing_onchain.tx = tal_free(peer->closing_onchain.tx); + peer->closing_onchain.resolved = NULL; + peer->closing_onchain.ci = NULL; + } +} + +static const struct bitcoin_tx *irrevocably_resolved(struct peer *peer) +{ + /* We can't all be irrevocably resolved until the commit tx is, + * so just mark that as resolving us. */ + return peer->closing_onchain.tx; +} + +static void resolve_cheating(struct peer *peer) +{ + FIXME_STUB(peer); +} + +static void our_htlc_spent(struct peer *peer, + const struct bitcoin_tx *tx, + size_t input_num, + ptrint_t *pi) +{ + struct channel_htlc *h; + struct sha256 preimage, sha; + size_t i = ptr2int(pi); + + /* It should be spending the HTLC we expect. */ + assert(peer->closing_onchain.ci->map[i] == tx->input[input_num].index); + + /* BOLT #onchain: + * + * If a node sees a redemption transaction...the node MUST extract the + * preimage from the transaction input witness. This is either to + * prove payment (if this node originated the payment), or to redeem + * the corresponding incoming HTLC from another peer. + */ + + /* This is the form of all HTLC spends. */ + if (!tx->input[input_num].witness + || tal_count(tx->input[input_num].witness) != 3 + || tal_count(tx->input[input_num].witness[1]) != sizeof(preimage)) + fatal("Impossible HTLC spend for %zu", i); + + /* Our timeout tx has all-zeroes, so we can distinguish it. */ + if (memeqzero(tx->input[input_num].witness[1], sizeof(preimage))) + return; + + memcpy(&preimage, tx->input[input_num].witness[1], sizeof(preimage)); + sha256(&sha, &preimage, sizeof(preimage)); + + h = htlc_by_index(peer->closing_onchain.ci, i); + + /* FIXME: This could happen with a ripemd collision, since + * script.c only checks that ripemd matches... */ + if (!structeq(&sha, &h->rhash)) + fatal("HTLC redeemed with incorrect r value?"); + + log_unusual(peer->log, "Peer redeemed HTLC %zu on-chain using r value", + i); + + /* BOLT #onchain: + * + * If a node sees a redemption transaction, the output is considered + * *irrevocably resolved*... Note that we don't care about the fate of + * the redemption transaction itself once we've extracted the + * preimage; the knowledge is not revocable. + */ + peer->closing_onchain.resolved[i] = irrevocably_resolved(peer); +} + +static void our_htlc_depth(struct peer *peer, + unsigned int depth, + const struct sha256_double *txid, + bool our_commit, + size_t i) +{ + u32 mediantime; + struct channel_htlc *h; + + /* Must be in a block. */ + if (depth == 0) + return; + + mediantime = get_tip_mediantime(peer->dstate); + h = htlc_by_index(peer->closing_onchain.ci, i); + + /* BOLT #onchain: + * + * If the *commitment tx* is the other node's, the output is + * considered *timed out* once the HTLC is expired. If the + * *commitment tx* is this node's, the output is considered *timed + * out* once the HTLC is expired, AND the output's + * `OP_CHECKSEQUENCEVERIFY` delay has passed. + */ + + /* FIXME: Handle expiry in blocks. */ + if (mediantime < abs_locktime_to_seconds(&h->expiry)) + return; + + if (our_commit) { + u32 csv_timeout; + + /* FIXME: Handle CSV in blocks. */ + csv_timeout = get_tx_mediantime(peer->dstate, txid) + + rel_locktime_to_seconds(&peer->them.locktime); + + if (mediantime <= csv_timeout) + return; + } + + /* BOLT #onchain: + * + * If the output has *timed out* and not been *resolved*, the node + * MUST *resolve* the output by spending it. + */ + if (!peer->closing_onchain.resolved[i]) { + peer->closing_onchain.resolved[i] + = htlc_timeout_tx(peer, peer->closing_onchain.ci, i); + broadcast_tx(peer, peer->closing_onchain.resolved[i]); + } +} + +static void our_htlc_depth_ourcommit(struct peer *peer, + unsigned int depth, + const struct sha256_double *txid, + ptrint_t *i) +{ + our_htlc_depth(peer, depth, txid, true, ptr2int(i)); +} + +static void our_htlc_depth_theircommit(struct peer *peer, + unsigned int depth, + const struct sha256_double *txid, + ptrint_t *i) +{ + our_htlc_depth(peer, depth, txid, false, ptr2int(i)); +} + +static void resolve_our_htlcs(struct peer *peer, + const struct commit_info *ci, + const struct bitcoin_tx *tx, + const struct bitcoin_tx **resolved, + bool from_ourcommit, + size_t start, size_t num) +{ + size_t i; + struct sha256_double txid; + + bitcoin_txid(tx, &txid); + for (i = start; i < start + num; i++) { + /* Doesn't exist? Resolved by tx itself. */ + if (ci->map[i] == -1) { + resolved[i] = tx; + continue; + } + + /* BOLT #onchain: + * + * A node MUST watch for spends of *commitment tx* outputs for + * HTLCs it offered; each one must be *resolved* by a timeout + * transaction (the node pays back to itself) or redemption + * transaction (the other node provides the redemption + * preimage). + */ + watch_txo(tx, peer, &txid, ci->map[i], our_htlc_spent, + int2ptr(i)); + watch_txid(tx, peer, &txid, + from_ourcommit + ? our_htlc_depth_ourcommit + : our_htlc_depth_theircommit, + int2ptr(i)); + } +} + +/* BOLT #onchain: + * + * If the node receives a redemption preimage for a *commitment tx* output it + * was offered, it MUST *resolve* the output by spending it using the + * preimage. Otherwise, the other node could spend it once it as *timed out* + * as above. + */ +bool resolve_one_htlc(struct peer *peer, u64 id, const struct sha256 *preimage) +{ + FIXME_STUB(peer); +} + +static void their_htlc_depth(struct peer *peer, + unsigned int depth, + const struct sha256_double *txid, + ptrint_t *pi) +{ + u32 mediantime; + struct channel_htlc *h; + size_t i = ptr2int(pi); + + /* Must be in a block. */ + if (depth == 0) + return; + + mediantime = get_tip_mediantime(peer->dstate); + h = htlc_by_index(peer->closing_onchain.ci, i); + + /* BOLT #onchain: + * + * Otherwise, if the output HTLC has expired, it is considered + * *irrevocably resolved*. + */ + + /* FIXME: Handle expiry in blocks. */ + if (mediantime < abs_locktime_to_seconds(&h->expiry)) + return; + + peer->closing_onchain.resolved[i] = irrevocably_resolved(peer); +} + +static void resolve_their_htlcs(struct peer *peer, + const struct commit_info *ci, + const struct bitcoin_tx *tx, + const struct bitcoin_tx **resolved, + size_t start, size_t num) +{ + size_t i; + + for (i = start; i < start + num; i++) { + /* Doesn't exist? Resolved by tx itself. */ + if (ci->map[i] == -1) { + resolved[i] = tx; + continue; + } + + watch_tx(tx, peer, tx, their_htlc_depth, int2ptr(i)); + } +} + +static void our_main_output_depth(struct peer *peer, + unsigned int depth, + const struct sha256_double *txid, + void *unused) +{ + u32 mediantime, csv_timeout; + + /* Not in block any more? */ + if (depth == 0) + return; + + mediantime = get_tip_mediantime(peer->dstate); + + /* FIXME: Handle CSV in blocks. */ + csv_timeout = get_tx_mediantime(peer->dstate, txid) + + rel_locktime_to_seconds(&peer->them.locktime); + + if (mediantime <= csv_timeout) + return; + + /* Already done? (FIXME: Delete after first time) */ + if (peer->closing_onchain.resolved[0]) + return; + + /* BOLT #onchain: + * + * 1. _A's main output_: A node SHOULD spend this output to a + * convenient address. This avoids having to remember the + * complicated witness script associated with that particular + * channel for later spending. ... If the output is spent (as + * recommended), the output is *resolved* by the spending + * transaction + */ + peer->closing_onchain.resolved[0] = bitcoin_spend_ours(peer); + broadcast_tx(peer, peer->closing_onchain.resolved[0]); +} + +/* BOLT #onchain: + * + * When node A sees its own *commitment tx*: + */ +static void resolve_our_unilateral(struct peer *peer) +{ + const struct bitcoin_tx *tx = peer->closing_onchain.tx; + const struct commit_info *ci = peer->closing_onchain.ci; + size_t num_ours, num_theirs; + + peer->closing_onchain.resolved + = tal_arrz(tx, const struct bitcoin_tx *, tal_count(ci->map)); + + /* BOLT #onchain: + * + * 1. _A's main output_: A node SHOULD spend this output to a + * convenient address. ... A node MUST wait until the + * `OP_CHECKSEQUENCEVERIFY` delay has passed (as specified by the + * other node's `open_channel` `delay` field) before spending the + * output. + */ + watch_tx(tx, peer, tx, our_main_output_depth, NULL); + + /* BOLT #onchain: + * + * 2. _B's main output_: No action required, this output is considered + * *resolved* by the *commitment tx*. + */ + peer->closing_onchain.resolved[1] = tx; + + num_ours = tal_count(ci->cstate->a.htlcs); + num_theirs = tal_count(ci->cstate->b.htlcs); + + /* BOLT #onchain: + * + * 3. _A's offered HTLCs_: See On-chain HTLC Handling: Our Offers below. + */ + resolve_our_htlcs(peer, ci, tx, + peer->closing_onchain.resolved, + true, 2, num_ours); + + /* BOLT #onchain: + * + * 4. _B's offered HTLCs_: See On-chain HTLC Handling: Their + * Offers below. + */ + resolve_their_htlcs(peer, ci, tx, + peer->closing_onchain.resolved, + 2 + num_ours, num_theirs); +} + +/* BOLT #onchain: + * + * Similarly, when node A sees a *commitment tx* from B: + */ +static void resolve_their_unilateral(struct peer *peer) +{ + const struct bitcoin_tx *tx = peer->closing_onchain.tx; + const struct commit_info *ci = peer->closing_onchain.ci; + size_t num_ours, num_theirs; + + peer->closing_onchain.resolved + = tal_arrz(tx, const struct bitcoin_tx *, tal_count(ci->map)); + + /* BOLT #onchain: + * + * 1. _A's main output_: No action is required; this is a + * simple P2WPKH output. This output is considered + * *resolved* by the *commitment tx*. + */ + peer->closing_onchain.resolved[1] = tx; + + /* BOLT #onchain: + * + * 2. _B's main output_: No action required, this output is + * considered *resolved* by the *commitment tx*. + */ + peer->closing_onchain.resolved[0] = tx; + + /* Note the reversal, since ci is theirs, we are B */ + num_ours = tal_count(ci->cstate->b.htlcs); + num_theirs = tal_count(ci->cstate->a.htlcs); + + /* BOLT #onchain: + * + * 3. _A's offered HTLCs_: See On-chain HTLC Handling: Our Offers below. + */ + resolve_our_htlcs(peer, ci, tx, + peer->closing_onchain.resolved, + false, 2 + num_theirs, num_ours); + + /* BOLT #onchain: + * + * 4. _B's offered HTLCs_: See On-chain HTLC Handling: Their + * Offers below. + */ + resolve_their_htlcs(peer, ci, tx, + peer->closing_onchain.resolved, + 2, num_theirs); +} + +static void resolve_mutual_close(struct peer *peer) +{ + const struct bitcoin_tx *tx = peer->closing_onchain.tx; + + /* BOLT #onchain: + * + * A node doesn't need to do anything else as it has already agreed to + * the output, which is sent to its specified scriptpubkey (see BOLT + * #2 "4.1: Closing initiation: close_clearing"). + */ + peer->closing_onchain.resolved + = tal_arr(tx, const struct bitcoin_tx *, 0); +} + +/* Called every time the tx spending the funding tx changes depth. */ +static void check_for_resolution(struct peer *peer, + unsigned int depth, + const struct sha256_double *txid, + void *unused) +{ + size_t i, n = tal_count(peer->closing_onchain.resolved); + size_t forever = peer->dstate->config.forever_confirms; + + /* BOLT #onchain: + * + * A node MUST *resolve* all outputs as specified below, and MUST be + * prepared to resolve them multiple times in case of blockchain + * reorganizations. + */ + for (i = 0; i < n; i++) + if (!peer->closing_onchain.resolved[i]) + return; + + /* BOLT #onchain: + * + * Outputs which are *resolved* by a transaction are considered + * *irrevocably resolved* once they are included in a block at least + * 100 deep on the most-work blockchain. + */ + if (depth < forever) + return; + + for (i = 0; i < n; i++) { + struct sha256_double txid; + + bitcoin_txid(peer->closing_onchain.resolved[i], &txid); + if (get_tx_depth(peer->dstate, &txid) < forever) + return; + } + + /* BOLT #onchain: + * + * A node MUST monitor the blockchain for transactions which spend any + * output which is not *irrevocably resolved* until all outputs are + * *irrevocably resolved*. + */ + peer->state = STATE_CLOSED; + io_break(peer); +} + /* We assume the tx is valid! Don't do a blockchain.info and feed this * invalid transactions! */ static void anchor_spent(struct peer *peer, @@ -841,32 +1292,63 @@ static void anchor_spent(struct peer *peer, size_t input_num, void *unused) { - struct anchor_watch *w = peer->anchor.watches; - union input idata; struct sha256_double txid; - + assert(input_num < tx->input_count); /* We only ever sign single-input txs. */ if (input_num != 0) fatal("Anchor spend by non-single input tx"); - + + /* BOLT #onchain: + * + * A node SHOULD fail the connection if it is not already + * closed when it sees the funding transaction spent. + */ + if (peer->cond != PEER_CLOSED) { + peer->cond = PEER_CLOSED; + + /* BOLT #onchain: + * + * A node MAY send a descriptive error packet in this case. + */ + queue_pkt_err(peer, + pkt_err(peer, "Funding transaction spent!")); + } + + /* We may have been following a different spend. Forget it. */ + reset_onchain_closing(peer); + + peer->closing_onchain.tx = tal_steal(peer, tx); bitcoin_txid(tx, &txid); - idata.ci = find_commit(peer->them.commit, &txid); - if (idata.ci) { - if (idata.ci->revocation_preimage) - state_event(peer, w->otherspent, &idata); - else { - idata.tx = idata.ci->tx; - state_event(peer, w->theyspent, &idata); + peer->closing_onchain.ci = find_commit(peer->them.commit, &txid); + if (peer->closing_onchain.ci) { + if (peer->closing_onchain.ci->revocation_preimage) { + peer->state = STATE_CLOSE_ONCHAIN_CHEATED; + resolve_cheating(peer); + } else { + peer->state = STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL; + resolve_their_unilateral(peer); } + } else if (txidmatch(peer->us.commit->tx, &txid)) { + peer->state = STATE_CLOSE_ONCHAIN_OUR_UNILATERAL; + peer->closing_onchain.ci = peer->us.commit; + resolve_our_unilateral(peer); } else if (is_mutual_close(peer, tx)) { - watch_tx(peer, peer, tx, close_depth_cb, NULL); - } else { - if (!txidmatch(peer->us.commit->tx, &txid)) - fatal("Unknown tx spend!"); - } + peer->state = STATE_CLOSE_ONCHAIN_MUTUAL; + resolve_mutual_close(peer); + } else + /* FIXME: Log harder! */ + fatal("Unknown tx spend!"); + + assert(peer->closing_onchain.resolved != NULL); + watch_tx(tx, peer, tx, check_for_resolution, NULL); + + /* 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) @@ -1491,6 +1973,8 @@ static void json_getpeers(struct command *cmd, json_add_hex(response, "peerid", p->id.der, sizeof(p->id.der)); + json_add_bool(response, "connected", p->conn && !p->fake_close); + /* FIXME: Report anchor. */ if (!p->us.commit) { @@ -1993,7 +2477,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; - state_single(peer, INPUT_CONNECTION_LOST, NULL); + peer_breakdown(peer); command_success(cmd, null_response(cmd)); } diff --git a/daemon/peer.h b/daemon/peer.h index 921ff9784..99bc86a57 100644 --- a/daemon/peer.h +++ b/daemon/peer.h @@ -174,7 +174,8 @@ struct peer { /* Counter to make unique HTLC ids. */ u64 htlc_id_counter; - + + /* Mutual close info. */ struct { /* Our last suggested closing fee. */ u64 our_fee; @@ -186,6 +187,14 @@ struct peer { u8 *our_script, *their_script; } closing; + /* If we're closing on-chain */ + struct { + /* Everything (watches, resolved[], etc) tal'ed off this */ + const struct bitcoin_tx *tx; + const struct commit_info *ci; + const struct bitcoin_tx **resolved; + } closing_onchain; + /* If not INPUT_NONE, send this when we have no more HTLCs. */ enum state_input cleared; @@ -230,4 +239,5 @@ struct bitcoin_tx *peer_create_close_tx(struct peer *peer, u64 fee); uint64_t commit_tx_fee(const struct bitcoin_tx *commit, uint64_t anchor_satoshis); +bool resolve_one_htlc(struct peer *peer, u64 id, const struct sha256 *preimage); #endif /* LIGHTNING_DAEMON_PEER_H */ diff --git a/daemon/test/test.sh b/daemon/test/test.sh index d73245c92..d24f8ba05 100755 --- a/daemon/test/test.sh +++ b/daemon/test/test.sh @@ -149,6 +149,16 @@ check_peerstate() fi } +check_peerconnected() +{ + if $1 getpeers | $FGREP -w '"connected" : '$2; then : + else + echo "$1" not connected "$2": >&2 + $1 getpeers >&2 + exit 1 + fi +} + check_no_peers() { if $1 getpeers | tr -s '\012\011 ' ' ' | $FGREP '"peers" : [ ]'; then : @@ -258,13 +268,20 @@ if [ -n "$TIMEOUT_ANCHOR" ]; then sleep 2 # It should send out commit tx. - check_peerstate lcli1 STATE_CLOSE_WAIT_OURCOMMIT + check_peerconnected lcli1 false # Generate a block (should include commit tx) check_tx_spend - + + # Should be handling it now. + TIME=$(($TIME + 1)) + lcli1 dev-mocktime $TIME + sleep 1 + + check_peerstate lcli1 STATE_CLOSE_ONCHAIN_OUR_UNILATERAL + # Now "wait" for 1 day, which is what node2 asked for on commit. - TIME=$(($TIME + 24 * 60 * 60)) + TIME=$(($TIME + 24 * 60 * 60 - 1)) lcli1 dev-mocktime $TIME # Move bitcoind median time as well, so CSV moves. @@ -281,7 +298,7 @@ if [ -n "$TIMEOUT_ANCHOR" ]; then lcli1 dev-mocktime $TIME sleep 2 - check_peerstate lcli1 STATE_CLOSE_WAIT_SPENDOURS + check_peerstate lcli1 STATE_CLOSE_ONCHAIN_OUR_UNILATERAL # Now it should have spent the commit tx. check_tx_spend @@ -413,19 +430,27 @@ sleep 1 check_peerstate lcli1 STATE_CLOSE_WAIT_CLOSE check_peerstate lcli2 STATE_CLOSE_WAIT_CLOSE -# Give it 99 blocks. -$CLI generate 99 - +$CLI generate 1 # Make sure they saw it! lcli1 dev-mocktime $(($EXPIRY + 32)) lcli2 dev-mocktime $(($EXPIRY + 32)) +sleep 1 +check_peerstate lcli1 STATE_CLOSE_ONCHAIN_MUTUAL +check_peerstate lcli2 STATE_CLOSE_ONCHAIN_MUTUAL + +# Give it 99 blocks. +$CLI generate 98 + +# Make sure they saw it! +lcli1 dev-mocktime $(($EXPIRY + 33)) +lcli2 dev-mocktime $(($EXPIRY + 33)) sleep 5 -check_peerstate lcli1 STATE_CLOSE_WAIT_CLOSE -check_peerstate lcli2 STATE_CLOSE_WAIT_CLOSE +check_peerstate lcli1 STATE_CLOSE_ONCHAIN_MUTUAL +check_peerstate lcli2 STATE_CLOSE_ONCHAIN_MUTUAL # Now the final one. $CLI generate 1 -TIME=$(($EXPIRY + 33)) +TIME=$(($EXPIRY + 34)) lcli1 dev-mocktime $TIME lcli2 dev-mocktime $TIME sleep 2 diff --git a/state.c b/state.c index 5999cbfae..b82ddef4c 100644 --- a/state.c +++ b/state.c @@ -785,6 +785,10 @@ enum command_status state(struct peer *peer, 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: + case STATE_CLOSE_ONCHAIN_MUTUAL: return next_state(peer, cstatus, STATE_ERR_INTERNAL); } diff --git a/state_types.h b/state_types.h index 15230222a..6a3f04c9c 100644 --- a/state_types.h +++ b/state_types.h @@ -151,6 +151,12 @@ enum state { 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, + STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL, + STATE_CLOSE_ONCHAIN_OUR_UNILATERAL, + STATE_CLOSE_ONCHAIN_MUTUAL, + /* * Where angels fear to tread. */