<div>Good morning c-lightningers,<br></div><div><br></div><div>Ideally, a nontechnical human user will simply cause funds to be sent to their c-lightning node, and then some time after be able to send funds on Lightning.<br></div><div><br></div><div>A step towards that ideal, is an autopilot (similar to that of lnd) which manages onchain funds and opens channels to the network as it detects funds.<br></div><div><br></div><div>So I propose an autopilotd, of the below architecture<br></div><div><br></div><div>--<br></div><div><br></div><div>At lightningd, we add support by a new autopilot_control.[ch] module.  This provides a `struct autopilotd`.  Creating this object by `new_autopilotd` will launch the `lightning_autopilotd` subd.  Destroying this tal-allocated object will shut down forcibly the subd.<br></div><div><br></div><div>Internally, the `new_autopilotd` will need to be provided a socket.  This socket is access to the JSON-RPC (i.e. it is backed by a `struct json_connection` that is the other end of the socket).<br></div><div><br></div><div>In addition, the `new_autopilotd` will create a new socket, which will be the status socket.<br></div><div><br></div><div>The `lightning_autopilotd` program will then receive two sockets on startup: the JSON-RPC control socket and the status socket.<br></div><div><br></div><div>The autopilot primarily interacts with lightningd via the JSON-RPC socket.  The status socket simply contains autopilotd->lightningd status messages, which are put into a billboard (similar to the channel-level daemon billboards).  The lightningd has no need to send commands to the autopilot: enabling autopilot simply means starting `lightning_autopilotd` (i.e. creating a `struct autopilotd`), disabling autopilot simply means killing `lightning_autopilotd` and closing its attached sockets (i.e. destroying the `struct autopilotd`).  Configuration data for the autopilot can be provided in the `listconfigs` command, which the autopilotd can query via the JSON-RPC socket.<br></div><div><br></div><div>Why does autopilot interact primarily via the JSON-RPC interface?  Others may have better ideas on how to manage channels, perhaps with better integration with higher-level user-facing applications.  Such applications are likely to use JSON-RPC.  By using JSON-RPC ourselves for our built-in autopilot, we can find out if there are missing features/commands/info in JSON-RPC that prevent a good autopilot from being implemented via JSON-RPC, i.e. we are forced to eat our own dog food.<br></div><div><br></div><div>So, this is the architecture as seen from the lightningd side: we hand over a JSON-RPC command interface, and a status interface that we store in the logs.  We provide RPC commands to turn on/off the autopilot and change its configuration, and query its billboard.<br></div><div><br></div><div>--<br></div><div><br></div><div>At the autopilotd side, we split up the autopilot into two parts: a driver and an algorithm wrangler.<br></div><div><br></div><div>The driver is obsessed with one thing: converting onchain funds into onLightning funds.  Periodically (every 3 seconds?) it performs `listfunds`.  If that shows any onchain funds, driver gets a candidate node from its queue of candidate nodes, tries to connect and fundchannel to it, until it has run out of onchain funds.  If that queue of candidate nodes is empty, it then requests for a new queue of candidate nodes from the algorithm wrangler.<br></div><div><br></div><div>The algorithm wrangler calls out to a list of algorithms.  Those algorithms are given an (initially empty) sequence of candidate nodes, and can manipulate that sequence of nodes (add entries primarily, remove entries, rearrange..).  The algorithms the wrangler uses can be configured at lightningd (the wrangler uses `listconfigs` to get the configuration), as a comma-separated list of algorithm names.  When the algorithm wrangler finishes calling all the listed algorithms, it returns the resulting sequence of candidate nodes to the driver, which then proceeds to its work of putting onchain funds onLightning.<br></div><div><br></div><div>Example algorithms could be:<br></div><div><br></div><div>* `random` - get all known nodes from `listchannels` command, randomly select one.<br></div><div>* `customer` - get payments from `listpayments`, check which payee node we pay to often, and select the most-often-paid node that we do not have a direct channel to already.<br></div><div>* `superhub` - see "Towards a gridlike Lightning Network" topic on lightning-dev: <a href="https://lists.linuxfoundation.org/pipermail/lightning-dev/2018-March/001108.html">https://lists.linuxfoundation.org/pipermail/lightning-dev/2018-March/001108.html</a><br></div><div>* `bridger` - get all known nodes from `listchannels` command, look for nodes with least number of public channels (if that node becomes a popular payee we have a chance of being on one of the few viable routes to it).  Select one from the lowest bin as candidate.<br></div><div>* `EVILCENTRALIZERDONOTUSE` - get all known nodes from `listchannels`, look for nodes with most number of public channels (more likely that node will be able to route our own payments to our destination with all the channels it has).  Select one from the highest bin as candidate.<br></div><div>* `blockstream` - add store.blockstream.com as candidate hahahahahaha.<br></div><div><br></div><div>Now a good number of the above algorithms call `listchannels` and other queries from the lightningd.  It would be wasteful to re-query lightningd each time, if the user configures multiple algorithms that each call `listchannels`.  One thing we can do is to cache such queries.  Start the cache empty.  When an algorithm asks for a query, check if it is already done and try to get it from the cache, else go actually perform the query and store it.  Then if the user lists multiple algorithms that call the same query on lightningd, only the first algorithm needs to wait for the reply, and succeeding algorithms simply reuse the same data.  The cache is reset just before the algorithm wrangler completes and returns the list of nodes.<br></div><div><br></div><div>For example, someone who wants to become a hub node may want the `superhub` and `bridger` algorithms to run, and as a fallback also the `random` algorithm to sometimes connect to random nodes in case they become useful someday.  Someone who just wants to pay for groceries and coffee might want `customer` and `EVILCENTRALIZERDONOTUSE`, and once Blockstream starts selling coffee maybe `blockstream`.<br></div><div><br></div><div>The resulting list of nodes after all algorithms have run may have duplicates, i.e. if multiple algorithms think those are good candidates.  The wrangler can also prioritize nodes that have duplicates over nodes that do not have duplicates.<br></div><div><br></div><div>Separating bits of logic into the "algorithm" system suggests we can provide a plug-in system eventually, by which external projects can provide new algorithms that change or tweak how autopilot works.<br></div><div><br></div><div>--<br></div><div><br></div><div>In addition, we want to consider the question of closing channels.<br></div><div><br></div><div>Obviously we will want good statistics, e.g. how many payments we have succeeded on that channel, how much those payments are, etc.<br></div><div><br></div><div>A similar system for algorithms could be done too, although I am unsure how the driver decides when to close channels.<br></div><div><br></div><div>Perhaps the wrangler can unify things somewhat: each algorithm has multiple possible entry points, one for opening, one for closing, and those are optional to the algorithm (an algorithm can have entrypoint for opening channel, entrypoint for closing channel, or both).  Then the driver calls the wrangler on whether it wants to open channels or close them.  This will let us configure autopilot with a single list.<br></div><div><br></div><div>Regards,<br></div><div>ZmnSCPxj<br></div>