Skip to content

Commit

Permalink
feat: subnet metrics for canisterStatus (#790)
Browse files Browse the repository at this point in the history
  • Loading branch information
krpeacock authored Oct 30, 2023
1 parent 2d195f8 commit 1917055
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/generated/changelog.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ <h1>Agent-JS Changelog</h1>
<section>
<h2>Version x.x.x</h2>
<ul>
<li>feat: adds subnet metrics decoding to canisterStatus for `/subnet` path</li>
<li>
chore: replaces use of localhost with 127.0.0.1 for better node 18 support. Also swaps
Jest for vitest, runs mitm against mainnet, and updates some packages
Expand Down
9 changes: 9 additions & 0 deletions packages/agent/src/certificate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,15 @@ describe('node keys', () => {
const nodeKeys = cert.cache_node_keys();
expect(nodeKeys).toMatchInlineSnapshot(`
Object {
"metrics": Object {
"canister_state_bytes": 10007399447n,
"consumed_cycles_total": Object {
"current": 15136490391288n,
"deleted": 0n,
},
"num_canisters": 451n,
"update_transactions_total": 222360n,
},
"nodeKeys": Array [
"302a300506032b65700321005b0bdf0329932ab0a78fa7192ad76cf37d67eb2024739774d3b67da7799ebc9c",
"302a300506032b65700321009776d25542873dafb8099303d1fca8e4aa344e73cf5a3d7df5b40f9c8ed5a085",
Expand Down
56 changes: 55 additions & 1 deletion packages/agent/src/certificate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ export type SubnetStatus = {
// Principal as a string
subnetId: string;
nodeKeys: string[];
metrics?: {
num_canisters: bigint;
canister_state_bytes: bigint;
consumed_cycles_total: {
current: bigint;
deleted: bigint;
};
update_transactions_total: bigint;
};
};

/**
Expand Down Expand Up @@ -164,6 +173,8 @@ export interface CreateCertificateOptions {
maxAgeInMinutes?: number;
}

type MetricsResult = number | bigint | Map<number, number | bigint> | undefined;

export class Certificate {
private readonly cert: Cert;
#nodeKeys: string[] = [];
Expand Down Expand Up @@ -216,6 +227,12 @@ export class Certificate {
return this.lookup([label]);
}

#toBigInt(n: MetricsResult): bigint {
if (typeof n === 'undefined') return BigInt(0);
if (typeof n === 'bigint') return n;
return BigInt(Number(n));
}

public cache_node_keys(root_key?: Uint8Array): SubnetStatus {
const tree = this.cert.tree;
let delegation = this.cert.delegation;
Expand Down Expand Up @@ -248,10 +265,47 @@ export class Certificate {
}
});

return {
const metricsTree = lookup_path(
['subnet', delegation?.subnet_id as ArrayBuffer, 'metrics'],
tree,
);
let metrics: SubnetStatus['metrics'] | undefined = undefined;
if (metricsTree) {
const decoded = cbor.decode(metricsTree as ArrayBuffer) as Map<
number,
Map<number, number | bigint>
>;

// Cbor may decode values as either number or bigint. For consistency, we convert all numbers to bigint
const num_canisters = this.#toBigInt(decoded.get(0));
const canister_state_bytes = this.#toBigInt(decoded.get(1));
const current_consumed_cycles = this.#toBigInt(
(decoded.get(2) as Map<number, number>).get(0),
);
const deleted_consumed_cycles = this.#toBigInt(
(decoded.get(2) as Map<number, number>).get(1),
);
const update_transactions_total = this.#toBigInt(decoded.get(3));

metrics = {
num_canisters: num_canisters,
canister_state_bytes: canister_state_bytes,
consumed_cycles_total: {
current: current_consumed_cycles,
deleted: deleted_consumed_cycles,
},
update_transactions_total: update_transactions_total,
};
}

const result: SubnetStatus = {
subnetId: Principal.fromUint8Array(new Uint8Array(delegation.subnet_id)).toText(),
nodeKeys: this.#nodeKeys,
};
if (metrics) {
result.metrics = metrics;
}
return result;
}

private async verify(): Promise<void> {
Expand Down

0 comments on commit 1917055

Please sign in to comment.