mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 15:44:21 +01:00
daemon: handle cheating.
As per onchain.md. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
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;
|
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);
|
assert(index >= 2);
|
||||||
index -= 2;
|
index -= 2;
|
||||||
@@ -872,9 +872,137 @@ static const struct bitcoin_tx *irrevocably_resolved(struct peer *peer)
|
|||||||
return peer->closing_onchain.tx;
|
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)
|
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,
|
static void our_htlc_spent(struct peer *peer,
|
||||||
|
|||||||
@@ -112,6 +112,22 @@ void peer_sign_mutual_close(const struct peer *peer,
|
|||||||
sig);
|
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,
|
static void new_keypair(struct lightningd_state *dstate,
|
||||||
struct privkey *privkey, struct pubkey *pubkey)
|
struct privkey *privkey, struct pubkey *pubkey)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ void peer_sign_mutual_close(const struct peer *peer,
|
|||||||
struct bitcoin_tx *close,
|
struct bitcoin_tx *close,
|
||||||
struct signature *sig);
|
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_secrets_init(struct peer *peer);
|
||||||
|
|
||||||
void peer_get_revocation_hash(const struct peer *peer, u64 index,
|
void peer_get_revocation_hash(const struct peer *peer, u64 index,
|
||||||
|
|||||||
Reference in New Issue
Block a user