daemon: fix logic which determines how anchor output was spent.

We watch the anchor output, and separate it into different cases.
This is simpler with segwit (txids are known before sigs), but we also
had missed the case of our own commit transaction spend.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2016-05-03 11:06:20 +09:30
parent eb5d832963
commit 12b37d5f80
3 changed files with 35 additions and 45 deletions

View File

@ -703,45 +703,26 @@ static void anchor_depthchange(struct peer *peer, int depth,
}
}
/* We don't compare scriptSigs: we don't know them anyway! */
static bool txmatch(const struct bitcoin_tx *txa, const struct bitcoin_tx *txb)
/* Yay, segwit! We can just compare txids, even though we don't have both
* signatures. */
static bool txidmatch(const struct bitcoin_tx *tx,
const struct sha256_double *txid)
{
size_t i;
struct sha256_double tx_txid;
if (txa->version != txb->version
|| txa->input_count != txb->input_count
|| txa->output_count != txb->output_count
|| txa->lock_time != txb->lock_time)
return false;
for (i = 0; i < txa->input_count; i++) {
if (!structeq(&txa->input[i].txid, &txb->input[i].txid)
|| txa->input[i].index != txb->input[i].index
|| txa->input[i].sequence_number != txb->input[i].sequence_number)
return false;
}
for (i = 0; i < txa->output_count; i++) {
if (txa->output[i].amount != txb->output[i].amount
|| txa->output[i].script_length != txb->output[i].script_length
|| memcmp(txa->output[i].script, txb->output[i].script,
txa->output[i].script_length != 0))
return false;
}
return true;
bitcoin_txid(tx, &tx_txid);
return structeq(txid, &tx_txid);
}
/* We may have two possible "current" commits; this loop will check them both. */
static bool is_unrevoked_commit(const struct commit_info *ci,
const struct bitcoin_tx *tx)
static struct commit_info *find_commit(struct commit_info *ci,
const struct sha256_double *txid)
{
while (ci && !ci->revocation_preimage) {
if (txmatch(ci->tx, tx))
return true;
while (ci) {
if (txidmatch(ci->tx, txid))
return ci;
ci = ci->prev;
}
return false;
return NULL;
}
static bool is_mutual_close(const struct peer *peer,
@ -792,21 +773,30 @@ static void anchor_spent(struct peer *peer,
{
struct anchor_watch *w = peer->anchor.watches;
union input idata;
struct sha256_double txid;
assert(input_num < tx->input_count);
/* We only ever sign single-input txs. */
if (input_num != 0)
fatal("Anchor spend by non-single input tx");
/* FIXME: change type in idata? */
idata.btc = (struct bitcoin_event *)tx;
if (is_unrevoked_commit(peer->them.commit, tx))
state_event(peer, w->theyspent, &idata);
else if (is_mutual_close(peer, tx))
bitcoin_txid(tx, &txid);
idata.ci = find_commit(peer->them.commit, &txid);
if (idata.ci) {
if (idata.ci->revocation_preimage)
state_event(peer, w->otherspent, &idata);
else {
idata.tx = idata.ci->tx;
state_event(peer, w->theyspent, &idata);
}
} else if (is_mutual_close(peer, tx)) {
watch_tx(peer, peer, tx, close_depth_cb, NULL);
else
state_event(peer, w->otherspent, &idata);
} else {
if (!txidmatch(peer->us.commit->tx, &txid))
fatal("Unknown tx spend!");
}
}
static void anchor_timeout(struct anchor_watch *w)
@ -1224,7 +1214,7 @@ const struct bitcoin_tx *bitcoin_spend_ours(struct peer *peer)
/* Create a bitcoin steal tx (to steal all their commit's outputs) */
const struct bitcoin_tx *bitcoin_steal(const struct peer *peer,
struct bitcoin_event *btc)
struct commit_info *ci)
{
FIXME_STUB(peer);
}

View File

@ -757,7 +757,7 @@ enum command_status state(struct peer *peer,
return next_state_bits(peer, cstatus, bits);
/* This can happen multiple times: need to steal ALL */
} else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) {
tx = bitcoin_steal(peer, idata->btc);
tx = bitcoin_steal(peer, idata->ci);
if (!tx)
return next_state(peer, cstatus,
STATE_ERR_INFORMATION_LEAK);
@ -953,7 +953,7 @@ old_commit_spotted:
set_peer_cond(peer, PEER_CLOSED);
/* If we can't find it, we're lost. */
tx = bitcoin_steal(peer, idata->btc);
tx = bitcoin_steal(peer, idata->ci);
if (!tx)
return next_state(peer, cstatus,
STATE_ERR_INFORMATION_LEAK);

View File

@ -30,9 +30,9 @@ static inline bool input_is_pkt(enum state_input input)
union input {
Pkt *pkt;
struct command *cmd;
struct bitcoin_event *btc;
struct bitcoin_tx *tx;
struct htlc_progress *htlc_prog;
struct commit_info *ci;
struct htlc_onchain {
/* Which commitment we using. */
struct commit_info *ci;
@ -321,7 +321,7 @@ const struct bitcoin_tx *bitcoin_spend_ours(struct peer *peer);
/* Create a bitcoin steal tx (to steal all their commit's outputs) */
const struct bitcoin_tx *bitcoin_steal(const struct peer *peer,
struct bitcoin_event *btc);
struct commit_info *ci);
/* Create our commit tx */
const struct bitcoin_tx *bitcoin_commit(struct peer *peer);