Rusty Russell
7 years ago
committed by
Christian Decker
68 changed files with 75 additions and 14951 deletions
@ -1 +1 @@ |
|||
from .lightning import LightningRpc, LegacyLightningRpc |
|||
from .lightning import LightningRpc |
|||
|
@ -1,359 +0,0 @@ |
|||
#include "channel.h" |
|||
#include "htlc.h" |
|||
#include "remove_dust.h" |
|||
#include "type_to_string.h" |
|||
#include <assert.h> |
|||
#include <ccan/array_size/array_size.h> |
|||
#include <ccan/mem/mem.h> |
|||
#include <ccan/structeq/structeq.h> |
|||
#include <ccan/tal/str/str.h> |
|||
#include <inttypes.h> |
|||
#include <string.h> |
|||
|
|||
uint64_t fee_by_feerate(size_t txsize, uint64_t fee_rate) |
|||
{ |
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* The fee for a transaction MUST be calculated by multiplying this |
|||
* bytecount by the fee rate, dividing by 1000 and truncating |
|||
* (rounding down) the result to an even number of satoshis. |
|||
*/ |
|||
return txsize * fee_rate / 2000 * 2; |
|||
} |
|||
|
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* A node MUST use the formula 338 + 32 bytes for every non-dust HTLC |
|||
* as the bytecount for calculating commitment transaction fees. Note |
|||
* that the fee requirement is unchanged, even if the elimination of |
|||
* dust HTLC outputs has caused a non-zero fee already. |
|||
*/ |
|||
static size_t tx_bytes(size_t num_nondust_htlcs) |
|||
{ |
|||
return 338 + 32 * num_nondust_htlcs; |
|||
} |
|||
|
|||
static uint64_t calculate_fee_msat(size_t num_nondust_htlcs, |
|||
uint64_t fee_rate) |
|||
{ |
|||
/* milli-satoshis */ |
|||
return fee_by_feerate(tx_bytes(num_nondust_htlcs), fee_rate) * 1000; |
|||
} |
|||
|
|||
/* Pay this much fee, if possible. Return amount unpaid. */ |
|||
static uint64_t pay_fee(struct channel_oneside *side, uint64_t fee_msat) |
|||
{ |
|||
if (side->pay_msat >= fee_msat) { |
|||
side->pay_msat -= fee_msat; |
|||
side->fee_msat += fee_msat; |
|||
return 0; |
|||
} else { |
|||
uint64_t remainder = fee_msat - side->pay_msat; |
|||
side->fee_msat += side->pay_msat; |
|||
side->pay_msat = 0; |
|||
return remainder; |
|||
} |
|||
} |
|||
|
|||
/* Charge the fee as per FIXME-OLD #2 */ |
|||
static void recalculate_fees(struct channel_oneside *a, |
|||
struct channel_oneside *b, |
|||
uint64_t fee_msat) |
|||
{ |
|||
uint64_t remainder; |
|||
|
|||
/* Fold in fees, to recalcuate again below. */ |
|||
a->pay_msat += a->fee_msat; |
|||
b->pay_msat += b->fee_msat; |
|||
a->fee_msat = b->fee_msat = 0; |
|||
|
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* 1. If each nodes can afford half the fee from their |
|||
* to-`final_key` output, reduce the two to-`final_key` |
|||
* outputs accordingly. |
|||
* |
|||
* 2. Otherwise, reduce the to-`final_key` output of one node |
|||
* which cannot afford the fee to zero (resulting in that |
|||
* entire output paying fees). If the remaining |
|||
* to-`final_key` output is greater than the fee remaining, |
|||
* reduce it accordingly, otherwise reduce it to zero to |
|||
* pay as much fee as possible. |
|||
*/ |
|||
remainder = pay_fee(a, fee_msat / 2) + pay_fee(b, fee_msat / 2); |
|||
|
|||
/* If there's anything left, the other side tries to pay for it. */ |
|||
remainder = pay_fee(a, remainder); |
|||
pay_fee(b, remainder); |
|||
} |
|||
|
|||
/* a transfers htlc_msat to a HTLC (gains it, if -ve) */ |
|||
static bool change_funding(uint64_t anchor_satoshis, |
|||
uint64_t fee_rate, |
|||
int64_t htlc_msat, |
|||
struct channel_oneside *a, |
|||
struct channel_oneside *b, |
|||
size_t num_nondust_htlcs, |
|||
bool must_afford_fee) |
|||
{ |
|||
uint64_t fee_msat; |
|||
uint64_t htlcs_total; |
|||
|
|||
htlcs_total = anchor_satoshis * 1000 |
|||
- (a->pay_msat + a->fee_msat + b->pay_msat + b->fee_msat); |
|||
|
|||
fee_msat = calculate_fee_msat(num_nondust_htlcs, fee_rate); |
|||
|
|||
/* If A is paying, can it afford it? */ |
|||
if (htlc_msat >= 0) { |
|||
uint64_t cost = htlc_msat; |
|||
if (must_afford_fee) |
|||
cost += fee_msat / 2; |
|||
if (cost > a->pay_msat + a->fee_msat) |
|||
return false; |
|||
} |
|||
|
|||
/* OK, now adjust funds for A, then recalculate fees. */ |
|||
a->pay_msat -= htlc_msat; |
|||
recalculate_fees(a, b, fee_msat); |
|||
|
|||
htlcs_total += htlc_msat; |
|||
assert(htlcs_total == anchor_satoshis * 1000 |
|||
- (a->pay_msat + a->fee_msat + b->pay_msat + b->fee_msat)); |
|||
return true; |
|||
} |
|||
|
|||
bool anchor_too_large(uint64_t anchor_satoshis) |
|||
{ |
|||
/* Anchor must fit in 32 bit. */ |
|||
return anchor_satoshis >= (1ULL << 32) / 1000; |
|||
} |
|||
|
|||
struct channel_state *initial_cstate(const tal_t *ctx, |
|||
uint64_t anchor_satoshis, |
|||
uint64_t fee_rate, |
|||
enum side funding) |
|||
{ |
|||
uint64_t fee_msat; |
|||
struct channel_state *cstate = talz(ctx, struct channel_state); |
|||
struct channel_oneside *funder, *fundee; |
|||
|
|||
cstate->fee_rate = fee_rate; |
|||
cstate->anchor = anchor_satoshis; |
|||
cstate->num_nondust = 0; |
|||
|
|||
/* Anchor must fit in 32 bit. */ |
|||
assert(!anchor_too_large(anchor_satoshis)); |
|||
|
|||
fee_msat = calculate_fee_msat(0, fee_rate); |
|||
if (fee_msat > anchor_satoshis * 1000) |
|||
return tal_free(cstate); |
|||
|
|||
funder = &cstate->side[funding]; |
|||
fundee = &cstate->side[!funding]; |
|||
|
|||
/* Neither side has HTLCs. */ |
|||
funder->num_htlcs = fundee->num_htlcs = 0; |
|||
|
|||
/* Initially, all goes back to funder. */ |
|||
funder->pay_msat = anchor_satoshis * 1000 - fee_msat; |
|||
funder->fee_msat = fee_msat; |
|||
|
|||
/* Make sure it checks out. */ |
|||
assert(change_funding(anchor_satoshis, fee_rate, 0, funder, fundee, 0, false)); |
|||
assert(funder->fee_msat == fee_msat); |
|||
assert(fundee->fee_msat == 0); |
|||
|
|||
return cstate; |
|||
} |
|||
|
|||
/* FIXME: Write exact variant! */ |
|||
uint64_t approx_max_feerate(const struct channel_state *cstate, |
|||
enum side side) |
|||
{ |
|||
uint64_t max_funds; |
|||
|
|||
max_funds = cstate->side[side].pay_msat + cstate->side[side].fee_msat; |
|||
|
|||
return max_funds / tx_bytes(cstate->num_nondust); |
|||
} |
|||
|
|||
bool can_afford_feerate(const struct channel_state *cstate, uint64_t fee_rate, |
|||
enum side side) |
|||
{ |
|||
u64 fee_msat = calculate_fee_msat(cstate->num_nondust, fee_rate); |
|||
|
|||
return cstate->side[side].pay_msat + cstate->side[side].fee_msat |
|||
>= fee_msat; |
|||
} |
|||
|
|||
void adjust_fee(struct channel_state *cstate, uint64_t fee_rate) |
|||
{ |
|||
uint64_t fee_msat; |
|||
|
|||
fee_msat = calculate_fee_msat(cstate->num_nondust, fee_rate); |
|||
|
|||
recalculate_fees(&cstate->side[LOCAL], &cstate->side[REMOTE], fee_msat); |
|||
} |
|||
|
|||
bool force_fee(struct channel_state *cstate, uint64_t fee) |
|||
{ |
|||
/* Beware overflow! */ |
|||
if (fee > 0xFFFFFFFFFFFFFFFFULL / 1000) |
|||
return false; |
|||
recalculate_fees(&cstate->side[LOCAL], &cstate->side[REMOTE], fee * 1000); |
|||
return cstate->side[LOCAL].fee_msat + cstate->side[REMOTE].fee_msat == fee * 1000; |
|||
} |
|||
|
|||
/* Add a HTLC to @creator if it can afford it. */ |
|||
bool cstate_add_htlc(struct channel_state *cstate, const struct htlc *htlc, |
|||
bool must_afford_fee) |
|||
{ |
|||
size_t nondust; |
|||
struct channel_oneside *creator, *recipient; |
|||
|
|||
creator = &cstate->side[htlc_owner(htlc)]; |
|||
recipient = &cstate->side[!htlc_owner(htlc)]; |
|||
|
|||
/* Remember to count the new one in total txsize if not dust! */ |
|||
nondust = cstate->num_nondust; |
|||
if (!is_dust(htlc->msatoshi / 1000)) |
|||
nondust++; |
|||
|
|||
if (!change_funding(cstate->anchor, cstate->fee_rate, |
|||
htlc->msatoshi, creator, recipient, nondust, |
|||
must_afford_fee)) |
|||
return false; |
|||
|
|||
cstate->num_nondust = nondust; |
|||
creator->num_htlcs++; |
|||
return true; |
|||
} |
|||
|
|||
/* Remove htlc from creator, credit it to beneficiary. */ |
|||
static void remove_htlc(struct channel_state *cstate, |
|||
enum side creator, |
|||
enum side beneficiary, |
|||
const struct htlc *htlc) |
|||
{ |
|||
size_t nondust; |
|||
|
|||
/* Remember to remove this one in total txsize if not dust! */ |
|||
nondust = cstate->num_nondust; |
|||
if (!is_dust(htlc->msatoshi / 1000)) { |
|||
assert(nondust > 0); |
|||
nondust--; |
|||
} |
|||
|
|||
/* Can't fail since msatoshi is positive. */ |
|||
if (!change_funding(cstate->anchor, cstate->fee_rate, |
|||
-(int64_t)htlc->msatoshi, |
|||
&cstate->side[beneficiary], |
|||
&cstate->side[!beneficiary], nondust, false)) |
|||
abort(); |
|||
|
|||
/* Actually remove the HTLC. */ |
|||
assert(cstate->side[creator].num_htlcs > 0); |
|||
cstate->side[creator].num_htlcs--; |
|||
cstate->num_nondust = nondust; |
|||
} |
|||
|
|||
void cstate_fail_htlc(struct channel_state *cstate, const struct htlc *htlc) |
|||
{ |
|||
remove_htlc(cstate, htlc_owner(htlc), htlc_owner(htlc), htlc); |
|||
} |
|||
|
|||
void cstate_fulfill_htlc(struct channel_state *cstate, const struct htlc *htlc) |
|||
{ |
|||
remove_htlc(cstate, htlc_owner(htlc), !htlc_owner(htlc), htlc); |
|||
} |
|||
|
|||
struct channel_state *copy_cstate(const tal_t *ctx, |
|||
const struct channel_state *cstate) |
|||
{ |
|||
return tal_dup(ctx, struct channel_state, cstate); |
|||
} |
|||
|
|||
void force_add_htlc(struct channel_state *cstate, const struct htlc *htlc) |
|||
{ |
|||
struct channel_oneside *creator; |
|||
|
|||
creator = &cstate->side[htlc_owner(htlc)]; |
|||
creator->num_htlcs++; |
|||
creator->pay_msat -= htlc->msatoshi; |
|||
|
|||
/* Remember to count the new one in total txsize if not dust! */ |
|||
if (!is_dust(htlc->msatoshi / 1000)) |
|||
cstate->num_nondust++; |
|||
} |
|||
|
|||
static void force_remove_htlc(struct channel_state *cstate, |
|||
enum side beneficiary, |
|||
const struct htlc *htlc) |
|||
{ |
|||
cstate->side[beneficiary].pay_msat += htlc->msatoshi; |
|||
cstate->side[htlc_owner(htlc)].num_htlcs--; |
|||
if (!is_dust(htlc->msatoshi / 1000)) |
|||
cstate->num_nondust--; |
|||
} |
|||
|
|||
void force_fail_htlc(struct channel_state *cstate, const struct htlc *htlc) |
|||
{ |
|||
force_remove_htlc(cstate, htlc_owner(htlc), htlc); |
|||
} |
|||
|
|||
void force_fulfill_htlc(struct channel_state *cstate, const struct htlc *htlc) |
|||
{ |
|||
force_remove_htlc(cstate, !htlc_owner(htlc), htlc); |
|||
} |
|||
|
|||
bool balance_after_force(struct channel_state *cstate) |
|||
{ |
|||
/* We should not spend more than anchor */ |
|||
if (cstate->side[LOCAL].pay_msat + cstate->side[REMOTE].pay_msat |
|||
> cstate->anchor * 1000) |
|||
return false; |
|||
|
|||
/* Check for wrap. */ |
|||
if (cstate->side[LOCAL].pay_msat > cstate->anchor * 1000) |
|||
return false; |
|||
if (cstate->side[REMOTE].pay_msat > cstate->anchor * 1000) |
|||
return false; |
|||
|
|||
if (cstate->num_nondust |
|||
> cstate->side[LOCAL].num_htlcs + cstate->side[REMOTE].num_htlcs) |
|||
return false; |
|||
|
|||
/* Recalc fees. */ |
|||
adjust_fee(cstate, cstate->fee_rate); |
|||
return true; |
|||
} |
|||
|
|||
static char *fmt_channel_oneside(const tal_t *ctx, |
|||
const struct channel_oneside *co) |
|||
{ |
|||
return tal_fmt(ctx, "{ pay_msat=%u" |
|||
" fee_msat=%u" |
|||
" num_htlcs=%u }", |
|||
co->pay_msat, |
|||
co->fee_msat, |
|||
co->num_htlcs); |
|||
} |
|||
|
|||
static char *fmt_channel_state(const tal_t *ctx, |
|||
const struct channel_state *cs) |
|||
{ |
|||
return tal_fmt(ctx, "{ anchor=%"PRIu64 |
|||
" fee_rate=%"PRIu64 |
|||
" num_nondust=%u" |
|||
" ours=%s" |
|||
" theirs=%s }", |
|||
cs->anchor, |
|||
cs->fee_rate, |
|||
cs->num_nondust, |
|||
fmt_channel_oneside(ctx, &cs->side[LOCAL]), |
|||
fmt_channel_oneside(ctx, &cs->side[REMOTE])); |
|||
} |
|||
|
|||
REGISTER_TYPE_TO_STRING(channel_oneside, fmt_channel_oneside); |
|||
REGISTER_TYPE_TO_STRING(channel_state, fmt_channel_state); |
@ -1,140 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_CHANNEL_H |
|||
#define LIGHTNING_DAEMON_CHANNEL_H |
|||
#include "config.h" |
|||
#include "bitcoin/locktime.h" |
|||
#include "daemon/htlc.h" |
|||
#include <assert.h> |
|||
#include <ccan/crypto/sha256/sha256.h> |
|||
#include <ccan/tal/tal.h> |
|||
#include <stdbool.h> |
|||
|
|||
struct channel_oneside { |
|||
/* Payment and fee is in millisatoshi. */ |
|||
uint32_t pay_msat, fee_msat; |
|||
/* Number of HTLCs (required for limiting total number) */ |
|||
unsigned int num_htlcs; |
|||
}; |
|||
|
|||
struct channel_state { |
|||
/* Satoshis paid by anchor. */ |
|||
uint64_t anchor; |
|||
/* Satoshis per 1000 bytes. */ |
|||
uint64_t fee_rate; |
|||
/* Number of non-dust htlcs (to calculate txsize) */ |
|||
unsigned int num_nondust; |
|||
struct channel_oneside side[2]; |
|||
}; |
|||
|
|||
/**
|
|||
* initial_cstate: Given initial fees and funding anchor, what is initial state? |
|||
* @ctx: tal context to allocate return value from. |
|||
* @anchor_satoshis: The anchor amount. |
|||
* @fee_rate: amount to pay in fees per kb (in satoshi). |
|||
* @dir: which side paid for the anchor. |
|||
* |
|||
* Returns state, or NULL if malformed. |
|||
*/ |
|||
struct channel_state *initial_cstate(const tal_t *ctx, |
|||
uint64_t anchor_satoshis, |
|||
uint64_t fee_rate, |
|||
enum side side); |
|||
|
|||
/**
|
|||
* copy_cstate: Make a deep copy of channel_state |
|||
* @ctx: tal context to allocate return value from. |
|||
* @cstate: state to copy. |
|||
*/ |
|||
struct channel_state *copy_cstate(const tal_t *ctx, |
|||
const struct channel_state *cstate); |
|||
|
|||
/**
|
|||
* cstate_add_htlc: append an HTLC to cstate if it can afford it |
|||
* @cstate: The channel state |
|||
* @htlc: the htlc pointer. |
|||
* @must_afford_fee: true if payer must meet fee. |
|||
* |
|||
* If that direction can't afford the HTLC this will return false and |
|||
* leave @cstate unchanged. If @must_afford_fee is true, and the |
|||
* direction can't afford its half of the fees, it will also return |
|||
* false and leave @cstate unchanged. Otherwise, pay_msat and fee_msat |
|||
* are adjusted accordingly; true is returned. |
|||
*/ |
|||
bool cstate_add_htlc(struct channel_state *cstate, const struct htlc *htlc, |
|||
bool must_afford_fee); |
|||
|
|||
/**
|
|||
* cstate_fail_htlc: remove an HTLC, funds to the side which offered it. |
|||
* @cstate: The channel state |
|||
* @htlc: the htlc to remove. |
|||
* |
|||
* This will remove the @index'th entry in cstate->side[dir].htlcs[], and credit |
|||
* the value of the HTLC (back) to cstate->side[dir]. |
|||
*/ |
|||
void cstate_fail_htlc(struct channel_state *cstate, const struct htlc *htlc); |
|||
|
|||
/**
|
|||
* cstate_fulfill_htlc: remove an HTLC, funds to side which accepted it. |
|||
* @cstate: The channel state |
|||
* @htlc: the htlc to remove |
|||
* |
|||
* This will remove the @index'th entry in cstate->side[dir].htlcs[], and credit |
|||
* the value of the HTLC to cstate->side[!dir]. |
|||
*/ |
|||
void cstate_fulfill_htlc(struct channel_state *cstate, const struct htlc *htlc); |
|||
|
|||
/**
|
|||
* approx_max_feerate: what's the most side could raise fee rate to? |
|||
* @cstate: The channel state |
|||
* @side: LOCAL or REMOTE |
|||
* |
|||
* This is not exact! To check if their offer is valid, use can_afford_feerate. |
|||
*/ |
|||
uint64_t approx_max_feerate(const struct channel_state *cstate, |
|||
enum side side); |
|||
|
|||
/**
|
|||
* can_afford_feerate: could this side pay for the fee if changed to fee_rate? |
|||
* @cstate: The channel state |
|||
* @fee_rate: the new fee rate proposed |
|||
* @side: LOCAL or REMOTE |
|||
*/ |
|||
bool can_afford_feerate(const struct channel_state *cstate, uint64_t fee_rate, |
|||
enum side side); |
|||
|
|||
/**
|
|||
* adjust_fee: Change fee rate. |
|||
* @cstate: The channel state |
|||
* @fee_rate: fee in satoshi per 1000 bytes. |
|||
*/ |
|||
void adjust_fee(struct channel_state *cstate, uint64_t fee_rate); |
|||
|
|||
/**
|
|||
* force_fee: Change fee to a specific value. |
|||
* @cstate: The channel state |
|||
* @fee: fee in satoshi. |
|||
* |
|||
* This is used for the close transaction, which specifies an exact fee. |
|||
* If the fee cannot be paid in full, this return false (but cstate will |
|||
* still be altered). |
|||
*/ |
|||
bool force_fee(struct channel_state *cstate, uint64_t fee); |
|||
|
|||
/**
|
|||
* fee_for_feerate: calculate the fee (in satoshi) for a given fee_rate. |
|||
* @txsize: transaction size in bytes. |
|||
* @fee_rate: satoshi per 1000 bytes. |
|||
*/ |
|||
uint64_t fee_by_feerate(size_t txsize, uint64_t fee_rate); |
|||
|
|||
/**
|
|||
* anchor_too_large: does anchor amount fit in 32-bits of millisatoshi. |
|||
* @anchor_satoshis: amount in satoshis |
|||
*/ |
|||
bool anchor_too_large(uint64_t anchor_satoshis); |
|||
|
|||
/* Routines to db to force HTLC changes out-of-order which may wrap. */ |
|||
void force_add_htlc(struct channel_state *cstate, const struct htlc *htlc); |
|||
void force_fail_htlc(struct channel_state *cstate, const struct htlc *htlc); |
|||
void force_fulfill_htlc(struct channel_state *cstate, const struct htlc *htlc); |
|||
bool balance_after_force(struct channel_state *cstate); |
|||
#endif /* LIGHTNING_DAEMON_CHANNEL_H */ |
@ -1,225 +0,0 @@ |
|||
#include "bitcoin/locktime.h" |
|||
#include "bitcoin/pubkey.h" |
|||
#include "bitcoin/script.h" |
|||
#include "bitcoin/shadouble.h" |
|||
#include "bitcoin/tx.h" |
|||
#include "channel.h" |
|||
#include "commit_tx.h" |
|||
#include "htlc.h" |
|||
#include "lightningd.h" |
|||
#include "log.h" |
|||
#include "overflows.h" |
|||
#include "peer.h" |
|||
#include "peer_internal.h" |
|||
#include "permute_tx.h" |
|||
#include "remove_dust.h" |
|||
#include "utils.h" |
|||
#include <assert.h> |
|||
#include <inttypes.h> |
|||
|
|||
u8 *wscript_for_htlc(const tal_t *ctx, |
|||
const struct peer *peer, |
|||
const struct htlc *h, |
|||
const struct sha256 *rhash, |
|||
enum side side) |
|||
{ |
|||
const struct peer_visible_state *this_side, *other_side; |
|||
u8 *(*fn)(const tal_t *, |
|||
const struct pubkey *, const struct pubkey *, |
|||
const struct abs_locktime *, const struct rel_locktime *, |
|||
const struct sha256 *, const struct sha256 *); |
|||
|
|||
/* scripts are different for htlcs offered vs accepted */ |
|||
if (side == htlc_owner(h)) |
|||
fn = bitcoin_redeem_htlc_send; |
|||
else |
|||
fn = bitcoin_redeem_htlc_recv; |
|||
|
|||
if (side == LOCAL) { |
|||
this_side = &peer->local; |
|||
other_side = &peer->remote; |
|||
} else { |
|||
this_side = &peer->remote; |
|||
other_side = &peer->local; |
|||
} |
|||
|
|||
return fn(ctx, |
|||
&this_side->finalkey, &other_side->finalkey, |
|||
&h->expiry, &this_side->locktime, rhash, &h->rhash); |
|||
} |
|||
|
|||
static size_t count_htlcs(const struct htlc_map *htlcs, int flag) |
|||
{ |
|||
struct htlc_map_iter it; |
|||
struct htlc *h; |
|||
size_t n = 0; |
|||
|
|||
for (h = htlc_map_first(htlcs, &it); h; h = htlc_map_next(htlcs, &it)) { |
|||
if (htlc_has(h, flag)) |
|||
n++; |
|||
} |
|||
return n; |
|||
} |
|||
|
|||
u8 *commit_output_to_us(const tal_t *ctx, |
|||
const struct peer *peer, |
|||
const struct sha256 *rhash, |
|||
enum side side, |
|||
u8 **wscript) |
|||
{ |
|||
u8 *tmp; |
|||
if (!wscript) |
|||
wscript = &tmp; |
|||
|
|||
/* Our output to ourself is encumbered by delay. */ |
|||
if (side == LOCAL) { |
|||
*wscript = bitcoin_redeem_secret_or_delay(ctx, |
|||
&peer->local.finalkey, |
|||
&peer->remote.locktime, |
|||
&peer->remote.finalkey, |
|||
rhash); |
|||
return scriptpubkey_p2wsh(ctx, *wscript); |
|||
} else { |
|||
/* Their output to us is a simple p2wpkh */ |
|||
*wscript = NULL; |
|||
return scriptpubkey_p2wpkh(ctx, &peer->local.finalkey); |
|||
} |
|||
} |
|||
|
|||
u8 *commit_output_to_them(const tal_t *ctx, |
|||
const struct peer *peer, |
|||
const struct sha256 *rhash, |
|||
enum side side, |
|||
u8 **wscript) |
|||
{ |
|||
u8 *tmp; |
|||
if (!wscript) |
|||
wscript = &tmp; |
|||
|
|||
/* Their output to themselves is encumbered by delay. */ |
|||
if (side == REMOTE) { |
|||
*wscript = bitcoin_redeem_secret_or_delay(ctx, |
|||
&peer->remote.finalkey, |
|||
&peer->local.locktime, |
|||
&peer->local.finalkey, |
|||
rhash); |
|||
return scriptpubkey_p2wsh(ctx, *wscript); |
|||
} else { |
|||
/* Our output to them is a simple p2wpkh */ |
|||
*wscript = NULL; |
|||
return scriptpubkey_p2wpkh(ctx, &peer->remote.finalkey); |
|||
} |
|||
} |
|||
|
|||
/* Takes ownership of script. */ |
|||
static bool add_output(struct bitcoin_tx *tx, u8 *script, u64 amount, |
|||
size_t *output_count, |
|||
u64 *total) |
|||
{ |
|||
assert(*output_count < tal_count(tx->output)); |
|||
if (is_dust(amount)) |
|||
return false; |
|||
tx->output[*output_count].script = tal_steal(tx, script); |
|||
tx->output[*output_count].amount = amount; |
|||
(*output_count)++; |
|||
(*total) += amount; |
|||
return true; |
|||
} |
|||
|
|||
struct bitcoin_tx *create_commit_tx(const tal_t *ctx, |
|||
struct peer *peer, |
|||
const struct sha256 *rhash, |
|||
const struct channel_state *cstate, |
|||
enum side side, |
|||
bool *otherside_only) |
|||
{ |
|||
const tal_t *tmpctx = tal_tmpctx(ctx); |
|||
struct bitcoin_tx *tx; |
|||
uint64_t total = 0; |
|||
struct htlc_map_iter it; |
|||
struct htlc *h; |
|||
size_t output_count; |
|||
bool pays_to[2]; |
|||
int committed_flag = HTLC_FLAG(side,HTLC_F_COMMITTED); |
|||
|
|||
/* Now create commitment tx: one input, two outputs (plus htlcs) */ |
|||
tx = bitcoin_tx(ctx, 1, 2 + count_htlcs(&peer->htlcs, committed_flag)); |
|||
|
|||
log_debug(peer->log, "Creating commitment tx:"); |
|||
log_add_struct(peer->log, " rhash = %s", struct sha256, rhash); |
|||
log_add_struct(peer->log, " My finalkey = %s", struct pubkey, |
|||
&peer->local.finalkey); |
|||
log_add_struct(peer->log, " Their finalkey = %s", struct pubkey, |
|||
&peer->remote.finalkey); |
|||
log_add_struct(peer->log, " My locktime = %s", struct rel_locktime, |
|||
&peer->local.locktime); |
|||
log_add_struct(peer->log, " Their locktime = %s", struct rel_locktime, |
|||
&peer->remote.locktime); |
|||
|
|||
/* Our input spends the anchor tx output. */ |
|||
tx->input[0].txid = peer->anchor.txid; |
|||
tx->input[0].index = peer->anchor.index; |
|||
tx->input[0].amount = tal_dup(tx->input, u64, &peer->anchor.satoshis); |
|||
|
|||
output_count = 0; |
|||
pays_to[LOCAL] = add_output(tx, commit_output_to_us(tmpctx, peer, rhash, |
|||
side, NULL), |
|||
cstate->side[LOCAL].pay_msat / 1000, |
|||
&output_count, |
|||
&total); |
|||
if (pays_to[LOCAL]) |
|||
log_debug(peer->log, "Pays %u to local: %s", |
|||
cstate->side[LOCAL].pay_msat / 1000, |
|||
tal_hex(tmpctx, tx->output[output_count-1].script)); |
|||
else |
|||
log_debug(peer->log, "DOES NOT pay %u to local", |
|||
cstate->side[LOCAL].pay_msat / 1000); |
|||
pays_to[REMOTE] = add_output(tx, commit_output_to_them(tmpctx, peer, |
|||
rhash, side, |
|||
NULL), |
|||
cstate->side[REMOTE].pay_msat / 1000, |
|||
&output_count, |
|||
&total); |
|||
if (pays_to[REMOTE]) |
|||
log_debug(peer->log, "Pays %u to remote: %s", |
|||
cstate->side[REMOTE].pay_msat / 1000, |
|||
tal_hex(tmpctx, tx->output[output_count-1].script)); |
|||
else |
|||
log_debug(peer->log, "DOES NOT pay %u to remote", |
|||
cstate->side[REMOTE].pay_msat / 1000); |
|||
|
|||
/* If their tx doesn't pay to them, or our tx doesn't pay to us... */ |
|||
*otherside_only = !pays_to[side]; |
|||
|
|||
/* First two outputs done, now for the HTLCs. */ |
|||
for (h = htlc_map_first(&peer->htlcs, &it); |
|||
h; |
|||
h = htlc_map_next(&peer->htlcs, &it)) { |
|||
const u8 *wscript; |
|||
|
|||
if (!htlc_has(h, committed_flag)) |
|||
continue; |
|||
wscript = wscript_for_htlc(tmpctx, peer, h, rhash, side); |
|||
/* If we pay any HTLC, it's txout is not just to other side. */ |
|||
if (add_output(tx, scriptpubkey_p2wsh(tmpctx, wscript), |
|||
h->msatoshi / 1000, &output_count, &total)) { |
|||
*otherside_only = false; |
|||
log_debug(peer->log, "Pays %"PRIu64" to htlc %"PRIu64, |
|||
h->msatoshi / 1000, h->id); |
|||
log_add_struct(peer->log, " expiry %s", |
|||
struct abs_locktime, &h->expiry); |
|||
log_add_struct(peer->log, " rhash %s", struct sha256, |
|||
&h->rhash); |
|||
log_debug(peer->log, "Script: %s", |
|||
tal_hex(tmpctx, wscript)); |
|||
} else |
|||
log_debug(peer->log, "DOES NOT pay %"PRIu64" to htlc %"PRIu64, |
|||
h->msatoshi / 1000, h->id); |
|||
} |
|||
assert(total <= peer->anchor.satoshis); |
|||
|
|||
tal_resize(&tx->output, output_count); |
|||
permute_outputs(tx->output, tal_count(tx->output), NULL); |
|||
tal_free(tmpctx); |
|||
return tx; |
|||
} |
@ -1,40 +0,0 @@ |
|||
#ifndef LIGHTNING_COMMIT_TX_H |
|||
#define LIGHTNING_COMMIT_TX_H |
|||
#include "config.h" |
|||
#include "htlc.h" |
|||
#include <ccan/tal/tal.h> |
|||
|
|||
struct channel_state; |
|||
struct sha256; |
|||
struct pubkey; |
|||
struct peer; |
|||
|
|||
u8 *wscript_for_htlc(const tal_t *ctx, |
|||
const struct peer *peer, |
|||
const struct htlc *h, |
|||
const struct sha256 *rhash, |
|||
enum side side); |
|||
|
|||
/* Returns scriptpubkey: *wscript is NULL if it's a direct p2wpkh. */ |
|||
u8 *commit_output_to_us(const tal_t *ctx, |
|||
const struct peer *peer, |
|||
const struct sha256 *rhash, |
|||
enum side side, |
|||
u8 **wscript); |
|||
|
|||
/* Returns scriptpubkey: *wscript is NULL if it's a direct p2wpkh. */ |
|||
u8 *commit_output_to_them(const tal_t *ctx, |
|||
const struct peer *peer, |
|||
const struct sha256 *rhash, |
|||
enum side side, |
|||
u8 **wscript); |
|||
|
|||
/* Create commitment tx to spend the anchor tx output; doesn't fill in
|
|||
* input scriptsig. */ |
|||
struct bitcoin_tx *create_commit_tx(const tal_t *ctx, |
|||
struct peer *peer, |
|||
const struct sha256 *rhash, |
|||
const struct channel_state *cstate, |
|||
enum side side, |
|||
bool *otherside_only); |
|||
#endif |
@ -1,656 +0,0 @@ |
|||
#include "bitcoin/shadouble.h" |
|||
#include "bitcoin/signature.h" |
|||
#include "cryptopkt.h" |
|||
#include "lightning.pb-c.h" |
|||
#include "lightningd.h" |
|||
#include "log.h" |
|||
#include "names.h" |
|||
#include "peer.h" |
|||
#include "peer_internal.h" |
|||
#include "protobuf_convert.h" |
|||
#include "secrets.h" |
|||
#include "utils.h" |
|||
#include <ccan/build_assert/build_assert.h> |
|||
#include <ccan/crypto/sha256/sha256.h> |
|||
#include <ccan/endian/endian.h> |
|||
#include <ccan/mem/mem.h> |
|||
#include <ccan/short_types/short_types.h> |
|||
#include <ccan/structeq/structeq.h> |
|||
#include <inttypes.h> |
|||
#include <secp256k1.h> |
|||
#include <secp256k1_ecdh.h> |
|||
#include <sodium/crypto_aead_chacha20poly1305.h> |
|||
#include <sodium/randombytes.h> |
|||
|
|||
#define MAX_PKT_LEN (1024 * 1024) |
|||
|
|||
/* FIXME-OLD#1:
|
|||
`length` is a 4-byte little-endian field indicating the size of the unencrypted body. |
|||
*/ |
|||
|
|||
struct crypto_pkt { |
|||
le32 length; |
|||
u8 auth_tag[crypto_aead_chacha20poly1305_ABYTES]; |
|||
|
|||
/* ... contents... */ |
|||
u8 data[]; |
|||
}; |
|||
|
|||
/* Temporary structure for negotiation */ |
|||
struct key_negotiate { |
|||
struct lightningd_state *dstate; |
|||
|
|||
/* Our session secret key. */ |
|||
u8 seckey[32]; |
|||
|
|||
/* Our pubkey, their pubkey. */ |
|||
le32 keylen; |
|||
u8 our_sessionpubkey[33], their_sessionpubkey[33]; |
|||
|
|||
/* After DH key exchange, we create io_data to check auth. */ |
|||
struct io_data *iod; |
|||
|
|||
/* Logging structure we're using. */ |
|||
struct log *log; |
|||
|
|||
/* Did we expect a particular ID? */ |
|||
const struct pubkey *expected_id; |
|||
|
|||
/* Callback once it's all done. */ |
|||
struct io_plan *(*cb)(struct io_conn *conn, |
|||
struct lightningd_state *dstate, |
|||
struct io_data *iod, |
|||
struct log *log, |
|||
const struct pubkey *id, |
|||
void *arg); |
|||
void *arg; |
|||
}; |
|||
|
|||
struct enckey { |
|||
struct sha256 k; |
|||
}; |
|||
|
|||
|
|||
/* FIXME-OLD #1:
|
|||
* * sending-key: SHA256(shared-secret || sending-node-session-pubkey) |
|||
* * receiving-key: SHA256(shared-secret || receiving-node-session-pubkey) |
|||
*/ |
|||
static struct enckey enckey_from_secret(const unsigned char secret[32], |
|||
const unsigned char serial_pubkey[33]) |
|||
{ |
|||
struct sha256_ctx ctx; |
|||
struct enckey enckey; |
|||
|
|||
sha256_init(&ctx); |
|||
sha256_update(&ctx, memcheck(secret, 32), 32); |
|||
sha256_update(&ctx, memcheck(serial_pubkey, 33), 33); |
|||
sha256_done(&ctx, &enckey.k); |
|||
|
|||
return enckey; |
|||
} |
|||
|
|||
struct dir_state { |
|||
u64 nonce; |
|||
struct enckey enckey; |
|||
|
|||
/* Current packet (encrypted). */ |
|||
struct crypto_pkt *cpkt; |
|||
size_t pkt_len; |
|||
}; |
|||
|
|||
static void setup_crypto(struct dir_state *dir, |
|||
u8 shared_secret[32], u8 serial_pubkey[33]) |
|||
{ |
|||
/* FIXME-OLD #1: Nonces...MUST begin at 0 */ |
|||
dir->nonce = 0; |
|||
|
|||
dir->enckey = enckey_from_secret(shared_secret, serial_pubkey); |
|||
|
|||
dir->cpkt = NULL; |
|||
} |
|||
|
|||
struct io_data { |
|||
/* Stuff we need to keep around to talk to peer. */ |
|||
struct dir_state in, out; |
|||
|
|||
/* Callback once packet decrypted. */ |
|||
struct io_plan *(*cb)(struct io_conn *, struct peer *); |
|||
|
|||
/* Once peer is assigned, this is set. */ |
|||
struct peer *peer; |
|||
|
|||
/* Length we're currently reading. */ |
|||
struct crypto_pkt hdr_in; |
|||
}; |
|||
|
|||
static void *proto_tal_alloc(void *allocator_data, size_t size) |
|||
{ |
|||
return tal_arr(allocator_data, char, size); |
|||
} |
|||
|
|||
static void proto_tal_free(void *allocator_data, void *pointer) |
|||
{ |
|||
tal_free(pointer); |
|||
} |
|||
|
|||
static void le64_nonce(unsigned char *npub, u64 nonce) |
|||
{ |
|||
/* FIXME-OLD #1: Nonces are 64-bit little-endian numbers */ |
|||
le64 le_nonce = cpu_to_le64(nonce); |
|||
memcpy(npub, &le_nonce, sizeof(le_nonce)); |
|||
BUILD_ASSERT(crypto_aead_chacha20poly1305_NPUBBYTES == sizeof(le_nonce)); |
|||
} |
|||
|
|||
/* Encrypts data..data + len - 1 inclusive into data..data + len - 1 and
|
|||
* then writes the authentication tag at data+len. |
|||
* |
|||
* This increments nonce every time. |
|||
*/ |
|||
static void encrypt_in_place(void *data, size_t len, |
|||
u64 *nonce, const struct enckey *enckey) |
|||
{ |
|||
int ret; |
|||
unsigned long long clen; |
|||
unsigned char npub[crypto_aead_chacha20poly1305_NPUBBYTES]; |
|||
|
|||
le64_nonce(npub, *nonce); |
|||
ret = crypto_aead_chacha20poly1305_encrypt(data, &clen, |
|||
memcheck(data, len), len, |
|||
NULL, 0, NULL, |
|||
npub, enckey->k.u.u8); |
|||
assert(ret == 0); |
|||
assert(clen == len + crypto_aead_chacha20poly1305_ABYTES); |
|||
(*nonce)++; |
|||
} |
|||
|
|||
/* Checks authentication tag at data+len, then
|
|||
* decrypts data..data + len - 1 inclusive into data..data + len - 1. |
|||
* |
|||
* This increments nonce every time. |
|||
*/ |
|||
static bool decrypt_in_place(void *data, size_t len, |
|||
u64 *nonce, const struct enckey *enckey) |
|||
{ |
|||
int ret; |
|||
unsigned long long mlen; |
|||
unsigned char npub[crypto_aead_chacha20poly1305_NPUBBYTES]; |
|||
|
|||
le64_nonce(npub, *nonce); |
|||
mlen = len + crypto_aead_chacha20poly1305_ABYTES; |
|||
|
|||
ret = crypto_aead_chacha20poly1305_decrypt(data, &mlen, NULL, |
|||
memcheck(data, mlen), mlen, |
|||
NULL, 0, |
|||
npub, enckey->k.u.u8); |
|||
if (ret == 0) { |
|||
assert(mlen == len); |
|||
(*nonce)++; |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
static Pkt *decrypt_body(const tal_t *ctx, struct io_data *iod, struct log *log) |
|||
{ |
|||
struct ProtobufCAllocator prototal; |
|||
Pkt *ret; |
|||
size_t data_len = le32_to_cpu(iod->hdr_in.length); |
|||
|
|||
if (!decrypt_in_place(iod->in.cpkt->data, data_len, |
|||
&iod->in.nonce, &iod->in.enckey)) { |
|||
/* Free encrypted packet. */ |
|||
iod->in.cpkt = tal_free(iod->in.cpkt); |
|||
log_unusual(log, "Body decryption failed"); |
|||
return NULL; |
|||
} |
|||
|
|||
/* De-protobuf it. */ |
|||
prototal.alloc = proto_tal_alloc; |
|||
prototal.free = proto_tal_free; |
|||
prototal.allocator_data = tal(ctx, char); |
|||
|
|||
ret = pkt__unpack(&prototal, data_len, iod->in.cpkt->data); |
|||
if (!ret) { |
|||
log_unusual(log, "Packet failed to unpack!"); |
|||
tal_free(prototal.allocator_data); |
|||
} else { |
|||
/* Make sure packet owns contents */ |
|||
tal_steal(ctx, ret); |
|||
tal_steal(ret, prototal.allocator_data); |
|||
|
|||
log_debug(log, "Received packet LEN=%zu, type=%s", |
|||
data_len, |
|||
ret->pkt_case == PKT__PKT_AUTH ? "PKT_AUTH" |
|||
: pkt_name(ret->pkt_case)); |
|||
} |
|||
|
|||
/* Free encrypted packet. */ |
|||
iod->in.cpkt = tal_free(iod->in.cpkt); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
static struct crypto_pkt *encrypt_pkt(struct io_data *iod, const Pkt *pkt, |
|||
size_t *totlen) |
|||
{ |
|||
struct crypto_pkt *cpkt; |
|||
size_t len; |
|||
|
|||
len = pkt__get_packed_size(pkt); |
|||
*totlen = sizeof(*cpkt) + len + crypto_aead_chacha20poly1305_ABYTES; |
|||
|
|||
cpkt = (struct crypto_pkt *)tal_arr(iod, char, *totlen); |
|||
cpkt->length = cpu_to_le32(len); |
|||
|
|||
/* Encrypt header. */ |
|||
encrypt_in_place(cpkt, sizeof(cpkt->length), |
|||
&iod->out.nonce, &iod->out.enckey); |
|||
|
|||
/* Encrypt body. */ |
|||
pkt__pack(pkt, cpkt->data); |
|||
encrypt_in_place(cpkt->data, len, &iod->out.nonce, &iod->out.enckey); |
|||
|
|||
return cpkt; |
|||
} |
|||
|
|||
static struct io_plan *recv_body(struct io_conn *conn, struct peer *peer) |
|||
{ |
|||
struct io_data *iod = peer->io_data; |
|||
|
|||
assert(!peer->inpkt); |
|||
|
|||
/* We have full packet. */ |
|||
peer->inpkt = decrypt_body(iod, iod, peer->log); |
|||
if (!peer->inpkt) |
|||
return io_close(conn); |
|||
|
|||
return iod->cb(conn, peer); |
|||
} |
|||
|
|||
static bool decrypt_header(struct log *log, struct io_data *iod, |
|||
size_t *body_len) |
|||
{ |
|||
/* We have length: Check it. */ |
|||
if (!decrypt_in_place(&iod->hdr_in.length, sizeof(iod->hdr_in.length), |
|||
&iod->in.nonce, &iod->in.enckey)) { |
|||
log_unusual(log, "Header decryption failed"); |
|||
return false; |
|||
} |
|||
log_debug(log, "Decrypted header len %u", |
|||
le32_to_cpu(iod->hdr_in.length)); |
|||
|
|||
/* FIXME-OLD #1: `length` MUST NOT exceed 1MB (1048576 bytes). */ |
|||
if (le32_to_cpu(iod->hdr_in.length) > MAX_PKT_LEN) { |
|||
log_unusual(log, |
|||
"Packet overlength: %"PRIu64, |
|||
le64_to_cpu(iod->hdr_in.length)); |
|||
return false; |
|||
} |
|||
|
|||
/* Allocate room for body, copy header. */ |
|||
*body_len = le32_to_cpu(iod->hdr_in.length) |
|||
+ crypto_aead_chacha20poly1305_ABYTES; |
|||
|
|||
iod->in.cpkt = (struct crypto_pkt *) |
|||
tal_arr(iod, char, sizeof(iod->hdr_in) + *body_len); |
|||
*iod->in.cpkt = iod->hdr_in; |
|||
return true; |
|||
} |
|||
|
|||
static struct io_plan *recv_header(struct io_conn *conn, struct peer *peer) |
|||
{ |
|||
struct io_data *iod = peer->io_data; |
|||
size_t body_len; |
|||
|
|||
if (!decrypt_header(peer->log, iod, &body_len)) |
|||
return io_close(conn); |
|||
|
|||
return io_read(conn, iod->in.cpkt->data, body_len, recv_body, peer); |
|||
} |
|||
|
|||
struct io_plan *peer_read_packet(struct io_conn *conn, |
|||
struct peer *peer, |
|||
struct io_plan *(*cb)(struct io_conn *, |
|||
struct peer *)) |
|||
{ |
|||
struct io_data *iod = peer->io_data; |
|||
|
|||
iod->cb = cb; |
|||
return io_read(conn, &iod->hdr_in, sizeof(iod->hdr_in), |
|||
recv_header, peer); |
|||
} |
|||
|
|||
/* Caller must free data! */ |
|||
struct io_plan *peer_write_packet(struct io_conn *conn, |
|||
struct peer *peer, |
|||
const Pkt *pkt, |
|||
struct io_plan *(*next)(struct io_conn *, |
|||
struct peer *)) |
|||
{ |
|||
struct io_data *iod = peer->io_data; |
|||
size_t totlen; |
|||
|
|||
/* We free previous packet here, rather than doing indirection
|
|||
* via io_write */ |
|||
tal_free(iod->out.cpkt); |
|||
|
|||
iod->out.cpkt = encrypt_pkt(iod, pkt, &totlen); |
|||
/* Free unencrypted packet. */ |
|||
tal_free(pkt); |
|||
|
|||
return io_write(conn, iod->out.cpkt, totlen, next, peer); |
|||
} |
|||
|
|||
static void *pkt_unwrap(Pkt *inpkt, struct log *log, Pkt__PktCase which) |
|||
{ |
|||
size_t i; |
|||
const ProtobufCMessage *base; |
|||
|
|||
if (inpkt->pkt_case != which) { |
|||
log_unusual(log, "Expected %u, got %u", |
|||
which, inpkt->pkt_case); |
|||
return NULL; |
|||
} |
|||
|
|||
/* It's a union, and each member starts with base. Pick one */ |
|||
base = &inpkt->error->base; |
|||
|
|||
/* Look for unknown fields. Remember, "It's OK to be odd!" */ |
|||
for (i = 0; i < base->n_unknown_fields; i++) { |
|||
log_debug(log, "Unknown field in %u: %u", |
|||
which, base->unknown_fields[i].tag); |
|||
/* Odd is OK */ |
|||
if (base->unknown_fields[i].tag & 1) |
|||
continue; |
|||
log_unusual(log, "Unknown field %u in %u", |
|||
base->unknown_fields[i].tag, which); |
|||
return NULL; |
|||
} |
|||
return inpkt->error; |
|||
} |
|||
|
|||
static bool check_proof(struct key_negotiate *neg, struct log *log, |
|||
Pkt *inpkt, |
|||
const struct pubkey *expected_id, |
|||
struct pubkey *id) |
|||
{ |
|||
struct sha256_double sha; |
|||
secp256k1_ecdsa_signature sig; |
|||
Authenticate *auth; |
|||
|
|||
auth = pkt_unwrap(inpkt, log, PKT__PKT_AUTH); |
|||
if (!auth) |
|||
return false; |
|||
|
|||
/* FIXME-OLD #1:
|
|||
* |
|||
* The receiving node MUST check that: |
|||
* |
|||
* 1. `node_id` is the expected value for the sending node. |
|||
*/ |
|||
if (!proto_to_pubkey(auth->node_id, id)) { |
|||
log_unusual(log, "Invalid auth id"); |
|||
return false; |
|||
} |
|||
|
|||
if (expected_id && !structeq(id, expected_id)) { |
|||
log_unusual(log, "Incorrect auth id"); |
|||
return false; |
|||
} |
|||
|
|||
/* FIXME-OLD #1:
|
|||
* |
|||
* 2. `session_sig` is a valid secp256k1 ECDSA signature encoded as |
|||
* a 32-byte big endian R value, followed by a 32-byte big |
|||
* endian S value. |
|||
*/ |
|||
if (!proto_to_signature(auth->session_sig, &sig)) { |
|||
log_unusual(log, "Invalid auth signature"); |
|||
return false; |
|||
} |
|||
|
|||
|
|||
/* FIXME-OLD #1:
|
|||
* |
|||
* 3. `session_sig` is the signature of the SHA256 of SHA256 of the |
|||
* its own sessionpubkey, using the secret key corresponding to |
|||
* the sender's `node_id`. |
|||
*/ |
|||
sha256_double(&sha, neg->our_sessionpubkey, |
|||
sizeof(neg->our_sessionpubkey)); |
|||
|
|||
if (!check_signed_hash(&sha, &sig, id)) { |
|||
log_unusual(log, "Bad auth signature"); |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
static struct io_plan *recv_body_negotiate(struct io_conn *conn, |
|||
struct key_negotiate *neg) |
|||
{ |
|||
struct io_data *iod = neg->iod; |
|||
struct io_plan *plan; |
|||
Pkt *pkt; |
|||
struct pubkey id; |
|||
|
|||
/* We have full packet. */ |
|||
pkt = decrypt_body(neg, iod, neg->log); |
|||
if (!pkt) |
|||
return io_close(conn); |
|||
|
|||
if (!check_proof(neg, neg->log, pkt, neg->expected_id, &id)) |
|||
return io_close(conn); |
|||
|
|||
/* Steal so that the callback may not accidentally free it for us */ |
|||
tal_steal(NULL, neg); |
|||
|
|||
plan = neg->cb(conn, neg->dstate, neg->iod, neg->log, &id, neg->arg); |
|||
tal_free(neg); |
|||
return plan; |
|||
} |
|||
|
|||
static struct io_plan *recv_header_negotiate(struct io_conn *conn, |
|||
struct key_negotiate *neg) |
|||
{ |
|||
size_t body_len; |
|||
struct io_data *iod = neg->iod; |
|||
|
|||
if (!decrypt_header(neg->log, iod, &body_len)) |
|||
return io_close(conn); |
|||
|
|||
return io_read(conn, iod->in.cpkt->data, body_len, recv_body_negotiate, |
|||
neg); |
|||
} |
|||
|
|||
static struct io_plan *receive_proof(struct io_conn *conn, |
|||
struct key_negotiate *neg) |
|||
{ |
|||
return io_read(conn, &neg->iod->hdr_in, sizeof(neg->iod->hdr_in), |
|||
recv_header_negotiate, neg); |
|||
} |
|||
|
|||
/* Steals w onto the returned Pkt */ |
|||
static Pkt *pkt_wrap(const tal_t *ctx, void *w, Pkt__PktCase pkt_case) |
|||
{ |
|||
Pkt *pkt = tal(ctx, Pkt); |
|||
pkt__init(pkt); |
|||
pkt->pkt_case = pkt_case; |
|||
/* Union, so any will do */ |
|||
pkt->error = tal_steal(pkt, w); |
|||
return pkt; |
|||
} |
|||
|
|||
static Pkt *authenticate_pkt(const tal_t *ctx, |
|||
const struct pubkey *node_id, |
|||
const secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
Authenticate *auth = tal(ctx, Authenticate); |
|||
authenticate__init(auth); |
|||
auth->node_id = pubkey_to_proto(auth, node_id); |
|||
auth->session_sig = signature_to_proto(auth, sig); |
|||
return pkt_wrap(ctx, auth, PKT__PKT_AUTH); |
|||
} |
|||
|
|||
static struct io_plan *keys_exchanged(struct io_conn *conn, |
|||
struct key_negotiate *neg) |
|||
{ |
|||
u8 shared_secret[32]; |
|||
struct pubkey sessionkey; |
|||
secp256k1_ecdsa_signature sig; |
|||
Pkt *auth; |
|||
size_t totlen; |
|||
|
|||
if (!pubkey_from_der(neg->their_sessionpubkey, |
|||
sizeof(neg->their_sessionpubkey), |
|||
&sessionkey)) { |
|||
log_unusual_blob(neg->log, "Bad sessionkey %s", |
|||
neg->their_sessionpubkey, |
|||
sizeof(neg->their_sessionpubkey)); |
|||
return io_close(conn); |
|||
} |
|||
|
|||
/* Derive shared secret. */ |
|||
if (!secp256k1_ecdh(secp256k1_ctx, shared_secret, |
|||
&sessionkey.pubkey, neg->seckey)) { |
|||
log_unusual(neg->log, "Bad ECDH"); |
|||
return io_close(conn); |
|||
} |
|||
|
|||
/* Each side combines with their OWN session key to SENDING crypto. */ |
|||
neg->iod = tal(neg, struct io_data); |
|||
setup_crypto(&neg->iod->in, shared_secret, neg->their_sessionpubkey); |
|||
setup_crypto(&neg->iod->out, shared_secret, neg->our_sessionpubkey); |
|||
|
|||
/* FIXME-OLD #1:
|
|||
* |
|||
* `session_sig` is the signature of the SHA256 of SHA256 of the its |
|||
* own sessionpubkey, using the secret key corresponding to the |
|||
* sender's `node_id`. |
|||
*/ |
|||
privkey_sign(neg->dstate, neg->their_sessionpubkey, |
|||
sizeof(neg->their_sessionpubkey), &sig); |
|||
|
|||
auth = authenticate_pkt(neg, &neg->dstate->id, &sig); |
|||
|
|||
neg->iod->out.cpkt = encrypt_pkt(neg->iod, auth, &totlen); |
|||
return io_write(conn, neg->iod->out.cpkt, totlen, receive_proof, neg); |
|||
} |
|||
|
|||
/* Read and ignore any extra bytes... */ |
|||
static struct io_plan *discard_extra(struct io_conn *conn, |
|||
struct key_negotiate *neg) |
|||
{ |
|||
size_t len = le32_to_cpu(neg->keylen); |
|||
|
|||
/* FIXME-OLD#1: Additional fields MAY be added, and MUST be
|
|||
* included in the `length` field. These MUST be ignored by |
|||
* implementations which do not understand them. */ |
|||
if (len > sizeof(neg->their_sessionpubkey)) { |
|||
char *discard; |
|||
|
|||
len -= sizeof(neg->their_sessionpubkey); |
|||
discard = tal_arr(neg, char, len); |
|||
log_unusual(neg->log, |
|||
"Ignoring %zu extra handshake bytes", |
|||
len); |
|||
return io_read(conn, discard, len, keys_exchanged, neg); |
|||
} |
|||
|
|||
return keys_exchanged(conn, neg); |
|||
} |
|||
|
|||
static struct io_plan *session_key_receive(struct io_conn *conn, |
|||
struct key_negotiate *neg) |
|||
{ |
|||
/* FIXME-OLD#1: The `length` field is the length after the field
|
|||
itself, and MUST be 33 or greater. */ |
|||
if (le32_to_cpu(neg->keylen) < sizeof(neg->their_sessionpubkey)) { |
|||
log_unusual(neg->log, "short session key length %u", |
|||
le32_to_cpu(neg->keylen)); |
|||
return io_close(conn); |
|||
} |
|||
|
|||
/* FIXME-OLD#1: `length` MUST NOT exceed 1MB (1048576 bytes). */ |
|||
if (le32_to_cpu(neg->keylen) > 1048576) { |
|||
log_unusual(neg->log, |
|||
"Oversize session key length %u", |
|||
le32_to_cpu(neg->keylen)); |
|||
return io_close(conn); |
|||
} |
|||
|
|||
log_debug(neg->log, "Session key length %u", le32_to_cpu(neg->keylen)); |
|||
|
|||
/* Now read their key. */ |
|||
return io_read(conn, neg->their_sessionpubkey, |
|||
sizeof(neg->their_sessionpubkey), discard_extra, neg); |
|||
} |
|||
|
|||
static struct io_plan *session_key_len_receive(struct io_conn *conn, |
|||
struct key_negotiate *neg) |
|||
{ |
|||
/* Read the amount of data they will send.. */ |
|||
return io_read(conn, &neg->keylen, sizeof(neg->keylen), |
|||
session_key_receive, neg); |
|||
} |
|||
|
|||
static void gen_sessionkey(u8 seckey[32], |
|||
secp256k1_pubkey *pubkey) |
|||
{ |
|||
do { |
|||
randombytes_buf(seckey, 32); |
|||
} while (!secp256k1_ec_pubkey_create(secp256k1_ctx, pubkey, seckey)); |
|||
} |
|||
|
|||
static struct io_plan *write_sessionkey(struct io_conn *conn, |
|||
struct key_negotiate *neg) |
|||
{ |
|||
return io_write(conn, neg->our_sessionpubkey, |
|||
sizeof(neg->our_sessionpubkey), |
|||
session_key_len_receive, neg); |
|||
} |
|||
|
|||
struct io_plan *peer_crypto_setup_(struct io_conn *conn, |
|||
struct lightningd_state *dstate, |
|||
const struct pubkey *id, |
|||
struct log *log, |
|||
struct io_plan *(*cb)(struct io_conn *conn, |
|||
struct lightningd_state *dstate, |
|||
struct io_data *iod, |
|||
struct log *log, |
|||
const struct pubkey *id, |
|||
void *arg), |
|||
void *arg) |
|||
{ |
|||
size_t outputlen; |
|||
secp256k1_pubkey sessionkey; |
|||
struct key_negotiate *neg; |
|||
|
|||
/* FIXME-OLD #1:
|
|||
* |
|||
* The 4-byte length for each message is encrypted separately |
|||
* (resulting in a 20 byte header when the authentication tag |
|||
* is appended) */ |
|||
BUILD_ASSERT(sizeof(struct crypto_pkt) == 20); |
|||
|
|||
/* We store negotiation state here. */ |
|||
neg = tal(conn, struct key_negotiate); |
|||
neg->cb = cb; |
|||
neg->arg = arg; |
|||
neg->dstate = dstate; |
|||
neg->expected_id = id; |
|||
neg->log = log; |
|||
|
|||
gen_sessionkey(neg->seckey, &sessionkey); |
|||
|
|||
outputlen = sizeof(neg->our_sessionpubkey); |
|||
secp256k1_ec_pubkey_serialize(secp256k1_ctx, |
|||
neg->our_sessionpubkey, &outputlen, |
|||
&sessionkey, |
|||
SECP256K1_EC_COMPRESSED); |
|||
assert(outputlen == sizeof(neg->our_sessionpubkey)); |
|||
neg->keylen = cpu_to_le32(sizeof(neg->our_sessionpubkey)); |
|||
return io_write(conn, &neg->keylen, sizeof(neg->keylen), |
|||
write_sessionkey, neg); |
|||
} |
@ -1,48 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_CRYPTOPKT_H |
|||
#define LIGHTNING_DAEMON_CRYPTOPKT_H |
|||
#include "config.h" |
|||
#include "lightning.pb-c.h" |
|||
#include <ccan/io/io.h> |
|||
#include <ccan/typesafe_cb/typesafe_cb.h> |
|||
|
|||
struct io_data; |
|||
struct json_connecting; |
|||
struct lightningd_state; |
|||
struct log; |
|||
struct peer; |
|||
|
|||
struct io_plan *peer_crypto_setup_(struct io_conn *conn, |
|||
struct lightningd_state *dstate, |
|||
const struct pubkey *id, |
|||
struct log *log, |
|||
struct io_plan *(*cb)(struct io_conn *conn, |
|||
struct lightningd_state *dstate, |
|||
struct io_data *iod, |
|||
struct log *log, |
|||
const struct pubkey *id, |
|||
void *arg), |
|||
void *arg); |
|||
|
|||
#define peer_crypto_setup(conn, dstate, id, log_, cb, arg) \ |
|||
peer_crypto_setup_((conn), (dstate), (id), (log_), \ |
|||
typesafe_cb_preargs(struct io_plan *, void *, \ |
|||
(cb), (arg), \ |
|||
struct io_conn *, \ |
|||
struct lightningd_state *, \ |
|||
struct io_data *, \ |
|||
struct log *, \ |
|||
const struct pubkey *), \ |
|||
(arg)) |
|||
|
|||
/* Reads packet into peer->inpkt/peer->inpkt_len */ |
|||
struct io_plan *peer_read_packet(struct io_conn *conn, |
|||
struct peer *peer, |
|||
struct io_plan *(*cb)(struct io_conn *, |
|||
struct peer *)); |
|||
|
|||
struct io_plan *peer_write_packet(struct io_conn *conn, |
|||
struct peer *peer, |
|||
const Pkt *pkt, |
|||
struct io_plan *(*next)(struct io_conn *, |
|||
struct peer *)); |
|||
#endif /* LIGHTNING_DAEMON_CRYPTOPKT_H */ |
File diff suppressed because it is too large
@ -1,76 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_DB_H |
|||
#define LIGHTNING_DAEMON_DB_H |
|||
#include "config.h" |
|||
#include "peer.h" |
|||
#include <stdbool.h> |
|||
|
|||
void db_init(struct lightningd_state *dstate); |
|||
|
|||
void db_start_transaction(struct peer *peer); |
|||
void db_abort_transaction(struct peer *peer); |
|||
const char *db_commit_transaction(struct peer *peer); |
|||
|
|||
void db_add_wallet_privkey(struct lightningd_state *dstate, |
|||
const struct privkey *privkey); |
|||
|
|||
bool db_add_peer_address(struct lightningd_state *dstate, |
|||
const struct peer_address *addr); |
|||
|
|||
/* Must NOT be inside transaction. */ |
|||
bool db_update_their_closing(struct peer *peer); |
|||
bool db_new_pay_command(struct lightningd_state *dstate, |
|||
const struct sha256 *rhash, |
|||
const struct pubkey *ids, |
|||
u64 msatoshi, |
|||
const struct htlc *htlc); |
|||
bool db_replace_pay_command(struct lightningd_state *dstate, |
|||
const struct sha256 *rhash, |
|||
const struct pubkey *ids, |
|||
u64 msatoshi, |
|||
const struct htlc *htlc); |
|||
bool db_new_invoice(struct lightningd_state *dstate, |
|||
u64 msatoshi, |
|||
const char *label, |
|||
const struct preimage *r); |
|||
|
|||
bool db_remove_invoice(struct lightningd_state *dstate, |
|||
const char *label); |
|||
|
|||
/* FIXME: save error handling until db_commit_transaction for calls
|
|||
* which have to be inside transaction anyway. */ |
|||
|
|||
/* Must be inside transaction. */ |
|||
void db_create_peer(struct peer *peer); |
|||
void db_set_visible_state(struct peer *peer); |
|||
void db_set_anchor(struct peer *peer); |
|||
void db_new_htlc(struct peer *peer, const struct htlc *htlc); |
|||
void db_new_feechange(struct peer *peer, const struct feechange *feechange); |
|||
void db_htlc_fulfilled(struct peer *peer, const struct htlc *htlc); |
|||
void db_htlc_failed(struct peer *peer, const struct htlc *htlc); |
|||
void db_update_htlc_state(struct peer *peer, const struct htlc *htlc, |
|||
enum htlc_state oldstate); |
|||
void db_complete_pay_command(struct lightningd_state *dstate, |
|||
const struct htlc *htlc); |
|||
void db_resolve_invoice(struct lightningd_state *dstate, |
|||
const char *label, u64 paid_num); |
|||
void db_update_feechange_state(struct peer *peer, |
|||
const struct feechange *f, |
|||
enum feechange_state oldstate); |
|||
void db_remove_feechange(struct peer *peer, const struct feechange *feechange, |
|||
enum feechange_state oldstate); |
|||
void db_new_commit_info(struct peer *peer, enum side side, |
|||
const struct sha256 *prev_rhash); |
|||
void db_remove_their_prev_revocation_hash(struct peer *peer); |
|||
void db_update_next_revocation_hash(struct peer *peer); |
|||
void db_save_shachain(struct peer *peer); |
|||
void db_update_state(struct peer *peer); |
|||
void db_begin_shutdown(struct peer *peer); |
|||
void db_set_our_closing_script(struct peer *peer); |
|||
void db_update_our_closing(struct peer *peer); |
|||
void db_set_their_closing_script(struct peer *peer); |
|||
|
|||
void db_add_commit_map(struct peer *peer, |
|||
const struct sha256_double *txid, u64 commit_num); |
|||
|
|||
void db_forget_peer(struct peer *peer); |
|||
#endif /* LIGHTNING_DAEMON_DB_H */ |
@ -1,40 +0,0 @@ |
|||
#include "failure.h" |
|||
#include "protobuf_convert.h" |
|||
#include <ccan/tal/str/str.h> |
|||
|
|||
/* FIXME: Crypto! */ |
|||
const u8 *failinfo_create(const tal_t *ctx, |
|||
const struct pubkey *id, |
|||
u32 error_code, |
|||
const char *reason) |
|||
{ |
|||
FailInfo *f = tal(ctx, FailInfo); |
|||
u8 *arr; |
|||
|
|||
fail_info__init(f); |
|||
f->id = pubkey_to_proto(f, id); |
|||
f->error_code = error_code; |
|||
if (reason) |
|||
f->reason = tal_strdup(f, reason); |
|||
else |
|||
f->reason = NULL; |
|||
|
|||
arr = tal_arr(ctx, u8, fail_info__get_packed_size(f)); |
|||
fail_info__pack(f, arr); |
|||
tal_free(f); |
|||
return arr; |
|||
} |
|||
|
|||
FailInfo *failinfo_unwrap(const tal_t *ctx, const void *data, size_t len) |
|||
{ |
|||
struct ProtobufCAllocator *prototal = make_prototal(ctx); |
|||
FailInfo *f; |
|||
|
|||
f = fail_info__unpack(prototal, len, data); |
|||
if (f) |
|||
steal_from_prototal(ctx, prototal, f); |
|||
else |
|||
tal_free(prototal); |
|||
|
|||
return f; |
|||
} |
@ -1,36 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_FAILURE_H |
|||
#define LIGHTNING_DAEMON_FAILURE_H |
|||
#include "config.h" |
|||
#include "lightning.pb-c.h" |
|||
#include <ccan/short_types/short_types.h> |
|||
#include <ccan/tal/tal.h> |
|||
#include <secp256k1.h> |
|||
|
|||
struct pubkey; |
|||
|
|||
enum fail_error { |
|||
BAD_REQUEST_400 = 400, |
|||
UNAUTHORIZED_401 = 401, |
|||
PAYMENT_REQUIRED_402 = 402, |
|||
FORBIDDEN_403 = 403, |
|||
NOT_FOUND_404 = 404, |
|||
METHOD_NOT_ALLOWED_405 = 405, |
|||
REQUEST_TIMEOUT_408 = 408, |
|||
GONE_410 = 410, |
|||
IM_A_TEAPOT_418 = 418, |
|||
INTERNAL_SERVER_ERROR_500 = 500, |
|||
NOT_IMPLEMENTED_501 = 501, |
|||
BAD_GATEWAY_502 = 502, |
|||
SERVICE_UNAVAILABLE_503 = 503, |
|||
GATEWAY_TIMEOUT_504 = 504, |
|||
VERSION_NOT_SUPPORTED_505 = 505 |
|||
}; |
|||
|
|||
const u8 *failinfo_create(const tal_t *ctx, |
|||
const struct pubkey *id, |
|||
enum fail_error error_code, |
|||
const char *reason); |
|||
|
|||
FailInfo *failinfo_unwrap(const tal_t *ctx, const void *data, size_t len); |
|||
|
|||
#endif /* LIGHTNING_DAEMON_FAILURE_H */ |
@ -1,144 +0,0 @@ |
|||
#include "db.h" |
|||
#include "feechange.h" |
|||
#include "log.h" |
|||
#include "peer.h" |
|||
#include "peer_internal.h" |
|||
#include <ccan/array_size/array_size.h> |
|||
#include <inttypes.h> |
|||
#include "gen_feechange_state_names.h" |
|||
|
|||
/* This is the HTLC-like flags for each state. */ |
|||
static const int per_state_bits[] = { |
|||
[SENT_FEECHANGE] = HTLC_ADDING + HTLC_LOCAL_F_OWNER |
|||
+ HTLC_REMOTE_F_PENDING, |
|||
|
|||
[SENT_FEECHANGE_COMMIT] = HTLC_ADDING + HTLC_LOCAL_F_OWNER |
|||
+ HTLC_REMOTE_F_COMMITTED |
|||
+ HTLC_REMOTE_F_WAS_COMMITTED, |
|||
|
|||
[RCVD_FEECHANGE_REVOCATION] = HTLC_ADDING + HTLC_LOCAL_F_OWNER |
|||
+ HTLC_REMOTE_F_COMMITTED |
|||
+ HTLC_REMOTE_F_REVOKED |
|||
+ HTLC_LOCAL_F_PENDING |
|||
+ HTLC_REMOTE_F_WAS_COMMITTED, |
|||
|
|||
[RCVD_FEECHANGE_ACK_COMMIT] = HTLC_ADDING + HTLC_LOCAL_F_OWNER |
|||
+ HTLC_REMOTE_F_COMMITTED |
|||
+ HTLC_REMOTE_F_REVOKED |
|||
+ HTLC_LOCAL_F_COMMITTED |
|||
+ HTLC_LOCAL_F_WAS_COMMITTED |
|||
+ HTLC_REMOTE_F_WAS_COMMITTED, |
|||
|
|||
[SENT_FEECHANGE_ACK_REVOCATION] = HTLC_LOCAL_F_OWNER |
|||
+ HTLC_REMOTE_F_COMMITTED |
|||
+ HTLC_REMOTE_F_REVOKED |
|||
+ HTLC_LOCAL_F_COMMITTED |
|||
+ HTLC_LOCAL_F_REVOKED |
|||
+ HTLC_LOCAL_F_WAS_COMMITTED |
|||
+ HTLC_REMOTE_F_WAS_COMMITTED, |
|||
|
|||
[RCVD_FEECHANGE] = HTLC_ADDING + HTLC_REMOTE_F_OWNER |
|||
+ HTLC_LOCAL_F_PENDING, |
|||
|
|||
[RCVD_FEECHANGE_COMMIT] = HTLC_ADDING + HTLC_REMOTE_F_OWNER |
|||
+ HTLC_LOCAL_F_COMMITTED |
|||
+ HTLC_LOCAL_F_WAS_COMMITTED, |
|||
|
|||
[SENT_FEECHANGE_REVOCATION] = HTLC_ADDING + HTLC_REMOTE_F_OWNER |
|||
+ HTLC_LOCAL_F_COMMITTED |
|||
+ HTLC_LOCAL_F_REVOKED |
|||
+ HTLC_REMOTE_F_PENDING |
|||
+ HTLC_LOCAL_F_WAS_COMMITTED, |
|||
|
|||
[SENT_FEECHANGE_ACK_COMMIT] = HTLC_ADDING + HTLC_REMOTE_F_OWNER |
|||
+ HTLC_LOCAL_F_COMMITTED |
|||
+ HTLC_LOCAL_F_REVOKED |
|||
+ HTLC_REMOTE_F_COMMITTED |
|||
+ HTLC_LOCAL_F_WAS_COMMITTED |
|||
+ HTLC_REMOTE_F_WAS_COMMITTED, |
|||
|
|||
[RCVD_FEECHANGE_ACK_REVOCATION] = HTLC_REMOTE_F_OWNER |
|||
+ HTLC_LOCAL_F_COMMITTED |
|||
+ HTLC_LOCAL_F_REVOKED |
|||
+ HTLC_REMOTE_F_COMMITTED |
|||
+ HTLC_REMOTE_F_REVOKED |
|||
+ HTLC_LOCAL_F_WAS_COMMITTED |
|||
+ HTLC_REMOTE_F_WAS_COMMITTED, |
|||
}; |
|||
|
|||
int feechange_state_flags(enum feechange_state state) |
|||
{ |
|||
assert(state < ARRAY_SIZE(per_state_bits)); |
|||
assert(per_state_bits[state]); |
|||
return per_state_bits[state]; |
|||
} |
|||
|
|||
const char *feechange_state_name(enum feechange_state s) |
|||
{ |
|||
size_t i; |
|||
|
|||
for (i = 0; enum_feechange_state_names[i].name; i++) |
|||
if (enum_feechange_state_names[i].v == s) |
|||
return enum_feechange_state_names[i].name; |
|||
return "unknown"; |
|||
} |
|||
|
|||
enum feechange_state feechange_state_from_name(const char *name) |
|||
{ |
|||
size_t i; |
|||
|
|||
for (i = 0; enum_feechange_state_names[i].name; i++) |
|||
if (streq(enum_feechange_state_names[i].name, name)) |
|||
return enum_feechange_state_names[i].v; |
|||
return FEECHANGE_STATE_INVALID; |
|||
} |
|||
|
|||
struct feechange *new_feechange(struct peer *peer, |
|||
u64 fee_rate, |
|||
enum feechange_state state) |
|||
{ |
|||
struct feechange *f = tal(peer, struct feechange); |
|||
f->state = state; |
|||
f->fee_rate = fee_rate; |
|||
|
|||
return f; |
|||
} |
|||
|
|||
void feechange_changestate(struct peer *peer, |
|||
struct feechange *f, |
|||
enum feechange_state oldstate, |
|||
enum feechange_state newstate, |
|||
bool db_commit) |
|||
{ |
|||
peer_debug(peer, "feechange: %s->%s", |
|||
feechange_state_name(f->state), |
|||
feechange_state_name(newstate)); |
|||
assert(f->state == oldstate); |
|||
assert(peer->feechanges[f->state] == f); |
|||
|
|||
/* You can only go to consecutive states. */ |
|||
assert(newstate == f->state + 1); |
|||
|
|||
/* You can't change sides. */ |
|||
assert(feechange_side(f->state) == feechange_side(newstate)); |
|||
|
|||
f->state = newstate; |
|||
|
|||
/* We can have multiple dead feestates, but only one in any other */ |
|||
if (!feechange_is_dead(f)) |
|||
assert(!peer->feechanges[f->state]); |
|||
|
|||
peer->feechanges[oldstate] = NULL; |
|||
peer->feechanges[newstate] = f; |
|||
|
|||
if (db_commit) { |
|||
if (newstate == RCVD_FEECHANGE_COMMIT |
|||
|| newstate == SENT_FEECHANGE_COMMIT) |
|||
db_new_feechange(peer, f); |
|||
else if (newstate == RCVD_FEECHANGE_ACK_REVOCATION |
|||
|| newstate == SENT_FEECHANGE_ACK_REVOCATION) |
|||
db_remove_feechange(peer, f, oldstate); |
|||
else |
|||
db_update_feechange_state(peer, f, oldstate); |
|||
} |
|||
} |
@ -1,52 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_FEECHANGE_H |
|||
#define LIGHTNING_DAEMON_FEECHANGE_H |
|||
#include "config.h" |
|||
#include "channel.h" |
|||
#include "feechange_state.h" |
|||
|
|||
struct peer; |
|||
|
|||
struct feechange { |
|||
/* What's the status */ |
|||
enum feechange_state state; |
|||
/* The rate. */ |
|||
u64 fee_rate; |
|||
}; |
|||
|
|||
static inline enum side feechange_side(enum feechange_state state) |
|||
{ |
|||
if (state <= SENT_FEECHANGE_ACK_REVOCATION) { |
|||
return LOCAL; |
|||
} else { |
|||
assert(state < FEECHANGE_STATE_INVALID); |
|||
return REMOTE; |
|||
} |
|||
} |
|||
|
|||
void feechange_changestate(struct peer *peer, |
|||
struct feechange *feechange, |
|||
enum feechange_state oldstate, |
|||
enum feechange_state newstate, |
|||
bool db_commit); |
|||
|
|||
struct feechange *new_feechange(struct peer *peer, |
|||
u64 fee_rate, |
|||
enum feechange_state state); |
|||
|
|||
const char *feechange_state_name(enum feechange_state s); |
|||
enum feechange_state feechange_state_from_name(const char *name); |
|||
|
|||
/* HTLC-add-style bitflags for each feechange state */ |
|||
int feechange_state_flags(enum feechange_state state); |
|||
|
|||
static inline bool feechange_has(const struct feechange *f, int flag) |
|||
{ |
|||
return feechange_state_flags(f->state) & flag; |
|||
} |
|||
|
|||
static inline bool feechange_is_dead(const struct feechange *feechange) |
|||
{ |
|||
return feechange->state == SENT_FEECHANGE_ACK_REVOCATION |
|||
|| feechange->state == RCVD_FEECHANGE_ACK_REVOCATION; |
|||
} |
|||
#endif /* LIGHTNING_DAEMON_FEECHANGE_H */ |
@ -1,23 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_FEECHANGE_STATE_H |
|||
#define LIGHTNING_DAEMON_FEECHANGE_STATE_H |
|||
#include "config.h" |
|||
|
|||
/* Like HTLCs, but only adding; we never "remove" a feechange. */ |
|||
enum feechange_state { |
|||
/* When we add a new feechange, it goes in this order. */ |
|||
SENT_FEECHANGE, |
|||
SENT_FEECHANGE_COMMIT, |
|||
RCVD_FEECHANGE_REVOCATION, |
|||
RCVD_FEECHANGE_ACK_COMMIT, |
|||
SENT_FEECHANGE_ACK_REVOCATION, |
|||
|
|||
/* When they add a new feechange, it goes in this order. */ |
|||
RCVD_FEECHANGE, |
|||
RCVD_FEECHANGE_COMMIT, |
|||
SENT_FEECHANGE_REVOCATION, |
|||
SENT_FEECHANGE_ACK_COMMIT, |
|||
RCVD_FEECHANGE_ACK_REVOCATION, |
|||
|
|||
FEECHANGE_STATE_INVALID |
|||
}; |
|||
#endif /* LIGHTNING_DAEMON_FEECHANGE_STATE_H */ |
@ -1,81 +0,0 @@ |
|||
#include "db.h" |
|||
#include "htlc.h" |
|||
#include "log.h" |
|||
#include "peer.h" |
|||
#include "peer_internal.h" |
|||
#include "type_to_string.h" |
|||
#include <bitcoin/preimage.h> |
|||
#include <ccan/tal/str/str.h> |
|||
#include <inttypes.h> |
|||
|
|||
void htlc_changestate(struct htlc *h, |
|||
enum htlc_state oldstate, |
|||
enum htlc_state newstate, |
|||
bool db_commit) |
|||
{ |
|||
peer_debug(h->peer, "htlc %"PRIu64": %s->%s", h->id, |
|||
htlc_state_name(h->state), htlc_state_name(newstate)); |
|||
assert(h->state == oldstate); |
|||
|
|||
/* You can only go to consecutive states. */ |
|||
assert(newstate == h->state + 1); |
|||
|
|||
/* You can't change sides. */ |
|||
assert((htlc_state_flags(h->state)&(HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER)) |
|||
== (htlc_state_flags(newstate)&(HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER))); |
|||
|
|||
h->state = newstate; |
|||
|
|||
if (db_commit) { |
|||
if (newstate == RCVD_ADD_COMMIT || newstate == SENT_ADD_COMMIT) { |
|||
db_new_htlc(h->peer, h); |
|||
return; |
|||
} |
|||
/* These never hit the database. */ |
|||
if (oldstate == RCVD_REMOVE_HTLC) |
|||
oldstate = SENT_ADD_ACK_REVOCATION; |
|||
else if (oldstate == SENT_REMOVE_HTLC) |
|||
oldstate = RCVD_ADD_ACK_REVOCATION; |
|||
db_update_htlc_state(h->peer, h, oldstate); |
|||
} |
|||
} |
|||
|
|||
void htlc_undostate(struct htlc *h, |
|||
enum htlc_state oldstate, |
|||
enum htlc_state newstate) |
|||
{ |
|||
log_debug(h->peer->log, "htlc %"PRIu64": %s->%s", h->id, |
|||
htlc_state_name(h->state), htlc_state_name(newstate)); |
|||
assert(h->state == oldstate); |
|||
|
|||
/* You can only return to previous state. */ |
|||
assert(newstate == h->state - 1); |
|||
|
|||
/* And must only be proposal, not commit. */ |
|||
assert(h->state == SENT_REMOVE_HTLC || h->state == RCVD_REMOVE_HTLC); |
|||
|
|||
/* You can't change sides. */ |
|||
assert((htlc_state_flags(h->state)&(HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER)) |
|||
== (htlc_state_flags(newstate)&(HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER))); |
|||
|
|||
h->state = newstate; |
|||
} |
|||
|
|||
static char *fmt_htlc(const tal_t *ctx, const struct htlc *h) |
|||
{ |
|||
return tal_fmt(ctx, "{ id=%"PRIu64 |
|||
" msatoshi=%"PRIu64 |
|||
" expiry=%s" |
|||
" rhash=%s" |
|||
" rval=%s" |
|||
" src=%s }", |
|||
h->id, h->msatoshi, |
|||
type_to_string(ctx, struct abs_locktime, &h->expiry), |
|||
type_to_string(ctx, struct sha256, &h->rhash), |
|||
h->r ? tal_hexstr(ctx, h->r, sizeof(*h->r)) |
|||
: "UNKNOWN", |
|||
h->src ? type_to_string(ctx, struct pubkey, |
|||
h->src->peer->id) |
|||
: "local"); |
|||
} |
|||
REGISTER_TYPE_TO_STRING(htlc, fmt_htlc); |
@ -1,280 +0,0 @@ |
|||
#include "bitcoin/privkey.h" |
|||
#include "bitcoin/signature.h" |
|||
#include "daemon/chaintopology.h" |
|||
#include "daemon/irc_announce.h" |
|||
#include "daemon/lightningd.h" |
|||
#include "daemon/log.h" |
|||
#include "daemon/peer.h" |
|||
#include "daemon/peer_internal.h" |
|||
#include "daemon/routing.h" |
|||
#include "daemon/secrets.h" |
|||
#include "daemon/timeout.h" |
|||
#include "utils.h" |
|||
|
|||
#include <ccan/list/list.h> |
|||
#include <ccan/str/hex/hex.h> |
|||
|
|||
/* Sign a privmsg by prepending the signature to the message */ |
|||
static void sign_privmsg(struct ircstate *state, struct privmsg *msg) |
|||
{ |
|||
int siglen; |
|||
u8 der[72]; |
|||
secp256k1_ecdsa_signature sig; |
|||
privkey_sign(state->dstate, msg->msg, strlen(msg->msg), &sig); |
|||
siglen = signature_to_der(der, &sig); |
|||
msg->msg = tal_fmt(msg, "%s %s", tal_hexstr(msg, der, siglen), msg->msg); |
|||
} |
|||
|
|||
static bool announce_channel(const tal_t *ctx, struct ircstate *state, struct peer *p) |
|||
{ |
|||
char txid[65]; |
|||
struct privmsg *msg = talz(ctx, struct privmsg); |
|||
struct txlocator *loc = locate_tx(ctx, state->dstate->topology, &p->anchor.txid); |
|||
|
|||
if (loc == NULL) |
|||
return false; |
|||
|
|||
bitcoin_txid_to_hex(&p->anchor.txid, txid, sizeof(txid)); |
|||
msg->channel = "#lightning-nodes"; |
|||
msg->msg = tal_fmt( |
|||
msg, "CHAN %s %s %s %d %d %d %d %d", |
|||
pubkey_to_hexstr(msg, &state->dstate->id), |
|||
pubkey_to_hexstr(msg, p->id), |
|||
txid, |
|||
loc->blkheight, |
|||
loc->index, |
|||
state->dstate->config.fee_base, |
|||
state->dstate->config.fee_per_satoshi, |
|||
state->dstate->config.min_htlc_expiry |
|||
); |
|||
sign_privmsg(state, msg); |
|||
irc_send_msg(state, msg); |
|||
return true; |
|||
} |
|||
|
|||
/* Send an announcement for this node to the channel, including its
|
|||
* hostname, port and ID */ |
|||
static void announce_node(const tal_t *ctx, struct ircstate *state) |
|||
{ |
|||
char *hostname = state->dstate->external_ip; |
|||
int port = state->dstate->portnum; |
|||
struct privmsg *msg = talz(ctx, struct privmsg); |
|||
|
|||
if (hostname == NULL) { |
|||
//FIXME: log that we don't know our IP yet.
|
|||
return; |
|||
} |
|||
|
|||
msg->channel = "#lightning-nodes"; |
|||
msg->msg = tal_fmt( |
|||
msg, "NODE %s %s %d", |
|||
pubkey_to_hexstr(msg, &state->dstate->id), |
|||
hostname, |
|||
port |
|||
); |
|||
|
|||
sign_privmsg(state, msg); |
|||
irc_send_msg(state, msg); |
|||
} |
|||
|
|||
/* Announce the node's contact information and all of its channels */ |
|||
static void announce(struct ircstate *state) |
|||
{ |
|||
|
|||
tal_t *ctx = tal(state, tal_t); |
|||
struct peer *p; |
|||
|
|||
announce_node(ctx, state); |
|||
|
|||
list_for_each(&state->dstate->peers, p, list) { |
|||
|
|||
if (!state_is_normal(p->state)) |
|||
continue; |
|||
announce_channel(ctx, state, p); |
|||
} |
|||
tal_free(ctx); |
|||
|
|||
/* By default we announce every 6 hours, otherwise when someone joins */ |
|||
log_debug(state->log, "Setting long announce time: 6 hours"); |
|||
state->dstate->announce = new_reltimer(&state->dstate->timers, state, |
|||
time_from_sec(3600 * 6), |
|||
announce, state); |
|||
} |
|||
|
|||
/* Reconnect to IRC server upon disconnection. */ |
|||
static void handle_irc_disconnect(struct ircstate *state) |
|||
{ |
|||
/* Stop announcing. */ |
|||
state->dstate->announce = tal_free(state->dstate->announce); |
|||
new_reltimer(&state->dstate->timers, state, state->reconnect_timeout, |
|||
irc_connect, state); |
|||
} |
|||
|
|||
/* Verify a signed privmsg */ |
|||
static bool verify_signed_privmsg( |
|||
struct ircstate *istate, |
|||
const struct pubkey *pk, |
|||
const struct privmsg *msg) |
|||
{ |
|||
secp256k1_ecdsa_signature sig; |
|||
struct sha256_double hash; |
|||
const char *m = msg->msg + 1; |
|||
int siglen = strchr(m, ' ') - m; |
|||
const char *content = m + siglen + 1; |
|||
u8 *der = tal_hexdata(msg, m, siglen); |
|||
|
|||
siglen = hex_data_size(siglen); |
|||
if (der == NULL) |
|||
return false; |
|||
|
|||
if (!signature_from_der(der, siglen, &sig)) |
|||
return false; |
|||
sha256_double(&hash, content, strlen(content)); |
|||
return check_signed_hash(&hash, &sig, pk); |
|||
} |
|||
|
|||
static void handle_irc_channel_announcement( |
|||
struct ircstate *istate, |
|||
const struct privmsg *msg, |
|||
char **splits) |
|||
{ |
|||
struct pubkey *pk1 = talz(msg, struct pubkey); |
|||
struct pubkey *pk2 = talz(msg, struct pubkey); |
|||
struct sha256_double *txid = talz(msg, struct sha256_double); |
|||
int index; |
|||
bool ok = true; |
|||
int blkheight; |
|||
|
|||
ok &= pubkey_from_hexstr(splits[1], strlen(splits[1]), pk1); |
|||
ok &= pubkey_from_hexstr(splits[2], strlen(splits[2]), pk2); |
|||
ok &= bitcoin_txid_from_hex(splits[3], strlen(splits[3]), txid); |
|||
blkheight = atoi(splits[4]); |
|||
index = atoi(splits[5]); |
|||
if (!ok || index < 0 || blkheight < 0) { |
|||
log_debug(istate->dstate->base_log, "Unable to parse channel announcent."); |
|||
return; |
|||
} |
|||
|
|||
if (!verify_signed_privmsg(istate, pk1, msg)) { |
|||
log_debug(istate->log, |
|||
"Ignoring announcement from %s, signature check failed.", |
|||
splits[1]); |
|||
return; |
|||
} |
|||
|
|||
/*
|
|||
* FIXME Check in topology that the tx is in the block and |
|||
* that the endpoints match. |
|||
*/ |
|||
|
|||
add_connection(istate->dstate->rstate, pk1, pk2, atoi(splits[6]), |
|||
atoi(splits[7]), atoi(splits[8]), 6); |
|||
} |
|||
|
|||
static void handle_irc_node_announcement( |
|||
struct ircstate *istate, |
|||
const struct privmsg *msg, |
|||
char **splits) |
|||
{ |
|||
struct pubkey *pk = talz(msg, struct pubkey); |
|||
if (!pubkey_from_hexstr(splits[1], strlen(splits[1]), pk)) |
|||
return; |
|||
|
|||
if (!verify_signed_privmsg(istate, pk, msg)) { |
|||
log_debug(istate->log, "Ignoring node announcement from %s, signature check failed.", |
|||
splits[1]); |
|||
return; |
|||
} else if(splits[4] != NULL && strlen(splits[4]) > 64) { |
|||
log_debug(istate->log, "Ignoring node announcement from %s, alias too long", |
|||
splits[1]); |
|||
} |
|||
|
|||
struct node *node = add_node(istate->dstate->rstate, pk); |
|||
if (splits[4] != NULL){ |
|||
tal_free(node->alias); |
|||
node->alias = tal_hexdata(node, splits[4], strlen(splits[4])); |
|||
} |
|||
} |
|||
|
|||
/*
|
|||
* Handle an incoming message by checking if it is a channel |
|||
* announcement, parse it and add the channel to the topology if yes. |
|||
* |
|||
* The format for a valid announcement is: |
|||
* <sig> CHAN <pk1> <pk2> <anchor txid> <block height> <tx position> <base_fee> |
|||
* <proportional_fee> <locktime> |
|||
*/ |
|||
static void handle_irc_privmsg(struct ircstate *istate, const struct privmsg *msg) |
|||
{ |
|||
char **splits = tal_strsplit(msg, msg->msg + 1, " ", STR_NO_EMPTY); |
|||
int splitcount = tal_count(splits) - 1; |
|||
|
|||
if (splitcount < 2) |
|||
return; |
|||
|
|||
char *type = splits[1]; |
|||
|
|||
if (splitcount == 10 && streq(type, "CHAN")) |
|||
handle_irc_channel_announcement(istate, msg, splits + 1); |
|||
else if (splitcount >= 5 && streq(type, "NODE")) |
|||
handle_irc_node_announcement(istate, msg, splits + 1); |
|||
} |
|||
|
|||
static void handle_irc_command(struct ircstate *istate, const struct irccommand *cmd) |
|||
{ |
|||
struct lightningd_state *dstate = istate->dstate; |
|||
char **params = tal_strsplit(cmd, cmd->params, " ", STR_NO_EMPTY); |
|||
|
|||
if (streq(cmd->command, "338") && tal_count(params) >= 4) { |
|||
dstate->external_ip = tal_strdup( |
|||
istate->dstate, params[3]); |
|||
log_debug(dstate->base_log, "Detected my own IP as %s", dstate->external_ip); |
|||
|
|||
// Add our node to the node_map for completeness
|
|||
add_node(istate->dstate->rstate, &dstate->id); |
|||
} else if (streq(cmd->command, "JOIN")) { |
|||
unsigned int delay; |
|||
|
|||
/* Throw away any existing announce timer, and announce within
|
|||
* 60 seconds. */ |
|||
dstate->announce = tal_free(dstate->announce); |
|||
|
|||
delay = pseudorand(60000000); |
|||
log_debug(istate->log, "Setting new announce time %u sec", |
|||
delay / 1000000); |
|||
dstate->announce = new_reltimer(&dstate->timers, istate, |
|||
time_from_usec(delay), |
|||
announce, istate); |
|||
} |
|||
} |
|||
|
|||
static void handle_irc_connected(struct ircstate *istate) |
|||
{ |
|||
irc_send(istate, "JOIN", "#lightning-nodes"); |
|||
irc_send(istate, "WHOIS", "%s", istate->nick); |
|||
} |
|||
|
|||
void setup_irc_connection(struct lightningd_state *dstate) |
|||
{ |
|||
// Register callback
|
|||
irc_privmsg_cb = *handle_irc_privmsg; |
|||
irc_connect_cb = *handle_irc_connected; |
|||
irc_disconnect_cb = *handle_irc_disconnect; |
|||
irc_command_cb = *handle_irc_command; |
|||
|
|||
struct ircstate *state = talz(dstate, struct ircstate); |
|||
state->dstate = dstate; |
|||
state->server = "irc.lfnet.org"; |
|||
state->reconnect_timeout = time_from_sec(15); |
|||
state->log = new_log(state, state->dstate->log_book, "%s:irc", |
|||
log_prefix(state->dstate->base_log)); |
|||
|
|||
/* Truncate nick at 13 bytes, would be imposed by freenode anyway */ |
|||
state->nick = tal_fmt( |
|||
state, |
|||
"N%.12s", |
|||
pubkey_to_hexstr(state, &dstate->id) + 1); |
|||
|
|||
/* We will see our own JOIN message, which will trigger announce */ |
|||
irc_connect(state); |
|||
} |
@ -1,9 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_IRC_ANNOUNCE_H |
|||
#define LIGHTNING_DAEMON_IRC_ANNOUNCE_H |
|||
#include "config.h" |
|||
#include "irc.h" |
|||
|
|||
// Main entrypoint for the lightning daemon
|
|||
void setup_irc_connection(struct lightningd_state *dstate); |
|||
|
|||
#endif /* LIGHTNING_DAEMON_IRC_ANNOUNCE_H */ |
@ -1,174 +0,0 @@ |
|||
#include "bitcoind.h" |
|||
#include "chaintopology.h" |
|||
#include "db.h" |
|||
#include "invoice.h" |
|||
#include "irc_announce.h" |
|||
#include "jsonrpc.h" |
|||
#include "lightningd.h" |
|||
#include "log.h" |
|||
#include "options.h" |
|||
#include "p2p_announce.h" |
|||
#include "peer.h" |
|||
#include "routing.h" |
|||
#include "secrets.h" |
|||
#include "timeout.h" |
|||
#include "utils.h" |
|||
#include <bitcoin/chainparams.h> |
|||
#include <ccan/container_of/container_of.h> |
|||
#include <ccan/err/err.h> |
|||
#include <ccan/io/io.h> |
|||
#include <ccan/opt/opt.h> |
|||
#include <ccan/tal/grab_file/grab_file.h> |
|||
#include <ccan/tal/str/str.h> |
|||
#include <ccan/tal/tal.h> |
|||
#include <ccan/time/time.h> |
|||
#include <ccan/timer/timer.h> |
|||
#include <errno.h> |
|||
#include <inttypes.h> |
|||
#include <signal.h> |
|||
#include <unistd.h> |
|||
#include <version.h> |
|||
|
|||
static struct lightningd_state *lightningd_state(void) |
|||
{ |
|||
struct lightningd_state *dstate = tal(NULL, struct lightningd_state); |
|||
struct sha256_double unused; |
|||
|
|||
dstate->log_book = new_log_book(dstate, 20*1024*1024, LOG_INFORM); |
|||
dstate->base_log = new_log(dstate, dstate->log_book, |
|||
"lightningd(%u):", (int)getpid()); |
|||
|
|||
list_head_init(&dstate->peers); |
|||
list_head_init(&dstate->pay_commands); |
|||
dstate->portnum = 0; |
|||
dstate->testnet = true; |
|||
timers_init(&dstate->timers, time_mono()); |
|||
list_head_init(&dstate->wallet); |
|||
list_head_init(&dstate->addresses); |
|||
dstate->dev_never_routefail = false; |
|||
dstate->rstate = new_routing_state(dstate, dstate->base_log, &unused); |
|||
dstate->reexec = NULL; |
|||
dstate->external_ip = NULL; |
|||
dstate->announce = NULL; |
|||
dstate->invoices = invoices_init(dstate); |
|||
return dstate; |
|||
} |
|||
|
|||
static void json_lightningd_dev_broadcast(struct command *cmd, |
|||
const char *buffer, |
|||
const jsmntok_t *params) |
|||
{ |
|||
json_dev_broadcast(cmd, cmd->dstate->topology, buffer, params); |
|||
} |
|||
|
|||
static const struct json_command dev_broadcast_command = { |
|||
"dev-broadcast", |
|||
json_lightningd_dev_broadcast, |
|||
"Pretend we broadcast txs, but don't send to bitcoind", |
|||
"Returns an empty result on success (waits for flush if enabled)" |
|||
}; |
|||
AUTODATA(json_command, &dev_broadcast_command); |
|||
|
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
struct lightningd_state *dstate = lightningd_state(); |
|||
|
|||
err_set_progname(argv[0]); |
|||
|
|||
if (!streq(protobuf_c_version(), PROTOBUF_C_VERSION)) |
|||
errx(1, "Compiled against protobuf %s, but have %s", |
|||
PROTOBUF_C_VERSION, protobuf_c_version()); |
|||
|
|||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY |
|||
| SECP256K1_CONTEXT_SIGN); |
|||
|
|||
dstate->topology = new_topology(dstate, dstate->base_log); |
|||
dstate->bitcoind = new_bitcoind(dstate, dstate->base_log); |
|||
dstate->bitcoind->chainparams = chainparams_for_network("regtest"); |
|||
|
|||
/* Handle options and config; move to .lightningd */ |
|||
register_opts(dstate); |
|||
handle_opts(dstate, argc, argv); |
|||
|
|||
/* Now we can set chain_hash properly. */ |
|||
dstate->rstate->chain_hash |
|||
= dstate->bitcoind->chainparams->genesis_blockhash; |
|||
|
|||
/* Activate crash log now we're in the right place. */ |
|||
crashlog_activate(dstate->base_log); |
|||
|
|||
/* Ignore SIGPIPE: we look at our write return values*/ |
|||
signal(SIGPIPE, SIG_IGN); |
|||
|
|||
/* Set up node ID and private key. */ |
|||
secrets_init(dstate); |
|||
new_node(dstate->rstate, &dstate->id); |
|||
|
|||
/* Read or create database. */ |
|||
db_init(dstate); |
|||
|
|||
/* Initialize block topology. */ |
|||
setup_topology(dstate->topology, dstate->bitcoind, &dstate->timers, |
|||
dstate->config.poll_time, |
|||
get_peer_min_block(dstate)); |
|||
|
|||
/* Create RPC socket (if any) */ |
|||
setup_jsonrpc(dstate, dstate->rpc_filename); |
|||
|
|||
/* Set up connections from peers (if dstate->portnum is set) */ |
|||
setup_listeners(dstate); |
|||
|
|||
/* set up IRC peer discovery */ |
|||
if (dstate->config.use_irc) |
|||
setup_irc_connection(dstate); |
|||
|
|||
/* set up P2P gossip protocol */ |
|||
setup_p2p_announce(dstate); |
|||
|
|||
log_info(dstate->base_log, "Hello world!"); |
|||
|
|||
/* If we loaded peers from database, reconnect now. */ |
|||
reconnect_peers(dstate); |
|||
|
|||
/* And send out anchors again if we're waiting. */ |
|||
rebroadcast_anchors(dstate); |
|||
|
|||
for (;;) { |
|||
struct timer *expired; |
|||
void *v = io_loop(&dstate->timers, &expired); |
|||
|
|||
/* We use io_break(dstate) to shut down. */ |
|||
if (v == dstate) |
|||
break; |
|||
|
|||
if (expired) |
|||
timer_expired(dstate, expired); |
|||
else |
|||
cleanup_peers(dstate); |
|||
} |
|||
|
|||
if (dstate->reexec) { |
|||
int fd; |
|||
|
|||
log_unusual(dstate->base_log, "Restart at user request"); |
|||
fflush(stdout); |
|||
fflush(stderr); |
|||
|
|||
/* Manually close all fds (or near enough!) */ |
|||
for (fd = 3; fd < 1024; fd++) |
|||
close(fd); |
|||
|
|||
if (dstate->dev_never_routefail) { |
|||
size_t n = tal_count(dstate->reexec); |
|||
tal_resizez(&dstate->reexec, n+1); |
|||
dstate->reexec[n-1] = "--dev-no-routefail"; |
|||
} |
|||
execvp(dstate->reexec[0], dstate->reexec); |
|||
fatal("Exec '%s' failed: %s", |
|||
dstate->reexec[0], strerror(errno)); |
|||
} |
|||
|
|||
tal_free(dstate); |
|||
opt_free_table(); |
|||
return 0; |
|||
} |
@ -1,36 +0,0 @@ |
|||
#include "names.h" |
|||
#include <ccan/str/str.h> |
|||
/* Indented for 'check-source' because it has to be included after names.h */ |
|||
#include "daemon/gen_state_names.h" |
|||
#include "daemon/gen_pkt_names.h" |
|||
|
|||
const char *state_name(enum state s) |
|||
{ |
|||
size_t i; |
|||
|
|||
for (i = 0; enum_state_names[i].name; i++) |
|||
if (enum_state_names[i].v == s) |
|||
return enum_state_names[i].name; |
|||
return "unknown"; |
|||
} |
|||
|
|||
enum state name_to_state(const char *name) |
|||
{ |
|||
size_t i; |
|||
|
|||
for (i = 0; enum_state_names[i].name; i++) |
|||
if (streq(name, enum_state_names[i].name)) |
|||
return enum_state_names[i].v; |
|||
|
|||
return STATE_MAX; |
|||
} |
|||
|
|||
const char *pkt_name(Pkt__PktCase pkt) |
|||
{ |
|||
size_t i; |
|||
|
|||
for (i = 0; enum_PktCase_names[i].name; i++) |
|||
if (enum_PktCase_names[i].v == pkt) |
|||
return enum_PktCase_names[i].name; |
|||
return "unknown"; |
|||
} |
@ -1,10 +0,0 @@ |
|||
#ifndef LIGHTNING_NAMES_H |
|||
#define LIGHTNING_NAMES_H |
|||
#include "config.h" |
|||
#include "lightning.pb-c.h" |
|||
#include "state_types.h" |
|||
|
|||
const char *state_name(enum state s); |
|||
enum state name_to_state(const char *name); |
|||
const char *pkt_name(Pkt__PktCase pkt); |
|||
#endif /* LIGHTNING_NAMES_H */ |
@ -1,80 +0,0 @@ |
|||
#include "commit_tx.h" |
|||
#include "output_to_htlc.h" |
|||
#include "peer.h" |
|||
#include "peer_internal.h" |
|||
|
|||
/* FIXME: Array makes this O(n^2). Use a hash table. */ |
|||
struct wscript_by_wpkh { |
|||
struct htlc *h; |
|||
const u8 *wscript; |
|||
struct sha256 hash; |
|||
}; |
|||
|
|||
struct htlc_output_map { |
|||
struct wscript_by_wpkh *wpkh; |
|||
}; |
|||
|
|||
struct htlc_output_map *get_htlc_output_map(const tal_t *ctx, |
|||
const struct peer *peer, |
|||
const struct sha256 *rhash, |
|||
enum side side, |
|||
unsigned int commit_num) |
|||
{ |
|||
struct htlc_map_iter it; |
|||
struct htlc *h; |
|||
size_t i; |
|||
struct htlc_output_map *omap = tal(ctx, struct htlc_output_map); |
|||
|
|||
/* FIXME: use commit_num to filter htlcs. */ |
|||
if (side == LOCAL) |
|||
assert(commit_num <= peer->local.commit->commit_num); |
|||
else |
|||
assert(commit_num <= peer->remote.commit->commit_num); |
|||
|
|||
omap->wpkh = tal_arr(omap, struct wscript_by_wpkh, |
|||
htlc_map_count(&peer->htlcs)); |
|||
|
|||
for (i = 0, h = htlc_map_first(&peer->htlcs, &it); |
|||
h; |
|||
h = htlc_map_next(&peer->htlcs, &it)) { |
|||
omap->wpkh[i].h = h; |
|||
omap->wpkh[i].wscript = wscript_for_htlc(omap, peer, h, rhash, |
|||
side); |
|||
sha256(&omap->wpkh[i].hash, |
|||
omap->wpkh[i].wscript, |
|||
tal_count(omap->wpkh[i].wscript)); |
|||
i++; |
|||
} |
|||
tal_resize(&omap->wpkh, i); |
|||
return omap; |
|||
} |
|||
|
|||
static struct wscript_by_wpkh *get_wpkh(struct htlc_output_map *omap, |
|||
const u8 *script) |
|||
{ |
|||
size_t i; |
|||
|
|||
if (!is_p2wsh(script)) |
|||
return NULL; |
|||
|
|||
for (i = 0; i < tal_count(omap->wpkh); i++) { |
|||
if (!memcmp(script + 2, omap->wpkh[i].hash.u.u8, |
|||
sizeof(omap->wpkh[i].hash))) |
|||
return &omap->wpkh[i]; |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
/* Which wscript does this pay to? */ |
|||
struct htlc *txout_get_htlc(struct htlc_output_map *omap, |
|||
const u8 *script, |
|||
const u8 **wscript) |
|||
{ |
|||
struct wscript_by_wpkh *wpkh = get_wpkh(omap, script); |
|||
|
|||
if (wpkh) { |
|||
*wscript = wpkh->wscript; |
|||
return wpkh->h; |
|||
} |
|||
return NULL; |
|||
} |
@ -1,20 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_OUTPUT_TO_HTLC_H |
|||
#define LIGHTNING_DAEMON_OUTPUT_TO_HTLC_H |
|||
#include "config.h" |
|||
#include "htlc.h" |
|||
|
|||
struct peer; |
|||
struct sha256; |
|||
|
|||
/* Get a map of HTLCs (including at least those at the given commit_num). */ |
|||
struct htlc_output_map *get_htlc_output_map(const tal_t *ctx, |
|||
const struct peer *peer, |
|||
const struct sha256 *rhash, |
|||
enum side side, |
|||
unsigned int commit_num); |
|||
|
|||
/* If this scriptPubkey pays to a HTLC, get the full wscript */ |
|||
struct htlc *txout_get_htlc(struct htlc_output_map *omap, |
|||
const u8 *script, const u8 **wscript); |
|||
|
|||
#endif /* LIGHTNING_DAEMON_OUTPUT_TO_HTLC_H */ |
@ -1,231 +0,0 @@ |
|||
#include "daemon/broadcast.h" |
|||
#include "daemon/chaintopology.h" |
|||
#include "daemon/log.h" |
|||
#include "daemon/p2p_announce.h" |
|||
#include "daemon/packets.h" |
|||
#include "daemon/peer.h" |
|||
#include "daemon/peer_internal.h" |
|||
#include "daemon/routing.h" |
|||
#include "daemon/secrets.h" |
|||
#include "daemon/timeout.h" |
|||
#include "utils.h" |
|||
|
|||
#include <ccan/tal/str/str.h> |
|||
#include <ccan/tal/tal.h> |
|||
#include <secp256k1.h> |
|||
|
|||
static void broadcast_channel_update(struct lightningd_state *dstate, struct peer *peer) |
|||
{ |
|||
struct txlocator *loc; |
|||
u8 *serialized; |
|||
secp256k1_ecdsa_signature signature; |
|||
struct short_channel_id short_channel_id; |
|||
u32 timestamp = time_now().ts.tv_sec; |
|||
const tal_t *tmpctx = tal_tmpctx(dstate); |
|||
|
|||
loc = locate_tx(tmpctx, dstate->topology, &peer->anchor.txid); |
|||
short_channel_id.blocknum = loc->blkheight; |
|||
short_channel_id.txnum = loc->index; |
|||
short_channel_id.outnum = peer->anchor.index; |
|||
|
|||
/* Avoid triggering memcheck */ |
|||
memset(&signature, 0, sizeof(signature)); |
|||
|
|||
serialized = towire_channel_update(tmpctx, &signature, |
|||
&dstate->rstate->chain_hash, |
|||
&short_channel_id, |
|||
timestamp, |
|||
pubkey_cmp(&dstate->id, peer->id) > 0, |
|||
dstate->config.min_htlc_expiry, |
|||
//FIXME(cdecker) Make the minimum HTLC configurable
|
|||
1, |
|||
dstate->config.fee_base, |
|||
dstate->config.fee_per_satoshi); |
|||
privkey_sign(dstate, serialized + 66, tal_count(serialized) - 66, |
|||
&signature); |
|||
serialized = towire_channel_update(tmpctx, &signature, |
|||
&dstate->rstate->chain_hash, |
|||
&short_channel_id, |
|||
timestamp, |
|||
pubkey_cmp(&dstate->id, peer->id) > 0, |
|||
dstate->config.min_htlc_expiry, |
|||
1, |
|||
dstate->config.fee_base, |
|||
dstate->config.fee_per_satoshi); |
|||
u8 *tag = tal_arr(tmpctx, u8, 0); |
|||
towire_short_channel_id(&tag, &short_channel_id); |
|||
queue_broadcast(dstate->rstate->broadcasts, WIRE_CHANNEL_UPDATE, tag, serialized); |
|||
tal_free(tmpctx); |
|||
} |
|||
|
|||
static void broadcast_node_announcement(struct lightningd_state *dstate) |
|||
{ |
|||
u8 *serialized; |
|||
secp256k1_ecdsa_signature signature; |
|||
static const u8 rgb_color[3]; |
|||
static const u8 alias[32]; |
|||
u32 timestamp = time_now().ts.tv_sec; |
|||
const tal_t *tmpctx = tal_tmpctx(dstate); |
|||
u8 *address; |
|||
|
|||
/* Are we listening for incoming connections at all? */ |
|||
if (!dstate->external_ip || !dstate->portnum) { |
|||
tal_free(tmpctx); |
|||
return; |
|||
} |
|||
|
|||
/* Avoid triggering memcheck */ |
|||
memset(&signature, 0, sizeof(signature)); |
|||
|
|||
address = write_ip(tmpctx, dstate->external_ip, dstate->portnum); |
|||
serialized = towire_node_announcement(tmpctx, &signature, |
|||
NULL, |
|||
timestamp, |
|||
&dstate->id, rgb_color, alias, |
|||
address); |
|||
privkey_sign(dstate, serialized + 66, tal_count(serialized) - 66, |
|||
&signature); |
|||
serialized = towire_node_announcement(tmpctx, &signature, |
|||
NULL, |
|||
timestamp, |
|||
&dstate->id, rgb_color, alias, |
|||
address); |
|||
u8 *tag = tal_arr(tmpctx, u8, 0); |
|||
towire_pubkey(&tag, &dstate->id); |
|||
queue_broadcast(dstate->rstate->broadcasts, WIRE_NODE_ANNOUNCEMENT, tag, |
|||
serialized); |
|||
tal_free(tmpctx); |
|||
} |
|||
|
|||
static void broadcast_channel_announcement(struct lightningd_state *dstate, struct peer *peer) |
|||
{ |
|||
struct txlocator *loc; |
|||
struct short_channel_id short_channel_id; |
|||
secp256k1_ecdsa_signature node_signature[2]; |
|||
secp256k1_ecdsa_signature bitcoin_signature[2]; |
|||
const struct pubkey *node_id[2]; |
|||
const struct pubkey *bitcoin_key[2]; |
|||
secp256k1_ecdsa_signature *my_node_signature; |
|||
secp256k1_ecdsa_signature *my_bitcoin_signature; |
|||
u8 *serialized; |
|||
const tal_t *tmpctx = tal_tmpctx(dstate); |
|||
|
|||
loc = locate_tx(tmpctx, dstate->topology, &peer->anchor.txid); |
|||
|
|||
short_channel_id.blocknum = loc->blkheight; |
|||
short_channel_id.txnum = loc->index; |
|||
short_channel_id.outnum = peer->anchor.index; |
|||
|
|||
/* Set all sigs to zero */ |
|||
memset(node_signature, 0, sizeof(node_signature)); |
|||
memset(bitcoin_signature, 0, sizeof(bitcoin_signature)); |
|||
|
|||
//FIXME(cdecker) Copy remote stored signatures into place
|
|||
if (pubkey_cmp(&dstate->id, peer->id) > 0) { |
|||
node_id[0] = peer->id; |
|||
node_id[1] = &dstate->id; |
|||
bitcoin_key[0] = peer->id; |
|||
bitcoin_key[1] = &dstate->id; |
|||
my_node_signature = &node_signature[1]; |
|||
my_bitcoin_signature = &bitcoin_signature[1]; |
|||
} else { |
|||
node_id[1] = peer->id; |
|||
node_id[0] = &dstate->id; |
|||
bitcoin_key[1] = peer->id; |
|||
bitcoin_key[0] = &dstate->id; |
|||
my_node_signature = &node_signature[0]; |
|||
my_bitcoin_signature = &bitcoin_signature[0]; |
|||
} |
|||
|
|||
/* Sign the node_id with the bitcoin_key, proves delegation */ |
|||
serialized = tal_arr(tmpctx, u8, 0); |
|||
towire_pubkey(&serialized, &dstate->id); |
|||
privkey_sign(dstate, serialized, tal_count(serialized), my_bitcoin_signature); |
|||
|
|||
/* BOLT #7:
|
|||
* |
|||
* The creating node MUST compute the double-SHA256 hash `h` of the |
|||
* message, starting at offset 256, up to the end of the message. |
|||
*/ |
|||
serialized = towire_channel_announcement(tmpctx, &node_signature[0], |
|||
&node_signature[1], |
|||
&bitcoin_signature[0], |
|||
&bitcoin_signature[1], |
|||
NULL, |
|||
&dstate->rstate->chain_hash, |
|||
&short_channel_id, |
|||
node_id[0], |
|||
node_id[1], |
|||
bitcoin_key[0], |
|||
bitcoin_key[1]); |
|||
privkey_sign(dstate, serialized + 256, tal_count(serialized) - 256, my_node_signature); |
|||
|
|||
serialized = towire_channel_announcement(tmpctx, &node_signature[0], |
|||
&node_signature[1], |
|||
&bitcoin_signature[0], |
|||
&bitcoin_signature[1], |
|||
NULL, |
|||
&dstate->rstate->chain_hash, |
|||
&short_channel_id, |
|||
node_id[0], |
|||
node_id[1], |
|||
bitcoin_key[0], |
|||
bitcoin_key[1]); |
|||
u8 *tag = tal_arr(tmpctx, u8, 0); |
|||
towire_short_channel_id(&tag, &short_channel_id); |
|||
queue_broadcast(dstate->rstate->broadcasts, WIRE_CHANNEL_ANNOUNCEMENT, |
|||
tag, serialized); |
|||
tal_free(tmpctx); |
|||
} |
|||
|
|||
static void announce(struct lightningd_state *dstate) |
|||
{ |
|||
struct peer *p; |
|||
int nchan = 0; |
|||
|
|||
new_reltimer(&dstate->timers, dstate, time_from_sec(5*60*60), announce, dstate); |
|||
|
|||
list_for_each(&dstate->peers, p, list) { |
|||
if (state_is_normal(p->state)) { |
|||
broadcast_channel_announcement(dstate, p); |
|||
broadcast_channel_update(dstate, p); |
|||
nchan += 1; |
|||
} |
|||
} |
|||
|
|||
/* No point in broadcasting our node if we don't have a channel */ |
|||
if (nchan > 0) |
|||
broadcast_node_announcement(dstate); |
|||
} |
|||
|
|||
void announce_channel(struct lightningd_state *dstate, struct peer *peer) |
|||
{ |
|||
broadcast_channel_announcement(dstate, peer); |
|||
broadcast_channel_update(dstate, peer); |
|||
broadcast_node_announcement(dstate); |
|||
|
|||
} |
|||
|
|||
static void process_broadcast_queue(struct lightningd_state *dstate) |
|||
{ |
|||
struct peer *p; |
|||
struct queued_message *msg; |
|||
new_reltimer(&dstate->timers, dstate, time_from_sec(30), process_broadcast_queue, dstate); |
|||
list_for_each(&dstate->peers, p, list) { |
|||
if (!state_is_normal(p->state)) |
|||
continue; |
|||
msg = next_broadcast_message(dstate->rstate->broadcasts, |
|||
&p->broadcast_index); |
|||
while (msg != NULL) { |
|||
queue_pkt_nested(p, msg->type, msg->payload); |
|||
msg = next_broadcast_message(dstate->rstate->broadcasts, |
|||
&p->broadcast_index); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void setup_p2p_announce(struct lightningd_state *dstate) |
|||
{ |
|||
new_reltimer(&dstate->timers, dstate, time_from_sec(5*60*60), announce, dstate); |
|||
new_reltimer(&dstate->timers, dstate, time_from_sec(30), process_broadcast_queue, dstate); |
|||
} |
@ -1,15 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_P2P_ANNOUNCE_H |
|||
#define LIGHTNING_DAEMON_P2P_ANNOUNCE_H |
|||
#include "config.h" |
|||
#include "daemon/broadcast.h" |
|||
#include "daemon/lightningd.h" |
|||
#include "daemon/routing.h" |
|||
#include "lightningd.h" |
|||
#include "wire/gen_peer_wire.h" |
|||
|
|||
void setup_p2p_announce(struct lightningd_state *dstate); |
|||
|
|||
/* Used to announce the existence of a channel and the endpoints */ |
|||
void announce_channel(struct lightningd_state *dstate, struct peer *peer); |
|||
|
|||
#endif /* LIGHTNING_DAEMON_P2P_ANNOUNCE_H */ |
@ -1,599 +0,0 @@ |
|||
#include "bitcoin/preimage.h" |
|||
#include "bitcoin/script.h" |
|||
#include "bitcoin/tx.h" |
|||
#include "chaintopology.h" |
|||
#include "close_tx.h" |
|||
#include "commit_tx.h" |
|||
#include "cryptopkt.h" |
|||
#include "htlc.h" |
|||
#include "lightningd.h" |
|||
#include "log.h" |
|||
#include "names.h" |
|||
#include "packets.h" |
|||
#include "peer.h" |
|||
#include "peer_internal.h" |
|||
#include "protobuf_convert.h" |
|||
#include "secrets.h" |
|||
#include "state.h" |
|||
#include "utils.h" |
|||
#include <ccan/array_size/array_size.h> |
|||
#include <ccan/crypto/sha256/sha256.h> |
|||
#include <ccan/io/io.h> |
|||
#include <ccan/mem/mem.h> |
|||
#include <ccan/ptrint/ptrint.h> |
|||
#include <ccan/str/hex/hex.h> |
|||
#include <ccan/structeq/structeq.h> |
|||
#include <ccan/tal/str/str.h> |
|||
#include <inttypes.h> |
|||
|
|||
/* Wrap (and own!) member inside Pkt */ |
|||
static Pkt *make_pkt(const tal_t *ctx, Pkt__PktCase type, const void *msg) |
|||
{ |
|||
Pkt *pkt = tal(ctx, Pkt); |
|||
|
|||
pkt__init(pkt); |
|||
pkt->pkt_case = type; |
|||
/* This is a union, so doesn't matter which we assign. */ |
|||
pkt->error = (Error *)tal_steal(pkt, msg); |
|||
|
|||
/* This makes sure all packets are valid. */ |
|||
#ifndef NDEBUG |
|||
{ |
|||
size_t len; |
|||
u8 *packed; |
|||
Pkt *cpy; |
|||
|
|||
len = pkt__get_packed_size(pkt); |
|||
packed = tal_arr(pkt, u8, len); |
|||
pkt__pack(pkt, packed); |
|||
cpy = pkt__unpack(NULL, len, memcheck(packed, len)); |
|||
assert(cpy); |
|||
pkt__free_unpacked(cpy, NULL); |
|||
tal_free(packed); |
|||
} |
|||
#endif |
|||
return pkt; |
|||
} |
|||
|
|||
static void queue_raw_pkt(struct peer *peer, Pkt *pkt) |
|||
{ |
|||
size_t n = tal_count(peer->outpkt); |
|||
tal_resize(&peer->outpkt, n+1); |
|||
peer->outpkt[n] = pkt; |
|||
|
|||
log_debug(peer->log, "Queued pkt %s (order=%"PRIu64")", |
|||
pkt_name(pkt->pkt_case), peer->order_counter); |
|||
|
|||
/* In case it was waiting for output. */ |
|||
io_wake(peer); |
|||
} |
|||
|
|||
static void queue_pkt(struct peer *peer, Pkt__PktCase type, const void *msg) |
|||
{ |
|||
queue_raw_pkt(peer, make_pkt(peer, type, msg)); |
|||
} |
|||
|
|||
void queue_pkt_open(struct peer *peer, bool offer_anchor) |
|||
{ |
|||
OpenChannel *o = tal(peer, OpenChannel); |
|||
|
|||
open_channel__init(o); |
|||
o->revocation_hash = sha256_to_proto(o, &peer->local.commit->revocation_hash); |
|||
o->next_revocation_hash = sha256_to_proto(o, &peer->local.next_revocation_hash); |
|||
o->commit_key = pubkey_to_proto(o, &peer->local.commitkey); |
|||
o->final_key = pubkey_to_proto(o, &peer->local.finalkey); |
|||
o->delay = tal(o, Locktime); |
|||
locktime__init(o->delay); |
|||
o->delay->locktime_case = LOCKTIME__LOCKTIME_BLOCKS; |
|||
o->delay->blocks = rel_locktime_to_blocks(&peer->local.locktime); |
|||
o->initial_fee_rate = peer->local.commit_fee_rate; |
|||
if (offer_anchor) |
|||
o->anch = OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR; |
|||
else |
|||
o->anch = OPEN_CHANNEL__ANCHOR_OFFER__WONT_CREATE_ANCHOR; |
|||
o->min_depth = peer->local.mindepth; |
|||
queue_pkt(peer, PKT__PKT_OPEN, o); |
|||
} |
|||
|
|||
void queue_pkt_anchor(struct peer *peer) |
|||
{ |
|||
OpenAnchor *a = tal(peer, OpenAnchor); |
|||
|
|||
open_anchor__init(a); |
|||
a->txid = sha256_to_proto(a, &peer->anchor.txid.sha); |
|||
a->output_index = peer->anchor.index; |
|||
a->amount = peer->anchor.satoshis; |
|||
|
|||
queue_pkt(peer, PKT__PKT_OPEN_ANCHOR, a); |
|||
} |
|||
|
|||
void queue_pkt_open_commit_sig(struct peer *peer) |
|||
{ |
|||
OpenCommitSig *s = tal(peer, OpenCommitSig); |
|||
|
|||
open_commit_sig__init(s); |
|||
|
|||
s->sig = signature_to_proto(s, peer->remote.commit->sig); |
|||
|
|||
queue_pkt(peer, PKT__PKT_OPEN_COMMIT_SIG, s); |
|||
} |
|||
|
|||
void queue_pkt_open_complete(struct peer *peer) |
|||
{ |
|||
OpenComplete *o = tal(peer, OpenComplete); |
|||
|
|||
open_complete__init(o); |
|||
queue_pkt(peer, PKT__PKT_OPEN_COMPLETE, o); |
|||
} |
|||
|
|||
void queue_pkt_htlc_add(struct peer *peer, struct htlc *htlc) |
|||
{ |
|||
UpdateAddHtlc *u = tal(peer, UpdateAddHtlc); |
|||
|
|||
update_add_htlc__init(u); |
|||
|
|||
u->id = htlc->id; |
|||
u->amount_msat = htlc->msatoshi; |
|||
u->r_hash = sha256_to_proto(u, &htlc->rhash); |
|||
u->expiry = abs_locktime_to_proto(u, &htlc->expiry); |
|||
u->route = tal(u, Routing); |
|||
routing__init(u->route); |
|||
u->route->info.data = tal_dup_arr(u, u8, |
|||
htlc->routing, |
|||
tal_count(htlc->routing), |
|||
0); |
|||
u->route->info.len = tal_count(u->route->info.data); |
|||
|
|||
queue_pkt(peer, PKT__PKT_UPDATE_ADD_HTLC, u); |
|||
} |
|||
|
|||
void queue_pkt_htlc_fulfill(struct peer *peer, struct htlc *htlc) |
|||
{ |
|||
UpdateFulfillHtlc *f = tal(peer, UpdateFulfillHtlc); |
|||
|
|||
update_fulfill_htlc__init(f); |
|||
f->id = htlc->id; |
|||
f->r = preimage_to_proto(f, htlc->r); |
|||
|
|||
queue_pkt(peer, PKT__PKT_UPDATE_FULFILL_HTLC, f); |
|||
} |
|||
|
|||
void queue_pkt_htlc_fail(struct peer *peer, struct htlc *htlc) |
|||
{ |
|||
UpdateFailHtlc *f = tal(peer, UpdateFailHtlc); |
|||
|
|||
update_fail_htlc__init(f); |
|||
f->id = htlc->id; |
|||
|
|||
f->reason = tal(f, FailReason); |
|||
fail_reason__init(f->reason); |
|||
f->reason->info.len = tal_count(htlc->fail); |
|||
f->reason->info.data = tal_dup_arr(f->reason, u8, |
|||
htlc->fail, f->reason->info.len, 0); |
|||
|
|||
queue_pkt(peer, PKT__PKT_UPDATE_FAIL_HTLC, f); |
|||
} |
|||
|
|||
void queue_pkt_feechange(struct peer *peer, u64 feerate) |
|||
{ |
|||
UpdateFee *f = tal(peer, UpdateFee); |
|||
|
|||
update_fee__init(f); |
|||
f->fee_rate = feerate; |
|||
|
|||
queue_pkt(peer, PKT__PKT_UPDATE_FEE, f); |
|||
} |
|||
|
|||
/* OK, we're sending a signature for their pending changes. */ |
|||
void queue_pkt_commit(struct peer *peer, const secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
UpdateCommit *u = tal(peer, UpdateCommit); |
|||
|
|||
/* Now send message */ |
|||
update_commit__init(u); |
|||
if (sig) |
|||
u->sig = signature_to_proto(u, sig); |
|||
else |
|||
u->sig = NULL; |
|||
|
|||
queue_pkt(peer, PKT__PKT_UPDATE_COMMIT, u); |
|||
} |
|||
|
|||
|
|||
/* Send a preimage for the old commit tx. The one we've just committed to is
|
|||
* in peer->local.commit. */ |
|||
void queue_pkt_revocation(struct peer *peer, |
|||
const struct sha256 *preimage, |
|||
const struct sha256 *next_hash) |
|||
{ |
|||
UpdateRevocation *u = tal(peer, UpdateRevocation); |
|||
|
|||
update_revocation__init(u); |
|||
|
|||
u->revocation_preimage = sha256_to_proto(u, preimage); |
|||
u->next_revocation_hash = sha256_to_proto(u, next_hash); |
|||
queue_pkt(peer, PKT__PKT_UPDATE_REVOCATION, u); |
|||
} |
|||
|
|||
/* Send a serialized nested packet. */ |
|||
void queue_pkt_nested(struct peer *peer, |
|||
int type, |
|||
const u8 *nested_pkt) |
|||
{ |
|||
NestedPkt *pb = tal(peer, NestedPkt); |
|||
nested_pkt__init(pb); |
|||
pb->type = type; |
|||
pb->inner_pkt.len = tal_count(nested_pkt); |
|||
pb->inner_pkt.data = tal_dup_arr(pb, u8, nested_pkt, pb->inner_pkt.len, 0); |
|||
queue_pkt(peer, PKT__PKT_NESTED, pb); |
|||
} |
|||
|
|||
Pkt *pkt_err(struct peer *peer, const char *msg, ...) |
|||
{ |
|||
Error *e = tal(peer, Error); |
|||
va_list ap; |
|||
|
|||
error__init(e); |
|||
va_start(ap, msg); |
|||
e->problem = tal_vfmt(e, msg, ap); |
|||
va_end(ap); |
|||
|
|||
log_unusual(peer->log, "Sending PKT_ERROR: %s", e->problem); |
|||
return make_pkt(peer, PKT__PKT_ERROR, e); |
|||
} |
|||
|
|||
Pkt *pkt_init(struct peer *peer, u64 ack) |
|||
{ |
|||
Init *i = tal(peer, Init); |
|||
init__init(i); |
|||
i->ack = ack; |
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* A node SHOULD set the `features` field of the `init` |
|||
* message to a bitset representing features it supports. |
|||
*/ |
|||
/* No features yet! */ |
|||
return make_pkt(peer, PKT__PKT_INIT, i); |
|||
} |
|||
|
|||
void queue_pkt_err(struct peer *peer, Pkt *err) |
|||
{ |
|||
queue_raw_pkt(peer, err); |
|||
} |
|||
|
|||
void queue_pkt_close_shutdown(struct peer *peer) |
|||
{ |
|||
CloseShutdown *c = tal(peer, CloseShutdown); |
|||
|
|||
close_shutdown__init(c); |
|||
c->scriptpubkey.data = tal_dup_arr(c, u8, |
|||
peer->closing.our_script, |
|||
tal_count(peer->closing.our_script), |
|||
0); |
|||
c->scriptpubkey.len = tal_count(c->scriptpubkey.data); |
|||
|
|||
queue_pkt(peer, PKT__PKT_CLOSE_SHUTDOWN, c); |
|||
} |
|||
|
|||
void queue_pkt_close_signature(struct peer *peer) |
|||
{ |
|||
CloseSignature *c = tal(peer, CloseSignature); |
|||
struct bitcoin_tx *close_tx; |
|||
secp256k1_ecdsa_signature our_close_sig; |
|||
|
|||
close_signature__init(c); |
|||
close_tx = peer_create_close_tx(c, peer, peer->closing.our_fee); |
|||
|
|||
peer_sign_mutual_close(peer, close_tx, &our_close_sig); |
|||
c->sig = signature_to_proto(c, &our_close_sig); |
|||
c->close_fee = peer->closing.our_fee; |
|||
log_info(peer->log, "queue_pkt_close_signature: offered close fee %" |
|||
PRIu64, c->close_fee); |
|||
|
|||
queue_pkt(peer, PKT__PKT_CLOSE_SIGNATURE, c); |
|||
} |
|||
|
|||
Pkt *pkt_err_unexpected(struct peer *peer, const Pkt *pkt) |
|||
{ |
|||
return pkt_err(peer, "Unexpected packet %s", pkt_name(pkt->pkt_case)); |
|||
} |
|||
|
|||
/* Process various packets: return an error packet on failure. */ |
|||
Pkt *accept_pkt_open(struct peer *peer, const Pkt *pkt, |
|||
struct sha256 *revocation_hash, |
|||
struct sha256 *next_revocation_hash) |
|||
{ |
|||
struct rel_locktime locktime; |
|||
const OpenChannel *o = pkt->open; |
|||
u64 feerate = get_feerate(peer->dstate->topology); |
|||
|
|||
if (!proto_to_rel_locktime(o->delay, &locktime)) |
|||
return pkt_err(peer, "Invalid delay"); |
|||
if (o->delay->locktime_case != LOCKTIME__LOCKTIME_BLOCKS) |
|||
return pkt_err(peer, "Delay in seconds not accepted"); |
|||
if (o->delay->blocks > peer->dstate->config.locktime_max) |
|||
return pkt_err(peer, "Delay %u too great", o->delay->blocks); |
|||
if (o->min_depth > peer->dstate->config.anchor_confirms_max) |
|||
return pkt_err(peer, "min_depth %u too great", o->min_depth); |
|||
if (o->initial_fee_rate |
|||
< feerate * peer->dstate->config.commitment_fee_min_percent / 100) |
|||
return pkt_err(peer, "Commitment fee %u below %"PRIu64" x %u%%", |
|||
o->initial_fee_rate, feerate, |
|||
peer->dstate->config.commitment_fee_min_percent); |
|||
if (peer->dstate->config.commitment_fee_max_percent != 0 |
|||
&& (o->initial_fee_rate |
|||
> feerate * peer->dstate->config.commitment_fee_max_percent/100)) |
|||
return pkt_err(peer, "Commitment fee %u above %"PRIu64" x %u%%", |
|||
o->initial_fee_rate, feerate, |
|||
peer->dstate->config.commitment_fee_max_percent); |
|||
if (o->anch == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR) |
|||
peer->remote.offer_anchor = true; |
|||
else if (o->anch == OPEN_CHANNEL__ANCHOR_OFFER__WONT_CREATE_ANCHOR) |
|||
peer->remote.offer_anchor = false; |
|||
else |
|||
return pkt_err(peer, "Unknown offer anchor value %u", |
|||
o->anch); |
|||
|
|||
if (peer->remote.offer_anchor == peer->local.offer_anchor) |
|||
return pkt_err(peer, "Exactly one side can offer anchor (we %s)", |
|||
peer->local.offer_anchor ? "do" : "don't"); |
|||
|
|||
if (!proto_to_rel_locktime(o->delay, &peer->remote.locktime)) |
|||
return pkt_err(peer, "Malformed locktime"); |
|||
peer->remote.mindepth = o->min_depth; |
|||
peer->remote.commit_fee_rate = o->initial_fee_rate; |
|||
if (!proto_to_pubkey(o->commit_key, &peer->remote.commitkey)) |
|||
return pkt_err(peer, "Bad commitkey"); |
|||
if (!proto_to_pubkey(o->final_key, &peer->remote.finalkey)) |
|||
return pkt_err(peer, "Bad finalkey"); |
|||
|
|||
proto_to_sha256(o->revocation_hash, revocation_hash); |
|||
proto_to_sha256(o->next_revocation_hash, next_revocation_hash); |
|||
return NULL; |
|||
} |
|||
|
|||
Pkt *accept_pkt_anchor(struct peer *peer, const Pkt *pkt) |
|||
{ |
|||
const OpenAnchor *a = pkt->open_anchor; |
|||
|
|||
/* They must be offering anchor for us to try accepting */ |
|||
assert(!peer->local.offer_anchor); |
|||
assert(peer->remote.offer_anchor); |
|||
|
|||
if (anchor_too_large(a->amount)) |
|||
return pkt_err(peer, "Anchor millisatoshis exceeds 32 bits"); |
|||
|
|||
proto_to_sha256(a->txid, &peer->anchor.txid.sha); |
|||
peer->anchor.index = a->output_index; |
|||
peer->anchor.satoshis = a->amount; |
|||
return NULL; |
|||
} |
|||
|
|||
Pkt *accept_pkt_open_commit_sig(struct peer *peer, const Pkt *pkt, |
|||
secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
const OpenCommitSig *s = pkt->open_commit_sig; |
|||
|
|||
if (!proto_to_signature(s->sig, sig)) |
|||
return pkt_err(peer, "Malformed signature"); |
|||
return NULL; |
|||
} |
|||
|
|||
Pkt *accept_pkt_open_complete(struct peer *peer, const Pkt *pkt) |
|||
{ |
|||
return NULL; |
|||
} |
|||
|
|||
/*
|
|||
* We add changes to both our staging cstate (as they did when they sent |
|||
* it) and theirs (as they will when we ack it). |
|||
*/ |
|||
Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt, struct htlc **h) |
|||
{ |
|||
const UpdateAddHtlc *u = pkt->update_add_htlc; |
|||
struct sha256 rhash; |
|||
struct abs_locktime expiry; |
|||
|
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* `amount_msat` MUST BE greater than 0. |
|||
*/ |
|||
if (u->amount_msat == 0) |
|||
return pkt_err(peer, "Invalid amount_msat"); |
|||
|
|||
proto_to_sha256(u->r_hash, &rhash); |
|||
if (!proto_to_abs_locktime(u->expiry, &expiry)) |
|||
return pkt_err(peer, "Invalid HTLC expiry"); |
|||
|
|||
if (abs_locktime_is_seconds(&expiry)) |
|||
return pkt_err(peer, "HTLC expiry in seconds not supported!"); |
|||
|
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* A node MUST NOT add a HTLC if it would result in it |
|||
* offering more than 300 HTLCs in the remote commitment transaction. |
|||
*/ |
|||
if (peer->remote.staging_cstate->side[REMOTE].num_htlcs == 300) |
|||
return pkt_err(peer, "Too many HTLCs"); |
|||
|
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* A node MUST set `id` to a unique identifier for this HTLC |
|||
* amongst all past or future `update_add_htlc` messages. |
|||
*/ |
|||
/* Note that it's not *our* problem if they do this, it's
|
|||
* theirs (future confusion). Nonetheless, we detect and |
|||
* error for them. */ |
|||
if (htlc_get(&peer->htlcs, u->id, REMOTE)) |
|||
return pkt_err(peer, "HTLC id %"PRIu64" clashes for you", u->id); |
|||
|
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* ...and the receiving node MUST add the HTLC addition to the |
|||
* unacked changeset for its local commitment. */ |
|||
*h = peer_new_htlc(peer, u->id, u->amount_msat, &rhash, |
|||
abs_locktime_to_blocks(&expiry), |
|||
u->route->info.data, u->route->info.len, |
|||
NULL, RCVD_ADD_HTLC); |
|||
return NULL; |
|||
} |
|||
|
|||
static Pkt *find_commited_htlc(struct peer *peer, uint64_t id, |
|||
struct htlc **local_htlc) |
|||
{ |
|||
*local_htlc = htlc_get(&peer->htlcs, id, LOCAL); |
|||
|
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* A node MUST check that `id` corresponds to an HTLC in its |
|||
* current commitment transaction, and MUST fail the |
|||
* connection if it does not. |
|||
*/ |
|||
if (!(*local_htlc)) |
|||
return pkt_err(peer, "Did not find HTLC %"PRIu64, id); |
|||
|
|||
if ((*local_htlc)->state != SENT_ADD_ACK_REVOCATION) |
|||
return pkt_err(peer, "HTLC %"PRIu64" state %s", id, |
|||
htlc_state_name((*local_htlc)->state)); |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
Pkt *accept_pkt_htlc_fail(struct peer *peer, const Pkt *pkt, struct htlc **h, |
|||
u8 **fail) |
|||
{ |
|||
const UpdateFailHtlc *f = pkt->update_fail_htlc; |
|||
Pkt *err; |
|||
|
|||
err = find_commited_htlc(peer, f->id, h); |
|||
if (err) |
|||
return err; |
|||
|
|||
if ((*h)->r) |
|||
return pkt_err(peer, "HTLC %"PRIu64" already fulfilled", |
|||
(*h)->id); |
|||
|
|||
*fail = tal_dup_arr(*h, u8, f->reason->info.data, f->reason->info.len,0); |
|||
return NULL; |
|||
} |
|||
|
|||
Pkt *accept_pkt_htlc_fulfill(struct peer *peer, const Pkt *pkt, struct htlc **h, |
|||
struct preimage *r) |
|||
{ |
|||
const UpdateFulfillHtlc *f = pkt->update_fulfill_htlc; |
|||
struct sha256 rhash; |
|||
Pkt *err; |
|||
|
|||
err = find_commited_htlc(peer, f->id, h); |
|||
if (err) |
|||
return err; |
|||
|
|||
/* Now, it must solve the HTLC rhash puzzle. */ |
|||
proto_to_preimage(f->r, r); |
|||
sha256(&rhash, r, sizeof(*r)); |
|||
|
|||
if (!structeq(&rhash, &(*h)->rhash)) |
|||
return pkt_err(peer, "Invalid r for %"PRIu64, f->id); |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
Pkt *accept_pkt_update_fee(struct peer *peer, const Pkt *pkt, u64 *feerate) |
|||
{ |
|||
const UpdateFee *f = pkt->update_fee; |
|||
|
|||
*feerate = f->fee_rate; |
|||
return NULL; |
|||
} |
|||
|
|||
Pkt *accept_pkt_commit(struct peer *peer, const Pkt *pkt, |
|||
secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
const UpdateCommit *c = pkt->update_commit; |
|||
|
|||
if (!c->sig && sig) |
|||
return pkt_err(peer, "Expected signature"); |
|||
|
|||
if (!sig && c->sig) |
|||
return pkt_err(peer, "Unexpected signature"); |
|||
|
|||
if (!sig && !c->sig) |
|||
return NULL; |
|||
|
|||
if (!proto_to_signature(c->sig, sig)) |
|||
return pkt_err(peer, "Malformed signature"); |
|||
return NULL; |
|||
} |
|||
|
|||
Pkt *accept_pkt_revocation(struct peer *peer, const Pkt *pkt) |
|||
{ |
|||
const UpdateRevocation *r = pkt->update_revocation; |
|||
struct sha256 h, preimage; |
|||
|
|||
assert(peer->their_prev_revocation_hash); |
|||
proto_to_sha256(r->revocation_preimage, &preimage); |
|||
|
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* The receiver of `update_revocation` MUST check that the |
|||
* SHA256 hash of `revocation_preimage` matches the previous commitment |
|||
* transaction, and MUST fail if it does not. |
|||
*/ |
|||
sha256(&h, &preimage, sizeof(preimage)); |
|||
if (!structeq(&h, peer->their_prev_revocation_hash)) { |
|||
log_unusual(peer->log, "Incorrect preimage for %"PRIu64, |
|||
peer->remote.commit->commit_num - 1); |
|||
return pkt_err(peer, "complete preimage incorrect"); |
|||
} |
|||
|
|||
// save revocation preimages in shachain
|
|||
if (!shachain_add_hash(&peer->their_preimages, |
|||
0xFFFFFFFFFFFFFFFFL |
|||
- (peer->remote.commit->commit_num - 1), |
|||
&preimage)) |
|||
return pkt_err(peer, "preimage not next in shachain"); |
|||
|
|||
log_debug(peer->log, "Got revocation preimage %"PRIu64, |
|||
peer->remote.commit->commit_num - 1); |
|||
|
|||
/* Clear the previous revocation hash. */ |
|||
peer->their_prev_revocation_hash |
|||
= tal_free(peer->their_prev_revocation_hash); |
|||
|
|||
/* Save next revocation hash. */ |
|||
proto_to_sha256(r->next_revocation_hash, |
|||
&peer->remote.next_revocation_hash); |
|||
return NULL; |
|||
} |
|||
|
|||
Pkt *accept_pkt_close_shutdown(struct peer *peer, const Pkt *pkt) |
|||
{ |
|||
const CloseShutdown *c = pkt->close_shutdown; |
|||
|
|||
peer->closing.their_script = tal_dup_arr(peer, u8, |
|||
c->scriptpubkey.data, |
|||
c->scriptpubkey.len, 0); |
|||
|
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* 1. `OP_DUP` `OP_HASH160` `20` 20-bytes `OP_EQUALVERIFY` `OP_CHECKSIG` |
|||
* (pay to pubkey hash), OR |
|||
* 2. `OP_HASH160` `20` 20-bytes `OP_EQUAL` (pay to script hash), OR |
|||
* 3. `OP_0` `20` 20-bytes (version 0 pay to witness pubkey), OR |
|||
* 4. `OP_0` `32` 32-bytes (version 0 pay to witness script hash) |
|||
* |
|||
* A node receiving `close_shutdown` SHOULD fail the connection |
|||
* `script_pubkey` is not one of those forms. |
|||
*/ |
|||
if (!is_p2pkh(peer->closing.their_script) |
|||
&& !is_p2sh(peer->closing.their_script) |
|||
&& !is_p2wpkh(peer->closing.their_script) |
|||
&& !is_p2wsh(peer->closing.their_script)) { |
|||
log_broken_blob(peer->log, "Bad script_pubkey %s", |
|||
peer->closing.their_script, |
|||
tal_count(peer->closing.their_script)); |
|||
return pkt_err(peer, "Bad script_pubkey"); |
|||
} |
|||
|
|||
return NULL; |
|||
} |
@ -1,478 +0,0 @@ |
|||
#include "chaintopology.h" |
|||
#include "db.h" |
|||
#include "failure.h" |
|||
#include "jsonrpc.h" |
|||
#include "lightningd.h" |
|||
#include "log.h" |
|||
#include "pay.h" |
|||
#include "peer.h" |
|||
#include "peer_internal.h" |
|||
#include "routing.h" |
|||
#include "sphinx.h" |
|||
#include <bitcoin/preimage.h> |
|||
#include <ccan/str/hex/hex.h> |
|||
#include <ccan/structeq/structeq.h> |
|||
#include <inttypes.h> |
|||
#include <sodium/randombytes.h> |
|||
|
|||
/* Outstanding "pay" commands. */ |
|||
struct pay_command { |
|||
struct list_node list; |
|||
struct sha256 rhash; |
|||
u64 msatoshi; |
|||
const struct pubkey *ids; |
|||
/* Set if this is in progress. */ |
|||
struct htlc *htlc; |
|||
/* Preimage if this succeeded. */ |
|||
const struct preimage *rval; |
|||
struct command *cmd; |
|||
}; |
|||
static void json_pay_success(struct command *cmd, const struct preimage *rval) |
|||
{ |
|||
struct json_result *response; |
|||
|
|||
response = new_json_result(cmd); |
|||
json_object_start(response, NULL); |
|||
json_add_hex(response, "preimage", rval, sizeof(*rval)); |
|||
json_object_end(response); |
|||
command_success(cmd, response); |
|||
} |
|||
|
|||
static void handle_json(struct command *cmd, const struct htlc *htlc, |
|||
const FailInfo *f) |
|||
{ |
|||
struct pubkey id; |
|||
const char *idstr = "INVALID"; |
|||
|
|||
if (htlc->r) { |
|||
json_pay_success(cmd, htlc->r); |
|||
return; |
|||
} |
|||
|
|||
if (!f) { |
|||
command_fail(cmd, "failed (bad message)"); |
|||
return; |
|||
} |
|||
|
|||
if (proto_to_pubkey(f->id, &id)) |
|||
idstr = pubkey_to_hexstr(cmd, &id); |
|||
|
|||
command_fail(cmd, |
|||
"failed: error code %u node %s reason %s", |
|||
f->error_code, idstr, f->reason ? f->reason : "unknown"); |
|||
} |
|||
|
|||
static void check_routing_failure(struct lightningd_state *dstate, |
|||
const struct pay_command *pc, |
|||
const FailInfo *f) |
|||
{ |
|||
size_t i; |
|||
struct pubkey id; |
|||
|
|||
if (!f) |
|||
return; |
|||
|
|||
/* FIXME: We remove route on *any* failure. */ |
|||
log_debug(dstate->base_log, "Seeking route for fail code %u", |
|||
f->error_code); |
|||
if (!proto_to_pubkey(f->id, &id)) { |
|||
log_add(dstate->base_log, " - bad node"); |
|||
return; |
|||
} |
|||
|
|||
log_add_struct(dstate->base_log, " node %s", struct pubkey, &id); |
|||
|
|||
/* Don't remove route if it's last node (obviously) */ |
|||
for (i = 0; i+1 < tal_count(pc->ids); i++) { |
|||
if (structeq(&pc->ids[i], &id)) { |
|||
remove_connection(dstate->rstate, &pc->ids[i], &pc->ids[i+1]); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
if (structeq(&pc->ids[i], &id)) |
|||
log_debug(dstate->base_log, "Final node: ignoring"); |
|||
else |
|||
log_debug(dstate->base_log, "Node not on route: ignoring"); |
|||
} |
|||
|
|||
void complete_pay_command(struct lightningd_state *dstate, |
|||
const struct htlc *htlc) |
|||
{ |
|||
struct pay_command *i; |
|||
|
|||
list_for_each(&dstate->pay_commands, i, list) { |
|||
if (i->htlc == htlc) { |
|||
FailInfo *f = NULL; |
|||
|
|||
db_complete_pay_command(dstate, htlc); |
|||
|
|||
if (htlc->r) |
|||
i->rval = tal_dup(i, struct preimage, htlc->r); |
|||
else { |
|||
f = failinfo_unwrap(i->cmd, htlc->fail, |
|||
tal_count(htlc->fail)); |
|||
check_routing_failure(dstate, i, f); |
|||
} |
|||
|
|||
/* No longer connected to live HTLC. */ |
|||
i->htlc = NULL; |
|||
|
|||
/* Can be NULL if JSON RPC goes away. */ |
|||
if (i->cmd) |
|||
handle_json(i->cmd, htlc, f); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
/* Can happen with testing low-level commands. */ |
|||
log_unusual(dstate->base_log, "No command for HTLC %"PRIu64" %s", |
|||
htlc->id, htlc->r ? "fulfill" : "fail"); |
|||
} |
|||
|
|||
/* When JSON RPC goes away, cmd is freed: detach from any running paycommand */ |
|||
static void remove_cmd_from_pc(struct command *cmd) |
|||
{ |
|||
struct pay_command *pc; |
|||
|
|||
list_for_each(&cmd->dstate->pay_commands, pc, list) { |
|||
if (pc->cmd == cmd) { |
|||
pc->cmd = NULL; |
|||
return; |
|||
} |
|||
} |
|||
/* We can reach here, in the case where another pay command
|
|||
* re-uses the pc->cmd before we get around to cleaning up. */ |
|||
} |
|||
|
|||
static struct pay_command *find_pay_command(struct lightningd_state *dstate, |
|||
const struct sha256 *rhash) |
|||
{ |
|||
struct pay_command *pc; |
|||
|
|||
list_for_each(&dstate->pay_commands, pc, list) { |
|||
if (structeq(rhash, &pc->rhash)) |
|||
return pc; |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
/* For database restore. */ |
|||
bool pay_add(struct lightningd_state *dstate, |
|||
const struct sha256 *rhash, |
|||
u64 msatoshi, |
|||
const struct pubkey *ids, |
|||
struct htlc *htlc, |
|||
const u8 *fail UNNEEDED, |
|||
const struct preimage *r) |
|||
{ |
|||
struct pay_command *pc; |
|||
|
|||
if (find_pay_command(dstate, rhash)) |
|||
return false; |
|||
|
|||
pc = tal(dstate, struct pay_command); |
|||
pc->rhash = *rhash; |
|||
pc->msatoshi = msatoshi; |
|||
pc->ids = tal_dup_arr(pc, struct pubkey, ids, tal_count(ids), 0); |
|||
pc->htlc = htlc; |
|||
if (r) |
|||
pc->rval = tal_dup(pc, struct preimage, r); |
|||
else |
|||
pc->rval = NULL; |
|||
pc->cmd = NULL; |
|||
|
|||
list_add_tail(&dstate->pay_commands, &pc->list); |
|||
return true; |
|||
} |
|||
|
|||
static void json_add_route(struct json_result *response, |
|||
const struct pubkey *id, |
|||
u64 amount, unsigned int delay) |
|||
{ |
|||
json_object_start(response, NULL); |
|||
json_add_pubkey(response, "id", id); |
|||
json_add_u64(response, "msatoshi", amount); |
|||
json_add_num(response, "delay", delay); |
|||
json_object_end(response); |
|||
} |
|||
|
|||
static void json_getroute(struct command *cmd, |
|||
const char *buffer, const jsmntok_t *params) |
|||
{ |
|||
struct pubkey id; |
|||
jsmntok_t *idtok, *msatoshitok, *riskfactortok; |
|||
struct json_result *response; |
|||
size_t i; |
|||
u64 msatoshi; |
|||
double riskfactor; |
|||
|
|||
if (!json_get_params(buffer, params, |
|||
"id", &idtok, |
|||
"msatoshi", &msatoshitok, |
|||
"riskfactor", &riskfactortok, |
|||
NULL)) { |
|||
command_fail(cmd, "Need id, msatoshi and riskfactor"); |
|||
return; |
|||
} |
|||
|
|||
if (!pubkey_from_hexstr(buffer + idtok->start, |
|||
idtok->end - idtok->start, &id)) { |
|||
command_fail(cmd, "Invalid id"); |
|||
return; |
|||
} |
|||
|
|||
if (!json_tok_u64(buffer, msatoshitok, &msatoshi)) { |
|||
command_fail(cmd, "'%.*s' is not a valid number", |
|||
(int)(msatoshitok->end - msatoshitok->start), |
|||
buffer + msatoshitok->start); |
|||
return; |
|||
} |
|||
|
|||
if (!json_tok_double(buffer, riskfactortok, &riskfactor)) { |
|||
command_fail(cmd, "'%.*s' is not a valid double", |
|||
(int)(riskfactortok->end - riskfactortok->start), |
|||
buffer + riskfactortok->start); |
|||
return; |
|||
} |
|||
|
|||
struct route_hop *hops = get_route(cmd, cmd->dstate->rstate, &cmd->dstate->id, &id, msatoshi, riskfactor); |
|||
|
|||
if (!hops) { |
|||
command_fail(cmd, "no route found"); |
|||
return; |
|||
} |
|||
|
|||
response = new_json_result(cmd); |
|||
json_object_start(response, NULL); |
|||
json_array_start(response, "route"); |
|||
for (i = 0; i < tal_count(hops); i++) |
|||
json_add_route(response, |
|||
&hops[i].nodeid, hops[i].amount, hops[i].delay); |
|||
json_array_end(response); |
|||
json_object_end(response); |
|||
command_success(cmd, response); |
|||
} |
|||
|
|||
static const struct json_command getroute_command = { |
|||
"getroute", |
|||
json_getroute, |
|||
"Return route to {id} for {msatoshi}, using {riskfactor}", |
|||
"Returns a {route} array of {id} {msatoshi} {delay}: msatoshi and delay (in blocks) is cumulative." |
|||
}; |
|||
AUTODATA(json_command, &getroute_command); |
|||
|
|||
static void json_sendpay(struct command *cmd, |
|||
const char *buffer, const jsmntok_t *params) |
|||
{ |
|||
struct pubkey *ids; |
|||
jsmntok_t *routetok, *rhashtok; |
|||
const jsmntok_t *t, *end; |
|||
unsigned int delay; |
|||
size_t n_hops; |
|||
struct sha256 rhash; |
|||
struct peer *peer; |
|||
struct pay_command *pc; |
|||
bool replacing = false; |
|||
const u8 *onion; |
|||
u8 sessionkey[32]; |
|||
enum fail_error error_code; |
|||
const char *err; |
|||
struct hoppayload *hoppayloads; |
|||
u64 amount, lastamount; |
|||
struct onionpacket *packet; |
|||
|
|||
if (!json_get_params(buffer, params, |
|||
"route", &routetok, |
|||
"rhash", &rhashtok, |
|||
NULL)) { |
|||
command_fail(cmd, "Need route and rhash"); |
|||
return; |
|||
} |
|||
|
|||
if (!hex_decode(buffer + rhashtok->start, |
|||
rhashtok->end - rhashtok->start, |
|||
&rhash, sizeof(rhash))) { |
|||
command_fail(cmd, "'%.*s' is not a valid sha256 hash", |
|||
(int)(rhashtok->end - rhashtok->start), |
|||
buffer + rhashtok->start); |
|||
return; |
|||
} |
|||
|
|||
if (routetok->type != JSMN_ARRAY) { |
|||
command_fail(cmd, "'%.*s' is not an array", |
|||
(int)(routetok->end - routetok->start), |
|||
buffer + routetok->start); |
|||
return; |
|||
} |
|||
|
|||
end = json_next(routetok); |
|||
n_hops = 0; |
|||
ids = tal_arr(cmd, struct pubkey, n_hops); |
|||
hoppayloads = tal_arr(cmd, struct hoppayload, 0); |
|||
for (t = routetok + 1; t < end; t = json_next(t)) { |
|||
const jsmntok_t *amttok, *idtok, *delaytok; |
|||
|
|||
if (t->type != JSMN_OBJECT) { |
|||
command_fail(cmd, "route %zu '%.*s' is not an object", |
|||
n_hops, |
|||
(int)(t->end - t->start), |
|||
buffer + t->start); |
|||
return; |
|||
} |
|||
amttok = json_get_member(buffer, t, "msatoshi"); |
|||
idtok = json_get_member(buffer, t, "id"); |
|||
delaytok = json_get_member(buffer, t, "delay"); |
|||
if (!amttok || !idtok || !delaytok) { |
|||
command_fail(cmd, "route %zu needs msatoshi/id/delay", |
|||
n_hops); |
|||
return; |
|||
} |
|||
|
|||
if (n_hops == 0) { |
|||
/* What we will send */ |
|||
if (!json_tok_u64(buffer, amttok, &amount)) { |
|||
command_fail(cmd, "route %zu invalid msatoshi", n_hops); |
|||
return; |
|||
} |
|||
lastamount = amount; |
|||
} else{ |
|||
/* What that hop will forward */ |
|||
tal_resize(&hoppayloads, n_hops); |
|||
memset(&hoppayloads[n_hops-1], 0, sizeof(struct hoppayload)); |
|||
if (!json_tok_u64(buffer, amttok, &hoppayloads[n_hops-1].amt_to_forward)) { |
|||
command_fail(cmd, "route %zu invalid msatoshi", n_hops); |
|||
return; |
|||
} |
|||
/* FIXME: Populate outgoing_cltv_value */ |
|||
lastamount = hoppayloads[n_hops-1].amt_to_forward; |
|||
} |
|||
|
|||
tal_resize(&ids, n_hops+1); |
|||
memset(&ids[n_hops], 0, sizeof(ids[n_hops])); |
|||
if (!pubkey_from_hexstr(buffer + idtok->start, |
|||
idtok->end - idtok->start, |
|||
&ids[n_hops])) { |
|||
command_fail(cmd, "route %zu invalid id", n_hops); |
|||
return; |
|||
} |
|||
/* Only need first delay. */ |
|||
if (n_hops == 0 && !json_tok_number(buffer, delaytok, &delay)) { |
|||
command_fail(cmd, "route %zu invalid delay", n_hops); |
|||
return; |
|||
} |
|||
n_hops++; |
|||
} |
|||
|
|||
/* Add payload for final hop */ |
|||
tal_resize(&hoppayloads, n_hops); |
|||
memset(&hoppayloads[n_hops-1], 0, sizeof(struct hoppayload)); |
|||
|
|||
if (n_hops == 0) { |
|||
command_fail(cmd, "Empty route"); |
|||
return; |
|||
} |
|||
|
|||
pc = find_pay_command(cmd->dstate, &rhash); |
|||
if (pc) { |
|||
replacing = true; |
|||
log_debug(cmd->dstate->base_log, "json_sendpay: found previous"); |
|||
if (pc->htlc) { |
|||
log_add(cmd->dstate->base_log, "... still in progress"); |
|||
command_fail(cmd, "still in progress"); |
|||
return; |
|||
} |
|||
if (pc->rval) { |
|||
size_t old_nhops = tal_count(pc->ids); |
|||
log_add(cmd->dstate->base_log, "... succeeded"); |
|||
/* Must match successful payment parameters. */ |
|||
if (pc->msatoshi != lastamount) { |
|||
command_fail(cmd, |
|||
"already succeeded with amount %" |
|||
PRIu64, pc->msatoshi); |
|||
return; |
|||
} |
|||
if (!structeq(&pc->ids[old_nhops-1], &ids[n_hops-1])) { |
|||
char *previd; |
|||
previd = pubkey_to_hexstr(cmd, |
|||
&pc->ids[old_nhops-1]); |
|||
command_fail(cmd, |
|||
"already succeeded to %s", |
|||
previd); |
|||
return; |
|||
} |
|||
json_pay_success(cmd, pc->rval); |
|||
return; |
|||
} |
|||
log_add(cmd->dstate->base_log, "... retrying"); |
|||
} |
|||
|
|||
peer = find_peer(cmd->dstate, &ids[0]); |
|||
if (!peer) { |
|||
command_fail(cmd, "no connection to first peer found"); |
|||
return; |
|||
} |
|||
|
|||
randombytes_buf(&sessionkey, sizeof(sessionkey)); |
|||
|
|||
/* Onion will carry us from first peer onwards. */ |
|||
packet = create_onionpacket(cmd, ids, hoppayloads, sessionkey, |
|||
rhash.u.u8, sizeof(struct sha256)); |
|||
onion = serialize_onionpacket(cmd, packet); |
|||
|
|||
if (pc) |
|||
pc->ids = tal_free(pc->ids); |
|||
else |
|||
pc = tal(cmd->dstate, struct pay_command); |
|||
pc->cmd = cmd; |
|||
pc->rhash = rhash; |
|||
pc->rval = NULL; |
|||
pc->ids = tal_steal(pc, ids); |
|||
pc->msatoshi = lastamount; |
|||
|
|||
/* Expiry for HTLCs is absolute. And add one to give some margin. */ |
|||
err = command_htlc_add(peer, amount, |
|||
delay + get_block_height(cmd->dstate->topology) |
|||
+ 1, |
|||
&rhash, NULL, |
|||
onion, &error_code, &pc->htlc); |
|||
if (err) { |
|||
command_fail(cmd, "could not add htlc: %u: %s", error_code, err); |
|||
tal_free(pc); |
|||
return; |
|||
} |
|||
|
|||
if (replacing) { |
|||
if (!db_replace_pay_command(cmd->dstate, &pc->rhash, |
|||
pc->ids, pc->msatoshi, |
|||
pc->htlc)) { |
|||
command_fail(cmd, "database error"); |
|||
/* We could reconnect, but db error is *bad*. */ |
|||
peer_fail(peer, __func__); |
|||
tal_free(pc); |
|||
return; |
|||
} |
|||
} else { |
|||
if (!db_new_pay_command(cmd->dstate, &pc->rhash, |
|||
pc->ids, pc->msatoshi, |
|||
pc->htlc)) { |
|||
command_fail(cmd, "database error"); |
|||
/* We could reconnect, but db error is *bad*. */ |
|||
peer_fail(peer, __func__); |
|||
tal_free(pc); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
/* Wait until we get response. */ |
|||
list_add_tail(&cmd->dstate->pay_commands, &pc->list); |
|||
tal_add_destructor(cmd, remove_cmd_from_pc); |
|||
} |
|||
|
|||
static const struct json_command sendpay_command = { |
|||
"sendpay", |
|||
json_sendpay, |
|||
"Send along {route} in return for preimage of {rhash}", |
|||
"Returns the {preimage} on success" |
|||
}; |
|||
AUTODATA(json_command, &sendpay_command); |
@ -1,19 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_PAY_H |
|||
#define LIGHTNING_DAEMON_PAY_H |
|||
#include "config.h" |
|||
|
|||
struct htlc; |
|||
struct lightningd_state; |
|||
struct preimage; |
|||
|
|||
void complete_pay_command(struct lightningd_state *dstate, |
|||
const struct htlc *htlc); |
|||
|
|||
bool pay_add(struct lightningd_state *dstate, |
|||
const struct sha256 *rhash, |
|||
u64 msatoshi, |
|||
const struct pubkey *ids, |
|||
struct htlc *htlc, |
|||
const u8 *fail, |
|||
const struct preimage *r); |
|||
#endif /* LIGHTNING_DAEMON_PAY_H */ |
File diff suppressed because it is too large
@ -1,91 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_PEER_H |
|||
#define LIGHTNING_DAEMON_PEER_H |
|||
#include "config.h" |
|||
#include "bitcoin/locktime.h" |
|||
#include "bitcoin/privkey.h" |
|||
#include "bitcoin/pubkey.h" |
|||
#include "bitcoin/script.h" |
|||
#include "bitcoin/shadouble.h" |
|||
#include "channel.h" |
|||
#include "failure.h" |
|||
#include "feechange.h" |
|||
#include "htlc.h" |
|||
#include "lightning.pb-c.h" |
|||
#include "netaddr.h" |
|||
#include "protobuf_convert.h" |
|||
#include "state.h" |
|||
#include "wire/gen_peer_wire.h" |
|||
#include <ccan/crypto/sha256/sha256.h> |
|||
#include <ccan/crypto/shachain/shachain.h> |
|||
#include <ccan/list/list.h> |
|||
#include <ccan/time/time.h> |
|||
|
|||
struct log; |
|||
struct lightningd_state; |
|||
struct peer; |
|||
|
|||
/* Mapping for id -> network address. */ |
|||
struct peer_address { |
|||
struct list_node list; |
|||
struct pubkey id; |
|||
struct netaddr addr; |
|||
}; |
|||
|
|||
void setup_listeners(struct lightningd_state *dstate); |
|||
|
|||
void peer_debug(struct peer *peer, const char *fmt, ...) |
|||
PRINTF_FMT(2,3); |
|||
|
|||
struct peer *find_peer(struct lightningd_state *dstate, const struct pubkey *id); |
|||
struct peer *find_peer_by_pkhash(struct lightningd_state *dstate, const u8 *pkhash); |
|||
|
|||
struct peer *new_peer(struct lightningd_state *dstate, |
|||
struct log *log, |
|||
enum state state, |
|||
bool offer_anchor); |
|||
|
|||
/* Populates very first peer->{local,remote}.commit->{tx,cstate} */ |
|||
bool setup_first_commit(struct peer *peer); |
|||
|
|||
/* Whenever we send a signature, remember the txid -> commit_num mapping */ |
|||
void peer_add_their_commit(struct peer *peer, |
|||
const struct sha256_double *txid, u64 commit_num); |
|||
|
|||
/* Allocate a new commit_info struct. */ |
|||
struct commit_info *new_commit_info(const tal_t *ctx, u64 commit_num); |
|||
|
|||
/* Freeing removes from map, too */ |
|||
struct htlc *peer_new_htlc(struct peer *peer, |
|||
u64 id, |
|||
u64 msatoshi, |
|||
const struct sha256 *rhash, |
|||
u32 expiry, |
|||
const u8 *route, |
|||
size_t route_len, |
|||
struct htlc *src, |
|||
enum htlc_state state); |
|||
|
|||
const char *command_htlc_add(struct peer *peer, u64 msatoshi, |
|||
unsigned int expiry, |
|||
const struct sha256 *rhash, |
|||
struct htlc *src, |
|||
const u8 *route, |
|||
enum fail_error *error_code, |
|||
struct htlc **htlc); |
|||
|
|||
/* Peer has an issue, breakdown and fail. */ |
|||
void peer_fail(struct peer *peer, const char *caller); |
|||
|
|||
void peer_watch_anchor(struct peer *peer, int depth); |
|||
|
|||
struct bitcoin_tx *peer_create_close_tx(const tal_t *ctx, |
|||
struct peer *peer, u64 fee); |
|||
|
|||
u32 get_peer_min_block(struct lightningd_state *dstate); |
|||
|
|||
void debug_dump_peers(struct lightningd_state *dstate); |
|||
|
|||
void reconnect_peers(struct lightningd_state *dstate); |
|||
void rebroadcast_anchors(struct lightningd_state *dstate); |
|||
void cleanup_peers(struct lightningd_state *dstate); |
|||
#endif /* LIGHTNING_DAEMON_PEER_H */ |
@ -1,210 +0,0 @@ |
|||
/* This header holds structure definitions for struct peer, which must
|
|||
* not be exposed to ../lightningd/ */ |
|||
#ifndef LIGHTNING_DAEMON_PEER_INTERNAL_H |
|||
#define LIGHTNING_DAEMON_PEER_INTERNAL_H |
|||
#include "config.h" |
|||
|
|||
struct anchor_input { |
|||
struct sha256_double txid; |
|||
unsigned int index; |
|||
/* Amount of input (satoshis), and output (satoshis) */ |
|||
u64 in_amount, out_amount; |
|||
/* Wallet entry to use to spend. */ |
|||
struct pubkey walletkey; |
|||
}; |
|||
|
|||
/* Information we remember for their commitment txs which we signed.
|
|||
* |
|||
* Given the commit_num, we can use shachain to derive the revocation preimage |
|||
* (if we've received it yet: we might have not, for the last). |
|||
*/ |
|||
struct their_commit { |
|||
struct list_node list; |
|||
|
|||
struct sha256_double txid; |
|||
u64 commit_num; |
|||
}; |
|||
|
|||
struct commit_info { |
|||
/* Commit number (0 == from open) */ |
|||
u64 commit_num; |
|||
/* Revocation hash. */ |
|||
struct sha256 revocation_hash; |
|||
/* Commit tx & txid */ |
|||
struct bitcoin_tx *tx; |
|||
struct sha256_double txid; |
|||
/* Channel state for this tx. */ |
|||
struct channel_state *cstate; |
|||
/* Other side's signature for last commit tx (if known) */ |
|||
secp256k1_ecdsa_signature *sig; |
|||
/* Order which commit was sent (theirs) / revocation was sent (ours) */ |
|||
s64 order; |
|||
}; |
|||
|
|||
struct peer_visible_state { |
|||
/* Is this side funding the channel? */ |
|||
bool offer_anchor; |
|||
/* Key for commitment tx inputs, then key for commitment tx outputs */ |
|||
struct pubkey commitkey, finalkey; |
|||
/* How long to they want the other's outputs locked (blocks) */ |
|||
struct rel_locktime locktime; |
|||
/* Minimum depth of anchor before channel usable. */ |
|||
unsigned int mindepth; |
|||
/* Commitment fee they're offering (satoshi). */ |
|||
u64 commit_fee_rate; |
|||
/* Revocation hash for next commit tx. */ |
|||
struct sha256 next_revocation_hash; |
|||
/* Commit txs: last one is current. */ |
|||
struct commit_info *commit; |
|||
|
|||
/* cstate to generate next commitment tx. */ |
|||
struct channel_state *staging_cstate; |
|||
}; |
|||
|
|||
struct peer { |
|||
/* dstate->peers list */ |
|||
struct list_node list; |
|||
|
|||
/* State in state machine. */ |
|||
enum state state; |
|||
|
|||
/* Network connection. */ |
|||
struct io_conn *conn; |
|||
|
|||
/* Are we connected now? (Crypto handshake completed). */ |
|||
bool connected; |
|||
|
|||
/* If we're doing an open, this is the command which triggered it */ |
|||
struct command *open_jsoncmd; |
|||
|
|||
/* If we're doing a commit, this is the command which triggered it */ |
|||
struct command *commit_jsoncmd; |
|||
|
|||
/* Global state. */ |
|||
struct lightningd_state *dstate; |
|||
|
|||
/* Their ID. */ |
|||
struct pubkey *id; |
|||
|
|||
/* Order counter for transmission of revocations/commitments. */ |
|||
s64 order_counter; |
|||
|
|||
/* Current received packet. */ |
|||
Pkt *inpkt; |
|||
|
|||
/* Queue of output packets. */ |
|||
Pkt **outpkt; |
|||
|
|||
/* Their commitments we have signed (which could appear on chain). */ |
|||
struct list_head their_commits; |
|||
|
|||
/* Number of commitment signatures we've received. */ |
|||
u64 their_commitsigs; |
|||
|
|||
/* Anchor tx output */ |
|||
struct { |
|||
struct sha256_double txid; |
|||
unsigned int index; |
|||
u64 satoshis; |
|||
u8 *witnessscript; |
|||
|
|||
/* Minimum possible depth for anchor */ |
|||
unsigned int min_depth; |
|||
|
|||
/* If we're creating anchor, this tells us where to source it */ |
|||
struct anchor_input *input; |
|||
|
|||
/* If we created it, we keep entire tx. */ |
|||
const struct bitcoin_tx *tx; |
|||
|
|||
/* Depth to trigger anchor if still opening, or -1. */ |
|||
int ok_depth; |
|||
|
|||
/* Did we create anchor? */ |
|||
bool ours; |
|||
} anchor; |
|||
|
|||
struct { |
|||
/* Their signature for our current commit sig. */ |
|||
secp256k1_ecdsa_signature theirsig; |
|||
/* The watch we have on a live commit tx. */ |
|||
struct txwatch *watch; |
|||
} cur_commit; |
|||
|
|||
/* Counter to make unique HTLC ids. */ |
|||
u64 htlc_id_counter; |
|||
|
|||
/* Mutual close info. */ |
|||
struct { |
|||
/* Our last suggested closing fee. */ |
|||
u64 our_fee; |
|||
/* If they've offered a signature, these are set: */ |
|||
secp256k1_ecdsa_signature *their_sig; |
|||
/* If their_sig is non-NULL, this is the fee. */ |
|||
u64 their_fee; |
|||
/* scriptPubKey we/they want for closing. */ |
|||
u8 *our_script, *their_script; |
|||
/* Last sent (in case we need to retransmit) */ |
|||
s64 shutdown_order, closing_order; |
|||
/* How many closing sigs have we receieved? */ |
|||
u32 sigs_in; |
|||
} closing; |
|||
|
|||
/* If we're closing on-chain */ |
|||
struct { |
|||
/* Everything (watches, resolved[], etc) tal'ed off this:
|
|||
* The commit which spends the anchor tx. */ |
|||
const struct bitcoin_tx *tx; |
|||
struct sha256_double txid; |
|||
|
|||
/* If >= 0, indicates which txout is to us and to them. */ |
|||
int to_us_idx, to_them_idx; |
|||
/* Maps what txouts are HTLCs (NULL implies to_us/them_idx). */ |
|||
struct htlc **htlcs; |
|||
/* Witness scripts for each output (where appropriate) */ |
|||
const u8 **wscripts; |
|||
/* The tx which resolves each txout. */ |
|||
const struct bitcoin_tx **resolved; |
|||
} onchain; |
|||
|
|||
/* All HTLCs. */ |
|||
struct htlc_map htlcs; |
|||
|
|||
/* We only track one feechange per state: last one counts. */ |
|||
struct feechange *feechanges[FEECHANGE_STATE_INVALID]; |
|||
|
|||
/* Current ongoing packetflow */ |
|||
struct io_data *io_data; |
|||
|
|||
/* What happened. */ |
|||
struct log *log; |
|||
|
|||
/* Things we're watching for (see watches.c) */ |
|||
struct list_head watches; |
|||
|
|||
/* Timeout for collecting changes before sending commit. */ |
|||
struct oneshot *commit_timer; |
|||
|
|||
/* Private keys for dealing with this peer. */ |
|||
struct peer_secrets *secrets; |
|||
|
|||
/* Our route connection to peer: NULL until we are in normal mode. */ |
|||
struct node_connection *nc; |
|||
|
|||
/* For testing. */ |
|||
bool fake_close; |
|||
bool output_enabled; |
|||
|
|||
/* Stuff we have in common. */ |
|||
struct peer_visible_state local, remote; |
|||
|
|||
/* If we have sent a new commit tx, but not received their revocation */ |
|||
struct sha256 *their_prev_revocation_hash; |
|||
|
|||
/* this is where we will store their revocation preimages*/ |
|||
struct shachain their_preimages; |
|||
|
|||
/* High water mark for the staggered broadcast */ |
|||
u64 broadcast_index; |
|||
}; |
|||
#endif /* LIGHTNING_DAEMON_PEER_INTERNAL_H */ |
@ -1,169 +0,0 @@ |
|||
#include "jsonrpc.h" |
|||
#include "lightningd.h" |
|||
#include "log.h" |
|||
#include "routing.h" |
|||
|
|||
static void json_add_route(struct command *cmd, |
|||
const char *buffer, const jsmntok_t *params) |
|||
{ |
|||
jsmntok_t *srctok, *dsttok, *basetok, *vartok, *delaytok, *minblockstok; |
|||
struct pubkey src, dst; |
|||
u32 base, var, delay, minblocks; |
|||
|
|||
if (!json_get_params(buffer, params, |
|||
"src", &srctok, |
|||
"dst", &dsttok, |
|||
"base", &basetok, |
|||
"var", &vartok, |
|||
"delay", &delaytok, |
|||
"minblocks", &minblockstok, |
|||
NULL)) { |
|||
command_fail(cmd, "Need src, dst, base, var, delay & minblocks"); |
|||
return; |
|||
} |
|||
|
|||
if (!pubkey_from_hexstr(buffer + srctok->start, |
|||
srctok->end - srctok->start, &src)) { |
|||
command_fail(cmd, "src %.*s not valid", |
|||
srctok->end - srctok->start, |
|||
buffer + srctok->start); |
|||
return; |
|||
} |
|||
|
|||
if (!pubkey_from_hexstr(buffer + dsttok->start, |
|||
dsttok->end - dsttok->start, &dst)) { |
|||
command_fail(cmd, "dst %.*s not valid", |
|||
dsttok->end - dsttok->start, |
|||
buffer + dsttok->start); |
|||
return; |
|||
} |
|||
|
|||
if (!json_tok_number(buffer, basetok, &base) |
|||
|| !json_tok_number(buffer, vartok, &var) |
|||
|| !json_tok_number(buffer, delaytok, &delay) |
|||
|| !json_tok_number(buffer, minblockstok, &minblocks)) { |
|||
command_fail(cmd, |
|||
"base, var, delay and minblocks must be numbers"); |
|||
return; |
|||
} |
|||
|
|||
add_connection(cmd->dstate->rstate, &src, &dst, base, var, delay, minblocks); |
|||
command_success(cmd, null_response(cmd)); |
|||
} |
|||
|
|||
static const struct json_command dev_add_route_command = { |
|||
"dev-add-route", |
|||
json_add_route, |
|||
"Add route from {src} to {dst}, {base} rate in msatoshi, {var} rate in msatoshi, {delay} blocks delay and {minblocks} minimum timeout", |
|||
"Returns an empty result on success" |
|||
}; |
|||
AUTODATA(json_command, &dev_add_route_command); |
|||
|
|||
static void json_getchannels(struct command *cmd, |
|||
const char *buffer, const jsmntok_t *params) |
|||
{ |
|||
struct json_result *response = new_json_result(cmd); |
|||
struct node_map_iter it; |
|||
struct node *n; |
|||
struct node_map *nodes = cmd->dstate->rstate->nodes; |
|||
struct node_connection *c; |
|||
int num_conn, i; |
|||
|
|||
json_object_start(response, NULL); |
|||
json_array_start(response, "channels"); |
|||
for (n = node_map_first(nodes, &it); n; n = node_map_next(nodes, &it)) { |
|||
num_conn = tal_count(n->out); |
|||
for (i = 0; i < num_conn; i++){ |
|||
c = n->out[i]; |
|||
json_object_start(response, NULL); |
|||
json_add_pubkey(response, "from", &n->id); |
|||
json_add_pubkey(response, "to", &c->dst->id); |
|||
json_add_num(response, "base_fee", c->base_fee); |
|||
json_add_num(response, "proportional_fee", c->proportional_fee); |
|||
json_add_num(response, "expiry", c->delay); |
|||
json_add_bool(response, "active", c->active); |
|||
json_object_end(response); |
|||
} |
|||
} |
|||
json_array_end(response); |
|||
json_object_end(response); |
|||
command_success(cmd, response); |
|||
} |
|||
|
|||
static const struct json_command getchannels_command = { |
|||
"getchannels", |
|||
json_getchannels, |
|||
"List all known channels.", |
|||
"Returns a 'channels' array with all known channels including their fees." |
|||
}; |
|||
AUTODATA(json_command, &getchannels_command); |
|||
|
|||
static void json_routefail(struct command *cmd, |
|||
const char *buffer, const jsmntok_t *params) |
|||
{ |
|||
jsmntok_t *enabletok; |
|||
bool enable; |
|||
|
|||
if (!json_get_params(buffer, params, |
|||
"enable", &enabletok, |
|||
NULL)) { |
|||
command_fail(cmd, "Need enable"); |
|||
return; |
|||
} |
|||
|
|||
if (!json_tok_bool(buffer, enabletok, &enable)) { |
|||
command_fail(cmd, "enable must be true or false"); |
|||
return; |
|||
} |
|||
|
|||
log_debug(cmd->dstate->base_log, "dev-routefail: routefail %s", |
|||
enable ? "enabled" : "disabled"); |
|||
cmd->dstate->dev_never_routefail = !enable; |
|||
|
|||
command_success(cmd, null_response(cmd)); |
|||
} |
|||
static const struct json_command dev_routefail_command = { |
|||
"dev-routefail", |
|||
json_routefail, |
|||
"FAIL htlcs that we can't route if {enable}", |
|||
"Returns an empty result on success" |
|||
}; |
|||
AUTODATA(json_command, &dev_routefail_command); |
|||
|
|||
static void json_getnodes(struct command *cmd, |
|||
const char *buffer, const jsmntok_t *params) |
|||
{ |
|||
struct json_result *response = new_json_result(cmd); |
|||
struct node *n; |
|||
struct node_map_iter i; |
|||
size_t j; |
|||
|
|||
n = node_map_first(cmd->dstate->rstate->nodes, &i); |
|||
|
|||
json_object_start(response, NULL); |
|||
json_array_start(response, "nodes"); |
|||
|
|||
while (n != NULL) { |
|||
json_object_start(response, NULL); |
|||
json_add_pubkey(response, "nodeid", &n->id); |
|||
json_array_start(response, "addresses"); |
|||
for (j=0; j<tal_count(n->addresses); j++) { |
|||
json_add_address(response, NULL, &n->addresses[j]); |
|||
} |
|||
json_array_end(response); |
|||
json_object_end(response); |
|||
n = node_map_next(cmd->dstate->rstate->nodes, &i); |
|||
} |
|||
|
|||
json_array_end(response); |
|||
json_object_end(response); |
|||
command_success(cmd, response); |
|||
} |
|||
|
|||
static const struct json_command getnodes_command = { |
|||
"getnodes", |
|||
json_getnodes, |
|||
"List all known nodes in the network.", |
|||
"Returns a 'nodes' array" |
|||
}; |
|||
AUTODATA(json_command, &getnodes_command); |
@ -1,251 +0,0 @@ |
|||
#include "bitcoin/privkey.h" |
|||
#include "bitcoin/shadouble.h" |
|||
#include "bitcoin/signature.h" |
|||
#include "lightningd.h" |
|||
#include "log.h" |
|||
#include "peer.h" |
|||
#include "peer_internal.h" |
|||
#include "secrets.h" |
|||
#include "utils.h" |
|||
#include <ccan/crypto/sha256/sha256.h> |
|||
#include <ccan/crypto/shachain/shachain.h> |
|||
#include <ccan/mem/mem.h> |
|||
#include <ccan/noerr/noerr.h> |
|||
#include <ccan/read_write_all/read_write_all.h> |
|||
#include <ccan/short_types/short_types.h> |
|||
#include <ccan/tal/str/str.h> |
|||
#include <errno.h> |
|||
#include <fcntl.h> |
|||
#include <secp256k1.h> |
|||
#include <sodium/randombytes.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/types.h> |
|||
#include <unistd.h> |
|||
|
|||
void privkey_sign(struct lightningd_state *dstate, const void *src, size_t len, |
|||
secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
struct sha256_double h; |
|||
|
|||
sha256_double(&h, memcheck(src, len), len); |
|||
sign_hash(dstate->privkey, &h, sig); |
|||
} |
|||
|
|||
struct peer_secrets { |
|||
/* Two private keys, one for commit txs, one for final output. */ |
|||
struct privkey commit, final; |
|||
/* Seed from which we generate revocation hashes. */ |
|||
struct sha256 revocation_seed; |
|||
}; |
|||
|
|||
void peer_sign_theircommit(const struct peer *peer, |
|||
struct bitcoin_tx *commit, |
|||
secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
/* Commit tx only has one input: that of the anchor. */ |
|||
sign_tx_input(commit, 0, |
|||
NULL, |
|||
peer->anchor.witnessscript, |
|||
&peer->secrets->commit, |
|||
&peer->local.commitkey, |
|||
sig); |
|||
} |
|||
|
|||
void peer_sign_ourcommit(const struct peer *peer, |
|||
struct bitcoin_tx *commit, |
|||
secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
/* Commit tx only has one input: that of the anchor. */ |
|||
sign_tx_input(commit, 0, |
|||
NULL, |
|||
peer->anchor.witnessscript, |
|||
&peer->secrets->commit, |
|||
&peer->local.commitkey, |
|||
sig); |
|||
} |
|||
|
|||
void peer_sign_spend(const struct peer *peer, |
|||
struct bitcoin_tx *spend, |
|||
const u8 *commit_witnessscript, |
|||
secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
/* Spend tx only has one input: that of the commit tx. */ |
|||
sign_tx_input(spend, 0, |
|||
NULL, |
|||
commit_witnessscript, |
|||
&peer->secrets->final, |
|||
&peer->local.finalkey, |
|||
sig); |
|||
} |
|||
|
|||
void peer_sign_htlc_refund(const struct peer *peer, |
|||
struct bitcoin_tx *spend, |
|||
const u8 *htlc_witnessscript, |
|||
secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
/* Spend tx only has one input: that of the commit tx. */ |
|||
sign_tx_input(spend, 0, |
|||
NULL, |
|||
htlc_witnessscript, |
|||
&peer->secrets->final, |
|||
&peer->local.finalkey, |
|||
sig); |
|||
} |
|||
|
|||
void peer_sign_htlc_fulfill(const struct peer *peer, |
|||
struct bitcoin_tx *spend, |
|||
const u8 *htlc_witnessscript, |
|||
secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
/* Spend tx only has one input: that of the commit tx. */ |
|||
sign_tx_input(spend, 0, |
|||
NULL, |
|||
htlc_witnessscript, |
|||
&peer->secrets->final, |
|||
&peer->local.finalkey, |
|||
sig); |
|||
} |
|||
|
|||
void peer_sign_mutual_close(const struct peer *peer, |
|||
struct bitcoin_tx *close, |
|||
secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
sign_tx_input(close, 0, |
|||
NULL, |
|||
peer->anchor.witnessscript, |
|||
&peer->secrets->commit, |
|||
&peer->local.commitkey, |
|||
sig); |
|||
} |
|||
|
|||
void peer_sign_steal_input(const struct peer *peer, |
|||
struct bitcoin_tx *spend, |
|||
size_t i, |
|||
const u8 *witnessscript, |
|||
secp256k1_ecdsa_signature *sig) |
|||
{ |
|||
/* Spend tx only has one input: that of the commit tx. */ |
|||
sign_tx_input(spend, i, |
|||
NULL, |
|||
witnessscript, |
|||
&peer->secrets->final, |
|||
&peer->local.finalkey, |
|||
sig); |
|||
} |
|||
|
|||
static void new_keypair(struct lightningd_state *dstate, |
|||
struct privkey *privkey, struct pubkey *pubkey) |
|||
{ |
|||
do { |
|||
randombytes_buf(privkey->secret.data, |
|||
sizeof(privkey->secret.data)); |
|||
} while (!pubkey_from_privkey(privkey, pubkey)); |
|||
} |
|||
|
|||
void peer_secrets_init(struct peer *peer) |
|||
{ |
|||
peer->secrets = tal(peer, struct peer_secrets); |
|||
|
|||
new_keypair(peer->dstate, &peer->secrets->commit, &peer->local.commitkey); |
|||
new_keypair(peer->dstate, &peer->secrets->final, &peer->local.finalkey); |
|||
randombytes_buf(peer->secrets->revocation_seed.u.u8, sizeof(peer->secrets->revocation_seed.u.u8)); |
|||
} |
|||
|
|||
void peer_get_revocation_preimage(const struct peer *peer, u64 index, |
|||
struct sha256 *preimage) |
|||
{ |
|||
// generate hashes in reverse order, otherwise the first hash gives away everything
|
|||
shachain_from_seed(&peer->secrets->revocation_seed, 0xFFFFFFFFFFFFFFFFL - index, preimage); |
|||
} |
|||
|
|||
void peer_get_revocation_hash(const struct peer *peer, u64 index, |
|||
struct sha256 *rhash) |
|||
{ |
|||
struct sha256 preimage; |
|||
|
|||
peer_get_revocation_preimage(peer, index, &preimage); |
|||
sha256(rhash, preimage.u.u8, sizeof(preimage.u.u8)); |
|||
} |
|||
|
|||
const char *peer_secrets_for_db(const tal_t *ctx, struct peer *peer) |
|||
{ |
|||
const struct peer_secrets *ps = peer->secrets; |
|||
return tal_fmt(ctx, "x'%s', x'%s', x'%s'", |
|||
tal_hexstr(ctx, &ps->commit, sizeof(ps->commit)), |
|||
tal_hexstr(ctx, &ps->final, sizeof(ps->final)), |
|||
tal_hexstr(ctx, &ps->revocation_seed, |
|||
sizeof(ps->revocation_seed))); |
|||
} |
|||
|
|||
void peer_set_secrets_from_db(struct peer *peer, |
|||
const void *commit_privkey, |
|||
size_t commit_privkey_len, |
|||
const void *final_privkey, |
|||
size_t final_privkey_len, |
|||
const void *revocation_seed, |
|||
size_t revocation_seed_len) |
|||
{ |
|||
struct peer_secrets *ps = tal(peer, struct peer_secrets); |
|||
|
|||
assert(!peer->secrets); |
|||
peer->secrets = ps; |
|||
|
|||
if (commit_privkey_len != sizeof(ps->commit) |
|||
|| final_privkey_len != sizeof(ps->final) |
|||
|| revocation_seed_len != sizeof(ps->revocation_seed)) |
|||
fatal("peer_set_secrets_from_db: bad lengths %zu/%zu/%zu", |
|||
commit_privkey_len, final_privkey_len, |
|||
revocation_seed_len); |
|||
|
|||
memcpy(&ps->commit, commit_privkey, commit_privkey_len); |
|||
memcpy(&ps->final, final_privkey, final_privkey_len); |
|||
memcpy(&ps->revocation_seed, revocation_seed, revocation_seed_len); |
|||
|
|||
if (!pubkey_from_privkey(&ps->commit, &peer->local.commitkey)) |
|||
fatal("peer_set_secrets_from_db:bad commit privkey"); |
|||
if (!pubkey_from_privkey(&ps->final, &peer->local.finalkey)) |
|||
fatal("peer_set_secrets_from_db:bad final privkey"); |
|||
} |
|||
|
|||
void secrets_init(struct lightningd_state *dstate) |
|||
{ |
|||
int fd; |
|||
|
|||
dstate->privkey = tal(dstate, struct privkey); |
|||
|
|||
fd = open("privkey", O_RDONLY); |
|||
if (fd < 0) { |
|||
if (errno != ENOENT) |
|||
fatal("Failed to open privkey: %s", strerror(errno)); |
|||
|
|||
log_unusual(dstate->base_log, "Creating privkey file"); |
|||
new_keypair(dstate, dstate->privkey, &dstate->id); |
|||
|
|||
fd = open("privkey", O_CREAT|O_EXCL|O_WRONLY, 0400); |
|||
if (fd < 0) |
|||
fatal("Failed to create privkey file: %s", |
|||
strerror(errno)); |
|||
if (!write_all(fd, &dstate->privkey->secret, |
|||
sizeof(dstate->privkey->secret))) { |
|||
unlink_noerr("privkey"); |
|||
fatal("Failed to write to privkey file: %s", |
|||
strerror(errno)); |
|||
} |
|||
if (fsync(fd) != 0) |
|||
fatal("Failed to sync to privkey file: %s", |
|||
strerror(errno)); |
|||
close(fd); |
|||
|
|||
fd = open("privkey", O_RDONLY); |
|||
if (fd < 0) |
|||
fatal("Failed to reopen privkey: %s", strerror(errno)); |
|||
} |
|||
if (!read_all(fd, &dstate->privkey->secret, |
|||
sizeof(dstate->privkey->secret))) |
|||
fatal("Failed to read privkey: %s", strerror(errno)); |
|||
close(fd); |
|||
if (!pubkey_from_privkey(dstate->privkey, &dstate->id)) |
|||
fatal("Invalid privkey"); |
|||
|
|||
log_info_struct(dstate->base_log, "ID: %s", struct pubkey, &dstate->id); |
|||
} |
@ -1,68 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_SECRETS_H |
|||
#define LIGHTNING_DAEMON_SECRETS_H |
|||
/* Routines to handle private keys. */ |
|||
#include "config.h" |
|||
#include <ccan/short_types/short_types.h> |
|||
#include <ccan/tal/tal.h> |
|||
#include <secp256k1.h> |
|||
|
|||
struct peer; |
|||
struct lightningd_state; |
|||
struct sha256; |
|||
|
|||
void privkey_sign(struct lightningd_state *dstate, const void *src, size_t len, |
|||
secp256k1_ecdsa_signature *sig); |
|||
|
|||
void peer_sign_theircommit(const struct peer *peer, |
|||
struct bitcoin_tx *commit, |
|||
secp256k1_ecdsa_signature *sig); |
|||
|
|||
void peer_sign_ourcommit(const struct peer *peer, |
|||
struct bitcoin_tx *commit, |
|||
secp256k1_ecdsa_signature *sig); |
|||
|
|||
void peer_sign_spend(const struct peer *peer, |
|||
struct bitcoin_tx *spend, |
|||
const u8 *commit_witnessscript, |
|||
secp256k1_ecdsa_signature *sig); |
|||
|
|||
void peer_sign_htlc_refund(const struct peer *peer, |
|||
struct bitcoin_tx *spend, |
|||
const u8 *htlc_witnessscript, |
|||
secp256k1_ecdsa_signature *sig); |
|||
|
|||
void peer_sign_htlc_fulfill(const struct peer *peer, |
|||
struct bitcoin_tx *spend, |
|||
const u8 *htlc_witnessscript, |
|||
secp256k1_ecdsa_signature *sig); |
|||
|
|||
void peer_sign_mutual_close(const struct peer *peer, |
|||
struct bitcoin_tx *close, |
|||
secp256k1_ecdsa_signature *sig); |
|||
|
|||
void peer_sign_steal_input(const struct peer *peer, |
|||
struct bitcoin_tx *spend, |
|||
size_t i, |
|||
const u8 *witnessscript, |
|||
secp256k1_ecdsa_signature *sig); |
|||
|
|||
const char *peer_secrets_for_db(const tal_t *ctx, struct peer *peer); |
|||
|
|||
void peer_set_secrets_from_db(struct peer *peer, |
|||
const void *commit_privkey, |
|||
size_t commit_privkey_len, |
|||
const void *final_privkey, |
|||
size_t final_privkey_len, |
|||
const void *revocation_seed, |
|||
size_t revocation_seed_len); |
|||
|
|||
void peer_secrets_init(struct peer *peer); |
|||
|
|||
void peer_get_revocation_hash(const struct peer *peer, u64 index, |
|||
struct sha256 *rhash); |
|||
void peer_get_revocation_preimage(const struct peer *peer, u64 index, |
|||
struct sha256 *preimage); |
|||
|
|||
void secrets_init(struct lightningd_state *dstate); |
|||
|
|||
#endif /* LIGHTNING_DAEMON_SECRETS_H */ |
@ -1,479 +0,0 @@ |
|||
#include "sphinx.h" |
|||
#include "utils.h" |
|||
#include <assert.h> |
|||
|
|||
#include <bitcoin/address.h> |
|||
|
|||
#include <ccan/crypto/ripemd160/ripemd160.h> |
|||
#include <ccan/crypto/sha256/sha256.h> |
|||
#include <ccan/mem/mem.h> |
|||
|
|||
#include <err.h> |
|||
|
|||
#include <secp256k1_ecdh.h> |
|||
|
|||
#include <sodium/crypto_auth_hmacsha256.h> |
|||
#include <sodium/crypto_stream_chacha20.h> |
|||
|
|||
#define BLINDING_FACTOR_SIZE 32 |
|||
#define SHARED_SECRET_SIZE 32 |
|||
#define NUM_STREAM_BYTES ((2 * NUM_MAX_HOPS + 2) * SECURITY_PARAMETER) |
|||
#define KEY_LEN 32 |
|||
|
|||
struct hop_params { |
|||
u8 secret[SHARED_SECRET_SIZE]; |
|||
u8 blind[BLINDING_FACTOR_SIZE]; |
|||
secp256k1_pubkey ephemeralkey; |
|||
}; |
|||
|
|||
struct keyset { |
|||
u8 pi[KEY_LEN]; |
|||
u8 mu[KEY_LEN]; |
|||
u8 rho[KEY_LEN]; |
|||
u8 gamma[KEY_LEN]; |
|||
}; |
|||
|
|||
/* Small helper to append data to a buffer and update the position
|
|||
* into the buffer |
|||
*/ |
|||
static void write_buffer(u8 *dst, const void *src, const size_t len, int *pos) |
|||
{ |
|||
memcpy(dst + *pos, src, len); |
|||
*pos += len; |
|||
} |
|||
|
|||
/* Read len bytes from the source at position pos into dst and update
|
|||
* the position pos accordingly. |
|||
*/ |
|||
static void read_buffer(void *dst, const u8 *src, const size_t len, int *pos) |
|||
{ |
|||
memcpy(dst, src + *pos, len); |
|||
*pos += len; |
|||
} |
|||
|
|||
u8 *serialize_onionpacket( |
|||
const tal_t *ctx, |
|||
const struct onionpacket *m) |
|||
{ |
|||
u8 *dst = tal_arr(ctx, u8, TOTAL_PACKET_SIZE); |
|||
|
|||
u8 der[33]; |
|||
size_t outputlen = 33; |
|||
int p = 0; |
|||
|
|||
secp256k1_ec_pubkey_serialize(secp256k1_ctx, |
|||
der, |
|||
&outputlen, |
|||
&m->ephemeralkey, |
|||
SECP256K1_EC_COMPRESSED); |
|||
|
|||
write_buffer(dst, &m->version, 1, &p); |
|||
write_buffer(dst, der, outputlen, &p); |
|||
write_buffer(dst, m->mac, sizeof(m->mac), &p); |
|||
write_buffer(dst, m->routinginfo, ROUTING_INFO_SIZE, &p); |
|||
write_buffer(dst, m->hoppayloads, TOTAL_HOP_PAYLOAD_SIZE, &p); |
|||
return dst; |
|||
} |
|||
|
|||
struct onionpacket *parse_onionpacket( |
|||
const tal_t *ctx, |
|||
const void *src, |
|||
const size_t srclen |
|||
) |
|||
{ |
|||
struct onionpacket *m; |
|||
int p = 0; |
|||
u8 rawEphemeralkey[33]; |
|||
|
|||
if (srclen != TOTAL_PACKET_SIZE) |
|||
return NULL; |
|||
|
|||
m = talz(ctx, struct onionpacket); |
|||
|
|||
read_buffer(&m->version, src, 1, &p); |
|||
if (m->version != 0x01) { |
|||
// FIXME add logging
|
|||
return tal_free(m); |
|||
} |
|||
read_buffer(rawEphemeralkey, src, 33, &p); |
|||
|
|||
if (secp256k1_ec_pubkey_parse(secp256k1_ctx, &m->ephemeralkey, rawEphemeralkey, 33) != 1) |
|||
return tal_free(m); |
|||
|
|||
read_buffer(&m->mac, src, 20, &p); |
|||
read_buffer(&m->routinginfo, src, ROUTING_INFO_SIZE, &p); |
|||
read_buffer(&m->hoppayloads, src, TOTAL_HOP_PAYLOAD_SIZE, &p); |
|||
return m; |
|||
} |
|||
|
|||
static struct hoppayload *parse_hoppayload(const tal_t *ctx, u8 *src) |
|||
{ |
|||
int p = 0; |
|||
struct hoppayload *result = talz(ctx, struct hoppayload); |
|||
|
|||
read_buffer(&result->realm, src, sizeof(result->realm), &p); |
|||
read_buffer(&result->amt_to_forward, |
|||
src, sizeof(result->amt_to_forward), &p); |
|||
read_buffer(&result->outgoing_cltv_value, |
|||
src, sizeof(result->outgoing_cltv_value), &p); |
|||
read_buffer(&result->unused_with_v0_version_on_header, |
|||
src, sizeof(result->unused_with_v0_version_on_header), &p); |
|||
return result; |
|||
} |
|||
|
|||
static void serialize_hoppayload(u8 *dst, struct hoppayload *hp) |
|||
{ |
|||
int p = 0; |
|||
|
|||
write_buffer(dst, &hp->realm, sizeof(hp->realm), &p); |
|||
write_buffer(dst, &hp->amt_to_forward, sizeof(hp->amt_to_forward), &p); |
|||
write_buffer(dst, &hp->outgoing_cltv_value, |
|||
sizeof(hp->outgoing_cltv_value), &p); |
|||
write_buffer(dst, &hp->unused_with_v0_version_on_header, |
|||
sizeof(hp->unused_with_v0_version_on_header), &p); |
|||
} |
|||
|
|||
|
|||
static void xorbytes(uint8_t *d, const uint8_t *a, const uint8_t *b, size_t len) |
|||
{ |
|||
size_t i; |
|||
|
|||
for (i = 0; i < len; i++) |
|||
d[i] = a[i] ^ b[i]; |
|||
} |
|||
|
|||
/*
|
|||
* Generate a pseudo-random byte stream of length `dstlen` from key `k` and |
|||
* store it in `dst`. `dst must be at least `dstlen` bytes long. |
|||
*/ |
|||
static void generate_cipher_stream(void *dst, const u8 *k, size_t dstlen) |
|||
{ |
|||
u8 nonce[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
|||
|
|||
crypto_stream_chacha20(dst, dstlen, nonce, k); |
|||
} |
|||
|
|||
static bool compute_hmac( |
|||
void *dst, |
|||
const void *src, |
|||
size_t len, |
|||
const void *key, |
|||
size_t keylen) |
|||
{ |
|||
crypto_auth_hmacsha256_state state; |
|||
|
|||
crypto_auth_hmacsha256_init(&state, key, keylen); |
|||
crypto_auth_hmacsha256_update(&state, memcheck(src, len), len); |
|||
crypto_auth_hmacsha256_final(&state, dst); |
|||
return true; |
|||
} |
|||
|
|||
static void compute_packet_hmac(const struct onionpacket *packet, |
|||
const u8 *assocdata, const size_t assocdatalen, |
|||
u8 *mukey, u8 *hmac) |
|||
{ |
|||
u8 mactemp[ROUTING_INFO_SIZE + TOTAL_HOP_PAYLOAD_SIZE + assocdatalen]; |
|||
u8 mac[32]; |
|||
int pos = 0; |
|||
|
|||
write_buffer(mactemp, packet->routinginfo, ROUTING_INFO_SIZE, &pos); |
|||
write_buffer(mactemp, packet->hoppayloads, TOTAL_HOP_PAYLOAD_SIZE, &pos); |
|||
write_buffer(mactemp, assocdata, assocdatalen, &pos); |
|||
|
|||
compute_hmac(mac, mactemp, sizeof(mactemp), mukey, KEY_LEN); |
|||
memcpy(hmac, mac, 20); |
|||
} |
|||
|
|||
static bool generate_key(void *k, const char *t, u8 tlen, const u8 *s) |
|||
{ |
|||
return compute_hmac(k, s, KEY_LEN, t, tlen); |
|||
} |
|||
|
|||
static bool generate_header_padding( |
|||
void *dst, size_t dstlen, |
|||
const size_t hopsize, |
|||
const char *keytype, |
|||
size_t keytypelen, |
|||
const u8 numhops, |
|||
struct hop_params *params |
|||
) |
|||
{ |
|||
int i; |
|||
u8 cipher_stream[(NUM_MAX_HOPS + 1) * hopsize]; |
|||
u8 key[KEY_LEN]; |
|||
|
|||
memset(dst, 0, dstlen); |
|||
for (i = 1; i < numhops; i++) { |
|||
if (!generate_key(&key, keytype, keytypelen, params[i - 1].secret)) |
|||
return false; |
|||
|
|||
generate_cipher_stream(cipher_stream, key, sizeof(cipher_stream)); |
|||
int pos = ((NUM_MAX_HOPS - i) + 1) * hopsize; |
|||
xorbytes(dst, dst, cipher_stream + pos, sizeof(cipher_stream) - pos); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
static void compute_blinding_factor(const secp256k1_pubkey *key, |
|||
const u8 sharedsecret[SHARED_SECRET_SIZE], |
|||
u8 res[BLINDING_FACTOR_SIZE]) |
|||
{ |
|||
struct sha256_ctx ctx; |
|||
u8 der[33]; |
|||
size_t outputlen = 33; |
|||
struct sha256 temp; |
|||
|
|||
secp256k1_ec_pubkey_serialize(secp256k1_ctx, der, &outputlen, key, |
|||
SECP256K1_EC_COMPRESSED); |
|||
sha256_init(&ctx); |
|||
sha256_update(&ctx, der, sizeof(der)); |
|||
sha256_update(&ctx, sharedsecret, SHARED_SECRET_SIZE); |
|||
sha256_done(&ctx, &temp); |
|||
memcpy(res, &temp, 32); |
|||
} |
|||
|
|||
static bool blind_group_element( |
|||
secp256k1_pubkey *blindedelement, |
|||
const secp256k1_pubkey *pubkey, |
|||
const u8 blind[BLINDING_FACTOR_SIZE]) |
|||
{ |
|||
/* tweak_mul is inplace so copy first. */ |
|||
if (pubkey != blindedelement) |
|||
*blindedelement = *pubkey; |
|||
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx, blindedelement, blind) != 1) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
static bool create_shared_secret( |
|||
u8 *secret, |
|||
const secp256k1_pubkey *pubkey, |
|||
const u8 *sessionkey) |
|||
{ |
|||
|
|||
if (secp256k1_ecdh(secp256k1_ctx, secret, pubkey, sessionkey) != 1) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
bool onion_shared_secret( |
|||
u8 *secret, |
|||
const struct onionpacket *packet, |
|||
const struct privkey *privkey) |
|||
{ |
|||
return create_shared_secret(secret, &packet->ephemeralkey, |
|||
privkey->secret.data); |
|||
} |
|||
|
|||
static void generate_key_set(const u8 secret[SHARED_SECRET_SIZE], |
|||
struct keyset *keys) |
|||
{ |
|||
generate_key(keys->rho, "rho", 3, secret); |
|||
generate_key(keys->pi, "pi", 2, secret); |
|||
generate_key(keys->mu, "mu", 2, secret); |
|||
generate_key(keys->gamma, "gamma", 5, secret); |
|||
} |
|||
|
|||
static struct hop_params *generate_hop_params( |
|||
const tal_t *ctx, |
|||
const u8 *sessionkey, |
|||
struct pubkey path[]) |
|||
{ |
|||
int i, j, num_hops = tal_count(path); |
|||
secp256k1_pubkey temp; |
|||
u8 blind[BLINDING_FACTOR_SIZE]; |
|||
struct hop_params *params = tal_arr(ctx, struct hop_params, num_hops); |
|||
|
|||
/* Initialize the first hop with the raw information */ |
|||
if (secp256k1_ec_pubkey_create( |
|||
secp256k1_ctx, ¶ms[0].ephemeralkey, sessionkey) != 1) |
|||
return NULL; |
|||
|
|||
if (!create_shared_secret( |
|||
params[0].secret, &path[0].pubkey, sessionkey)) |
|||
return NULL; |
|||
|
|||
compute_blinding_factor( |
|||
¶ms[0].ephemeralkey, params[0].secret, |
|||
params[0].blind); |
|||
|
|||
/* Recursively compute all following ephemeral public keys,
|
|||
* secrets and blinding factors |
|||
*/ |
|||
for (i = 1; i < num_hops; i++) { |
|||
if (!blind_group_element( |
|||
¶ms[i].ephemeralkey, |
|||
¶ms[i - 1].ephemeralkey, |
|||
params[i - 1].blind)) |
|||
return NULL; |
|||
|
|||
/* Blind this hop's point with all previous blinding factors
|
|||
* Order is indifferent, multiplication is commutative. |
|||
*/ |
|||
memcpy(&blind, sessionkey, 32); |
|||
temp = path[i].pubkey; |
|||
if (!blind_group_element(&temp, &temp, blind)) |
|||
return NULL; |
|||
for (j = 0; j < i; j++) |
|||
if (!blind_group_element( |
|||
&temp, |
|||
&temp, |
|||
params[j].blind)) |
|||
return NULL; |
|||
|
|||
/* Now hash temp and store it. This requires us to
|
|||
* DER-serialize first and then skip the sign byte. |
|||
*/ |
|||
u8 der[33]; |
|||
size_t outputlen = 33; |
|||
secp256k1_ec_pubkey_serialize( |
|||
secp256k1_ctx, der, &outputlen, &temp, |
|||
SECP256K1_EC_COMPRESSED); |
|||
struct sha256 h; |
|||
sha256(&h, der, sizeof(der)); |
|||
memcpy(¶ms[i].secret, &h, sizeof(h)); |
|||
|
|||
compute_blinding_factor( |
|||
¶ms[i].ephemeralkey, |
|||
params[i].secret, params[i].blind); |
|||
} |
|||
return params; |
|||
} |
|||
|
|||
struct onionpacket *create_onionpacket( |
|||
const tal_t *ctx, |
|||
struct pubkey *path, |
|||
struct hoppayload hoppayloads[], |
|||
const u8 *sessionkey, |
|||
const u8 *assocdata, |
|||
const size_t assocdatalen |
|||
) |
|||
{ |
|||
struct onionpacket *packet = talz(ctx, struct onionpacket); |
|||
int i, num_hops = tal_count(path); |
|||
u8 filler[2 * (num_hops - 1) * SECURITY_PARAMETER]; |
|||
u8 hopfiller[(num_hops - 1) * HOP_PAYLOAD_SIZE]; |
|||
struct keyset keys; |
|||
struct bitcoin_address nextaddr; |
|||
u8 nexthmac[SECURITY_PARAMETER]; |
|||
u8 stream[ROUTING_INFO_SIZE], hopstream[TOTAL_HOP_PAYLOAD_SIZE]; |
|||
struct hop_params *params = generate_hop_params(ctx, sessionkey, path); |
|||
u8 binhoppayloads[tal_count(path)][HOP_PAYLOAD_SIZE]; |
|||
|
|||
for (i = 0; i < num_hops; i++) |
|||
serialize_hoppayload(binhoppayloads[i], &hoppayloads[i]); |
|||
|
|||
if (!params) |
|||
return NULL; |
|||
packet->version = 1; |
|||
memset(&nextaddr, 0, 20); |
|||
memset(nexthmac, 0, 20); |
|||
memset(packet->routinginfo, 0, ROUTING_INFO_SIZE); |
|||
|
|||
generate_header_padding(filler, sizeof(filler), 2 * SECURITY_PARAMETER, |
|||
"rho", 3, num_hops, params); |
|||
generate_header_padding(hopfiller, sizeof(hopfiller), HOP_PAYLOAD_SIZE, |
|||
"gamma", 5, num_hops, params); |
|||
|
|||
for (i = num_hops - 1; i >= 0; i--) { |
|||
generate_key_set(params[i].secret, &keys); |
|||
generate_cipher_stream(stream, keys.rho, ROUTING_INFO_SIZE); |
|||
|
|||
/* Rightshift mix-header by 2*SECURITY_PARAMETER */ |
|||
memmove(packet->routinginfo + 2 * SECURITY_PARAMETER, packet->routinginfo, |
|||
ROUTING_INFO_SIZE - 2 * SECURITY_PARAMETER); |
|||
memcpy(packet->routinginfo, &nextaddr, SECURITY_PARAMETER); |
|||
memcpy(packet->routinginfo + SECURITY_PARAMETER, nexthmac, SECURITY_PARAMETER); |
|||
xorbytes(packet->routinginfo, packet->routinginfo, stream, ROUTING_INFO_SIZE); |
|||
|
|||
/* Rightshift hop-payloads and obfuscate */ |
|||
memmove(packet->hoppayloads + HOP_PAYLOAD_SIZE, packet->hoppayloads, |
|||
TOTAL_HOP_PAYLOAD_SIZE - HOP_PAYLOAD_SIZE); |
|||
memcpy(packet->hoppayloads, binhoppayloads[i], HOP_PAYLOAD_SIZE); |
|||
generate_cipher_stream(hopstream, keys.gamma, TOTAL_HOP_PAYLOAD_SIZE); |
|||
xorbytes(packet->hoppayloads, packet->hoppayloads, hopstream, |
|||
TOTAL_HOP_PAYLOAD_SIZE); |
|||
|
|||
if (i == num_hops - 1) { |
|||
size_t len = (NUM_MAX_HOPS - num_hops + 1) * 2 * SECURITY_PARAMETER; |
|||
memcpy(packet->routinginfo + len, filler, sizeof(filler)); |
|||
len = (NUM_MAX_HOPS - num_hops + 1) * HOP_PAYLOAD_SIZE; |
|||
memcpy(packet->hoppayloads + len, hopfiller, sizeof(hopfiller)); |
|||
} |
|||
|
|||
compute_packet_hmac(packet, assocdata, assocdatalen, keys.mu, |
|||
nexthmac); |
|||
pubkey_to_hash160(&path[i], &nextaddr.addr); |
|||
} |
|||
memcpy(packet->mac, nexthmac, sizeof(nexthmac)); |
|||
memcpy(&packet->ephemeralkey, ¶ms[0].ephemeralkey, sizeof(secp256k1_pubkey)); |
|||
return packet; |
|||
} |
|||
|
|||
/*
|
|||
* Given a onionpacket msg extract the information for the current |
|||
* node and unwrap the remainder so that the node can forward it. |
|||
*/ |
|||
struct route_step *process_onionpacket( |
|||
const tal_t *ctx, |
|||
const struct onionpacket *msg, |
|||
const u8 *shared_secret, |
|||
const u8 *assocdata, |
|||
const size_t assocdatalen |
|||
) |
|||
{ |
|||
struct route_step *step = talz(ctx, struct route_step); |
|||
u8 hmac[20]; |
|||
struct keyset keys; |
|||
u8 paddedhoppayloads[TOTAL_HOP_PAYLOAD_SIZE + HOP_PAYLOAD_SIZE]; |
|||
u8 hopstream[TOTAL_HOP_PAYLOAD_SIZE + HOP_PAYLOAD_SIZE]; |
|||
u8 blind[BLINDING_FACTOR_SIZE]; |
|||
u8 stream[NUM_STREAM_BYTES]; |
|||
u8 paddedheader[ROUTING_INFO_SIZE + 2 * SECURITY_PARAMETER]; |
|||
|
|||
step->next = talz(step, struct onionpacket); |
|||
step->next->version = msg->version; |
|||
generate_key_set(shared_secret, &keys); |
|||
|
|||
compute_packet_hmac(msg, assocdata, assocdatalen, keys.mu, hmac); |
|||
|
|||
if (memcmp(msg->mac, hmac, sizeof(hmac)) != 0) { |
|||
warnx("Computed MAC does not match expected MAC, the message was modified."); |
|||
return tal_free(step); |
|||
} |
|||
|
|||
//FIXME:store seen secrets to avoid replay attacks
|
|||
generate_cipher_stream(stream, keys.rho, sizeof(stream)); |
|||
|
|||
memset(paddedheader, 0, sizeof(paddedheader)); |
|||
memcpy(paddedheader, msg->routinginfo, ROUTING_INFO_SIZE); |
|||
xorbytes(paddedheader, paddedheader, stream, sizeof(stream)); |
|||
|
|||
/* Extract the per-hop payload */ |
|||
generate_cipher_stream(hopstream, keys.gamma, sizeof(hopstream)); |
|||
|
|||
memset(paddedhoppayloads, 0, sizeof(paddedhoppayloads)); |
|||
memcpy(paddedhoppayloads, msg->hoppayloads, TOTAL_HOP_PAYLOAD_SIZE); |
|||
xorbytes(paddedhoppayloads, paddedhoppayloads, hopstream, sizeof(hopstream)); |
|||
step->hoppayload = parse_hoppayload(step, paddedhoppayloads); |
|||
memcpy(&step->next->hoppayloads, paddedhoppayloads + HOP_PAYLOAD_SIZE, |
|||
TOTAL_HOP_PAYLOAD_SIZE); |
|||
|
|||
compute_blinding_factor(&msg->ephemeralkey, shared_secret, blind); |
|||
if (!blind_group_element(&step->next->ephemeralkey, &msg->ephemeralkey, blind)) |
|||
return tal_free(step); |
|||
memcpy(&step->next->nexthop, paddedheader, SECURITY_PARAMETER); |
|||
memcpy(&step->next->mac, |
|||
paddedheader + SECURITY_PARAMETER, |
|||
SECURITY_PARAMETER); |
|||
|
|||
memcpy(&step->next->routinginfo, paddedheader + 2 * SECURITY_PARAMETER, ROUTING_INFO_SIZE); |
|||
|
|||
if (memeqzero(step->next->mac, sizeof(step->next->mac))) { |
|||
step->nextcase = ONION_END; |
|||
} else { |
|||
step->nextcase = ONION_FORWARD; |
|||
} |
|||
|
|||
return step; |
|||
} |
@ -1,136 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_SPHINX_H |
|||
#define LIGHTNING_DAEMON_SPHINX_H |
|||
|
|||
#include "config.h" |
|||
#include "bitcoin/privkey.h" |
|||
#include "bitcoin/pubkey.h" |
|||
|
|||
#include <ccan/short_types/short_types.h> |
|||
#include <ccan/tal/tal.h> |
|||
#include <secp256k1.h> |
|||
#include <sodium/randombytes.h> |
|||
|
|||
#define SECURITY_PARAMETER 20 |
|||
#define NUM_MAX_HOPS 20 |
|||
#define HOP_PAYLOAD_SIZE 20 |
|||
#define TOTAL_HOP_PAYLOAD_SIZE (NUM_MAX_HOPS * HOP_PAYLOAD_SIZE) |
|||
#define ROUTING_INFO_SIZE (2 * NUM_MAX_HOPS * SECURITY_PARAMETER) |
|||
#define TOTAL_PACKET_SIZE (1 + 33 + SECURITY_PARAMETER + ROUTING_INFO_SIZE + \ |
|||
TOTAL_HOP_PAYLOAD_SIZE) |
|||
|
|||
struct onionpacket { |
|||
/* Cleartext information */ |
|||
u8 version; |
|||
u8 nexthop[20]; |
|||
u8 mac[20]; |
|||
secp256k1_pubkey ephemeralkey; |
|||
|
|||
/* Encrypted information */ |
|||
u8 routinginfo[ROUTING_INFO_SIZE]; |
|||
u8 hoppayloads[TOTAL_HOP_PAYLOAD_SIZE]; |
|||
}; |
|||
|
|||
enum route_next_case { |
|||
ONION_END = 0, |
|||
ONION_FORWARD = 1, |
|||
}; |
|||
|
|||
/* FIXME-OLD #4:
|
|||
* |
|||
* The format of the per-hop-payload for a version 0 packet is as follows: |
|||
``` |
|||
+----------------+--------------------------+-------------------------------+--------------------------------------------+ |
|||
| realm (1 byte) | amt_to_forward (8 bytes) | outgoing_cltv_value (4 bytes) | unused_with_v0_version_on_header (7 bytes) | |
|||
+----------------+--------------------------+-------------------------------+--------------------------------------------+ |
|||
``` |
|||
*/ |
|||
struct hoppayload { |
|||
u8 realm; |
|||
u64 amt_to_forward; |
|||
u32 outgoing_cltv_value; |
|||
u8 unused_with_v0_version_on_header[7]; |
|||
}; |
|||
|
|||
struct route_step { |
|||
enum route_next_case nextcase; |
|||
struct onionpacket *next; |
|||
struct hoppayload *hoppayload; |
|||
}; |
|||
|
|||
/**
|
|||
* create_onionpacket - Create a new onionpacket that can be routed |
|||
* over a path of intermediate nodes. |
|||
* |
|||
* @ctx: tal context to allocate from |
|||
* @path: public keys of nodes along the path. |
|||
* @hoppayloads: payloads destined for individual hosts (limited to |
|||
* HOP_PAYLOAD_SIZE bytes) |
|||
* @num_hops: path length in nodes |
|||
* @sessionkey: 20 byte random session key to derive secrets from |
|||
* @assocdata: associated data to commit to in HMACs |
|||
* @assocdatalen: length of the assocdata |
|||
*/ |
|||
struct onionpacket *create_onionpacket( |
|||
const tal_t * ctx, |
|||
struct pubkey path[], |
|||
struct hoppayload hoppayloads[], |
|||
const u8 * sessionkey, |
|||
const u8 *assocdata, |
|||
const size_t assocdatalen |
|||
); |
|||
|
|||
/**
|
|||
* onion_shared_secret - calculate ECDH shared secret between nodes. |
|||
* |
|||
* @secret: the shared secret (32 bytes long) |
|||
* @pubkey: the public key of the other node |
|||
* @privkey: the private key of this node (32 bytes long) |
|||
*/ |
|||
bool onion_shared_secret( |
|||
u8 *secret, |
|||
const struct onionpacket *packet, |
|||
const struct privkey *privkey); |
|||
|
|||
/**
|
|||
* process_onionpacket - process an incoming packet by stripping one |
|||
* onion layer and return the packet for the next hop. |
|||
* |
|||
* @ctx: tal context to allocate from |
|||
* @packet: incoming packet being processed |
|||
* @shared_secret: the result of onion_shared_secret. |
|||
* @hoppayload: the per-hop payload destined for the processing node. |
|||
* @assocdata: associated data to commit to in HMACs |
|||
* @assocdatalen: length of the assocdata |
|||
*/ |
|||
struct route_step *process_onionpacket( |
|||
const tal_t * ctx, |
|||
const struct onionpacket *packet, |
|||
const u8 *shared_secret, |
|||
const u8 *assocdata, |
|||
const size_t assocdatalen |
|||
); |
|||
|
|||
/**
|
|||
* serialize_onionpacket - Serialize an onionpacket to a buffer. |
|||
* |
|||
* @ctx: tal context to allocate from |
|||
* @packet: the packet to serialize |
|||
*/ |
|||
u8 *serialize_onionpacket( |
|||
const tal_t *ctx, |
|||
const struct onionpacket *packet); |
|||
|
|||
/**
|
|||
* parese_onionpacket - Parse an onionpacket from a buffer. |
|||
* |
|||
* @ctx: tal context to allocate from |
|||
* @src: buffer to read the packet from |
|||
* @srclen: length of the @src |
|||
*/ |
|||
struct onionpacket *parse_onionpacket( |
|||
const tal_t *ctx, |
|||
const void *src, |
|||
const size_t srclen |
|||
); |
|||
|
|||
#endif /* LIGHTNING_DAEMON_SPHINX_H */ |
@ -1,77 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_STATE_H |
|||
#define LIGHTNING_DAEMON_STATE_H |
|||
#include "config.h" |
|||
|
|||
#include "daemon/state_types.h" |
|||
#include <stdbool.h> |
|||
|
|||
static inline bool state_is_error(enum state s) |
|||
{ |
|||
return s >= STATE_ERR_BREAKDOWN && s <= STATE_ERR_INTERNAL; |
|||
} |
|||
|
|||
static inline bool state_is_shutdown(enum state s) |
|||
{ |
|||
return s == STATE_SHUTDOWN || s == STATE_SHUTDOWN_COMMITTING; |
|||
} |
|||
|
|||
static inline bool state_is_onchain(enum state s) |
|||
{ |
|||
return s >= STATE_CLOSE_ONCHAIN_CHEATED |
|||
&& s <= STATE_CLOSE_ONCHAIN_MUTUAL; |
|||
} |
|||
|
|||
static inline bool state_is_normal(enum state s) |
|||
{ |
|||
return s == STATE_NORMAL || s == STATE_NORMAL_COMMITTING; |
|||
} |
|||
|
|||
static inline bool state_is_waiting_for_anchor(enum state s) |
|||
{ |
|||
return s == STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE |
|||
|| s == STATE_OPEN_WAIT_ANCHORDEPTH; |
|||
} |
|||
|
|||
static inline bool state_is_openwait(enum state s) |
|||
{ |
|||
return s == STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE |
|||
|| s == STATE_OPEN_WAIT_ANCHORDEPTH |
|||
|| s == STATE_OPEN_WAIT_THEIRCOMPLETE; |
|||
} |
|||
|
|||
static inline bool state_is_opening(enum state s) |
|||
{ |
|||
return s <= STATE_OPEN_WAIT_THEIRCOMPLETE; |
|||
} |
|||
|
|||
static inline bool state_can_io(enum state s) |
|||
{ |
|||
if (state_is_error(s)) |
|||
return false; |
|||
if (s == STATE_CLOSED) |
|||
return false; |
|||
if (state_is_onchain(s)) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
static inline bool state_can_commit(enum state s) |
|||
{ |
|||
return s == STATE_NORMAL || s == STATE_SHUTDOWN; |
|||
} |
|||
|
|||
/* FIXME-OLD #2:
|
|||
* |
|||
* A node MUST NOT send a `update_add_htlc` after a `close_shutdown` |
|||
*/ |
|||
static inline bool state_can_add_htlc(enum state s) |
|||
{ |
|||
return state_is_normal(s); |
|||
} |
|||
|
|||
static inline bool state_can_remove_htlc(enum state s) |
|||
{ |
|||
return state_is_normal(s) || state_is_shutdown(s); |
|||
} |
|||
|
|||
#endif /* LIGHTNING_STATE_H */ |
@ -1,99 +0,0 @@ |
|||
#ifndef LIGHTNING_STATE_TYPES_H |
|||
#define LIGHTNING_STATE_TYPES_H |
|||
#include "config.h" |
|||
/* FIXME: cdump is really dumb, so we put these in their own header. */ |
|||
#include "lightning.pb-c.h" |
|||
|
|||
enum state { |
|||
STATE_INIT, |
|||
|
|||
/*
|
|||
* Opening. |
|||
*/ |
|||
STATE_OPEN_WAIT_FOR_OPENPKT, |
|||
STATE_OPEN_WAIT_FOR_ANCHORPKT, |
|||
STATE_OPEN_WAIT_FOR_COMMIT_SIGPKT, |
|||
|
|||
/* We're waiting for depth+their complete. */ |
|||
STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE, |
|||
/* Got their pkt_complete. */ |
|||
STATE_OPEN_WAIT_ANCHORDEPTH, |
|||
/* Got anchor depth. */ |
|||
STATE_OPEN_WAIT_THEIRCOMPLETE, |
|||
|
|||
/*
|
|||
* Normal state. |
|||
*/ |
|||
STATE_NORMAL, |
|||
STATE_NORMAL_COMMITTING, |
|||
|
|||
/*
|
|||
* Closing (handled outside state machine). |
|||
*/ |
|||
STATE_SHUTDOWN, |
|||
STATE_SHUTDOWN_COMMITTING, |
|||
STATE_MUTUAL_CLOSING, |
|||
|
|||
/* Four states to represent closing onchain (for getpeers) */ |
|||
STATE_CLOSE_ONCHAIN_CHEATED, |
|||
STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL, |
|||
STATE_CLOSE_ONCHAIN_OUR_UNILATERAL, |
|||
STATE_CLOSE_ONCHAIN_MUTUAL, |
|||
|
|||
/* All closed. */ |
|||
STATE_CLOSED, |
|||
|
|||
/*
|
|||
* Where angels fear to tread. |
|||
*/ |
|||
/* Bad packet from them / protocol breakdown. */ |
|||
STATE_ERR_BREAKDOWN, |
|||
/* The anchor didn't reach blockchain in reasonable time. */ |
|||
STATE_ERR_ANCHOR_TIMEOUT, |
|||
/* We saw a tx we didn't sign. */ |
|||
STATE_ERR_INFORMATION_LEAK, |
|||
/* We ended up in an unexpected state. */ |
|||
STATE_ERR_INTERNAL, |
|||
|
|||
STATE_MAX |
|||
}; |
|||
|
|||
enum state_input { |
|||
/*
|
|||
* Packet inputs. |
|||
*/ |
|||
PKT_OPEN = PKT__PKT_OPEN, |
|||
PKT_OPEN_ANCHOR = PKT__PKT_OPEN_ANCHOR, |
|||
PKT_OPEN_COMMIT_SIG = PKT__PKT_OPEN_COMMIT_SIG, |
|||
PKT_OPEN_COMPLETE = PKT__PKT_OPEN_COMPLETE, |
|||
|
|||
/* Updating the commit transaction: new HTLC */ |
|||
PKT_UPDATE_ADD_HTLC = PKT__PKT_UPDATE_ADD_HTLC, |
|||
/* Updating the commit transaction: I have your R value! */ |
|||
PKT_UPDATE_FULFILL_HTLC = PKT__PKT_UPDATE_FULFILL_HTLC, |
|||
/* Updating the commit transaction: your HTLC failed upstream */ |
|||
PKT_UPDATE_FAIL_HTLC = PKT__PKT_UPDATE_FAIL_HTLC, |
|||
|
|||
/* Committing updates */ |
|||
PKT_UPDATE_COMMIT = PKT__PKT_UPDATE_COMMIT, |
|||
PKT_UPDATE_REVOCATION = PKT__PKT_UPDATE_REVOCATION, |
|||
|
|||
/* If they want to close. */ |
|||
PKT_CLOSE_SHUTDOWN = PKT__PKT_CLOSE_SHUTDOWN, |
|||
|
|||
/* Something unexpected went wrong. */ |
|||
PKT_ERROR = PKT__PKT_ERROR, |
|||
|
|||
/*
|
|||
* Non-packet inputs. |
|||
*/ |
|||
INPUT_NONE, |
|||
|
|||
/*
|
|||
* Timeouts. |
|||
*/ |
|||
INPUT_CLOSE_COMPLETE_TIMEOUT, |
|||
|
|||
INPUT_MAX |
|||
}; |
|||
#endif /* LIGHTNING_STATE_TYPES_H */ |
@ -1,73 +0,0 @@ |
|||
check: daemon-tests |
|||
|
|||
# We run three different bitcoinds, for different types of tests.
|
|||
# Provides limited paralellism.
|
|||
daemon-test-0-%: |
|||
NO_VALGRIND=$(NO_VALGRIND) VARIANT=0 daemon/test/test-$* |
|||
daemon-test-1-%: |
|||
NO_VALGRIND=$(NO_VALGRIND) VARIANT=1 daemon/test/test-$* |
|||
daemon-test-2-%: |
|||
NO_VALGRIND=$(NO_VALGRIND) VARIANT=2 daemon/test/test-$* |
|||
|
|||
# These don't work in parallel, so chain the deps
|
|||
daemon-test-0-steal: daemon-test-0-unilateral |
|||
daemon-test-0-unilateral: daemon-test-0-funding-timeout |
|||
daemon-test-0-funding-timeout: daemon-test-0-mutual-close-with-htlcs |
|||
daemon-test-0-mutual-close-with-htlcs: daemon-test-0-different-fees |
|||
daemon-test-0-different-fees: daemon-test-0-routing |
|||
daemon-test-0-routing: daemon-test-0-invoice |
|||
daemon-test-0-invoice: daemon-test-0-basic\ manual-commit |
|||
daemon-test-0-basic\ manual-commit: daemon-test-0-basic |
|||
daemon-test-0-basic: daemon-test-setup-0 |
|||
|
|||
daemon-test-2-steal\ --reconnect: daemon-test-2-unilateral\ --reconnect |
|||
daemon-test-2-unilateral\ --reconnect: daemon-test-2-funding-timeout\ --reconnect |
|||
daemon-test-2-funding-timeout\ --reconnect: daemon-test-2-mutual-close-with-htlcs\ --reconnect |
|||
daemon-test-2-mutual-close-with-htlcs\ --reconnect: daemon-test-2-different-fees\ --reconnect |
|||
daemon-test-2-different-fees\ --reconnect: daemon-test-2-routing\ --reconnect |
|||
daemon-test-2-routing\ --reconnect: daemon-test-2-invoice\ --reconnect |
|||
daemon-test-2-invoice\ --reconnect: daemon-test-2-basic\ manual-commit\ --reconnect |
|||
daemon-test-2-basic\ manual-commit\ --reconnect: daemon-test-2-basic\ --reconnect |
|||
daemon-test-2-basic\ --reconnect: daemon-test-setup-2 |
|||
|
|||
daemon-test-1-steal\ --restart: daemon-test-1-unilateral\ --restart |
|||
daemon-test-1-unilateral\ --restart: daemon-test-1-funding-timeout\ --restart |
|||
daemon-test-1-funding-timeout\ --restart: daemon-test-1-mutual-close-with-htlcs\ --restart |
|||
daemon-test-1-mutual-close-with-htlcs\ --restart: daemon-test-1-different-fees\ --restart |
|||
daemon-test-1-different-fees\ --restart: daemon-test-1-routing\ --restart |
|||
daemon-test-1-routing\ --restart: daemon-test-1-invoice\ --restart |
|||
daemon-test-1-invoice\ --restart: daemon-test-1-basic\ manual-commit\ --restart |
|||
daemon-test-1-basic\ manual-commit\ --restart: daemon-test-1-basic\ --restart |
|||
daemon-test-1-basic\ --restart: daemon-test-setup-1 |
|||
|
|||
# We shutdown first in case something is left over.
|
|||
daemon-test-setup-%: daemon-all |
|||
VARIANT=$* daemon/test/scripts/shutdown.sh 2>/dev/null || true |
|||
VARIANT=$* daemon/test/scripts/setup.sh |
|||
|
|||
daemon-test-shutdown-0: daemon-test-0-steal |
|||
VARIANT=0 daemon/test/scripts/shutdown.sh |
|||
daemon-test-shutdown-1: daemon-test-1-steal\ --restart |
|||
VARIANT=1 daemon/test/scripts/shutdown.sh |
|||
daemon-test-shutdown-2: daemon-test-2-steal\ --reconnect |
|||
VARIANT=2 daemon/test/scripts/shutdown.sh |
|||
|
|||
# Forms long dependency chains.
|
|||
daemon-all-test: daemon-test-shutdown-0 daemon-test-shutdown-1 daemon-test-shutdown-2 |
|||
|
|||
# Note that these actually #include everything they need, except ccan/ and bitcoin/.
|
|||
# That allows for unit testing of statics, and special effects.
|
|||
DAEMON_TEST_SRC := $(wildcard daemon/test/run-*.c) |
|||
DAEMON_TEST_OBJS := $(DAEMON_TEST_SRC:.c=.o) |
|||
DAEMON_TEST_PROGRAMS := $(DAEMON_TEST_OBJS:.o=) |
|||
|
|||
update-mocks: $(DAEMON_TEST_SRC:%=update-mocks/%) |
|||
|
|||
$(DAEMON_TEST_PROGRAMS): $(CCAN_OBJS) $(BITCOIN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(CORE_PROTOBUF_OBJS) $(LIBBASE58_OBJS) $(WIRE_OBJS) libsecp256k1.a libsodium.a utils.o |
|||
|
|||
$(DAEMON_TEST_OBJS): $(DAEMON_HEADERS) $(DAEMON_JSMN_HEADERS) $(BITCOIN_HEADERS) $(CORE_HEADERS) $(CORE_TX_HEADERS) $(GEN_HEADERS) $(DAEMON_GEN_HEADERS) $(CCAN_HEADERS) $(WIRE_HEADERS) |
|||
|
|||
daemon-unit-tests: $(DAEMON_TEST_PROGRAMS:%=unittest/%) |
|||
|
|||
daemon-tests: daemon-unit-tests daemon-all-test |
|||
|
@ -1,52 +0,0 @@ |
|||
#include "daemon/channel.c" |
|||
#include "daemon/htlc.c" |
|||
#include "daemon/htlc_state.c" |
|||
#include <assert.h> |
|||
#include <stdio.h> |
|||
|
|||
/* AUTOGENERATED MOCKS START */ |
|||
/* Generated stub for db_new_htlc */ |
|||
void db_new_htlc(struct peer *peer UNNEEDED, const struct htlc *htlc UNNEEDED) |
|||
{ fprintf(stderr, "db_new_htlc called!\n"); abort(); } |
|||
/* Generated stub for db_update_htlc_state */ |
|||
void db_update_htlc_state(struct peer *peer UNNEEDED, const struct htlc *htlc UNNEEDED, |
|||
enum htlc_state oldstate UNNEEDED) |
|||
{ fprintf(stderr, "db_update_htlc_state called!\n"); abort(); } |
|||
/* Generated stub for log_ */ |
|||
void log_(struct log *log UNNEEDED, enum log_level level UNNEEDED, const char *fmt UNNEEDED, ...) |
|||
|
|||
{ fprintf(stderr, "log_ called!\n"); abort(); } |
|||
/* Generated stub for peer_debug */ |
|||
void peer_debug(struct peer *peer UNNEEDED, const char *fmt UNNEEDED, ...) |
|||
|
|||
{ fprintf(stderr, "peer_debug called!\n"); abort(); } |
|||
/* Could not find declaration for tal_hexstr */ |
|||
/* Could not find declaration for type_to_string_ */ |
|||
/* AUTOGENERATED MOCKS END */ |
|||
|
|||
static void test_maxfee(size_t htlcs, u64 funds) |
|||
{ |
|||
struct channel_state cstate; |
|||
uint64_t maxrate; |
|||
|
|||
cstate.side[LOCAL].pay_msat = funds; |
|||
cstate.side[LOCAL].fee_msat = 0; |
|||
cstate.num_nondust = htlcs; |
|||
|
|||
maxrate = approx_max_feerate(&cstate, LOCAL); |
|||
assert(fee_by_feerate(tx_bytes(htlcs), maxrate) <= funds); |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
size_t htlcs, i; |
|||
for (htlcs = 0; htlcs < 600; htlcs++) { |
|||
for (i = 0; i < 32; i++) { |
|||
test_maxfee(htlcs, i); |
|||
test_maxfee(htlcs, 1ULL << i); |
|||
test_maxfee(htlcs, (1ULL << i) - 1); |
|||
test_maxfee(htlcs, (1ULL << i) + 1); |
|||
} |
|||
} |
|||
return 0; |
|||
} |
@ -1,21 +0,0 @@ |
|||
#! /bin/sh |
|||
# Generate a block. |
|||
|
|||
set -e |
|||
|
|||
. `dirname $0`/vars.sh |
|||
INIT=$1 |
|||
|
|||
# Initially we need 100 blocks so coinbase matures, giving us funds. |
|||
if [ -n "$INIT" ]; then |
|||
# To activate segwit via BIP9, we need at least 432 blocks! |
|||
$CLI generate 432 > /dev/null |
|||
if $CLI getblockchaininfo | tr -s '\012\011 ' ' ' | grep -q '"segwit": { "status": "active",'; then : |
|||
else |
|||
echo "Segwit not activated after 432 blocks?" >&2 |
|||
$CLI getblockchaininfo >&2 |
|||
exit 1 |
|||
fi |
|||
else |
|||
$CLI generate 1 > /dev/null |
|||
fi |
@ -1,29 +0,0 @@ |
|||
#! /bin/sh |
|||
# Query bitcoind to get (first) unspent output to spend. |
|||
|
|||
### |
|||
# Nobody should *EVER* write code like this. EVER!! |
|||
### |
|||
set -e |
|||
|
|||
. `dirname $0`/vars.sh |
|||
|
|||
NUM=1 |
|||
if [ $# = 1 ]; then |
|||
NUM=$1 |
|||
shift |
|||
fi |
|||
|
|||
if [ $# -gt 0 ]; then |
|||
echo "Usage: getinput.sh [INPUT-INDEX]" |
|||
exit 1 |
|||
fi |
|||
|
|||
TXID=`$CLI listunspent | sed -n 's/^ *"txid" *: *"\([0-9a-f]*\)",$/\1/p' | tail -n +$NUM | head -n1` |
|||
OUTNUM=`$CLI listunspent | sed -n 's/^ *"vout" *: *\([0-9]*\),$/\1/p' | tail -n +$NUM | head -n1` |
|||
AMOUNT=`$CLI listunspent | sed -n 's/^ *"amount" *: *\([0-9.]*\),$/\1/p' | tail -n +$NUM | head -n1 | tr -d . | sed 's/^0*//'` |
|||
SCRIPT=`$CLI listunspent | sed -n 's/^ *"scriptPubKey" *: *"\([0-9a-f]*\)",$/\1/p' | tail -n +$NUM | head -n1` |
|||
ADDR=`$CLI listunspent | sed -n 's/^ *"address" *: *"\([0-9a-zA-Z]*\)",$/\1/p' | tail -n +$NUM | head -n1` |
|||
PRIVKEY=`$CLI dumpprivkey $ADDR` |
|||
|
|||
echo $TXID/$OUTNUM/$AMOUNT/$SCRIPT/$PRIVKEY |
@ -1,467 +0,0 @@ |
|||
#! /bin/sh |
|||
# Sourced by test script. |
|||
|
|||
# Takes the number of lightningd's we're going to start (2 or 3), then args |
|||
parse_cmdline() |
|||
{ |
|||
NUM_LIGHTNINGD=$1 |
|||
shift |
|||
|
|||
DIR1=/tmp/lightning.$$.1 |
|||
DIR2=/tmp/lightning.$$.2 |
|||
REDIR1="$DIR1/output" |
|||
REDIR2="$DIR2/output" |
|||
REDIRERR1="$DIR1/errors" |
|||
REDIRERR2="$DIR2/errors" |
|||
|
|||
if [ $NUM_LIGHTNINGD = 3 ]; then |
|||
DIR3=/tmp/lightning.$$.3 |
|||
REDIR3="$DIR3/output" |
|||
REDIRERR3="$DIR3/errors" |
|||
fi |
|||
|
|||
while [ $# != 0 ]; do |
|||
case x"$1" in |
|||
x"--valgrind-vgdb") |
|||
[ -n "$NO_VALGRIND" ] || PREFIX="$PREFIX --vgdb-error=1" |
|||
REDIR1="/dev/tty" |
|||
REDIRERR1="/dev/tty" |
|||
REDIR2="/dev/tty" |
|||
REDIRERR2="/dev/tty" |
|||
if [ $NUM_LIGHTNINGD = 3 ]; then |
|||
REDIR3="/dev/tty" |
|||
REDIRERR3="/dev/tty" |
|||
fi |
|||
;; |
|||
x"--gdb1") |
|||
GDB1=1 |
|||
;; |
|||
x"--gdb2") |
|||
GDB2=1 |
|||
;; |
|||
x"--gdb3") |
|||
GDB3=1 |
|||
if [ $NUM_LIGHTNINGD -lt 3 ]; then |
|||
echo "$1" invalid with only 2 lightning daemons >&2 |
|||
exit 1 |
|||
fi |
|||
;; |
|||
x"--gdb1="*) |
|||
DAEMON1_EXTRA=--dev-debugger=${1#--gdb1=} |
|||
;; |
|||
x"--gdb2="*) |
|||
DAEMON2_EXTRA=--dev-debugger=${1#--gdb2=} |
|||
;; |
|||
x"--reconnect") |
|||
RECONNECT=reconnect |
|||
;; |
|||
x"--restart") |
|||
RECONNECT=restart |
|||
;; |
|||
x"--crash") |
|||
CRASH_ON_FAIL=1 |
|||
;; |
|||
x"--verbose") |
|||
VERBOSE=1 |
|||
;; |
|||
*) |
|||
echo Unknown arg "$1" >&2 |
|||
exit 1 |
|||
esac |
|||
shift |
|||
done |
|||
|
|||
if [ -n "$VERBOSE" ]; then |
|||
FGREP="fgrep" |
|||
else |
|||
FGREP="fgrep -q" |
|||
# Suppress command output. |
|||
exec >/dev/null |
|||
fi |
|||
} |
|||
|
|||
failed() |
|||
{ |
|||
if [ -n "$CRASH_ON_FAIL" ]; then |
|||
$LCLI1 dev-crash 2>/dev/null || true |
|||
$LCLI2 dev-crash 2>/dev/null || true |
|||
echo -n Crash results in $DIR1 and $DIR2 >&2 |
|||
if [ -n "$LCLI3" ]; then |
|||
$LCLI3 dev-crash 2>/dev/null || true |
|||
echo and $DIR3 >&2 |
|||
else |
|||
echo >&2 |
|||
fi |
|||
fi |
|||
cat $DIR1/errors $DIR2/errors $DIR3/errors 2>/dev/null || true |
|||
exit 1 |
|||
} |
|||
|
|||
setup_lightning() |
|||
{ |
|||
NUM_LIGHTNINGD=$1 |
|||
|
|||
LCLI1="../lightning-cli --lightning-dir=$DIR1" |
|||
LCLI2="../lightning-cli --lightning-dir=$DIR2" |
|||
[ $NUM_LIGHTNINGD = 2 ] || LCLI3="../lightning-cli --lightning-dir=$DIR3" |
|||
|
|||
trap failed EXIT |
|||
mkdir $DIR1 $DIR2 |
|||
[ $NUM_LIGHTNINGD = 2 ] || mkdir $DIR3 |
|||
|
|||
cat > $DIR1/config <<EOF |
|||
disable-irc |
|||
log-level=debug |
|||
bitcoind-poll=5s |
|||
deadline-blocks=5 |
|||
min-htlc-expiry=6 |
|||
bitcoin-datadir=$DATADIR |
|||
locktime-blocks=6 |
|||
EOF |
|||
|
|||
cp $DIR1/config $DIR2/config |
|||
[ $NUM_LIGHTNINGD = 2 ] || cp $DIR1/config $DIR3/config |
|||
|
|||
# Find a free TCP port. |
|||
echo port=`findport 4000 $VARIANT` >> $DIR2/config |
|||
[ $NUM_LIGHTNINGD = 2 ] || echo port=`findport 4010 $VARIANT` >> $DIR3/config |
|||
} |
|||
|
|||
# Use DIR REDIR REDIRERR GDBFLAG BINARY EXTRAARGS |
|||
start_one_lightningd() |
|||
{ |
|||
# Need absolute path for re-exec testing. |
|||
local CMD |
|||
CMD="$(readlink -f `pwd`/../../$5) --lightning-dir=$1" |
|||
if [ -n "$4" ]; then |
|||
echo Press return once you run: gdb --args $CMD $6 >&2 |
|||
|
|||
read REPLY |
|||
else |
|||
CMD="$PREFIX $CMD" |
|||
$CMD $6 > $2 2> $3 & |
|||
fi |
|||
echo $CMD $6 |
|||
} |
|||
|
|||
start_lightningd() |
|||
{ |
|||
NUM_LIGHTNINGD=$1 |
|||
BINARY=${2:-daemon/lightningd} |
|||
|
|||
# If bitcoind not already running, start it. |
|||
if ! $CLI getinfo >/dev/null 2>&1; then |
|||
echo Starting bitcoind... |
|||
scripts/setup.sh |
|||
SHUTDOWN_BITCOIN=scripts/shutdown.sh |
|||
else |
|||
SHUTDOWN_BITCOIN=/bin/true |
|||
fi |
|||
|
|||
LIGHTNINGD1=`start_one_lightningd $DIR1 $REDIR1 $REDIRERR1 "$GDB1" $BINARY $DAEMON1_EXTRA` |
|||
LIGHTNINGD2=`start_one_lightningd $DIR2 $REDIR2 $REDIRERR2 "$GDB2" $BINARY $DAEMON2_EXTRA` |
|||
[ $NUM_LIGHTNINGD = 2 ] || LIGHTNINGD3=`start_one_lightningd $DIR3 $REDIR3 $REDIRERR3 "$GDB3" $BINARY` |
|||
|
|||
if ! check "$LCLI1 getlog 2>/dev/null | $FGREP Hello"; then |
|||
echo Failed to start daemon 1 >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
if ! check "$LCLI2 getlog 2>/dev/null | $FGREP Hello"; then |
|||
echo Failed to start daemon 2 >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
if [ $NUM_LIGHTNINGD = 3 ] && ! check "$LCLI3 getlog 2>/dev/null | $FGREP Hello"; then |
|||
echo Failed to start daemon 3 >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
# Version should match binary version |
|||
GETINFO_VERSION=`$LCLI1 getinfo | sed -n 's/.*"version" : "\([^"]*\)".*/\1/p'` |
|||
LCLI_VERSION=$($LCLI1 --version | head -n1) |
|||
LDAEMON_VERSION=$($LIGHTNINGD1 --version | head -n1) |
|||
if [ $GETINFO_VERSION != $LCLI_VERSION -o $GETINFO_VERSION != $LDAEMON_VERSION ]; then |
|||
echo Wrong versions: getinfo gave $GETINFO_VERSION, cli gave $LCLI_VERSION, daemon gave $LDAEMON_VERSION >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
ID1=`get_info_field "$LCLI1" id` |
|||
ID2=`get_info_field "$LCLI2" id` |
|||
[ $NUM_LIGHTNINGD = 2 ] || ID3=`get_info_field "$LCLI3" id` |
|||
|
|||
PORT2=`get_info_field "$LCLI2" port` |
|||
[ $NUM_LIGHTNINGD = 2 ] || PORT3=`get_info_field "$LCLI3" port` |
|||
} |
|||
|
|||
fund_lightningd() |
|||
{ |
|||
# Make a payment into a P2SH for anchor. |
|||
P2SHADDR=`$LCLI1 newaddr | sed -n 's/{ "address" : "\(.*\)" }/\1/p'` |
|||
FUND_INPUT_TXID=`$CLI sendtoaddress $P2SHADDR 0.01` |
|||
FUND_INPUT_TX=`$CLI getrawtransaction $FUND_INPUT_TXID` |
|||
|
|||
# Mine it so check_tx_spend doesn't see it (breaks some tests). |
|||
$CLI generate 1 |
|||
} |
|||
|
|||
lcli1() |
|||
{ |
|||
if [ -n "$VERBOSE" ]; then |
|||
echo $LCLI1 "$@" >&2 |
|||
fi |
|||
# Make sure we output if it fails; we need to capture it otherwise. |
|||
if ! OUT=`$LCLI1 "$@"`; then |
|||
echo "$OUT" |
|||
return 1 |
|||
fi |
|||
echo "$OUT" |
|||
if [ -n "$DO_RECONNECT" ]; then |
|||
case "$1" in |
|||
# Don't restart on every get* command. |
|||
get*) |
|||
;; |
|||
dev-disconnect) |
|||
;; |
|||
stop) |
|||
;; |
|||
*) |
|||
case "$RECONNECT" in |
|||
reconnect) |
|||
[ -z "$VERBOSE" ] || echo RECONNECTING >&2 |
|||
$LCLI1 dev-reconnect $ID2 >/dev/null |
|||
;; |
|||
restart) |
|||
[ -z "$VERBOSE" ] || echo RESTARTING >&2 |
|||
$LCLI1 -- dev-restart $LIGHTNINGD1 >/dev/null 2>&1 || true |
|||
if ! check "$LCLI1 getlog 2>/dev/null | fgrep -q Hello"; then |
|||
echo "dev-restart failed!">&2 |
|||
exit 1 |
|||
fi |
|||
;; |
|||
esac |
|||
# Wait for reconnect (if peer2 still there) |
|||
if [ -z "$NO_PEER2" ] && ! check "$LCLI1 getpeers | tr -s '\012\011\" ' ' ' | fgrep -q 'connected : true'"; then |
|||
echo "Failed to reconnect!">&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
if [ "$1" = "dev-newhtlc" ]; then |
|||
# It might have gotten committed, or might be forgotten. |
|||
ID=`echo "$OUT" | extract_id` |
|||
if ! htlc_exists "$LCLI1" $2 $ID; then |
|||
if [ -z "$VERBOSE" ]; then |
|||
$LCLI1 "$@" >/dev/null 2>&1 || true |
|||
else |
|||
echo "Rerunning $LCLI1 $@" >&2 |
|||
$LCLI1 "$@" >&2 || true |
|||
fi |
|||
fi |
|||
# Make sure it's confirmed before we run next command, |
|||
# in case *that* restarts (unless manual commit) |
|||
[ -n "$MANUALCOMMIT" ] || check ! htlc_is_state \'"$LCLI1"\' $2 $ID SENT_ADD_HTLC |
|||
# Removals may also be forgotten. |
|||
elif [ "$1" = "fulfillhtlc" -o "$1" = "failhtlc" ]; then |
|||
ID="$3" |
|||
if htlc_is_state "$LCLI1" $2 $ID RCVD_ADD_ACK_REVOCATION; then |
|||
if [ -z "$VERBOSE" ]; then |
|||
$LCLI1 "$@" >/dev/null 2>&1 || true |
|||
else |
|||
echo "Rerunning $LCLI1 $@" >&2 |
|||
$LCLI1 "$@" >&2 || true |
|||
fi |
|||
# Make sure it's confirmed before we run next command, |
|||
# in case *that* restarts. |
|||
[ -n "$MANUALCOMMIT" ] || check ! htlc_is_state \'"$LCLI1"\' $2 $ID SENT_REMOVE_HTLC |
|||
fi |
|||
fi |
|||
;; |
|||
esac |
|||
fi |
|||
} |
|||
|
|||
lcli2() |
|||
{ |
|||
if [ -n "$VERBOSE" ]; then |
|||
echo $LCLI2 "$@" >&2 |
|||
fi |
|||
$LCLI2 "$@" |
|||
} |
|||
|
|||
lcli3() |
|||
{ |
|||
if [ -n "$VERBOSE" ]; then |
|||
echo $LCLI3 "$@" >&2 |
|||
fi |
|||
$LCLI3 "$@" |
|||
} |
|||
|
|||
all_ok() |
|||
{ |
|||
# Look for valgrind errors. |
|||
if grep ^== $DIR1/errors; then exit 1; fi |
|||
if grep ^== $DIR2/errors; then exit 1; fi |
|||
[ $NUM_LIGHTNINGD = 2 ] || if grep ^== $DIR3/errors; then exit 1; fi |
|||
|
|||
# Look for unknown logging types. |
|||
if grep "UNKNOWN TYPE" $DIR1/output >&2; then exit 1; fi |
|||
if grep "UNKNOWN TYPE" $DIR2/output >&2; then exit 1; fi |
|||
[ $NUM_LIGHTNINGD = 2 ] || if grep "UNKNOWN TYPE" $DIR3/output >&2; then exit 1; fi |
|||
$SHUTDOWN_BITCOIN |
|||
|
|||
trap "rm -rf $DIR1 $DIR2 $DIR3" EXIT |
|||
exit 0 |
|||
} |
|||
|
|||
# If result is in quotes, those are stripped. Spaces in quotes not handled |
|||
get_field() |
|||
{ |
|||
tr -s '\012\011" ' ' ' | sed 's/.* '$1' : \([^, }]*\).*/\1/' |
|||
} |
|||
|
|||
# If result is in quotes, those are stripped. Spaces in quotes not handled |
|||
get_info_field() |
|||
{ |
|||
$1 getinfo | tr -s '\012\011" ' ' ' | sed 's/.* '$2' : \([^, }]*\).*/\1/' |
|||
} |
|||
|
|||
# Peer $1 -> $2's htlc $3 is in state $4 |
|||
htlc_is_state() |
|||
{ |
|||
if [ $# != 4 ]; then echo "htlc_is_state got $# ARGS: $@" >&2; exit 1; fi |
|||
$1 gethtlcs $2 true | tr -s '\012\011\" ' ' ' | $FGREP "id : $3, state : $4 ," >&2 |
|||
} |
|||
|
|||
# Peer $1 -> $2's htlc $3 exists |
|||
htlc_exists() |
|||
{ |
|||
$1 gethtlcs $2 true | tr -s '\012\011\" ' ' ' | $FGREP "id : $3," >&2 |
|||
} |
|||
|
|||
blockheight() |
|||
{ |
|||
$CLI getblockcount |
|||
} |
|||
|
|||
# Usage: <cmd to test>... |
|||
check() |
|||
{ |
|||
local i=0 |
|||
while ! eval "$@"; do |
|||
sleep 1 |
|||
i=$(($i + 1)) |
|||
if [ $i = 60 ]; then |
|||
return 1 |
|||
fi |
|||
done |
|||
} |
|||
|
|||
check_balance_single() |
|||
{ |
|||
lcli="$1" |
|||
us_pay=$2 |
|||
us_fee=$3 |
|||
them_pay=$4 |
|||
them_fee=$5 |
|||
|
|||
if check "$lcli getpeers | tr -s '\012\011\" ' ' ' | $FGREP \"our_amount : $us_pay, our_fee : $us_fee, their_amount : $them_pay, their_fee : $them_fee,\""; then :; else |
|||
echo Cannot find $lcli output: "our_amount : $us_pay, our_fee : $us_fee, their_amount : $them_pay, their_fee : $them_fee," >&2 |
|||
$lcli getpeers | tr -s '\012\011" ' ' ' >&2 |
|||
return 1 |
|||
fi |
|||
} |
|||
|
|||
check_status_single() |
|||
{ |
|||
lcli="$1" |
|||
us_pay=$2 |
|||
us_fee=$3 |
|||
us_htlcs="$4" |
|||
them_pay=$5 |
|||
them_fee=$6 |
|||
them_htlcs="$7" |
|||
|
|||
check_balance_single "$lcli" $us_pay $us_fee $them_pay $them_fee |
|||
|
|||
if check "$lcli getpeers | tr -s '\012\011\" ' ' ' | $FGREP \"our_htlcs : [ $us_htlcs], their_htlcs : [ $them_htlcs]\""; then :; else |
|||
echo Cannot find $lcli output: "our_htlcs : [ $us_htlcs], their_htlcs : [ $them_htlcs]" >&2 |
|||
$lcli getpeers | tr -s '\012\011" ' ' ' >&2 |
|||
return 1 |
|||
fi |
|||
} |
|||
|
|||
# SEND_ -> RCVD_ and RCVD_ -> SEND_ |
|||
swap_status() |
|||
{ |
|||
echo "$@" | sed -e 's/state : RCVD_/@@/g' -e 's/state : SENT_/state : RCVD_/g' -e 's/@@/state : SENT_/g' |
|||
} |
|||
|
|||
check_status() |
|||
{ |
|||
us_pay=$1 |
|||
us_fee=$2 |
|||
us_htlcs="$3" |
|||
them_pay=$4 |
|||
them_fee=$5 |
|||
them_htlcs="$6" |
|||
|
|||
check_status_single lcli1 "$us_pay" "$us_fee" "$us_htlcs" "$them_pay" "$them_fee" "$them_htlcs" |
|||
check_status_single lcli2 "$them_pay" "$them_fee" "`swap_status \"$them_htlcs\"`" "$us_pay" "$us_fee" "`swap_status \"$us_htlcs\"`" |
|||
} |
|||
|
|||
check_tx_spend() |
|||
{ |
|||
local FAIL |
|||
FAIL=0 |
|||
if [ $# = 1 ]; then |
|||
check "$CLI getrawmempool | $FGREP $1" || FAIL=1 |
|||
else |
|||
check "$CLI getrawmempool | $FGREP '\"'" || FAIL=1 |
|||
fi |
|||
if [ $FAIL = 1 ]; then |
|||
echo "No tx $1 in mempool:" >&2 |
|||
$CLI getrawmempool >&2 |
|||
exit 1 |
|||
fi |
|||
} |
|||
|
|||
check_peerstate() |
|||
{ |
|||
if check "$1 getpeers | $FGREP -w $2"; then : |
|||
else |
|||
echo "$1" not in state "$2": >&2 |
|||
$1 getpeers >&2 |
|||
exit 1 |
|||
fi |
|||
} |
|||
|
|||
check_peerconnected() |
|||
{ |
|||
if check "$1 getpeers | tr -s '\012\011\" ' ' ' | $FGREP -w 'connected : '$2"; then : |
|||
else |
|||
echo "$1" not connected "$2": >&2 |
|||
$1 getpeers >&2 |
|||
exit 1 |
|||
fi |
|||
} |
|||
|
|||
check_no_peers() |
|||
{ |
|||
if check "$1 getpeers | tr -s '\012\011\" ' ' ' | $FGREP 'peers : [ ]'"; then : |
|||
else |
|||
echo "$1" still has peers: >&2 |
|||
$1 getpeers >&2 |
|||
exit 1 |
|||
fi |
|||
} |
|||
|
|||
extract_id() |
|||
{ |
|||
XID=`tr -s '\012\011\" ' ' ' | sed -n 's/{ id : \([0-9]*\) }/\1/p'` |
|||
case "$XID" in |
|||
[0-9]*) |
|||
echo $XID;; |
|||
*) |
|||
return 1;; |
|||
esac |
|||
} |
@ -1,47 +0,0 @@ |
|||
#! /bin/sh -e |
|||
|
|||
. `dirname $0`/vars.sh |
|||
|
|||
VERSION=$(`dirname $0`/../../lightning-cli --version | head -n1) |
|||
[ $VERSION = `git describe --always --dirty` ] || (echo Wrong version $VERSION >&2; exit 1) |
|||
|
|||
# Start clean |
|||
rm -rf $DATADIR |
|||
mkdir $DATADIR |
|||
|
|||
# Find a free port (racy, but hey) |
|||
PORT=`findport 18332 $VARIANT` |
|||
RPCPORT=`findport $(($PORT + 1))` |
|||
|
|||
# Create appropriate config file so cmdline matches. |
|||
cat > $DATADIR/bitcoin.conf <<EOF |
|||
regtest=1 |
|||
testnet=0 |
|||
rpcport=$RPCPORT |
|||
port=$PORT |
|||
EOF |
|||
|
|||
$DAEMON & |
|||
i=0 |
|||
while ! $CLI getinfo >/dev/null 2>&1; do |
|||
if [ $i -gt 60 ]; then |
|||
echo $DAEMON start failed? >&1 |
|||
exit 1 |
|||
fi |
|||
sleep 1 |
|||
i=$(($i + 1)) |
|||
done |
|||
|
|||
# Make sure they have segwit support! |
|||
if $CLI getblockchaininfo | grep -q '"segwit"'; then : |
|||
else |
|||
echo This bitcoind does not have segwit support. >&2 |
|||
echo Please install a recent one >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
`dirname $0`/generate-block.sh init |
|||
|
|||
A1=$($CLI getnewaddress) |
|||
TX=`$CLI sendmany "" "{ \"$A1\":0.01 }"` |
|||
`dirname $0`/generate-block.sh |
@ -1,11 +0,0 @@ |
|||
#! /bin/sh -e |
|||
|
|||
. `dirname $0`/vars.sh |
|||
|
|||
[ ! -f $DATADIR/regtest/bitcoind.pid ] || BITCOIN_PID=`cat $DATADIR/regtest/bitcoind.pid` |
|||
|
|||
$CLI stop |
|||
sleep 1 # Make sure socket is closed. |
|||
|
|||
# Now make sure it's dead. |
|||
if [ -n "$BITCOIN_PID" ]; then kill -9 $BITCOIN_PID 2>/dev/null || true; fi |
@ -1,40 +0,0 @@ |
|||
# Sourced by other scripts |
|||
|
|||
# Bash variables for in-depth debugging. |
|||
#set -vx |
|||
#export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' |
|||
|
|||
# Suppress sync if we can, for speedup. |
|||
if which eatmydata >/dev/null; then EATMYDATA=eatmydata; fi |
|||
|
|||
DATADIR=/tmp/bitcoin-lightning$VARIANT |
|||
CLI="bitcoin-cli -datadir=$DATADIR" |
|||
REGTESTDIR=regtest |
|||
DAEMON="$EATMYDATA bitcoind -datadir=$DATADIR" |
|||
|
|||
PREFIX=$EATMYDATA |
|||
|
|||
# Always use valgrind if available (unless NO_VALGRIND=1 set) |
|||
if which valgrind >/dev/null; then :; else NO_VALGRIND=1; fi |
|||
[ -n "$NO_VALGRIND" ] || PREFIX="$EATMYDATA valgrind -q $VG_TRACE_CHILDREN --trace-children-skip=*bitcoin-cli* --error-exitcode=7" |
|||
|
|||
# We inject 0.01 bitcoin, but then fees (estimatefee fails and we use a |
|||
# fee rate as per the default). |
|||
AMOUNT=991880000 |
|||
|
|||
# Default fee rate per kb. |
|||
FEE_RATE=200000 |
|||
|
|||
# Fee in millisatoshi if we have no htlcs (note rounding to make it even) |
|||
NO_HTLCS_FEE=$((338 * $FEE_RATE / 2000 * 2000)) |
|||
ONE_HTLCS_FEE=$(( (338 + 32) * $FEE_RATE / 2000 * 2000)) |
|||
EXTRA_FEE=$(($ONE_HTLCS_FEE - $NO_HTLCS_FEE)) |
|||
|
|||
findport() |
|||
{ |
|||
PORT=$1 |
|||
# Give two ports per variant. |
|||
if [ x"$2" != x ]; then PORT=$(($PORT + $2 * 2)); fi |
|||
while netstat -ntl | grep -q ":$PORT "; do PORT=$(($PORT + 1)); done |
|||
echo $PORT |
|||
} |
@ -1,359 +0,0 @@ |
|||
#! /bin/sh -e |
|||
|
|||
# Wherever we are, we want to be in daemon/test dir. |
|||
cd `git rev-parse --show-toplevel`/daemon/test |
|||
|
|||
. scripts/vars.sh |
|||
. scripts/helpers.sh |
|||
|
|||
if [ x"$1" = x"manual-commit" ]; then |
|||
MANUALCOMMIT=1 |
|||
shift |
|||
fi |
|||
|
|||
parse_cmdline 2 "$@" |
|||
setup_lightning 2 |
|||
|
|||
if [ -n "$MANUALCOMMIT" ]; then |
|||
# Aka. never. |
|||
echo 'commit-time=1h' >> $DIR1/config |
|||
echo 'commit-time=1h' >> $DIR2/config |
|||
fi |
|||
|
|||
start_lightningd 2 |
|||
fund_lightningd |
|||
|
|||
# Check IDs match logs |
|||
[ `$LCLI1 getlog | sed -n 's/.*"ID: \([0-9a-f]*\)".*/\1/p'` = $ID1 ] |
|||
[ `$LCLI2 getlog | sed -n 's/.*"ID: \([0-9a-f]*\)".*/\1/p'` = $ID2 ] |
|||
|
|||
lcli1 connect localhost $PORT2 $FUND_INPUT_TX & |
|||
|
|||
# Expect them to be waiting for anchor, and ack from other side. |
|||
check_peerstate lcli1 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE |
|||
check_peerstate lcli2 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE |
|||
|
|||
# Enable reconnect from here. |
|||
DO_RECONNECT=$RECONNECT |
|||
|
|||
# Now make it pass anchor (should be in mempool: one block to bury it) |
|||
check_tx_spend |
|||
$CLI generate 1 |
|||
|
|||
check_peerstate lcli1 STATE_NORMAL |
|||
check_peerstate lcli2 STATE_NORMAL |
|||
|
|||
# We turn off routing failure for the moment. |
|||
lcli1 dev-routefail false |
|||
lcli2 dev-routefail false |
|||
|
|||
A_AMOUNT=$(($AMOUNT - $NO_HTLCS_FEE)) |
|||
A_FEE=$NO_HTLCS_FEE |
|||
B_AMOUNT=0 |
|||
B_FEE=0 |
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
# This is 10,000 satoshi, so not dust! |
|||
HTLC_AMOUNT=10000000 |
|||
|
|||
EXPIRY=$(( $(blockheight) + 10)) |
|||
SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd |
|||
RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'` |
|||
|
|||
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
|
|||
if [ -n "$MANUALCOMMIT" ]; then |
|||
# They should register a staged htlc. |
|||
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_HTLC } " $B_AMOUNT $B_FEE "" |
|||
|
|||
# Now commit it. |
|||
lcli1 dev-commit $ID2 |
|||
|
|||
# Node 1 hasn't got it committed, but node2 should have told it to stage. |
|||
check_status_single lcli1 $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_REVOCATION } " $B_AMOUNT $B_FEE "" |
|||
|
|||
# Check channel status |
|||
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) |
|||
A_FEE=$(($A_FEE + $EXTRA_FEE)) |
|||
|
|||
# Node 2 has it committed. |
|||
check_status_single lcli2 $B_AMOUNT $B_FEE "" $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_REVOCATION } " |
|||
|
|||
# There should be no "both committed" here yet |
|||
if lcli1 getlog debug | $FGREP "Both committed"; then |
|||
echo "Node1 thinks they are both committed"; |
|||
exit 1 |
|||
fi |
|||
if lcli2 getlog debug | $FGREP "Both committed"; then |
|||
echo "Node2 thinks they are both committed"; |
|||
exit 1 |
|||
fi |
|||
|
|||
# Now node2 gives commitment to node1. |
|||
lcli2 dev-commit $ID1 |
|||
|
|||
# After revocation, they should know they're both committed. |
|||
check lcli1 "getlog debug | $FGREP 'Both committed to ADD of our HTLC'" |
|||
check lcli2 "getlog debug | $FGREP 'Both committed to ADD of their HTLC'" |
|||
else |
|||
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) |
|||
A_FEE=$(($A_FEE + $EXTRA_FEE)) |
|||
fi |
|||
|
|||
# Both should have committed tx. |
|||
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE "" |
|||
|
|||
lcli2 dev-fulfillhtlc $ID1 $HTLCID $SECRET |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
|
|||
# Without manual commit, this check is racy. |
|||
if [ -n "$MANUALCOMMIT" ]; then |
|||
if lcli1 getlog debug | $FGREP 'Both committed to FULFILL'; then |
|||
echo "Node1 thinks they are both committed"; |
|||
exit 1 |
|||
fi |
|||
if lcli2 getlog debug | $FGREP 'Both committed to FULFILL'; then |
|||
echo "Node2 thinks they are both committed"; |
|||
exit 1 |
|||
fi |
|||
fi |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
|
|||
# If we're very slow, manually committed above, and we're restarting, |
|||
# we may restart *after* this and thus not see it in the log. |
|||
[ "$RECONNECT$MANUALCOMMIT" = restart1 ] || check lcli1 "getlog debug | $FGREP 'Both committed to FULFILL of our HTLC'" |
|||
check lcli2 "getlog debug | $FGREP 'Both committed to FULFILL of their HTLC'" |
|||
|
|||
# We've transferred the HTLC amount to 2, who now has to pay fees, |
|||
# so no net change for A who saves on fees. |
|||
B_FEE=$HTLC_AMOUNT |
|||
# With no HTLCs, extra fee no longer required. |
|||
A_FEE=$(($A_FEE - $EXTRA_FEE - $B_FEE)) |
|||
A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT)) |
|||
|
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
# A new one, at 10x the amount. |
|||
HTLC_AMOUNT=100000000 |
|||
|
|||
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
|
|||
# Check channel status |
|||
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) |
|||
A_FEE=$(($A_FEE + $EXTRA_FEE)) |
|||
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE "" |
|||
|
|||
lcli2 dev-failhtlc $ID1 $HTLCID 695 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
|
|||
# Back to how we were before. |
|||
A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT)) |
|||
A_FEE=$(($A_FEE - $EXTRA_FEE)) |
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
# Same again, but this time it expires. |
|||
HTLC_AMOUNT=10000001 |
|||
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
|
|||
# Check channel status |
|||
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) |
|||
A_FEE=$(($A_FEE + $EXTRA_FEE)) |
|||
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE "" |
|||
|
|||
# Make sure node1 accepts the expiry packet. |
|||
while [ $(blockheight) != $EXPIRY ]; do |
|||
$CLI generate 1 |
|||
done |
|||
|
|||
# This should make node2 send it. |
|||
$CLI generate 1 |
|||
|
|||
if [ -n "$MANUALCOMMIT" ]; then |
|||
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_REMOVE_HTLC } " $B_AMOUNT $B_FEE "" |
|||
|
|||
lcli2 dev-commit $ID1 |
|||
lcli1 dev-commit $ID2 |
|||
fi |
|||
|
|||
# Back to how we were before. |
|||
A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT)) |
|||
A_FEE=$(($A_FEE - $EXTRA_FEE)) |
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
# First, give more money to node2, so it can offer HTLCs. |
|||
EXPIRY=$(( $(blockheight) + 10)) |
|||
HTLC_AMOUNT=100000000 |
|||
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
|
|||
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE "" |
|||
|
|||
lcli2 dev-fulfillhtlc $ID1 $HTLCID $SECRET |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
|
|||
# Both now pay equal fees. |
|||
A_FEE=$(($NO_HTLCS_FEE / 2)) |
|||
B_FEE=$(($NO_HTLCS_FEE / 2)) |
|||
# We transferred 10000000 before, and $HTLC_AMOUNT now. |
|||
A_AMOUNT=$(($AMOUNT - 10000000 - $HTLC_AMOUNT - $A_FEE)) |
|||
B_AMOUNT=$((10000000 + $HTLC_AMOUNT - $B_FEE)) |
|||
|
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
# Two failures crossover |
|||
SECRET2=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfe |
|||
RHASH2=`lcli1 dev-rhash $SECRET2 | sed 's/.*"\([0-9a-f]*\)".*/\1/'` |
|||
|
|||
# This means B will *just* afford it (but can't cover increased fees) |
|||
HTLC_AMOUNT=$(($B_AMOUNT - $EXTRA_FEE / 2)) |
|||
HTLCID=`lcli2 dev-newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
# Make sure that's committed, in case lcli1 restarts. |
|||
lcli2 dev-commit $ID1 >/dev/null || true |
|||
|
|||
HTLCID2=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH2 | extract_id` |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
|
|||
# A covers the extra part of the fee. |
|||
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE - $EXTRA_FEE / 2)) $(($A_FEE + $EXTRA_FEE + $EXTRA_FEE / 2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : SENT_ADD_ACK_REVOCATION } " 0 $(($B_FEE + $EXTRA_FEE / 2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION } " |
|||
|
|||
# Fail both, to reset. |
|||
lcli1 dev-failhtlc $ID2 $HTLCID 830 |
|||
lcli2 dev-failhtlc $ID1 $HTLCID2 829 |
|||
|
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
|
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
# Now, two HTLCs at once, one from each direction. |
|||
# Both sides can afford this. |
|||
HTLC_AMOUNT=1000000 |
|||
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
HTLCID2=`lcli2 dev-newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH2 | extract_id` |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
|
|||
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $(($B_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : RCVD_ADD_ACK_REVOCATION } " |
|||
|
|||
lcli1 dev-fulfillhtlc $ID2 $HTLCID2 $SECRET2 |
|||
lcli2 dev-failhtlc $ID1 $HTLCID 849 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
|
|||
# We transferred amount from B to A. |
|||
A_AMOUNT=$(($A_AMOUNT + $HTLC_AMOUNT)) |
|||
B_AMOUNT=$(($B_AMOUNT - $HTLC_AMOUNT)) |
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
# Now, test making more changes before receiving commit reply. |
|||
DO_RECONNECT="" |
|||
lcli2 dev-output $ID1 false |
|||
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
|
|||
# Make sure node1 sends commit (in the background, since it will block!) |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 & |
|||
|
|||
if [ -n "$MANUALCOMMIT" ]; then |
|||
# node2 will consider this committed. |
|||
check_status_single lcli2 $(($B_AMOUNT - $EXTRA_FEE/2)) $(($B_FEE + $EXTRA_FEE/2)) "" $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE/2)) $(($A_FEE + $EXTRA_FEE/2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_REVOCATION } " |
|||
else |
|||
# It will start committing by itself |
|||
check_status_single lcli2 $(($B_AMOUNT - $EXTRA_FEE/2)) $(($B_FEE + $EXTRA_FEE/2)) "" $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE/2)) $(($A_FEE + $EXTRA_FEE/2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_COMMIT } " |
|||
fi |
|||
|
|||
# node1 will still be awaiting node2's revocation reply. |
|||
check_status_single lcli1 $(($A_AMOUNT)) $(($A_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_COMMIT } " $B_AMOUNT $B_FEE "" |
|||
|
|||
# Now send another offer, and enable node2 output. |
|||
HTLCID2=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH2 | extract_id` |
|||
lcli2 dev-output $ID1 true |
|||
|
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
|
|||
DO_RECONNECT=$RECONNECT |
|||
|
|||
# Both sides should be committed to htlcs |
|||
# We open-code check_status here: HTLCs could be in either order. |
|||
check_balance_single lcli1 $(($A_AMOUNT - $HTLC_AMOUNT*2 - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) $(($B_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) |
|||
check_balance_single lcli2 $(($B_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) $(($A_AMOUNT - $HTLC_AMOUNT*2 - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) |
|||
|
|||
# Once both balances are correct, this should be right. |
|||
lcli1 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : SENT_ADD_ACK_REVOCATION } ], their_htlcs : [ ]" || lcli1 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : SENT_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } ], their_htlcs : [ ]" |
|||
|
|||
lcli2 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ ], their_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : RCVD_ADD_ACK_REVOCATION } ]" || lcli2 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ ], their_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : RCVD_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION } ]" |
|||
|
|||
# Just for once, reconnect/restart node 2. |
|||
case "$RECONNECT" in |
|||
reconnect) |
|||
echo RECONNECTING NODE2 |
|||
$LCLI2 dev-reconnect $ID1 >/dev/null |
|||
sleep 1 |
|||
;; |
|||
restart) |
|||
echo RESTARTING NODE2 |
|||
$LCLI2 -- dev-restart $LIGHTNINGD2 >/dev/null 2>&1 || true |
|||
if ! check "$LCLI2 getlog 2>/dev/null | fgrep -q Hello"; then |
|||
echo "Node2 dev-restart failed!">&2 |
|||
exit 1 |
|||
fi |
|||
;; |
|||
esac |
|||
|
|||
if ! check "$LCLI2 getpeers | tr -s '\012\011\" ' ' ' | fgrep -q 'connected : true'"; then |
|||
echo "Failed to reconnect!">&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
# Node2 collects the HTLCs. |
|||
lcli2 dev-fulfillhtlc $ID1 $HTLCID $SECRET |
|||
lcli2 dev-fulfillhtlc $ID1 $HTLCID2 $SECRET2 |
|||
|
|||
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
|
|||
# We transferred 2 * amount from A to B. |
|||
A_AMOUNT=$(($A_AMOUNT - $HTLC_AMOUNT * 2)) |
|||
B_AMOUNT=$(($B_AMOUNT + $HTLC_AMOUNT * 2)) |
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
lcli1 close $ID2 |
|||
|
|||
# They should be negotiating the close. |
|||
check_peerstate lcli1 STATE_MUTUAL_CLOSING |
|||
check_peerstate lcli2 STATE_MUTUAL_CLOSING |
|||
|
|||
$CLI generate 1 |
|||
|
|||
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_MUTUAL |
|||
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_MUTUAL |
|||
|
|||
# Give it forever-1 blocks. |
|||
$CLI generate 8 |
|||
|
|||
# Make sure they saw it! |
|||
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_MUTUAL |
|||
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_MUTUAL |
|||
|
|||
# Now the final one. |
|||
$CLI generate 1 |
|||
|
|||
check_no_peers lcli1 |
|||
check_no_peers lcli2 |
|||
|
|||
lcli1 stop |
|||
lcli2 stop |
|||
|
|||
all_ok |
@ -1,86 +0,0 @@ |
|||
#! /bin/sh -e |
|||
|
|||
# Wherever we are, we want to be in daemon/test dir. |
|||
cd `git rev-parse --show-toplevel`/daemon/test |
|||
|
|||
. scripts/vars.sh |
|||
. scripts/helpers.sh |
|||
|
|||
parse_cmdline 2 "$@" |
|||
setup_lightning 2 |
|||
|
|||
# Simply override default fee (estimatefee fails on regtest anyway) |
|||
DEFAULT_FEE_RATE2=50000 |
|||
# We use 5x fee rate for commits, by defailt. |
|||
FEE_RATE2=$(($DEFAULT_FEE_RATE2 * 5)) |
|||
echo "default-fee-rate=$DEFAULT_FEE_RATE2" >> $DIR2/config |
|||
|
|||
start_lightningd 2 |
|||
fund_lightningd |
|||
|
|||
lcli1 connect localhost $PORT2 $FUND_INPUT_TX & |
|||
|
|||
# Now make it pass anchor (should be in mempool: one block to bury it) |
|||
check_tx_spend |
|||
$CLI generate 1 |
|||
|
|||
DO_RECONNECT=$RECONNECT |
|||
|
|||
check_peerstate lcli1 STATE_NORMAL |
|||
check_peerstate lcli2 STATE_NORMAL |
|||
|
|||
# Asymmetry, since fee rates different. |
|||
NO_HTLCS_FEE2=$((338 * $FEE_RATE2 / 2000 * 2000)) |
|||
ONE_HTLCS_FEE2=$(( (338 + 32) * $FEE_RATE2 / 2000 * 2000)) |
|||
|
|||
A_AMOUNT1=$(($AMOUNT - $NO_HTLCS_FEE)) |
|||
A_FEE1=$NO_HTLCS_FEE |
|||
A_AMOUNT2=$(($AMOUNT - $NO_HTLCS_FEE2)) |
|||
A_FEE2=$NO_HTLCS_FEE2 |
|||
B_AMOUNT=0 |
|||
B_FEE=0 |
|||
|
|||
check_status_single lcli1 $A_AMOUNT1 $A_FEE1 "" $B_AMOUNT $B_FEE "" |
|||
check_status_single lcli2 $B_AMOUNT $B_FEE "" $(($A_AMOUNT2)) $(($A_FEE2)) "" |
|||
|
|||
# This is 100,000 satoshi, so covers fees. |
|||
HTLC_AMOUNT=100000000 |
|||
RHASH=`lcli2 invoice $HTLC_AMOUNT RHASH3 | sed 's/.*"\([0-9a-f]*\)".*/\1/'` |
|||
ROUTE=`lcli1 getroute $ID2 $HTLC_AMOUNT 1` |
|||
ROUTE=`echo $ROUTE | sed 's/^{ "route" : \(.*\) }$/\1/'` |
|||
lcli1 sendpay "$ROUTE" $RHASH |
|||
|
|||
# They should not split fees. |
|||
check_status_single lcli1 $(($AMOUNT - $HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) "" $(($HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) "" |
|||
check_status_single lcli2 $(($HTLC_AMOUNT - $NO_HTLCS_FEE2 / 2)) $(($NO_HTLCS_FEE2 / 2)) "" $(($AMOUNT - $HTLC_AMOUNT - $NO_HTLCS_FEE2 / 2)) $(($NO_HTLCS_FEE2 / 2)) "" |
|||
|
|||
# FIXME: reactivate feechanges! |
|||
# # Change fee rate on node2 to same as node1. |
|||
# lcli2 dev-feerate 40000 |
|||
# $CLI generate 1 |
|||
# [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
# [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
|
|||
# check_status $(($AMOUNT - $HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) "" $(($HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) "" |
|||
|
|||
# # Change back. |
|||
# lcli2 dev-feerate 50000 |
|||
# $CLI generate 1 |
|||
# [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 |
|||
# [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 |
|||
|
|||
# check_status_single lcli1 $(($AMOUNT - $HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) "" $(($HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) "" |
|||
# check_status_single lcli2 $(($HTLC_AMOUNT - $NO_HTLCS_FEE2 / 2)) $(($NO_HTLCS_FEE2 / 2)) "" $(($AMOUNT - $HTLC_AMOUNT - $NO_HTLCS_FEE2 / 2)) $(($NO_HTLCS_FEE2 / 2)) "" |
|||
|
|||
lcli1 close $ID2 |
|||
check_tx_spend |
|||
|
|||
# Give it 10 blocks ie "forever" |
|||
$CLI generate 10 |
|||
check_no_peers lcli1 |
|||
check_no_peers lcli2 |
|||
|
|||
lcli1 stop |
|||
lcli2 stop |
|||
|
|||
all_ok |
@ -1,82 +0,0 @@ |
|||
#! /bin/sh -e |
|||
|
|||
# Wherever we are, we want to be in daemon/test dir. |
|||
cd `git rev-parse --show-toplevel`/daemon/test |
|||
|
|||
. scripts/vars.sh |
|||
. scripts/helpers.sh |
|||
|
|||
parse_cmdline 2 "$@" |
|||
setup_lightning 2 |
|||
start_lightningd 2 |
|||
fund_lightningd |
|||
|
|||
# Prevent anchor broadcast |
|||
lcli1 dev-broadcast false |
|||
lcli1 connect localhost $PORT2 $FUND_INPUT_TX & |
|||
|
|||
# Expect them to be waiting for anchor, and ack from other side. |
|||
check_peerstate lcli1 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE |
|||
check_peerstate lcli2 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE |
|||
|
|||
# Enable reconnect from here. |
|||
DO_RECONNECT=$RECONNECT |
|||
|
|||
$CLI generate 99 |
|||
|
|||
# Still waiting. |
|||
check_peerstate lcli1 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE |
|||
check_peerstate lcli2 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE |
|||
|
|||
# Make sure whichever times out first doesn't tell the other. |
|||
lcli1 dev-output $ID2 false |
|||
lcli2 dev-output $ID1 false |
|||
$CLI generate 1 |
|||
|
|||
# Node1 should have gone into STATE_ERR_ANCHOR_TIMEOUT. |
|||
check "lcli1 getlog debug | $FGREP STATE_ERR_ANCHOR_TIMEOUT" |
|||
|
|||
# Don't try to reconnect any more if we are. |
|||
if [ x"$RECONNECT" = xreconnect ]; then DO_RECONNECT=""; fi |
|||
|
|||
# If we're restarting, don't expect peer. |
|||
NO_PEER2=1 |
|||
|
|||
# Now let them send errors if they're still trying. |
|||
lcli2 dev-output $ID1 true || true |
|||
lcli1 dev-output $ID2 true || true |
|||
|
|||
# Peer 2 should give up, and have forgotten all about it. |
|||
check "lcli2 getlog debug | $FGREP STATE_CLOSED" |
|||
check_no_peers lcli2 |
|||
|
|||
# Node1 should be disconnected. |
|||
check_peerconnected lcli1 false |
|||
|
|||
# Now let node1 broadcast anchor and unilateral close belatedly! |
|||
lcli1 dev-broadcast true |
|||
|
|||
# Now mine that transaction so they see it. |
|||
$CLI generate 1 |
|||
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_OUR_UNILATERAL |
|||
|
|||
# Now move bitcoind 1 day, which is what node2 asked for on commit. |
|||
# Get current time from last block (works if we run this twice). |
|||
CURTIME=$($CLI getblock $($CLI getblockhash $(($BLOCKHEIGHT + 100))) | sed -n 's/ "time": \([0-9]*\),/\1/p') |
|||
$CLI setmocktime $(($CURTIME + 24 * 60 * 60)) |
|||
|
|||
# Move average so CSV moves. |
|||
$CLI generate 6 |
|||
|
|||
# Now it should have spent the commit tx. |
|||
check_tx_spend |
|||
|
|||
# 100 blocks pass |
|||
$CLI generate 100 |
|||
|
|||
# Considers it all done now. |
|||
check_no_peers lcli1 |
|||
|
|||
lcli1 stop |
|||
lcli2 stop |
|||
all_ok |
@ -1,87 +0,0 @@ |
|||
#! /bin/sh -e |
|||
|
|||
# Wherever we are, we want to be in daemon/test dir. |
|||
cd `git rev-parse --show-toplevel`/daemon/test |
|||
|
|||
. scripts/vars.sh |
|||
. scripts/helpers.sh |
|||
|
|||
parse_cmdline 2 "$@" |
|||
setup_lightning 2 |
|||
start_lightningd 2 |
|||
fund_lightningd |
|||
|
|||
lcli1 connect localhost $PORT2 $FUND_INPUT_TX & |
|||
|
|||
# Now make it pass anchor (should be in mempool: one block to bury it) |
|||
check_tx_spend |
|||
$CLI generate 1 |
|||
|
|||
DO_RECONNECT=$RECONNECT |
|||
|
|||
check_peerstate lcli1 STATE_NORMAL |
|||
check_peerstate lcli2 STATE_NORMAL |
|||
|
|||
A_AMOUNT=$(($AMOUNT - $NO_HTLCS_FEE)) |
|||
A_FEE=$NO_HTLCS_FEE |
|||
B_AMOUNT=0 |
|||
B_FEE=0 |
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
# 100k satoshi should cover fees. |
|||
HTLC_AMOUNT=100000000 |
|||
EXPIRY=$(( $(blockheight) + 10)) |
|||
RHASH3=`lcli2 invoice $HTLC_AMOUNT RHASH3 | sed 's/.*"\([0-9a-f]*\)".*/\1/'` |
|||
|
|||
lcli2 listinvoice |
|||
[ "`lcli2 listinvoice | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH3 , rhash : $RHASH3 , msatoshi : $HTLC_AMOUNT, complete : false } ] " ] |
|||
|
|||
HTLCID3=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH3 | extract_id` |
|||
|
|||
# We transferred amount from A to B, but fee now split evenly. |
|||
A_AMOUNT=$(($A_AMOUNT - $HTLC_AMOUNT + $NO_HTLCS_FEE / 2)) |
|||
B_AMOUNT=$(($B_AMOUNT + $HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) |
|||
A_FEE=$(($NO_HTLCS_FEE / 2)) |
|||
B_FEE=$(($NO_HTLCS_FEE / 2)) |
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
[ "`lcli2 listinvoice | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH3 , rhash : $RHASH3 , msatoshi : $HTLC_AMOUNT, complete : true } ] " ] |
|||
|
|||
# Now, failed payment (didn't pay enough) |
|||
RHASH4=`lcli2 invoice $HTLC_AMOUNT RHASH4 | sed 's/.*"\([0-9a-f]*\)".*/\1/'` |
|||
|
|||
# Shouldn't have this already. |
|||
if lcli2 getlog | $FGREP 'Short payment for'; then exit 1; fi |
|||
|
|||
# Test listinvoice with both, or subset (either order possible!) |
|||
INVOICES=`lcli2 listinvoice | tr -s '\012\011\" ' ' '` |
|||
[ "$INVOICES" = "[ { label : RHASH3 , rhash : $RHASH3 , msatoshi : $HTLC_AMOUNT, complete : true }, { label : RHASH4 , rhash : $RHASH4 , msatoshi : $HTLC_AMOUNT, complete : false } ] " ] || [ "$INVOICES" = "[ { label : RHASH4 , rhash : $RHASH4 , msatoshi : $HTLC_AMOUNT, complete : false }, { label : RHASH3 , rhash : $RHASH3 , msatoshi : $HTLC_AMOUNT, complete : true } ] " ] |
|||
[ "`lcli2 listinvoice RHASH3 | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH3 , rhash : $RHASH3 , msatoshi : $HTLC_AMOUNT, complete : true } ] " ] |
|||
[ "`lcli2 listinvoice RHASH4 | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH4 , rhash : $RHASH4 , msatoshi : $HTLC_AMOUNT, complete : false } ] " ] |
|||
|
|||
HTLCID4=`lcli1 dev-newhtlc $ID2 $(($HTLC_AMOUNT - 1)) $EXPIRY $RHASH4 | extract_id` |
|||
|
|||
check lcli2 "getlog | $FGREP 'Short payment for'" |
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
lcli2 delinvoice RHASH4 |
|||
if lcli2 delinvoice RHASH3 >/dev/null; then |
|||
echo "Should not be able to delete completed invoice!" >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
lcli1 close $ID2 |
|||
|
|||
# They should be negotiate the close. |
|||
check_tx_spend |
|||
|
|||
# Bury it in "forever" blocks. |
|||
$CLI generate 10 |
|||
|
|||
check_no_peers lcli1 |
|||
check_no_peers lcli2 |
|||
|
|||
lcli1 stop |
|||
lcli2 stop |
|||
|
|||
all_ok |
@ -1,96 +0,0 @@ |
|||
#! /bin/sh -e |
|||
|
|||
# Wherever we are, we want to be in daemon/test dir. |
|||
cd `git rev-parse --show-toplevel`/daemon/test |
|||
|
|||
. scripts/vars.sh |
|||
. scripts/helpers.sh |
|||
|
|||
parse_cmdline 2 "$@" |
|||
setup_lightning 2 |
|||
start_lightningd 2 |
|||
fund_lightningd |
|||
|
|||
lcli1 connect localhost $PORT2 $FUND_INPUT_TX & |
|||
|
|||
# Now make it pass anchor (should be in mempool: one block to bury it) |
|||
check_tx_spend |
|||
$CLI generate 1 |
|||
|
|||
DO_RECONNECT=$RECONNECT |
|||
|
|||
check_peerstate lcli1 STATE_NORMAL |
|||
check_peerstate lcli2 STATE_NORMAL |
|||
|
|||
A_AMOUNT=$(($AMOUNT - $NO_HTLCS_FEE)) |
|||
A_FEE=$NO_HTLCS_FEE |
|||
B_AMOUNT=0 |
|||
B_FEE=0 |
|||
|
|||
# Send funds to 2 so it can offer HTLCS |
|||
HTLC_AMOUNT=100000000 |
|||
RHASH=`lcli2 invoice $HTLC_AMOUNT RHASH3 | sed 's/.*"\([0-9a-f]*\)".*/\1/'` |
|||
ROUTE=`lcli1 getroute $ID2 $HTLC_AMOUNT 1` |
|||
ROUTE=`echo $ROUTE | sed 's/^{ "route" : \(.*\) }$/\1/'` |
|||
lcli1 sendpay "$ROUTE" $RHASH |
|||
|
|||
# They pay half fees each. |
|||
A_AMOUNT=$(($A_AMOUNT - $HTLC_AMOUNT + $NO_HTLCS_FEE / 2)) |
|||
A_FEE=$(($NO_HTLCS_FEE / 2)) |
|||
B_AMOUNT=$(($B_AMOUNT + $HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) |
|||
B_FEE=$(($NO_HTLCS_FEE / 2)) |
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
# For next step, make sure neither node fails HTLCs we're about to set up. |
|||
lcli1 dev-routefail false |
|||
lcli2 dev-routefail false |
|||
|
|||
# Set up HTLCs both ways. |
|||
|
|||
# This is 10,000 satoshi, so not dust! |
|||
HTLC_AMOUNT=10000000 |
|||
|
|||
EXPIRY=$(( $(blockheight) + 10)) |
|||
SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd |
|||
RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'` |
|||
|
|||
HTLCID1=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
|
|||
# FIXME: Test with dust htlc, too. |
|||
HTLCID2=`lcli2 dev-newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
|
|||
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $(($B_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION } " |
|||
|
|||
# Now begin close |
|||
lcli1 close $ID2 |
|||
|
|||
# They should be waiting for it to clear up. |
|||
check_peerstate lcli1 STATE_SHUTDOWN |
|||
check_peerstate lcli2 STATE_SHUTDOWN |
|||
|
|||
# Fail one, still waiting. |
|||
lcli2 dev-failhtlc $ID1 $HTLCID1 800 |
|||
check_peerstate lcli1 STATE_SHUTDOWN |
|||
check_peerstate lcli2 STATE_SHUTDOWN |
|||
|
|||
# Fulfill the other causes them to actually complete the close. |
|||
lcli1 dev-fulfillhtlc $ID2 $HTLCID2 $SECRET |
|||
check_peerstate lcli1 STATE_MUTUAL_CLOSING |
|||
check_peerstate lcli2 STATE_MUTUAL_CLOSING |
|||
|
|||
check_tx_spend |
|||
$CLI generate 1 |
|||
|
|||
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_MUTUAL |
|||
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_MUTUAL |
|||
|
|||
# Give it "forever" blocks. |
|||
$CLI generate 9 |
|||
|
|||
check_no_peers lcli1 |
|||
check_no_peers lcli2 |
|||
|
|||
lcli1 stop |
|||
lcli2 stop |
|||
|
|||
all_ok |
@ -1,146 +0,0 @@ |
|||
#! /bin/sh -e |
|||
|
|||
# Wherever we are, we want to be in daemon/test dir. |
|||
cd `git rev-parse --show-toplevel`/daemon/test |
|||
|
|||
. scripts/vars.sh |
|||
. scripts/helpers.sh |
|||
|
|||
parse_cmdline 3 "$@" |
|||
setup_lightning 3 |
|||
start_lightningd 3 |
|||
fund_lightningd |
|||
|
|||
# We connect 1->2->3 |
|||
lcli1 connect localhost $PORT2 $FUND_INPUT_TX & |
|||
check_tx_spend |
|||
$CLI generate 1 |
|||
|
|||
P2SHADDR2=`$LCLI2 newaddr | sed -n 's/{ "address" : "\(.*\)" }/\1/p'` |
|||
TXID2=`$CLI sendtoaddress $P2SHADDR2 0.01` |
|||
FUND_INPUT_TX2=`$CLI getrawtransaction $TXID2` |
|||
$CLI generate 1 |
|||
|
|||
lcli2 connect localhost $PORT3 $FUND_INPUT_TX2 & |
|||
check_tx_spend |
|||
$CLI generate 1 |
|||
|
|||
DO_RECONNECT=$RECONNECT |
|||
|
|||
# Make sure all in STATE_NORMAL. |
|||
check_peerstate lcli1 STATE_NORMAL |
|||
check_peerstate lcli3 STATE_NORMAL |
|||
|
|||
# More than enough to cover commit fees. |
|||
HTLC_AMOUNT=100000000 |
|||
|
|||
# Tell node 1 about the 2->3 route. |
|||
# Add to config in case we are restaring. |
|||
echo "add-route=$ID2/$ID3/546000/10/36/36" >> $DIR1/config |
|||
lcli1 dev-add-route $ID2 $ID3 546000 10 36 36 |
|||
RHASH=`lcli3 invoice $HTLC_AMOUNT RHASH | sed 's/.*"\([0-9a-f]*\)".*/\1/'` |
|||
BAD_RHASH=`echo $RHASH | tr '0-9a-f' 'a-f0-9'` |
|||
|
|||
# Get route. |
|||
ROUTE=`lcli1 getroute $ID3 $HTLC_AMOUNT 1` |
|||
ROUTE=`echo $ROUTE | sed 's/^{ "route" : \(.*\) }$/\1/'` |
|||
|
|||
# Try wrong hash. |
|||
if lcli1 sendpay "$ROUTE" $BAD_RHASH; then |
|||
echo Paid with wrong hash? >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
# Try underpaying. |
|||
PAID=`echo "$ROUTE" | sed -n 's/.*"msatoshi" : \([0-9]*\),.*/\1/p'` |
|||
UNDERPAY=`echo "$ROUTE" | sed "s/: $PAID,/: $(($PAID - 1)),/"` |
|||
if lcli1 sendpay "$UNDERPAY" $RHASH; then |
|||
echo Paid with too little? >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
# If restarting, make sure node3 remembers incoming payment. |
|||
if [ "$RECONNECT" = restart ]; then |
|||
$LCLI3 -- dev-restart $LIGHTNINGD3 >/dev/null 2>&1 || true |
|||
if ! check "$LCLI3 getpeers 2>/dev/null | tr -s '\012\011\" ' ' ' | fgrep -q 'connected : true'"; then |
|||
echo "Failed to reconnect!">&2 |
|||
exit 1 |
|||
fi |
|||
fi |
|||
|
|||
[ "`lcli3 listinvoice RHASH | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH , rhash : $RHASH , msatoshi : $HTLC_AMOUNT, complete : false } ] " ] |
|||
# Pay correctly. |
|||
lcli1 sendpay "$ROUTE" $RHASH |
|||
|
|||
# Node 3 should end up with that amount (minus 1/2 tx fee) |
|||
# Note that it is delayed a little, since node2 fulfils as soon as fulfill |
|||
# starts. |
|||
check lcli3 "getpeers | $FGREP \"\\\"our_amount\\\" : $(($HTLC_AMOUNT - $NO_HTLCS_FEE / 2))\"" |
|||
|
|||
# If restarting, make sure node3 remembers completed payment. |
|||
if [ "$RECONNECT" = restart ]; then |
|||
echo RESTARTING NODE3 |
|||
$LCLI3 -- dev-restart $LIGHTNINGD3 >/dev/null 2>&1 || true |
|||
sleep 5 |
|||
$LCLI2 -- dev-restart $LIGHTNINGD2 >/dev/null 2>&1 || true |
|||
if ! check "$LCLI3 getpeers 2>/dev/null | tr -s '\012\011\" ' ' ' | fgrep -q 'connected : true'"; then |
|||
echo "Failed to reconnect!">&2 |
|||
exit 1 |
|||
fi |
|||
fi |
|||
|
|||
[ "`lcli3 listinvoice RHASH | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH , rhash : $RHASH , msatoshi : $HTLC_AMOUNT, complete : true } ] " ] |
|||
|
|||
[ "`lcli3 waitanyinvoice | tr -s '\012\011\" ' ' '`" = "{ label : RHASH , rhash : $RHASH , msatoshi : $HTLC_AMOUNT } " ] |
|||
|
|||
# Can't pay twice (try from node2) |
|||
ROUTE2=`lcli2 getroute $ID3 $HTLC_AMOUNT 1` |
|||
ROUTE2=`echo $ROUTE2 | sed 's/^{ "route" : \(.*\) }$/\1/'` |
|||
if lcli2 sendpay "$ROUTE2" $RHASH; then |
|||
echo "Paying twice worked?" >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
lcli3 close $ID2 |
|||
check_peerstate lcli3 STATE_MUTUAL_CLOSING |
|||
|
|||
# Re-send should be a noop (doesn't matter that node3 is down!) |
|||
lcli1 sendpay "$ROUTE" $RHASH |
|||
|
|||
# Re-send to different id or amount should complain. |
|||
SHORTROUTE=`echo "$ROUTE" | sed 's/, { "id" : .* }//' | sed 's/"msatoshi" : [0-9]*,/"msatoshi" : '$HTLC_AMOUNT,/` |
|||
lcli1 sendpay "$SHORTROUTE" $RHASH | $FGREP "already succeeded to $ID3" |
|||
lcli1 sendpay "$UNDERPAY" $RHASH | $FGREP "already succeeded with amount $HTLC_AMOUNT" |
|||
|
|||
# Now node2 should fail to route. |
|||
if lcli1 sendpay "$ROUTE" $BAD_RHASH | $FGREP "failed: error code 404 node $ID2 reason Unknown peer"; then : ; |
|||
else |
|||
echo "Pay to node3 didn't give 404" >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
# Now node1 should fail to route (route deleted) |
|||
if lcli1 getroute $ID3 $HTLC_AMOUNT 1 | $FGREP "no route found"; then : ; |
|||
else |
|||
echo "Pay to node3 didn't fail instantly second time" >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
lcli1 close $ID2 |
|||
check_peerstate lcli1 STATE_MUTUAL_CLOSING |
|||
|
|||
# Make sure both txs broadcast. |
|||
check '[ `$CLI getrawmempool | egrep -c "[a-f0-9]{32}"` = 2 ]' |
|||
|
|||
# Bury them in "forever" blocks. |
|||
$CLI generate 10 |
|||
|
|||
check_no_peers lcli1 |
|||
check_no_peers lcli2 |
|||
check_no_peers lcli3 |
|||
|
|||
lcli1 stop |
|||
lcli2 stop |
|||
lcli3 stop |
|||
|
|||
all_ok |
@ -1,91 +0,0 @@ |
|||
#! /bin/sh -e |
|||
|
|||
# Wherever we are, we want to be in daemon/test dir. |
|||
cd `git rev-parse --show-toplevel`/daemon/test |
|||
|
|||
. scripts/vars.sh |
|||
. scripts/helpers.sh |
|||
|
|||
parse_cmdline 2 "$@" |
|||
setup_lightning 2 |
|||
start_lightningd 2 |
|||
fund_lightningd |
|||
|
|||
lcli1 connect localhost $PORT2 $FUND_INPUT_TX & |
|||
|
|||
# Now make it pass anchor (should be in mempool: one block to bury it) |
|||
check_tx_spend |
|||
$CLI generate 1 |
|||
|
|||
DO_RECONNECT=$RECONNECT |
|||
|
|||
check_peerstate lcli1 STATE_NORMAL |
|||
check_peerstate lcli2 STATE_NORMAL |
|||
|
|||
A_AMOUNT=$(($AMOUNT - $NO_HTLCS_FEE)) |
|||
A_FEE=$NO_HTLCS_FEE |
|||
B_AMOUNT=0 |
|||
B_FEE=0 |
|||
|
|||
# Send funds to 2 so it can offer HTLCS |
|||
HTLC_AMOUNT=100000000 |
|||
RHASH=`lcli2 invoice $HTLC_AMOUNT RHASH3 | sed 's/.*"\([0-9a-f]*\)".*/\1/'` |
|||
ROUTE=`lcli1 getroute $ID2 $HTLC_AMOUNT 1` |
|||
ROUTE=`echo $ROUTE | sed 's/^{ "route" : \(.*\) }$/\1/'` |
|||
lcli1 sendpay "$ROUTE" $RHASH |
|||
|
|||
# They pay half fees each noe. |
|||
A_AMOUNT=$(($A_AMOUNT - $HTLC_AMOUNT + $NO_HTLCS_FEE / 2)) |
|||
A_FEE=$(($NO_HTLCS_FEE / 2)) |
|||
B_AMOUNT=$(($B_AMOUNT + $HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) |
|||
B_FEE=$(($NO_HTLCS_FEE / 2)) |
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
# For next step, make sure neither node fails HTLCs we're about to set up. |
|||
lcli1 dev-routefail false |
|||
lcli2 dev-routefail false |
|||
|
|||
# Set up HTLCs both ways. |
|||
|
|||
# This is 10,000 satoshi, so not dust! |
|||
HTLC_AMOUNT=10000000 |
|||
|
|||
EXPIRY=$(( $(blockheight) + 10)) |
|||
SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd |
|||
RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'` |
|||
|
|||
HTLCID1=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
|
|||
# FIXME: Test with dust htlc, too. |
|||
HTLCID2=`lcli2 dev-newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
|
|||
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $(($B_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION } " |
|||
|
|||
# This is the tx we're going to try to spend. |
|||
STEAL_TX=`$LCLI1 dev-signcommit $ID2 | cut -d\" -f4` |
|||
|
|||
# Fail one, succeed 2->1 payment |
|||
lcli2 dev-failhtlc $ID1 $HTLCID1 800 |
|||
lcli1 dev-fulfillhtlc $ID2 $HTLCID2 $SECRET |
|||
|
|||
A_AMOUNT=$(($A_AMOUNT + $HTLC_AMOUNT)) |
|||
B_AMOUNT=$(($B_AMOUNT - $HTLC_AMOUNT)) |
|||
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" |
|||
|
|||
# Send out old commit tx from peer 1. |
|||
$CLI sendrawtransaction $STEAL_TX |
|||
$CLI generate 1 |
|||
|
|||
# Node1 should get really upset; node2 should steal the transaction. |
|||
check_peerstate lcli1 STATE_ERR_INFORMATION_LEAK |
|||
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_CHEATED |
|||
check_tx_spend |
|||
|
|||
# Give it "forever" blocks. |
|||
$CLI generate 10 |
|||
|
|||
check_no_peers lcli2 |
|||
|
|||
lcli1 stop |
|||
lcli2 stop |
|||
all_ok |
@ -1,87 +0,0 @@ |
|||
#! /bin/sh -e |
|||
|
|||
# Wherever we are, we want to be in daemon/test dir. |
|||
cd `git rev-parse --show-toplevel`/daemon/test |
|||
|
|||
. scripts/vars.sh |
|||
. scripts/helpers.sh |
|||
|
|||
parse_cmdline 2 "$@" |
|||
setup_lightning 2 |
|||
start_lightningd 2 |
|||
fund_lightningd |
|||
|
|||
lcli1 connect localhost $PORT2 $FUND_INPUT_TX & |
|||
|
|||
# Now make it pass anchor (should be in mempool: one block to bury it) |
|||
check_tx_spend |
|||
$CLI generate 1 |
|||
|
|||
DO_RECONNECT=$RECONNECT |
|||
|
|||
check_peerstate lcli1 STATE_NORMAL |
|||
check_peerstate lcli2 STATE_NORMAL |
|||
|
|||
# Make sure node2 doesn't fail |
|||
lcli2 dev-routefail false |
|||
|
|||
A_AMOUNT=$(($AMOUNT - $NO_HTLCS_FEE)) |
|||
A_FEE=$NO_HTLCS_FEE |
|||
B_AMOUNT=0 |
|||
B_FEE=0 |
|||
|
|||
# This is 10,000 satoshi, so not dust! |
|||
HTLC_AMOUNT=10000000 |
|||
|
|||
EXPIRY=$(( $(blockheight) + 10)) |
|||
SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd |
|||
RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'` |
|||
|
|||
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` |
|||
|
|||
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) |
|||
A_FEE=$(($A_FEE + $EXTRA_FEE)) |
|||
B_AMOUNT=0 |
|||
B_FEE=0 |
|||
|
|||
# Wait for both to committed. |
|||
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE "" |
|||
|
|||
# make node1 disconnect with node2. |
|||
lcli1 dev-disconnect $ID2 |
|||
check_peerconnected lcli1 false |
|||
|
|||
# lcli1 should have sent out commitment tx |
|||
check_peerstate lcli1 STATE_ERR_BREAKDOWN |
|||
check_tx_spend |
|||
|
|||
# Mine it. |
|||
$CLI generate 1 |
|||
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_OUR_UNILATERAL |
|||
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL |
|||
|
|||
# both still know about htlc |
|||
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE "" |
|||
|
|||
# Generate 6 blocks so CSV timeout has expired. |
|||
$CLI generate 6 |
|||
|
|||
# Now, lcli1 should spend its own output. |
|||
check_tx_spend |
|||
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_OUR_UNILATERAL |
|||
|
|||
while [ $(blockheight) != $EXPIRY ]; do |
|||
$CLI generate 1 |
|||
done |
|||
|
|||
# lcli1 should have gotten HTLC back. |
|||
check_tx_spend |
|||
|
|||
# Now, after "forever" blocks, should all be concluded. |
|||
$CLI generate 10 |
|||
|
|||
# Both consider it all done now. |
|||
check_no_peers lcli1 |
|||
|
|||
lcli1 stop |
|||
all_ok |
@ -1,144 +0,0 @@ |
|||
/* Poor man's wallet.
|
|||
* Needed because bitcoind doesn't (yet) produce segwit outputs, and we need |
|||
* such outputs for our anchor tx to make it immalleable. |
|||
*/ |
|||
#include "bitcoin/base58.h" |
|||
#include "bitcoin/privkey.h" |
|||
#include "bitcoin/script.h" |
|||
#include "bitcoin/signature.h" |
|||
#include "bitcoin/tx.h" |
|||
#include "db.h" |
|||
#include "jsonrpc.h" |
|||
#include "lightningd.h" |
|||
#include "log.h" |
|||
#include "wallet.h" |
|||
#include <ccan/structeq/structeq.h> |
|||
#include <sodium/randombytes.h> |
|||
|
|||
struct wallet { |
|||
struct list_node list; |
|||
struct privkey privkey; |
|||
struct pubkey pubkey; |
|||
struct ripemd160 p2sh; |
|||
}; |
|||
|
|||
bool restore_wallet_address(struct lightningd_state *dstate, |
|||
const struct privkey *privkey) |
|||
{ |
|||
struct wallet *w = tal(dstate, struct wallet); |
|||
u8 *redeemscript; |
|||
struct sha256 h; |
|||
|
|||
w->privkey = *privkey; |
|||
if (!pubkey_from_privkey(&w->privkey, &w->pubkey)) |
|||
return false; |
|||
|
|||
redeemscript = bitcoin_redeem_p2sh_p2wpkh(w, &w->pubkey); |
|||
sha256(&h, redeemscript, tal_count(redeemscript)); |
|||
ripemd160(&w->p2sh, h.u.u8, sizeof(h)); |
|||
|
|||
list_add_tail(&dstate->wallet, &w->list); |
|||
tal_free(redeemscript); |
|||
return true; |
|||
} |
|||
|
|||
static void new_keypair(struct privkey *privkey, struct pubkey *pubkey) |
|||
{ |
|||
do { |
|||
randombytes_buf(privkey->secret.data, |
|||
sizeof(privkey->secret.data)); |
|||
} while (!pubkey_from_privkey(privkey, pubkey)); |
|||
} |
|||
|
|||
static struct wallet *find_by_pubkey(struct lightningd_state *dstate, |
|||
const struct pubkey *walletkey) |
|||
{ |
|||
struct wallet *w; |
|||
|
|||
list_for_each(&dstate->wallet, w, list) { |
|||
if (pubkey_eq(walletkey, &w->pubkey)) |
|||
return w; |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
bool wallet_add_signed_input(struct lightningd_state *dstate, |
|||
const struct pubkey *walletkey, |
|||
struct bitcoin_tx *tx, |
|||
unsigned int input_num) |
|||
{ |
|||
u8 *redeemscript; |
|||
secp256k1_ecdsa_signature sig; |
|||
struct wallet *w = find_by_pubkey(dstate, walletkey); |
|||
|
|||
assert(input_num < tal_count(tx->input)); |
|||
if (!w) |
|||
return false; |
|||
|
|||
redeemscript = bitcoin_redeem_p2sh_p2wpkh(tx, &w->pubkey); |
|||
|
|||
sign_tx_input(tx, input_num, |
|||
redeemscript, |
|||
p2wpkh_scriptcode(redeemscript, &w->pubkey), |
|||
&w->privkey, |
|||
&w->pubkey, |
|||
&sig); |
|||
|
|||
bitcoin_witness_p2sh_p2wpkh(tx->input, |
|||
&tx->input[input_num], |
|||
&sig, |
|||
&w->pubkey); |
|||
tal_free(redeemscript); |
|||
return true; |
|||
} |
|||
|
|||
bool wallet_can_spend(struct lightningd_state *dstate, |
|||
const struct bitcoin_tx_output *output, |
|||
struct pubkey *walletkey) |
|||
{ |
|||
struct ripemd160 h; |
|||
struct wallet *w; |
|||
|
|||
if (!is_p2sh(output->script)) |
|||
return NULL; |
|||
|
|||
memcpy(&h, output->script + 2, 20); |
|||
list_for_each(&dstate->wallet, w, list) { |
|||
if (structeq(&h, &w->p2sh)) { |
|||
*walletkey = w->pubkey; |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
static void json_newaddr(struct command *cmd, |
|||
const char *buffer, const jsmntok_t *params) |
|||
{ |
|||
struct json_result *response = new_json_result(cmd); |
|||
struct wallet *w = tal(cmd->dstate, struct wallet); |
|||
u8 *redeemscript; |
|||
struct sha256 h; |
|||
|
|||
new_keypair(&w->privkey, &w->pubkey); |
|||
redeemscript = bitcoin_redeem_p2sh_p2wpkh(cmd, &w->pubkey); |
|||
sha256(&h, redeemscript, tal_count(redeemscript)); |
|||
ripemd160(&w->p2sh, h.u.u8, sizeof(h)); |
|||
|
|||
list_add_tail(&cmd->dstate->wallet, &w->list); |
|||
db_add_wallet_privkey(cmd->dstate, &w->privkey); |
|||
|
|||
json_object_start(response, NULL); |
|||
json_add_string(response, "address", |
|||
p2sh_to_base58(cmd, cmd->dstate->testnet, &w->p2sh)); |
|||
json_object_end(response); |
|||
command_success(cmd, response); |
|||
} |
|||
|
|||
static const struct json_command newaddr_command = { |
|||
"newaddr", |
|||
json_newaddr, |
|||
"Get a new address to fund a channel", |
|||
"Returns {address} a p2sh address" |
|||
}; |
|||
AUTODATA(json_command, &newaddr_command); |
@ -1,21 +0,0 @@ |
|||
#ifndef LIGHTNING_DAEMON_WALLET_H |
|||
#define LIGHTNING_DAEMON_WALLET_H |
|||
#include "config.h" |
|||
|
|||
struct lightningd_state; |
|||
struct bitcoin_tx; |
|||
struct bitcoin_tx_output; |
|||
|
|||
bool restore_wallet_address(struct lightningd_state *dstate, |
|||
const struct privkey *privkey); |
|||
|
|||
bool wallet_add_signed_input(struct lightningd_state *dstate, |
|||
const struct pubkey *walletkey, |
|||
struct bitcoin_tx *tx, |
|||
unsigned int input_num); |
|||
|
|||
bool wallet_can_spend(struct lightningd_state *dstate, |
|||
const struct bitcoin_tx_output *output, |
|||
struct pubkey *walletkey); |
|||
|
|||
#endif /* LIGHTNING_DAEMON_WALLET_H */ |
Loading…
Reference in new issue