mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-15 11:59:16 +01:00
offer / offerout: return existing if its still active.
As requested by @shesek: it's weird to fail if they ask for the exact same thing (which is quite possible, since offers don't expire by default). And add a new "created" field so they can tell if they have an old one. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
44c469d52b
commit
cb9e0268a7
9 changed files with 95 additions and 26 deletions
19
doc/lightning-offer.7
generated
19
doc/lightning-offer.7
generated
|
@ -10,9 +10,10 @@ lightning-offer - Command for accepting payments
|
|||
|
||||
.SH DESCRIPTION
|
||||
|
||||
The \fBoffer\fR RPC command creates an offer, which is a precursor to
|
||||
creating one or more invoices\. It automatically enables the processing of
|
||||
an incoming invoice_request, and issuing of invoices\.
|
||||
The \fBoffer\fR RPC command creates an offer (or returns an existing
|
||||
one), which is a precursor to creating one or more invoices\. It
|
||||
automatically enables the processing of an incoming invoice_request,
|
||||
and issuing of invoices\.
|
||||
|
||||
|
||||
Note that it creates two variants of the offer: a signed and an
|
||||
|
@ -119,7 +120,9 @@ On success, an object is returned, containing:
|
|||
.IP \[bu]
|
||||
\fBbolt12_unsigned\fR (string): the bolt12 encoding of the offer, without a signature
|
||||
.IP \[bu]
|
||||
\fBused\fR (boolean): True if an associated invoice has been paid (always \fIfalse\fR)
|
||||
\fBused\fR (boolean): True if an associated invoice has been paid
|
||||
.IP \[bu]
|
||||
\fBcreated\fR (boolean): false if the offer already existed
|
||||
.IP \[bu]
|
||||
\fBlabel\fR (string, optional): the (optional) user-specified label
|
||||
|
||||
|
@ -131,13 +134,17 @@ lightning process fails before responding, the caller should use
|
|||
not\.
|
||||
|
||||
|
||||
If the offer already existed, and is still active, that is returned;
|
||||
if it's not active then this call fails\.
|
||||
|
||||
|
||||
The following error codes may occur:
|
||||
|
||||
.RS
|
||||
.IP \[bu]
|
||||
-1: Catchall nonspecific error\.
|
||||
.IP \[bu]
|
||||
1000: Offer with this offer_id already exists\.
|
||||
1000: Offer with this offer_id already exists (but is not active)\.
|
||||
|
||||
.RE
|
||||
.SH AUTHOR
|
||||
|
@ -152,4 +159,4 @@ Rusty Russell \fI<rusty@rustcorp.com.au\fR> is mainly responsible\.
|
|||
|
||||
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
|
||||
|
||||
\" SHA256STAMP:f7faf86c7cb052200c3b4d6e3d6209afa54600cc7a33e1082583a2766d02a275
|
||||
\" SHA256STAMP:bd1bae6f6b56d4efa95e17b7aff042b897acacdd783cef7df0dd729f6c9b5d8f
|
||||
|
|
|
@ -11,9 +11,10 @@ SYNOPSIS
|
|||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
The **offer** RPC command creates an offer, which is a precursor to
|
||||
creating one or more invoices. It automatically enables the processing of
|
||||
an incoming invoice_request, and issuing of invoices.
|
||||
The **offer** RPC command creates an offer (or returns an existing
|
||||
one), which is a precursor to creating one or more invoices. It
|
||||
automatically enables the processing of an incoming invoice_request,
|
||||
and issuing of invoices.
|
||||
|
||||
Note that it creates two variants of the offer: a signed and an
|
||||
unsigned one (which is smaller). Wallets should accept both: the
|
||||
|
@ -100,7 +101,8 @@ On success, an object is returned, containing:
|
|||
- **single_use** (boolean): whether this expires as soon as it's paid (reflects the *single_use* parameter)
|
||||
- **bolt12** (string): the bolt12 encoding of the offer
|
||||
- **bolt12_unsigned** (string): the bolt12 encoding of the offer, without a signature
|
||||
- **used** (boolean): True if an associated invoice has been paid (always *false*)
|
||||
- **used** (boolean): True if an associated invoice has been paid
|
||||
- **created** (boolean): false if the offer already existed
|
||||
- **label** (string, optional): the (optional) user-specified label
|
||||
[comment]: # (GENERATE-FROM-SCHEMA-END)
|
||||
|
||||
|
@ -109,9 +111,12 @@ lightning process fails before responding, the caller should use
|
|||
lightning-listoffers(7) to query whether this offer was created or
|
||||
not.
|
||||
|
||||
If the offer already existed, and is still active, that is returned;
|
||||
if it's not active then this call fails.
|
||||
|
||||
The following error codes may occur:
|
||||
- -1: Catchall nonspecific error.
|
||||
- 1000: Offer with this offer_id already exists.
|
||||
- 1000: Offer with this offer_id already exists (but is not active).
|
||||
|
||||
AUTHOR
|
||||
------
|
||||
|
@ -128,4 +133,4 @@ RESOURCES
|
|||
|
||||
Main web site: <https://github.com/ElementsProject/lightning>
|
||||
|
||||
[comment]: # ( SHA256STAMP:0f9cfd3cc68aaba20af0eee763c93b475016619d960e3f5bbc0b762a809f0fef)
|
||||
[comment]: # ( SHA256STAMP:53f1460e28d45129b2c00b7116c87eb47a5b717f7912f499e864f4aa28b320fa)
|
||||
|
|
4
doc/lightning-offerout.7
generated
4
doc/lightning-offerout.7
generated
|
@ -73,6 +73,8 @@ On success, an object is returned, containing:
|
|||
.IP \[bu]
|
||||
\fBused\fR (boolean): True if an incoming invoice has been paid (always \fIfalse\fR)
|
||||
.IP \[bu]
|
||||
\fBcreated\fR (boolean): false if the offer already existed
|
||||
.IP \[bu]
|
||||
\fBlabel\fR (string, optional): the (optional) user-specified label
|
||||
|
||||
.RE
|
||||
|
@ -113,4 +115,4 @@ Rusty Russell \fI<rusty@rustcorp.com.au\fR> is mainly responsible\.
|
|||
|
||||
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
|
||||
|
||||
\" SHA256STAMP:3de11c6de7905322d9ef748981fc1d4f9ca91f4be46d76af6e9124572853047d
|
||||
\" SHA256STAMP:4998ef3e06f37823c969a524fc3deb96b58eb2babee560df27e3f006fc535186
|
||||
|
|
|
@ -61,6 +61,7 @@ On success, an object is returned, containing:
|
|||
- **bolt12** (string): the bolt12 encoding of the offer
|
||||
- **bolt12_unsigned** (string): the bolt12 encoding of the offer, without a signature
|
||||
- **used** (boolean): True if an incoming invoice has been paid (always *false*)
|
||||
- **created** (boolean): false if the offer already existed
|
||||
- **label** (string, optional): the (optional) user-specified label
|
||||
[comment]: # (GENERATE-FROM-SCHEMA-END)
|
||||
|
||||
|
@ -97,4 +98,4 @@ RESOURCES
|
|||
|
||||
Main web site: <https://github.com/ElementsProject/lightning>
|
||||
|
||||
[comment]: # ( SHA256STAMP:2b7e7b543a88a10dbfbca2508e034af79f43ed0845abdb9df1fdf7e28ee33c26)
|
||||
[comment]: # ( SHA256STAMP:14fada9336956a08b6d55c4ce01fcb62726cbdef9a065f1966335f61c4e91ce5)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [ "offer_id", "active", "single_use", "bolt12", "bolt12_unsigned", "used" ],
|
||||
"required": [ "offer_id", "active", "single_use", "bolt12", "bolt12_unsigned", "used", "created" ],
|
||||
"properties": {
|
||||
"offer_id": {
|
||||
"type": "hex",
|
||||
|
@ -29,9 +29,12 @@
|
|||
},
|
||||
"used": {
|
||||
"type": "boolean",
|
||||
"enum": [ false ],
|
||||
"description": "True if an associated invoice has been paid"
|
||||
},
|
||||
"created": {
|
||||
"type": "boolean",
|
||||
"description": "false if the offer already existed"
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "the (optional) user-specified label"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [ "offer_id", "active", "single_use", "bolt12", "bolt12_unsigned", "used" ],
|
||||
"required": [ "offer_id", "active", "single_use", "bolt12", "bolt12_unsigned", "used", "created" ],
|
||||
"properties": {
|
||||
"offer_id": {
|
||||
"type": "hex",
|
||||
|
@ -33,6 +33,10 @@
|
|||
"enum": [ false ],
|
||||
"description": "True if an incoming invoice has been paid"
|
||||
},
|
||||
"created": {
|
||||
"type": "boolean",
|
||||
"description": "false if the offer already existed"
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "the (optional) user-specified label"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <ccan/cast/cast.h>
|
||||
#include <common/bolt12.h>
|
||||
#include <common/bolt12_merkle.h>
|
||||
#include <common/configdir.h>
|
||||
|
@ -91,6 +92,7 @@ static struct command_result *json_createoffer(struct command *cmd,
|
|||
bool *single_use;
|
||||
enum offer_status status;
|
||||
struct pubkey32 key;
|
||||
bool created;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("bolt12", param_b12_offer, &offer),
|
||||
|
@ -110,17 +112,28 @@ static struct command_result *json_createoffer(struct command *cmd,
|
|||
hsm_sign_b12(cmd->ld, "offer", "signature", &merkle, NULL, &key,
|
||||
offer->signature);
|
||||
b12str = offer_encode(cmd, offer);
|
||||
if (!wallet_offer_create(cmd->ld->wallet, &merkle, b12str, label,
|
||||
status)) {
|
||||
return command_fail(cmd,
|
||||
OFFER_ALREADY_EXISTS,
|
||||
"Duplicate offer");
|
||||
}
|
||||
|
||||
/* If it already exists, we use that one instead (and then
|
||||
* the offer plugin will complain if it's inactive or expired) */
|
||||
if (!wallet_offer_create(cmd->ld->wallet, &merkle,
|
||||
b12str, label, status)) {
|
||||
if (!wallet_offer_find(cmd, cmd->ld->wallet, &merkle,
|
||||
cast_const2(const struct json_escape **,
|
||||
&label),
|
||||
&status)) {
|
||||
return command_fail(cmd, LIGHTNINGD,
|
||||
"Could not create, nor find offer");
|
||||
}
|
||||
created = false;
|
||||
} else
|
||||
created = true;
|
||||
|
||||
offer->signature = tal_free(offer->signature);
|
||||
b12str_nosig = offer_encode(cmd, offer);
|
||||
|
||||
response = json_stream_success(cmd);
|
||||
json_populate_offer(response, &merkle, b12str, b12str_nosig, label, status);
|
||||
json_add_bool(response, "created", created);
|
||||
return command_success(cmd, response);
|
||||
}
|
||||
|
||||
|
|
|
@ -255,6 +255,31 @@ struct offer_info {
|
|||
bool *single_use;
|
||||
};
|
||||
|
||||
static struct command_result *check_result(struct command *cmd,
|
||||
const char *buf,
|
||||
const jsmntok_t *result,
|
||||
void *arg UNNEEDED)
|
||||
{
|
||||
bool active;
|
||||
|
||||
/* If it's inactive, we can't return it, */
|
||||
if (!json_to_bool(buf, json_get_member(buf, result, "active"),
|
||||
&active)) {
|
||||
return command_fail(cmd,
|
||||
LIGHTNINGD,
|
||||
"Bad creaoffer status reply %.*s",
|
||||
json_tok_full_len(result),
|
||||
json_tok_full(buf, result));
|
||||
}
|
||||
if (!active)
|
||||
return command_fail(cmd,
|
||||
OFFER_ALREADY_EXISTS,
|
||||
"Offer already exists, but isn't active");
|
||||
|
||||
/* Otherwise, push through the result. */
|
||||
return forward_result(cmd, buf, result, arg);
|
||||
}
|
||||
|
||||
static struct command_result *create_offer(struct command *cmd,
|
||||
struct offer_info *offinfo)
|
||||
{
|
||||
|
@ -262,7 +287,7 @@ static struct command_result *create_offer(struct command *cmd,
|
|||
|
||||
/* We simply pass this through. */
|
||||
req = jsonrpc_request_start(cmd->plugin, cmd, "createoffer",
|
||||
forward_result, forward_error,
|
||||
check_result, forward_error,
|
||||
offinfo);
|
||||
json_add_string(req->js, "bolt12",
|
||||
offer_encode(tmpctx, offinfo->offer));
|
||||
|
@ -436,9 +461,8 @@ struct command_result *json_offerout(struct command *cmd,
|
|||
|
||||
offer->node_id = tal_dup(offer, struct pubkey32, &id);
|
||||
|
||||
/* We simply pass this through. */
|
||||
req = jsonrpc_request_start(cmd->plugin, cmd, "createoffer",
|
||||
forward_result, forward_error,
|
||||
check_result, forward_error,
|
||||
offer);
|
||||
json_add_string(req->js, "bolt12", offer_encode(tmpctx, offer));
|
||||
if (label)
|
||||
|
|
|
@ -4122,6 +4122,7 @@ def test_fetchinvoice(node_factory, bitcoind):
|
|||
# Simple offer first.
|
||||
offer1 = l3.rpc.call('offer', {'amount': '2msat',
|
||||
'description': 'simple test'})
|
||||
assert offer1['created'] is True
|
||||
|
||||
inv1 = l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12']})
|
||||
inv2 = l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12_unsigned'],
|
||||
|
@ -4274,6 +4275,15 @@ def test_fetchinvoice(node_factory, bitcoind):
|
|||
# But we can still pay the (already-converted) invoice.
|
||||
l1.rpc.pay(inv['invoice'])
|
||||
|
||||
# Identical creation gives it again, just with created false.
|
||||
offer1 = l3.rpc.call('offer', {'amount': '2msat',
|
||||
'description': 'simple test'})
|
||||
assert offer1['created'] is False
|
||||
l3.rpc.call('disableoffer', {'offer_id': offer1['offer_id']})
|
||||
with pytest.raises(RpcError, match="1000.*Offer already exists, but isn't active"):
|
||||
l3.rpc.call('offer', {'amount': '2msat',
|
||||
'description': 'simple test'})
|
||||
|
||||
# Test timeout.
|
||||
l3.stop()
|
||||
with pytest.raises(RpcError, match='Timeout waiting for response'):
|
||||
|
|
Loading…
Add table
Reference in a new issue