#include"Boss/Mod/ChannelFeeManager.hpp" #include"Boss/Msg/ManifestOption.hpp" #include"Boss/Msg/Manifestation.hpp" #include"Boss/Msg/Option.hpp" #include"Boss/Msg/PeerMedianChannelFee.hpp" #include"Boss/Msg/ProvideChannelFeeModifier.hpp" #include"Boss/Msg/ProvideStatus.hpp" #include"Boss/Msg/SetChannelFee.hpp" #include"Boss/Msg/SolicitChannelFeeModifier.hpp" #include"Boss/Msg/SolicitStatus.hpp" #include"Boss/concurrent.hpp" #include"Boss/log.hpp" #include"Ev/Io.hpp" #include"Ev/map.hpp" #include"Ev/yield.hpp" #include"Ln/NodeId.hpp" #include"S/Bus.hpp" #include #include namespace Boss { namespace Mod { void ChannelFeeManager::start() { bus.subscribe([this](Msg::Manifestation const& _) { return bus.raise(Msg::ManifestOption{ "clboss-zerobasefee", Msg::OptionType_String, Json::Out::direct(std::string("allow")), "Whether to require, allow, or disallow a " "0 base fee." }); }); bus.subscribe([this](Msg::Option const& o) { if (o.name != "clboss-zerobasefee") return Ev::lift(); auto svalue = std::string(o.value); if (svalue == "require" || svalue == "required") zero_base_fee = ZeroBaseFee_Require; else if (svalue == "disallow" || svalue == "disallowed") zero_base_fee = ZeroBaseFee_Disallow; else zero_base_fee = ZeroBaseFee_Allow; auto comment = (zero_base_fee == ZeroBaseFee_Require) ? "require" : (zero_base_fee == ZeroBaseFee_Allow) ? "allow" : (zero_base_fee == ZeroBaseFee_Disallow) ? "disallow" : /*otherwise*/ "?" ; return Boss::log( bus, Boss::Info , "ChannelFeeManager: zerobasefee: %s" , comment ); }); bus.subscribe([this](Msg::PeerMedianChannelFee const& m) { return Boss::concurrent( perform(m.node, m.base, m.proportional) ); }); bus.subscribe([this](Msg::ProvideChannelFeeModifier const& m) { if (soliciting) modifiers.push_back(m.modifier); return Ev::lift(); }); bus.subscribe([this](Msg::SolicitStatus const& _) { auto stat = Json::Out(); auto obj = stat.start_object(); for (auto const& node_inf : infos) { auto const& node = node_inf.first; auto const& inf = node_inf.second; obj .start_object(std::string(node)) .field( "median_base" , inf.median_base ) .field( "median_proportional" , inf.median_proportional ) .field( "multiplier" , inf.multiplier ) .field( "final_base" , inf.final_base ) .field( "final_proportional" , inf.final_proportional ) .end_object(); } obj.end_object(); return bus.raise(Msg::ProvideStatus{ "lnfee", std::move(stat) }); }); } Ev::Io ChannelFeeManager::solicit() { /* Busy wait. */ if (soliciting && !initted) return Ev::yield().then([this]() { return solicit(); }); if (initted) return Ev::lift(); soliciting = true; return bus.raise( Msg::SolicitChannelFeeModifier{} ).then([this]() { soliciting = false; initted = true; return Ev::lift(); }); } Ev::Io ChannelFeeManager::perform( Ln::NodeId node , std::uint32_t base , std::uint32_t proportional ) { /* This message will be mutated later. */ auto msg = std::make_shared(); msg->node = node; msg->base = base; msg->proportional = proportional; return Ev::lift().then([this]() { return solicit(); }).then([this, msg]() { /* Run the modifiers */ auto f = [msg](std::function( Ln::NodeId , std::uint32_t , std::uint32_t ) > modifier) { return modifier( msg->node , msg->base , msg->proportional ); }; return Ev::map(std::move(f), modifiers); }).then([this, msg](std::vector multipliers) { /* Get our info structure. */ auto& inf = infos[msg->node]; inf.median_base = msg->base; inf.median_proportional = msg->proportional; /* Get double versions of the base and proportional fees. */ auto b = double(msg->base); auto p = double(msg->proportional); auto ms = double(1.0); /* Multiply by all, using the `double` versions. */ for (auto m : multipliers) { b *= m; p *= m; ms *= m; } inf.multiplier = ms; /* Round and convert back to uint32_t. */ msg->base = std::uint32_t(round(b)); msg->proportional = std::uint32_t(round(p)); /* Handle zerobasefee. */ if (zero_base_fee == ZeroBaseFee_Disallow && msg->base == 0) msg->base = 1; if (zero_base_fee == ZeroBaseFee_Require) msg->base = 0; /* If 0, set to 1. */ if (msg->proportional == 0) msg->proportional = 1; /* Get our final base and proportional fees. */ inf.final_base = msg->base; inf.final_proportional = msg->proportional; /* Send the message! */ return bus.raise(std::move(*msg)); }); } }}