diff --git a/lightningd/Makefile b/lightningd/Makefile index 310f02cdc..a619a6381 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -59,6 +59,7 @@ LIGHTNINGD_LIB_HEADERS := $(LIGHTNINGD_LIB_SRC:.c=.h) LIGHTNINGD_SRC := \ lightningd/build_utxos.c \ + lightningd/dev_newhtlc.c \ lightningd/gossip_control.c \ lightningd/hsm_control.c \ lightningd/lightningd.c \ diff --git a/lightningd/dev_newhtlc.c b/lightningd/dev_newhtlc.c new file mode 100644 index 000000000..ee12a8d7b --- /dev/null +++ b/lightningd/dev_newhtlc.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool offer_htlc_reply(struct subd *subd, const u8 *msg, const int *fds, + struct command *cmd) +{ + u64 htlc_id; + u16 failcode; + u8 *failstr; + + if (!fromwire_channel_offer_htlc_reply(msg, msg, NULL, + &htlc_id, &failcode, &failstr)) { + command_fail(cmd, "Invalid reply from daemon: %s", + tal_hex(msg, msg)); + return true; + } + + if (failcode != 0) { + command_fail(cmd, "failure %u: %.*s", failcode, + (int)tal_len(failstr), (char *)failstr); + } else { + struct json_result *response = new_json_result(cmd); + + json_object_start(response, NULL); + json_add_u64(response, "id", htlc_id); + json_object_end(response); + command_success(cmd, response); + } + return true; +} + +static void json_dev_newhtlc(struct command *cmd, + const char *buffer, const jsmntok_t *params) +{ + struct lightningd *ld = ld_from_dstate(cmd->dstate); + struct peer *peer; + u8 *msg; + jsmntok_t *peeridtok, *msatoshitok, *expirytok, *rhashtok; + unsigned int expiry; + u64 msatoshi; + struct sha256 rhash; + struct hoppayload *hoppayloads; + u8 sessionkey[32]; + struct onionpacket *packet; + u8 *onion; + struct pubkey *path = tal_arrz(cmd, struct pubkey, 1); + + if (!json_get_params(buffer, params, + "peerid", &peeridtok, + "msatoshi", &msatoshitok, + "expiry", &expirytok, + "rhash", &rhashtok, + NULL)) { + command_fail(cmd, "Need peerid, msatoshi, expiry and rhash"); + return; + } + + peer = peer_from_json(ld, buffer, peeridtok); + if (!peer) { + command_fail(cmd, "Could not find peer with that peerid"); + return; + } + + /* FIXME: These checks are horrible, use a peer flag to say it's + * ready to forward! */ + if (peer->owner && !streq(peer->owner->name, "lightningd_channel")) { + command_fail(cmd, "Peer not in lightningd_channel (%s instead)", + peer->owner ? peer->owner->name : "unattached"); + return; + } + + if (!streq(peer->condition, "Normal operation")) { + command_fail(cmd, "Peer in condition %s", peer->condition); + return; + } + + if (!json_tok_u64(buffer, msatoshitok, &msatoshi)) { + command_fail(cmd, "'%.*s' is not a valid number", + (int)(msatoshitok->end - msatoshitok->start), + buffer + msatoshitok->start); + return; + } + if (!json_tok_number(buffer, expirytok, &expiry)) { + command_fail(cmd, "'%.*s' is not a valid number", + (int)(expirytok->end - expirytok->start), + buffer + expirytok->start); + return; + } + + if (!hex_decode(buffer + rhashtok->start, + rhashtok->end - rhashtok->start, + &rhash, sizeof(rhash))) { + command_fail(cmd, "'%.*s' is not a valid sha256 hash", + (int)(rhashtok->end - rhashtok->start), + buffer + rhashtok->start); + return; + } + + tal_arr(cmd, struct pubkey, 1); + hoppayloads = tal_arrz(cmd, struct hoppayload, 1); + path[0] = *peer->id; + randombytes_buf(&sessionkey, sizeof(sessionkey)); + packet = create_onionpacket(cmd, path, hoppayloads, sessionkey, + rhash.u.u8, sizeof(rhash)); + onion = serialize_onionpacket(cmd, packet); + + log_debug(peer->log, "JSON command to add new HTLC"); + + /* FIXME: If subdaemon dies? */ + msg = towire_channel_offer_htlc(cmd, msatoshi, expiry, &rhash, onion); + subd_req(peer->owner, take(msg), -1, 0, offer_htlc_reply, cmd); +} + +static const struct json_command dev_newhtlc_command = { + "dev-newhtlc", + json_dev_newhtlc, + "Offer {peerid} an HTLC worth {msatoshi} in {expiry} (block number) with {rhash}", + "Returns { id: u64 } result on success" +}; +AUTODATA(json_command, &dev_newhtlc_command); diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 290ca6ed7..40878da76 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -488,9 +488,9 @@ static const struct json_command getpeers_command = { }; AUTODATA(json_command, &getpeers_command); -static struct peer *find_peer_json(struct lightningd *ld, - const char *buffer, - jsmntok_t *peeridtok) +struct peer *peer_from_json(struct lightningd *ld, + const char *buffer, + jsmntok_t *peeridtok) { struct pubkey peerid; @@ -1058,7 +1058,7 @@ static void json_fund_channel(struct command *cmd, } fc->cmd = cmd; - fc->peer = find_peer_json(ld, buffer, peertok); + fc->peer = peer_from_json(ld, buffer, peertok); if (!fc->peer) { command_fail(cmd, "Could not find peer with that peerid"); return; diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index 4574dd4e6..1c9010f3a 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -2,6 +2,8 @@ #define LIGHTNING_LIGHTNINGD_PEER_CONTROL_H #include "config.h" #include +#include +#include #include #include #include @@ -59,6 +61,9 @@ struct peer { struct peer *peer_by_unique_id(struct lightningd *ld, u64 unique_id); struct peer *peer_by_id(struct lightningd *ld, const struct pubkey *id); +struct peer *peer_from_json(struct lightningd *ld, + const char *buffer, + jsmntok_t *peeridtok); void peer_accept_open(struct peer *peer, const struct crypto_state *cs, const u8 *msg); diff --git a/lightningd/test/test-basic b/lightningd/test/test-basic index ae21b1dd0..90dec7bd9 100755 --- a/lightningd/test/test-basic +++ b/lightningd/test/test-basic @@ -50,6 +50,11 @@ check "lcli2 getpeers info | $FGREP 'Funding tx reached depth'" check "lcli1 getpeers | tr -s '\012\011\" ' ' ' | $FGREP 'condition : Normal operation'" check "lcli2 getpeers | tr -s '\012\011\" ' ' ' | $FGREP 'condition : Normal operation'" +SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd +RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'` + +lcli1 dev-newhtlc $ID2 100000 $(( $(blockheight) + 10 )) $RHASH + lcli1 stop lcli2 stop