Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion src/subnet-event-summary-cold-tier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,39 @@ function distinctPerKind(column: string, where: string): string {
);
}

/**
* What identifies ONE participant, for the per-kind actor count.
*
* NOT `hotkey` alone. WeightsSet is the highest-volume kind on most subnets and
* the chain event emits [netuid, uid] with NO hotkey, so `hotkey` is NULL on
* every one of its rows -- counting it reports `hotkey_count: 0` beside a
* five-figure `event_count`, which is precisely the "measured zero" this reader
* exists to stop publishing (netuid 64/30d: 9,830 events, 0 setters, against a
* real 15). The retired Postgres route counted this same hotkey-or-uid
* identity, citing the same reason, as do the weight-setter leaderboards.
*
* `netuid` is fixed by the caller's WHERE, so a bare uid is unambiguous here;
* the retired query spelled the (netuid, uid) pair only because it was not
* subnet-scoped. The prefixes keep the two namespaces from colliding, and the
* CASE yields NULL when a row carries neither -- dropped by the outer filter,
* matching COUNT(DISTINCT)'s own NULL handling.
*/
const ACTOR_IDENTITY =
`CASE WHEN hotkey IS NOT NULL AND hotkey != '' THEN 'hotkey:' || hotkey` +
` WHEN uid IS NOT NULL THEN 'uid:' || CAST(uid AS VARCHAR) END`;

/** The actor count per event_kind, distributed exactly like distinctPerKind
* but over the composite identity above. */
function distinctActorPerKind(where: string): string {
return (
`SELECT event_kind, count(*) AS n FROM (` +
`SELECT event_kind, ${ACTOR_IDENTITY} AS actor FROM chain.account_events` +
` WHERE ${where}` +
` GROUP BY event_kind, ${ACTOR_IDENTITY})` +
` WHERE actor IS NOT NULL GROUP BY event_kind`
);
}

/** event_kind -> the counted value, for merging a distinct read into the base
* rollup. A row whose kind is not a usable string is dropped rather than keyed
* under "undefined". */
Expand Down Expand Up @@ -142,7 +175,11 @@ export async function loadSubnetEventSummaryColdTier(
` sum(amount_tao) AS amount_tao, sum(alpha_amount) AS alpha_amount` +
` FROM chain.account_events WHERE ${where} GROUP BY event_kind`,
),
query(env, distinctPerKind("hotkey", where)),
query(env, distinctActorPerKind(where)),
// Coldkey has no such fallback and needs none: it is the delegating
// account, absent by nature on the kinds that have no delegator (a
// WeightsSet has no payer), so a plain distinct over the non-null rows is
// the answer rather than a gap to fill.
query(env, distinctPerKind("coldkey", where)),
query(
env,
Expand Down
57 changes: 44 additions & 13 deletions tests/subnet-event-summary-cold-tier.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,16 @@ const BASE: Row[] = [
amount_tao: "1234.5",
},
];
// WeightsSet is absent from BOTH distinct reads: its rows carry neither key,
// so the `IS NOT NULL` filter drops it entirely rather than returning 0.
const HOTKEYS: Row[] = [{ event_kind: "StakeAdded", n: 66 }];
// WeightsSet IS present in the actor read and absent from the coldkey one --
// the asymmetry is the point. Its rows carry no hotkey and no coldkey, but the
// chain event does emit a uid, so the actor identity falls back to that and
// counts real setters; there is no delegating account to fall back to for
// coldkey, so it drops out entirely. Measured live for netuid 64/30d: 15
// setters against 9,830 WeightsSet events.
const HOTKEYS: Row[] = [
{ event_kind: "StakeAdded", n: 66 },
{ event_kind: "WeightsSet", n: 15 },
];
const COLDKEYS: Row[] = [{ event_kind: "StakeAdded", n: 2109 }];
const RECENT: Row[] = [
{
Expand Down Expand Up @@ -77,8 +84,7 @@ function fakeEngine(
const query = async (_env: unknown, sql: string) => {
seen.push(sql);
if (sql.includes("ORDER BY")) return pick(overrides.recent, RECENT);
if (sql.includes("GROUP BY event_kind, hotkey"))
return pick(overrides.hotkeys, HOTKEYS);
if (sql.includes("AS actor")) return pick(overrides.hotkeys, HOTKEYS);
if (sql.includes("GROUP BY event_kind, coldkey"))
return pick(overrides.coldkeys, COLDKEYS);
return pick(overrides.base, BASE);
Expand All @@ -87,7 +93,7 @@ function fakeEngine(
query,
seen,
base: () => seen.find((s) => s.includes("count(*) AS event_count"))!,
hotkeys: () => seen.find((s) => s.includes("GROUP BY event_kind, hotkey"))!,
hotkeys: () => seen.find((s) => s.includes("AS actor"))!,
coldkeys: () =>
seen.find((s) => s.includes("GROUP BY event_kind, coldkey"))!,
recent: () => seen.find((s) => s.includes("ORDER BY"))!,
Expand Down Expand Up @@ -138,21 +144,44 @@ describe("loadSubnetEventSummaryColdTier", () => {
await load(engine);
assert.match(
engine.hotkeys(),
/count\(\*\) AS n FROM \(SELECT event_kind, hotkey FROM chain\.account_events .*GROUP BY event_kind, hotkey\) GROUP BY event_kind/,
/count\(\*\) AS n FROM \(SELECT event_kind, CASE .* AS actor FROM chain\.account_events .*GROUP BY event_kind, CASE .*\) WHERE actor IS NOT NULL GROUP BY event_kind/,
);
assert.match(
engine.coldkeys(),
/count\(\*\) AS n FROM \(SELECT event_kind, coldkey FROM chain\.account_events .*GROUP BY event_kind, coldkey\) GROUP BY event_kind/,
);
});

test("the actor count falls back to uid, or WeightsSet reports zero setters", async () => {
// THE BUG THIS REPLACED. Counting `hotkey` alone reported hotkey_count 0
// beside a five-figure event_count for WeightsSet -- the highest-volume
// kind on most subnets -- because the chain event emits [netuid, uid] and
// no hotkey at all. Live, netuid 64/30d: 9,830 events credited to 0
// setters, against a real 15. A confident zero, which is exactly what this
// reader exists to stop publishing.
//
// The retired Postgres route counted this same hotkey-or-uid identity for
// the same stated reason, as do the weight-setter leaderboards.
const engine = fakeEngine();
await load(engine);
assert.match(engine.hotkeys(), /WHEN uid IS NOT NULL/);
assert.match(engine.hotkeys(), /'uid:'/);
assert.doesNotMatch(
engine.hotkeys(),
/GROUP BY event_kind, hotkey\)/,
"grouping on hotkey alone is the zero-setter bug",
);
});

test("the distinct reads exclude NULL keys, or every kind gains a phantom", async () => {
// COUNT(DISTINCT col) ignores NULLs; GROUP BY col yields a NULL GROUP. So
// without the filter, WeightsSet -- whose rows carry no hotkey at all --
// would report exactly one distinct hotkey that does not exist.
// COUNT(DISTINCT col) ignores NULLs; GROUP BY col yields a NULL GROUP. The
// actor read filters the composite value AFTER grouping (a row with
// neither hotkey nor uid collapses to a NULL actor); the coldkey read
// filters the column directly. Without either, a kind carrying none of that
// key would report exactly one participant that does not exist.
const engine = fakeEngine();
await load(engine);
assert.match(engine.hotkeys(), /hotkey IS NOT NULL/);
assert.match(engine.hotkeys(), /WHERE actor IS NOT NULL/);
assert.match(engine.coldkeys(), /coldkey IS NOT NULL/);
});

Expand All @@ -169,9 +198,11 @@ describe("loadSubnetEventSummaryColdTier", () => {
assert.equal(byKind.StakeAdded.coldkey_count, 2109);
assert.equal(
byKind.WeightsSet.hotkey_count,
0,
"WeightsSet carries no hotkey, so 0 -- never StakeAdded's 66",
15,
"WeightsSet has no hotkey but does have uids -- its setters must be counted, never StakeAdded's 66",
);
// Still zero here, and genuinely so: a WeightsSet has no delegating
// account, so there is nothing for the coldkey count to fall back to.
assert.equal(byKind.WeightsSet.coldkey_count, 0);
});

Expand Down