Browse Source

Rename payment to invoice.

And rename JSON's accept-payment command to invoice.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 8 years ago
parent
commit
060ff29b45
  1. 4
      daemon/Makefile
  2. 39
      daemon/db.c
  3. 5
      daemon/db.h
  4. 127
      daemon/invoice.c
  5. 29
      daemon/invoice.h
  6. 2
      daemon/jsonrpc.c
  7. 2
      daemon/jsonrpc.h
  8. 2
      daemon/lightningd.c
  9. 2
      daemon/lightningd.h
  10. 98
      daemon/payment.c
  11. 25
      daemon/payment.h
  12. 33
      daemon/peer.c
  13. 6
      daemon/test/test.sh

4
daemon/Makefile

@ -25,6 +25,7 @@ DAEMON_SRC := \
daemon/failure.c \
daemon/feechange.c \
daemon/htlc.c \
daemon/invoice.c \
daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/netaddr.c \
@ -33,7 +34,6 @@ DAEMON_SRC := \
daemon/output_to_htlc.c \
daemon/packets.c \
daemon/pay.c \
daemon/payment.c \
daemon/peer.c \
daemon/routing.c \
daemon/secrets.c \
@ -70,6 +70,7 @@ DAEMON_HEADERS := \
daemon/feechange_state.h \
daemon/htlc.h \
daemon/htlc_state.h \
daemon/invoice.h \
daemon/json.h \
daemon/jsonrpc.h \
daemon/lightningd.h \
@ -80,7 +81,6 @@ DAEMON_HEADERS := \
daemon/output_to_htlc.h \
daemon/packets.h \
daemon/pay.h \
daemon/payment.h \
daemon/peer.h \
daemon/pseudorand.h \
daemon/routing.h \

39
daemon/db.c

@ -3,12 +3,12 @@
#include "db.h"
#include "feechange.h"
#include "htlc.h"
#include "invoice.h"
#include "lightningd.h"
#include "log.h"
#include "names.h"
#include "netaddr.h"
#include "pay.h"
#include "payment.h"
#include "routing.h"
#include "secrets.h"
#include "utils.h"
@ -57,12 +57,13 @@ static const char *sqlite3_column_str(sqlite3_stmt *stmt, int iCol)
#define SQL_RHASH(var) stringify(var)" CHAR(32)"
#define SQL_SHA256(var) stringify(var)" CHAR(32)"
#define SQL_R(var) stringify(var)" CHAR(32)"
#define SQL_STATENAME(var) stringify(var)" VARCHAR(44)"
/* STATE_OPEN_WAITING_THEIRANCHOR_THEYCOMPLETED == 44*/
#define SQL_STATENAME(var) stringify(var)" VARCHAR(44)"
#define SQL_INVLABEL(var) stringify(var)" VARCHAR("stringify(INVOICE_MAX_LABEL_LEN)")"
/* 8 + 4 + (8 + 32) * (64 + 1) */
#define SHACHAIN_SIZE 2612
#define SQL_SHACHAIN(var) stringify(var)" CHAR(2612)"
#define SQL_SHACHAIN(var) stringify(var)" CHAR("stringify(SHACHAIN_SIZE)")"
/* FIXME: Should be fixed size. */
#define SQL_ROUTING(var) stringify(var)" BLOB"
@ -1072,26 +1073,27 @@ static void db_load_pay(struct lightningd_state *dstate)
tal_free(ctx);
}
static void db_load_payment(struct lightningd_state *dstate)
static void db_load_invoice(struct lightningd_state *dstate)
{
int err;
sqlite3_stmt *stmt;
char *ctx = tal(dstate, char);
err = sqlite3_prepare_v2(dstate->db->sql, "SELECT * FROM payment;", -1,
err = sqlite3_prepare_v2(dstate->db->sql, "SELECT * FROM invoice;", -1,
&stmt, NULL);
if (err != SQLITE_OK)
fatal("db_load_payment:prepare gave %s:%s",
fatal("db_load_invoice:prepare gave %s:%s",
sqlite3_errstr(err), sqlite3_errmsg(dstate->db->sql));
while ((err = sqlite3_step(stmt)) != SQLITE_DONE) {
struct rval r;
u64 msatoshis;
bool complete;
const char *label;
if (err != SQLITE_ROW)
fatal("db_load_payment:step gave %s:%s",
fatal("db_load_invoice:step gave %s:%s",
sqlite3_errstr(err),
sqlite3_errmsg(dstate->db->sql));
if (sqlite3_column_count(stmt) != 3)
@ -1100,8 +1102,9 @@ static void db_load_payment(struct lightningd_state *dstate)
from_sql_blob(stmt, 0, &r, sizeof(r));
msatoshis = sqlite3_column_int64(stmt, 1);
complete = sqlite3_column_int(stmt, 2);
payment_add(dstate, &r, msatoshis, complete);
label = (const char *)sqlite3_column_text(stmt, 2);
complete = sqlite3_column_int(stmt, 3);
invoice_add(dstate, &r, msatoshis, label, complete);
}
tal_free(ctx);
}
@ -1147,7 +1150,7 @@ static void db_load(struct lightningd_state *dstate)
db_load_addresses(dstate);
db_load_peers(dstate);
db_load_pay(dstate);
db_load_payment(dstate);
db_load_invoice(dstate);
}
void db_init(struct lightningd_state *dstate)
@ -1194,8 +1197,9 @@ void db_init(struct lightningd_state *dstate)
SQL_BLOB(ids), SQL_PUBKEY(htlc_peer),
SQL_U64(htlc_id), SQL_R(r), SQL_FAIL(fail),
"PRIMARY KEY(rhash)")
TABLE(payment,
SQL_R(r), SQL_U64(msatoshis), SQL_BOOL(complete),
TABLE(invoice,
SQL_R(r), SQL_U64(msatoshis), SQL_INVLABEL(label),
SQL_BOOL(complete),
"PRIMARY KEY(r)")
TABLE(anchors,
SQL_PUBKEY(peer),
@ -1926,8 +1930,9 @@ bool db_complete_pay_command(struct lightningd_state *dstate,
return !errmsg;
}
bool db_new_payment(struct lightningd_state *dstate,
bool db_new_invoice(struct lightningd_state *dstate,
u64 msatoshis,
const char *label,
const struct rval *r)
{
const char *errmsg, *ctx = tal(dstate, char);
@ -1936,9 +1941,11 @@ bool db_new_payment(struct lightningd_state *dstate,
assert(!dstate->db->in_transaction);
errmsg = db_exec(ctx, dstate, "INSERT INTO payment VALUES (x'%s', %"PRIu64", %s);",
/* Insert label as hex; suspect injection attacks. */
errmsg = db_exec(ctx, dstate, "INSERT INTO invoice VALUES (x'%s', %"PRIu64", x'%s', %s);",
tal_hexstr(ctx, r, sizeof(*r)),
msatoshis,
tal_hexstr(ctx, label, strlen(label)),
sql_bool(false));
if (errmsg)
log_broken(dstate->base_log, "%s:%s", __func__, errmsg);
@ -1946,7 +1953,7 @@ bool db_new_payment(struct lightningd_state *dstate,
return !errmsg;
}
bool db_resolve_payment(struct lightningd_state *dstate, const struct rval *r)
bool db_resolve_invoice(struct lightningd_state *dstate, const struct rval *r)
{
const char *errmsg, *ctx = tal(dstate, char);
@ -1954,7 +1961,7 @@ bool db_resolve_payment(struct lightningd_state *dstate, const struct rval *r)
assert(dstate->db->in_transaction);
errmsg = db_exec(ctx, dstate, "UPDATE payment SET complete=%s WHERE r=x'%s';",
errmsg = db_exec(ctx, dstate, "UPDATE invoice SET complete=%s WHERE r=x'%s';",
sql_bool(true),
tal_hexstr(ctx, r, sizeof(*r)));
if (errmsg)

5
daemon/db.h

@ -37,8 +37,9 @@ bool db_replace_pay_command(struct lightningd_state *dstate,
const struct pubkey *ids,
u64 msatoshis,
const struct htlc *htlc);
bool db_new_payment(struct lightningd_state *dstate,
bool db_new_invoice(struct lightningd_state *dstate,
u64 msatoshis,
const char *label,
const struct rval *r);
/* FIXME: save error handling until db_commit_transaction for calls
@ -51,7 +52,7 @@ bool db_update_htlc_state(struct peer *peer, const struct htlc *htlc,
enum htlc_state oldstate);
bool db_complete_pay_command(struct lightningd_state *dstate,
const struct htlc *htlc);
bool db_resolve_payment(struct lightningd_state *dstate, const struct rval *r);
bool db_resolve_invoice(struct lightningd_state *dstate, const struct rval *r);
bool db_update_feechange_state(struct peer *peer,
const struct feechange *f,
enum htlc_state oldstate);

127
daemon/invoice.c

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

29
daemon/invoice.h

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

2
daemon/jsonrpc.c

@ -289,7 +289,7 @@ static const struct json_command *cmdlist[] = {
&commit_command,
&close_command,
&newaddr_command,
&accept_payment_command,
&invoice_command,
&getroute_command,
&sendpay_command,
&feerate_command,

2
daemon/jsonrpc.h

@ -71,7 +71,7 @@ extern const struct json_command reconnect_command;
extern const struct json_command disconnect_command;
extern const struct json_command signcommit_command;
extern const struct json_command output_command;
extern const struct json_command accept_payment_command;
extern const struct json_command invoice_command;
extern const struct json_command add_route_command;
extern const struct json_command routefail_command;
extern const struct json_command getroute_command;

2
daemon/lightningd.c

@ -255,7 +255,7 @@ static struct lightningd_state *lightningd_state(void)
default_config(&dstate->config);
list_head_init(&dstate->bitcoin_req);
list_head_init(&dstate->wallet);
list_head_init(&dstate->payments);
list_head_init(&dstate->invoices);
list_head_init(&dstate->addresses);
dstate->dev_never_routefail = false;
dstate->bitcoin_req_running = false;

2
daemon/lightningd.h

@ -111,7 +111,7 @@ struct lightningd_state {
struct list_head wallet;
/* Payments for r values we know about. */
struct list_head payments;
struct list_head invoices;
/* All known nodes. */
struct node_map *nodes;

98
daemon/payment.c

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

25
daemon/payment.h

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

33
daemon/peer.c

@ -7,6 +7,7 @@
#include "db.h"
#include "dns.h"
#include "find_p2sh_out.h"
#include "invoice.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
@ -16,7 +17,6 @@
#include "output_to_htlc.h"
#include "packets.h"
#include "pay.h"
#include "payment.h"
#include "peer.h"
#include "permute_tx.h"
#include "protobuf_convert.h"
@ -492,7 +492,7 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
{
RouteStep *step;
const u8 *rest_of_route;
struct payment *payment;
struct invoice *invoice;
if (abs_locktime_is_seconds(&htlc->expiry)) {
log_unusual(peer->log, "HTLC %"PRIu64" is in seconds", htlc->id);
@ -535,9 +535,9 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
case ROUTE_STEP__NEXT_END:
if (only_dest)
return;
payment = find_payment(peer->dstate, &htlc->rhash);
if (!payment) {
log_unusual(peer->log, "No payment for HTLC %"PRIu64,
invoice = find_invoice(peer->dstate, &htlc->rhash);
if (!invoice) {
log_unusual(peer->log, "No invoice for HTLC %"PRIu64,
htlc->id);
log_add_struct(peer->log, " rhash=%s",
struct sha256, &htlc->rhash);
@ -548,12 +548,13 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
goto free_rest;
}
if (htlc->msatoshis != payment->msatoshis) {
log_unusual(peer->log, "Short payment for HTLC %"PRIu64
if (htlc->msatoshis != invoice->msatoshis) {
log_unusual(peer->log, "Short payment for '%s' HTLC %"PRIu64
": %"PRIu64" not %"PRIu64 " satoshi!",
invoice->label,
htlc->id,
htlc->msatoshis,
payment->msatoshis);
invoice->msatoshis);
command_htlc_set_fail(peer, htlc,
UNAUTHORIZED_401,
"incorrect amount");
@ -561,28 +562,28 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
}
/* This is a courtesy: we could simply take your money! */
if (payment->complete) {
if (invoice->complete) {
log_unusual(peer->log,
"Repeated payment for HTLC %"PRIu64,
htlc->id);
"Repeated payment for '%s' HTLC %"PRIu64,
invoice->label, htlc->id);
command_htlc_set_fail(peer, htlc,
UNAUTHORIZED_401,
"already received payment");
return;
}
log_info(peer->log, "Immediately resolving HTLC %"PRIu64,
htlc->id);
log_info(peer->log, "Immediately resolving '%s' HTLC %"PRIu64,
invoice->label, htlc->id);
if (!db_resolve_payment(peer->dstate, &payment->r)) {
if (!db_resolve_invoice(peer->dstate, &invoice->r)) {
command_htlc_set_fail(peer, htlc,
INTERNAL_SERVER_ERROR_500,
"database error");
return;
}
payment->complete = true;
set_htlc_rval(peer, htlc, &payment->r);
invoice->complete = true;
set_htlc_rval(peer, htlc, &invoice->r);
command_htlc_fulfill(peer, htlc);
goto free_rest;

6
daemon/test/test.sh

@ -959,7 +959,7 @@ check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# Now, use automatic payment redemption
lcli1 dev-routefail true
lcli2 dev-routefail true
RHASH3=`lcli2 accept-payment $HTLC_AMOUNT | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
RHASH3=`lcli2 invoice $HTLC_AMOUNT RHASH3 | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
HTLCID3=`lcli1 newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH3 | extract_id`
[ ! -n "$MANUALCOMMIT" ] || lcli1 commit $ID2
@ -974,7 +974,7 @@ B_AMOUNT=$(($B_AMOUNT + $HTLC_AMOUNT))
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# Now, failed payment (didn't pay enough)
RHASH4=`lcli2 accept-payment $HTLC_AMOUNT | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
RHASH4=`lcli2 invoice $HTLC_AMOUNT RHASH4 | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
# Shouldn't have this already.
if lcli2 getlog | $FGREP 'Short payment for HTLC'; then exit 1; fi
@ -1010,7 +1010,7 @@ if [ ! -n "$MANUALCOMMIT" ]; then
# Add to config in case we are restaring.
echo "add-route=$ID2/$ID3/546000/10/36/36" >> $DIR1/config
lcli1 add-route $ID2 $ID3 546000 10 36 36
RHASH5=`lcli3 accept-payment $HTLC_AMOUNT | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
RHASH5=`lcli3 invoice $HTLC_AMOUNT RHASH5 | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
# Get route.
ROUTE=`lcli1 getroute $ID3 $HTLC_AMOUNT 1`

Loading…
Cancel
Save