Skip to content

Commit

Permalink
add clboss-recent-earnings and clboss-earnings-history
Browse files Browse the repository at this point in the history
  • Loading branch information
ksedgwic committed Aug 8, 2024
1 parent 188accf commit 6a9fe04
Show file tree
Hide file tree
Showing 6 changed files with 721 additions and 1 deletion.
216 changes: 215 additions & 1 deletion Boss/Mod/EarningsTracker.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#include"Boss/Mod/EarningsTracker.hpp"
#include"Boss/Msg/CommandFail.hpp"
#include"Boss/Msg/CommandRequest.hpp"
#include"Boss/Msg/CommandResponse.hpp"
#include"Boss/Msg/DbResource.hpp"
#include"Boss/Msg/ForwardFee.hpp"
#include"Boss/Msg/ManifestCommand.hpp"
#include"Boss/Msg/Manifestation.hpp"
#include"Boss/Msg/ProvideStatus.hpp"
#include"Boss/Msg/RequestEarningsInfo.hpp"
#include"Boss/Msg/RequestMoveFunds.hpp"
Expand All @@ -15,6 +20,7 @@

#include<cmath>
#include<map>
#include<iostream>

namespace Boss { namespace Mod {

Expand Down Expand Up @@ -54,7 +60,92 @@ class EarningsTracker::Impl {
>([this](Msg::RequestEarningsInfo const& req) {
return Boss::concurrent(request_earnings_info(req));
});

bus.subscribe<Msg::Manifestation
>([this](Msg::Manifestation const& _) {
return bus.raise(Msg::ManifestCommand{
"clboss-recent-earnings", "[days]",
"Show offchain_earnings_tracker data for the most recent {days} "
"(default 14 days).",
false
}) + bus.raise(Msg::ManifestCommand{
"clboss-earnings-history", "[nodeid]",
"Show earnings and expenditure history for {nodeid} "
"(default all nodes)",
false
});
});
bus.subscribe<Msg::CommandRequest>([this](Msg::CommandRequest const& req) {
auto id = req.id;
auto paramfail = [this, id]() {
return bus.raise(Msg::CommandFail{
id, -32602,
"Parameter failure",
Json::Out::empty_object()
});
};
if (req.command == "clboss-recent-earnings") {
auto days = double(14.0);
auto days_j = Jsmn::Object();
auto params = req.params;
if (params.is_object()) {
if (params.size() > 1)
return paramfail();
if (params.size() == 1) {
if (!params.has("days"))
return paramfail();
days_j = params["days"];
}
} else if (params.is_array()) {
if (params.size() > 1)
return paramfail();
if (params.size() == 1)
days_j = params[0];
}
if (!days_j.is_null()) {
if (!days_j.is_number())
return paramfail();
days = (double) days_j;
}
return db.transact().then([this, id, days](Sqlite3::Tx tx) {
auto report = recent_earnings_report(tx, days);
tx.commit();
return bus.raise(Msg::CommandResponse{
id, report
});
});
} else if (req.command == "clboss-earnings-history") {
auto nodeid = std::string("");
auto nodeid_j = Jsmn::Object();
auto params = req.params;
if (params.is_object()) {
if (params.size() > 1)
return paramfail();
if (params.size() == 1) {
if (!params.has("nodeid"))
return paramfail();
nodeid_j = params["nodeid"];
}
} else if (params.is_array()) {
if (params.size() > 1)
return paramfail();
if (params.size() == 1)
nodeid_j = params[0];
}
if (!nodeid_j.is_null()) {
if (!nodeid_j.is_string())
return paramfail();
nodeid = (std::string) nodeid_j;
}
return db.transact().then([this, id, nodeid](Sqlite3::Tx tx) {
auto report = earnings_history_report(tx, nodeid);
tx.commit();
return bus.raise(Msg::CommandResponse{
id, report
});
});
}
return Ev::lift();
});
bus.subscribe<Msg::SolicitStatus
>([this](Msg::SolicitStatus const& _) {
if (!db)
Expand Down Expand Up @@ -348,6 +439,129 @@ class EarningsTracker::Impl {
});
}

Json::Out recent_earnings_report(Sqlite3::Tx& tx, double days) {
auto cutoff = bucket_time(get_now()) - (days * 24 * 60 * 60);
auto fetch = tx.query(R"QRY(
SELECT node,
SUM(in_earnings) AS total_in_earnings,
SUM(in_expenditures) AS total_in_expenditures,
SUM(out_earnings) AS total_out_earnings,
SUM(out_expenditures) AS total_out_expenditures
FROM "EarningsTracker"
WHERE time_bucket >= :cutoff
GROUP BY node;
)QRY")
.bind(":cutoff", cutoff)
.execute()
;
auto out = Json::Out();
auto top = out.start_object();
auto recent = top.start_object("recent");
uint64_t total_in_earnings = 0;
uint64_t total_in_expenditures = 0;
uint64_t total_out_earnings = 0;
uint64_t total_out_expenditures = 0;
for (auto& r : fetch) {
auto in_earnings = r.get<std::uint64_t>(1);
auto in_expenditures = r.get<std::uint64_t>(2);
auto out_earnings = r.get<std::uint64_t>(3);
auto out_expenditures = r.get<std::uint64_t>(4);
auto sub = recent.start_object(r.get<std::string>(0));
sub
.field("in_earnings", in_earnings)
.field("in_expenditures", in_expenditures)
.field("out_earnings", out_earnings)
.field("out_expenditures", out_expenditures)
;
sub.end_object();
total_in_earnings += in_earnings;
total_in_expenditures += in_expenditures;
total_out_earnings += out_earnings;
total_out_expenditures += out_expenditures;
}
recent.end_object();
auto total = top.start_object("total");
total
.field("in_earnings", total_in_earnings)
.field("in_expenditures", total_in_expenditures)
.field("out_earnings", total_out_earnings)
.field("out_expenditures", total_out_expenditures)
;
total.end_object();
top.end_object();
return out;
}

Json::Out earnings_history_report(Sqlite3::Tx& tx, std::string nodeid) {
std::string sql;
if (nodeid.empty()) {
sql = R"QRY(
SELECT time_bucket,
SUM(in_earnings) AS total_in_earnings,
SUM(in_expenditures) AS total_in_expenditures,
SUM(out_earnings) AS total_out_earnings,
SUM(out_expenditures) AS total_out_expenditures
FROM "EarningsTracker"
GROUP BY time_bucket
ORDER BY time_bucket;
)QRY";
} else {
sql = R"QRY(
SELECT time_bucket,
in_earnings,
in_expenditures,
out_earnings,
out_expenditures
FROM "EarningsTracker"
WHERE node = :nodeid
ORDER BY time_bucket;
)QRY";
}
auto query = tx.query(sql.c_str());
if (!nodeid.empty()) {
query.bind(":nodeid", nodeid);
}
auto fetch = query.execute();

auto out = Json::Out();
auto top = out.start_object();
auto history = top.start_array("history");
uint64_t total_in_earnings = 0;
uint64_t total_in_expenditures = 0;
uint64_t total_out_earnings = 0;
uint64_t total_out_expenditures = 0;
for (auto& r : fetch) {
auto in_earnings = r.get<std::uint64_t>(1);
auto in_expenditures = r.get<std::uint64_t>(2);
auto out_earnings = r.get<std::uint64_t>(3);
auto out_expenditures = r.get<std::uint64_t>(4);
auto sub = history.start_object();
sub
.field("bucket_time", static_cast<std::uint64_t>(r.get<double>(0)))
.field("in_earnings", in_earnings)
.field("in_expenditures", in_expenditures)
.field("out_earnings", out_earnings)
.field("out_expenditures", out_expenditures)
;
sub.end_object();
total_in_earnings += in_earnings;
total_in_expenditures += in_expenditures;
total_out_earnings += out_earnings;
total_out_expenditures += out_expenditures;
}
history.end_array();
auto total = top.start_object("total");
total
.field("in_earnings", total_in_earnings)
.field("in_expenditures", total_in_expenditures)
.field("out_earnings", total_out_earnings)
.field("out_expenditures", total_out_expenditures)
;
total.end_object();
top.end_object();
return out;
}

public:
Impl() =delete;
Impl(Impl&&) =delete;
Expand Down
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,8 @@ TESTS = \
tests/boss/test_needsconnectsolicitor \
tests/boss/test_onchainfeemonitor_samples_init \
tests/boss/test_peerjudge_agetracker \
tests/boss/test_recentearnings \
tests/boss/test_earningshistory \
tests/boss/test_peerjudge_algo \
tests/boss/test_peerjudge_datagatherer \
tests/boss/test_peerstatistician \
Expand Down
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -432,3 +432,52 @@ Specify the value in satoshis without adding any unit
suffix, e.g.

lightningd --clboss-min-channel=1000000

### `clboss-recent-earnings`, `clboss-earnings-history`

As of CLBOSS version [TBD] earnings and expenditures are tracked on a
daily basis.

The `clboss-recent-earnings` command returns an equivalent data
structure to the `offchain_earnings_tracker` collection in
`clboss-status` but only shows recent earnings and expenditures. The
`clboss-recent-earnings` command takes an optional `days` argument
which defaults to a fortnight (14 days).

The `clboss-earnings-history` command returns a daily breakdown of
earnings and expenditures. The `clboss-earnings-history` command
takes an optional `nodeid` argument which limits the history to a
particular node. Without the argument the daily history accumulated
across all nodes. In the history output the time bucket with value 0
holds any legacy earnings and expenditures which were collected by
legacy nodes before daily tracking.

### `clboss-recent-earnings`, `clboss-earnings-history` Commands

As of CLBOSS version [TBD], earnings and expenditures are tracked on a daily basis.
The following commands have been added to observe the new data:

- **`clboss-recent-earnings`**:
- **Purpose**: Returns a data structure equivalent to the
`offchain_earnings_tracker` collection in `clboss-status`, but
only includes recent earnings and expenditures.
- **Arguments**:
- `days` (optional): Specifies the number of days to include in
the report. Defaults to a fortnight (14 days) if not provided.

- **`clboss-earnings-history`**:
- **Purpose**: Provides a daily breakdown of earnings and expenditures.
- **Arguments**:
- `nodeid` (optional): Limits the history to a particular node if
provided. Without this argument, the history is accumulated
across all nodes.
- **Output**:
- The history consists of an array of records showing the earnings
and expenditures for each day.
- The history includes an initial record with a time value of 0,
which contains any legacy earnings and expenditures collected by
CLBOSS before daily tracking was implemented.

These commands enhance the tracking of financial metrics, allowing for
detailed and recent analysis of earnings and expenditures on a daily
basis.
10 changes: 10 additions & 0 deletions tests/boss/test_availablerpccommandsannouncer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ auto const help = std::string(R"JSON(
, { "command": "clboss-unmanage nodeid tags"
, "category": "plugin"
}
, { "command": "clboss-recent-earnings [days]"
, "category": "plugin"
}
, { "command": "clboss-earnings-history [nodeid]"
, "category": "plugin"
}
]
}
)JSON");
Expand Down Expand Up @@ -73,6 +79,10 @@ int main() {
assert(commands["clboss-status"].usage == "");
assert(commands["clboss-ignore-onchain"].usage == "[hours]");
assert(commands["clboss-unmanage"].usage == "nodeid tags");
assert(commands.count("clboss-recent-earnings") != 0);
assert(commands["clboss-recent-earnings"].usage == "[days]");
assert(commands.count("clboss-earnings-history") != 0);
assert(commands["clboss-earnings-history"].usage == "[nodeid]");

return Ev::lift();
});
Expand Down
Loading

0 comments on commit 6a9fe04

Please sign in to comment.