mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-19 05:44:12 +01:00
pylightning: Switch to dict-based params instead of positional
Signed-off-by: Christian Decker <decker.christian@gmail.com> Co-authored-by: Guido Dassori @gdassori
This commit is contained in:
parent
ed2fee8977
commit
0e40b9b08c
@ -32,36 +32,41 @@ class UnixDomainSocketRpc(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
"""Intercept any call that is not explicitly defined and call _call
|
"""Intercept any call that is not explicitly defined and call @call
|
||||||
|
|
||||||
We might still want to define the actual methods in the subclasses for
|
We might still want to define the actual methods in the subclasses for
|
||||||
documentation purposes.
|
documentation purposes.
|
||||||
"""
|
"""
|
||||||
name = name.replace('_', '-')
|
name = name.replace('_', '-')
|
||||||
|
|
||||||
def wrapper(*args, **_):
|
def wrapper(**kwargs):
|
||||||
return self._call(name, args)
|
return self.call(name, payload=kwargs)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
def _call(self, method, args=None):
|
def call(self, method, payload=None):
|
||||||
self.logger.debug("Calling %s with payload %r", method, payload)
|
self.logger.debug("Calling %s with payload %r", method, payload)
|
||||||
|
|
||||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
sock.connect(self.socket_path)
|
sock.connect(self.socket_path)
|
||||||
self._writeobj(sock, {
|
self._writeobj(sock, {
|
||||||
"method": method,
|
"method": method,
|
||||||
"params": args or (),
|
"params": payload or {},
|
||||||
"id": 0
|
"id": 0
|
||||||
})
|
})
|
||||||
resp = self._readobj(sock)
|
resp = self._readobj(sock)
|
||||||
sock.close()
|
sock.close()
|
||||||
|
|
||||||
if 'error' in resp:
|
|
||||||
raise ValueError("RPC call failed: {}".format(resp['error']))
|
|
||||||
elif 'result' not in resp:
|
|
||||||
raise ValueError("Malformed response, 'result' missing.")
|
|
||||||
return resp['result']
|
|
||||||
self.logger.debug("Received response for %s call: %r", method, resp)
|
self.logger.debug("Received response for %s call: %r", method, resp)
|
||||||
|
if "error" in resp:
|
||||||
|
raise ValueError(
|
||||||
|
"RPC call failed: {}, method: {}, payload: {}".format(
|
||||||
|
resp["error"],
|
||||||
|
method,
|
||||||
|
payload
|
||||||
|
))
|
||||||
|
elif "result" not in resp:
|
||||||
|
raise ValueError("Malformed response, \"result\" missing.")
|
||||||
|
return resp["result"]
|
||||||
|
|
||||||
|
|
||||||
class LightningRpc(UnixDomainSocketRpc):
|
class LightningRpc(UnixDomainSocketRpc):
|
||||||
@ -78,233 +83,319 @@ class LightningRpc(UnixDomainSocketRpc):
|
|||||||
between calls, but it does not (yet) support concurrent calls.
|
between calls, but it does not (yet) support concurrent calls.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def getpeer(self, peer_id, logs=None):
|
def getpeer(self, peer_id, level=None):
|
||||||
"""
|
"""
|
||||||
Show peer with {peer_id}, if {level} is set, include {log}s
|
Show peer with {peer_id}, if {level} is set, include {log}s
|
||||||
"""
|
"""
|
||||||
args = [peer_id]
|
payload = {
|
||||||
logs is not None and args.append(logs)
|
"id": peer_id,
|
||||||
res = self.listpeers(peer_id, logs)
|
"level": level
|
||||||
return res.get('peers') and res['peers'][0] or None
|
}
|
||||||
|
res = self.call("listpeers", payload)
|
||||||
|
return res.get("peers") and res["peers"][0] or None
|
||||||
|
|
||||||
def dev_blockheight(self):
|
def dev_blockheight(self):
|
||||||
"""
|
"""
|
||||||
Show current block height
|
Show current block height
|
||||||
"""
|
"""
|
||||||
return self._call("dev-blockheight")
|
return self.call("dev-blockheight")
|
||||||
|
|
||||||
def dev_setfees(self, immediate, normal=None, slow=None):
|
def dev_setfees(self, immediate, normal=None, slow=None):
|
||||||
"""
|
"""
|
||||||
Set feerate in satoshi-per-kw for {immediate}, {normal} and {slow}
|
Set feerate in satoshi-per-kw for {immediate}, {normal} and {slow}
|
||||||
(each is optional, when set, separate by spaces) and show the value of those three feerates
|
(each is optional, when set, separate by spaces) and show the value of those three feerates
|
||||||
"""
|
"""
|
||||||
args = [immediate]
|
payload = {
|
||||||
normal is not None and args.append(normal)
|
"immediate": immediate,
|
||||||
slow is not None and args.append(slow)
|
"normal": normal,
|
||||||
return self._call("dev-setfees", args=args)
|
"slow": slow
|
||||||
|
}
|
||||||
|
return self.call("dev-setfees", payload)
|
||||||
|
|
||||||
def listnodes(self, node_id=None):
|
def listnodes(self, node_id=None):
|
||||||
"""
|
"""
|
||||||
Show all nodes in our local network view
|
Show all nodes in our local network view, filter on node {id} if provided
|
||||||
"""
|
"""
|
||||||
return self._call("listnodes", args=node_id and [node_id])
|
payload = {
|
||||||
|
"id": node_id
|
||||||
|
}
|
||||||
|
return self.call("listnodes", payload)
|
||||||
|
|
||||||
def getroute(self, peer_id, msatoshi, riskfactor, cltv=None):
|
def getroute(self, peer_id, msatoshi, riskfactor, cltv=9):
|
||||||
"""
|
"""
|
||||||
Show route to {peer_id} for {msatoshi}, using {riskfactor} and optional {cltv} (default 9)
|
Show route to {id} for {msatoshi}, using {riskfactor} and optional {cltv} (default 9)
|
||||||
"""
|
"""
|
||||||
args = [peer_id, msatoshi, riskfactor]
|
payload = {
|
||||||
cltv is not None and args.append(cltv)
|
"id": peer_id,
|
||||||
return self._call("getroute", args=args)
|
"msatoshi": msatoshi,
|
||||||
|
"riskfactor": riskfactor,
|
||||||
|
"cltv": cltv
|
||||||
|
}
|
||||||
|
return self.call("getroute", payload)
|
||||||
|
|
||||||
def listchannels(self, short_channel_id=None):
|
def listchannels(self, short_channel_id=None):
|
||||||
"""
|
"""
|
||||||
Show all known channels
|
Show all known channels, accept optional {short_channel_id}
|
||||||
"""
|
"""
|
||||||
return self._call("listchannels", args=short_channel_id and [short_channel_id])
|
payload = {
|
||||||
|
"short_channel_id": short_channel_id
|
||||||
|
}
|
||||||
|
return self.call("listchannels", payload)
|
||||||
|
|
||||||
def invoice(self, msatoshi, label, description, expiry=None):
|
def invoice(self, msatoshi, label, description, expiry=None):
|
||||||
"""
|
"""
|
||||||
Create an invoice for {msatoshi} with {label} and {description} with optional {expiry} seconds (default 1 hour)
|
Create an invoice for {msatoshi} with {label} and {description} with optional {expiry} seconds (default 1 hour)
|
||||||
"""
|
"""
|
||||||
args = [msatoshi, label, description]
|
payload = {
|
||||||
expiry is not None and args.append(expiry)
|
"msatoshi": msatoshi,
|
||||||
return self._call("invoice", args=args)
|
"label": label,
|
||||||
|
"description": description,
|
||||||
|
"expiry": expiry
|
||||||
|
}
|
||||||
|
return self.call("invoice", payload)
|
||||||
|
|
||||||
def listinvoices(self, label=None):
|
def listinvoices(self, label=None):
|
||||||
"""
|
"""
|
||||||
Show invoice {label} (or all, if no {label})
|
Show invoice {label} (or all, if no {label))
|
||||||
"""
|
"""
|
||||||
return self._call("listinvoices", args=label and [label])
|
payload = {
|
||||||
|
"label": label
|
||||||
|
}
|
||||||
|
return self.call("listinvoices", payload)
|
||||||
|
|
||||||
def delinvoice(self, label, status):
|
def delinvoice(self, label, status):
|
||||||
"""
|
"""
|
||||||
Delete unpaid invoice {label} with {status}
|
Delete unpaid invoice {label} with {status}
|
||||||
"""
|
"""
|
||||||
return self._call("delinvoice", args=[label, status])
|
payload = {
|
||||||
|
"label": label,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
return self.call("delinvoice", payload)
|
||||||
|
|
||||||
def waitanyinvoice(self, lastpay_index=None):
|
def waitanyinvoice(self, lastpay_index=None):
|
||||||
"""
|
"""
|
||||||
Wait for the next invoice to be paid, after {lastpay_index} (if supplied)
|
Wait for the next invoice to be paid, after {lastpay_index} (if supplied)
|
||||||
"""
|
"""
|
||||||
return self._call("waitanyinvoice", args=lastpay_index and [lastpay_index])
|
payload = {
|
||||||
|
"lastpay_index": lastpay_index
|
||||||
|
}
|
||||||
|
return self.call("waitanyinvoice", payload)
|
||||||
|
|
||||||
def waitinvoice(self, label):
|
def waitinvoice(self, label=None):
|
||||||
"""
|
"""
|
||||||
Wait for an incoming payment matching the invoice with {label}
|
Wait for an incoming payment matching the invoice with {label}
|
||||||
"""
|
"""
|
||||||
return self._call("waitinvoice", args=[label])
|
payload = {
|
||||||
|
"label": label
|
||||||
|
}
|
||||||
|
return self.call("waitinvoice", payload)
|
||||||
|
|
||||||
def decodepay(self, bolt11, description=None):
|
def decodepay(self, bolt11, description=None):
|
||||||
"""
|
"""
|
||||||
Decode {bolt11}, using {description} if necessary
|
Decode {bolt11}, using {description} if necessary
|
||||||
"""
|
"""
|
||||||
args = [bolt11]
|
payload = {
|
||||||
description is not None and args.append(description)
|
"bolt11": bolt11,
|
||||||
return self._call("decodepay", args=args)
|
"description": description
|
||||||
|
}
|
||||||
|
return self.call("decodepay", payload)
|
||||||
|
|
||||||
def help(self):
|
def help(self):
|
||||||
"""
|
"""
|
||||||
Show available commands
|
Show available commands
|
||||||
"""
|
"""
|
||||||
return self._call("help")
|
return self.call("help")
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""
|
"""
|
||||||
Shut down the lightningd process
|
Shut down the lightningd process
|
||||||
"""
|
"""
|
||||||
return self._call("stop")
|
return self.call("stop")
|
||||||
|
|
||||||
def getlog(self, level=None):
|
def getlog(self, level=None):
|
||||||
"""
|
"""
|
||||||
Show logs, with optional log {level} (info|unusual|debug|io)
|
Show logs, with optional log {level} (info|unusual|debug|io)
|
||||||
"""
|
"""
|
||||||
return self._call("getlog", args=level and [level])
|
payload = {
|
||||||
|
"level": level
|
||||||
|
}
|
||||||
|
return self.call("getlog", payload)
|
||||||
|
|
||||||
def dev_rhash(self, secret):
|
def dev_rhash(self, secret):
|
||||||
"""
|
"""
|
||||||
Show SHA256 of {secret}
|
Show SHA256 of {secret}
|
||||||
"""
|
"""
|
||||||
return self._call("dev-rhash", [secret])
|
payload = {
|
||||||
|
"secret": secret
|
||||||
|
}
|
||||||
|
return self.call("dev-rhash", payload)
|
||||||
|
|
||||||
def dev_crash(self):
|
def dev_crash(self):
|
||||||
"""
|
"""
|
||||||
Crash lightningd by calling fatal()
|
Crash lightningd by calling fatal()
|
||||||
"""
|
"""
|
||||||
return self._call("dev-crash")
|
return self.call("dev-crash")
|
||||||
|
|
||||||
def getinfo(self):
|
def getinfo(self):
|
||||||
"""
|
"""
|
||||||
Show information about this node
|
Show information about this node
|
||||||
"""
|
"""
|
||||||
return self._call("getinfo")
|
return self.call("getinfo")
|
||||||
|
|
||||||
def sendpay(self, route, rhash):
|
def sendpay(self, route, rhash):
|
||||||
"""
|
"""
|
||||||
Send along {route} in return for preimage of {rhash}
|
Send along {route} in return for preimage of {rhash}
|
||||||
"""
|
"""
|
||||||
return self._call("sendpay", args=[route, rhash])
|
payload = {
|
||||||
|
"route": route,
|
||||||
|
"rhash": rhash
|
||||||
|
}
|
||||||
|
return self.call("sendpay", payload)
|
||||||
|
|
||||||
def pay(self, bolt11, msatoshi=None, description=None, riskfactor=None):
|
def pay(self, bolt11, msatoshi=None, description=None, riskfactor=None):
|
||||||
"""
|
"""
|
||||||
Send payment specified by {bolt11} with optional {msatoshi} (if and only if {bolt11} does not have amount),
|
Send payment specified by {bolt11} with optional {msatoshi} (if and only if {bolt11} does not have amount),
|
||||||
{description} (required if {bolt11} uses description hash) and {riskfactor} (default 1.0)
|
{description} (required if {bolt11} uses description hash) and {riskfactor} (default 1.0)
|
||||||
"""
|
"""
|
||||||
args = [bolt11]
|
payload = {
|
||||||
msatoshi is not None and args.append(msatoshi)
|
"bolt11": bolt11,
|
||||||
description is not None and args.append(description)
|
"msatoshi": msatoshi,
|
||||||
riskfactor is not None and args.append(riskfactor)
|
"description": description,
|
||||||
return self._call("pay", args=args)
|
"riskfactor": riskfactor
|
||||||
|
}
|
||||||
|
return self.call("pay", payload)
|
||||||
|
|
||||||
def listpayments(self, bolt11=None, payment_hash=None):
|
def listpayments(self, bolt11=None, payment_hash=None):
|
||||||
"""
|
"""
|
||||||
Show outgoing payments, regarding {bolt11} or {payment_hash} if set
|
Show outgoing payments, regarding {bolt11} or {payment_hash} if set
|
||||||
Can only specify one of {bolt11} or {payment_hash}
|
Can only specify one of {bolt11} or {payment_hash}
|
||||||
"""
|
"""
|
||||||
args = []
|
assert not (bolt11 and payment_hash)
|
||||||
bolt11 and args.append(bolt11)
|
payload = {
|
||||||
payment_hash and args.append(payment_hash) if args else args.extend([bolt11, payment_hash])
|
"bolt11": bolt11,
|
||||||
return self._call("listpayments", args=args)
|
"payment_hash": payment_hash
|
||||||
|
}
|
||||||
|
return self.call("listpayments", payload)
|
||||||
|
|
||||||
def connect(self, peer_id, host=None, port=None):
|
def connect(self, peer_id, host=None, port=None):
|
||||||
"""
|
"""
|
||||||
Connect to {peer_id} at {host} and {port}
|
Connect to {peer_id} at {host} and {port}
|
||||||
"""
|
"""
|
||||||
args = [peer_id]
|
payload = {
|
||||||
host is not None and args.append(host)
|
"id": peer_id,
|
||||||
port is not None and args.append(port)
|
"host": host,
|
||||||
return self._call("connect", args=args)
|
"port": port
|
||||||
|
}
|
||||||
|
return self.call("connect", payload)
|
||||||
|
|
||||||
def listpeers(self, peer_id=None, logs=None):
|
def listpeers(self, peerid=None, level=None):
|
||||||
"""
|
"""
|
||||||
Show current peers, if {level} is set, include {log}s"
|
Show current peers, if {level} is set, include {log}s"
|
||||||
"""
|
"""
|
||||||
args = peer_id is not None and [peer_id] or []
|
payload = {
|
||||||
logs is not None and args.append(logs)
|
"id": peerid,
|
||||||
return self._call("listpeers", args=args)
|
"level": level,
|
||||||
|
}
|
||||||
|
return self.call("listpeers", payload)
|
||||||
|
|
||||||
def fundchannel(self, peer_id, satoshi):
|
def fundchannel(self, channel_id, satoshi):
|
||||||
"""
|
"""
|
||||||
Fund channel with {id} using {satoshi} satoshis"
|
Fund channel with {id} using {satoshi} satoshis"
|
||||||
"""
|
"""
|
||||||
return self._call("fundchannel", args=[peer_id, satoshi])
|
payload = {
|
||||||
|
"id": channel_id,
|
||||||
|
"satoshi": satoshi
|
||||||
|
}
|
||||||
|
return self.call("fundchannel", payload)
|
||||||
|
|
||||||
def close(self, peer_id):
|
def close(self, peer_id):
|
||||||
"""
|
"""
|
||||||
Close the channel with peer {peer_id}
|
Close the channel with peer {id}
|
||||||
"""
|
"""
|
||||||
return self._call("close", args=[peer_id])
|
payload = {
|
||||||
|
"id": peer_id
|
||||||
|
}
|
||||||
|
return self.call("close", payload)
|
||||||
|
|
||||||
def dev_sign_last_tx(self, peer_id):
|
def dev_sign_last_tx(self, peer_id):
|
||||||
"""
|
"""
|
||||||
Sign and show the last commitment transaction with peer {id}
|
Sign and show the last commitment transaction with peer {id}
|
||||||
"""
|
"""
|
||||||
return self._call("dev-sign-last-tx", args=[peer_id])
|
payload = {
|
||||||
|
"id": peer_id
|
||||||
|
}
|
||||||
|
return self.call("dev-sign-last-tx", payload)
|
||||||
|
|
||||||
def dev_fail(self, peer_id):
|
def dev_fail(self, peer_id):
|
||||||
"""
|
"""
|
||||||
Fail with peer {peer_id}
|
Fail with peer {peer_id}
|
||||||
"""
|
"""
|
||||||
return self._call("dev-fail", args=[peer_id])
|
payload = {
|
||||||
|
"id": peer_id
|
||||||
|
}
|
||||||
|
return self.call("dev-fail", payload)
|
||||||
|
|
||||||
def dev_reenable_commit(self, peer_id):
|
def dev_reenable_commit(self, peer_id):
|
||||||
"""
|
"""
|
||||||
Re-enable the commit timer on peer {peer_id}
|
Re-enable the commit timer on peer {id}
|
||||||
"""
|
"""
|
||||||
return self._call("dev-reenable-commit", args=[peer_id])
|
payload = {
|
||||||
|
"id": peer_id
|
||||||
|
}
|
||||||
|
return self.call("dev-reenable-commit", payload)
|
||||||
|
|
||||||
def dev_ping(self, peer_id, length, pongbytes):
|
def dev_ping(self, peer_id, length, pongbytes):
|
||||||
"""
|
"""
|
||||||
Send {peer_id} a ping of length {length} asking for {pongbytes}"
|
Send {peer_id} a ping of length {len} asking for {pongbytes}"
|
||||||
"""
|
"""
|
||||||
return self._call("dev-ping", args=[peer_id, length, pongbytes])
|
payload = {
|
||||||
|
"id": peer_id,
|
||||||
|
"len": length,
|
||||||
|
"pongbytes": pongbytes
|
||||||
|
}
|
||||||
|
return self.call("dev-ping", payload)
|
||||||
|
|
||||||
def dev_memdump(self):
|
def dev_memdump(self):
|
||||||
"""
|
"""
|
||||||
Show memory objects currently in use
|
Show memory objects currently in use
|
||||||
"""
|
"""
|
||||||
return self._call("dev-memdump")
|
return self.call("dev-memdump")
|
||||||
|
|
||||||
def dev_memleak(self):
|
def dev_memleak(self):
|
||||||
"""
|
"""
|
||||||
Show unreferenced memory objects
|
Show unreferenced memory objects
|
||||||
"""
|
"""
|
||||||
return self._call("dev-memleak")
|
return self.call("dev-memleak")
|
||||||
|
|
||||||
def withdraw(self, destination, satoshi):
|
def withdraw(self, destination, satoshi):
|
||||||
"""
|
"""
|
||||||
Send to {destination} address {satoshi} (or 'all') amount via Bitcoin transaction
|
Send to {destination} address {satoshi} (or "all") amount via Bitcoin transaction
|
||||||
"""
|
"""
|
||||||
return self._call("withdraw", args=[destination, satoshi])
|
payload = {
|
||||||
|
"destination": destination,
|
||||||
|
"satoshi": satoshi
|
||||||
|
}
|
||||||
|
return self.call("withdraw", payload)
|
||||||
|
|
||||||
def newaddr(self, addrtype='p2sh-segwit'):
|
def newaddr(self, addresstype=None):
|
||||||
|
"""Get a new address of type {addresstype} of the internal wallet.
|
||||||
"""
|
"""
|
||||||
Get a new address to fund a channel
|
return self.call("newaddr", {"addresstype": addresstype})
|
||||||
"""
|
|
||||||
return self._call("newaddr", [addrtype])
|
|
||||||
|
|
||||||
def listfunds(self):
|
def listfunds(self):
|
||||||
"""
|
"""
|
||||||
Show funds available for opening channels
|
Show funds available for opening channels
|
||||||
"""
|
"""
|
||||||
return self._call("listfunds")
|
return self.call("listfunds")
|
||||||
|
|
||||||
|
def dev_rescan_outputs(self):
|
||||||
|
"""
|
||||||
|
Synchronize the state of our funds with bitcoind
|
||||||
|
"""
|
||||||
|
return self.call("dev-rescan-outputs")
|
||||||
|
|
||||||
|
def dev_forget_channel(self, peerid, force=False):
|
||||||
|
""" Forget the channel with id=peerid
|
||||||
|
"""
|
||||||
|
return self.call("dev-forget-channel", payload={"id": peerid, "force": force})
|
||||||
|
@ -2579,7 +2579,7 @@ class LightningDTests(BaseLightningDTests):
|
|||||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port'])
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port'])
|
||||||
|
|
||||||
# fund a bech32 address and then open a channel with it
|
# fund a bech32 address and then open a channel with it
|
||||||
res = l1.openchannel(l2, 20000, addrtype='bech32')
|
res = l1.openchannel(l2, 20000, 'bech32')
|
||||||
address = res['address']
|
address = res['address']
|
||||||
assert address[0:4] == "bcrt"
|
assert address[0:4] == "bcrt"
|
||||||
|
|
||||||
@ -3379,7 +3379,7 @@ class LightningDTests(BaseLightningDTests):
|
|||||||
for c in configs.keys():
|
for c in configs.keys():
|
||||||
if c.startswith('#'):
|
if c.startswith('#'):
|
||||||
continue
|
continue
|
||||||
oneconfig = l1.rpc.listconfigs(c)
|
oneconfig = l1.rpc.listconfigs(config=c)
|
||||||
assert(oneconfig[c] == configs[c])
|
assert(oneconfig[c] == configs[c])
|
||||||
|
|
||||||
def test_multiple_channels(self):
|
def test_multiple_channels(self):
|
||||||
@ -3492,7 +3492,7 @@ class LightningDTests(BaseLightningDTests):
|
|||||||
assert len(l1.rpc.listpeers()['peers']) == 1
|
assert len(l1.rpc.listpeers()['peers']) == 1
|
||||||
|
|
||||||
# Forcing should work
|
# Forcing should work
|
||||||
l1.rpc.dev_forget_channel(l2.info['id'], None, True)
|
l1.rpc.dev_forget_channel(l2.info['id'], True)
|
||||||
assert len(l1.rpc.listpeers()['peers']) == 0
|
assert len(l1.rpc.listpeers()['peers']) == 0
|
||||||
|
|
||||||
# And restarting should keep that peer forgotten
|
# And restarting should keep that peer forgotten
|
||||||
|
Loading…
Reference in New Issue
Block a user