Browse Source

pyln-client: Add facility to register featurebits from plugins

we have 4 venues in which we can add features, 3 of which are unilaterally
controlled (`init`, `node_announcement`, and `invoices`) the
`channel_announcement` is co-signed by both parties, so we can't add
featurebits without additional coordination overhead.

Each location is encoded as a key-value pair in a dict called `featurebits` in
the manifest (omitted if no custom featurebits are set).
travis-debug
Christian Decker 5 years ago
committed by Rusty Russell
parent
commit
a13591400a
  1. 42
      contrib/pyln-client/pyln/client/plugin.py

42
contrib/pyln-client/pyln/client/plugin.py

@ -1,3 +1,4 @@
from binascii import hexlify
from collections import OrderedDict from collections import OrderedDict
from enum import Enum from enum import Enum
from .lightning import LightningRpc, Millisatoshi from .lightning import LightningRpc, Millisatoshi
@ -5,6 +6,7 @@ from threading import RLock
import inspect import inspect
import json import json
import math
import os import os
import re import re
import sys import sys
@ -99,10 +101,37 @@ class Plugin(object):
""" """
def __init__(self, stdout=None, stdin=None, autopatch=True, dynamic=True): def __init__(self, stdout=None, stdin=None, autopatch=True, dynamic=True,
init_features=None, node_features=None, invoice_features=None):
self.methods = {'init': Method('init', self._init, MethodType.RPCMETHOD)} self.methods = {'init': Method('init', self._init, MethodType.RPCMETHOD)}
self.options = {} self.options = {}
def convert_featurebits(bits):
"""Convert the featurebits into the bytes required to hexencode.
"""
if bits is None:
return None
elif isinstance(bits, int):
bitlen = math.ceil(math.log(bits, 256))
return hexlify(bits.to_bytes(bitlen, 'big')).decode('ASCII')
elif isinstance(bits, str):
# Assume this is already hex encoded
return bits
elif isinstance(bits, bytes):
return hexlify(bits).decode('ASCII')
else:
raise ValueError("Could not convert featurebits to hex-encoded string")
self.featurebits = {
'init': convert_featurebits(init_features),
'node': convert_featurebits(node_features),
'invoice': convert_featurebits(invoice_features),
}
# A dict from topics to handler functions # A dict from topics to handler functions
self.subscriptions = {} self.subscriptions = {}
@ -523,14 +552,21 @@ class Plugin(object):
if method.long_desc: if method.long_desc:
methods[len(methods) - 1]["long_description"] = method.long_desc methods[len(methods) - 1]["long_description"] = method.long_desc
return { manifest = {
'options': list(self.options.values()), 'options': list(self.options.values()),
'rpcmethods': methods, 'rpcmethods': methods,
'subscriptions': list(self.subscriptions.keys()), 'subscriptions': list(self.subscriptions.keys()),
'hooks': hooks, 'hooks': hooks,
'dynamic': self.dynamic 'dynamic': self.dynamic,
} }
# Compact the features a bit, not important.
features = {k: v for k, v in self.featurebits.items() if v is not None}
if features is not None:
manifest['featurebits'] = features
return manifest
def _init(self, options, configuration, request): def _init(self, options, configuration, request):
self.rpc_filename = configuration['rpc-file'] self.rpc_filename = configuration['rpc-file']
self.lightning_dir = configuration['lightning-dir'] self.lightning_dir = configuration['lightning-dir']

Loading…
Cancel
Save