From 2346f6bf1495540f43422b14604b2822ac54e161 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 22 Jan 2016 06:45:28 +1030 Subject: [PATCH] daemon: routefail command. This should be renamed: it's actually any kind of after-the-fact failure. Signed-off-by: Rusty Russell --- daemon/jsonrpc.c | 1 + daemon/jsonrpc.h | 1 + daemon/packets.c | 54 ++++++++++++++++++++++++++-- daemon/peer.c | 86 +++++++++++++++++++++++++++++++++++++++++++++ daemon/test/test.sh | 11 ++++++ 5 files changed, 151 insertions(+), 2 deletions(-) diff --git a/daemon/jsonrpc.c b/daemon/jsonrpc.c index 51d489c82..e5dcbd259 100644 --- a/daemon/jsonrpc.c +++ b/daemon/jsonrpc.c @@ -240,6 +240,7 @@ static const struct json_command *cmdlist[] = { &getpeers_command, &newhtlc_command, &fulfillhtlc_command, + &failhtlc_command, /* Developer/debugging options. */ &echo_command, &rhash_command, diff --git a/daemon/jsonrpc.h b/daemon/jsonrpc.h index 461c20544..3b7da4e72 100644 --- a/daemon/jsonrpc.h +++ b/daemon/jsonrpc.h @@ -60,4 +60,5 @@ extern const struct json_command connect_command; extern const struct json_command getpeers_command; extern const struct json_command newhtlc_command; extern const struct json_command fulfillhtlc_command; +extern const struct json_command failhtlc_command; #endif /* LIGHTNING_DAEMON_JSONRPC_H */ diff --git a/daemon/packets.c b/daemon/packets.c index 4e624d897..9819072d5 100644 --- a/daemon/packets.c +++ b/daemon/packets.c @@ -168,7 +168,14 @@ Pkt *pkt_htlc_timedout(const tal_t *ctx, const struct peer *peer, Pkt *pkt_htlc_routefail(const tal_t *ctx, const struct peer *peer, const struct htlc_progress *htlc_prog) { - FIXME_STUB(peer); + UpdateRoutefailHtlc *f = tal(ctx, UpdateRoutefailHtlc); + + update_routefail_htlc__init(f); + + f->revocation_hash = sha256_to_proto(f, &htlc_prog->our_revocation_hash); + f->r_hash = sha256_to_proto(f, &htlc_prog->htlc->rhash); + + return make_pkt(ctx, PKT__PKT_UPDATE_ROUTEFAIL_HTLC, f); } Pkt *pkt_update_accept(const tal_t *ctx, const struct peer *peer) @@ -432,7 +439,50 @@ fail: Pkt *accept_pkt_htlc_routefail(const tal_t *ctx, struct peer *peer, const Pkt *pkt) { - FIXME_STUB(peer); + const UpdateRoutefailHtlc *f = pkt->update_routefail_htlc; + struct htlc_progress *cur = tal(peer, struct htlc_progress); + Pkt *err; + size_t i; + struct sha256 rhash; + + proto_to_sha256(f->revocation_hash, &cur->their_revocation_hash); + proto_to_sha256(f->r_hash, &rhash); + + i = funding_find_htlc(&peer->cstate->a, &rhash); + if (i == tal_count(peer->cstate->a.htlcs)) { + err = pkt_err(ctx, "Unknown HTLC"); + goto fail; + } + + cur->htlc = &peer->cstate->a.htlcs[i]; + + /* Removing it should not fail: we regain HTLC amount */ + cur->cstate = copy_funding(cur, peer->cstate); + if (!funding_delta(peer->us.offer_anchor == CMD_OPEN_WITH_ANCHOR, + peer->anchor.satoshis, + 0, -cur->htlc->msatoshis, + &cur->cstate->a, &cur->cstate->b)) { + fatal("Unexpected failure fulfilling HTLC of %"PRIu64 + " milli-satoshis", cur->htlc->msatoshis); + } + funding_remove_htlc(&cur->cstate->a, i); + + peer_get_revocation_hash(peer, peer->num_htlcs+1, + &cur->our_revocation_hash); + + /* Now we create the commit tx pair. */ + make_commit_txs(cur, peer, &cur->our_revocation_hash, + &cur->their_revocation_hash, + cur->cstate, + &cur->our_commit, &cur->their_commit); + + assert(!peer->current_htlc); + peer->current_htlc = cur; + return NULL; + +fail: + tal_free(cur); + return err; } Pkt *accept_pkt_htlc_timedout(const tal_t *ctx, diff --git a/daemon/peer.c b/daemon/peer.c index 9b4718966..f0e922f0d 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -1157,3 +1157,89 @@ const struct json_command fulfillhtlc_command = { "Redeem htlc proposed by {id} using {r}", "Returns an empty result on success" }; + + +static void json_failhtlc(struct command *cmd, + const char *buffer, const jsmntok_t *params) +{ + struct peer *peer; + jsmntok_t *idtok, *rhashtok; + struct pubkey id; + struct sha256 rhash; + struct htlc_progress *cur; + size_t i; + + json_get_params(buffer, params, + "id", &idtok, + "rhash", &rhashtok, + NULL); + + if (!idtok || !rhashtok) { + command_fail(cmd, "Need id and rhash"); + return; + } + + if (!pubkey_from_hexstr(cmd->dstate->secpctx, + buffer + idtok->start, + idtok->end - idtok->start, &id)) { + command_fail(cmd, "Not a valid id"); + return; + } + peer = find_peer(cmd->dstate, &id); + if (!peer) { + command_fail(cmd, "Could not find peer with that id"); + return; + } + + /* Attach to cmd until it's complete. */ + cur = tal(cmd, struct htlc_progress); + + if (!hex_decode(buffer + rhashtok->start, + rhashtok->end - rhashtok->start, + &rhash, sizeof(rhash))) { + command_fail(cmd, "'%.*s' is not a valid sha256 preimage", + (int)(rhashtok->end - rhashtok->start), + buffer + rhashtok->start); + return; + } + + i = funding_find_htlc(&peer->cstate->b, &rhash); + if (i == tal_count(peer->cstate->b.htlcs)) { + command_fail(cmd, "'%.*s' htlc not found", + (int)(rhashtok->end - rhashtok->start), + buffer + rhashtok->start); + return; + } + cur->htlc = &peer->cstate->b.htlcs[i]; + + /* Removing it should not fail: they gain HTLC amount */ + cur->cstate = copy_funding(cur, peer->cstate); + if (!funding_delta(peer->them.offer_anchor == CMD_OPEN_WITH_ANCHOR, + peer->anchor.satoshis, + 0, + -cur->htlc->msatoshis, + &cur->cstate->b, &cur->cstate->a)) { + fatal("Unexpected failure routefailing HTLC of %"PRIu64 + " milli-satoshis", cur->htlc->msatoshis); + return; + } + funding_remove_htlc(&cur->cstate->b, i); + + peer_get_revocation_hash(peer, peer->num_htlcs+1, + &cur->our_revocation_hash); + + peer->current_htlc = tal_steal(peer, cur); + peer->jsoncmd = cmd; + + /* FIXME: do we need this? */ + peer->cmddata.htlc_prog = peer->current_htlc; + peer->cmd = CMD_SEND_HTLC_ROUTEFAIL; + try_command(peer); +} + +const struct json_command failhtlc_command = { + "failhtlc", + json_failhtlc, + "Fail htlc proposed by {id} which has redeem hash {rhash}", + "Returns an empty result on success" +}; diff --git a/daemon/test/test.sh b/daemon/test/test.sh index 0a01c01ea..1705e95b5 100755 --- a/daemon/test/test.sh +++ b/daemon/test/test.sh @@ -111,6 +111,17 @@ $LCLI2 fulfillhtlc $ID1 $SECRET # We've transferred the HTLC amount to 2, who now has to pay fees. check_status 949999000 49000000 "" 0 1000000 "" +# A new one, at 10x the amount. +$LCLI1 newhtlc $ID2 10000000 $EXPIRY $RHASH + +# Check channel status +check_status 939999000 49000000 '{ "msatoshis" : 10000000, "expiry" : { "second" : '$EXPIRY' }, "rhash" : "'$RHASH'" } ' 0 1000000 "" + +$LCLI2 failhtlc $ID1 $RHASH + +# Back to how we were before. +check_status 949999000 49000000 "" 0 1000000 "" + sleep 1 $LCLI1 stop