Skip to content

Commit

Permalink
delpay: introduced a new rpc method to delete a payment by hash
Browse files Browse the repository at this point in the history
Changelog-Added: JSON-RPC: delpay a new method to delete the payment completed or failed.
  • Loading branch information
vincenzopalazzo committed Aug 3, 2020
1 parent 094eac4 commit bfb4282
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ MANPAGES := doc/lightning-cli.1 \
doc/lightning-decodepay.7 \
doc/lightning-delexpiredinvoice.7 \
doc/lightning-delinvoice.7 \
doc/lightning-delpay.7 \
doc/lightning-dev-sendcustommsg.7 \
doc/lightning-disconnect.7 \
doc/lightning-feerates.7 \
Expand Down
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ c-lightning Documentation
lightning-decodepay <lightning-decodepay.7.md>
lightning-delexpiredinvoice <lightning-delexpiredinvoice.7.md>
lightning-delinvoice <lightning-delinvoice.7.md>
lightning-delpay <lightning-delpay.7.md>
lightning-dev-sendcustommsg <lightning-dev-sendcustommsg.7.md>
lightning-disconnect <lightning-disconnect.7.md>
lightning-feerates <lightning-feerates.7.md>
Expand Down
63 changes: 63 additions & 0 deletions doc/lightning-delpay.7

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions doc/lightning-delpay.7.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
lightning-delpay -- Command for removing a completed payment
============================================================

SYNOPSIS
--------

**delpay** *payment_hash* \[status\] (is not specify the status is complete)

DESCRIPTION
-----------

The **delpay** RPC command removes a payment as given in **listsendpays** or **listpays** with a complete or failed
status. However, the command doesn't permit to remove the pending payment.

EXAMPLE JSON REQUEST
------------
```json
{
"id": 82,
"method": "delpay",
"params": {
"payment_hash": "4fa2f1b001067ec06d7f95b8695b8acd9ef04c1b4d1110e3b94e1fa0687bb1e0",
"status": "complete"
}
}
```

RETURN VALUE
------------

On success, the command will return a payment object, such as the listpays.

On failure, an error is returned and any payment is deleted. If the lightning process fails before responding, the
caller should use lightning-listsentpays(7) or lightning-listpays(7) to query whether this payment was deleted or not.

The following error codes may occur:

- -32602: Some parameter missed or some parameter is malformed;
- -1: Payment with wrong status
- -1: Payment not found.

-
AUTHOR
------

Vincenzo Palazzo <<vincenzopalazzodev@gmail.com>> is mainly responsible.

SEE ALSO
--------

lightning-listpays(7), lightning-listsendpays(7),
lightning-pay(7), lightning-paystatus(7),
~~lightning-keysend(7)~~

RESOURCES
---------

Main web site: <https://github.com/ElementsProject/lightning>
93 changes: 93 additions & 0 deletions lightningd/pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,31 @@ struct sendpay_command {
struct command *cmd;
};

static enum wallet_payment_status string_to_payment_status(const char *status_str)
{
if (streq(status_str, "complete")) {
return PAYMENT_COMPLETE;
} else if (streq(status_str, "failed")) {
return PAYMENT_FAILED;
} else if (streq(status_str, "pending")) {
return PAYMENT_PENDING;
}
return -1;
}

static const char *payment_status_to_string(const enum wallet_payment_status status)
{
switch (status) {
case PAYMENT_COMPLETE:
return "complete";
case PAYMENT_FAILED:
return "failed";
default:
return "pending";
}
}


static void destroy_sendpay_command(struct sendpay_command *pc)
{
list_del(&pc->list);
Expand Down Expand Up @@ -1496,6 +1521,74 @@ static const struct json_command listsendpays_command = {
};
AUTODATA(json_command, &listsendpays_command);

static struct command_result *json_delpay(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct json_stream *response;
const struct wallet_payment *payment;
const char *status_str;
enum wallet_payment_status status;
struct sha256 *payment_hash;
u64 *partid;

if (!param(cmd, buffer, params,
p_req("payment_hash", param_sha256, &payment_hash),
p_opt("status", param_string, &status_str),
p_opt_def("partid", param_u64, &partid, 0),
NULL))
return command_param_failed();

if (!payment_hash)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"missing required parameter: payment_hash");


status = status_str == NULL ? PAYMENT_COMPLETE : string_to_payment_status(status_str);

if (status == -1)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"status insert %s wrong", status_str);

if (status == PAYMENT_PENDING)
return command_fail(cmd, LIGHTNINGD, "invalid status: %s",
payment_status_to_string(status));

payment = wallet_payment_by_hash(cmd, cmd->ld->wallet, payment_hash, *partid);

//FIXME(vicenzopalazzo): set the correct error about payment not found
if (!payment)
return command_fail(cmd, LIGHTNINGD,
"unknown payment with payment_hash: %s and status: %s",
type_to_string(tmpctx, struct sha256, payment_hash),
payment_status_to_string(status));

//FIXME(vicenzopalazzo) set the correct error about status
if (payment->status != status)
return command_fail(cmd, LIGHTNINGD,
"payment status is %s not %s",
payment_status_to_string(payment->status),
payment_status_to_string(status));

wallet_payment_delete(cmd->ld->wallet, payment_hash, payment->partid);

response = json_stream_success(cmd);
json_object_start(response, "payment");
json_add_payment_fields(response, payment);
json_object_end(response);

return command_success(cmd, response);
}

static const struct json_command delpay_command = {
"delpay",
"payment",
json_delpay,
"Delete payment with {payment_hash} and {status}, (if no is complete)",
};
AUTODATA(json_command, &delpay_command);

static struct command_result *json_createonion(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
Expand Down
55 changes: 55 additions & 0 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -3221,3 +3221,58 @@ def test_bolt11_null_after_pay(node_factory, bitcoind):
pays = l2.rpc.listpays()["pays"]
assert(pays[0]["bolt11"] == invl1)
assert('amount_msat' in pays[0] and pays[0]['amount_msat'] == amt)


def test_delpay_argument_invalid(node_factory):
"""
This test includes all possible combination of input error inside the
delpay command.
TODO(vincenzopalazzo) more sanity test when the payment exists.
"""

l1 = node_factory.get_node()

with pytest.raises(RpcError):
l1.rpc.delpay()

# invoice unpayed
payment_hash = l1.rpc.invoice(10**5, "no_payed", "Invoice unpayed")["payment_hash"]
with pytest.raises(RpcError):
l1.rpc.delpay(payment_hash)

# payment unpayed with wrong status (pending status is a illegal imput)
with pytest.raises(RpcError):
l1.rpc.delpay(payment_hash, "pending")

with pytest.raises(RpcError):
l1.rpc.delpay(payment_hash, "invalid_status")


def test_delpay(node_factory, bitcoind):
"""
This unit test try to catch some error inside the command
delpay when it receives the correct input from the user
"""

l1, l2 = node_factory.get_nodes(2)

amount_sat = 10 ** 6

# create l2->l1 channel.
l2.fundwallet(amount_sat * 5)
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l2.rpc.fundchannel(l1.info['id'], amount_sat * 3)

# Let the channel confirm.
bitcoind.generate_block(6)
sync_blockheight(bitcoind, [l1, l2])

invl1 = l1.rpc.invoice(Millisatoshi(amount_sat * 2 * 1000), "j", "j")
l2.rpc.pay(invl1["bolt11"])

before_del_pay = l2.rpc.listpays()

l2.rpc.delpay(invl1["payment_hash"])

after_del_pay = l2.rpc.listpays()["pays"]
assert len(after_del_pay) == (len(before_del_pay) - 1)

0 comments on commit bfb4282

Please sign in to comment.