diff --git a/daemon/lightningd.c b/daemon/lightningd.c index 856314126..d38b5e5db 100644 --- a/daemon/lightningd.c +++ b/daemon/lightningd.c @@ -88,21 +88,31 @@ static void config_register_opts(struct lightningd_state *dstate) opt_register_arg("--closing-fee", opt_set_u64, opt_show_u64, &dstate->config.closing_fee, "Satoshis to use for mutual close transaction fee"); + 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("--bitcoind-poll", opt_set_u32, opt_show_u32, &dstate->config.poll_seconds, "Seconds between polling for new transactions"); } +#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 = 60 * 60 * 24; + config->rel_locktime = 1 * DAYS; /* They can have up to 3 days. */ - config->rel_locktime_max = 60 * 60 * 24 * 3; + config->rel_locktime_max = 2 * DAYS; /* We're fairly trusting, under normal circumstances. */ config->anchor_confirms = 3; @@ -120,7 +130,12 @@ static void default_config(struct config *config) /* Use this for mutual close. */ config->closing_fee = 10000; - + + /* Don't bother me unless I have 6 hours to collect. */ + config->min_expiry = 6 * HOURS; + /* Don't lock up channel for more than 5 days. */ + config->max_expiry = 5 * DAYS; + config->poll_seconds = 30; } diff --git a/daemon/lightningd.h b/daemon/lightningd.h index 8713cf6d4..6f56acfec 100644 --- a/daemon/lightningd.h +++ b/daemon/lightningd.h @@ -35,6 +35,9 @@ struct config { /* What fee we use for the closing transaction (satoshis) */ u64 closing_fee; + /* Minimum/maximum time for an expiring HTLC (seconds). */ + u32 min_expiry, max_expiry; + /* How long (seconds) between polling bitcoind. */ u32 poll_seconds; }; diff --git a/daemon/packets.c b/daemon/packets.c index 9819072d5..36f8f82fd 100644 --- a/daemon/packets.c +++ b/daemon/packets.c @@ -1,5 +1,6 @@ #include "bitcoin/script.h" #include "bitcoin/tx.h" +#include "controlled_time.h" #include "find_p2sh_out.h" #include "lightningd.h" #include "log.h" @@ -386,7 +387,19 @@ Pkt *accept_pkt_open_commit_sig(const tal_t *ctx, return NULL; } - + +static Pkt *decline_htlc(const tal_t *ctx, const char *why) +{ + UpdateDeclineHtlc *d = tal(ctx, UpdateDeclineHtlc); + + update_decline_htlc__init(d); + /* FIXME: Define why in protocol! */ + d->reason_case = UPDATE_DECLINE_HTLC__REASON_CANNOT_ROUTE; + d->cannot_route = true; + + return make_pkt(ctx, PKT__PKT_UPDATE_DECLINE_HTLC, d); +} + Pkt *accept_pkt_htlc_update(const tal_t *ctx, struct peer *peer, const Pkt *pkt, Pkt **decline) @@ -403,6 +416,26 @@ Pkt *accept_pkt_htlc_update(const tal_t *ctx, err = pkt_err(ctx, "Invalid HTLC expiry"); goto fail; } + + /* FIXME: Handle block-based expiry! */ + if (!abs_locktime_is_seconds(&cur->htlc->expiry)) { + *decline = decline_htlc(ctx, + "HTLC expiry in blocks not supported!"); + goto decline; + } + + if (abs_locktime_to_seconds(&cur->htlc->expiry) < + controlled_time().ts.tv_sec + peer->dstate->config.min_expiry) { + *decline = decline_htlc(ctx, "HTLC expiry too soon!"); + goto decline; + } + + if (abs_locktime_to_seconds(&cur->htlc->expiry) > + controlled_time().ts.tv_sec + peer->dstate->config.max_expiry) { + *decline = decline_htlc(ctx, "HTLC expiry too far!"); + goto decline; + } + cur->cstate = copy_funding(cur, peer->cstate); if (!funding_delta(peer->them.offer_anchor == CMD_OPEN_WITH_ANCHOR, peer->anchor.satoshis, @@ -434,6 +467,11 @@ Pkt *accept_pkt_htlc_update(const tal_t *ctx, fail: tal_free(cur); return err; + +decline: + assert(*decline); + tal_free(cur); + return NULL; }; Pkt *accept_pkt_htlc_routefail(const tal_t *ctx, diff --git a/daemon/peer.c b/daemon/peer.c index 66eefc9ac..f51d4d67d 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -1,6 +1,7 @@ #include "bitcoind.h" #include "close_tx.h" #include "commit_tx.h" +#include "controlled_time.h" #include "cryptopkt.h" #include "dns.h" #include "find_p2sh_out.h" @@ -715,7 +716,9 @@ void peer_unexpected_pkt(struct peer *peer, const Pkt *pkt) /* Someone declined our HTLC: details in pkt (we will also get CMD_FAIL) */ void peer_htlc_declined(struct peer *peer, const Pkt *pkt) { - FIXME_STUB(peer); + log_unusual(peer->log, "Peer declined htlc, reason %i", + pkt->update_decline_htlc->reason_case); + peer->current_htlc = tal_free(peer->current_htlc); } /* Called when their update overrides our update cmd. */ @@ -1157,6 +1160,19 @@ static void json_newhtlc(struct command *cmd, buffer + expirytok->start); return; } + + if (abs_locktime_to_seconds(&newhtlc->htlc->expiry) < + controlled_time().ts.tv_sec + peer->dstate->config.min_expiry) { + command_fail(cmd, "HTLC expiry too soon!"); + return; + } + + if (abs_locktime_to_seconds(&newhtlc->htlc->expiry) > + controlled_time().ts.tv_sec + peer->dstate->config.max_expiry) { + command_fail(cmd, "HTLC expiry too far!"); + return; + } + if (!hex_decode(buffer + rhashtok->start, rhashtok->end - rhashtok->start, &newhtlc->htlc->rhash, diff --git a/daemon/test/test.sh b/daemon/test/test.sh index 1705e95b5..35b8e4255 100755 --- a/daemon/test/test.sh +++ b/daemon/test/test.sh @@ -53,8 +53,8 @@ check_status() trap "echo Results in $DIR1 and $DIR2" EXIT mkdir $DIR1 $DIR2 -$PREFIX1 ../daemon/lightningd --log-level=debug --bitcoind-poll=1 --lightning-dir=$DIR1 > $REDIR1 & -$PREFIX2 ../daemon/lightningd --log-level=debug --bitcoind-poll=1 --lightning-dir=$DIR2 > $REDIR2 & +$PREFIX1 ../daemon/lightningd --log-level=debug --bitcoind-poll=1 --min-expiry=900 --lightning-dir=$DIR1 > $REDIR1 & +$PREFIX2 ../daemon/lightningd --log-level=debug --bitcoind-poll=1 --min-expiry=900 --lightning-dir=$DIR2 > $REDIR2 & i=0 while ! $LCLI1 getlog | grep Hello; do