@aztec/aztec-node 0.0.0-test.1 → 0.0.1-commit.b655e406

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dest/aztec-node/config.d.ts +14 -9
  2. package/dest/aztec-node/config.d.ts.map +1 -1
  3. package/dest/aztec-node/config.js +75 -14
  4. package/dest/aztec-node/node_metrics.d.ts +4 -0
  5. package/dest/aztec-node/node_metrics.d.ts.map +1 -1
  6. package/dest/aztec-node/node_metrics.js +21 -0
  7. package/dest/aztec-node/server.d.ts +90 -50
  8. package/dest/aztec-node/server.d.ts.map +1 -1
  9. package/dest/aztec-node/server.js +526 -218
  10. package/dest/bin/index.js +4 -2
  11. package/dest/index.d.ts +0 -1
  12. package/dest/index.d.ts.map +1 -1
  13. package/dest/index.js +0 -1
  14. package/dest/sentinel/config.d.ts +8 -0
  15. package/dest/sentinel/config.d.ts.map +1 -0
  16. package/dest/sentinel/config.js +29 -0
  17. package/dest/sentinel/factory.d.ts +9 -0
  18. package/dest/sentinel/factory.d.ts.map +1 -0
  19. package/dest/sentinel/factory.js +17 -0
  20. package/dest/sentinel/index.d.ts +3 -0
  21. package/dest/sentinel/index.d.ts.map +1 -0
  22. package/dest/sentinel/index.js +1 -0
  23. package/dest/sentinel/sentinel.d.ts +91 -0
  24. package/dest/sentinel/sentinel.d.ts.map +1 -0
  25. package/dest/sentinel/sentinel.js +391 -0
  26. package/dest/sentinel/store.d.ts +34 -0
  27. package/dest/sentinel/store.d.ts.map +1 -0
  28. package/dest/sentinel/store.js +169 -0
  29. package/dest/test/index.d.ts +31 -0
  30. package/dest/test/index.d.ts.map +1 -0
  31. package/dest/test/index.js +1 -0
  32. package/package.json +42 -32
  33. package/src/aztec-node/config.ts +128 -25
  34. package/src/aztec-node/node_metrics.ts +28 -0
  35. package/src/aztec-node/server.ts +684 -278
  36. package/src/bin/index.ts +4 -2
  37. package/src/index.ts +0 -1
  38. package/src/sentinel/config.ts +37 -0
  39. package/src/sentinel/factory.ts +36 -0
  40. package/src/sentinel/index.ts +8 -0
  41. package/src/sentinel/sentinel.ts +489 -0
  42. package/src/sentinel/store.ts +184 -0
  43. package/src/test/index.ts +32 -0
  44. package/dest/aztec-node/http_rpc_server.d.ts +0 -8
  45. package/dest/aztec-node/http_rpc_server.d.ts.map +0 -1
  46. package/dest/aztec-node/http_rpc_server.js +0 -9
  47. package/src/aztec-node/http_rpc_server.ts +0 -11
@@ -0,0 +1,184 @@
1
+ import { EthAddress } from '@aztec/foundation/eth-address';
2
+ import { BufferReader, numToUInt8, numToUInt32BE, serializeToBuffer } from '@aztec/foundation/serialize';
3
+ import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
4
+ import type {
5
+ ValidatorStatusHistory,
6
+ ValidatorStatusInSlot,
7
+ ValidatorsEpochPerformance,
8
+ } from '@aztec/stdlib/validators';
9
+
10
+ export class SentinelStore {
11
+ public static readonly SCHEMA_VERSION = 2;
12
+
13
+ // a map from validator address to their ValidatorStatusHistory
14
+ private readonly historyMap: AztecAsyncMap<`0x${string}`, Buffer>;
15
+
16
+ // a map from validator address to their historical proven epoch performance
17
+ // e.g. { validator: [{ epoch: 1, missed: 1, total: 10 }, { epoch: 2, missed: 3, total: 7 }, ...] }
18
+ private readonly provenMap: AztecAsyncMap<`0x${string}`, Buffer>;
19
+
20
+ constructor(
21
+ private store: AztecAsyncKVStore,
22
+ private config: { historyLength: number; historicProvenPerformanceLength: number },
23
+ ) {
24
+ this.historyMap = store.openMap('sentinel-validator-status');
25
+ this.provenMap = store.openMap('sentinel-validator-proven');
26
+ }
27
+
28
+ public getHistoryLength() {
29
+ return this.config.historyLength;
30
+ }
31
+
32
+ public getHistoricProvenPerformanceLength() {
33
+ return this.config.historicProvenPerformanceLength;
34
+ }
35
+
36
+ public async updateProvenPerformance(epoch: bigint, performance: ValidatorsEpochPerformance) {
37
+ await this.store.transactionAsync(async () => {
38
+ for (const [who, { missed, total }] of Object.entries(performance)) {
39
+ await this.pushValidatorProvenPerformanceForEpoch({ who: EthAddress.fromString(who), missed, total, epoch });
40
+ }
41
+ });
42
+ }
43
+
44
+ public async getProvenPerformance(who: EthAddress): Promise<{ missed: number; total: number; epoch: bigint }[]> {
45
+ const currentPerformanceBuffer = await this.provenMap.getAsync(who.toString());
46
+ return currentPerformanceBuffer ? this.deserializePerformance(currentPerformanceBuffer) : [];
47
+ }
48
+
49
+ private async pushValidatorProvenPerformanceForEpoch({
50
+ who,
51
+ missed,
52
+ total,
53
+ epoch,
54
+ }: {
55
+ who: EthAddress;
56
+ missed: number;
57
+ total: number;
58
+ epoch: bigint;
59
+ }) {
60
+ const currentPerformance = await this.getProvenPerformance(who);
61
+ const existingIndex = currentPerformance.findIndex(p => p.epoch === epoch);
62
+ if (existingIndex !== -1) {
63
+ currentPerformance[existingIndex] = { missed, total, epoch };
64
+ } else {
65
+ currentPerformance.push({ missed, total, epoch });
66
+ }
67
+
68
+ // This should be sorted by epoch, but just in case.
69
+ // Since we keep the size small, this is not a big deal.
70
+ currentPerformance.sort((a, b) => Number(a.epoch - b.epoch));
71
+
72
+ // keep the most recent `historicProvenPerformanceLength` entries.
73
+ const performanceToKeep = currentPerformance.slice(-this.config.historicProvenPerformanceLength);
74
+
75
+ await this.provenMap.set(who.toString(), this.serializePerformance(performanceToKeep));
76
+ }
77
+
78
+ public async updateValidators(slot: bigint, statuses: Record<`0x${string}`, ValidatorStatusInSlot | undefined>) {
79
+ await this.store.transactionAsync(async () => {
80
+ for (const [who, status] of Object.entries(statuses)) {
81
+ if (status) {
82
+ await this.pushValidatorStatusForSlot(EthAddress.fromString(who), slot, status);
83
+ }
84
+ }
85
+ });
86
+ }
87
+
88
+ private async pushValidatorStatusForSlot(
89
+ who: EthAddress,
90
+ slot: bigint,
91
+ status: 'block-mined' | 'block-proposed' | 'block-missed' | 'attestation-sent' | 'attestation-missed',
92
+ ) {
93
+ await this.store.transactionAsync(async () => {
94
+ const currentHistory = (await this.getHistory(who)) ?? [];
95
+ const newHistory = [...currentHistory, { slot, status }].slice(-this.config.historyLength);
96
+ await this.historyMap.set(who.toString(), this.serializeHistory(newHistory));
97
+ });
98
+ }
99
+
100
+ public async getHistories(): Promise<Record<`0x${string}`, ValidatorStatusHistory>> {
101
+ const histories: Record<`0x${string}`, ValidatorStatusHistory> = {};
102
+ for await (const [address, history] of this.historyMap.entriesAsync()) {
103
+ histories[address] = this.deserializeHistory(history);
104
+ }
105
+ return histories;
106
+ }
107
+
108
+ public async getHistory(address: EthAddress): Promise<ValidatorStatusHistory | undefined> {
109
+ const data = await this.historyMap.getAsync(address.toString());
110
+ return data && this.deserializeHistory(data);
111
+ }
112
+
113
+ private serializePerformance(performance: { missed: number; total: number; epoch: bigint }[]): Buffer {
114
+ return serializeToBuffer(
115
+ performance.map(p => [numToUInt32BE(Number(p.epoch)), numToUInt32BE(p.missed), numToUInt32BE(p.total)]),
116
+ );
117
+ }
118
+
119
+ private deserializePerformance(buffer: Buffer): { missed: number; total: number; epoch: bigint }[] {
120
+ const reader = new BufferReader(buffer);
121
+ const performance: { missed: number; total: number; epoch: bigint }[] = [];
122
+ while (!reader.isEmpty()) {
123
+ performance.push({
124
+ epoch: BigInt(reader.readNumber()),
125
+ missed: reader.readNumber(),
126
+ total: reader.readNumber(),
127
+ });
128
+ }
129
+ return performance;
130
+ }
131
+
132
+ private serializeHistory(history: ValidatorStatusHistory): Buffer {
133
+ return serializeToBuffer(
134
+ history.map(h => [numToUInt32BE(Number(h.slot)), numToUInt8(this.statusToNumber(h.status))]),
135
+ );
136
+ }
137
+
138
+ private deserializeHistory(buffer: Buffer): ValidatorStatusHistory {
139
+ const reader = new BufferReader(buffer);
140
+ const history: ValidatorStatusHistory = [];
141
+ while (!reader.isEmpty()) {
142
+ const slot = BigInt(reader.readNumber());
143
+ const status = this.statusFromNumber(reader.readUInt8());
144
+ history.push({ slot, status });
145
+ }
146
+ return history;
147
+ }
148
+
149
+ private statusToNumber(status: ValidatorStatusInSlot): number {
150
+ switch (status) {
151
+ case 'block-mined':
152
+ return 1;
153
+ case 'block-proposed':
154
+ return 2;
155
+ case 'block-missed':
156
+ return 3;
157
+ case 'attestation-sent':
158
+ return 4;
159
+ case 'attestation-missed':
160
+ return 5;
161
+ default: {
162
+ const _exhaustive: never = status;
163
+ throw new Error(`Unknown status: ${status}`);
164
+ }
165
+ }
166
+ }
167
+
168
+ private statusFromNumber(status: number): ValidatorStatusInSlot {
169
+ switch (status) {
170
+ case 1:
171
+ return 'block-mined';
172
+ case 2:
173
+ return 'block-proposed';
174
+ case 3:
175
+ return 'block-missed';
176
+ case 4:
177
+ return 'attestation-sent';
178
+ case 5:
179
+ return 'attestation-missed';
180
+ default:
181
+ throw new Error(`Unknown status: ${status}`);
182
+ }
183
+ }
184
+ }
@@ -0,0 +1,32 @@
1
+ import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
+ import type { P2P } from '@aztec/p2p';
3
+ import { SequencerClient } from '@aztec/sequencer-client';
4
+ import { EpochPruneWatcher, type SlasherClientInterface } from '@aztec/slasher';
5
+ import type { L2BlockSource } from '@aztec/stdlib/block';
6
+ import type { ContractDataSource } from '@aztec/stdlib/contract';
7
+ import type { L2LogsSource, Service, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
8
+ import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
9
+ import type { GlobalVariableBuilder as GlobalVariableBuilderInterface } from '@aztec/stdlib/tx';
10
+
11
+ import type { AztecNodeConfig } from '../aztec-node/config.js';
12
+ import { AztecNodeService } from '../aztec-node/server.js';
13
+ import { Sentinel } from '../sentinel/sentinel.js';
14
+
15
+ export declare class TestAztecNodeService extends AztecNodeService {
16
+ declare public config: AztecNodeConfig;
17
+ declare public p2pClient: P2P;
18
+ declare public blockSource: L2BlockSource & Partial<Service>;
19
+ declare public logsSource: L2LogsSource;
20
+ declare public contractDataSource: ContractDataSource;
21
+ declare public l1ToL2MessageSource: L1ToL2MessageSource;
22
+ declare public worldStateSynchronizer: WorldStateSynchronizer;
23
+ declare public sequencer: SequencerClient | undefined;
24
+ declare public slasherClient: SlasherClientInterface | undefined;
25
+ declare public validatorsSentinel: Sentinel | undefined;
26
+ declare public epochPruneWatcher: EpochPruneWatcher | undefined;
27
+ declare public l1ChainId: number;
28
+ declare public version: number;
29
+ declare public globalVariableBuilder: GlobalVariableBuilderInterface;
30
+ declare public epochCache: EpochCacheInterface;
31
+ declare public packageVersion: string;
32
+ }
@@ -1,8 +0,0 @@
1
- import { type AztecNode } from '@aztec/stdlib/interfaces/client';
2
- /**
3
- * Wrap an AztecNode instance with a JSON RPC HTTP server.
4
- * @param node - The AztecNode
5
- * @returns An JSON-RPC HTTP server
6
- */
7
- export declare function createAztecNodeRpcServer(node: AztecNode): import("@aztec/foundation/json-rpc/server").SafeJsonRpcServer;
8
- //# sourceMappingURL=http_rpc_server.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"http_rpc_server.d.ts","sourceRoot":"","sources":["../../src/aztec-node/http_rpc_server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAsB,MAAM,iCAAiC,CAAC;AAGrF;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,SAAS,iEAEvD"}
@@ -1,9 +0,0 @@
1
- import { AztecNodeApiSchema } from '@aztec/stdlib/interfaces/client';
2
- import { createTracedJsonRpcServer } from '@aztec/telemetry-client';
3
- /**
4
- * Wrap an AztecNode instance with a JSON RPC HTTP server.
5
- * @param node - The AztecNode
6
- * @returns An JSON-RPC HTTP server
7
- */ export function createAztecNodeRpcServer(node) {
8
- return createTracedJsonRpcServer(node, AztecNodeApiSchema);
9
- }
@@ -1,11 +0,0 @@
1
- import { type AztecNode, AztecNodeApiSchema } from '@aztec/stdlib/interfaces/client';
2
- import { createTracedJsonRpcServer } from '@aztec/telemetry-client';
3
-
4
- /**
5
- * Wrap an AztecNode instance with a JSON RPC HTTP server.
6
- * @param node - The AztecNode
7
- * @returns An JSON-RPC HTTP server
8
- */
9
- export function createAztecNodeRpcServer(node: AztecNode) {
10
- return createTracedJsonRpcServer(node, AztecNodeApiSchema);
11
- }