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 <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2016-01-22 06:45:28 +10:30
parent 27eedc9f51
commit 862509637b
10 changed files with 256 additions and 58 deletions

View File

@ -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,

View File

@ -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;

View File

@ -20,6 +20,7 @@
#include <ccan/io/io.h>
#include <ccan/list/list.h>
#include <ccan/noerr/noerr.h>
#include <ccan/ptrint/ptrint.h>
#include <ccan/str/hex/hex.h>
#include <ccan/structeq/structeq.h>
#include <ccan/tal/str/str.h>
@ -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 */

View File

@ -11,6 +11,7 @@
#include "state.h"
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/list/list.h>
#include <ccan/time/time.h>
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;

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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. */

View File

@ -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), \

View File

@ -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);