diff --git a/daemon/peer.c b/daemon/peer.c index 9740a13fc..e2cfff726 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -1352,10 +1352,25 @@ static void anchor_spent(struct peer *peer, STATE_CLOSE_ONCHAIN_MUTUAL, "anchor_spent"); resolve_mutual_close(peer); - } else + } else { + /* BOLT #onchain: + * + * A node SHOULD report an error to the operator if it + * sees a transaction spend the funding transaction + * output which does not fall into one of these + * categories (mutual close, unilateral close, or + * cheating attempt). Such a transaction implies its + * private key has leaked, and funds may be lost. + */ /* FIXME: Log harder! */ - fatal("Unknown tx spend!"); - + log_broken(peer->log, "Unknown tx spend! Funds may be lost!"); + set_peer_state(peer, + STATE_ERR_INFORMATION_LEAK, + "anchor_spent"); + /* No longer call into the state machine. */ + peer->anchor.watches->depthok = INPUT_NONE; + return; + } assert(peer->closing_onchain.resolved != NULL); watch_tx(tx, peer, tx, check_for_resolution, NULL); diff --git a/state.c b/state.c index 855d9e023..0068916fe 100644 --- a/state.c +++ b/state.c @@ -462,6 +462,7 @@ enum command_status state(struct peer *peer, /* Should never happen. */ case STATE_ERR_INTERNAL: case STATE_ERR_ANCHOR_TIMEOUT: + case STATE_ERR_INFORMATION_LEAK: case STATE_ERR_BREAKDOWN: case STATE_CLOSE_WAIT_CLOSE: case STATE_CLOSED: diff --git a/state_types.h b/state_types.h index f8a76bc7e..c6ddb4b07 100644 --- a/state_types.h +++ b/state_types.h @@ -56,7 +56,8 @@ enum state { 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. */ + /* We saw a tx we didn't sign. */ + STATE_ERR_INFORMATION_LEAK, /* We ended up in an unexpected state. */ STATE_ERR_INTERNAL,