@aztec/aztec-node 0.85.0-alpha-testnet.3 → 0.85.0-alpha-testnet.5
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.
- package/dest/sentinel/sentinel.d.ts +5 -1
- package/dest/sentinel/sentinel.d.ts.map +1 -1
- package/dest/sentinel/sentinel.js +23 -14
- package/package.json +22 -21
- package/src/sentinel/sentinel.ts +24 -13
|
@@ -17,7 +17,11 @@ export declare class Sentinel implements L2BlockStreamEventHandler {
|
|
|
17
17
|
protected l2TipsStore: L2TipsStore;
|
|
18
18
|
protected initialSlot: bigint | undefined;
|
|
19
19
|
protected lastProcessedSlot: bigint | undefined;
|
|
20
|
-
protected
|
|
20
|
+
protected slotNumberToBlock: Map<bigint, {
|
|
21
|
+
blockNumber: number;
|
|
22
|
+
archive: string;
|
|
23
|
+
attestors: EthAddress[];
|
|
24
|
+
}>;
|
|
21
25
|
constructor(epochCache: EpochCache, archiver: L2BlockSource, p2p: P2PClient, store: SentinelStore, logger?: import("@aztec/foundation/log").Logger);
|
|
22
26
|
start(): Promise<void>;
|
|
23
27
|
/** Loads initial slot and initializes blockstream. We will not process anything at or before the initial slot. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sentinel.d.ts","sourceRoot":"","sources":["../../src/sentinel/sentinel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,KAAK,aAAa,EAClB,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,
|
|
1
|
+
{"version":3,"file":"sentinel.d.ts","sourceRoot":"","sources":["../../src/sentinel/sentinel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,KAAK,aAAa,EAClB,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAE/B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,qBAAa,QAAS,YAAW,yBAAyB;IAWtD,SAAS,CAAC,UAAU,EAAE,UAAU;IAChC,SAAS,CAAC,QAAQ,EAAE,aAAa;IACjC,SAAS,CAAC,GAAG,EAAE,SAAS;IACxB,SAAS,CAAC,KAAK,EAAE,aAAa;IAC9B,SAAS,CAAC,MAAM;IAdlB,SAAS,CAAC,cAAc,EAAE,cAAc,CAAC;IACzC,SAAS,CAAC,WAAW,EAAG,aAAa,CAAC;IACtC,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;IAEnC,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,SAAS,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,SAAS,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC,CAC/F;gBAGA,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,aAAa,EACpB,MAAM,yCAAgC;IAOrC,KAAK;IAKlB,kHAAkH;cAClG,IAAI;IAOb,IAAI;IAIE,sBAAsB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB7E;;;;OAIG;IACU,IAAI;IAmBjB;;;;OAIG;cACa,gBAAgB,CAAC,WAAW,EAAE,MAAM;IAkCpD;;;OAGG;cACa,WAAW,CAAC,IAAI,EAAE,MAAM;IAexC,0CAA0C;cAC1B,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE;;;IAwD1G,wDAAwD;IACxD,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAIxG,0DAA0D;IAC7C,YAAY,IAAI,OAAO,CAAC,eAAe,CAAC;IAiBrD,SAAS,CAAC,wBAAwB,CAChC,OAAO,EAAE,KAAK,MAAM,EAAE,EACtB,UAAU,EAAE,sBAAsB,EAClC,QAAQ,CAAC,EAAE,MAAM,GAChB,cAAc;IAejB,SAAS,CAAC,aAAa,CACrB,OAAO,EAAE,sBAAsB,EAC/B,iBAAiB,EAAE,mBAAmB,EACtC,MAAM,EAAE,qBAAqB;;;;;IAW/B,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS;;;;;CAOnD"}
|
|
@@ -3,7 +3,7 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
5
5
|
import { L2TipsMemoryStore } from '@aztec/kv-store/stores';
|
|
6
|
-
import { L2BlockStream } from '@aztec/stdlib/block';
|
|
6
|
+
import { L2BlockStream, getAttestationsFromPublishedL2Block } from '@aztec/stdlib/block';
|
|
7
7
|
import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
8
8
|
export class Sentinel {
|
|
9
9
|
epochCache;
|
|
@@ -16,14 +16,14 @@ export class Sentinel {
|
|
|
16
16
|
l2TipsStore;
|
|
17
17
|
initialSlot;
|
|
18
18
|
lastProcessedSlot;
|
|
19
|
-
|
|
19
|
+
slotNumberToBlock;
|
|
20
20
|
constructor(epochCache, archiver, p2p, store, logger = createLogger('node:sentinel')){
|
|
21
21
|
this.epochCache = epochCache;
|
|
22
22
|
this.archiver = archiver;
|
|
23
23
|
this.p2p = p2p;
|
|
24
24
|
this.store = store;
|
|
25
25
|
this.logger = logger;
|
|
26
|
-
this.
|
|
26
|
+
this.slotNumberToBlock = new Map();
|
|
27
27
|
this.l2TipsStore = new L2TipsMemoryStore();
|
|
28
28
|
const interval = epochCache.getL1Constants().ethereumSlotDuration * 1000 / 4;
|
|
29
29
|
this.runningPromise = new RunningPromise(this.work.bind(this), logger, interval);
|
|
@@ -46,16 +46,20 @@ export class Sentinel {
|
|
|
46
46
|
async handleBlockStreamEvent(event) {
|
|
47
47
|
await this.l2TipsStore.handleBlockStreamEvent(event);
|
|
48
48
|
if (event.type === 'blocks-added') {
|
|
49
|
-
// Store mapping from slot to archive
|
|
49
|
+
// Store mapping from slot to archive, block number, and attestors
|
|
50
50
|
for (const block of event.blocks){
|
|
51
|
-
this.
|
|
51
|
+
this.slotNumberToBlock.set(block.block.header.getSlot(), {
|
|
52
|
+
blockNumber: block.block.number,
|
|
53
|
+
archive: block.block.archive.root.toString(),
|
|
54
|
+
attestors: await Promise.all(getAttestationsFromPublishedL2Block(block).map((att)=>att.getSender()))
|
|
55
|
+
});
|
|
52
56
|
}
|
|
53
57
|
// Prune the archive map to only keep at most N entries
|
|
54
58
|
const historyLength = this.store.getHistoryLength();
|
|
55
|
-
if (this.
|
|
56
|
-
const toDelete = Array.from(this.
|
|
59
|
+
if (this.slotNumberToBlock.size > historyLength) {
|
|
60
|
+
const toDelete = Array.from(this.slotNumberToBlock.keys()).sort((a, b)=>Number(a - b)).slice(0, this.slotNumberToBlock.size - historyLength);
|
|
57
61
|
for (const key of toDelete){
|
|
58
|
-
this.
|
|
62
|
+
this.slotNumberToBlock.delete(key);
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
}
|
|
@@ -147,16 +151,21 @@ export class Sentinel {
|
|
|
147
151
|
// Check if there is an L2 block in L1 for this L2 slot
|
|
148
152
|
// Here we get all attestations for the block mined at the given slot,
|
|
149
153
|
// or all attestations for all proposals in the slot if no block was mined.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const
|
|
154
|
+
// We gather from both p2p (contains the ones seen on the p2p layer) and archiver
|
|
155
|
+
// (contains the ones synced from mined blocks, which we may have missed from p2p).
|
|
156
|
+
const block = this.slotNumberToBlock.get(slot);
|
|
157
|
+
const p2pAttested = await this.p2p.getAttestationsForSlot(slot, block?.archive);
|
|
158
|
+
const attestors = new Set([
|
|
159
|
+
...await Promise.all(p2pAttested.map((a)=>a.getSender().then((s)=>s.toString()))),
|
|
160
|
+
...block?.attestors.map((a)=>a.toString()) ?? []
|
|
161
|
+
]);
|
|
153
162
|
// We assume that there was a block proposal if at least one of the validators attested to it.
|
|
154
163
|
// It could be the case that every single validator failed, and we could differentiate it by having
|
|
155
164
|
// this node re-execute every block proposal it sees and storing it in the attestation pool.
|
|
156
165
|
// But we'll leave that corner case out to reduce pressure on the node.
|
|
157
|
-
const blockStatus =
|
|
166
|
+
const blockStatus = block ? 'mined' : attestors.size > 0 ? 'proposed' : 'missed';
|
|
158
167
|
this.logger.debug(`Block for slot ${slot} was ${blockStatus}`, {
|
|
159
|
-
|
|
168
|
+
...block,
|
|
160
169
|
slot
|
|
161
170
|
});
|
|
162
171
|
// Get attestors that failed their duties for this block, but only if there was a block proposed
|
|
@@ -164,7 +173,7 @@ export class Sentinel {
|
|
|
164
173
|
this.logger.debug(`Retrieved ${attestors.size} attestors out of ${committee.length} for slot ${slot}`, {
|
|
165
174
|
blockStatus,
|
|
166
175
|
proposer: proposer.toString(),
|
|
167
|
-
|
|
176
|
+
...block,
|
|
168
177
|
slot,
|
|
169
178
|
attestors: [
|
|
170
179
|
...attestors
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/aztec-node",
|
|
3
|
-
"version": "0.85.0-alpha-testnet.
|
|
3
|
+
"version": "0.85.0-alpha-testnet.5",
|
|
4
4
|
"main": "dest/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -63,26 +63,27 @@
|
|
|
63
63
|
]
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@aztec/archiver": "0.85.0-alpha-testnet.
|
|
67
|
-
"@aztec/bb-prover": "0.85.0-alpha-testnet.
|
|
68
|
-
"@aztec/blob-sink": "0.85.0-alpha-testnet.
|
|
69
|
-
"@aztec/constants": "0.85.0-alpha-testnet.
|
|
70
|
-
"@aztec/epoch-cache": "0.85.0-alpha-testnet.
|
|
71
|
-
"@aztec/ethereum": "0.85.0-alpha-testnet.
|
|
72
|
-
"@aztec/foundation": "0.85.0-alpha-testnet.
|
|
73
|
-
"@aztec/kv-store": "0.85.0-alpha-testnet.
|
|
74
|
-
"@aztec/l1-artifacts": "0.85.0-alpha-testnet.
|
|
75
|
-
"@aztec/merkle-tree": "0.85.0-alpha-testnet.
|
|
76
|
-
"@aztec/node-lib": "0.85.0-alpha-testnet.
|
|
77
|
-
"@aztec/
|
|
78
|
-
"@aztec/
|
|
79
|
-
"@aztec/
|
|
80
|
-
"@aztec/
|
|
81
|
-
"@aztec/
|
|
82
|
-
"@aztec/
|
|
83
|
-
"@aztec/
|
|
84
|
-
"@aztec/
|
|
85
|
-
"@aztec/
|
|
66
|
+
"@aztec/archiver": "0.85.0-alpha-testnet.5",
|
|
67
|
+
"@aztec/bb-prover": "0.85.0-alpha-testnet.5",
|
|
68
|
+
"@aztec/blob-sink": "0.85.0-alpha-testnet.5",
|
|
69
|
+
"@aztec/constants": "0.85.0-alpha-testnet.5",
|
|
70
|
+
"@aztec/epoch-cache": "0.85.0-alpha-testnet.5",
|
|
71
|
+
"@aztec/ethereum": "0.85.0-alpha-testnet.5",
|
|
72
|
+
"@aztec/foundation": "0.85.0-alpha-testnet.5",
|
|
73
|
+
"@aztec/kv-store": "0.85.0-alpha-testnet.5",
|
|
74
|
+
"@aztec/l1-artifacts": "0.85.0-alpha-testnet.5",
|
|
75
|
+
"@aztec/merkle-tree": "0.85.0-alpha-testnet.5",
|
|
76
|
+
"@aztec/node-lib": "0.85.0-alpha-testnet.5",
|
|
77
|
+
"@aztec/noir-protocol-circuits-types": "0.85.0-alpha-testnet.5",
|
|
78
|
+
"@aztec/p2p": "0.85.0-alpha-testnet.5",
|
|
79
|
+
"@aztec/protocol-contracts": "0.85.0-alpha-testnet.5",
|
|
80
|
+
"@aztec/prover-client": "0.85.0-alpha-testnet.5",
|
|
81
|
+
"@aztec/sequencer-client": "0.85.0-alpha-testnet.5",
|
|
82
|
+
"@aztec/simulator": "0.85.0-alpha-testnet.5",
|
|
83
|
+
"@aztec/stdlib": "0.85.0-alpha-testnet.5",
|
|
84
|
+
"@aztec/telemetry-client": "0.85.0-alpha-testnet.5",
|
|
85
|
+
"@aztec/validator-client": "0.85.0-alpha-testnet.5",
|
|
86
|
+
"@aztec/world-state": "0.85.0-alpha-testnet.5",
|
|
86
87
|
"koa": "^2.16.1",
|
|
87
88
|
"koa-router": "^12.0.0",
|
|
88
89
|
"tslib": "^2.4.0",
|
package/src/sentinel/sentinel.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
L2BlockStream,
|
|
11
11
|
type L2BlockStreamEvent,
|
|
12
12
|
type L2BlockStreamEventHandler,
|
|
13
|
+
getAttestationsFromPublishedL2Block,
|
|
13
14
|
} from '@aztec/stdlib/block';
|
|
14
15
|
import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
15
16
|
import type {
|
|
@@ -29,7 +30,8 @@ export class Sentinel implements L2BlockStreamEventHandler {
|
|
|
29
30
|
|
|
30
31
|
protected initialSlot: bigint | undefined;
|
|
31
32
|
protected lastProcessedSlot: bigint | undefined;
|
|
32
|
-
protected
|
|
33
|
+
protected slotNumberToBlock: Map<bigint, { blockNumber: number; archive: string; attestors: EthAddress[] }> =
|
|
34
|
+
new Map();
|
|
33
35
|
|
|
34
36
|
constructor(
|
|
35
37
|
protected epochCache: EpochCache,
|
|
@@ -63,19 +65,23 @@ export class Sentinel implements L2BlockStreamEventHandler {
|
|
|
63
65
|
public async handleBlockStreamEvent(event: L2BlockStreamEvent): Promise<void> {
|
|
64
66
|
await this.l2TipsStore.handleBlockStreamEvent(event);
|
|
65
67
|
if (event.type === 'blocks-added') {
|
|
66
|
-
// Store mapping from slot to archive
|
|
68
|
+
// Store mapping from slot to archive, block number, and attestors
|
|
67
69
|
for (const block of event.blocks) {
|
|
68
|
-
this.
|
|
70
|
+
this.slotNumberToBlock.set(block.block.header.getSlot(), {
|
|
71
|
+
blockNumber: block.block.number,
|
|
72
|
+
archive: block.block.archive.root.toString(),
|
|
73
|
+
attestors: await Promise.all(getAttestationsFromPublishedL2Block(block).map(att => att.getSender())),
|
|
74
|
+
});
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
// Prune the archive map to only keep at most N entries
|
|
72
78
|
const historyLength = this.store.getHistoryLength();
|
|
73
|
-
if (this.
|
|
74
|
-
const toDelete = Array.from(this.
|
|
79
|
+
if (this.slotNumberToBlock.size > historyLength) {
|
|
80
|
+
const toDelete = Array.from(this.slotNumberToBlock.keys())
|
|
75
81
|
.sort((a, b) => Number(a - b))
|
|
76
|
-
.slice(0, this.
|
|
82
|
+
.slice(0, this.slotNumberToBlock.size - historyLength);
|
|
77
83
|
for (const key of toDelete) {
|
|
78
|
-
this.
|
|
84
|
+
this.slotNumberToBlock.delete(key);
|
|
79
85
|
}
|
|
80
86
|
}
|
|
81
87
|
}
|
|
@@ -171,16 +177,21 @@ export class Sentinel implements L2BlockStreamEventHandler {
|
|
|
171
177
|
|
|
172
178
|
// Here we get all attestations for the block mined at the given slot,
|
|
173
179
|
// or all attestations for all proposals in the slot if no block was mined.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const
|
|
180
|
+
// We gather from both p2p (contains the ones seen on the p2p layer) and archiver
|
|
181
|
+
// (contains the ones synced from mined blocks, which we may have missed from p2p).
|
|
182
|
+
const block = this.slotNumberToBlock.get(slot);
|
|
183
|
+
const p2pAttested = await this.p2p.getAttestationsForSlot(slot, block?.archive);
|
|
184
|
+
const attestors = new Set([
|
|
185
|
+
...(await Promise.all(p2pAttested.map(a => a.getSender().then(s => s.toString())))),
|
|
186
|
+
...(block?.attestors.map(a => a.toString()) ?? []),
|
|
187
|
+
]);
|
|
177
188
|
|
|
178
189
|
// We assume that there was a block proposal if at least one of the validators attested to it.
|
|
179
190
|
// It could be the case that every single validator failed, and we could differentiate it by having
|
|
180
191
|
// this node re-execute every block proposal it sees and storing it in the attestation pool.
|
|
181
192
|
// But we'll leave that corner case out to reduce pressure on the node.
|
|
182
|
-
const blockStatus =
|
|
183
|
-
this.logger.debug(`Block for slot ${slot} was ${blockStatus}`, {
|
|
193
|
+
const blockStatus = block ? 'mined' : attestors.size > 0 ? 'proposed' : 'missed';
|
|
194
|
+
this.logger.debug(`Block for slot ${slot} was ${blockStatus}`, { ...block, slot });
|
|
184
195
|
|
|
185
196
|
// Get attestors that failed their duties for this block, but only if there was a block proposed
|
|
186
197
|
const missedAttestors = new Set(
|
|
@@ -192,7 +203,7 @@ export class Sentinel implements L2BlockStreamEventHandler {
|
|
|
192
203
|
this.logger.debug(`Retrieved ${attestors.size} attestors out of ${committee.length} for slot ${slot}`, {
|
|
193
204
|
blockStatus,
|
|
194
205
|
proposer: proposer.toString(),
|
|
195
|
-
|
|
206
|
+
...block,
|
|
196
207
|
slot,
|
|
197
208
|
attestors: [...attestors],
|
|
198
209
|
missedAttestors: [...missedAttestors],
|