mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-21 14:24:09 +01:00
pay: new all-in-one RPC command.
Closes: #240 Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
d577769350
commit
e1dc75e954
2 changed files with 123 additions and 0 deletions
107
lightningd/pay.c
107
lightningd/pay.c
|
@ -2,9 +2,12 @@
|
|||
#include <bitcoin/preimage.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <channeld/gen_channel_wire.h>
|
||||
#include <gossipd/gen_gossip_wire.h>
|
||||
#include <gossipd/routing.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/bolt11.h>
|
||||
#include <lightningd/chaintopology.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
|
@ -362,3 +365,107 @@ static const struct json_command sendpay_command = {
|
|||
"Returns the {preimage} on success"
|
||||
};
|
||||
AUTODATA(json_command, &sendpay_command);
|
||||
|
||||
struct pay {
|
||||
struct sha256 payment_hash;
|
||||
struct command *cmd;
|
||||
};
|
||||
|
||||
static void json_pay_getroute_reply(struct subd *gossip,
|
||||
const u8 *reply, const int *fds,
|
||||
struct pay *pay)
|
||||
{
|
||||
struct route_hop *route;
|
||||
|
||||
fromwire_gossip_getroute_reply(reply, reply, NULL, &route);
|
||||
|
||||
if (tal_count(route) == 0) {
|
||||
command_fail(pay->cmd, "Could not find a route");
|
||||
return;
|
||||
}
|
||||
|
||||
send_payment(pay->cmd, &pay->payment_hash, route);
|
||||
}
|
||||
|
||||
static void json_pay(struct command *cmd,
|
||||
const char *buffer, const jsmntok_t *params)
|
||||
{
|
||||
jsmntok_t *bolt11tok, *msatoshitok, *desctok, *riskfactortok;
|
||||
double riskfactor = 1.0;
|
||||
u64 msatoshi;
|
||||
/* FIXME: add ctlv to bolt11 */
|
||||
u32 cltv = 9;
|
||||
struct pay *pay = tal(cmd, struct pay);
|
||||
struct bolt11 *b11;
|
||||
char *fail, *b11str, *desc;
|
||||
u8 *req;
|
||||
|
||||
if (!json_get_params(buffer, params,
|
||||
"bolt11", &bolt11tok,
|
||||
"?msatoshi", &msatoshitok,
|
||||
"?description", &desctok,
|
||||
"?riskfactor", &riskfactortok,
|
||||
NULL)) {
|
||||
command_fail(cmd, "Need bolt11 string");
|
||||
return;
|
||||
}
|
||||
|
||||
b11str = tal_strndup(cmd, buffer + bolt11tok->start,
|
||||
bolt11tok->end - bolt11tok->start);
|
||||
if (desctok)
|
||||
desc = tal_strndup(cmd, buffer + desctok->start,
|
||||
desctok->end - desctok->start);
|
||||
else
|
||||
desc = NULL;
|
||||
|
||||
b11 = bolt11_decode(pay, b11str, desc, &fail);
|
||||
if (!b11) {
|
||||
command_fail(cmd, "Invalid bolt11: %s", fail);
|
||||
return;
|
||||
}
|
||||
|
||||
pay->cmd = cmd;
|
||||
pay->payment_hash = b11->payment_hash;
|
||||
|
||||
if (b11->msatoshi) {
|
||||
msatoshi = *b11->msatoshi;
|
||||
if (msatoshitok) {
|
||||
command_fail(cmd, "msatoshi parameter unnecessary");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!msatoshitok) {
|
||||
command_fail(cmd, "msatoshi parameter required");
|
||||
return;
|
||||
}
|
||||
if (!json_tok_u64(buffer, msatoshitok, &msatoshi)) {
|
||||
command_fail(cmd,
|
||||
"msatoshi '%.*s' is not a valid number",
|
||||
(int)(msatoshitok->end-msatoshitok->start),
|
||||
buffer + msatoshitok->start);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (riskfactortok
|
||||
&& !json_tok_double(buffer, riskfactortok, &riskfactor)) {
|
||||
command_fail(cmd, "'%.*s' is not a valid double",
|
||||
(int)(riskfactortok->end - riskfactortok->start),
|
||||
buffer + riskfactortok->start);
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: use b11->routes */
|
||||
req = towire_gossip_getroute_request(cmd, &cmd->ld->id,
|
||||
&b11->receiver_id,
|
||||
msatoshi, riskfactor*1000, cltv);
|
||||
subd_req(pay, cmd->ld->gossip, req, -1, 0, json_pay_getroute_reply, pay);
|
||||
}
|
||||
|
||||
static const struct json_command pay_command = {
|
||||
"pay",
|
||||
json_pay,
|
||||
"Send payment in {bolt11} with optional {msatoshi}, {description} and {riskfactor}",
|
||||
"Returns the {preimage} on success"
|
||||
};
|
||||
AUTODATA(json_command, &pay_command);
|
||||
|
|
|
@ -644,6 +644,22 @@ class LightningDTests(BaseLightningDTests):
|
|||
# But this should work.
|
||||
self.pay(l2, l1, available - reserve*2)
|
||||
|
||||
def test_pay(self):
|
||||
l1,l2 = self.connect()
|
||||
|
||||
chanid = self.fund_channel(l1, l2, 10**6)
|
||||
|
||||
# Wait for route propagation.
|
||||
bitcoind.rpc.generate(5)
|
||||
l1.daemon.wait_for_logs(['Received channel_update for channel {}\(0\)'
|
||||
.format(chanid),
|
||||
'Received channel_update for channel {}\(1\)'
|
||||
.format(chanid)])
|
||||
|
||||
inv = l2.rpc.invoice(123000, 'test_pay', 'description')['bolt11']
|
||||
l1.rpc.pay(inv);
|
||||
assert l2.rpc.listinvoice('test_pay')[0]['complete'] == True
|
||||
|
||||
def test_bad_opening(self):
|
||||
# l1 asks for a too-long locktime
|
||||
l1 = self.node_factory.get_node(options=['--locktime-blocks=100'])
|
||||
|
|
Loading…
Add table
Reference in a new issue