Browse Source

daemon: remove closing states from state machine.

We already removed the on-chain states, now we remove the "clearing" state
(which wasn't fully implemented anyway).

This turns into two smaller state machines: one for clearing, which
still allows HTLCs to be failed and fulfilled, and one for mutual
close negotiation which only allows close_signature messages.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 9 years ago
parent
commit
5aed0e12f8
  1. 124
      daemon/packets.c
  2. 540
      daemon/peer.c
  3. 3
      daemon/peer.h
  4. 6
      daemon/test/test.sh
  5. 157
      state.c
  6. 21
      state.h
  7. 25
      state_types.h

124
daemon/packets.c

@ -70,6 +70,8 @@ static void queue_raw_pkt(struct peer *peer, Pkt *pkt)
tal_resize(&peer->outpkt, n+1); tal_resize(&peer->outpkt, n+1);
peer->outpkt[n] = pkt; peer->outpkt[n] = pkt;
log_debug(peer->log, "Queued pkt %s", pkt_name(pkt->pkt_case));
/* In case it was waiting for output. */ /* In case it was waiting for output. */
io_wake(peer); io_wake(peer);
} }
@ -202,17 +204,15 @@ void queue_pkt_htlc_add(struct peer *peer,
queue_pkt(peer, PKT__PKT_UPDATE_ADD_HTLC, u); queue_pkt(peer, PKT__PKT_UPDATE_ADD_HTLC, u);
} }
void queue_pkt_htlc_fulfill(struct peer *peer, void queue_pkt_htlc_fulfill(struct peer *peer, u64 id, const struct sha256 *r)
const struct htlc_progress *htlc_prog)
{ {
UpdateFulfillHtlc *f = tal(peer, UpdateFulfillHtlc); UpdateFulfillHtlc *f = tal(peer, UpdateFulfillHtlc);
size_t n; size_t n;
union htlc_staging stage;
update_fulfill_htlc__init(f); update_fulfill_htlc__init(f);
assert(htlc_prog->stage.type == HTLC_FULFILL); f->id = id;
f->r = sha256_to_proto(f, r);
f->id = htlc_prog->stage.fulfill.id;
f->r = sha256_to_proto(f, &htlc_prog->stage.fulfill.r);
/* BOLT #2: /* BOLT #2:
* *
@ -222,23 +222,26 @@ void queue_pkt_htlc_fulfill(struct peer *peer,
n = funding_htlc_by_id(peer->remote.staging_cstate, f->id, THEIRS); n = funding_htlc_by_id(peer->remote.staging_cstate, f->id, THEIRS);
assert(n != -1); assert(n != -1);
funding_fulfill_htlc(peer->remote.staging_cstate, n, THEIRS); funding_fulfill_htlc(peer->remote.staging_cstate, n, THEIRS);
add_unacked(&peer->remote, &htlc_prog->stage);
stage.fulfill.fulfill = HTLC_FULFILL;
stage.fulfill.id = f->id;
stage.fulfill.r = *r;
add_unacked(&peer->remote, &stage);
remote_changes_pending(peer); remote_changes_pending(peer);
queue_pkt(peer, PKT__PKT_UPDATE_FULFILL_HTLC, f); queue_pkt(peer, PKT__PKT_UPDATE_FULFILL_HTLC, f);
} }
void queue_pkt_htlc_fail(struct peer *peer, void queue_pkt_htlc_fail(struct peer *peer, u64 id)
const struct htlc_progress *htlc_prog)
{ {
UpdateFailHtlc *f = tal(peer, UpdateFailHtlc); UpdateFailHtlc *f = tal(peer, UpdateFailHtlc);
size_t n; size_t n;
union htlc_staging stage;
update_fail_htlc__init(f); update_fail_htlc__init(f);
assert(htlc_prog->stage.type == HTLC_FAIL); f->id = id;
f->id = htlc_prog->stage.fail.id;
/* FIXME: reason! */ /* FIXME: reason! */
f->reason = tal(f, FailReason); f->reason = tal(f, FailReason);
fail_reason__init(f->reason); fail_reason__init(f->reason);
@ -251,7 +254,10 @@ void queue_pkt_htlc_fail(struct peer *peer,
n = funding_htlc_by_id(peer->remote.staging_cstate, f->id, THEIRS); n = funding_htlc_by_id(peer->remote.staging_cstate, f->id, THEIRS);
assert(n != -1); assert(n != -1);
funding_fail_htlc(peer->remote.staging_cstate, n, THEIRS); funding_fail_htlc(peer->remote.staging_cstate, n, THEIRS);
add_unacked(&peer->remote, &htlc_prog->stage);
stage.fail.fail = HTLC_FAIL;
stage.fail.id = f->id;
add_unacked(&peer->remote, &stage);
remote_changes_pending(peer); remote_changes_pending(peer);
queue_pkt(peer, PKT__PKT_UPDATE_FAIL_HTLC, f); queue_pkt(peer, PKT__PKT_UPDATE_FAIL_HTLC, f);
@ -306,8 +312,6 @@ void queue_pkt_commit(struct peer *peer)
/* Switch to the new commitment. */ /* Switch to the new commitment. */
peer->remote.commit = ci; peer->remote.commit = ci;
peer_check_if_cleared(peer);
/* Now send message */ /* Now send message */
update_commit__init(u); update_commit__init(u);
u->sig = signature_to_proto(u, &ci->sig->sig); u->sig = signature_to_proto(u, &ci->sig->sig);
@ -381,7 +385,7 @@ void queue_pkt_revocation(struct peer *peer)
= tal(peer->local.commit->prev, struct sha256); = tal(peer->local.commit->prev, struct sha256);
peer_get_revocation_preimage(peer, peer->local.commit->prev->commit_num, peer_get_revocation_preimage(peer, peer->local.commit->prev->commit_num,
peer->local.commit->prev->revocation_preimage); peer->local.commit->prev->revocation_preimage);
peer_check_if_cleared(peer);
u->revocation_preimage u->revocation_preimage
= sha256_to_proto(u, peer->local.commit->prev->revocation_preimage); = sha256_to_proto(u, peer->local.commit->prev->revocation_preimage);
@ -783,7 +787,6 @@ Pkt *accept_pkt_commit(struct peer *peer, const Pkt *pkt)
peer_get_revocation_hash(peer, ci->commit_num + 1, peer_get_revocation_hash(peer, ci->commit_num + 1,
&peer->local.next_revocation_hash); &peer->local.next_revocation_hash);
peer_check_if_cleared(peer);
return NULL; return NULL;
} }
@ -818,7 +821,6 @@ Pkt *accept_pkt_revocation(struct peer *peer, const Pkt *pkt)
proto_to_sha256(r->revocation_preimage, proto_to_sha256(r->revocation_preimage,
peer->remote.commit->prev->revocation_preimage); peer->remote.commit->prev->revocation_preimage);
peer_check_if_cleared(peer);
/* Save next revocation hash. */ /* Save next revocation hash. */
proto_to_sha256(r->next_revocation_hash, proto_to_sha256(r->next_revocation_hash,
@ -851,91 +853,3 @@ Pkt *accept_pkt_close_clearing(struct peer *peer, const Pkt *pkt)
return NULL; return NULL;
} }
Pkt *accept_pkt_close_sig(struct peer *peer, const Pkt *pkt, bool *acked,
bool *we_agree)
{
const CloseSignature *c = pkt->close_signature;
struct bitcoin_tx *close_tx;
struct bitcoin_signature theirsig;
log_info(peer->log, "accept_pkt_close_sig: they offered close fee %"
PRIu64, c->close_fee);
*acked = *we_agree = false;
/* BOLT #2:
*
* The sender MUST set `close_fee` lower than or equal to the fee of the
* final commitment transaction, and MUST set `close_fee` to an even
* number of satoshis.
*/
if ((c->close_fee & 1)
|| c->close_fee > commit_tx_fee(peer->remote.commit->tx,
peer->anchor.satoshis)) {
return pkt_err(peer, "Invalid close fee");
}
/* FIXME: Don't accept tiny fee at all? */
/* BOLT #2:
... otherwise it SHOULD propose a
value strictly between the received `close_fee` and its
previously-sent `close_fee`.
*/
if (peer->closing.their_sig) {
/* We want more, they should give more. */
if (peer->closing.our_fee > peer->closing.their_fee) {
if (c->close_fee <= peer->closing.their_fee)
return pkt_err(peer, "Didn't increase close fee");
} else {
if (c->close_fee >= peer->closing.their_fee)
return pkt_err(peer, "Didn't decrease close fee");
}
}
/* BOLT #2:
*
* The receiver MUST check `sig` is valid for the close
* transaction with the given `close_fee`, and MUST fail the
* connection if it is not. */
theirsig.stype = SIGHASH_ALL;
if (!proto_to_signature(c->sig, &theirsig.sig))
return pkt_err(peer, "Invalid signature format");
close_tx = peer_create_close_tx(peer, c->close_fee);
if (!check_tx_sig(peer->dstate->secpctx, close_tx, 0,
NULL, 0,
peer->anchor.witnessscript,
&peer->remote.commitkey, &theirsig))
return pkt_err(peer, "Invalid signature");
tal_free(peer->closing.their_sig);
peer->closing.their_sig = tal_dup(peer,
struct bitcoin_signature, &theirsig);
peer->closing.their_fee = c->close_fee;
if (peer->closing.our_fee == peer->closing.their_fee) {
log_info(peer->log, "accept_pkt_close_sig: That's an ack");
*acked = true;
} else {
/* Adjust our fee to close on their fee. */
u64 sum;
/* Beware overflow! */
sum = (u64)peer->closing.our_fee + peer->closing.their_fee;
peer->closing.our_fee = sum / 2;
if (peer->closing.our_fee & 1)
peer->closing.our_fee++;
log_info(peer->log, "accept_pkt_close_sig: we change to %"PRIu64,
peer->closing.our_fee);
/* Corner case: we may now agree with them. */
if (peer->closing.our_fee == peer->closing.their_fee)
*we_agree = true;
}
/* FIXME: Dynamic fee! */
return NULL;
}

540
daemon/peer.c

@ -12,6 +12,7 @@
#include "names.h" #include "names.h"
#include "peer.h" #include "peer.h"
#include "permute_tx.h" #include "permute_tx.h"
#include "protobuf_convert.h"
#include "pseudorand.h" #include "pseudorand.h"
#include "secrets.h" #include "secrets.h"
#include "state.h" #include "state.h"
@ -88,22 +89,25 @@ static struct json_result *null_response(const tal_t *ctx)
json_object_end(response); json_object_end(response);
return response; return response;
} }
static void peer_cmd_complete(struct peer *peer, enum command_status status)
{
assert(peer->curr_cmd.cmd != INPUT_NONE);
/* If it's a json command, complete that now. */ static void complete_json_command(struct command *jsoncmd,
if (peer->curr_cmd.jsoncmd) { enum command_status status)
{
if (jsoncmd) {
if (status == CMD_FAIL) if (status == CMD_FAIL)
/* FIXME: y'know, details. */ /* FIXME: y'know, details. */
command_fail(peer->curr_cmd.jsoncmd, "Failed"); command_fail(jsoncmd, "Failed");
else { else {
assert(status == CMD_SUCCESS); assert(status == CMD_SUCCESS);
command_success(peer->curr_cmd.jsoncmd, command_success(jsoncmd, null_response(jsoncmd));
null_response(peer->curr_cmd.jsoncmd));
} }
} }
}
static void peer_cmd_complete(struct peer *peer, enum command_status status)
{
complete_json_command(peer->curr_cmd.jsoncmd, status);
peer->curr_cmd.jsoncmd = NULL;
peer->curr_cmd.cmd = INPUT_NONE; peer->curr_cmd.cmd = INPUT_NONE;
} }
@ -128,6 +132,86 @@ void set_peer_state(struct peer *peer, enum state newstate, const char *caller)
peer->state = newstate; peer->state = newstate;
} }
static void command_send_commit(struct peer *peer, struct command *jsoncmd)
{
assert(peer->curr_cmd.cmd == INPUT_NONE);
/* Commands should still be blocked during this! */
assert(peer->state != STATE_CLEARING_COMMITTING);
if (peer->state == STATE_CLEARING) {
peer->cond = PEER_BUSY;
peer->curr_cmd.jsoncmd = jsoncmd;
queue_pkt_commit(peer);
set_peer_state(peer, STATE_CLEARING_COMMITTING, __func__);
} else {
/* You can send commands if closing; peer->cond == CLOSING */
assert(!state_is_closing(peer->state));
set_current_command(peer, CMD_SEND_COMMIT, NULL, jsoncmd);
}
}
static void set_htlc_command(struct peer *peer,
struct command *jsoncmd,
enum state_input cmd,
const union htlc_staging *stage)
{
/* FIXME: memleak! */
/* FIXME: Get rid of struct htlc_progress */
struct htlc_progress *progress = tal(peer, struct htlc_progress);
progress->stage = *stage;
set_current_command(peer, cmd, progress, jsoncmd);
}
static void command_htlc_fail(struct peer *peer, u64 id, struct command *jsoncmd)
{
assert(peer->curr_cmd.cmd == INPUT_NONE);
/* Commands should still be blocked during this! */
assert(peer->state != STATE_CLEARING_COMMITTING);
if (peer->state == STATE_CLEARING) {
queue_pkt_htlc_fail(peer, id);
complete_json_command(jsoncmd, CMD_SUCCESS);
} else {
union htlc_staging stage;
/* You can't send commands if closing; peer->cond == CLOSING */
assert(!state_is_closing(peer->state));
stage.fail.fail = HTLC_FAIL;
stage.fail.id = id;
set_htlc_command(peer, jsoncmd, CMD_SEND_HTLC_FAIL, &stage);
}
}
static void command_htlc_fulfill(struct peer *peer,
u64 id,
const struct sha256 *r,
struct command *jsoncmd)
{
assert(peer->curr_cmd.cmd == INPUT_NONE);
/* Commands should still be blocked during this! */
assert(peer->state != STATE_CLEARING_COMMITTING);
if (peer->state == STATE_CLEARING) {
queue_pkt_htlc_fulfill(peer, id, r);
complete_json_command(jsoncmd, CMD_SUCCESS);
} else {
union htlc_staging stage;
/* You can't send commands if closing; peer->cond == CLOSING */
assert(!state_is_closing(peer->state));
stage.fulfill.fulfill = HTLC_FULFILL;
stage.fulfill.r = *r;
stage.fulfill.id = id;
set_htlc_command(peer, jsoncmd, CMD_SEND_HTLC_FULFILL, &stage);
}
}
static void peer_breakdown(struct peer *peer) static void peer_breakdown(struct peer *peer)
{ {
peer->cond = PEER_CLOSED; peer->cond = PEER_CLOSED;
@ -158,6 +242,296 @@ static bool peer_uncommitted_changes(const struct peer *peer)
!= peer->remote.commit->cstate->changes; != peer->remote.commit->cstate->changes;
} }
/* All unrevoked commit txs must have no HTLCs in them. */
static bool committed_to_htlcs(const struct peer *peer)
{
const struct commit_info *i;
/* Before anchor exchange, we don't even have cstate. */
if (!peer->local.commit || !peer->local.commit->cstate)
return false;
i = peer->local.commit;
while (i && !i->revocation_preimage) {
if (tal_count(i->cstate->side[OURS].htlcs))
return true;
if (tal_count(i->cstate->side[THEIRS].htlcs))
return true;
i = i->prev;
}
i = peer->remote.commit;
while (i && !i->revocation_preimage) {
if (tal_count(i->cstate->side[OURS].htlcs))
return true;
if (tal_count(i->cstate->side[THEIRS].htlcs))
return true;
i = i->prev;
}
return false;
}
static struct io_plan *peer_close(struct io_conn *conn, struct peer *peer)
{
/* Tell writer to wrap it up (may have to xmit first) */
peer->cond = PEER_CLOSED;
io_wake(peer);
/* We do nothing more. */
return io_wait(conn, NULL, io_never, NULL);
}
/* Communication failed: send err (if non-NULL), then dump to chain and close. */
static struct io_plan *peer_comms_err(struct io_conn *conn, struct peer *peer,
Pkt *err)
{
if (err)
queue_pkt_err(peer, err);
set_peer_state(peer, STATE_ERR_BREAKDOWN, __func__);
peer_breakdown(peer);
return peer_close(conn, peer);
}
/* Unexpected packet received: stop listening, start breakdown procedure. */
static struct io_plan *peer_received_unexpected_pkt(struct io_conn *conn,
struct peer *peer,
const Pkt *pkt)
{
peer_unexpected_pkt(peer, pkt);
return peer_comms_err(conn, peer, pkt_err_unexpected(peer, pkt));
}
/* This is the io loop while we're negotiating closing tx. */
static struct io_plan *closing_pkt_in(struct io_conn *conn, struct peer *peer)
{
const CloseSignature *c = peer->inpkt->close_signature;
struct bitcoin_tx *close_tx;
struct bitcoin_signature theirsig;
assert(peer->state == STATE_MUTUAL_CLOSING);
if (peer->inpkt->pkt_case != PKT__PKT_CLOSE_SIGNATURE)
return peer_received_unexpected_pkt(conn, peer, peer->inpkt);
log_info(peer->log, "closing_pkt_in: they offered close fee %"PRIu64,
c->close_fee);
/* BOLT #2:
*
* The sender MUST set `close_fee` lower than or equal to the fee of the
* final commitment transaction, and MUST set `close_fee` to an even
* number of satoshis.
*/
if ((c->close_fee & 1)
|| c->close_fee > commit_tx_fee(peer->remote.commit->tx,
peer->anchor.satoshis)) {
return peer_comms_err(conn, peer,
pkt_err(peer, "Invalid close fee"));
}
/* FIXME: Don't accept tiny fee at all? */
/* BOLT #2:
... otherwise it SHOULD propose a
value strictly between the received `close_fee` and its
previously-sent `close_fee`.
*/
if (peer->closing.their_sig) {
/* We want more, they should give more. */
if (peer->closing.our_fee > peer->closing.their_fee) {
if (c->close_fee <= peer->closing.their_fee)
return peer_comms_err(conn, peer,
pkt_err(peer, "Didn't increase close fee"));
} else {
if (c->close_fee >= peer->closing.their_fee)
return peer_comms_err(conn, peer,
pkt_err(peer, "Didn't decrease close fee"));
}
}
/* BOLT #2:
*
* The receiver MUST check `sig` is valid for the close
* transaction with the given `close_fee`, and MUST fail the
* connection if it is not. */
theirsig.stype = SIGHASH_ALL;
if (!proto_to_signature(c->sig, &theirsig.sig))
return peer_comms_err(conn, peer,
pkt_err(peer, "Invalid signature format"));
close_tx = peer_create_close_tx(peer, c->close_fee);
if (!check_tx_sig(peer->dstate->secpctx, close_tx, 0,
NULL, 0,
peer->anchor.witnessscript,
&peer->remote.commitkey, &theirsig))
return peer_comms_err(conn, peer,
pkt_err(peer, "Invalid signature"));
tal_free(peer->closing.their_sig);
peer->closing.their_sig = tal_dup(peer,
struct bitcoin_signature, &theirsig);
peer->closing.their_fee = c->close_fee;
if (peer->closing.our_fee != peer->closing.their_fee) {
/* BOLT #2:
*
* If the receiver agrees with the fee, it SHOULD reply with a
* `close_signature` with the same `close_fee` value,
* otherwise it SHOULD propose a value strictly between the
* received `close_fee` and its previously-sent `close_fee`.
*/
/* Adjust our fee to close on their fee. */
u64 sum;
/* Beware overflow! */
sum = (u64)peer->closing.our_fee + peer->closing.their_fee;
peer->closing.our_fee = sum / 2;
if (peer->closing.our_fee & 1)
peer->closing.our_fee++;
log_info(peer->log, "accept_pkt_close_sig: we change to %"PRIu64,
peer->closing.our_fee);
queue_pkt_close_signature(peer);
}
/* Note corner case: we may *now* agree with them! */
if (peer->closing.our_fee == peer->closing.their_fee) {
log_info(peer->log, "accept_pkt_close_sig: we agree");
/* BOLT #2:
*
* Once a node has sent or received a `close_signature` with
* matching `close_fee` it SHOULD close the connection and
* SHOULD sign and broadcast the final closing transaction.
*/
broadcast_tx(peer, bitcoin_close(peer));
return peer_close(conn, peer);
}
/* FIXME: Dynamic fee! */
return peer_read_packet(conn, peer, closing_pkt_in);
}
/* FIXME: Predecls are bad, move up! */
static void try_command(struct peer *peer);
/* This is the io loop while we're clearing. */
static struct io_plan *clearing_pkt_in(struct io_conn *conn, struct peer *peer)
{
Pkt *err = NULL, *pkt = peer->inpkt;
assert(peer->state == STATE_CLEARING
|| peer->state == STATE_CLEARING_COMMITTING);
switch (pkt->pkt_case) {
case PKT__PKT_UPDATE_REVOCATION:
if (peer->state == STATE_CLEARING)
err = pkt_err_unexpected(peer, pkt);
else {
err = accept_pkt_revocation(peer, pkt);
if (!err) {
set_peer_state(peer, STATE_CLEARING, __func__);
peer_cmd_complete(peer, CMD_SUCCESS);
peer->cond = PEER_CMD_OK;
/* In case command is queued. */
try_command(peer);
}
}
break;
case PKT__PKT_UPDATE_ADD_HTLC:
/* BOLT #2:
*
* A node MUST NOT send a `update_add_htlc` after a
* `close_clearing` */
if (peer->closing.their_script)
err = pkt_err(peer, "Update during clearing");
else
err = accept_pkt_htlc_add(peer, pkt);
break;
case PKT__PKT_CLOSE_CLEARING:
/* BOLT #2:
*
* A node... MUST NOT send more than one `close_clearing`. */
if (peer->closing.their_script)
err = pkt_err_unexpected(peer, pkt);
else
err = accept_pkt_close_clearing(peer, pkt);
break;
case PKT__PKT_UPDATE_FULFILL_HTLC:
err = accept_pkt_htlc_fulfill(peer, pkt);
break;
case PKT__PKT_UPDATE_FAIL_HTLC:
err = accept_pkt_htlc_fail(peer, pkt);
break;
case PKT__PKT_UPDATE_COMMIT:
err = accept_pkt_commit(peer, pkt);
if (!err)
queue_pkt_revocation(peer);
break;
case PKT__PKT_ERROR:
peer_unexpected_pkt(peer, pkt);
return peer_comms_err(conn, peer, NULL);
case PKT__PKT_AUTH:
case PKT__PKT_OPEN:
case PKT__PKT_OPEN_ANCHOR:
case PKT__PKT_OPEN_COMMIT_SIG:
case PKT__PKT_OPEN_COMPLETE:
case PKT__PKT_CLOSE_SIGNATURE:
default:
peer_unexpected_pkt(peer, pkt);
err = pkt_err_unexpected(peer, pkt);
break;
}
if (err)
return peer_comms_err(conn, peer, err);
if (!committed_to_htlcs(peer)) {
set_peer_state(peer, STATE_MUTUAL_CLOSING, __func__);
peer_calculate_close_fee(peer);
queue_pkt_close_signature(peer);
return peer_read_packet(conn, peer, closing_pkt_in);
}
return peer_read_packet(conn, peer, clearing_pkt_in);
}
static void peer_start_clearing(struct peer *peer)
{
assert(peer->state == STATE_CLEARING
|| peer->state == STATE_CLEARING_COMMITTING);
/* If they started close, we might not have sent ours. */
if (!peer->closing.our_script) {
u8 *redeemscript = bitcoin_redeem_single(peer,
&peer->local.finalkey);
peer->closing.our_script = scriptpubkey_p2sh(peer, redeemscript);
tal_free(redeemscript);
/* BOLT #2:
*
* A node SHOULD send a `close_clearing` (if it has
* not already) after receiving `close_clearing`.
*/
queue_pkt_close_clearing(peer);
}
/* Catch case where we've exchanged and had no HTLCs anyway. */
if (peer->closing.our_script && peer->closing.their_script
&& !committed_to_htlcs(peer)) {
set_peer_state(peer, STATE_MUTUAL_CLOSING, __func__);
peer_calculate_close_fee(peer);
queue_pkt_close_signature(peer);
}
}
static void state_single(struct peer *peer, static void state_single(struct peer *peer,
const enum state_input input, const enum state_input input,
const union input *idata) const union input *idata)
@ -199,6 +573,10 @@ static void state_single(struct peer *peer,
if (peer->cond == PEER_CLOSED) if (peer->cond == PEER_CLOSED)
io_wake(peer); io_wake(peer);
else if (peer->state == STATE_CLEARING
|| peer->state == STATE_CLEARING_COMMITTING)
peer_start_clearing(peer);
/* FIXME: Some of these should just result in this peer being killed? */ /* FIXME: Some of these should just result in this peer being killed? */
else if (state_is_error(peer->state)) { else if (state_is_error(peer->state)) {
log_broken(peer->log, "Entered error state %s", log_broken(peer->log, "Entered error state %s",
@ -245,7 +623,7 @@ static bool queue_cmd_(struct peer *peer,
{ {
struct pending_cmd *pend; struct pending_cmd *pend;
if (peer->cond == PEER_CLOSING || peer->cond == PEER_CLOSED) if (peer->cond == PEER_CLOSED)
return false; return false;
pend = tal(peer, struct pending_cmd); pend = tal(peer, struct pending_cmd);
@ -257,7 +635,7 @@ static bool queue_cmd_(struct peer *peer,
return true; return true;
}; };
static void queue_input(struct peer *peer, static void UNNEEDED queue_input(struct peer *peer,
enum state_input input, enum state_input input,
const union input *idata) const union input *idata)
{ {
@ -269,43 +647,19 @@ static void queue_input(struct peer *peer,
list_add_tail(&peer->pending_input, &pend->list); list_add_tail(&peer->pending_input, &pend->list);
} }
/* All unrevoked commit txs must have no HTLCs in them. */
static bool committed_to_htlcs(const struct peer *peer)
{
const struct commit_info *i;
/* Before anchor exchange, we don't even have cstate. */
if (!peer->local.commit || !peer->local.commit->cstate)
return false;
i = peer->local.commit;
while (i && !i->revocation_preimage) {
if (tal_count(i->cstate->side[OURS].htlcs))
return true;
if (tal_count(i->cstate->side[THEIRS].htlcs))
return true;
i = i->prev;
}
i = peer->remote.commit;
while (i && !i->revocation_preimage) {
if (tal_count(i->cstate->side[OURS].htlcs))
return true;
if (tal_count(i->cstate->side[THEIRS].htlcs))
return true;
i = i->prev;
}
return false;
}
static void state_event(struct peer *peer, static void state_event(struct peer *peer,
const enum state_input input, const enum state_input input,
const union input *idata) const union input *idata)
{ {
struct pending_input *pend; struct pending_input *pend;
state_single(peer, input, idata); if (state_is_closing(peer->state)) {
log_unusual(peer->log,
"Unexpected input %s while state %s",
input_name(input), state_name(peer->state));
} else {
state_single(peer, input, idata);
}
pend = list_pop(&peer->pending_input, struct pending_input, list); pend = list_pop(&peer->pending_input, struct pending_input, list);
if (pend) { if (pend) {
@ -316,18 +670,6 @@ static void state_event(struct peer *peer,
try_command(peer); try_command(peer);
} }
void peer_check_if_cleared(struct peer *peer)
{
if (peer->cleared == INPUT_NONE)
return;
if (committed_to_htlcs(peer))
return;
queue_input(peer, peer->cleared, NULL);
peer->cleared = INPUT_NONE;
}
static struct io_plan *pkt_out(struct io_conn *conn, struct peer *peer) static struct io_plan *pkt_out(struct io_conn *conn, struct peer *peer)
{ {
Pkt *out; Pkt *out;
@ -352,8 +694,16 @@ static struct io_plan *pkt_out(struct io_conn *conn, struct peer *peer)
static struct io_plan *pkt_in(struct io_conn *conn, struct peer *peer) static struct io_plan *pkt_in(struct io_conn *conn, struct peer *peer)
{ {
union input idata; union input idata;
const tal_t *ctx = tal(peer, char); const tal_t *ctx;
/* Did something move us into STATE_CLEARING? */
if (peer->state == STATE_CLEARING
|| peer->state == STATE_CLEARING_COMMITTING)
return clearing_pkt_in(conn, peer);
else if (peer->state == STATE_MUTUAL_CLOSING)
return closing_pkt_in(conn, peer);
ctx = tal(peer, char);
idata.pkt = tal_steal(ctx, peer->inpkt); idata.pkt = tal_steal(ctx, peer->inpkt);
/* We ignore packets if they tell us to. */ /* We ignore packets if they tell us to. */
@ -435,7 +785,7 @@ static void do_commit(struct peer *peer, struct command *jsoncmd)
&& peer->remote.staging_cstate->changes && peer->remote.staging_cstate->changes
!= peer->remote.commit->cstate->changes) { != peer->remote.commit->cstate->changes) {
log_debug(peer->log, "do_commit: sending commit command"); log_debug(peer->log, "do_commit: sending commit command");
set_current_command(peer, CMD_SEND_COMMIT, NULL, jsoncmd); command_send_commit(peer, jsoncmd);
return; return;
} }
log_debug(peer->log, "do_commit: no changes to commit"); log_debug(peer->log, "do_commit: no changes to commit");
@ -1724,16 +2074,6 @@ void peer_unexpected_pkt(struct peer *peer, const Pkt *pkt)
log_unusual(peer->log, "Error pkt '%s'", pkt->error->problem); log_unusual(peer->log, "Error pkt '%s'", pkt->error->problem);
} }
void peer_watch_htlcs_cleared(struct peer *peer,
enum state_input all_done)
{
assert(peer->cleared == INPUT_NONE);
assert(all_done != INPUT_NONE);
peer->cleared = all_done;
peer_check_if_cleared(peer);
}
/* Create a bitcoin close tx, using last signature they sent. */ /* Create a bitcoin close tx, using last signature they sent. */
const struct bitcoin_tx *bitcoin_close(struct peer *peer) const struct bitcoin_tx *bitcoin_close(struct peer *peer)
{ {
@ -2060,19 +2400,6 @@ const struct json_command getpeers_command = {
"Returns a 'peers' array" "Returns a 'peers' array"
}; };
static void set_htlc_command(struct peer *peer,
struct command *jsoncmd,
enum state_input cmd,
const union htlc_staging *stage)
{
/* FIXME: memleak! */
/* FIXME: Get rid of struct htlc_progress */
struct htlc_progress *progress = tal(peer, struct htlc_progress);
progress->stage = *stage;
set_current_command(peer, cmd, progress, jsoncmd);
}
/* FIXME: Keep a timeout for each peer, in case they're unresponsive. */ /* FIXME: Keep a timeout for each peer, in case they're unresponsive. */
/* FIXME: Make sure no HTLCs in any unrevoked commit tx are live. */ /* FIXME: Make sure no HTLCs in any unrevoked commit tx are live. */
@ -2080,9 +2407,6 @@ static void set_htlc_command(struct peer *peer,
static void check_htlc_expiry(struct peer *peer, void *unused) static void check_htlc_expiry(struct peer *peer, void *unused)
{ {
size_t i; size_t i;
union htlc_staging stage;
stage.fail.fail = HTLC_FAIL;
/* Check their currently still-existing htlcs for expiry: /* Check their currently still-existing htlcs for expiry:
* We eliminate them from staging as we go. */ * We eliminate them from staging as we go. */
@ -2098,8 +2422,7 @@ static void check_htlc_expiry(struct peer *peer, void *unused)
< abs_locktime_to_seconds(&htlc->expiry)) < abs_locktime_to_seconds(&htlc->expiry))
continue; continue;
stage.fail.id = htlc->id; command_htlc_fail(peer, htlc->id, NULL);
set_htlc_command(peer, NULL, CMD_SEND_HTLC_FAIL, &stage);
return; return;
} }
} }
@ -2147,9 +2470,19 @@ static void do_newhtlc(struct peer *peer, struct newhtlc *newhtlc)
if (tal_count(peer->local.staging_cstate->side[OURS].htlcs) == 300 if (tal_count(peer->local.staging_cstate->side[OURS].htlcs) == 300
|| tal_count(peer->remote.staging_cstate->side[OURS].htlcs) == 300) { || tal_count(peer->remote.staging_cstate->side[OURS].htlcs) == 300) {
command_fail(newhtlc->jsoncmd, "Too many HTLCs"); command_fail(newhtlc->jsoncmd, "Too many HTLCs");
return;
} }
/* BOLT #2:
*
* A node MUST NOT send a `update_add_htlc` after a `close_clearing`
*/
if (state_is_closing(peer->state)) {
command_fail(newhtlc->jsoncmd, "Channel closing, state %s",
state_name(peer->state));
return;
}
/* BOLT #2: /* BOLT #2:
* *
* A node MUST NOT offer `amount_msat` it cannot pay for in * A node MUST NOT offer `amount_msat` it cannot pay for in
@ -2292,10 +2625,7 @@ static void do_fullfill(struct peer *peer,
{ {
struct sha256 rhash; struct sha256 rhash;
size_t i; size_t i;
union htlc_staging stage; u64 id;
stage.fulfill.fulfill = HTLC_FULFILL;
stage.fulfill.r = fulfillhtlc->r;
sha256(&rhash, &fulfillhtlc->r, sizeof(fulfillhtlc->r)); sha256(&rhash, &fulfillhtlc->r, sizeof(fulfillhtlc->r));
@ -2304,9 +2634,8 @@ static void do_fullfill(struct peer *peer,
command_fail(fulfillhtlc->jsoncmd, "preimage htlc not found"); command_fail(fulfillhtlc->jsoncmd, "preimage htlc not found");
return; return;
} }
stage.fulfill.id = peer->remote.staging_cstate->side[THEIRS].htlcs[i].id; id = peer->remote.staging_cstate->side[THEIRS].htlcs[i].id;
set_htlc_command(peer, fulfillhtlc->jsoncmd, command_htlc_fulfill(peer, id, &fulfillhtlc->r, fulfillhtlc->jsoncmd);
CMD_SEND_HTLC_FULFILL, &stage);
} }
static void json_fulfillhtlc(struct command *cmd, static void json_fulfillhtlc(struct command *cmd,
@ -2367,9 +2696,7 @@ static void do_failhtlc(struct peer *peer,
struct failhtlc *failhtlc) struct failhtlc *failhtlc)
{ {
size_t i; size_t i;
union htlc_staging stage; u64 id;
stage.fail.fail = HTLC_FAIL;
/* Look in peer->remote.staging_cstate->a, as that's where we'll /* Look in peer->remote.staging_cstate->a, as that's where we'll
* immediately remove it from: avoids double-handling. */ * immediately remove it from: avoids double-handling. */
@ -2378,9 +2705,8 @@ static void do_failhtlc(struct peer *peer,
command_fail(failhtlc->jsoncmd, "htlc not found"); command_fail(failhtlc->jsoncmd, "htlc not found");
return; return;
} }
stage.fail.id = peer->remote.staging_cstate->side[THEIRS].htlcs[i].id; id = peer->remote.staging_cstate->side[THEIRS].htlcs[i].id;
command_htlc_fail(peer, id, failhtlc->jsoncmd);
set_htlc_command(peer, failhtlc->jsoncmd, CMD_SEND_HTLC_FAIL, &stage);
} }
static void json_failhtlc(struct command *cmd, static void json_failhtlc(struct command *cmd,
@ -2485,14 +2811,22 @@ static void json_close(struct command *cmd,
command_fail(cmd, "Could not find peer with that peerid"); command_fail(cmd, "Could not find peer with that peerid");
return; return;
} }
if (peer->cond == PEER_CLOSING) {
command_fail(cmd, "Peer is already closing"); if (state_is_closing(peer->state)) {
command_fail(cmd, "Peer is already closing: state %s",
state_name(peer->state));
return; return;
} }
/* Unlike other things, CMD_CLOSE is always valid. */ /* Closing causes any current command to fail. */
log_debug(peer->log, "Sending CMD_CLOSE"); if (peer->curr_cmd.cmd != INPUT_NONE)
state_event(peer, CMD_CLOSE, NULL); peer_cmd_complete(peer, CMD_FAIL);
if (peer->state == STATE_NORMAL_COMMITTING)
set_peer_state(peer, STATE_CLEARING_COMMITTING, __func__);
else
set_peer_state(peer, STATE_CLEARING, __func__);
peer_start_clearing(peer);
command_success(cmd, null_response(cmd)); command_success(cmd, null_response(cmd));
} }

3
daemon/peer.h

@ -235,9 +235,6 @@ bool setup_first_commit(struct peer *peer);
void set_peer_state(struct peer *peer, enum state newstate, const char *why); void set_peer_state(struct peer *peer, enum state newstate, const char *why);
/* Call this after commit changes, or revocation accepted/sent. */
void peer_check_if_cleared(struct peer *peer);
/* Set up timer: we have something we can commit. */ /* Set up timer: we have something we can commit. */
void remote_changes_pending(struct peer *peer); void remote_changes_pending(struct peer *peer);

6
daemon/test/test.sh

@ -557,9 +557,9 @@ check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
lcli1 close $ID2 lcli1 close $ID2
# They should be waiting for close. # They should be negotiating the close.
check_peerstate lcli1 STATE_CLOSE_WAIT_CLOSE check_peerstate lcli1 STATE_MUTUAL_CLOSING
check_peerstate lcli2 STATE_CLOSE_WAIT_CLOSE check_peerstate lcli2 STATE_MUTUAL_CLOSING
$CLI generate 1 $CLI generate 1

157
state.c

@ -34,12 +34,6 @@ static enum command_status unchanged_state(const struct peer *peer,
return cstatus; return cstatus;
} }
static void set_peer_cond(struct peer *peer, enum state_peercond cond)
{
assert(peer->cond != cond);
peer->cond = cond;
}
static void change_peer_cond(struct peer *peer, static void change_peer_cond(struct peer *peer,
enum state_peercond old, enum state_peercond old,
enum state_peercond new) enum state_peercond new)
@ -110,9 +104,6 @@ enum command_status state(struct peer *peer,
goto err_breakdown; goto err_breakdown;
} }
return next_state(peer, input, cstatus, STATE_OPEN_WAIT_FOR_ANCHOR); return next_state(peer, input, cstatus, STATE_OPEN_WAIT_FOR_ANCHOR);
} else if (input_is(input, CMD_CLOSE)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto breakdown;
} else if (input_is_pkt(input)) { } else if (input_is_pkt(input)) {
complete_cmd(peer, &cstatus, CMD_FAIL); complete_cmd(peer, &cstatus, CMD_FAIL);
goto unexpected_pkt; goto unexpected_pkt;
@ -128,9 +119,6 @@ enum command_status state(struct peer *peer,
bitcoin_create_anchor(peer, BITCOIN_ANCHOR_CREATED); bitcoin_create_anchor(peer, BITCOIN_ANCHOR_CREATED);
return next_state(peer, input, cstatus, return next_state(peer, input, cstatus,
STATE_OPEN_WAIT_FOR_ANCHOR_CREATE); STATE_OPEN_WAIT_FOR_ANCHOR_CREATE);
} else if (input_is(input, CMD_CLOSE)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto breakdown;
} else if (input_is_pkt(input)) { } else if (input_is_pkt(input)) {
complete_cmd(peer, &cstatus, CMD_FAIL); complete_cmd(peer, &cstatus, CMD_FAIL);
goto unexpected_pkt; goto unexpected_pkt;
@ -141,10 +129,6 @@ enum command_status state(struct peer *peer,
queue_pkt_anchor(peer); queue_pkt_anchor(peer);
return next_state(peer, input, cstatus, return next_state(peer, input, cstatus,
STATE_OPEN_WAIT_FOR_COMMIT_SIG); STATE_OPEN_WAIT_FOR_COMMIT_SIG);
} else if (input_is(input, CMD_CLOSE)) {
bitcoin_release_anchor(peer, BITCOIN_ANCHOR_CREATED);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto breakdown;
} else if (input_is_pkt(input)) { } else if (input_is_pkt(input)) {
bitcoin_release_anchor(peer, BITCOIN_ANCHOR_CREATED); bitcoin_release_anchor(peer, BITCOIN_ANCHOR_CREATED);
complete_cmd(peer, &cstatus, CMD_FAIL); complete_cmd(peer, &cstatus, CMD_FAIL);
@ -165,9 +149,6 @@ enum command_status state(struct peer *peer,
return next_state(peer, input, cstatus, return next_state(peer, input, cstatus,
STATE_OPEN_WAITING_THEIRANCHOR); STATE_OPEN_WAITING_THEIRANCHOR);
} else if (input_is(input, CMD_CLOSE)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto breakdown;
} else if (input_is_pkt(input)) { } else if (input_is_pkt(input)) {
complete_cmd(peer, &cstatus, CMD_FAIL); complete_cmd(peer, &cstatus, CMD_FAIL);
goto unexpected_pkt; goto unexpected_pkt;
@ -187,10 +168,6 @@ enum command_status state(struct peer *peer,
INPUT_NONE); INPUT_NONE);
return next_state(peer, input, cstatus, return next_state(peer, input, cstatus,
STATE_OPEN_WAITING_OURANCHOR); STATE_OPEN_WAITING_OURANCHOR);
} else if (input_is(input, CMD_CLOSE)) {
bitcoin_release_anchor(peer, INPUT_NONE);
complete_cmd(peer, &cstatus, CMD_FAIL);
goto breakdown;
} else if (input_is_pkt(input)) { } else if (input_is_pkt(input)) {
bitcoin_release_anchor(peer, INPUT_NONE); bitcoin_release_anchor(peer, INPUT_NONE);
complete_cmd(peer, &cstatus, CMD_FAIL); complete_cmd(peer, &cstatus, CMD_FAIL);
@ -221,13 +198,6 @@ enum command_status state(struct peer *peer,
} }
return next_state(peer, input, cstatus, return next_state(peer, input, cstatus,
STATE_OPEN_WAIT_FOR_COMPLETE_OURANCHOR); STATE_OPEN_WAIT_FOR_COMPLETE_OURANCHOR);
} else if (input_is(input, CMD_CLOSE)) {
/* 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_clearing;
} else if (input_is(input, PKT_CLOSE_CLEARING)) { } else if (input_is(input, PKT_CLOSE_CLEARING)) {
/* We no longer care about anchor depth. */ /* We no longer care about anchor depth. */
peer_unwatch_anchor_depth(peer, peer_unwatch_anchor_depth(peer,
@ -272,13 +242,6 @@ enum command_status state(struct peer *peer,
} }
return next_state(peer, input, cstatus, return next_state(peer, input, cstatus,
STATE_OPEN_WAIT_FOR_COMPLETE_THEIRANCHOR); STATE_OPEN_WAIT_FOR_COMPLETE_THEIRANCHOR);
} else if (input_is(input, CMD_CLOSE)) {
/* 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_clearing;
} else if (input_is(input, PKT_CLOSE_CLEARING)) { } else if (input_is(input, PKT_CLOSE_CLEARING)) {
/* We no longer care about anchor depth. */ /* We no longer care about anchor depth. */
peer_unwatch_anchor_depth(peer, peer_unwatch_anchor_depth(peer,
@ -306,9 +269,6 @@ enum command_status state(struct peer *peer,
complete_cmd(peer, &cstatus, CMD_SUCCESS); complete_cmd(peer, &cstatus, CMD_SUCCESS);
return next_state(peer, input, cstatus, STATE_NORMAL); return next_state(peer, input, cstatus, STATE_NORMAL);
} }
} else if (input_is(input, CMD_CLOSE)) {
complete_cmd(peer, &cstatus, CMD_FAIL);
goto start_clearing;
} else if (input_is(input, PKT_CLOSE_CLEARING)) { } else if (input_is(input, PKT_CLOSE_CLEARING)) {
complete_cmd(peer, &cstatus, CMD_FAIL); complete_cmd(peer, &cstatus, CMD_FAIL);
goto accept_clearing; goto accept_clearing;
@ -337,12 +297,16 @@ enum command_status state(struct peer *peer,
queue_pkt_htlc_add(peer, idata->htlc_prog); queue_pkt_htlc_add(peer, idata->htlc_prog);
return instant_cmd_success(peer, cstatus); return instant_cmd_success(peer, cstatus);
} else if (input_is(input, CMD_SEND_HTLC_FULFILL)) { } else if (input_is(input, CMD_SEND_HTLC_FULFILL)) {
assert(idata->htlc_prog->stage.type == HTLC_FULFILL);
/* We are to send an HTLC fulfill. */ /* We are to send an HTLC fulfill. */
queue_pkt_htlc_fulfill(peer, idata->htlc_prog); queue_pkt_htlc_fulfill(peer,
idata->htlc_prog->stage.fulfill.id,
&idata->htlc_prog->stage.fulfill.r);
return instant_cmd_success(peer, cstatus); return instant_cmd_success(peer, cstatus);
} else if (input_is(input, CMD_SEND_HTLC_FAIL)) { } else if (input_is(input, CMD_SEND_HTLC_FAIL)) {
assert(idata->htlc_prog->stage.type == HTLC_FAIL);
/* We are to send an HTLC fail. */ /* We are to send an HTLC fail. */
queue_pkt_htlc_fail(peer, idata->htlc_prog); queue_pkt_htlc_fail(peer, idata->htlc_prog->stage.fail.id);
return instant_cmd_success(peer, cstatus); return instant_cmd_success(peer, cstatus);
} }
/* Fall through... */ /* Fall through... */
@ -359,9 +323,7 @@ enum command_status state(struct peer *peer,
return next_state(peer, input, cstatus, STATE_NORMAL); return next_state(peer, input, cstatus, STATE_NORMAL);
} }
if (input_is(input, CMD_CLOSE)) { if (input_is(input, PKT_UPDATE_ADD_HTLC)) {
goto start_clearing;
} else if (input_is(input, PKT_UPDATE_ADD_HTLC)) {
err = accept_pkt_htlc_add(peer, idata->pkt); err = accept_pkt_htlc_add(peer, idata->pkt);
if (err) if (err)
goto err_breakdown; goto err_breakdown;
@ -388,85 +350,17 @@ enum command_status state(struct peer *peer,
goto unexpected_pkt; goto unexpected_pkt;
} }
break; break;
case STATE_US_CLEARING:
/* This is their reply once they're clearing too. */
if (input_is(input, PKT_CLOSE_CLEARING)) {
err = accept_pkt_close_clearing(peer, idata->pkt);
if (err)
goto err_breakdown;
/* Notify us when there are no more htlcs in
* either commit tx */
peer_watch_htlcs_cleared(peer, INPUT_HTLCS_CLEARED);
return next_state(peer, input, cstatus, STATE_BOTH_CLEARING);
/* FIXME: We must continue to allow fulfill & fail! */
} 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_breakdown;
} else if (input_is_pkt(input)) {
/* FIXME: We must continue to allow add, fulfill & fail packets */
goto unexpected_pkt;
}
break;
case STATE_BOTH_CLEARING:
if (input_is(input, INPUT_HTLCS_CLEARED)) {
goto start_closing_cleared;
} 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_breakdown;
} else if (input_is_pkt(input)) {
/* FIXME: We must continue to allow fulfill & fail packets */
goto unexpected_pkt;
}
break;
case STATE_WAIT_FOR_CLOSE_SIG:
if (input_is(input, PKT_CLOSE_SIGNATURE)) {
bool acked, we_agree;
err = accept_pkt_close_sig(peer, idata->pkt,
&acked, &we_agree);
if (err)
goto err_breakdown;
/* Are we about to offer the same fee they did? */
if (we_agree) {
/* Offer the new fee. */
queue_pkt_close_signature(peer);
acked = true;
}
/* Do fees now match? */
if (acked) {
/* Send close TX. */
queue_tx_broadcast(broadcast,
bitcoin_close(peer));
change_peer_cond(peer,
PEER_CLOSING, PEER_CLOSED);
return next_state(peer, input, cstatus,
STATE_CLOSE_WAIT_CLOSE);
}
/* Offer the new fee. */
queue_pkt_close_signature(peer);
return unchanged_state(peer, input, cstatus);
} else if (input_is(input, INPUT_CLOSE_COMPLETE_TIMEOUT)) {
err = pkt_err(peer, "Close timed out");
goto err_breakdown;
} else if (input_is_pkt(input)) {
goto unexpected_pkt;
}
break;
/* Should never happen. */ /* Should never happen. */
case STATE_ERR_INTERNAL: case STATE_ERR_INTERNAL:
case STATE_ERR_ANCHOR_TIMEOUT: case STATE_ERR_ANCHOR_TIMEOUT:
case STATE_ERR_INFORMATION_LEAK: case STATE_ERR_INFORMATION_LEAK:
case STATE_ERR_BREAKDOWN: case STATE_ERR_BREAKDOWN:
case STATE_CLOSE_WAIT_CLOSE:
case STATE_CLOSED: case STATE_CLOSED:
case STATE_MAX: case STATE_MAX:
case STATE_CLEARING:
case STATE_CLEARING_COMMITTING:
case STATE_MUTUAL_CLOSING:
case STATE_CLOSE_ONCHAIN_CHEATED: case STATE_CLOSE_ONCHAIN_CHEATED:
case STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL: case STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL:
case STATE_CLOSE_ONCHAIN_OUR_UNILATERAL: case STATE_CLOSE_ONCHAIN_OUR_UNILATERAL:
@ -491,36 +385,13 @@ err_breakdown:
breakdown: breakdown:
return next_state(peer, input, cstatus, STATE_ERR_BREAKDOWN); return next_state(peer, input, cstatus, STATE_ERR_BREAKDOWN);
start_clearing:
/*
* Start a mutual close: tell them we want to clear.
*/
queue_pkt_close_clearing(peer);
/* No more commands, we're already closing. */
set_peer_cond(peer, PEER_CLOSING);
return next_state(peer, input, cstatus, STATE_US_CLEARING);
start_closing_cleared:
/* As soon as we send packet, they could close. */
peer_calculate_close_fee(peer);
queue_pkt_close_signature(peer);
return next_state(peer, input, cstatus, STATE_WAIT_FOR_CLOSE_SIG);
accept_clearing: accept_clearing:
err = accept_pkt_close_clearing(peer, idata->pkt); err = accept_pkt_close_clearing(peer, idata->pkt);
if (err) if (err)
goto err_breakdown; goto err_breakdown;
/* Notify us when there are no more htlcs in either commit tx */ /* If we've sent commit, we're still waiting for it when clearing. */
peer_watch_htlcs_cleared(peer, INPUT_HTLCS_CLEARED); if (peer->state == STATE_NORMAL_COMMITTING)
return next_state(peer, input, cstatus, STATE_CLEARING_COMMITTING);
/* No more commands, we're already closing. */ return next_state(peer, input, cstatus, STATE_CLEARING);
set_peer_cond(peer, PEER_CLOSING);
/* Tell them we're clearing too. */
queue_pkt_close_clearing(peer);
return next_state(peer, input, cstatus, STATE_BOTH_CLEARING);
} }

21
state.h

@ -19,6 +19,11 @@ static inline bool state_is_error(enum state s)
return s >= STATE_ERR_ANCHOR_TIMEOUT && s <= STATE_ERR_INTERNAL; return s >= STATE_ERR_ANCHOR_TIMEOUT && s <= STATE_ERR_INTERNAL;
} }
static inline bool state_is_closing(enum state s)
{
return s >= STATE_CLEARING;
}
struct peer; struct peer;
struct bitcoin_tx; struct bitcoin_tx;
@ -84,10 +89,8 @@ void queue_pkt_open_commit_sig(struct peer *peer);
void queue_pkt_open_complete(struct peer *peer); void queue_pkt_open_complete(struct peer *peer);
void queue_pkt_htlc_add(struct peer *peer, void queue_pkt_htlc_add(struct peer *peer,
const struct htlc_progress *htlc_prog); const struct htlc_progress *htlc_prog);
void queue_pkt_htlc_fulfill(struct peer *peer, void queue_pkt_htlc_fulfill(struct peer *peer, u64 id, const struct sha256 *r);
const struct htlc_progress *htlc_prog); void queue_pkt_htlc_fail(struct peer *peer, u64 id);
void queue_pkt_htlc_fail(struct peer *peer,
const struct htlc_progress *htlc_prog);
void queue_pkt_commit(struct peer *peer); void queue_pkt_commit(struct peer *peer);
void queue_pkt_revocation(struct peer *peer); void queue_pkt_revocation(struct peer *peer);
void queue_pkt_close_clearing(struct peer *peer); void queue_pkt_close_clearing(struct peer *peer);
@ -118,8 +121,6 @@ Pkt *accept_pkt_commit(struct peer *peer, const Pkt *pkt);
Pkt *accept_pkt_revocation(struct peer *peer, const Pkt *pkt); Pkt *accept_pkt_revocation(struct peer *peer, const Pkt *pkt);
Pkt *accept_pkt_close_clearing(struct peer *peer, const Pkt *pkt); 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);
/** /**
* peer_watch_anchor: create a watch for the anchor transaction. * peer_watch_anchor: create a watch for the anchor transaction.
@ -145,14 +146,6 @@ void peer_unwatch_anchor_depth(struct peer *peer,
enum state_input depthok, enum state_input depthok,
enum state_input timeout); enum state_input timeout);
/**
* peer_watch_htlcs_cleared: tell us when no HTLCs are in commit txs.
* @peer: the state data for this peer.
* @all_done: input to give when all HTLCs are done.
*/
void peer_watch_htlcs_cleared(struct peer *peer,
enum state_input all_done);
/** /**
* peer_calculate_close_fee: figure out what the fee for closing is. * peer_calculate_close_fee: figure out what the fee for closing is.
* @peer: the state data for this peer. * @peer: the state data for this peer.

25
state_types.h

@ -29,26 +29,21 @@ enum state {
STATE_NORMAL_COMMITTING, STATE_NORMAL_COMMITTING,
/* /*
* Closing. * Closing (handled outside state machine).
*/ */
/* We told them to clear. */ STATE_CLEARING,
STATE_US_CLEARING, STATE_CLEARING_COMMITTING,
/* They told us to clear, or acked our CLEARING. */ STATE_MUTUAL_CLOSING,
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,
/* Four states to represent closing onchain (for getpeers) */ /* Four states to represent closing onchain (for getpeers) */
STATE_CLOSE_ONCHAIN_CHEATED, STATE_CLOSE_ONCHAIN_CHEATED,
STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL, STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL,
STATE_CLOSE_ONCHAIN_OUR_UNILATERAL, STATE_CLOSE_ONCHAIN_OUR_UNILATERAL,
STATE_CLOSE_ONCHAIN_MUTUAL, STATE_CLOSE_ONCHAIN_MUTUAL,
/* All closed. */
STATE_CLOSED,
/* /*
* Where angels fear to tread. * Where angels fear to tread.
*/ */
@ -84,9 +79,8 @@ enum state_input {
PKT_UPDATE_COMMIT = PKT__PKT_UPDATE_COMMIT, PKT_UPDATE_COMMIT = PKT__PKT_UPDATE_COMMIT,
PKT_UPDATE_REVOCATION = PKT__PKT_UPDATE_REVOCATION, PKT_UPDATE_REVOCATION = PKT__PKT_UPDATE_REVOCATION,
/* Mutual close sequence. */ /* If they want to close. */
PKT_CLOSE_CLEARING = PKT__PKT_CLOSE_CLEARING, PKT_CLOSE_CLEARING = PKT__PKT_CLOSE_CLEARING,
PKT_CLOSE_SIGNATURE = PKT__PKT_CLOSE_SIGNATURE,
/* Something unexpected went wrong. */ /* Something unexpected went wrong. */
PKT_ERROR = PKT__PKT_ERROR, PKT_ERROR = PKT__PKT_ERROR,
@ -120,7 +114,6 @@ enum state_input {
CMD_SEND_HTLC_FULFILL, CMD_SEND_HTLC_FULFILL,
CMD_SEND_HTLC_FAIL, CMD_SEND_HTLC_FAIL,
CMD_SEND_COMMIT, CMD_SEND_COMMIT,
CMD_CLOSE,
INPUT_MAX INPUT_MAX
}; };
@ -130,8 +123,6 @@ enum state_peercond {
PEER_CMD_OK, PEER_CMD_OK,
/* Don't send me commands, I'm busy. */ /* Don't send me commands, I'm busy. */
PEER_BUSY, PEER_BUSY,
/* No more commands, I'm closing. */
PEER_CLOSING,
/* No more packets, I'm closed. */ /* No more packets, I'm closed. */
PEER_CLOSED PEER_CLOSED
}; };

Loading…
Cancel
Save