From 079778e357395aeb4fdcddc0f92d5cb6ca4e20c6 Mon Sep 17 00:00:00 2001 From: ZmnSCPxj Date: Tue, 24 Apr 2018 23:04:33 +0000 Subject: [PATCH] invoice: Check duplicate preimage when explicitly sprcified. Reported-by: @mcudev --- lightningd/invoice.c | 10 ++++++++++ tests/test_lightningd.py | 6 ++++++ wallet/invoices.c | 21 +++++++++++++++++++++ wallet/invoices.h | 15 +++++++++++++++ wallet/test/run-wallet.c | 5 +++++ wallet/wallet.c | 6 ++++++ wallet/wallet.h | 14 ++++++++++++++ 7 files changed, 77 insertions(+) diff --git a/lightningd/invoice.c b/lightningd/invoice.c index d3301ce68..3b016a619 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -297,6 +297,16 @@ static void json_invoice(struct command *cmd, /* Generate preimage hash. */ sha256(&rhash, r.r, sizeof(r.r)); + /* Check duplicate preimage if explicitly specified. + * We do not check when it is randomly generated, since + * the probability of that matching is very low. + */ + if (preimagetok && + wallet_invoice_find_by_rhash(cmd->ld->wallet, &invoice, &rhash)) { + command_fail(cmd, "preimage already used"); + return; + } + /* Construct bolt11 string. */ b11 = new_bolt11(cmd, msatoshi_val); b11->chain = get_chainparams(cmd->ld); diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py index 94f615029..aa42794a2 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -462,6 +462,12 @@ class LightningDTests(BaseLightningDTests): payment_preimage = payment['payment_preimage'] assert invoice_preimage == payment_preimage + # Creating a new invoice with same preimage should error. + self.assertRaisesRegex(ValueError, + "preimage already used", + l2.rpc.invoice, 123456, 'inv2', '?', + None, None, invoice_preimage) + def test_invoice(self): l1 = self.node_factory.get_node() l2 = self.node_factory.get_node() diff --git a/wallet/invoices.c b/wallet/invoices.c index b4ae1a5a4..c5bd36266 100644 --- a/wallet/invoices.c +++ b/wallet/invoices.c @@ -347,6 +347,27 @@ bool invoices_find_by_label(struct invoices *invoices, } } +bool invoices_find_by_rhash(struct invoices *invoices, + struct invoice *pinvoice, + const struct sha256 *rhash) +{ + sqlite3_stmt *stmt; + + stmt = db_prepare(invoices->db, + "SELECT id" + " FROM invoices" + " WHERE payment_hash = ?;"); + sqlite3_bind_blob(stmt, 1, rhash, sizeof(*rhash), SQLITE_TRANSIENT); + if (sqlite3_step(stmt) == SQLITE_ROW) { + pinvoice->id = sqlite3_column_int64(stmt, 0); + sqlite3_finalize(stmt); + return true; + } else { + sqlite3_finalize(stmt); + return false; + } +} + bool invoices_find_unpaid(struct invoices *invoices, struct invoice *pinvoice, const struct sha256 *rhash) diff --git a/wallet/invoices.h b/wallet/invoices.h index 5c4bbac47..6677834d9 100644 --- a/wallet/invoices.h +++ b/wallet/invoices.h @@ -76,6 +76,21 @@ bool invoices_find_by_label(struct invoices *invoices, struct invoice *pinvoice, const struct json_escaped *label); +/** + * invoices_find_by_rhash - Search for an invoice by + * payment_hash + * + * @invoices - the invoice handler. + * @pinvoice - pointer to location to load found invoice in. + * @rhash - the payment_hash to search for. + * + * Returns false if no invoice with that rhash exists. + * Returns true if found. + */ +bool invoices_find_by_rhash(struct invoices *invoices, + struct invoice *pinvoice, + const struct sha256 *rhash); + /** * invoices_find_unpaid - Search for an unpaid, unexpired invoice by * payment_hash diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 6f4514832..c65f354db 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -136,6 +136,11 @@ bool invoices_find_by_label(struct invoices *invoices UNNEEDED, struct invoice *pinvoice UNNEEDED, const struct json_escaped *label UNNEEDED) { fprintf(stderr, "invoices_find_by_label called!\n"); abort(); } +/* Generated stub for invoices_find_by_rhash */ +bool invoices_find_by_rhash(struct invoices *invoices UNNEEDED, + struct invoice *pinvoice UNNEEDED, + const struct sha256 *rhash UNNEEDED) +{ fprintf(stderr, "invoices_find_by_rhash called!\n"); abort(); } /* Generated stub for invoices_find_unpaid */ bool invoices_find_unpaid(struct invoices *invoices UNNEEDED, struct invoice *pinvoice UNNEEDED, diff --git a/wallet/wallet.c b/wallet/wallet.c index 1f1bfc124..93e8559e1 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1386,6 +1386,12 @@ bool wallet_invoice_find_by_label(struct wallet *wallet, { return invoices_find_by_label(wallet->invoices, pinvoice, label); } +bool wallet_invoice_find_by_rhash(struct wallet *wallet, + struct invoice *pinvoice, + const struct sha256 *rhash) +{ + return invoices_find_by_rhash(wallet->invoices, pinvoice, rhash); +} bool wallet_invoice_find_unpaid(struct wallet *wallet, struct invoice *pinvoice, const struct sha256 *rhash) diff --git a/wallet/wallet.h b/wallet/wallet.h index f754efad7..164f6eb82 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -510,6 +510,20 @@ bool wallet_invoice_find_by_label(struct wallet *wallet, struct invoice *pinvoice, const struct json_escaped *label); +/** + * wallet_invoice_find_by_rhash - Search for an invoice by payment_hash + * + * @wallet - the wallet to search. + * @pinvoice - pointer to location to load found invoice in. + * @rhash - the payment_hash to search for. + * + * Returns false if no invoice with that rhash exists. + * Returns true if found. + */ +bool wallet_invoice_find_by_rhash(struct wallet *wallet, + struct invoice *pinvoice, + const struct sha256 *rhash); + /** * wallet_invoice_find_unpaid - Search for an unpaid, unexpired invoice by * payment_hash