mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
daemon: open-code handling of on-chain states.
Once we see an on-chain tx, we ignore the state machine and handle it as per the onchain.md draft. This specifies a *resolution* for each output, and we're done when they're irrevocable. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
f6b36b9be3
commit
f29a6043d2
3
Makefile
3
Makefile
@ -62,6 +62,7 @@ CCAN_OBJS := \
|
|||||||
ccan-isaac.o \
|
ccan-isaac.o \
|
||||||
ccan-isaac64.o \
|
ccan-isaac64.o \
|
||||||
ccan-list.o \
|
ccan-list.o \
|
||||||
|
ccan-mem.o \
|
||||||
ccan-noerr.o \
|
ccan-noerr.o \
|
||||||
ccan-opt-helpers.o \
|
ccan-opt-helpers.o \
|
||||||
ccan-opt-parse.o \
|
ccan-opt-parse.o \
|
||||||
@ -378,3 +379,5 @@ ccan-io-poll.o: $(CCANDIR)/ccan/io/poll.c
|
|||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
ccan-pipecmd.o: $(CCANDIR)/ccan/pipecmd/pipecmd.c
|
ccan-pipecmd.o: $(CCANDIR)/ccan/pipecmd/pipecmd.c
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
ccan-mem.o: $(CCANDIR)/ccan/mem/mem.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
538
daemon/peer.c
538
daemon/peer.c
@ -23,6 +23,7 @@
|
|||||||
#include <ccan/cast/cast.h>
|
#include <ccan/cast/cast.h>
|
||||||
#include <ccan/io/io.h>
|
#include <ccan/io/io.h>
|
||||||
#include <ccan/list/list.h>
|
#include <ccan/list/list.h>
|
||||||
|
#include <ccan/mem/mem.h>
|
||||||
#include <ccan/noerr/noerr.h>
|
#include <ccan/noerr/noerr.h>
|
||||||
#include <ccan/ptrint/ptrint.h>
|
#include <ccan/ptrint/ptrint.h>
|
||||||
#include <ccan/str/hex/hex.h>
|
#include <ccan/str/hex/hex.h>
|
||||||
@ -285,9 +286,12 @@ static struct io_plan *pkt_out(struct io_conn *conn, struct peer *peer)
|
|||||||
struct out_pkt out;
|
struct out_pkt out;
|
||||||
size_t n = tal_count(peer->outpkt);
|
size_t n = tal_count(peer->outpkt);
|
||||||
|
|
||||||
|
if (peer->fake_close)
|
||||||
|
return io_out_wait(conn, peer, pkt_out, peer);
|
||||||
|
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
/* We close the connection once we've sent everything. */
|
/* 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_close(conn);
|
||||||
return io_out_wait(conn, peer, pkt_out, peer);
|
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);
|
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)
|
static void peer_disconnect(struct io_conn *conn, struct peer *peer)
|
||||||
{
|
{
|
||||||
log_info(peer->log, "Disconnected");
|
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)
|
if (peer->cond == PEER_CLOSED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
state_single(peer, INPUT_CONNECTION_LOST, NULL);
|
peer_breakdown(peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct peer *new_peer(struct lightningd_state *dstate,
|
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.our_script = NULL;
|
||||||
peer->closing.their_script = NULL;
|
peer->closing.their_script = NULL;
|
||||||
peer->cleared = INPUT_NONE;
|
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
|
/* Make it different from other node (to catch bugs!), but a
|
||||||
* round number for simple eyeballing. */
|
* round number for simple eyeballing. */
|
||||||
peer->htlc_id_counter = pseudorand(1ULL << 32) * 1000;
|
peer->htlc_id_counter = pseudorand(1ULL << 32) * 1000;
|
||||||
@ -735,15 +757,6 @@ static bool is_mutual_close(const struct peer *peer,
|
|||||||
return false;
|
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,
|
static struct channel_htlc *htlc_by_index(const struct commit_info *ci,
|
||||||
size_t index)
|
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 */
|
/* 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,
|
const struct commit_info *ci,
|
||||||
unsigned int i)
|
unsigned int i)
|
||||||
{
|
{
|
||||||
@ -834,6 +847,444 @@ static UNNEEDED const struct bitcoin_tx *htlc_timeout_tx(const struct peer *peer
|
|||||||
return tx;
|
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
|
/* We assume the tx is valid! Don't do a blockchain.info and feed this
|
||||||
* invalid transactions! */
|
* invalid transactions! */
|
||||||
static void anchor_spent(struct peer *peer,
|
static void anchor_spent(struct peer *peer,
|
||||||
@ -841,8 +1292,6 @@ static void anchor_spent(struct peer *peer,
|
|||||||
size_t input_num,
|
size_t input_num,
|
||||||
void *unused)
|
void *unused)
|
||||||
{
|
{
|
||||||
struct anchor_watch *w = peer->anchor.watches;
|
|
||||||
union input idata;
|
|
||||||
struct sha256_double txid;
|
struct sha256_double txid;
|
||||||
|
|
||||||
assert(input_num < tx->input_count);
|
assert(input_num < tx->input_count);
|
||||||
@ -851,22 +1300,55 @@ static void anchor_spent(struct peer *peer,
|
|||||||
if (input_num != 0)
|
if (input_num != 0)
|
||||||
fatal("Anchor spend by non-single input tx");
|
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);
|
bitcoin_txid(tx, &txid);
|
||||||
|
|
||||||
idata.ci = find_commit(peer->them.commit, &txid);
|
peer->closing_onchain.ci = find_commit(peer->them.commit, &txid);
|
||||||
if (idata.ci) {
|
if (peer->closing_onchain.ci) {
|
||||||
if (idata.ci->revocation_preimage)
|
if (peer->closing_onchain.ci->revocation_preimage) {
|
||||||
state_event(peer, w->otherspent, &idata);
|
peer->state = STATE_CLOSE_ONCHAIN_CHEATED;
|
||||||
else {
|
resolve_cheating(peer);
|
||||||
idata.tx = idata.ci->tx;
|
} else {
|
||||||
state_event(peer, w->theyspent, &idata);
|
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)) {
|
} else if (is_mutual_close(peer, tx)) {
|
||||||
watch_tx(peer, peer, tx, close_depth_cb, NULL);
|
peer->state = STATE_CLOSE_ONCHAIN_MUTUAL;
|
||||||
} else {
|
resolve_mutual_close(peer);
|
||||||
if (!txidmatch(peer->us.commit->tx, &txid))
|
} else
|
||||||
fatal("Unknown tx spend!");
|
/* 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)
|
static void anchor_timeout(struct anchor_watch *w)
|
||||||
@ -1491,6 +1973,8 @@ static void json_getpeers(struct command *cmd,
|
|||||||
json_add_hex(response, "peerid",
|
json_add_hex(response, "peerid",
|
||||||
p->id.der, sizeof(p->id.der));
|
p->id.der, sizeof(p->id.der));
|
||||||
|
|
||||||
|
json_add_bool(response, "connected", p->conn && !p->fake_close);
|
||||||
|
|
||||||
/* FIXME: Report anchor. */
|
/* FIXME: Report anchor. */
|
||||||
|
|
||||||
if (!p->us.commit) {
|
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. */
|
* one side to freak out. We just ensure we ignore it. */
|
||||||
log_debug(peer->log, "Pretending connection is closed");
|
log_debug(peer->log, "Pretending connection is closed");
|
||||||
peer->fake_close = true;
|
peer->fake_close = true;
|
||||||
state_single(peer, INPUT_CONNECTION_LOST, NULL);
|
peer_breakdown(peer);
|
||||||
|
|
||||||
command_success(cmd, null_response(cmd));
|
command_success(cmd, null_response(cmd));
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,7 @@ struct peer {
|
|||||||
/* Counter to make unique HTLC ids. */
|
/* Counter to make unique HTLC ids. */
|
||||||
u64 htlc_id_counter;
|
u64 htlc_id_counter;
|
||||||
|
|
||||||
|
/* Mutual close info. */
|
||||||
struct {
|
struct {
|
||||||
/* Our last suggested closing fee. */
|
/* Our last suggested closing fee. */
|
||||||
u64 our_fee;
|
u64 our_fee;
|
||||||
@ -186,6 +187,14 @@ struct peer {
|
|||||||
u8 *our_script, *their_script;
|
u8 *our_script, *their_script;
|
||||||
} closing;
|
} 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. */
|
/* If not INPUT_NONE, send this when we have no more HTLCs. */
|
||||||
enum state_input cleared;
|
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 commit_tx_fee(const struct bitcoin_tx *commit,
|
||||||
uint64_t anchor_satoshis);
|
uint64_t anchor_satoshis);
|
||||||
|
|
||||||
|
bool resolve_one_htlc(struct peer *peer, u64 id, const struct sha256 *preimage);
|
||||||
#endif /* LIGHTNING_DAEMON_PEER_H */
|
#endif /* LIGHTNING_DAEMON_PEER_H */
|
||||||
|
@ -149,6 +149,16 @@ check_peerstate()
|
|||||||
fi
|
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()
|
check_no_peers()
|
||||||
{
|
{
|
||||||
if $1 getpeers | tr -s '\012\011 ' ' ' | $FGREP '"peers" : [ ]'; then :
|
if $1 getpeers | tr -s '\012\011 ' ' ' | $FGREP '"peers" : [ ]'; then :
|
||||||
@ -258,13 +268,20 @@ if [ -n "$TIMEOUT_ANCHOR" ]; then
|
|||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
# It should send out commit tx.
|
# It should send out commit tx.
|
||||||
check_peerstate lcli1 STATE_CLOSE_WAIT_OURCOMMIT
|
check_peerconnected lcli1 false
|
||||||
|
|
||||||
# Generate a block (should include commit tx)
|
# Generate a block (should include commit tx)
|
||||||
check_tx_spend
|
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.
|
# 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
|
lcli1 dev-mocktime $TIME
|
||||||
|
|
||||||
# Move bitcoind median time as well, so CSV moves.
|
# Move bitcoind median time as well, so CSV moves.
|
||||||
@ -281,7 +298,7 @@ if [ -n "$TIMEOUT_ANCHOR" ]; then
|
|||||||
lcli1 dev-mocktime $TIME
|
lcli1 dev-mocktime $TIME
|
||||||
sleep 2
|
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.
|
# Now it should have spent the commit tx.
|
||||||
check_tx_spend
|
check_tx_spend
|
||||||
@ -413,19 +430,27 @@ sleep 1
|
|||||||
check_peerstate lcli1 STATE_CLOSE_WAIT_CLOSE
|
check_peerstate lcli1 STATE_CLOSE_WAIT_CLOSE
|
||||||
check_peerstate lcli2 STATE_CLOSE_WAIT_CLOSE
|
check_peerstate lcli2 STATE_CLOSE_WAIT_CLOSE
|
||||||
|
|
||||||
# Give it 99 blocks.
|
$CLI generate 1
|
||||||
$CLI generate 99
|
|
||||||
|
|
||||||
# Make sure they saw it!
|
# Make sure they saw it!
|
||||||
lcli1 dev-mocktime $(($EXPIRY + 32))
|
lcli1 dev-mocktime $(($EXPIRY + 32))
|
||||||
lcli2 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
|
sleep 5
|
||||||
check_peerstate lcli1 STATE_CLOSE_WAIT_CLOSE
|
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_MUTUAL
|
||||||
check_peerstate lcli2 STATE_CLOSE_WAIT_CLOSE
|
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_MUTUAL
|
||||||
|
|
||||||
# Now the final one.
|
# Now the final one.
|
||||||
$CLI generate 1
|
$CLI generate 1
|
||||||
TIME=$(($EXPIRY + 33))
|
TIME=$(($EXPIRY + 34))
|
||||||
lcli1 dev-mocktime $TIME
|
lcli1 dev-mocktime $TIME
|
||||||
lcli2 dev-mocktime $TIME
|
lcli2 dev-mocktime $TIME
|
||||||
sleep 2
|
sleep 2
|
||||||
|
4
state.c
4
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_STEAL_CLOSE_OURCOMMIT_WITH_HTLCS:
|
||||||
case STATE_UNUSED_CLOSE_WAIT_CLOSE_SPENDOURS_WITH_HTLCS:
|
case STATE_UNUSED_CLOSE_WAIT_CLOSE_SPENDOURS_WITH_HTLCS:
|
||||||
case STATE_UNUSED_CLOSE_WAIT_STEAL_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);
|
return next_state(peer, cstatus, STATE_ERR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,6 +151,12 @@ enum state {
|
|||||||
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_SPENDOURS,
|
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_SPENDOURS,
|
||||||
STATE_CLOSE_WAIT_STEAL_THEIRCOMMIT_CLOSE_SPENDOURS_WITH_HTLCS,
|
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.
|
* Where angels fear to tread.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user