2020-10-26 11:31:33 +08:00
|
|
|
#include"Boss/Mod/InitialRebalancer.hpp"
|
2022-05-09 16:35:34 +08:00
|
|
|
#include"Boss/ModG/RebalanceUnmanagerProxy.hpp"
|
2020-10-26 11:31:33 +08:00
|
|
|
#include"Boss/ModG/ReqResp.hpp"
|
|
|
|
|
#include"Boss/Msg/ListpeersResult.hpp"
|
2021-01-11 14:42:15 +08:00
|
|
|
#include"Boss/Msg/RequestEarningsInfo.hpp"
|
2020-10-26 11:31:33 +08:00
|
|
|
#include"Boss/Msg/RequestMoveFunds.hpp"
|
2021-01-11 14:42:15 +08:00
|
|
|
#include"Boss/Msg/ResponseEarningsInfo.hpp"
|
2020-10-26 11:31:33 +08:00
|
|
|
#include"Boss/Msg/ResponseMoveFunds.hpp"
|
|
|
|
|
#include"Boss/concurrent.hpp"
|
|
|
|
|
#include"Boss/log.hpp"
|
|
|
|
|
#include"Boss/random_engine.hpp"
|
|
|
|
|
#include"Ev/Io.hpp"
|
2021-01-11 14:42:15 +08:00
|
|
|
#include"Ev/map.hpp"
|
2020-10-26 11:31:33 +08:00
|
|
|
#include"Ev/yield.hpp"
|
|
|
|
|
#include"Jsmn/Object.hpp"
|
|
|
|
|
#include"Json/Out.hpp"
|
|
|
|
|
#include"Ln/Amount.hpp"
|
|
|
|
|
#include"Ln/NodeId.hpp"
|
|
|
|
|
#include"S/Bus.hpp"
|
|
|
|
|
#include"Stats/ReservoirSampler.hpp"
|
|
|
|
|
#include"Util/make_unique.hpp"
|
|
|
|
|
#include"Util/stringify.hpp"
|
2021-02-11 15:01:00 +08:00
|
|
|
#include<assert.h>
|
2020-10-26 11:31:33 +08:00
|
|
|
#include<map>
|
2021-02-11 15:01:00 +08:00
|
|
|
#include<set>
|
2020-11-16 23:43:14 +08:00
|
|
|
#include<sstream>
|
2020-10-26 11:31:33 +08:00
|
|
|
#include<vector>
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
/* If the spendable amount exceeds this percent of the channel total,
|
|
|
|
|
* this code triggers.
|
|
|
|
|
*/
|
|
|
|
|
auto constexpr spendable_percent = double(80.0);
|
2020-11-22 01:55:51 +08:00
|
|
|
/* Gap to prevent destinations from hitting the spendable_percent. */
|
|
|
|
|
auto constexpr dest_gap_percent = double(5.0);
|
2020-10-26 11:31:33 +08:00
|
|
|
/* Limit on rebalance fee. */
|
2021-02-15 11:01:50 +08:00
|
|
|
auto const min_rebalance_fee = Ln::Amount::sat(3);
|
|
|
|
|
auto constexpr rebalance_fee_percent = double(0.25);
|
2020-10-26 11:31:33 +08:00
|
|
|
|
2021-01-11 14:42:15 +08:00
|
|
|
/* Limit on total amount this module will expend on all rebalances,
|
|
|
|
|
* as a percent of the channel capacity. */
|
2021-02-15 11:01:50 +08:00
|
|
|
auto constexpr max_in_expenditures_percent = double(0.04); // 10mBTC * 0.0004 = 400 sats
|
2021-01-11 14:42:15 +08:00
|
|
|
|
2020-10-26 11:31:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace Boss { namespace Mod {
|
|
|
|
|
|
|
|
|
|
class InitialRebalancer::Impl {
|
|
|
|
|
private:
|
|
|
|
|
S::Bus& bus;
|
2020-10-28 08:35:08 +08:00
|
|
|
/* Interface to funds mover. */
|
|
|
|
|
typedef
|
|
|
|
|
ModG::ReqResp< Msg::RequestMoveFunds
|
|
|
|
|
, Msg::ResponseMoveFunds
|
|
|
|
|
> MoveRR;
|
|
|
|
|
MoveRR move_rr;
|
2021-01-11 14:42:15 +08:00
|
|
|
/* Interface to expenditures tracker. */
|
|
|
|
|
typedef
|
|
|
|
|
ModG::ReqResp< Msg::RequestEarningsInfo
|
|
|
|
|
, Msg::ResponseEarningsInfo
|
|
|
|
|
> ExpenseRR;
|
|
|
|
|
ExpenseRR expense_rr;
|
2022-05-09 16:35:34 +08:00
|
|
|
/* Interface to the rebalance unmanager. */
|
|
|
|
|
ModG::RebalanceUnmanagerProxy unmanager;
|
2020-10-26 11:31:33 +08:00
|
|
|
|
2021-02-11 15:01:00 +08:00
|
|
|
/* Peers currently being rebalanced. */
|
|
|
|
|
std::set<Ln::NodeId> current_sources;
|
|
|
|
|
|
2020-10-26 11:31:33 +08:00
|
|
|
void start() {
|
|
|
|
|
bus.subscribe<Msg::ListpeersResult
|
|
|
|
|
>([this](Msg::ListpeersResult const& m) {
|
2020-11-16 23:43:14 +08:00
|
|
|
/* If this is the initial startup, then we might not
|
|
|
|
|
* be connected to the peers involved yet, so better
|
|
|
|
|
* to wait and let it "simmer" a bit.
|
|
|
|
|
*/
|
|
|
|
|
if (m.initial)
|
|
|
|
|
return Ev::lift();
|
2024-04-29 01:45:47 -05:00
|
|
|
return run(m.cpeers);
|
2020-10-26 11:31:33 +08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Run {
|
|
|
|
|
private:
|
|
|
|
|
class Impl;
|
|
|
|
|
std::shared_ptr<Impl> pimpl;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
Run() =delete;
|
|
|
|
|
|
|
|
|
|
Run(Run&&) =default;
|
|
|
|
|
~Run() =default;
|
|
|
|
|
|
|
|
|
|
explicit
|
2024-04-29 01:45:47 -05:00
|
|
|
Run( S::Bus& bus, Boss::Mod::ConstructedListpeers const& peers
|
2021-01-11 14:42:15 +08:00
|
|
|
, MoveRR& move_rr, ExpenseRR& expense_rr
|
2021-02-11 15:01:00 +08:00
|
|
|
, std::set<Ln::NodeId>& current_sources
|
2022-05-09 16:35:34 +08:00
|
|
|
, std::set<Ln::NodeId> const& unmanaged
|
2021-01-11 14:42:15 +08:00
|
|
|
);
|
2020-10-26 11:31:33 +08:00
|
|
|
Ev::Io<void> run();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ev::Io<void>
|
2024-04-29 01:45:47 -05:00
|
|
|
run(Boss::Mod::ConstructedListpeers const& peers) {
|
|
|
|
|
auto ppeers = std::make_shared<Boss::Mod::ConstructedListpeers>(peers);
|
2022-05-09 16:35:34 +08:00
|
|
|
return Ev::lift().then([this]() {
|
|
|
|
|
return unmanager.get_unmanaged();
|
|
|
|
|
}).then([ this
|
|
|
|
|
, ppeers
|
|
|
|
|
](std::set<Ln::NodeId> const* unmanagedp) {
|
|
|
|
|
return Boss::concurrent( Run( bus
|
|
|
|
|
, *ppeers
|
|
|
|
|
, move_rr
|
|
|
|
|
, expense_rr
|
|
|
|
|
, current_sources
|
|
|
|
|
, *unmanagedp
|
|
|
|
|
).run()
|
|
|
|
|
);
|
|
|
|
|
});
|
2020-10-26 11:31:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
Impl() =delete;
|
|
|
|
|
Impl(Impl&&) =delete;
|
|
|
|
|
Impl(Impl const&) =delete;
|
|
|
|
|
|
|
|
|
|
explicit
|
2020-10-28 08:35:08 +08:00
|
|
|
Impl( S::Bus& bus_
|
|
|
|
|
) : bus(bus_)
|
2022-05-31 16:53:28 -07:00
|
|
|
, move_rr(bus_)
|
|
|
|
|
, expense_rr(bus_)
|
2022-05-09 16:35:34 +08:00
|
|
|
, unmanager(bus_)
|
2020-10-28 08:35:08 +08:00
|
|
|
{ start(); }
|
2020-10-26 11:31:33 +08:00
|
|
|
};
|
|
|
|
|
|
2021-04-08 17:56:31 +08:00
|
|
|
class InitialRebalancer::Impl::Run::Impl
|
|
|
|
|
: public std::enable_shared_from_this<Impl> {
|
2020-10-26 11:31:33 +08:00
|
|
|
private:
|
|
|
|
|
S::Bus& bus;
|
2024-04-29 01:45:47 -05:00
|
|
|
Boss::Mod::ConstructedListpeers peers;
|
2020-10-26 11:31:33 +08:00
|
|
|
|
|
|
|
|
/* Data about a peer. */
|
|
|
|
|
struct Info {
|
|
|
|
|
Ln::Amount spendable;
|
|
|
|
|
Ln::Amount receivable;
|
|
|
|
|
Ln::Amount total;
|
|
|
|
|
};
|
|
|
|
|
std::map<Ln::NodeId, Info> info;
|
2021-01-11 14:42:15 +08:00
|
|
|
/* Sources and destinations. */
|
|
|
|
|
std::vector<std::pair<Ln::NodeId, Ln::Amount>> sources_total;
|
|
|
|
|
std::vector<Ln::NodeId> sources;
|
|
|
|
|
std::map<Ln::NodeId, Info> destinations;
|
2020-10-26 11:31:33 +08:00
|
|
|
/* Plan to move. */
|
|
|
|
|
std::vector<std::pair<Ln::NodeId, Ln::NodeId>> plan;
|
|
|
|
|
|
|
|
|
|
/* Interface to funds mover. */
|
|
|
|
|
ModG::ReqResp< Msg::RequestMoveFunds
|
|
|
|
|
, Msg::ResponseMoveFunds
|
2020-10-28 08:35:08 +08:00
|
|
|
>& move_rr;
|
2021-01-11 14:42:15 +08:00
|
|
|
/* Interface to expenditures tracker. */
|
|
|
|
|
ModG::ReqResp< Msg::RequestEarningsInfo
|
|
|
|
|
, Msg::ResponseEarningsInfo
|
|
|
|
|
>& expense_rr;
|
2021-02-11 15:01:00 +08:00
|
|
|
std::set<Ln::NodeId>& current_sources;
|
2020-10-26 11:31:33 +08:00
|
|
|
|
2022-05-09 16:35:34 +08:00
|
|
|
/* Set of unmanaged nodes. */
|
|
|
|
|
std::set<Ln::NodeId> const& unmanaged;
|
|
|
|
|
|
2020-10-26 11:31:33 +08:00
|
|
|
Ev::Io<void> core_run() {
|
|
|
|
|
return Ev::lift().then([this]() {
|
|
|
|
|
try {
|
2020-11-16 23:43:14 +08:00
|
|
|
for (auto p : peers) {
|
2020-10-26 11:31:33 +08:00
|
|
|
auto spendable = Ln::Amount::sat(0);
|
|
|
|
|
auto receivable = Ln::Amount::sat(0);
|
|
|
|
|
auto total = Ln::Amount::sat(0);
|
|
|
|
|
|
2024-04-29 01:45:47 -05:00
|
|
|
auto id = p.first;
|
2022-05-09 16:35:34 +08:00
|
|
|
if (unmanaged.count(id) != 0)
|
|
|
|
|
continue;
|
2020-10-26 11:31:33 +08:00
|
|
|
|
2024-04-29 01:45:47 -05:00
|
|
|
auto cs = p.second.channels;
|
2020-11-16 23:43:14 +08:00
|
|
|
for (auto c : cs) {
|
2020-10-26 11:31:33 +08:00
|
|
|
auto state = std::string(
|
|
|
|
|
c["state"]
|
|
|
|
|
);
|
|
|
|
|
if (state != "CHANNELD_NORMAL")
|
|
|
|
|
continue;
|
2020-11-16 23:43:14 +08:00
|
|
|
compute_spendable( spendable
|
|
|
|
|
, receivable
|
|
|
|
|
, total
|
|
|
|
|
, c
|
|
|
|
|
);
|
2020-10-26 11:31:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (total == Ln::Amount::sat(0))
|
|
|
|
|
continue;
|
|
|
|
|
info[id].spendable = spendable;
|
|
|
|
|
info[id].receivable = receivable;
|
|
|
|
|
info[id].total = total;
|
|
|
|
|
}
|
2024-06-15 10:50:37 -07:00
|
|
|
} catch (std::exception const& e) {
|
2020-10-26 11:31:33 +08:00
|
|
|
return Boss::log( bus, Error
|
2024-06-15 10:50:37 -07:00
|
|
|
, "InitialRebalancer:"
|
|
|
|
|
" Unexpected exception: %s "
|
|
|
|
|
" handling: %s"
|
|
|
|
|
, e.what()
|
|
|
|
|
, Util::stringify(peers).c_str()
|
2020-10-26 11:31:33 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return plan_move();
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-11-16 23:43:14 +08:00
|
|
|
void compute_spendable( Ln::Amount& a_spendable
|
|
|
|
|
, Ln::Amount& a_receivable
|
|
|
|
|
, Ln::Amount& a_total
|
|
|
|
|
, Jsmn::Object const& c
|
|
|
|
|
) {
|
|
|
|
|
if ( !c.has("to_us_msat")
|
|
|
|
|
|| !c.has("total_msat")
|
|
|
|
|
|| !c.has("htlcs")
|
|
|
|
|
)
|
|
|
|
|
return;
|
|
|
|
|
/* FIXME: Handle reserves. */
|
2023-05-02 20:20:50 -07:00
|
|
|
auto to_us = Ln::Amount::object(c["to_us_msat"]);
|
|
|
|
|
auto total = Ln::Amount::object(c["total_msat"]);
|
2020-11-16 23:43:14 +08:00
|
|
|
auto to_them = total - to_us;
|
|
|
|
|
for (auto h : c["htlcs"])
|
2023-05-02 20:20:50 -07:00
|
|
|
to_them -= Ln::Amount::object(
|
2020-11-16 23:43:14 +08:00
|
|
|
h["amount_msat"]
|
2023-05-02 20:20:50 -07:00
|
|
|
);
|
2020-11-16 23:43:14 +08:00
|
|
|
a_spendable += to_us;
|
|
|
|
|
a_receivable += to_them;
|
|
|
|
|
a_total += total;
|
|
|
|
|
}
|
2020-10-26 11:31:33 +08:00
|
|
|
Ev::Io<void> plan_move() {
|
2020-11-16 23:43:14 +08:00
|
|
|
auto msg = std::ostringstream();
|
|
|
|
|
auto first = true;
|
2020-10-26 11:31:33 +08:00
|
|
|
/* Gather sources and destinations. */
|
2021-01-11 14:42:15 +08:00
|
|
|
sources_total.clear();
|
|
|
|
|
destinations.clear();
|
2020-10-26 11:31:33 +08:00
|
|
|
for ( auto it = info.begin(), next = info.begin()
|
|
|
|
|
; it != info.end()
|
|
|
|
|
; it = next
|
|
|
|
|
) {
|
|
|
|
|
next = it;
|
|
|
|
|
++next;
|
|
|
|
|
|
2020-11-16 23:43:14 +08:00
|
|
|
if (first)
|
|
|
|
|
first = false;
|
|
|
|
|
else
|
|
|
|
|
msg << ", ";
|
|
|
|
|
|
2020-10-26 11:31:33 +08:00
|
|
|
auto& info = it->second;
|
2020-11-16 23:43:14 +08:00
|
|
|
auto peer_spendable_percent = ( info.spendable
|
|
|
|
|
/ info.total
|
|
|
|
|
)
|
|
|
|
|
* 100.0
|
|
|
|
|
;
|
|
|
|
|
msg << it->first << ": "
|
|
|
|
|
<< peer_spendable_percent << "% "
|
|
|
|
|
;
|
|
|
|
|
if (peer_spendable_percent >= spendable_percent) {
|
2021-01-11 14:42:15 +08:00
|
|
|
sources_total.push_back(std::make_pair( it->first
|
|
|
|
|
, info.total
|
|
|
|
|
));
|
2020-11-16 23:43:14 +08:00
|
|
|
msg << "(source)";
|
2020-11-22 01:55:51 +08:00
|
|
|
} else if ( peer_spendable_percent
|
|
|
|
|
>= (spendable_percent - dest_gap_percent)
|
|
|
|
|
) {
|
|
|
|
|
msg << "(neutral)";
|
2020-11-16 23:43:14 +08:00
|
|
|
} else {
|
2020-10-26 11:31:33 +08:00
|
|
|
destinations.insert(*it);
|
2020-11-16 23:43:14 +08:00
|
|
|
msg << "(destination)";
|
|
|
|
|
}
|
2020-10-26 11:31:33 +08:00
|
|
|
}
|
2020-11-16 23:43:14 +08:00
|
|
|
auto act = Ev::lift();
|
|
|
|
|
if (!first)
|
|
|
|
|
act += Boss::log( bus, Debug
|
|
|
|
|
, "InitialRebalancer: %s"
|
|
|
|
|
, msg.str().c_str()
|
|
|
|
|
);
|
2020-10-26 11:31:33 +08:00
|
|
|
|
|
|
|
|
/* Nothing to do. */
|
2021-02-10 08:37:47 +08:00
|
|
|
if (sources_total.empty())
|
2020-11-16 23:43:14 +08:00
|
|
|
return act;
|
2020-10-26 11:31:33 +08:00
|
|
|
|
2021-01-11 14:42:15 +08:00
|
|
|
return std::move(act) + filter_sources();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reject sources that have already spent too much on rebalances. */
|
|
|
|
|
Ev::Io<void> filter_sources() {
|
|
|
|
|
/* Data about a potential source. */
|
|
|
|
|
struct SourceInfo {
|
|
|
|
|
Ln::NodeId source;
|
|
|
|
|
Ln::Amount total;
|
|
|
|
|
Ln::Amount in_expenditures;
|
|
|
|
|
};
|
|
|
|
|
auto get_source_info = [this](std::pair< Ln::NodeId
|
|
|
|
|
, Ln::Amount
|
|
|
|
|
> source_total) {
|
|
|
|
|
return expense_rr.execute(Msg::RequestEarningsInfo{
|
|
|
|
|
nullptr, source_total.first
|
|
|
|
|
}).then([source_total](Msg::ResponseEarningsInfo rsp) {
|
|
|
|
|
auto source = source_total.first;
|
|
|
|
|
auto total = source_total.second;
|
|
|
|
|
return Ev::lift(SourceInfo{
|
|
|
|
|
source, total, rsp.in_expenditures
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
return Ev::map( get_source_info
|
|
|
|
|
, std::move(sources_total)
|
|
|
|
|
).then([this](std::vector<SourceInfo> source_infos) {
|
|
|
|
|
auto act = Ev::lift();
|
|
|
|
|
auto new_sources = std::vector<Ln::NodeId>();
|
|
|
|
|
for (auto const& si : source_infos) {
|
|
|
|
|
auto source = si.source;
|
|
|
|
|
auto total = si.total;
|
|
|
|
|
auto in_expenditures = si.in_expenditures;
|
|
|
|
|
|
|
|
|
|
auto limit = (total * max_in_expenditures_percent) / 100.0;
|
|
|
|
|
|
|
|
|
|
if (in_expenditures > limit)
|
|
|
|
|
act += Boss::log( bus, Debug
|
|
|
|
|
, "InitialRebalancer: Will not "
|
|
|
|
|
"rebalance from %s, we already "
|
|
|
|
|
"spent %s on it, limit is %s."
|
|
|
|
|
, std::string(source)
|
|
|
|
|
.c_str()
|
|
|
|
|
, Util::stringify(in_expenditures)
|
|
|
|
|
.c_str()
|
|
|
|
|
, Util::stringify(limit)
|
|
|
|
|
.c_str()
|
|
|
|
|
);
|
|
|
|
|
else
|
|
|
|
|
new_sources.push_back(source);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sources = std::move(new_sources);
|
|
|
|
|
|
|
|
|
|
return std::move(act) + assign_destinations();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ev::Io<void> assign_destinations() {
|
2020-10-26 11:31:33 +08:00
|
|
|
for (auto& s : sources) {
|
|
|
|
|
if (destinations.empty())
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
auto sampler = Stats::ReservoirSampler<Ln::NodeId>(1);
|
|
|
|
|
for (auto& d : destinations) {
|
|
|
|
|
auto& info = d.second;
|
|
|
|
|
sampler.add( d.first
|
|
|
|
|
, info.receivable / info.total
|
|
|
|
|
, Boss::random_engine
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto dest = std::move(sampler).finalize()[0];
|
|
|
|
|
plan.push_back(std::make_pair(s, dest));
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-11 14:42:15 +08:00
|
|
|
return execute_plan();
|
2020-10-26 11:31:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ev::Io<void> execute_plan() {
|
|
|
|
|
auto act = Ev::lift();
|
|
|
|
|
for (auto& p : plan) {
|
|
|
|
|
auto source = p.first;
|
|
|
|
|
auto destination = p.second;
|
|
|
|
|
auto s_info = info[source];
|
|
|
|
|
auto d_info = info[destination];
|
|
|
|
|
|
|
|
|
|
auto max_send = s_info.spendable / 2.0;
|
|
|
|
|
|
2020-11-22 01:55:51 +08:00
|
|
|
auto max_dest = d_info.total * ( ( spendable_percent
|
|
|
|
|
- dest_gap_percent
|
|
|
|
|
)
|
2020-10-26 11:31:33 +08:00
|
|
|
/ 100.0
|
|
|
|
|
);
|
|
|
|
|
auto max_receive = max_dest - d_info.spendable;
|
|
|
|
|
|
|
|
|
|
auto amount = max_send;
|
|
|
|
|
if (amount > max_receive)
|
|
|
|
|
amount = max_receive;
|
|
|
|
|
|
2020-11-22 01:55:51 +08:00
|
|
|
if (amount == Ln::Amount::sat(0))
|
|
|
|
|
continue;
|
|
|
|
|
|
2021-02-11 15:01:00 +08:00
|
|
|
auto it = current_sources.find(source);
|
|
|
|
|
if (it != current_sources.end()) {
|
|
|
|
|
act += Boss::log( bus, Debug
|
|
|
|
|
, "InitialRebalancer: %s currently "
|
|
|
|
|
"rebalancing, will not rebalance further."
|
|
|
|
|
, std::string(source).c_str()
|
|
|
|
|
);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
current_sources.insert(source);
|
|
|
|
|
|
2020-11-16 23:43:14 +08:00
|
|
|
act += Boss::log( bus, Debug
|
|
|
|
|
, "InitialRebalancer: %s --> %s --> %s"
|
|
|
|
|
, std::string(source).c_str()
|
|
|
|
|
, std::string(amount).c_str()
|
|
|
|
|
, std::string(destination).c_str()
|
|
|
|
|
);
|
2021-04-08 17:56:31 +08:00
|
|
|
/* Since move_funds is performed concurrently, we
|
|
|
|
|
* keep our self alive, otherwise we could be
|
|
|
|
|
* deleted before move_funds completes.
|
|
|
|
|
*/
|
2020-10-26 11:31:33 +08:00
|
|
|
act += Boss::concurrent(move_funds( source
|
|
|
|
|
, destination
|
|
|
|
|
, amount
|
2021-04-08 17:56:31 +08:00
|
|
|
/* Keep alive! */
|
|
|
|
|
, shared_from_this()
|
2020-10-26 11:31:33 +08:00
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
return act;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ev::Io<void> move_funds( Ln::NodeId const& source
|
|
|
|
|
, Ln::NodeId const& destination
|
|
|
|
|
, Ln::Amount amount
|
2021-04-08 17:56:31 +08:00
|
|
|
, std::shared_ptr<Impl> self
|
2020-10-26 11:31:33 +08:00
|
|
|
) {
|
2021-05-17 09:28:29 +08:00
|
|
|
auto moved = std::make_shared<Msg::ResponseMoveFunds>();
|
|
|
|
|
|
2020-10-28 08:58:51 +08:00
|
|
|
auto this_rebalance_fee = amount
|
|
|
|
|
* (rebalance_fee_percent / 100.0)
|
|
|
|
|
;
|
|
|
|
|
if (this_rebalance_fee < min_rebalance_fee)
|
|
|
|
|
this_rebalance_fee = min_rebalance_fee;
|
2021-02-11 15:01:00 +08:00
|
|
|
|
2020-10-26 11:31:33 +08:00
|
|
|
return move_rr.execute(Msg::RequestMoveFunds{
|
2020-10-28 08:58:51 +08:00
|
|
|
nullptr, source, destination, amount,
|
|
|
|
|
this_rebalance_fee
|
2021-05-17 09:28:29 +08:00
|
|
|
}).then([this, source, moved
|
|
|
|
|
](Msg::ResponseMoveFunds move_result) {
|
|
|
|
|
*moved = move_result;
|
|
|
|
|
|
2021-02-11 15:01:00 +08:00
|
|
|
auto it = current_sources.find(source);
|
|
|
|
|
assert(it != current_sources.end());
|
|
|
|
|
current_sources.erase(it);
|
2020-10-26 11:31:33 +08:00
|
|
|
return Ev::lift();
|
2021-04-08 17:56:31 +08:00
|
|
|
|
2021-05-17 09:28:29 +08:00
|
|
|
/* `self` is used below in order to ensure that
|
2021-04-08 17:56:31 +08:00
|
|
|
* we are still alive after requesting the
|
2021-05-17 09:28:29 +08:00
|
|
|
* transfer of funds.
|
2021-04-08 17:56:31 +08:00
|
|
|
*/
|
2021-05-17 09:28:29 +08:00
|
|
|
}).then([self, source, moved, destination
|
|
|
|
|
]() {
|
|
|
|
|
auto amount = moved->amount_moved;
|
|
|
|
|
auto fee = moved->fee_spent;
|
|
|
|
|
return Boss::log( self->bus, Debug
|
|
|
|
|
, "InitialRebalancer: "
|
|
|
|
|
"Moved %s -> "
|
|
|
|
|
"%s (fee: %s) -> "
|
|
|
|
|
"%s"
|
|
|
|
|
, std::string(source).c_str()
|
|
|
|
|
, std::string(amount).c_str()
|
|
|
|
|
, std::string(fee).c_str()
|
|
|
|
|
, std::string(destination).c_str()
|
|
|
|
|
);
|
2020-10-26 11:31:33 +08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
Impl( S::Bus& bus_
|
2024-04-29 01:45:47 -05:00
|
|
|
, Boss::Mod::ConstructedListpeers const& peers_
|
2020-10-28 08:35:08 +08:00
|
|
|
, MoveRR& move_rr_
|
2021-01-11 14:42:15 +08:00
|
|
|
, ExpenseRR& expense_rr_
|
2021-02-11 15:01:00 +08:00
|
|
|
, std::set<Ln::NodeId>& current_sources_
|
2022-05-09 16:35:34 +08:00
|
|
|
, std::set<Ln::NodeId> const& unmanaged_
|
2020-10-26 11:31:33 +08:00
|
|
|
) : bus(bus_), peers(peers_)
|
2020-10-28 08:35:08 +08:00
|
|
|
, move_rr(move_rr_)
|
2021-01-11 14:42:15 +08:00
|
|
|
, expense_rr(expense_rr_)
|
2021-02-11 15:01:00 +08:00
|
|
|
, current_sources(current_sources_)
|
2022-05-09 16:35:34 +08:00
|
|
|
, unmanaged(unmanaged_)
|
2020-10-26 11:31:33 +08:00
|
|
|
{ }
|
2021-04-08 17:56:31 +08:00
|
|
|
/* Make sure a shared pointer exists, since core_run uses
|
|
|
|
|
* shared_from_this.
|
|
|
|
|
*/
|
2020-10-26 11:31:33 +08:00
|
|
|
static
|
|
|
|
|
Ev::Io<void> run(std::shared_ptr<Impl> self) {
|
|
|
|
|
return self->core_run().then([self]() {
|
|
|
|
|
return Ev::lift();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
InitialRebalancer::Impl::Run::Run( S::Bus& bus
|
2024-04-29 01:45:47 -05:00
|
|
|
, Boss::Mod::ConstructedListpeers const& peers
|
2021-01-11 14:42:15 +08:00
|
|
|
, MoveRR& move_rr, ExpenseRR& expense_rr
|
2021-02-11 15:01:00 +08:00
|
|
|
, std::set<Ln::NodeId>& current_sources
|
2022-05-09 16:35:34 +08:00
|
|
|
, std::set<Ln::NodeId> const& unmanaged
|
2021-01-11 14:42:15 +08:00
|
|
|
) : pimpl(std::make_shared<Impl>( bus, peers
|
|
|
|
|
, move_rr, expense_rr
|
2021-02-11 15:01:00 +08:00
|
|
|
, current_sources
|
2022-05-09 16:35:34 +08:00
|
|
|
, unmanaged
|
2021-01-11 14:42:15 +08:00
|
|
|
))
|
2020-10-26 11:31:33 +08:00
|
|
|
{ }
|
|
|
|
|
Ev::Io<void> InitialRebalancer::Impl::Run::run() {
|
|
|
|
|
return Impl::run(pimpl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InitialRebalancer::InitialRebalancer(InitialRebalancer&&) =default;
|
|
|
|
|
InitialRebalancer::~InitialRebalancer() =default;
|
|
|
|
|
|
|
|
|
|
InitialRebalancer::InitialRebalancer(S::Bus& bus)
|
|
|
|
|
: pimpl(Util::make_unique<Impl>(bus)) { }
|
|
|
|
|
|
|
|
|
|
}}
|