mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
daemon: handle cheating.
As per onchain.md. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
4cb6cd1f90
commit
5e40b264dd
132
daemon/peer.c
132
daemon/peer.c
@ -782,7 +782,7 @@ static struct channel_htlc *htlc_by_index(const struct commit_info *ci,
|
||||
return cast_const(struct channel_htlc *, ci->cstate->b.htlcs) + index;
|
||||
}
|
||||
|
||||
static UNNEEDED bool htlc_a_offered(struct commit_info *ci, size_t index)
|
||||
static bool htlc_a_offered(const struct commit_info *ci, size_t index)
|
||||
{
|
||||
assert(index >= 2);
|
||||
index -= 2;
|
||||
@ -872,9 +872,137 @@ static const struct bitcoin_tx *irrevocably_resolved(struct peer *peer)
|
||||
return peer->closing_onchain.tx;
|
||||
}
|
||||
|
||||
static void connect_input(const struct commit_info *ci,
|
||||
struct bitcoin_tx_input *input,
|
||||
u32 index)
|
||||
{
|
||||
bitcoin_txid(ci->tx, &input->txid);
|
||||
input->index = index;
|
||||
input->amount = tal_dup(ci, u64, &ci->tx->output[index].amount);
|
||||
}
|
||||
|
||||
static void resolve_cheating(struct peer *peer)
|
||||
{
|
||||
FIXME_STUB(peer);
|
||||
const struct bitcoin_tx *tx = peer->closing_onchain.tx;
|
||||
const struct commit_info *ci = peer->closing_onchain.ci;
|
||||
struct bitcoin_tx *steal_tx;
|
||||
u8 **wscripts;
|
||||
size_t i, n, num_to_steal;
|
||||
|
||||
peer->closing_onchain.resolved
|
||||
= tal_arrz(tx, const struct bitcoin_tx *, tal_count(ci->map));
|
||||
|
||||
/* BOLT #onchain:
|
||||
*
|
||||
* If a node sees a *commitment tx* for which it has a revocation
|
||||
* preimage, it *resolves* the funding transaction output:
|
||||
*
|
||||
* 1. _A's main output_: No action is required; this is a
|
||||
* simple P2WPKH output. This output is considered
|
||||
* *resolved* by the *commitment tx*.
|
||||
*/
|
||||
|
||||
/* Their commit tx, so our output is [1], theirs in [0]. */
|
||||
peer->closing_onchain.resolved[1] = tx;
|
||||
|
||||
/* BOLT #onchain:
|
||||
*
|
||||
* 2. _B's main output_: The node MUST *resolve* this by
|
||||
* spending using the revocation preimage.
|
||||
*
|
||||
* 3. _A's offered HTLCs_: The node MUST *resolve* this by
|
||||
* spending using the revocation preimage.
|
||||
*
|
||||
* 4. _B's offered HTLCs_: The node MUST *resolve* this by
|
||||
* spending using the revocation preimage. */
|
||||
num_to_steal = 0;
|
||||
if (ci->map[0] == -1)
|
||||
peer->closing_onchain.resolved[0] = tx;
|
||||
else
|
||||
num_to_steal++;
|
||||
|
||||
for (i = 2; i < tal_count(ci->map); i++)
|
||||
if (ci->map[i] == -1)
|
||||
peer->closing_onchain.resolved[i] = tx;
|
||||
else
|
||||
num_to_steal++;
|
||||
|
||||
/* Nothing to steal? */
|
||||
if (num_to_steal == 0)
|
||||
return;
|
||||
|
||||
/* BOLT #onchain:
|
||||
*
|
||||
* The node MAY use a single transaction to *resolve* all the
|
||||
* outputs; due to the 450 HTLC-per-party limit (See BOLT #2:
|
||||
* 3.2. Adding an HTLC) this can be done within a standard
|
||||
* transaction.
|
||||
*/
|
||||
steal_tx = bitcoin_tx(peer, num_to_steal, 1);
|
||||
|
||||
wscripts = tal_arr(steal_tx, u8 *, num_to_steal);
|
||||
|
||||
n = 0;
|
||||
if (ci->map[0] != -1) {
|
||||
connect_input(ci, &steal_tx->input[n], ci->map[0]);
|
||||
wscripts[n++]
|
||||
= bitcoin_redeem_secret_or_delay(wscripts,
|
||||
&peer->them.finalkey,
|
||||
&peer->us.locktime,
|
||||
&peer->us.finalkey,
|
||||
&ci->revocation_hash);
|
||||
}
|
||||
|
||||
for (i = 2; i < tal_count(ci->map); i++) {
|
||||
struct channel_htlc *h;
|
||||
|
||||
if (ci->map[i] == -1)
|
||||
continue;
|
||||
|
||||
peer->closing_onchain.resolved[i] = steal_tx;
|
||||
|
||||
connect_input(ci, &steal_tx->input[n], ci->map[i]);
|
||||
|
||||
h = htlc_by_index(ci, i);
|
||||
if (htlc_a_offered(ci, i)) {
|
||||
wscripts[n]
|
||||
= bitcoin_redeem_htlc_send(wscripts,
|
||||
&peer->them.finalkey,
|
||||
&peer->us.finalkey,
|
||||
&h->expiry,
|
||||
&peer->us.locktime,
|
||||
&ci->revocation_hash,
|
||||
&h->rhash);
|
||||
} else {
|
||||
wscripts[n]
|
||||
= bitcoin_redeem_htlc_recv(wscripts,
|
||||
&peer->them.finalkey,
|
||||
&peer->us.finalkey,
|
||||
&h->expiry,
|
||||
&peer->us.locktime,
|
||||
&ci->revocation_hash,
|
||||
&h->rhash);
|
||||
}
|
||||
n++;
|
||||
}
|
||||
assert(n == num_to_steal);
|
||||
|
||||
/* Now, we can sign them all (they're all of same form). */
|
||||
for (n = 0; n < num_to_steal; n++) {
|
||||
struct bitcoin_signature sig;
|
||||
|
||||
sig.stype = SIGHASH_ALL;
|
||||
peer_sign_steal_input(peer, steal_tx, n, wscripts[n], &sig.sig);
|
||||
|
||||
steal_tx->input[n].witness
|
||||
= bitcoin_witness_secret(steal_tx,
|
||||
ci->revocation_preimage,
|
||||
sizeof(*ci->revocation_preimage),
|
||||
&sig,
|
||||
wscripts[n]);
|
||||
}
|
||||
|
||||
broadcast_tx(peer, steal_tx);
|
||||
}
|
||||
|
||||
static void our_htlc_spent(struct peer *peer,
|
||||
|
@ -112,6 +112,22 @@ void peer_sign_mutual_close(const struct peer *peer,
|
||||
sig);
|
||||
}
|
||||
|
||||
void peer_sign_steal_input(const struct peer *peer,
|
||||
struct bitcoin_tx *spend,
|
||||
size_t i,
|
||||
const u8 *witnessscript,
|
||||
struct signature *sig)
|
||||
{
|
||||
/* Spend tx only has one input: that of the commit tx. */
|
||||
sign_tx_input(peer->dstate->secpctx,
|
||||
spend, i,
|
||||
NULL, 0,
|
||||
witnessscript,
|
||||
&peer->secrets->final,
|
||||
&peer->us.finalkey,
|
||||
sig);
|
||||
}
|
||||
|
||||
static void new_keypair(struct lightningd_state *dstate,
|
||||
struct privkey *privkey, struct pubkey *pubkey)
|
||||
{
|
||||
|
@ -34,6 +34,12 @@ void peer_sign_mutual_close(const struct peer *peer,
|
||||
struct bitcoin_tx *close,
|
||||
struct signature *sig);
|
||||
|
||||
void peer_sign_steal_input(const struct peer *peer,
|
||||
struct bitcoin_tx *spend,
|
||||
size_t i,
|
||||
const u8 *witnessscript,
|
||||
struct signature *sig);
|
||||
|
||||
void peer_secrets_init(struct peer *peer);
|
||||
|
||||
void peer_get_revocation_hash(const struct peer *peer, u64 index,
|
||||
|
Loading…
Reference in New Issue
Block a user