ElementsProject / lightning

Core Lightning — Lightning Network implementation focusing on spec compliance and performance
Other
2.85k stars 902 forks source link

Sendpay usage is not clear from the documentation #3419

Open s-tikhomirov opened 4 years ago

s-tikhomirov commented 4 years ago

Issue and Steps to Reproduce

It's not clear from the documentation how this command should be used:

sendpay route payment_hash [label] [msatoshi] [bolt11] [partid]

I send a payment to a neighboring node 03b6 with the hash value of ones and get an error:

lightning-cli sendpay [03b66cddd29beb92f9fbdce91924cde26904ba7f5c44ddf73c4d3e0379541b3987] '1111111111111111111111111111111111111111111111111111111111111111' 
{
   "code": -32602,
   "message": "Expected array or object for params"
}

How should I use sendpay?

getinfo output

{
   "id": "03068d9ac7f6973cbdb7212f2598afee2db14becd3d31e937659b0c09cee9f78f2",
   "alias": "clightningM",
   "color": "03068d",
   "num_peers": 2,
   "num_pending_channels": 0,
   "num_active_channels": 2,
   "num_inactive_channels": 0,
   "address": [],
   "binding": [
      {
         "type": "ipv4",
         "address": "127.0.0.1",
         "port": 9737
      }
   ],
   "version": "v0.8.0-40-g899f5de",
   "blockheight": 995,
   "network": "regtest",
   "msatoshi_fees_collected": 0,
   "fees_collected_msat": "0msat",
   "lightning-dir": "/home/sergei/.lightning/regtest"
}
darosior commented 4 years ago

It wants the output of the getroute command as the first argument. You can use dev-rhash for the second one.

That said sendpay isnt meant to be used by [end users / directly from the cli] but rather by plugins or low-level applications, prefer using pay.

s-tikhomirov commented 4 years ago

@darosior I unserstand that pay is the preferred way but still want to use sendpay for my purposes. I'm gonna use it in a plugin eventually, just wanted to understand how it works using the CLI first.

Now I'm trying this (using getroute output without whitespace as the first argument):

$ lightning-cli sendpay {"route":[{"id":"03b66cddd29beb92f9fbdce91924cde26904ba7f5c44ddf73c4d3e0379541b3987","channel":"693x1x0","direction":0,"msatoshi":100,"amount_msat":"100msat","delay":9,"style":"tlv"}]} '1111111111111111111111111111111111111111111111111111111111111111'
lightning-cli: Incorrect 'id' in response: null

Am I on the right track?

What is dev-rhash and how do I use it (the docs don't have any info on this)?

UPD Tried the same from a plugin.

Plugin code (initialization omitted):

@plugin.method("sendpay_test")
def sendpay_test(plugin, receiver):
    route = plugin.rpc.getroute(
        receiver,
        1000,
        0
        )
    sendpay_result = plugin.rpc.sendpay(
        route=[n['id'] for n in route['route']],
        payment_hash=1111111111111111111111111111111111111111111111111111111111111111,
        msatoshi=1000
        )
    return sendpay_result

Then I call it with:

lightning-cli sendpay_test 03b66cddd29beb92f9fbdce91924cde26904ba7f5c44ddf73c4d3e0379541b3987

I get:

"Error while processing sendpay_test: RpcError('RPC call failed: method: sendpay, payload: {\\'route\\': {\\'route\\': [{\\'id\\': \\'03b66cddd29beb92f9fbdce91924cde26904ba7f5c44ddf73c4d3e0379541b3987\\', \\'channel\\': \\'693x1x0\\', \\'direction\\': 0, \\'msatoshi\\': 1000, \\'amount_msat\\': 1000msat, \\'delay\\': 9, \\'style\\': \\'tlv\\'}]}, \\'payment_hash\\': 1111111111111111111111111111111111111111111111111111111111111111, \\'msatoshi\\': 1000}, error: {\\'code\\': -32602, \\'message\\': \\'\\\\\\'route\\\\\\' should be an array, not \\\\\\'{\"route\": [{\"id\": \"03b66cddd29beb92f9fbdce91924cde26904ba7f5c44ddf73c4d3e0379541b3987\", \"channel\": \"693x1x0\", \"direction\": 0, \"msatoshi\": 1000, \"amount_msat\": \"1000msat\", \"delay\": 9, \"style\": \"tlv\"}]}\\\\\\'\\'}',)"

I also tried extracting the list of node IDs from the output of getroute (route = [n['id'] for n in route['route']]) and passing it to sendpay. Now I get:

"Error while processing sendpay_test: RpcError(\"RPC call failed: method: sendpay, payload: {'route': ['03b66cddd29beb92f9fbdce91924cde26904ba7f5c44ddf73c4d3e0379541b3987'], 'payment_hash': 1111111111111111111111111111111111111111111111111111111111111111, 'msatoshi': 1000}, error: {'code': -32602, 'message': 'Expected array or object for params'}\",)"

UPD2 Here is what I actually works (issue #2010 helped).

The gist: sendpay expects an array of objects describing a node. getroute returns a dictionary ({}) with that array as the value at key route.

This is what works from the plugin:

sendpay_result = plugin.rpc.sendpay(
        route=route['route'],
        payment_hash=1111111111111111111111111111111111111111111111111111111111111111,
        msatoshi=1000
        )

And from CLI:

$ lightning-cli sendpay '[{"id": "03b66cddd29beb92f9fbdce91924cde26904ba7f5c44ddf73c4d3e0379541b3987","channel": "693x1x0","direction": 0,"msatoshi": 1000,"amount_msat": "1000msat","delay": 9,"style":"tlv"}]' "1111111111111111111111111111111111111111111111111111111111111111"

I had no issues with the manually constructed hash value: a string of 64 characters in double-quotes is OK.

I've solved my particular issues, but I have to admit that searching for the solution involved a bit of guesswork which may have not been necessary with a more clear documentation.

ZmnSCPxj commented 4 years ago

Do not transform the route with a list comprehension, instead just pass it in directly:

route = plugin.rpc.getroute(receiver, whatever2, 1)
plugin.rpc.sendpay(route=route, payment_hash=whatever, msatoshi=whatever2)

(do not set riskfactor to 0, as Strange Things (TM) will happen with getroute. I think. @cdecker knows riskfactor better than I do.)

Using the CLI to learn the interface of getroute and sendpay for routes is a bad idea: you need to understand how the shell does escapes and so on, making it difficult to use getroute and sendpay on the command line. Use them inside a plugin, and understand that the output of getroute is designed to be the input to sendpay.

dev-rhash is a dev command and is not deliberately not documented in the user docs. It might not exist if you do not compile with DEVELOPER=1. To use dev- commands and --dev- options, you should understand the source code, since such commands are usually expected to be useable only by people who do know the source code. Though dev-rhash is simple enough that maybe a devtools/ program should have it and get some minimal documentation on this.

s-tikhomirov commented 4 years ago

@ZmnSCPxj Thanks for the clarification!

Still, when I try to use the route and sendpay from a plugin as you describe, I get:

"Error while processing sendpay_test: RpcError('RPC call failed: method: sendpay, payload: {\\'route\\': {\\'route\\': [{\\'id\\': \\'03b66cddd29beb92f9fbdce91924cde26904ba7f5c44ddf73c4d3e0379541b3987\\', \\'channel\\': \\'693x1x0\\', \\'direction\\': 0, \\'msatoshi\\': 1000, \\'amount_msat\\': 1000msat, \\'delay\\': 9, \\'style\\': \\'tlv\\'}]}, \\'payment_hash\\': 1111111111111111111111111111111111111111111111111111111111111111, \\'msatoshi\\': 1000}, error: {\\'code\\': -32602, \\'message\\': \\'\\\\\\'route\\\\\\' should be an array, not \\\\\\'{\"route\": [{\"id\": \"03b66cddd29beb92f9fbdce91924cde26904ba7f5c44ddf73c4d3e0379541b3987\", \"channel\": \"693x1x0\", \"direction\": 0, \"msatoshi\": 1000, \"amount_msat\": \"1000msat\", \"delay\": 9, \"style\": \"tlv\"}]}\\\\\\'\\'}',)"

But when I extract the route from the getroute output as plugin.rpc.getroute(receiver, whatever2, 1)['route'], it works...

ZmnSCPxj commented 4 years ago

Ah, yes, I forgot that getroute returns an object which contains the route, which is the actual array in use.

Still not a good idea to try it on the command line though, it can get complicated.

cdecker commented 4 years ago

On the command line I usually do the following to do a one-off payment attempt:

lightning-cli sendpay $(lightning-cli getroute [destination_node_id] [amount_msat] 10 | jq .route) [payment_hash]

It's nesting the getroute call inside the sendpay command, but you can pull them apart:

ROUTE=$(lightning-cli getroute [destination_node_id] [amount_msat] 10 | jq .route)
lightning-cli sendpay $ROUTE [payment_hash]

Notice that I'm using jq .route to unwrap the list containing the actual route from the outer wrapper object.

s-tikhomirov commented 4 years ago

@cdecker This one doesn't work for me, surprisingly (I specify the directory explicitly due to #1768):

$ lightning-cli --lightning-dir=$HOME/.lightning-testnet sendpay $(lightning-cli --lightning-dir=$HOME/.lightning-testnet getroute 03d5e17a3c213fe490e1b0c389f8cfcfcea08a29717d50a9f453735e0ab2a7c003 1000000 10 | jq .route) "1111111111111111111111111111111111111111111111111111111111111111"
{
   "code": -32602,
   "message": "'route' should be an array, not '['"
}
darosior commented 4 years ago

@s-tikhomirov You need to quote the output and use -rc, untested but that's what I use too when I (unusually want to use sendpay from the CLI:

lightning-cli --lightning-dir=$HOME/.lightning-testnet sendpay "$(lightning-cli --lightning-dir=$HOME/.lightning-testnet getroute 03d5e17a3c213fe490e1b0c389f8cfcfcea08a29717d50a9f453735e0ab2a7c003 1000000 10 | jq -rc .route)" "1111111111111111111111111111111111111111111111111111111111111111"
darosior commented 4 years ago

Actually by just running

lightning-cli --lightning-dir=$HOME/.lightning-testnet getroute 03d5e17a3c213fe490e1b0c389f8cfcfcea08a29717d50a9f453735e0ab2a7c003 1000000 10 | jq .route

You'd have been able to see that the output is on multiple lines and thus won't work (and eventually adapt your command)..

ZmnSCPxj commented 4 years ago

Or just do not use the commandline for these, note that a good part of what you are now doing is fighting off the shell and its ad hoc methods of deciding what to pass to lightning-cli.

s-tikhomirov commented 4 years ago

fighting off the shell and its ad hoc methods

Fair enough. Are the considerations outlined in this issue worth including in the docs for sendpay? Something along the lines of: "This method is intended to be used from a plugin. Using it from CLI may be troublesome due to [insert reasons]."

ZmnSCPxj commented 4 years ago

Seems reasonable.

This method is intended to be used directly from JSON-RPC libraries of your
preferred programming language.
Using it from *lightning-cli(1)* may be difficult from most shells, as you would
need to understand how your command line shell handles text replacement
and token parsing, which is beyond the scope of this document.

Does not have to be from a plugin, just any application that can execute JSON-RPC commands to the Lightning RPC (plugins are a subset of such applications).

hyperet commented 1 year ago

I found the right expression in CLI that works:

lightning-cli sendpay '[{ "id": "~", "channel": "~", "direction": ~, "msatoshi": ~, "amount_msat": "~msat", "delay": ~, "style": "" } ]' payment_hash

You can get route info by getroute, and payment_hash from here (https://lndecode.com/) by decoding LN invoice.

harvhat commented 1 year ago

You can get route info by getroute, and payment_hash from here (https://lndecode.com/) by decoding LN invoice.

Even better you can get the payment_hash from decodepay no need to use a 3rd party service.