Browse Source
And rename JSON's accept-payment command to invoice. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
Rusty Russell
9 years ago
13 changed files with 209 additions and 167 deletions
@ -0,0 +1,127 @@ |
|||||
|
#include "db.h" |
||||
|
#include "invoice.h" |
||||
|
#include "jsonrpc.h" |
||||
|
#include "lightningd.h" |
||||
|
#include <ccan/str/hex/hex.h> |
||||
|
#include <ccan/structeq/structeq.h> |
||||
|
#include <ccan/tal/str/str.h> |
||||
|
#include <sodium/randombytes.h> |
||||
|
|
||||
|
struct invoice *find_invoice(struct lightningd_state *dstate, |
||||
|
const struct sha256 *rhash) |
||||
|
{ |
||||
|
struct invoice *i; |
||||
|
|
||||
|
list_for_each(&dstate->invoices, i, list) { |
||||
|
if (structeq(rhash, &i->rhash)) |
||||
|
return i; |
||||
|
} |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
static struct invoice *find_invoice_by_label(struct lightningd_state *dstate, |
||||
|
const char *label) |
||||
|
{ |
||||
|
struct invoice *i; |
||||
|
|
||||
|
list_for_each(&dstate->invoices, i, list) { |
||||
|
if (streq(i->label, label)) |
||||
|
return i; |
||||
|
} |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
void invoice_add(struct lightningd_state *dstate, |
||||
|
const struct rval *r, |
||||
|
u64 msatoshis, |
||||
|
const char *label, |
||||
|
bool complete) |
||||
|
{ |
||||
|
struct invoice *invoice = tal(dstate, struct invoice); |
||||
|
|
||||
|
invoice->msatoshis = msatoshis; |
||||
|
invoice->r = *r; |
||||
|
invoice->complete = complete; |
||||
|
invoice->label = tal_strdup(invoice, label); |
||||
|
sha256(&invoice->rhash, invoice->r.r, sizeof(invoice->r.r)); |
||||
|
list_add(&dstate->invoices, &invoice->list); |
||||
|
} |
||||
|
|
||||
|
static void json_invoice(struct command *cmd, |
||||
|
const char *buffer, const jsmntok_t *params) |
||||
|
{ |
||||
|
struct invoice *invoice; |
||||
|
jsmntok_t *msatoshis, *r, *label; |
||||
|
struct json_result *response = new_json_result(cmd); |
||||
|
|
||||
|
if (!json_get_params(buffer, params, |
||||
|
"amount", &msatoshis, |
||||
|
"label", &label, |
||||
|
"?r", &r, |
||||
|
NULL)) { |
||||
|
command_fail(cmd, "Need {amount} and {label}"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
invoice = tal(cmd, struct invoice); |
||||
|
if (r) { |
||||
|
if (!hex_decode(buffer + r->start, r->end - r->start, |
||||
|
invoice->r.r, sizeof(invoice->r.r))) { |
||||
|
command_fail(cmd, "Invalid hex r '%.*s'", |
||||
|
r->end - r->start, buffer + r->start); |
||||
|
return; |
||||
|
} |
||||
|
} else |
||||
|
randombytes_buf(invoice->r.r, sizeof(invoice->r.r)); |
||||
|
|
||||
|
sha256(&invoice->rhash, invoice->r.r, sizeof(invoice->r.r)); |
||||
|
if (find_invoice(cmd->dstate, &invoice->rhash)) { |
||||
|
command_fail(cmd, "Duplicate r value '%.*s'", |
||||
|
r->end - r->start, buffer + r->start); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!json_tok_u64(buffer, msatoshis, &invoice->msatoshis) |
||||
|
|| invoice->msatoshis == 0) { |
||||
|
command_fail(cmd, "'%.*s' is not a valid positive number", |
||||
|
msatoshis->end - msatoshis->start, |
||||
|
buffer + msatoshis->start); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
invoice->label = tal_strndup(invoice, buffer + label->start, |
||||
|
label->end - label->start); |
||||
|
if (find_invoice_by_label(cmd->dstate, invoice->label)) { |
||||
|
command_fail(cmd, "Duplicate label '%s'", invoice->label); |
||||
|
return; |
||||
|
} |
||||
|
if (strlen(invoice->label) > INVOICE_MAX_LABEL_LEN) { |
||||
|
command_fail(cmd, "label '%s' over %u bytes", invoice->label, |
||||
|
INVOICE_MAX_LABEL_LEN); |
||||
|
return; |
||||
|
} |
||||
|
invoice->complete = false; |
||||
|
|
||||
|
if (!db_new_invoice(cmd->dstate, invoice->msatoshis, invoice->label, |
||||
|
&invoice->r)) { |
||||
|
command_fail(cmd, "database error"); |
||||
|
return; |
||||
|
} |
||||
|
/* OK, connect it to main state, respond with hash */ |
||||
|
tal_steal(cmd->dstate, invoice); |
||||
|
list_add(&cmd->dstate->invoices, &invoice->list); |
||||
|
|
||||
|
json_object_start(response, NULL); |
||||
|
json_add_hex(response, "rhash", |
||||
|
&invoice->rhash, sizeof(invoice->rhash)); |
||||
|
json_object_end(response); |
||||
|
|
||||
|
command_success(cmd, response); |
||||
|
} |
||||
|
|
||||
|
const struct json_command invoice_command = { |
||||
|
"invoice", |
||||
|
json_invoice, |
||||
|
"Create invoice for {msatoshis} with {label} (with a set {r}, otherwise generate one)", |
||||
|
"Returns the {rhash} on success. " |
||||
|
}; |
@ -0,0 +1,29 @@ |
|||||
|
#ifndef LIGHTNING_DAEMON_INVOICE_H |
||||
|
#define LIGHTNING_DAEMON_INVOICE_H |
||||
|
#include "config.h" |
||||
|
#include "peer.h" |
||||
|
|
||||
|
struct lightningd_state; |
||||
|
|
||||
|
struct invoice { |
||||
|
struct list_node list; |
||||
|
const char *label; |
||||
|
u64 msatoshis; |
||||
|
struct rval r; |
||||
|
struct sha256 rhash; |
||||
|
bool complete; |
||||
|
}; |
||||
|
|
||||
|
#define INVOICE_MAX_LABEL_LEN 128 |
||||
|
|
||||
|
/* From database */ |
||||
|
void invoice_add(struct lightningd_state *dstate, |
||||
|
const struct rval *r, |
||||
|
u64 msatoshis, |
||||
|
const char *label, |
||||
|
bool complete); |
||||
|
|
||||
|
struct invoice *find_invoice(struct lightningd_state *dstate, |
||||
|
const struct sha256 *rhash); |
||||
|
|
||||
|
#endif /* LIGHTNING_DAEMON_INVOICE_H */ |
@ -1,98 +0,0 @@ |
|||||
#include "db.h" |
|
||||
#include "jsonrpc.h" |
|
||||
#include "lightningd.h" |
|
||||
#include "payment.h" |
|
||||
#include <ccan/str/hex/hex.h> |
|
||||
#include <ccan/structeq/structeq.h> |
|
||||
#include <sodium/randombytes.h> |
|
||||
|
|
||||
struct payment *find_payment(struct lightningd_state *dstate, |
|
||||
const struct sha256 *rhash) |
|
||||
{ |
|
||||
struct payment *i; |
|
||||
|
|
||||
list_for_each(&dstate->payments, i, list) { |
|
||||
if (structeq(rhash, &i->rhash)) |
|
||||
return i; |
|
||||
} |
|
||||
return NULL; |
|
||||
} |
|
||||
|
|
||||
void payment_add(struct lightningd_state *dstate, |
|
||||
const struct rval *r, |
|
||||
u64 msatoshis, |
|
||||
bool complete) |
|
||||
{ |
|
||||
struct payment *payment = tal(dstate, struct payment); |
|
||||
|
|
||||
payment->msatoshis = msatoshis; |
|
||||
payment->r = *r; |
|
||||
payment->complete = complete; |
|
||||
sha256(&payment->rhash, payment->r.r, sizeof(payment->r.r)); |
|
||||
list_add(&dstate->payments, &payment->list); |
|
||||
} |
|
||||
|
|
||||
static void json_accept_payment(struct command *cmd, |
|
||||
const char *buffer, const jsmntok_t *params) |
|
||||
{ |
|
||||
struct payment *payment; |
|
||||
jsmntok_t *msatoshis, *r; |
|
||||
struct json_result *response = new_json_result(cmd); |
|
||||
|
|
||||
if (!json_get_params(buffer, params, |
|
||||
"amount", &msatoshis, |
|
||||
"?r", &r, |
|
||||
NULL)) { |
|
||||
command_fail(cmd, "Need {amount}"); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
payment = tal(cmd, struct payment); |
|
||||
if (r) { |
|
||||
if (!hex_decode(buffer + r->start, r->end - r->start, |
|
||||
payment->r.r, sizeof(payment->r.r))) { |
|
||||
command_fail(cmd, "Invalid hex r '%.*s'", |
|
||||
r->end - r->start, buffer + r->start); |
|
||||
return; |
|
||||
} |
|
||||
} else |
|
||||
randombytes_buf(payment->r.r, sizeof(payment->r.r)); |
|
||||
|
|
||||
sha256(&payment->rhash, payment->r.r, sizeof(payment->r.r)); |
|
||||
if (find_payment(cmd->dstate, &payment->rhash)) { |
|
||||
command_fail(cmd, "Duplicate r value '%.*s'", |
|
||||
r->end - r->start, buffer + r->start); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
if (!json_tok_u64(buffer, msatoshis, &payment->msatoshis) |
|
||||
|| payment->msatoshis == 0) { |
|
||||
command_fail(cmd, "'%.*s' is not a valid positive number", |
|
||||
msatoshis->end - msatoshis->start, |
|
||||
buffer + msatoshis->start); |
|
||||
return; |
|
||||
} |
|
||||
payment->complete = false; |
|
||||
|
|
||||
if (!db_new_payment(cmd->dstate, payment->msatoshis, &payment->r)) { |
|
||||
command_fail(cmd, "database error"); |
|
||||
return; |
|
||||
} |
|
||||
/* OK, connect it to main state, respond with hash */ |
|
||||
tal_steal(cmd->dstate, payment); |
|
||||
list_add(&cmd->dstate->payments, &payment->list); |
|
||||
|
|
||||
json_object_start(response, NULL); |
|
||||
json_add_hex(response, "rhash", |
|
||||
&payment->rhash, sizeof(payment->rhash)); |
|
||||
json_object_end(response); |
|
||||
|
|
||||
command_success(cmd, response); |
|
||||
} |
|
||||
|
|
||||
const struct json_command accept_payment_command = { |
|
||||
"accept-payment", |
|
||||
json_accept_payment, |
|
||||
"Accept payment for {amount} (with a set {r}, otherwise generate one)", |
|
||||
"Returns the {rhash} on success. " |
|
||||
}; |
|
@ -1,25 +0,0 @@ |
|||||
#ifndef LIGHTNING_DAEMON_PAYMENT_H |
|
||||
#define LIGHTNING_DAEMON_PAYMENT_H |
|
||||
#include "config.h" |
|
||||
#include "peer.h" |
|
||||
|
|
||||
struct lightningd_state; |
|
||||
|
|
||||
struct payment { |
|
||||
struct list_node list; |
|
||||
u64 msatoshis; |
|
||||
struct rval r; |
|
||||
struct sha256 rhash; |
|
||||
bool complete; |
|
||||
}; |
|
||||
|
|
||||
/* From database */ |
|
||||
void payment_add(struct lightningd_state *dstate, |
|
||||
const struct rval *r, |
|
||||
u64 msatoshis, |
|
||||
bool complete); |
|
||||
|
|
||||
struct payment *find_payment(struct lightningd_state *dstate, |
|
||||
const struct sha256 *rhash); |
|
||||
|
|
||||
#endif /* LIGHTNING_DAEMON_PAYMENT_H */ |
|
Loading…
Reference in new issue