daemon: routefail command.

This should be renamed: it's actually any kind of after-the-fact failure.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2016-01-22 06:45:28 +10:30
parent 86f4bd772c
commit 2346f6bf14
5 changed files with 151 additions and 2 deletions

View File

@ -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,

View File

@ -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 */

View File

@ -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,

View File

@ -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"
};

View File

@ -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