clboss/Boss/Mod
Ken Sedgwick 3c8dc3c16d
FundsMover: verify incoming amount before resolving self-payment HTLCs
The claim of a returning self-payment matched payment_hash and
payment_secret but not the HTLC amount.  Answering the hook with
resolve settles the HTLC at once, so lightningd's own
final_incorrect_htlc_amount check is skipped.  The last-hop peer
relays our onion (and thus the secret) intact but chooses the offered
amount, so it could settle a reduced HTLC, learn the preimage, and
claim the full amount upstream.

Record the intended amount at Claimer::generate() time and resolve
only an exact match; a mismatch is left to normal handling, which
fails the HTLC for lack of an invoice.

The same issue was recently fixed in sling (daywalker90/sling@835f36e8).

Fixes #322.
2026-08-11 14:56:24 -07:00
..
BoltzSwapper Addition of Boltz backend on signet (clearnet address needs proxy) 2026-06-08 13:28:45 -07:00
ChannelCandidateInvestigator configure.ac: Enable C++20. 2026-01-21 11:40:01 -08:00
ChannelCreator Insert exception what() value in logging messages 2024-08-19 15:04:30 -07:00
FundsMover FundsMover: verify incoming amount before resolving self-payment HTLCs 2026-08-11 14:56:24 -07:00
PeerCompetitorFeeMonitor Handle JSON-RPC msat amounts in either the old or new conventions 2023-08-18 20:29:21 -07:00
PeerComplaintsDesk Boss/Msg/ReqRespTraits.hpp: Use a traits class for requests and response. 2023-07-11 20:57:51 +08:00
PeerJudge Insert exception what() value in logging messages 2024-08-19 15:04:30 -07:00
ActiveProber.cpp Convert some listpeers uses to listpeerchannels. 2024-06-02 16:19:56 -07:00
ActiveProber.hpp Boss/Mod/ActiveProber.cpp: active probing module. 2020-10-07 15:06:38 +08:00
all.cpp feemon: add fee monitor to save per-channel stats 2026-02-27 14:28:53 -08:00
all.hpp Boss/open_rpc_socket.cpp: Function to open the RPC socket. 2020-09-07 21:50:38 +08:00
AmountSettingsHandler.cpp Boss/Mod/all.cpp: Actuall instantiate AmountSettingsHandler. 2022-04-25 10:01:46 +00:00
AmountSettingsHandler.hpp Boss/Mod/all.cpp: Actuall instantiate AmountSettingsHandler. 2022-04-25 10:01:46 +00:00
AutoDisconnector.cpp Boss/Mod/AutoDisconnector.cpp: Module to disconnect peers if there are too many. 2020-09-13 21:51:47 +08:00
AutoDisconnector.hpp *: Silence clang warnings. 2020-11-02 19:02:35 +08:00
AvailableRpcCommandsAnnouncer.cpp Boss/Mod/AvailableRpcCommandsAnnouncer.cpp: New module to announce the commands found on this node. 2022-05-04 00:34:22 +00:00
AvailableRpcCommandsAnnouncer.hpp Boss/Mod/AvailableRpcCommandsAnnouncer.cpp: New module to announce the commands found on this node. 2022-05-04 00:34:22 +00:00
BlockTracker.cpp Fix rpc error: blockheight: should be an integer 2023-08-18 20:56:57 -07:00
BlockTracker.hpp Boss/Mod/BlockTracker.cpp: Track blocks. 2020-09-08 17:03:48 +08:00
ChannelCandidateMatchmaker.cpp Convert deprecated "msatoshi" fields to "amount_msat" 2024-04-05 12:48:08 -07:00
ChannelCandidateMatchmaker.hpp Boss/Mod/ChannelCandidateMatchmaker.cpp: Add minimum amount for channels to matchmake with. 2022-04-21 12:45:29 +08:00
ChannelCandidatePreinvestigator.cpp Boss/Msg/ReqRespTraits.hpp: Use a traits class for requests and response. 2023-07-11 20:57:51 +08:00
ChannelCandidatePreinvestigator.hpp Boss/Msg/PreinvestigateChannelCandidates.hpp: New message for preinvestigating. 2020-09-14 04:17:57 +08:00
ChannelCreateDestroyMonitor.cpp ChannelCreateDestroyMonitor: tolerate missing old_state (CLN v26.06) 2026-08-06 16:41:57 -07:00
ChannelCreateDestroyMonitor.hpp Boss/Mod/ChannelCreateDestroyMonitor.cpp: Module to monitor channel creation and destruction events. 2020-10-13 15:53:44 +08:00
ChannelCreationDecider.cpp Boss/Mod/AmountSettingsHandler.cpp: New module to centralize some size settings. 2022-04-21 12:40:02 +08:00
ChannelCreationDecider.hpp Boss/Mod/ChannelCreationDecider.cpp: Module to decide on whether to create channels. 2020-09-15 14:49:51 +08:00
ChannelFeeManager.cpp Boss/Mod/ChannelFeeManager.cpp: Support various zerobasefee settings. 2022-03-25 16:49:19 +08:00
ChannelFeeManager.hpp Boss/Mod/ChannelFeeManager.cpp: Support various zerobasefee settings. 2022-03-25 16:49:19 +08:00
ChannelFeeSetter.cpp coroutine: mitigate GCC PR 107288 coroutine issue 2026-02-27 14:28:53 -08:00
ChannelFeeSetter.hpp Boss/Mod/*: Modify items deprecated in C-Lightning 0.11. 2022-06-01 00:07:38 +00:00
ChannelFinderByDistance.cpp Boss/Mod/ChannelFinderByDistance.cpp: Use iterators for JSON. 2020-11-11 13:05:34 +08:00
ChannelFinderByDistance.hpp Boss/Mod/ChannelFinderBy*: Only re-trigger if not already running. 2020-11-03 11:26:00 +08:00
ChannelFinderByEarnedFee.cpp Insert exception what() value in logging messages 2024-08-19 15:04:30 -07:00
ChannelFinderByEarnedFee.hpp Boss/Mod/ChannelFinderByEarnedFee.cpp: Module to propose channels to peers of peers which have earned us high fees. 2020-11-13 10:26:25 +08:00
ChannelFinderByListpays.cpp Insert exception what() value in logging messages 2024-08-19 15:04:30 -07:00
ChannelFinderByListpays.hpp Boss/Mod/ChannelFinderByListpays.cpp: Ignore self-payments. 2020-11-11 13:11:32 +08:00
ChannelFinderByPopularity.cpp Decrease the testnet default for min_nodes_to_process 2025-09-11 13:49:22 -07:00
ChannelFinderByPopularity.hpp Boss/Mod/ChannelFinderByPopularity.cpp: Trigger if we are going to retry later, when a new connection comes. 2020-09-11 00:29:16 +08:00
ChannelFundsComputer.cpp Handle JSON-RPC msat amounts in either the old or new conventions 2023-08-18 20:29:21 -07:00
ChannelFundsComputer.hpp *: Silence clang warnings. 2020-11-02 19:02:35 +08:00
CommandReceiver.cpp *: Use Ln::CommandId for command IDs for received commands and hook events. 2022-11-23 00:36:43 +08:00
CommandReceiver.hpp *: Use Ln::CommandId for command IDs for received commands and hook events. 2022-11-23 00:36:43 +08:00
ComplainerByLowConnectRate.cpp Boss/Mod/ComplainerByLowConnectRate.cpp: Complain about low peer uptime. 2021-04-09 11:01:56 +08:00
ComplainerByLowConnectRate.hpp Boss/Mod/ComplainerByLowConnectRate.cpp: Complain about low peer uptime. 2021-04-09 11:01:56 +08:00
ComplainerByLowSuccessPerDay.cpp Boss/Msg/ReqRespTraits.hpp: Use a traits class for requests and response. 2023-07-11 20:57:51 +08:00
ComplainerByLowSuccessPerDay.hpp Boss/Mod/ComplainerByLowSuccessPerDay.cpp: Complain about peers with low success-per-day metric. 2021-04-09 11:01:56 +08:00
ConnectFinderByDns.cpp Remove defunct DNS seed entries (#309) 2026-03-23 14:27:21 -07:00
ConnectFinderByDns.hpp DnsSeed/get.cpp: Do not resolve hostnames, leave that to the lightningd. 2020-09-10 09:24:34 +08:00
ConnectFinderByHardcode.cpp seeds: update the seeds list 2024-07-18 14:47:57 -07:00
ConnectFinderByHardcode.hpp Boss/Mod/ConnectFinderByHardcode.cpp: Module with a list of hardcoded nodes. 2020-09-10 09:08:24 +08:00
Connector.cpp Boss/Mod/Connector.cpp: Add debug logs. 2020-09-10 00:59:31 +08:00
Connector.hpp Boss/Mod/Connector.cpp: Module to connect to other nodes. 2020-09-09 09:52:08 +08:00
ConstructedListpeers.cpp Improve the ConstructedListpeers handling diagnostics 2024-07-16 16:01:56 -07:00
ConstructedListpeers.hpp Improve the ConstructedListpeers handling diagnostics 2024-07-16 16:01:56 -07:00
Dowser.cpp Convert deprecated "msatoshi" fields to "amount_msat" 2024-04-05 12:48:08 -07:00
Dowser.hpp Boss/Mod/Dowser.cpp: Implement clboss-dowser command for testing dowser algo. 2020-11-17 11:11:26 +08:00
EarningsRebalancer.cpp Reduce the default max-rebalance-fee-ppm 2025-08-25 09:30:52 -07:00
EarningsRebalancer.hpp Boss/Mod/EarningsRebalancer.cpp: Rebalancer based on earnings. 2021-01-13 10:15:37 +08:00
EarningsTracker.cpp remove dead code, if by_node is set, node_id must be empty 2026-01-22 11:09:08 -08:00
EarningsTracker.hpp add EarningsTracker::bucket_time quantizer and unit tests 2024-09-25 13:23:04 -05:00
FeeModderByBalance.cpp feemon: add fee monitor to save per-channel stats 2026-02-27 14:28:53 -08:00
FeeModderByBalance.hpp Boss/Mod/FeeModderByBalance.cpp: Passive balancing by fee manipulation. 2020-10-16 21:54:17 +08:00
FeeModderByPriceTheory.cpp feemon: add price theory center price 2026-02-27 14:28:55 -08:00
FeeModderByPriceTheory.hpp Boss/Mod/FeeModderByPriceTheory.cpp: Initial cut at price theory. 2021-04-18 18:43:48 +08:00
FeeModderBySize.cpp feemon: add fee monitor to save per-channel stats 2026-02-27 14:28:53 -08:00
FeeModderBySize.hpp Boss/Mod/FeeModderBySize.cpp: Modify our fees according to our size relative to other nodes. 2020-10-14 17:33:14 +08:00
FeeMonitor.cpp feemon: add clboss-feemon-peers to determine peer set for time window 2026-02-27 14:28:59 -08:00
FeeMonitor.hpp feemon: add price theory center price 2026-02-27 14:28:55 -08:00
ForwardFeeMonitor.cpp Add associated primary volume (forwarded and rebalanced) to EarningsTracker 2024-09-25 13:23:04 -05:00
ForwardFeeMonitor.hpp Add associated primary volume (forwarded and rebalanced) to EarningsTracker 2024-09-25 13:23:04 -05:00
HtlcAcceptor.cpp Handle JSON-RPC msat amounts in either the old or new conventions 2023-08-18 20:29:21 -07:00
HtlcAcceptor.hpp Boss/Mod/HtlcAcceptor.cpp: Module to handle and dispatch HTLC acceptance. 2020-10-03 18:49:27 +08:00
InitialConnect.cpp Boss/Mod/InitialConnect.cpp: Use new ListpeersAnalyzedResult message. 2020-09-13 18:14:26 +08:00
InitialConnect.hpp *: Silence clang warnings. 2020-11-02 19:02:35 +08:00
InitialRebalancer.cpp Improve the ConstructedListpeers handling diagnostics 2024-07-16 16:01:56 -07:00
InitialRebalancer.hpp Boss/Mod/InitialRebalancer.cpp: Module to rebalance channels that are heavily owned by us. 2020-10-26 11:31:33 +08:00
Initiator.cpp fix missing quote 2026-02-19 14:47:31 -08:00
Initiator.hpp Boss/Mod/Initiator.cpp: Module to handle init. 2020-09-08 15:51:31 +08:00
InternetConnectionMonitor.cpp Boss/Mod/InternetConnectionMonitor.cpp: Fix compile on MacOS. 2020-12-30 15:39:34 +00:00
InternetConnectionMonitor.hpp Boss/Mod/InternetConnectionMonitor.cpp: Module to monitor internet connectivity. 2020-09-14 20:34:09 +08:00
InvoicePayer.cpp fix: make the argument to decode "string" instead of "bolt11" 2026-02-17 15:49:04 -08:00
InvoicePayer.hpp Boss/Mod/InvoicePayer.cpp: Module to pay invoices. 2020-09-28 11:28:07 +08:00
JitRebalancer.cpp Reduce the default max-rebalance-fee-ppm 2025-08-25 09:30:52 -07:00
JitRebalancer.hpp Boss/Mod/JitRebalancer.cpp: Implement JIT rebalancing. 2020-10-25 10:17:48 +08:00
JsonOutputter.cpp Boss/Mod/JsonOutputter.cpp: Module to output JSON to the COUT. 2020-09-07 16:43:19 +08:00
JsonOutputter.hpp Boss/Mod/JsonOutputter.cpp: Module to output JSON to the COUT. 2020-09-07 16:43:19 +08:00
ListfundsAnalyzer.cpp Handle JSON-RPC msat amounts in either the old or new conventions 2023-08-18 20:29:21 -07:00
ListfundsAnalyzer.hpp Boss/Mod/ListfundsAnalyzer.cpp: Module to analyze result of listfunds command. 2022-04-21 12:30:29 +08:00
ListfundsAnnouncer.cpp Boss/Mod/ListfundsAnnouncer.cpp: Module to announce funds. 2020-09-15 11:29:39 +08:00
ListfundsAnnouncer.hpp Boss/Mod/ListfundsAnnouncer.cpp: Module to announce funds. 2020-09-15 11:29:39 +08:00
ListpaysHandler.cpp Handle JSON-RPC msat amounts in either the old or new conventions 2023-08-18 20:29:21 -07:00
ListpaysHandler.hpp Boss/Mod/ListpaysHandler.cpp: Module to perform listpays. 2020-09-28 14:48:19 +08:00
ListpeersAnalyzer.cpp Convert ListpeerResult to use ConstructedListpeers 2024-06-02 16:19:56 -07:00
ListpeersAnalyzer.hpp Boss/Msg/ListpeersAnalyzedResult.hpp: New message containing binned listpeers. 2020-09-13 18:05:29 +08:00
ListpeersAnnouncer.cpp Convert ListpeerResult to use ConstructedListpeers 2024-06-02 16:19:56 -07:00
ListpeersAnnouncer.hpp Convert ListpeerResult to use ConstructedListpeers 2024-06-02 16:19:56 -07:00
Manifester.cpp Boss/Mod/Manifester.cpp: Add support for options. 2020-11-22 12:30:23 +00:00
Manifester.hpp Boss/Mod/Manifester.cpp: Add support for options. 2020-11-22 12:30:23 +00:00
MoveFundsCommand.cpp Handle JSON-RPC msat amounts in either the old or new conventions 2023-08-18 20:29:21 -07:00
MoveFundsCommand.hpp Boss/Mod/MoveFundsCommand.cpp: Temporary debugging command to check funds mover. 2020-10-22 11:38:47 +08:00
NeedsConnectSolicitor.cpp Boss/Mod/NeedsConnectSolicitor.cpp: Use standard shuffle algorithm. 2020-09-10 18:56:19 +08:00
NeedsConnectSolicitor.hpp Boss/Mod/NeedsConnectSolicitor.cpp: Module to solicit nodes to connect to. 2020-09-09 15:18:25 +08:00
NeedsOnchainFundsSwapper.cpp Boss/Mod/NeedsOnchainFundsSwapper.cpp: Add missing space in log message. 2020-10-12 14:23:02 +08:00
NeedsOnchainFundsSwapper.hpp Boss/Mod/NeedsOnchainFundsSwapper.cpp: Swap when we need more funds onchain. 2020-09-29 14:51:19 +08:00
NewaddrHandler.cpp Boss/Mod/NewaddrHandler.cpp: Request p2tr addresses (CLN bech32 default removed). 2026-08-06 16:42:23 -07:00
NewaddrHandler.hpp Boss/Mod/NewaddrHandler.cpp: Module to perform newaddr commands. 2020-09-28 16:17:47 +08:00
NodeBalanceSwapper.cpp Improve the ConstructedListpeers handling diagnostics 2024-07-16 16:01:56 -07:00
NodeBalanceSwapper.hpp Boss/Mod/NodeBalanceSwapper.cpp: Module to get incoming capacity. 2020-09-30 09:56:58 +08:00
OnchainFeeMonitor.cpp Add clboss-feerates RPC 2025-07-07 11:21:09 -07:00
OnchainFeeMonitor.hpp Improve Initialization of OnchainFeeMonitor with Conservative Synthetic History 2024-07-16 16:02:32 -07:00
OnchainFundsAnnouncer.cpp coroutine: mitigate GCC PR 107288 coroutine issue 2026-02-27 14:28:53 -08:00
OnchainFundsAnnouncer.hpp Boss/Mod/*: Modify items deprecated in C-Lightning 0.11. 2022-06-01 00:07:38 +00:00
OnchainFundsIgnorer.cpp Boss/Mod/*: Use the new Util::date to provide human-readable dates. 2021-04-26 16:17:10 +08:00
OnchainFundsIgnorer.hpp Boss/Mod/OnchainFundsIgnorer.cpp: Module to provide a flag for ignoring or noticing onchain funds. 2020-11-20 00:11:38 +08:00
PaymentDeleter.cpp Insert exception what() value in logging messages 2024-08-19 15:04:30 -07:00
PaymentDeleter.hpp Boss/Mod/PaymentDeleter.cpp: Generalized deleter of probe and funds-movement payments. 2021-04-28 19:02:31 +08:00
PeerFromScidMapper.cpp Convert ListpeerResult to use ConstructedListpeers 2024-06-02 16:19:56 -07:00
PeerFromScidMapper.hpp Boss/Mod/PeerFromScidMapper.cpp: Module to centralize getting peer node IDs from SCIDs. 2023-07-11 20:57:51 +08:00
PeerMetrician.cpp Boss/Msg/ReqRespTraits.hpp: Use a traits class for requests and response. 2023-07-11 20:57:51 +08:00
PeerMetrician.hpp Boss/Mod/PeerMetrician.cpp: Add metrics generator. 2020-10-06 15:38:13 +08:00
PeerStatistician.cpp *: Silence clang warnings. 2020-11-02 19:02:35 +08:00
PeerStatistician.hpp Boss/Mod/PeerStatistician.cpp: Stores statistics. 2020-10-06 13:26:09 +08:00
README.md new-mod: Utility script to create a new module. 2022-06-07 23:26:08 -04:00
RebalanceUnmanager.cpp Boss/Mod/RebalanceUnmanager.cpp: Module to keep track of nodes that must not be managed for rebalancing. 2022-05-11 12:09:13 +00:00
RebalanceUnmanager.hpp Boss/Mod/RebalanceUnmanager.cpp: Module to keep track of nodes that must not be managed for rebalancing. 2022-05-11 12:09:13 +00:00
Reconnector.cpp Boss/Mod/: Use iterators instead of indexing for Jsmn::Object types. 2020-11-18 16:46:20 +08:00
Reconnector.hpp Boss/Mod/Reconnector.cpp: Add module to reconnect when peers disconnect from us while we have no channels. 2020-09-10 14:31:11 +08:00
RegularActiveProbe.cpp Boss/Mod/RegularActiveProbe.cpp: Trigger for ActiveProber. 2020-10-07 16:08:09 +08:00
RegularActiveProbe.hpp Boss/Mod/RegularActiveProbe.cpp: Trigger for ActiveProber. 2020-10-07 16:08:09 +08:00
Rpc.cpp configure.ac: Enable C++20. 2026-01-21 11:40:01 -08:00
Rpc.hpp Use BacktraceException for appropriate (most) exceptions 2024-08-19 15:04:30 -07:00
RpcWrapper.cpp Boss/Mod/RpcWrapper.cpp: Add new module for wrapping the RPC interface into one for the S::Bus. 2022-05-02 05:15:18 +00:00
RpcWrapper.hpp Boss/Mod/RpcWrapper.cpp: Add new module for wrapping the RPC interface into one for the S::Bus. 2022-05-02 05:15:18 +00:00
SelfUptimeMonitor.cpp Boss/Mod/SelfUptimeMonitor.cpp: Module to track our own uptime. 2021-02-09 15:51:36 +08:00
SelfUptimeMonitor.hpp Boss/Mod/SelfUptimeMonitor.cpp: Module to track our own uptime. 2021-02-09 15:51:36 +08:00
SendpayResultMonitor.cpp Boss/Mod/SendpayResultMonitor.cpp: Fix type for partid. 2020-11-24 18:22:43 +08:00
SendpayResultMonitor.hpp Boss/Mod/SendpayResultMonitor.cpp: Module to monitor our sendpay/sendonion. 2020-10-04 23:22:17 +08:00
StatusCommand.cpp Boss/Mod/StatusCommand.cpp: Properly set usage of clboss-status command. 2020-10-12 18:26:49 +08:00
StatusCommand.hpp *: Use Ln::CommandId for command IDs for received commands and hook events. 2022-11-23 00:36:43 +08:00
SwapManager.cpp swaps: Init SQL query to remove blank addresses from cache. 2025-01-24 14:38:15 -06:00
SwapManager.hpp Boss/Mod/SwapManager.cpp: Offchain-to-onchain swap manager. 2020-09-29 08:17:33 +08:00
SwapReporter.cpp Boss/Mod/SwapReporter.cpp: New module to provide report on swaps. 2021-11-27 12:53:05 +00:00
SwapReporter.hpp Boss/Mod/SwapReporter.cpp: New module to provide report on swaps. 2021-11-27 12:53:05 +00:00
Timers.cpp Boss/Mod/Timers.cpp: Use Boss::random_engine. 2021-01-25 10:54:39 +08:00
Timers.hpp Boss/Mod/Timers.cpp: Module to emit regular timing messages. 2020-09-08 18:40:19 +08:00
TimerTwiceDailyAnnouncer.cpp Boss/Mod/TimerTwiceDailyAnnouncer.cpp: Correct twice-daily updating of time. 2021-03-11 18:42:23 +08:00
TimerTwiceDailyAnnouncer.hpp Boss/Msg/TimerTwiceDaily.hpp: Emitted twice a day. 2021-01-25 10:54:39 +08:00
UnmanagedManager.cpp Use BacktraceException for appropriate (most) exceptions 2024-08-19 15:04:30 -07:00
UnmanagedManager.hpp Boss/Mod/UnmanagedManager.cpp: Module to suppress automatic management. 2021-03-01 17:17:12 +08:00
Waiter.cpp Boss/Mod/InternetConnectionMonitor.cpp: Add some debugging code to find the 'ping success is failing' bug. 2020-09-16 15:31:13 +08:00
Waiter.hpp Boss/Mod/Waiter.cpp: Add capability to apply timeouts to operations. 2020-09-14 19:39:51 +08:00

Boss Modules

This directory contains modules of CLBOSS.

CLBOSS (Boss::Main) is constructed as a bunch of modules centered around a common bus, the S::Bus.

Each module is given access to the S::Bus, and can subscribe to any messages on the bus. It can also raise any messages on the bus.

A module is just a generic object. The only requirement is that it be constructible and destructible.

Ideally, modules should not have references or pointers to other modules; instead, it interacts with other modules by raise-ing messages, and responding to subscribed messages. There are a few modules which violate this rule, mostly ones from the early days of CLBOSS when I was much less confident of this design, but those few --- mostly Boss::Mod::Rpc and Boss::Mod::Waiter --- should eventually be migrated to using S::Bus fully.

To create a new module, use the new-mod script in the top level:

./new-mod NewModule

Module Header

Below is a sketch of what a new module would have in its header:

#ifndef BOSS_MOD_NEWMODULE_HPP
#define BOSS_MOD_NEWMODULE_HPP

#include<memory>

namespace S { class Bus; }

namespace Boss { namespace Mod {

/** class Boss::Mod::NewModule
 *
 * @brief this is a simple example of a new module.
 */
class NewModule {
private:
	class Impl;
	std::unique_ptr<Impl> pimpl;

public:
	/* We need to be constructed explicitly with a
	 * S::Bus!  */
	NewModule() =delete;

	/* These will be defined in the source file using
	 * `default`.
	 */
	NewModule(NewModule&&);
	~NewModule();

	/* The constructor.  */
	explicit
	NewModule(S::Bus&);
};

}}

#endif /* !defined(BOSS_MOD_NEWMODULE_HPP) */

Yes, it is really that simple. There is no need to define anything in the header other than the fact that the module exists and can be moved and destructed and can be constructed with a S::Bus.

The meat of the module will be defined in the source file, in the Boss::Mod::NewModule::Impl implementation class.

(The few modules which do not use this pattern were from earlier days before I realized this pattern worked best.)

Module Source

A minimal new module has this code in the corresponding source file:

#include"Boss/Mod/NewModule.hpp"
#include"Ev/Io.hpp"
#include"S/Bus.hpp"
#include"Util/make_unique.hpp"

namespace Boss { namespace Mod {

/* This contains all the data and code that the new module
 * actually needs.
 */
class NewModule::Impl {
private:
	S::Bus& bus;

	int your_data_here;

	void start() {
		your_data_here = default_your_data_value;
		bus.subacribe<Boss::Msg::Whateverness
			     >([this](Boss::Msg::Whateverness const& msg) {
			return do_whatever(msg);
		});
		// ...
	}

	Ev::Io<void> do_whatever(Boss::Msg::Whateverness const& msg) {
		// ...
		return Ev::lift();
	}

public:
	/* The below are not really necessary (this source file is
	 * the only one that will see the `Impl` class anyway) but I
	 * feel they are necessary.  */
	Impl() =delete;
	Impl(Impl&&) =delete;

	explicit
	Impl(S::Bus& bus_) : bus(bus_) { start(); }
};

/* The C++-generated defaults should work fine.  We just need to
 * let the compiler know about the `Impl` class first before the
 * compiler can generate the `default`, which is why the `Impl`
 * class definition above comes first.
 */
NewModule::NewModule(NewModule&&) =default;
NewModule::~NewModule() =default;

/* Just construct the implementation.  */
NewModule::NewModule(S::Bus& bus)
	: pimpl(Util::make_unique<Impl>(bus)) { }

}}

So, as mentioned, the Impl class contains all that your module is. It declares the data and the code of your module.

From within your module, you can subscribe to and raise messages. Those are the ways by which your module can affect the rest of the modules.

Module Registration

Module code is nice, but they do need to be instantiated in the initial object graph before the module can start interacting with the rest of CLBOSS.

In order to do that, you need to add it to Boss/Mod/all.cpp.

Just #include the header file, then add an install decleration:

all->install<NewModule>(bus);

The order in which modules are installed into the instantiated CLBOSS should not matter. However, some old modules may be sensitive to order (due to being designed with dependencies, but "modern" CLBOSS should have modules depend only on a common interface, the bus, i.e. Dependency Inversion), so avoid reordering existing modules (but feel free to insert new modules wherever, do note that the modules are roughly grouped so try to locate the most logical group for the module and add it there).

Shutting Down

When the lightningd shuts down, it closes the stdin of clboss.

This causes Boss::JsonInput::run (the main loop) to return, which then causes the special message Boss::Shutdown to be emitted on the bus.

Some blocking interfaces are connected to objects that also monitor this message on the S::Bus. Below is not an exhaustive list but probably has all the important ones you would use.

  • Boss::Mod::Rpc::command
  • Boss::Mod::Waiter::wait
  • Boss::ModG::ReqResp<MsgType>::execute

When the Boss::Shutdown message is broadcasted on the bus, the above interfaces will throw an Ev::Io-level exception, of the Boss::Shutdown type (yes, the same as the message --- it is just some type, and that is all C++ cares about).

The proper thing to do is to simply not handle Boss::Shutdown. This causes the Ev::Io-level greenthread your module code is running in, to terminate with an uncaught exception, which allows CLBOSS to exit cleanly once all greenthreads have terminated.

There exists a Boss::concurrent function that you should use for launching Ev::Io-level greenthreads. This simply catches any uncaught Boss::Shutdown in the spawned greenthread and exits the greenthread when this is caught. Otherwise, the user will get a uncaught exception scare-message on stderr, which is benign (since the exception only exists to unblock blocking interfaces).

S::Bus::raise, Ev::map, Ev::foreach, which do not use Boss::concurrent to launch new Ev::Io-level greenthreads, are fine since any Ev::Io-level exception --- including a thrown Boss::Shutdown from the above blocking interfaces --- from any sub-greenthread they launch will propagate it to the calling thread as well, which should eventually reach out to the Boss::concurrent that launched whatever greenthread your module started in.

Thus, for the most part, shutting down "just works" and you can ignore it, usually.

However, if you have code that has to wait for something (and that something is not one of the above blocking interfaces), then take note that you should have a long-lived object that monitors for Boss::Shutdown and forces your code to stop waiting and throws Boss::Shutdown to the caller. For example, it could set a flag somewhere in your object, and your waiting code should also ccheck this flag (meaning your waiting code has to poll this flag as well, and throw Boss::Shutdown if the flag is set).

Lifetime Management

Managing the lifetimes of objects is fairly important in C++.

Modules registered in the Boss::Mod::all function are persistent; they will be alive until after Boss::Shutdown is broadcast on the bus and the above blocking interfaces have thrown the exception at the Ev::Io level.

Of course, if you use objects in your own code, you do need to be responsible for managing their lifetimes, usually by use of standard std::unique_ptr and std::shared_ptr.

Typically it means you need to have a container in your module that contains std::unique_ptrs to objects that have less than persistent lifetime. Then when you know that the object lifetime is over, you can remove the object from the container.

Sometimes, you might want to launch a background Ev::Io greenthread with its own object, and have the object automatically be reaped when the greenthread exits. For that case, you can take advantage of C++ lambda captures:

Ev::Io<void> do_something_in_foreground() {
	auto temp_object = std::make_shared<TempObject>();
	return Ev::lift().then([temp_object]() {
		return temp_object->do_something();
	}).then([temp_object]() {
		/* This function only exists to keep the
		 * `temp_object` alive until the above
		 * function completes.
		 */
		return Ev::lift();
	});
}
Ev::Io<void> do_something() {
	return Boss::concurrent(do_something_in_foreground());
}

The above do_something function will then launch the task in some background greenthread. The TempObject remains alive until its do_something member function returns. The nice thing is that even if the TempObject::do_something throws an uncaught exception (like the aforementioned Boss::Shutdown), the temp_object will also be destructed correctly.

When using the above pattern, be careful with all uses of Boss::concurrent from within the temporary objects. If the Boss::concurrent outlasts the temporary object, then it might refer to objects that the temporary object is keeping alive, and which might be dead at that point. See commit f01a730e for an example of this bug.

An important thing to note is that only persistent objects can subscribe to the S::Bus. Temporary objects cannot subscribe to any messages. If a temporary object like the above TempObject needs to listen for messages, your module (being persistent) should listen on behalf of those objects, then either forward it to any TempObject, or allow TempObject to somehow access the contents of messages.

If you have a temporary object subscribe on the bus, then when the object dies and is destructed, the bus will still forward any raised messages to its function, which would, with high probability, attempt to access its previous memory area and lead to use-after-free bugs.

This is a limitation of the current S::Bus; in principle it should be possible to add a sort of "leased subscribe" which would return an object that your temporary object will keep alive, whose destruction would unsubscribe the corresponding function.

Boss::ModG::ReqResp

Often, a module keeps track of some information about the universe, or may serve as wrappers around some functionality that can be replaced (most likely for mocking, so that we can write module-level tests by instantiating just the module under test and adding code to subscribe and raise messages on the test harness. See the tests in tests/boss).

Obviously, other modules then need to somehow "call" into the module, to query the data or to trigger the functionality.

In a typical object graph this is done by having the caller object somehow get access to the interface of the callee object.

However, with the S::Bus, the caller can instead just be given the very generic S::Bus interface to trigger code on the callee object, and get a response.

To facilitate this, the Boss::ModG::ReqResp templated class exists. Simply instantiate this in your module --- it has to be a persistent object with the same lifetime as your module, since it subscribes to messages --- and call its execute member function. This function will send the Req message (the first argument of the template) and will wait for the corresponding Resp message, and will block the calling greenthread until the corresponding response is received. It will also handle Boss::Shutdown correctly --- any blocked greenthread will experience Boss::Shutdown being thrown to unblock the greenthread.

Now, Boss::ModG::ReqResp is not magic. Any Req message and its corresponding Resp has to have a void* requester member. The callee object that handles this Req and raises the Resp has to propagate the void* requester from the Req to the Resp that contains the response to the given Req.

For example:

/* Request message.  */
struct RequestAddOne {
	void* requester;
	int x;
};
/* Response message.  */
struct ResponseAddOne {
	void* requester;
	int x_plus_1;
};
/* Callee module implementation.  */
class AddOneHandler::Impl {
private:
	S::Bus& bus;

	void start() {
		bus.subscribe< RequestAddOne
			     >([this](RequestAddOne const& m) {
			auto x_plus_1 = m.x + 1;
			return bus.raise(ResponseAddOne{
				/* Propagate the requester.  */
				m.requester,
				x_plus_1
			});
		});
	}
public:
	Impl() =delete;
	Impl(S::Bus& bus_) : bus(bus_) { start(); }
};

/* Caller module implementation.  */
class AddOneCaller::Impl {
private:
	S::Bus& bus;

	Boss::ModG::ReqResp< RequestAddOne
			   , ResponseAddOne
			   > add_one;

	void start() {
		bus.subscribe< Boss::Msg::Init
			     >([this](Boss::Msg::Init const& _) {
			return Ev::lift().then([this]() {
				/* Call into the AddOneHandler.  */
				return add_one.execute(RequestAddOne{
					/* ReqResp will fill in the
					 * requester field appropriately.  */
					nullptr,
					/* x.  */
					42
				});
			}).then([](ResponseAddOne rsp) {
				assert(resp.x_plus_1 == 43);
				return Ev::lift();
			});
		});
	}

public:
	Impl() =delete;
	Impl( S::Bus& bus_
	    ) : bus(bus_)
	      , add_one( bus_
		       , [](RequestAddOne& m, void* p) {
				m.requester = p;
			 }
		       , [](ResponseAddOne& m) {
				return m.requester;
			 }
		       )
	      { start(); }
};

In principle, the functions passed into the constructor of Boss::ModG::ReqResp should really be in a traits class, this should be modified at some point in the future.

A major advantage of this system is that it provides some amount of cross-module introspection. Any module can "tap into" the Req and/or Resp of another module, and keep track of various statistics about how often those bits of functionality get called. For example, a module could be written that just subscribes to RequestMoveFunds and ResponseMoveFunds, which then keeps statistics on how often and how much fund movements can actually succeed. Then that module can expose this information.

Indeed, the other blocking interfaces, Boss::Mod::Rpc and Boss::Mod::Waiter, do not use the Boss::ModG::ReqResp framework only because they predate it. At some point, those interfaces should be migrated to using Boss::ModG::ReqResp for a single implementation of handling the Boss::Shutdown message.

On-disk Data

If your module keeps statistics or other information on various events, you probably want to persist that data across restarts of lightningd.

This is done by using an SQLITE3 database. See the Sqlite3/ directory for the internal API.

CLBOSS uses a single database, named data.clboss. An Sqlite3::Db is broadcasted at initialization via the Boss::Msg::DbResource message, which represents an opened handle to this database. Your module should subscribe to this message, and copy the handle to its own variable.

Your module should then create a table in this database to hold all the data that needs to persist. Table names you create should be prefixed with the module name, for example NewModule_nodes, to ensure that tables of other modules do not conflict.

You should probably use CREATE TABLE IF NOT EXISTS in order to create tables if and only if they do not exist yet. Note that you cannot easily change the table schema --- if your module has been released before, then users already have the previous table schema and you cannot easily modify it. Adding columns is possible with SQLITE3 via ALTER TABLE, but changing columns or deleting them is not possible, so make sure to think deeply about the table design before writing code for it.