mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
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:
parent
27eedc9f51
commit
862509637b
@ -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,
|
||||
|
@ -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;
|
||||
|
147
daemon/peer.c
147
daemon/peer.c
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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), \
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user