Browse Source

daemon: don't ever use timeouts in seconds, always blocks,

The protocol still supports both, but we now only support blocks.

It's hard to do risk management with timeouts in seconds, given block
variance.  This is also signficantly simpler, as HTLC timeouts are
always fired in response to blocks, not wall-clock times.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 9 years ago
parent
commit
a3375516e5
  1. 5
      daemon/chaintopology.c
  2. 3
      daemon/chaintopology.h
  3. 36
      daemon/lightningd.c
  4. 14
      daemon/lightningd.h
  5. 21
      daemon/packets.c
  6. 132
      daemon/peer.c
  7. 5
      daemon/peer.h
  8. 66
      daemon/test/test.sh

5
daemon/chaintopology.c

@ -452,6 +452,11 @@ u32 get_tip_mediantime(struct lightningd_state *dstate)
return dstate->topology->tip->mediantime; return dstate->topology->tip->mediantime;
} }
u32 get_block_height(struct lightningd_state *dstate)
{
return dstate->topology->tip->height;
}
void setup_topology(struct lightningd_state *dstate) void setup_topology(struct lightningd_state *dstate)
{ {
dstate->topology = tal(dstate, struct topology); dstate->topology = tal(dstate, struct topology);

3
daemon/chaintopology.h

@ -18,6 +18,9 @@ u32 get_tx_mediantime(struct lightningd_state *dstate,
/* Get mediantime of the tip; if more than one, pick greatest time. */ /* Get mediantime of the tip; if more than one, pick greatest time. */
u32 get_tip_mediantime(struct lightningd_state *dstate); u32 get_tip_mediantime(struct lightningd_state *dstate);
/* Get highest block number. */
u32 get_block_height(struct lightningd_state *dstate);
/* Broadcast a single tx, and rebroadcast as reqd (takes ownership of tx) */ /* Broadcast a single tx, and rebroadcast as reqd (takes ownership of tx) */
void broadcast_tx(struct peer *peer, const struct bitcoin_tx *tx); void broadcast_tx(struct peer *peer, const struct bitcoin_tx *tx);

36
daemon/lightningd.c

@ -70,11 +70,11 @@ static void opt_show_u32(char buf[OPT_SHOW_LEN], const u32 *u)
static void config_register_opts(struct lightningd_state *dstate) static void config_register_opts(struct lightningd_state *dstate)
{ {
opt_register_arg("--locktime", opt_set_u32, opt_show_u32, opt_register_arg("--locktime-blocks", opt_set_u32, opt_show_u32,
&dstate->config.rel_locktime, &dstate->config.locktime_blocks,
"Seconds before peer can unilaterally spend funds"); "Blocks before peer can unilaterally spend funds");
opt_register_arg("--max-locktime", opt_set_u32, opt_show_u32, opt_register_arg("--max-locktime-blocks", opt_set_u32, opt_show_u32,
&dstate->config.rel_locktime_max, &dstate->config.locktime_max,
"Maximum seconds peer can lock up our funds"); "Maximum seconds peer can lock up our funds");
opt_register_arg("--anchor-confirms", opt_set_u32, opt_show_u32, opt_register_arg("--anchor-confirms", opt_set_u32, opt_show_u32,
&dstate->config.anchor_confirms, &dstate->config.anchor_confirms,
@ -94,12 +94,12 @@ static void config_register_opts(struct lightningd_state *dstate)
opt_register_arg("--closing-fee-rate", opt_set_u64, opt_show_u64, opt_register_arg("--closing-fee-rate", opt_set_u64, opt_show_u64,
&dstate->config.closing_fee_rate, &dstate->config.closing_fee_rate,
"Satoshis to use for mutual close transaction fee (per kb)"); "Satoshis to use for mutual close transaction fee (per kb)");
opt_register_arg("--min-expiry", opt_set_u32, opt_show_u32, opt_register_arg("--min-htlc-expiry", opt_set_u32, opt_show_u32,
&dstate->config.min_expiry, &dstate->config.min_htlc_expiry,
"Minimum number of seconds to accept an HTLC before expiry"); "Minimum number of blocks to accept an HTLC before expiry");
opt_register_arg("--max-expiry", opt_set_u32, opt_show_u32, opt_register_arg("--max-htlc-expiry", opt_set_u32, opt_show_u32,
&dstate->config.max_expiry, &dstate->config.max_htlc_expiry,
"Maximum number of seconds to accept an HTLC before expiry"); "Maximum number of blocks to accept an HTLC before expiry");
opt_register_arg("--bitcoind-poll", opt_set_time, opt_show_time, opt_register_arg("--bitcoind-poll", opt_set_time, opt_show_time,
&dstate->config.poll_time, &dstate->config.poll_time,
"Time between polling for new transactions"); "Time between polling for new transactions");
@ -108,20 +108,16 @@ static void config_register_opts(struct lightningd_state *dstate)
"Time after changes before sending out COMMIT"); "Time after changes before sending out COMMIT");
} }
#define MINUTES 60
#define HOURS (60 * MINUTES)
#define DAYS (24 * HOURS)
static void default_config(struct config *config) static void default_config(struct config *config)
{ {
/* aka. "Dude, where's my coins?" */ /* aka. "Dude, where's my coins?" */
config->testnet = true; config->testnet = true;
/* One day to catch cheating attempts. */ /* ~one day to catch cheating attempts. */
config->rel_locktime = 1 * DAYS; config->locktime_blocks = 6 * 24;
/* They can have up to 3 days. */ /* They can have up to 3 days. */
config->rel_locktime_max = 2 * DAYS; config->locktime_max = 3 * 6 * 24;
/* We're fairly trusting, under normal circumstances. */ /* We're fairly trusting, under normal circumstances. */
config->anchor_confirms = 3; config->anchor_confirms = 3;
@ -152,9 +148,9 @@ static void default_config(struct config *config)
config->closing_fee_rate = 20000; config->closing_fee_rate = 20000;
/* Don't bother me unless I have 6 hours to collect. */ /* Don't bother me unless I have 6 hours to collect. */
config->min_expiry = 6 * HOURS; config->min_htlc_expiry = 6 * 6;
/* Don't lock up channel for more than 5 days. */ /* Don't lock up channel for more than 5 days. */
config->max_expiry = 5 * DAYS; config->max_htlc_expiry = 5 * 6 * 24;
config->poll_time = time_from_sec(30); config->poll_time = time_from_sec(30);

14
daemon/lightningd.h

@ -14,11 +14,11 @@ struct config {
/* Are we on testnet? */ /* Are we on testnet? */
bool testnet; bool testnet;
/* How long do we want them to lock up their funds? (seconds) */ /* How long do we want them to lock up their funds? (blocks) */
u32 rel_locktime; u32 locktime_blocks;
/* How long do we let them lock up our funds? (seconds) */ /* How long do we let them lock up our funds? (blocks) */
u32 rel_locktime_max; u32 locktime_max;
/* How many confirms until we consider an anchor "settled". */ /* How many confirms until we consider an anchor "settled". */
u32 anchor_confirms; u32 anchor_confirms;
@ -38,13 +38,13 @@ struct config {
/* What fee we use for the closing transaction (satoshis/kb) */ /* What fee we use for the closing transaction (satoshis/kb) */
u64 closing_fee_rate; u64 closing_fee_rate;
/* Minimum/maximum time for an expiring HTLC (seconds). */ /* Minimum/maximum time for an expiring HTLC (blocks). */
u32 min_expiry, max_expiry; u32 min_htlc_expiry, max_htlc_expiry;
/* How long between polling bitcoind. */ /* How long between polling bitcoind. */
struct timerel poll_time; struct timerel poll_time;
/* How long between changing commit and sending COMMIT message.. */ /* How long between changing commit and sending COMMIT message. */
struct timerel commit_time; struct timerel commit_time;
}; };

21
daemon/packets.c

@ -106,8 +106,8 @@ void queue_pkt_open(struct peer *peer, OpenChannel__AnchorOffer anchor)
o->final_key = pubkey_to_proto(o, &peer->local.finalkey); o->final_key = pubkey_to_proto(o, &peer->local.finalkey);
o->delay = tal(o, Locktime); o->delay = tal(o, Locktime);
locktime__init(o->delay); locktime__init(o->delay);
o->delay->locktime_case = LOCKTIME__LOCKTIME_SECONDS; o->delay->locktime_case = LOCKTIME__LOCKTIME_BLOCKS;
o->delay->seconds = rel_locktime_to_seconds(&peer->local.locktime); o->delay->blocks = rel_locktime_to_blocks(&peer->local.locktime);
o->initial_fee_rate = peer->local.commit_fee_rate; o->initial_fee_rate = peer->local.commit_fee_rate;
if (anchor == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR) if (anchor == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR)
assert(peer->local.offer_anchor == CMD_OPEN_WITH_ANCHOR); assert(peer->local.offer_anchor == CMD_OPEN_WITH_ANCHOR);
@ -201,8 +201,6 @@ void queue_pkt_htlc_add(struct peer *peer, const struct channel_htlc *htlc)
remote_changes_pending(peer); remote_changes_pending(peer);
peer_add_htlc_expiry(peer, &htlc->expiry);
queue_pkt(peer, PKT__PKT_UPDATE_ADD_HTLC, u); queue_pkt(peer, PKT__PKT_UPDATE_ADD_HTLC, u);
} }
@ -488,10 +486,9 @@ Pkt *accept_pkt_open(struct peer *peer, const Pkt *pkt)
if (!proto_to_rel_locktime(o->delay, &locktime)) if (!proto_to_rel_locktime(o->delay, &locktime))
return pkt_err(peer, "Invalid delay"); return pkt_err(peer, "Invalid delay");
/* FIXME: handle blocks in locktime */ if (o->delay->locktime_case != LOCKTIME__LOCKTIME_BLOCKS)
if (o->delay->locktime_case != LOCKTIME__LOCKTIME_SECONDS) return pkt_err(peer, "Delay in seconds not accepted");
return pkt_err(peer, "Delay in blocks not accepted"); if (o->delay->blocks > peer->dstate->config.locktime_max)
if (o->delay->seconds > peer->dstate->config.rel_locktime_max)
return pkt_err(peer, "Delay too great"); return pkt_err(peer, "Delay too great");
if (o->min_depth > peer->dstate->config.anchor_confirms_max) if (o->min_depth > peer->dstate->config.anchor_confirms_max)
return pkt_err(peer, "min_depth too great"); return pkt_err(peer, "min_depth too great");
@ -616,9 +613,8 @@ Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt)
if (!proto_to_abs_locktime(u->expiry, &expiry)) if (!proto_to_abs_locktime(u->expiry, &expiry))
return pkt_err(peer, "Invalid HTLC expiry"); return pkt_err(peer, "Invalid HTLC expiry");
/* FIXME: Handle block-based expiry! */ if (abs_locktime_is_seconds(&expiry))
if (!abs_locktime_is_seconds(&expiry)) return pkt_err(peer, "HTLC expiry in seconds not supported!");
return pkt_err(peer, "HTLC expiry in blocks not supported!");
/* BOLT #2: /* BOLT #2:
* *
@ -674,9 +670,6 @@ Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt)
stage.add.htlc = *htlc; stage.add.htlc = *htlc;
add_unacked(&peer->local, &stage); add_unacked(&peer->local, &stage);
peer_add_htlc_expiry(peer, &expiry);
/* FIXME: Fees must be sufficient. */ /* FIXME: Fees must be sufficient. */
return NULL; return NULL;
} }

132
daemon/peer.c

@ -753,10 +753,9 @@ static struct peer *new_peer(struct lightningd_state *dstate,
io_set_finish(conn, peer_disconnect, peer); io_set_finish(conn, peer_disconnect, peer);
peer->local.offer_anchor = offer_anchor; peer->local.offer_anchor = offer_anchor;
if (!seconds_to_rel_locktime(dstate->config.rel_locktime, if (!blocks_to_rel_locktime(dstate->config.locktime_blocks,
&peer->local.locktime)) &peer->local.locktime))
fatal("Invalid locktime configuration %u", fatal("Could not convert locktime_blocks");
dstate->config.rel_locktime);
peer->local.mindepth = dstate->config.anchor_confirms; peer->local.mindepth = dstate->config.anchor_confirms;
peer->local.commit_fee_rate = dstate->config.commitment_fee_rate; peer->local.commit_fee_rate = dstate->config.commitment_fee_rate;
@ -975,6 +974,35 @@ const struct json_command connect_command = {
"Returns an empty result on success" "Returns an empty result on success"
}; };
/* FIXME: Keep a timeout for each peer, in case they're unresponsive. */
/* FIXME: Make sure no HTLCs in any unrevoked commit tx are live. */
static void check_htlc_expiry(struct peer *peer)
{
size_t i;
u32 height = get_block_height(peer->dstate);
again:
/* Check their currently still-existing htlcs for expiry:
* We eliminate them from staging as we go. */
for (i = 0; i < tal_count(peer->remote.staging_cstate->side[THEIRS].htlcs); i++) {
struct channel_htlc *htlc = &peer->remote.staging_cstate->side[THEIRS].htlcs[i];
assert(!abs_locktime_is_seconds(&htlc->expiry));
/* We give it an extra block, to avoid the worst of the
* inter-node timing issues. */
if (height <= abs_locktime_to_blocks(&htlc->expiry))
continue;
/* This can fail only if we're in an error state. */
if (!command_htlc_fail(peer, htlc->id))
return;
goto again;
}
}
struct anchor_watch { struct anchor_watch {
struct peer *peer; struct peer *peer;
enum state_input depthok; enum state_input depthok;
@ -1002,6 +1030,9 @@ static void anchor_depthchange(struct peer *peer, unsigned int depth,
} else if (depth == 0) } else if (depth == 0)
/* FIXME: Report losses! */ /* FIXME: Report losses! */
fatal("Funding transaction was unspent!"); fatal("Funding transaction was unspent!");
/* Since this gets called on every new block, check HTLCs here. */
check_htlc_expiry(peer);
} }
/* Yay, segwit! We can just compare txids, even though we don't have both /* Yay, segwit! We can just compare txids, even though we don't have both
@ -1365,14 +1396,14 @@ static void our_htlc_depth(struct peer *peer,
bool our_commit, bool our_commit,
size_t i) size_t i)
{ {
u32 mediantime;
struct channel_htlc *h; struct channel_htlc *h;
u32 height;
/* Must be in a block. */ /* Must be in a block. */
if (depth == 0) if (depth == 0)
return; return;
mediantime = get_tip_mediantime(peer->dstate); height = get_block_height(peer->dstate);
h = htlc_by_index(peer->closing_onchain.ci, i); h = htlc_by_index(peer->closing_onchain.ci, i);
/* BOLT #onchain: /* BOLT #onchain:
@ -1384,18 +1415,11 @@ static void our_htlc_depth(struct peer *peer,
* `OP_CHECKSEQUENCEVERIFY` delay has passed. * `OP_CHECKSEQUENCEVERIFY` delay has passed.
*/ */
/* FIXME: Handle expiry in blocks. */ if (height < abs_locktime_to_blocks(&h->expiry))
if (mediantime < abs_locktime_to_seconds(&h->expiry))
return; return;
if (our_commit) { if (our_commit) {
u32 csv_timeout; if (depth < rel_locktime_to_blocks(&peer->remote.locktime))
/* FIXME: Handle CSV in blocks. */
csv_timeout = get_tx_mediantime(peer->dstate, txid)
+ rel_locktime_to_seconds(&peer->remote.locktime);
if (mediantime <= csv_timeout)
return; return;
} }
@ -1480,7 +1504,7 @@ static void their_htlc_depth(struct peer *peer,
const struct sha256_double *txid, const struct sha256_double *txid,
ptrint_t *pi) ptrint_t *pi)
{ {
u32 mediantime; u32 height;
struct channel_htlc *h; struct channel_htlc *h;
size_t i = ptr2int(pi); size_t i = ptr2int(pi);
@ -1488,7 +1512,7 @@ static void their_htlc_depth(struct peer *peer,
if (depth == 0) if (depth == 0)
return; return;
mediantime = get_tip_mediantime(peer->dstate); height = get_block_height(peer->dstate);
h = htlc_by_index(peer->closing_onchain.ci, i); h = htlc_by_index(peer->closing_onchain.ci, i);
/* BOLT #onchain: /* BOLT #onchain:
@ -1497,8 +1521,7 @@ static void their_htlc_depth(struct peer *peer,
* *irrevocably resolved*. * *irrevocably resolved*.
*/ */
/* FIXME: Handle expiry in blocks. */ if (height < abs_locktime_to_blocks(&h->expiry))
if (mediantime < abs_locktime_to_seconds(&h->expiry))
return; return;
peer->closing_onchain.resolved[i] = irrevocably_resolved(peer); peer->closing_onchain.resolved[i] = irrevocably_resolved(peer);
@ -1528,19 +1551,8 @@ static void our_main_output_depth(struct peer *peer,
const struct sha256_double *txid, const struct sha256_double *txid,
void *unused) void *unused)
{ {
u32 mediantime, csv_timeout; /* Not past CSV timeout? */
if (depth < rel_locktime_to_blocks(&peer->remote.locktime))
/* Not in block any more? */
if (depth == 0)
return;
mediantime = get_tip_mediantime(peer->dstate);
/* FIXME: Handle CSV in blocks. */
csv_timeout = get_tx_mediantime(peer->dstate, txid)
+ rel_locktime_to_seconds(&peer->remote.locktime);
if (mediantime <= csv_timeout)
return; return;
/* Already done? (FIXME: Delete after first time) */ /* Already done? (FIXME: Delete after first time) */
@ -2408,48 +2420,6 @@ const struct json_command getpeers_command = {
"Returns a 'peers' array" "Returns a 'peers' array"
}; };
/* FIXME: Keep a timeout for each peer, in case they're unresponsive. */
/* FIXME: Make sure no HTLCs in any unrevoked commit tx are live. */
static void check_htlc_expiry(struct peer *peer)
{
size_t i;
log_debug(peer->log, "Expiry timedout!");
/* Check their currently still-existing htlcs for expiry:
* We eliminate them from staging as we go. */
for (i = 0; i < tal_count(peer->remote.staging_cstate->side[THEIRS].htlcs); i++) {
struct channel_htlc *htlc = &peer->remote.staging_cstate->side[THEIRS].htlcs[i];
/* Not a seconds-based expiry? */
if (!abs_locktime_is_seconds(&htlc->expiry))
continue;
/* Not well-expired? */
if (controlled_time().ts.tv_sec - 30
< abs_locktime_to_seconds(&htlc->expiry))
continue;
/* This can fail only if we're in an error state. */
command_htlc_fail(peer, htlc->id);
return;
}
}
void peer_add_htlc_expiry(struct peer *peer,
const struct abs_locktime *expiry)
{
struct timeabs absexpiry;
/* Add 30 seconds to be sure peers agree on timeout. */
absexpiry.ts.tv_sec = abs_locktime_to_seconds(expiry) + 30;
absexpiry.ts.tv_nsec = 0;
new_abstimer(peer->dstate, peer, absexpiry, check_htlc_expiry, peer);
}
static void do_newhtlc(struct peer *peer, static void do_newhtlc(struct peer *peer,
struct channel_htlc *htlc, struct channel_htlc *htlc,
struct command *jsoncmd) struct command *jsoncmd)
@ -2553,21 +2523,21 @@ static void json_newhtlc(struct command *cmd,
return; return;
} }
if (!seconds_to_abs_locktime(expiry, &htlc.expiry)) { if (!blocks_to_abs_locktime(expiry, &htlc.expiry)) {
command_fail(cmd, "'%.*s' is not a valid number", command_fail(cmd, "'%.*s' is not a valid number block number",
(int)(expirytok->end - expirytok->start), (int)(expirytok->end - expirytok->start),
buffer + expirytok->start); buffer + expirytok->start);
return; return;
} }
if (abs_locktime_to_seconds(&htlc.expiry) < if (abs_locktime_to_blocks(&htlc.expiry) <
controlled_time().ts.tv_sec + peer->dstate->config.min_expiry) { get_block_height(peer->dstate) + peer->dstate->config.min_htlc_expiry) {
command_fail(cmd, "HTLC expiry too soon!"); command_fail(cmd, "HTLC expiry too soon!");
return; return;
} }
if (abs_locktime_to_seconds(&htlc.expiry) > if (abs_locktime_to_blocks(&htlc.expiry) >
controlled_time().ts.tv_sec + peer->dstate->config.max_expiry) { get_block_height(peer->dstate) + peer->dstate->config.max_htlc_expiry) {
command_fail(cmd, "HTLC expiry too far!"); command_fail(cmd, "HTLC expiry too far!");
return; return;
} }
@ -2589,7 +2559,7 @@ static void json_newhtlc(struct command *cmd,
const struct json_command newhtlc_command = { const struct json_command newhtlc_command = {
"newhtlc", "newhtlc",
json_newhtlc, json_newhtlc,
"Offer {peerid} an HTLC worth {msatoshis} in {expiry} (in seconds since Jan 1 1970) with {rhash}", "Offer {peerid} an HTLC worth {msatoshis} in {expiry} (block number) with {rhash}",
"Returns an empty result on success" "Returns an empty result on success"
}; };

5
daemon/peer.h

@ -82,7 +82,7 @@ struct peer_visible_state {
enum state_input offer_anchor; enum state_input offer_anchor;
/* Key for commitment tx inputs, then key for commitment tx outputs */ /* Key for commitment tx inputs, then key for commitment tx outputs */
struct pubkey commitkey, finalkey; struct pubkey commitkey, finalkey;
/* How long to they want the other's outputs locked (seconds) */ /* How long to they want the other's outputs locked (blocks) */
struct rel_locktime locktime; struct rel_locktime locktime;
/* Minimum depth of anchor before channel usable. */ /* Minimum depth of anchor before channel usable. */
unsigned int mindepth; unsigned int mindepth;
@ -244,9 +244,6 @@ void peer_update_complete(struct peer *peer);
/* Peer has completed open, or problem (if non-NULL). */ /* Peer has completed open, or problem (if non-NULL). */
void peer_open_complete(struct peer *peer, const char *problem); void peer_open_complete(struct peer *peer, const char *problem);
void peer_add_htlc_expiry(struct peer *peer,
const struct abs_locktime *expiry);
struct bitcoin_tx *peer_create_close_tx(struct peer *peer, u64 fee); struct bitcoin_tx *peer_create_close_tx(struct peer *peer, u64 fee);
uint64_t commit_tx_fee(const struct bitcoin_tx *commit, uint64_t commit_tx_fee(const struct bitcoin_tx *commit,

66
daemon/test/test.sh

@ -105,6 +105,11 @@ lcli2()
$LCLI2 "$@" $LCLI2 "$@"
} }
blockheight()
{
$CLI getblockcount
}
# Usage: <cmd to test>... # Usage: <cmd to test>...
check() check()
{ {
@ -235,18 +240,18 @@ fi
cat > $DIR1/config <<EOF cat > $DIR1/config <<EOF
log-level=debug log-level=debug
bitcoind-poll=1s bitcoind-poll=1s
min-expiry=900 min-htlc-expiry=6
bitcoin-datadir=$DATADIR bitcoin-datadir=$DATADIR
locktime=600 locktime-blocks=6
commit-time=$COMMIT_TIME commit-time=$COMMIT_TIME
EOF EOF
cat > $DIR2/config <<EOF cat > $DIR2/config <<EOF
log-level=debug log-level=debug
bitcoind-poll=1s bitcoind-poll=1s
min-expiry=900 min-htlc-expiry=6
bitcoin-datadir=$DATADIR bitcoin-datadir=$DATADIR
locktime=600 locktime-blocks=6
commit-time=$COMMIT_TIME commit-time=$COMMIT_TIME
EOF EOF
@ -371,13 +376,13 @@ if [ -n "$DIFFERENT_FEES" ]; then
check_status_single lcli1 $A_AMOUNT1 $A_FEE1 "" $B_AMOUNT $B_FEE "" check_status_single lcli1 $A_AMOUNT1 $A_FEE1 "" $B_AMOUNT $B_FEE ""
check_status_single lcli2 $B_AMOUNT $B_FEE "" $(($A_AMOUNT2)) $(($A_FEE2)) "" check_status_single lcli2 $B_AMOUNT $B_FEE "" $(($A_AMOUNT2)) $(($A_FEE2)) ""
EXPIRY=$(( $(date +%s) + 1000)) EXPIRY=$(( $(blockheight) + 10))
SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd
RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'` RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH
[ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2
[ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1
check_status_single lcli2 0 0 "" $(($AMOUNT - $HTLC_AMOUNT - $ONE_HTLCS_FEE2)) $(($ONE_HTLCS_FEE2)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' check_status_single lcli2 0 0 "" $(($AMOUNT - $HTLC_AMOUNT - $ONE_HTLCS_FEE2)) $(($ONE_HTLCS_FEE2)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH'" } '
lcli2 fulfillhtlc $ID1 $SECRET lcli2 fulfillhtlc $ID1 $SECRET
[ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1
[ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2
@ -412,7 +417,7 @@ check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# This is 10,000 satoshi, so not dust! # This is 10,000 satoshi, so not dust!
HTLC_AMOUNT=10000000 HTLC_AMOUNT=10000000
EXPIRY=$(( $(date +%s) + 1000)) EXPIRY=$(( $(blockheight) + 10))
SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd
RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'` RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
@ -438,7 +443,7 @@ if [ -n "$MANUALCOMMIT" ]; then
A_FEE=$(($A_FEE + $EXTRA_FEE)) A_FEE=$(($A_FEE + $EXTRA_FEE))
# Node 2 has it committed. # Node 2 has it committed.
check_status_single lcli2 $B_AMOUNT $B_FEE "" $A_AMOUNT $A_FEE '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' check_status_single lcli2 $B_AMOUNT $B_FEE "" $A_AMOUNT $A_FEE '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH'" } '
# There should be no "both committed" here yet # There should be no "both committed" here yet
if lcli1 getlog debug | $FGREP "Both committed"; then if lcli1 getlog debug | $FGREP "Both committed"; then
@ -462,7 +467,7 @@ else
fi fi
# Both should have committed tx. # Both should have committed tx.
check_status $A_AMOUNT $A_FEE '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $B_AMOUNT $B_FEE "" check_status $A_AMOUNT $A_FEE '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $B_AMOUNT $B_FEE ""
if [ -n "$STEAL" ]; then if [ -n "$STEAL" ]; then
$LCLI1 dev-signcommit $ID2 >&2 $LCLI1 dev-signcommit $ID2 >&2
@ -484,19 +489,18 @@ if [ -n "$DUMP_ONCHAIN" ]; then
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL check_peerstate lcli2 STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL
# both still know about htlc # both still know about htlc
check_status $A_AMOUNT $A_FEE '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $B_AMOUNT $B_FEE "" check_status $A_AMOUNT $A_FEE '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $B_AMOUNT $B_FEE ""
# Move bitcoind's time so CSV timeout has expired. # Generate 6 blocks so CSV timeout has expired.
$CLI setmocktime $((`date +%s` + 600))
$CLI generate 6 $CLI generate 6
# Now, lcli1 should spend its own output. # Now, lcli1 should spend its own output.
check_tx_spend lcli1 check_tx_spend lcli1
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_OUR_UNILATERAL check_peerstate lcli1 STATE_CLOSE_ONCHAIN_OUR_UNILATERAL
# Move bitcoind's time so HTLC has expired. while [ $(blockheight) != $EXPIRY ]; do
$CLI setmocktime $(($EXPIRY + 1)) $CLI generate 1
$CLI generate 6 done
# lcli1 should have gotten HTLC back. # lcli1 should have gotten HTLC back.
check_tx_spend lcli1 check_tx_spend lcli1
@ -549,7 +553,7 @@ lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH
# Check channel status # Check channel status
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT))
A_FEE=$(($A_FEE + $EXTRA_FEE)) A_FEE=$(($A_FEE + $EXTRA_FEE))
check_status $A_AMOUNT $A_FEE '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $B_AMOUNT $B_FEE "" check_status $A_AMOUNT $A_FEE '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $B_AMOUNT $B_FEE ""
lcli2 failhtlc $ID1 $RHASH lcli2 failhtlc $ID1 $RHASH
[ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1
@ -569,17 +573,23 @@ lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH
# Check channel status # Check channel status
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT))
A_FEE=$(($A_FEE + $EXTRA_FEE)) A_FEE=$(($A_FEE + $EXTRA_FEE))
check_status $A_AMOUNT $A_FEE '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $B_AMOUNT $B_FEE "" check_status $A_AMOUNT $A_FEE '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $B_AMOUNT $B_FEE ""
# Make sure node1 accepts the expiry packet. # Make sure node1 accepts the expiry packet.
MOCKTIME=$(($EXPIRY)) while [ $(blockheight) != $EXPIRY ]; do
lcli1 dev-mocktime $MOCKTIME $CLI generate 1
done
# This should make node2 send it. # This should make node2 send it.
MOCKTIME=$(($MOCKTIME + 31)) $CLI generate 1
lcli2 dev-mocktime $MOCKTIME
[ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 if [ -n "$MANUALCOMMIT" ]; then
[ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2 # Don't commit until it's noticed the new block
check_staged lcli2 remote 1
lcli2 commit $ID1
lcli1 commit $ID2
fi
# Back to how we were before. # Back to how we were before.
A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT)) A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT))
@ -608,13 +618,13 @@ if [ -n "$STEAL" ]; then
fi fi
# First, give more money to node2, so it can offer HTLCs. # First, give more money to node2, so it can offer HTLCs.
EXPIRY=$(($MOCKTIME + 1000)) EXPIRY=$(( $(blockheight) + 10))
HTLC_AMOUNT=100000000 HTLC_AMOUNT=100000000
lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH
[ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2
[ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $B_AMOUNT $B_FEE "" check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $B_AMOUNT $B_FEE ""
lcli2 fulfillhtlc $ID1 $SECRET lcli2 fulfillhtlc $ID1 $SECRET
[ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1
@ -640,7 +650,7 @@ lcli2 newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH2
[ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1
[ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $(($B_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH2'" } ' check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' $(($B_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH2'" } '
if [ -n "$CLOSE_WITH_HTLCS" ]; then if [ -n "$CLOSE_WITH_HTLCS" ]; then
# Now begin close # Now begin close
@ -695,7 +705,7 @@ lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH
# Make sure node1 sends commit (in the background, since it will block!) # Make sure node1 sends commit (in the background, since it will block!)
[ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2 & [ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2 &
# node2 will consider this committed. # 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)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' 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)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH'" } '
# Now send another offer, and enable node2 output. # Now send another offer, and enable node2 output.
lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH2 lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH2
@ -706,7 +716,7 @@ lcli2 dev-output $ID1 true
[ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1
# Both sides should be committed to htlcs # Both sides should be committed to htlcs
check_status $(($A_AMOUNT - $HTLC_AMOUNT*2 - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH'" }, { "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH2'" } ' $(($B_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) "" check_status $(($A_AMOUNT - $HTLC_AMOUNT*2 - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) '{ "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH'" }, { "msatoshis" : '$HTLC_AMOUNT', "expiry" : { "block" : '$EXPIRY' }, "rhash" : "'$RHASH2'" } ' $(($B_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) ""
# Node2 collects the HTLCs. # Node2 collects the HTLCs.
lcli2 fulfillhtlc $ID1 $SECRET lcli2 fulfillhtlc $ID1 $SECRET

Loading…
Cancel
Save