diff --git a/daemon/chaintopology.c b/daemon/chaintopology.c index dadd939c3..e06319278 100644 --- a/daemon/chaintopology.c +++ b/daemon/chaintopology.c @@ -452,6 +452,11 @@ u32 get_tip_mediantime(struct lightningd_state *dstate) 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) { dstate->topology = tal(dstate, struct topology); diff --git a/daemon/chaintopology.h b/daemon/chaintopology.h index f621b2588..75977bd15 100644 --- a/daemon/chaintopology.h +++ b/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. */ 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) */ void broadcast_tx(struct peer *peer, const struct bitcoin_tx *tx); diff --git a/daemon/lightningd.c b/daemon/lightningd.c index 3f5667193..2e7faa0e1 100644 --- a/daemon/lightningd.c +++ b/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) { - opt_register_arg("--locktime", opt_set_u32, opt_show_u32, - &dstate->config.rel_locktime, - "Seconds before peer can unilaterally spend funds"); - opt_register_arg("--max-locktime", opt_set_u32, opt_show_u32, - &dstate->config.rel_locktime_max, + opt_register_arg("--locktime-blocks", opt_set_u32, opt_show_u32, + &dstate->config.locktime_blocks, + "Blocks before peer can unilaterally spend funds"); + opt_register_arg("--max-locktime-blocks", opt_set_u32, opt_show_u32, + &dstate->config.locktime_max, "Maximum seconds peer can lock up our funds"); opt_register_arg("--anchor-confirms", opt_set_u32, opt_show_u32, &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, &dstate->config.closing_fee_rate, "Satoshis to use for mutual close transaction fee (per kb)"); - opt_register_arg("--min-expiry", opt_set_u32, opt_show_u32, - &dstate->config.min_expiry, - "Minimum number of seconds to accept an HTLC before expiry"); - opt_register_arg("--max-expiry", opt_set_u32, opt_show_u32, - &dstate->config.max_expiry, - "Maximum number of seconds to accept an HTLC before expiry"); + opt_register_arg("--min-htlc-expiry", opt_set_u32, opt_show_u32, + &dstate->config.min_htlc_expiry, + "Minimum number of blocks to accept an HTLC before expiry"); + opt_register_arg("--max-htlc-expiry", opt_set_u32, opt_show_u32, + &dstate->config.max_htlc_expiry, + "Maximum number of blocks to accept an HTLC before expiry"); opt_register_arg("--bitcoind-poll", opt_set_time, opt_show_time, &dstate->config.poll_time, "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"); } -#define MINUTES 60 -#define HOURS (60 * MINUTES) -#define DAYS (24 * HOURS) - static void default_config(struct config *config) { /* aka. "Dude, where's my coins?" */ config->testnet = true; - /* One day to catch cheating attempts. */ - config->rel_locktime = 1 * DAYS; + /* ~one day to catch cheating attempts. */ + config->locktime_blocks = 6 * 24; /* 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. */ config->anchor_confirms = 3; @@ -152,9 +148,9 @@ static void default_config(struct config *config) config->closing_fee_rate = 20000; /* 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. */ - config->max_expiry = 5 * DAYS; + config->max_htlc_expiry = 5 * 6 * 24; config->poll_time = time_from_sec(30); diff --git a/daemon/lightningd.h b/daemon/lightningd.h index 2dd982983..ff169ed73 100644 --- a/daemon/lightningd.h +++ b/daemon/lightningd.h @@ -14,11 +14,11 @@ struct config { /* Are we on testnet? */ bool testnet; - /* How long do we want them to lock up their funds? (seconds) */ - u32 rel_locktime; + /* How long do we want them to lock up their funds? (blocks) */ + u32 locktime_blocks; - /* How long do we let them lock up our funds? (seconds) */ - u32 rel_locktime_max; + /* How long do we let them lock up our funds? (blocks) */ + u32 locktime_max; /* How many confirms until we consider an anchor "settled". */ u32 anchor_confirms; @@ -38,13 +38,13 @@ struct config { /* What fee we use for the closing transaction (satoshis/kb) */ u64 closing_fee_rate; - /* Minimum/maximum time for an expiring HTLC (seconds). */ - u32 min_expiry, max_expiry; + /* Minimum/maximum time for an expiring HTLC (blocks). */ + u32 min_htlc_expiry, max_htlc_expiry; /* How long between polling bitcoind. */ 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; }; diff --git a/daemon/packets.c b/daemon/packets.c index 225cab57f..257024363 100644 --- a/daemon/packets.c +++ b/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->delay = tal(o, Locktime); locktime__init(o->delay); - o->delay->locktime_case = LOCKTIME__LOCKTIME_SECONDS; - o->delay->seconds = rel_locktime_to_seconds(&peer->local.locktime); + 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 (anchor == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_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); - peer_add_htlc_expiry(peer, &htlc->expiry); - 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)) return pkt_err(peer, "Invalid delay"); - /* FIXME: handle blocks in locktime */ - if (o->delay->locktime_case != LOCKTIME__LOCKTIME_SECONDS) - return pkt_err(peer, "Delay in blocks not accepted"); - if (o->delay->seconds > peer->dstate->config.rel_locktime_max) + 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 too great"); if (o->min_depth > peer->dstate->config.anchor_confirms_max) 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)) return pkt_err(peer, "Invalid HTLC expiry"); - /* FIXME: Handle block-based expiry! */ - if (!abs_locktime_is_seconds(&expiry)) - return pkt_err(peer, "HTLC expiry in blocks not supported!"); + if (abs_locktime_is_seconds(&expiry)) + return pkt_err(peer, "HTLC expiry in seconds not supported!"); /* BOLT #2: * @@ -674,9 +670,6 @@ Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt) stage.add.htlc = *htlc; add_unacked(&peer->local, &stage); - peer_add_htlc_expiry(peer, &expiry); - - /* FIXME: Fees must be sufficient. */ return NULL; } diff --git a/daemon/peer.c b/daemon/peer.c index 8403c3898..4de9f11be 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -753,10 +753,9 @@ static struct peer *new_peer(struct lightningd_state *dstate, io_set_finish(conn, peer_disconnect, peer); peer->local.offer_anchor = offer_anchor; - if (!seconds_to_rel_locktime(dstate->config.rel_locktime, - &peer->local.locktime)) - fatal("Invalid locktime configuration %u", - dstate->config.rel_locktime); + if (!blocks_to_rel_locktime(dstate->config.locktime_blocks, + &peer->local.locktime)) + fatal("Could not convert locktime_blocks"); peer->local.mindepth = dstate->config.anchor_confirms; 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" }; +/* 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 peer *peer; enum state_input depthok; @@ -1002,6 +1030,9 @@ static void anchor_depthchange(struct peer *peer, unsigned int depth, } else if (depth == 0) /* FIXME: Report losses! */ 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 @@ -1365,14 +1396,14 @@ static void our_htlc_depth(struct peer *peer, bool our_commit, size_t i) { - u32 mediantime; struct channel_htlc *h; + u32 height; /* Must be in a block. */ if (depth == 0) return; - mediantime = get_tip_mediantime(peer->dstate); + height = get_block_height(peer->dstate); h = htlc_by_index(peer->closing_onchain.ci, i); /* BOLT #onchain: @@ -1384,18 +1415,11 @@ static void our_htlc_depth(struct peer *peer, * `OP_CHECKSEQUENCEVERIFY` delay has passed. */ - /* FIXME: Handle expiry in blocks. */ - if (mediantime < abs_locktime_to_seconds(&h->expiry)) + if (height < abs_locktime_to_blocks(&h->expiry)) return; if (our_commit) { - u32 csv_timeout; - - /* FIXME: Handle CSV in blocks. */ - csv_timeout = get_tx_mediantime(peer->dstate, txid) - + rel_locktime_to_seconds(&peer->remote.locktime); - - if (mediantime <= csv_timeout) + if (depth < rel_locktime_to_blocks(&peer->remote.locktime)) return; } @@ -1480,7 +1504,7 @@ static void their_htlc_depth(struct peer *peer, const struct sha256_double *txid, ptrint_t *pi) { - u32 mediantime; + u32 height; struct channel_htlc *h; size_t i = ptr2int(pi); @@ -1488,7 +1512,7 @@ static void their_htlc_depth(struct peer *peer, if (depth == 0) return; - mediantime = get_tip_mediantime(peer->dstate); + height = get_block_height(peer->dstate); h = htlc_by_index(peer->closing_onchain.ci, i); /* BOLT #onchain: @@ -1497,8 +1521,7 @@ static void their_htlc_depth(struct peer *peer, * *irrevocably resolved*. */ - /* FIXME: Handle expiry in blocks. */ - if (mediantime < abs_locktime_to_seconds(&h->expiry)) + if (height < abs_locktime_to_blocks(&h->expiry)) return; 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, void *unused) { - u32 mediantime, csv_timeout; - - /* 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) + /* Not past CSV timeout? */ + if (depth < rel_locktime_to_blocks(&peer->remote.locktime)) return; /* Already done? (FIXME: Delete after first time) */ @@ -2408,48 +2420,6 @@ const struct json_command getpeers_command = { "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, struct channel_htlc *htlc, struct command *jsoncmd) @@ -2553,21 +2523,21 @@ static void json_newhtlc(struct command *cmd, return; } - if (!seconds_to_abs_locktime(expiry, &htlc.expiry)) { - command_fail(cmd, "'%.*s' is not a valid number", + if (!blocks_to_abs_locktime(expiry, &htlc.expiry)) { + command_fail(cmd, "'%.*s' is not a valid number block number", (int)(expirytok->end - expirytok->start), buffer + expirytok->start); return; } - if (abs_locktime_to_seconds(&htlc.expiry) < - controlled_time().ts.tv_sec + peer->dstate->config.min_expiry) { + if (abs_locktime_to_blocks(&htlc.expiry) < + get_block_height(peer->dstate) + peer->dstate->config.min_htlc_expiry) { command_fail(cmd, "HTLC expiry too soon!"); return; } - if (abs_locktime_to_seconds(&htlc.expiry) > - controlled_time().ts.tv_sec + peer->dstate->config.max_expiry) { + if (abs_locktime_to_blocks(&htlc.expiry) > + get_block_height(peer->dstate) + peer->dstate->config.max_htlc_expiry) { command_fail(cmd, "HTLC expiry too far!"); return; } @@ -2589,7 +2559,7 @@ static void json_newhtlc(struct command *cmd, const struct json_command newhtlc_command = { "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" }; diff --git a/daemon/peer.h b/daemon/peer.h index 77335a101..6333fcfc4 100644 --- a/daemon/peer.h +++ b/daemon/peer.h @@ -82,7 +82,7 @@ struct peer_visible_state { enum state_input 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 (seconds) */ + /* 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; @@ -244,9 +244,6 @@ void peer_update_complete(struct peer *peer); /* Peer has completed open, or problem (if non-NULL). */ 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); uint64_t commit_tx_fee(const struct bitcoin_tx *commit, diff --git a/daemon/test/test.sh b/daemon/test/test.sh index dcfe53c7a..2794bb0cd 100755 --- a/daemon/test/test.sh +++ b/daemon/test/test.sh @@ -105,6 +105,11 @@ lcli2() $LCLI2 "$@" } +blockheight() +{ + $CLI getblockcount +} + # Usage: ... check() { @@ -235,18 +240,18 @@ fi cat > $DIR1/config < $DIR2/config <&2 @@ -484,19 +489,18 @@ if [ -n "$DUMP_ONCHAIN" ]; then check_peerstate lcli2 STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL # 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. - $CLI setmocktime $((`date +%s` + 600)) + # Generate 6 blocks so CSV timeout has expired. $CLI generate 6 # Now, lcli1 should spend its own output. check_tx_spend lcli1 check_peerstate lcli1 STATE_CLOSE_ONCHAIN_OUR_UNILATERAL - # Move bitcoind's time so HTLC has expired. - $CLI setmocktime $(($EXPIRY + 1)) - $CLI generate 6 + while [ $(blockheight) != $EXPIRY ]; do + $CLI generate 1 + done # lcli1 should have gotten HTLC back. check_tx_spend lcli1 @@ -549,7 +553,7 @@ lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH # Check channel status A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) 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 [ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 @@ -569,17 +573,23 @@ lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH # Check channel status A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) 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. -MOCKTIME=$(($EXPIRY)) -lcli1 dev-mocktime $MOCKTIME +while [ $(blockheight) != $EXPIRY ]; do + $CLI generate 1 +done # This should make node2 send it. -MOCKTIME=$(($MOCKTIME + 31)) -lcli2 dev-mocktime $MOCKTIME -[ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 -[ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2 +$CLI generate 1 + +if [ -n "$MANUALCOMMIT" ]; then + # 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. A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT)) @@ -608,13 +618,13 @@ if [ -n "$STEAL" ]; then fi # First, give more money to node2, so it can offer HTLCs. -EXPIRY=$(($MOCKTIME + 1000)) +EXPIRY=$(( $(blockheight) + 10)) HTLC_AMOUNT=100000000 lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH [ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2 [ ! -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 [ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 @@ -640,7 +650,7 @@ lcli2 newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH2 [ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 [ ! -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 # 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!) [ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2 & # 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. lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH2 @@ -706,7 +716,7 @@ lcli2 dev-output $ID1 true [ ! -n "$MANUALCOMMIT" ] || lcli2 commit $ID1 # 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. lcli2 fulfillhtlc $ID1 $SECRET