mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
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:
parent
eb5d832963
commit
12b37d5f80
@ -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;
|
||||
bitcoin_txid(tx, &tx_txid);
|
||||
return structeq(txid, &tx_txid);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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,6 +773,7 @@ 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);
|
||||
|
||||
@ -799,14 +781,22 @@ static void anchor_spent(struct peer *peer,
|
||||
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))
|
||||
watch_tx(peer, peer, tx, close_depth_cb, NULL);
|
||||
else
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
4
state.c
4
state.c
@ -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);
|
||||
|
4
state.h
4
state.h
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user