From 862509637ba4e6ef68b5a06daa7a6ee7d5ce4888 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 22 Jan 2016 06:45:28 +1030 Subject: [PATCH] daemon: implement unilateral commit. This is only for the simple case where there are no HTLCs. We group the current commit information together in the struct; this involves a trivial transform from peer->cur_commit_theirsig to peer->cur_commit.theirsig. Signed-off-by: Rusty Russell --- daemon/bitcoind.c | 3 + daemon/packets.c | 12 ++-- daemon/peer.c | 147 ++++++++++++++++++++++++++++++++++++++------ daemon/peer.h | 13 +++- daemon/secrets.c | 29 +++++++++ daemon/secrets.h | 9 +++ daemon/test/test.sh | 70 ++++++++++++++++----- daemon/watch.c | 16 ++--- daemon/watch.h | 14 ++--- find_p2sh_out.c | 1 + 10 files changed, 256 insertions(+), 58 deletions(-) diff --git a/daemon/bitcoind.c b/daemon/bitcoind.c index 5a7e9375b..9536c83bd 100644 --- a/daemon/bitcoind.c +++ b/daemon/bitcoind.c @@ -419,6 +419,7 @@ static void process_getblock(struct bitcoin_cli *bcli) const jsmntok_t *tokens, *mediantime; bool valid; + log_debug(bcli->dstate->base_log, "Got getblock result"); if (!bcli->output) fatal("bitcoind: '%s' '%s' failed", bcli->args[0], bcli->args[1]); @@ -445,6 +446,8 @@ static void process_getblock(struct bitcoin_cli *bcli) bcli->args[2], mediantime->end - mediantime->start, bcli->output + mediantime->start); + + log_debug(bcli->dstate->base_log, "mediantime = %u", *(u32 *)bcli->cb_arg); } void bitcoind_get_mediantime(struct lightningd_state *dstate, diff --git a/daemon/packets.c b/daemon/packets.c index 86bfc6d67..ca935bcac 100644 --- a/daemon/packets.c +++ b/daemon/packets.c @@ -365,8 +365,8 @@ Pkt *accept_pkt_anchor(const tal_t *ctx, &peer->us.commit, &peer->them.commit); - peer->cur_commit_theirsig.stype = SIGHASH_ALL; - if (!proto_to_signature(a->commit_sig, &peer->cur_commit_theirsig.sig)) + peer->cur_commit.theirsig.stype = SIGHASH_ALL; + if (!proto_to_signature(a->commit_sig, &peer->cur_commit.theirsig.sig)) return pkt_err(ctx, "Malformed signature"); /* Their sig should sign our commit tx. */ @@ -375,7 +375,7 @@ Pkt *accept_pkt_anchor(const tal_t *ctx, peer->anchor.redeemscript, tal_count(peer->anchor.redeemscript), &peer->them.commitkey, - &peer->cur_commit_theirsig)) + &peer->cur_commit.theirsig)) return pkt_err(ctx, "Bad signature"); return NULL; @@ -386,8 +386,8 @@ Pkt *accept_pkt_open_commit_sig(const tal_t *ctx, { const OpenCommitSig *s = pkt->open_commit_sig; - peer->cur_commit_theirsig.stype = SIGHASH_ALL; - if (!proto_to_signature(s->sig, &peer->cur_commit_theirsig.sig)) + peer->cur_commit.theirsig.stype = SIGHASH_ALL; + if (!proto_to_signature(s->sig, &peer->cur_commit.theirsig.sig)) return pkt_err(ctx, "Malformed signature"); dump_tx("Checking sig for:", peer->us.commit); @@ -399,7 +399,7 @@ Pkt *accept_pkt_open_commit_sig(const tal_t *ctx, peer->anchor.redeemscript, tal_count(peer->anchor.redeemscript), &peer->them.commitkey, - &peer->cur_commit_theirsig)) + &peer->cur_commit.theirsig)) return pkt_err(ctx, "Bad signature"); return NULL; diff --git a/daemon/peer.c b/daemon/peer.c index d78539451..b30e41b8b 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -344,6 +345,7 @@ static struct peer *new_peer(struct lightningd_state *dstate, peer->cstate = NULL; peer->close_watch_timeout = NULL; peer->anchor.watches = NULL; + peer->cur_commit.watch = NULL; /* If we free peer, conn should be closed, but can't be freed * immediately so don't make peer a parent. */ @@ -728,17 +730,100 @@ void peer_unwatch_anchor_depth(struct peer *peer, peer->anchor.watches = tal_free(peer->anchor.watches); } +static void commit_tx_depth(struct peer *peer, int depth, + const struct sha256_double *blkhash, + ptrint_t *canspend) +{ + log_debug(peer->log, "Commit tx reached depth %i", depth); + /* FIXME: Handle locktime in blocks, as well as seconds! */ + + /* Fell out of a block? */ + if (depth < 0) { + /* Forget any old block. */ + peer->cur_commit.start_time = 0; + memset(&peer->cur_commit.blockid, 0xFF, + sizeof(peer->cur_commit.blockid)); + return; + } + + /* In a new block? */ + if (!structeq(blkhash, &peer->cur_commit.blockid)) { + peer->cur_commit.start_time = 0; + peer->cur_commit.blockid = *blkhash; + bitcoind_get_mediantime(peer->dstate, blkhash, + &peer->cur_commit.start_time); + return; + } + + /* Don't yet know the median start time? */ + if (!peer->cur_commit.start_time) + return; + + /* FIXME: We should really use bitcoin time here. */ + if (controlled_time().ts.tv_sec > peer->cur_commit.start_time + + rel_locktime_to_seconds(&peer->them.locktime)) { + /* Free this watch; we're done */ + peer->cur_commit.watch = tal_free(peer->cur_commit.watch); + state_event(peer, ptr2int(canspend), NULL); + } +} + +/* FIXME: We tell bitcoind to watch all the outputs, which is overkill */ +static void watch_tx_outputs(struct peer *peer, const struct bitcoin_tx *tx) +{ + varint_t i; + + for (i = 0; i < tx->output_count; i++) { + struct ripemd160 redeemhash; + if (!is_p2sh(tx->output[i].script, tx->output[i].script_length)) + fatal("Unexpected non-p2sh output"); + memcpy(&redeemhash, tx->output[i].script+2, sizeof(redeemhash)); + bitcoind_watch_addr(peer->dstate, &redeemhash); + } +} + +/* Watch the commit tx until our side is spendable. */ void peer_watch_delayed(struct peer *peer, const struct bitcoin_tx *tx, enum state_input canspend) { - FIXME_STUB(peer); + struct sha256_double txid; + + assert(tx == peer->us.commit); + bitcoin_txid(tx, &txid); + memset(&peer->cur_commit.blockid, 0xFF, + sizeof(peer->cur_commit.blockid)); + peer->cur_commit.watch + = add_commit_tx_watch(tx, peer, &txid, commit_tx_depth, + int2ptr(canspend)); + + watch_tx_outputs(peer, tx); } + +static void spend_tx_done(struct peer *peer, int depth, + const struct sha256_double *blkhash, + ptrint_t *done) +{ + log_debug(peer->log, "tx reached depth %i", depth); + if (depth >= (int)peer->dstate->config.forever_confirms) + state_event(peer, ptr2int(done), NULL); +} + +/* Watch this tx until it's buried enough to be forgotten. */ void peer_watch_tx(struct peer *peer, const struct bitcoin_tx *tx, enum state_input done) { - FIXME_STUB(peer); + struct sha256_double txid; + + bitcoin_txid(tx, &txid); + log_debug(peer->log, "Watching tx %02x%02x%02x%02x...", + txid.sha.u.u8[0], + txid.sha.u.u8[1], + txid.sha.u.u8[2], + txid.sha.u.u8[3]); + + add_commit_tx_watch(tx, peer, &txid, spend_tx_done, int2ptr(done)); } bool peer_create_close_tx(struct peer *peer, u64 fee_satoshis) @@ -914,14 +999,18 @@ const struct bitcoin_tx *bitcoin_close(const tal_t *ctx, const struct bitcoin_tx *bitcoin_spend_ours(const tal_t *ctx, const struct peer *peer) { -#if 0 u8 *redeemscript; + const struct bitcoin_tx *commit = peer->us.commit; + struct bitcoin_signature sig; + struct bitcoin_tx *tx; + unsigned int p2sh_out; + /* The redeemscript for a commit tx is fairly complex. */ redeemscript = bitcoin_redeem_secret_or_delay(ctx, - &peer->us.commitkey, + &peer->us.finalkey, &peer->them.locktime, - &peer->them.commitkey, - &peer->revocation_hash); + &peer->them.finalkey, + &peer->us.revocation_hash); /* Now, create transaction to spend it. */ tx = bitcoin_tx(ctx, 1, 1); @@ -929,30 +1018,31 @@ const struct bitcoin_tx *bitcoin_spend_ours(const tal_t *ctx, p2sh_out = find_p2sh_out(commit, redeemscript); tx->input[0].index = p2sh_out; tx->input[0].input_amount = commit->output[p2sh_out].amount; - tx->fee = fee; + /* FIXME: Dynamic fee! */ + tx->fee = peer->dstate->config.closing_fee; - tx->input[0].sequence_number = bitcoin_nsequence(locktime); + tx->input[0].sequence_number = bitcoin_nsequence(&peer->them.locktime); - if (commit->output[p2sh_out].amount <= fee) - errx(1, "Amount of %llu won't exceed fee", - (unsigned long long)commit->output[p2sh_out].amount); + /* FIXME: In this case, we shouldn't do anything (not worth + * collecting) */ + if (commit->output[p2sh_out].amount <= tx->fee) + fatal("Amount of %"PRIu64" won't cover fee", + commit->output[p2sh_out].amount); - tx->output[0].amount = commit->output[p2sh_out].amount - fee; + tx->output[0].amount = commit->output[p2sh_out].amount - tx->fee; tx->output[0].script = scriptpubkey_p2sh(tx, - bitcoin_redeem_single(tx, &outpubkey)); + bitcoin_redeem_single(tx, &peer->us.finalkey)); tx->output[0].script_length = tal_count(tx->output[0].script); /* Now get signature, to set up input script. */ - if (!sign_tx_input(tx, 0, redeemscript, tal_count(redeemscript), - &privkey, &pubkey1, &sig.sig)) - errx(1, "Could not sign tx"); sig.stype = SIGHASH_ALL; + peer_sign_spend(peer, tx, redeemscript, &sig.sig); tx->input[0].script = scriptsig_p2sh_secret(tx, NULL, 0, &sig, redeemscript, tal_count(redeemscript)); tx->input[0].script_length = tal_count(tx->input[0].script); -#endif - FIXME_STUB(peer); + + return tx; } /* Create a bitcoin spend tx (to spend their commit's outputs) */ @@ -971,10 +1061,27 @@ const struct bitcoin_tx *bitcoin_steal(const tal_t *ctx, FIXME_STUB(peer); } -/* Create our commit tx */ +/* Sign and return our commit tx */ const struct bitcoin_tx *bitcoin_commit(const tal_t *ctx, struct peer *peer) { - FIXME_STUB(peer); + struct bitcoin_signature sig; + + /* Can't be signed already! */ + assert(peer->us.commit->input[0].script_length == 0); + + sig.stype = SIGHASH_ALL; + peer_sign_ourcommit(peer, peer->us.commit, &sig.sig); + + peer->us.commit->input[0].script + = scriptsig_p2sh_2of2(peer->us.commit, + &peer->cur_commit.theirsig, + &sig, + &peer->them.commitkey, + &peer->us.commitkey); + peer->us.commit->input[0].script_length + = tal_count(peer->us.commit->input[0].script); + + return peer->us.commit; } /* Create a HTLC refund collection */ diff --git a/daemon/peer.h b/daemon/peer.h index 77e884e34..74b24f90e 100644 --- a/daemon/peer.h +++ b/daemon/peer.h @@ -11,6 +11,7 @@ #include "state.h" #include #include +#include struct peer_visible_state { /* CMD_OPEN_WITH_ANCHOR or CMD_OPEN_WITHOUT_ANCHOR */ @@ -97,8 +98,16 @@ struct peer { struct anchor_watch *watches; } anchor; - /* Their signature for our current commit sig. */ - struct bitcoin_signature cur_commit_theirsig; + struct { + /* Their signature for our current commit sig. */ + struct bitcoin_signature theirsig; + /* When it entered a block (mediantime). */ + u32 start_time; + /* Which block it entered. */ + struct sha256_double blockid; + /* The watch we have on a live commit tx. */ + struct txwatch *watch; + } cur_commit; /* Current HTLC, if any. */ struct htlc_progress *current_htlc; diff --git a/daemon/secrets.c b/daemon/secrets.c index 17118b200..150f772fb 100644 --- a/daemon/secrets.c +++ b/daemon/secrets.c @@ -55,6 +55,35 @@ void peer_sign_theircommit(const struct peer *peer, sig); } +void peer_sign_ourcommit(const struct peer *peer, + struct bitcoin_tx *commit, + struct signature *sig) +{ + /* Commit tx only has one input: that of the anchor. */ + sign_tx_input(peer->dstate->secpctx, + commit, 0, + peer->anchor.redeemscript, + tal_count(peer->anchor.redeemscript), + &peer->secrets->commit, + &peer->us.commitkey, + sig); +} + +void peer_sign_spend(const struct peer *peer, + struct bitcoin_tx *spend, + const u8 *commit_redeemscript, + struct signature *sig) +{ + /* Spend tx only has one input: that of the commit tx. */ + sign_tx_input(peer->dstate->secpctx, + spend, 0, + commit_redeemscript, + tal_count(commit_redeemscript), + &peer->secrets->final, + &peer->us.finalkey, + sig); +} + void peer_sign_mutual_close(const struct peer *peer, struct bitcoin_tx *close, struct signature *sig) diff --git a/daemon/secrets.h b/daemon/secrets.h index 48ebba57f..4e1b974e6 100644 --- a/daemon/secrets.h +++ b/daemon/secrets.h @@ -16,6 +16,15 @@ void peer_sign_theircommit(const struct peer *peer, struct bitcoin_tx *commit, struct signature *sig); +void peer_sign_ourcommit(const struct peer *peer, + struct bitcoin_tx *commit, + struct signature *sig); + +void peer_sign_spend(const struct peer *peer, + struct bitcoin_tx *spend, + const u8 *commit_redeemscript, + struct signature *sig); + void peer_sign_mutual_close(const struct peer *peer, struct bitcoin_tx *close, struct signature *sig); diff --git a/daemon/test/test.sh b/daemon/test/test.sh index b25b3e026..89de055f4 100755 --- a/daemon/test/test.sh +++ b/daemon/test/test.sh @@ -54,6 +54,18 @@ check_status() fi } +check_tx_spend() +{ + $CLI generate 1 + if [ $($CLI getblock $($CLI getbestblockhash) | grep -c '^ "') = 2 ]; then + : + else + echo "Block didn't include tx:" >&2 + $($CLI getblock $($CLI getbestblockhash) ) >&2 + exit 1 + fi +} + all_ok() { scripts/shutdown.sh @@ -99,10 +111,12 @@ $LCLI1 getpeers | grep STATE_OPEN_WAITING_OURANCHOR $LCLI2 getpeers | grep STATE_OPEN_WAITING_THEIRANCHOR if [ "x$1" = x"--timeout-anchor" ]; then - # Timeout before anchor committed. + # Anchor gets 1 commit. + check_tx_spend + + # Timeout before anchor committed deep enough. TIME=$((`date +%s` + 7200 + 3 * 1200 + 1)) - # This will crash in a moment. $LCLI1 dev-mocktime $TIME # This will crash immediately @@ -110,26 +124,52 @@ if [ "x$1" = x"--timeout-anchor" ]; then echo Node2 did not crash >&2 exit 1 fi + fgrep 'Entered error state STATE_ERR_ANCHOR_TIMEOUT' $DIR2/crash.log sleep 1 - # Check crash logs - if [ ! -f $DIR1/crash.log ]; then - echo Node1 did not crash >&2 - exit 1 - fi - if [ ! -f $DIR2/crash.log ]; then - echo Node2 did not crash >&2 - exit 1 - fi + # It should send out commit tx. + $LCLI1 getpeers | fgrep -w STATE_CLOSE_WAIT_CLOSE_OURCOMMIT - fgrep 'Entered error state STATE_ERR_ANCHOR_TIMEOUT' $DIR2/crash.log + # Generate a block (should include commit tx) + check_tx_spend + + # Now "wait" for 1 day, which is what node2 asked for on commit. + TIME=$(($TIME + 24 * 60 * 60)) + $LCLI1 dev-mocktime $TIME + + # Due to laziness, we trigger by block generation. + $CLI generate 1 + TIME=$(($TIME + 1)) + $LCLI1 dev-mocktime $TIME + sleep 1 + + # Sometimes it skips poll because it's busy. Do it again. + TIME=$(($TIME + 1)) + $LCLI1 dev-mocktime $TIME + sleep 1 + + $LCLI1 getpeers | fgrep -w STATE_CLOSE_WAIT_CLOSE_SPENDOURS + + # Now it should have spent the commit tx. + check_tx_spend + + # 99 more blocks pass... + $CLI generate 99 + TIME=$(($TIME + 1)) + $LCLI1 dev-mocktime $TIME + sleep 1 + + # Considers it all done now. + $LCLI1 getpeers | tr -s '\012\011 ' ' ' | fgrep '"peers" : [ ]' + + $LCLI1 stop all_ok fi - -# Now make it pass anchor. -$CLI generate 3 +# Now make it pass anchor (should be in first block, then two more to bury it) +check_tx_spend +$CLI generate 2 # They poll every second, so give them time to process. sleep 2 diff --git a/daemon/watch.c b/daemon/watch.c index 43e2fb504..7d231fb40 100644 --- a/daemon/watch.c +++ b/daemon/watch.c @@ -178,15 +178,15 @@ void add_anchor_watch_(const tal_t *ctx, bitcoind_watch_addr(peer->dstate, &redeemhash); } -void add_commit_tx_watch_(const tal_t *ctx, - struct peer *peer, - const struct sha256_double *txid, - void (*cb)(struct peer *peer, int depth, - const struct sha256_double *blkhash, - void *), - void *cbdata) +struct txwatch *add_commit_tx_watch_(const tal_t *ctx, + struct peer *peer, + const struct sha256_double *txid, + void (*cb)(struct peer *peer, int depth, + const struct sha256_double *blkhash, + void *), + void *cbdata) { - insert_txwatch(ctx, peer, txid, cb, cbdata); + return insert_txwatch(ctx, peer, txid, cb, cbdata); /* We are already watching the anchor txo, so we don't need to * watch anything else. */ diff --git a/daemon/watch.h b/daemon/watch.h index 37ff98b6e..eda5d4d89 100644 --- a/daemon/watch.h +++ b/daemon/watch.h @@ -87,13 +87,13 @@ void add_anchor_watch_(const tal_t *ctx, const struct bitcoin_tx *), \ (cbdata)) -void add_commit_tx_watch_(const tal_t *ctx, - struct peer *peer, - const struct sha256_double *txid, - void (*cb)(struct peer *peer, int depth, - const struct sha256_double *blkhash, - void *), - void *cbdata); +struct txwatch *add_commit_tx_watch_(const tal_t *ctx, + struct peer *peer, + const struct sha256_double *txid, + void (*cb)(struct peer *peer, int depth, + const struct sha256_double *blkhash, + void *), + void *cbdata); #define add_commit_tx_watch(ctx, peer, txid, cb, cbdata) \ add_commit_tx_watch_((ctx), (peer), (txid), \ diff --git a/find_p2sh_out.c b/find_p2sh_out.c index 8fe9db223..5eb6aa7b6 100644 --- a/find_p2sh_out.c +++ b/find_p2sh_out.c @@ -17,6 +17,7 @@ u32 find_p2sh_out(const struct bitcoin_tx *tx, u8 *redeemscript) if (memcmp(tx->output[i].script, p2sh, tal_count(p2sh)) == 0) break; } + /* FIXME: Return failure! */ if (i == tx->output_count) errx(1, "No matching output in tx"); tal_free(p2sh);