@aztec-labs/aztec-node 6.0.0 → 6.1.0-nightly.20261024
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/aztec-node/next_block/next_block_fee_cache.d.ts +1 -1
- package/dest/aztec-node/next_block/next_block_fee_cache.d.ts.map +1 -1
- package/dest/aztec-node/next_block/next_block_fee_cache.js +10 -0
- package/dest/aztec-node/server.d.ts +5 -2
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +14 -4
- package/dest/factory.d.ts +1 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +19 -12
- package/dest/sentinel/sentinel.d.ts +77 -11
- package/dest/sentinel/sentinel.d.ts.map +1 -1
- package/dest/sentinel/sentinel.js +200 -19
- package/dest/sentinel/store.d.ts +1 -1
- package/dest/sentinel/store.d.ts.map +1 -1
- package/dest/sentinel/store.js +8 -0
- package/package.json +27 -27
- package/src/aztec-node/next_block/next_block_fee_cache.ts +13 -0
- package/src/aztec-node/server.ts +22 -5
- package/src/factory.ts +17 -6
- package/src/sentinel/README.md +20 -4
- package/src/sentinel/sentinel.ts +257 -21
- package/src/sentinel/store.ts +8 -0
|
@@ -1,14 +1,27 @@
|
|
|
1
|
+
import { INITIAL_CHECKPOINT_NUMBER } from '@aztec-labs/constants';
|
|
1
2
|
import { requireStableCommittee } from '@aztec-labs/epoch-cache';
|
|
2
|
-
import { CheckpointProposalHash, EpochNumber, SlotNumber } from '@aztec-labs/foundation/branded-types';
|
|
3
|
+
import { CheckpointNumber, CheckpointProposalHash, EpochNumber, SlotNumber } from '@aztec-labs/foundation/branded-types';
|
|
3
4
|
import { countWhile, filterAsync, fromEntries, getEntries, mapValues } from '@aztec-labs/foundation/collection';
|
|
4
5
|
import { EthAddress } from '@aztec-labs/foundation/eth-address';
|
|
5
6
|
import { createLogger } from '@aztec-labs/foundation/log';
|
|
6
7
|
import { RunningPromise } from '@aztec-labs/foundation/running-promise';
|
|
7
8
|
import { OffenseType, WANT_TO_SLASH_EVENT, getOffenseTypeName } from '@aztec-labs/slasher';
|
|
8
9
|
import { getAttestationInfoFromPublishedCheckpoint } from '@aztec-labs/stdlib/block';
|
|
9
|
-
import { getEpochAtSlot, getSlotRangeForEpoch, getTimestampForSlot } from '@aztec-labs/stdlib/epoch-helpers';
|
|
10
|
+
import { computeQuorum, getEpochAtSlot, getSlotRangeForEpoch, getTimestampForSlot } from '@aztec-labs/stdlib/epoch-helpers';
|
|
10
11
|
import { ConsensusPayload } from '@aztec-labs/stdlib/p2p';
|
|
11
12
|
import EventEmitter from 'node:events';
|
|
13
|
+
const ORPHANED_PROPOSAL_REASON_DESCRIPTIONS = {
|
|
14
|
+
'parent-not-on-l1': 'the parent checkpoint it built on never landed on L1',
|
|
15
|
+
'parent-hash-mismatch': 'a different checkpoint landed on L1 in place of the parent it built on',
|
|
16
|
+
'unexpected-parent-appeared': 'a checkpoint from an earlier slot landed on L1 with its checkpoint number after it was built on the previous one'
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Whether the classification shows the proposal conflicts with a checkpoint that landed on L1, either in its parent's
|
|
20
|
+
* position or in its own. A validator that already held the landed checkpoint's blocks rejects the proposal's blocks as
|
|
21
|
+
* conflicting, so it is right not to attest.
|
|
22
|
+
*/ function excusesMissingAttestations(classification) {
|
|
23
|
+
return classification !== undefined && 'reason' in classification && (classification.reason === 'parent-hash-mismatch' || classification.reason === 'unexpected-parent-appeared');
|
|
24
|
+
}
|
|
12
25
|
/** Maps a validator status to its category: proposer or attestation. */ function statusToCategory(status) {
|
|
13
26
|
switch(status){
|
|
14
27
|
case 'attestation-sent':
|
|
@@ -47,12 +60,19 @@ import EventEmitter from 'node:events';
|
|
|
47
60
|
* ## Six-case taxonomy in `getSlotActivity`
|
|
48
61
|
*
|
|
49
62
|
* For each slot, the sentinel assigns the proposer one of six statuses, ranked highest-confidence
|
|
50
|
-
* first:
|
|
63
|
+
* first, with case 5 refined into 5a and 5b:
|
|
51
64
|
*
|
|
52
65
|
* - `checkpoint-mined` — a checkpoint covering this slot has landed on L1
|
|
53
66
|
* (fetched on demand via `archiver.getCheckpoint({ slot })`).
|
|
67
|
+
* - `checkpoint-unpublished` — (5a) a valid checkpoint proposal built on a parent that is on L1
|
|
68
|
+
* reached quorum, yet the proposer did not land it.
|
|
69
|
+
* - `checkpoint-orphaned` — (5b) a valid checkpoint proposal could not land because the parent
|
|
70
|
+
* it built on never reached L1 (the proposer pipelining cascade), or
|
|
71
|
+
* because an earlier slot's checkpoint landed with its number after it
|
|
72
|
+
* had built on the previous one.
|
|
54
73
|
* - `checkpoint-valid` — the local node re-executed a checkpoint proposal for this slot
|
|
55
|
-
* successfully (consulted via `CheckpointReexecutionTracker`)
|
|
74
|
+
* successfully (consulted via `CheckpointReexecutionTracker`), and it
|
|
75
|
+
* could not be refined into 5a or 5b.
|
|
56
76
|
* - `checkpoint-invalid` — the local node re-executed a checkpoint proposal for this slot
|
|
57
77
|
* and rejected it (e.g. header/archive/out-hash mismatch, limit
|
|
58
78
|
* breach). Proposer-fault.
|
|
@@ -62,9 +82,15 @@ import EventEmitter from 'node:events';
|
|
|
62
82
|
* - `checkpoint-missed` — block proposals seen on P2P but no checkpoint proposal at all.
|
|
63
83
|
* - `blocks-missed` — no block proposals seen for this slot.
|
|
64
84
|
*
|
|
65
|
-
* Missing-attestor faults are recorded only in `checkpoint-mined` and
|
|
66
|
-
*
|
|
67
|
-
*
|
|
85
|
+
* Missing-attestor faults are recorded only in `checkpoint-mined` and the three valid-proposal
|
|
86
|
+
* statuses (`checkpoint-unpublished`, `checkpoint-orphaned`, `checkpoint-valid`), where the local
|
|
87
|
+
* node has positive evidence the checkpoint was canonical or valid. In the other four cases the
|
|
88
|
+
* proposer is at fault and no attestor penalty applies. A valid proposal that conflicts with a checkpoint
|
|
89
|
+
* that landed on L1, in its parent's position or its own, is also exempt: a validator holding the landed
|
|
90
|
+
* checkpoint's blocks rightly refuses it.
|
|
91
|
+
*
|
|
92
|
+
* `checkpoint-unpublished` and `checkpoint-orphaned` are neutral for the proposer, like
|
|
93
|
+
* `checkpoint-valid`: neither counts toward `missedProposals` or inactivity slashing.
|
|
68
94
|
*
|
|
69
95
|
* ## Re-execution tracker
|
|
70
96
|
*
|
|
@@ -100,8 +126,13 @@ import EventEmitter from 'node:events';
|
|
|
100
126
|
initialSlot;
|
|
101
127
|
lastProcessedSlot;
|
|
102
128
|
/** Largest epoch number for which the end-of-epoch aggregator has run. */ lastEvaluatedEpoch;
|
|
129
|
+
/** Bumped on every history write so cached stats are never served from before the write. */ historyGeneration;
|
|
130
|
+
/**
|
|
131
|
+
* Stats for the default window, shared by every caller until the next processed slot or history write. Computing them
|
|
132
|
+
* scans and deserializes the full history of every validator, while the inputs only change once per slot.
|
|
133
|
+
*/ defaultStatsCache;
|
|
103
134
|
constructor(epochCache, archiver, p2p, store, reexecutionTracker, config, logger = createLogger('node:sentinel')){
|
|
104
|
-
super(), this.epochCache = epochCache, this.archiver = archiver, this.p2p = p2p, this.store = store, this.reexecutionTracker = reexecutionTracker, this.config = config, this.logger = logger;
|
|
135
|
+
super(), this.epochCache = epochCache, this.archiver = archiver, this.p2p = p2p, this.store = store, this.reexecutionTracker = reexecutionTracker, this.config = config, this.logger = logger, this.historyGeneration = 0;
|
|
105
136
|
const interval = epochCache.getL1Constants().ethereumSlotDuration * 1000 / 4;
|
|
106
137
|
this.runningPromise = new RunningPromise(this.work.bind(this), logger, interval);
|
|
107
138
|
}
|
|
@@ -391,8 +422,12 @@ import EventEmitter from 'node:events';
|
|
|
391
422
|
*
|
|
392
423
|
* Proposer status:
|
|
393
424
|
* - case 6 `checkpoint-mined` — a checkpoint covering this slot has landed on L1.
|
|
425
|
+
* - case 5a `checkpoint-unpublished` — a valid proposal with its parent on L1 reached quorum but
|
|
426
|
+
* was not landed by the proposer.
|
|
427
|
+
* - case 5b `checkpoint-orphaned` — a valid proposal could not land because its parent never
|
|
428
|
+
* reached L1, or because an earlier slot took its checkpoint number.
|
|
394
429
|
* - case 5 `checkpoint-valid` — the local node re-executed a checkpoint proposal for this
|
|
395
|
-
* slot successfully.
|
|
430
|
+
* slot successfully, and it could not be refined into 5a or 5b.
|
|
396
431
|
* - case 4 `checkpoint-invalid` — the local node re-executed a checkpoint proposal for this
|
|
397
432
|
* slot and rejected it.
|
|
398
433
|
* - case 3 `checkpoint-unvalidated` — the local node observed a checkpoint proposal for this
|
|
@@ -400,8 +435,9 @@ import EventEmitter from 'node:events';
|
|
|
400
435
|
* - case 2 `checkpoint-missed` — block proposals seen on P2P but no checkpoint proposal.
|
|
401
436
|
* - case 1 `blocks-missed` — no block proposals seen for this slot.
|
|
402
437
|
*
|
|
403
|
-
* Missing-attestor penalties apply only in cases 5 and 6, where the local
|
|
404
|
-
* evidence the checkpoint was valid or has been canonicalised on L1
|
|
438
|
+
* Missing-attestor penalties apply only in cases 5 (including 5a and 5b) and 6, where the local
|
|
439
|
+
* node has positive evidence the checkpoint was valid or has been canonicalised on L1, and never when
|
|
440
|
+
* the proposal conflicts with a checkpoint that landed in its parent's position or its own.
|
|
405
441
|
*/ async getSlotActivity(slot, epoch, proposer, committee) {
|
|
406
442
|
this.logger.debug(`Computing stats for slot ${slot} at epoch ${epoch}`, {
|
|
407
443
|
slot,
|
|
@@ -419,13 +455,16 @@ import EventEmitter from 'node:events';
|
|
|
419
455
|
...p2pAttestors.map((a)=>a.toString()),
|
|
420
456
|
...checkpoint?.attestors.map((a)=>a.toString()) ?? []
|
|
421
457
|
].filter((addr)=>proposer.toString() !== addr));
|
|
422
|
-
// Determine the proposer status from the six-case taxonomy.
|
|
458
|
+
// Determine the proposer status from the six-case taxonomy. A valid proposal that never reached L1 (case 5) is
|
|
459
|
+
// refined into `checkpoint-unpublished` (5a) or `checkpoint-orphaned` (5b) when the evidence allows it.
|
|
423
460
|
const reexecutionOutcome = this.reexecutionTracker.getOutcomeForSlot(slot);
|
|
424
461
|
let status;
|
|
462
|
+
let classification;
|
|
425
463
|
if (checkpoint) {
|
|
426
464
|
status = 'checkpoint-mined';
|
|
427
465
|
} else if (reexecutionOutcome === 'valid') {
|
|
428
|
-
|
|
466
|
+
classification = await this.classifyUnpublishedProposal(slot, proposer, committee, p2pAttested);
|
|
467
|
+
status = classification.status;
|
|
429
468
|
} else if (reexecutionOutcome === 'invalid') {
|
|
430
469
|
status = 'checkpoint-invalid';
|
|
431
470
|
} else if (reexecutionOutcome === 'unvalidated') {
|
|
@@ -444,9 +483,10 @@ import EventEmitter from 'node:events';
|
|
|
444
483
|
// A local `invalid` verdict vetoes them even for a mined checkpoint (an honest validator refuses
|
|
445
484
|
// to sign what it re-executed as invalid), and so does a proposal equivocation in the slot: with
|
|
446
485
|
// two conflicting proposals an honest attestor may have seen an invalid one and correctly
|
|
447
|
-
// declined, so neither must count as a missed attestor (inactivity slashing).
|
|
486
|
+
// declined, so neither must count as a missed attestor (inactivity slashing). Nor does a proposal that conflicts
|
|
487
|
+
// with a checkpoint that landed on L1 (see excusesMissingAttestations).
|
|
448
488
|
const hasEquivocation = this.reexecutionTracker.hasEquivocation(slot);
|
|
449
|
-
const attestorsExpected = (status === 'checkpoint-mined' || status === 'checkpoint-valid') && reexecutionOutcome !== 'invalid' && !hasEquivocation;
|
|
489
|
+
const attestorsExpected = (status === 'checkpoint-mined' || status === 'checkpoint-unpublished' || status === 'checkpoint-orphaned' || status === 'checkpoint-valid') && reexecutionOutcome !== 'invalid' && !hasEquivocation && !excusesMissingAttestations(classification);
|
|
450
490
|
const missedAttestors = new Set(attestorsExpected ? committee.filter((v)=>!attestors.has(v.toString()) && !proposer.equals(v)).map((v)=>v.toString()) : []);
|
|
451
491
|
this.logger.debug(`Retrieved ${attestors.size} attestors out of ${committee.length} for slot ${slot}`, {
|
|
452
492
|
status,
|
|
@@ -478,10 +518,151 @@ import EventEmitter from 'node:events';
|
|
|
478
518
|
statusFor(who)
|
|
479
519
|
]));
|
|
480
520
|
}
|
|
481
|
-
/**
|
|
482
|
-
|
|
521
|
+
/**
|
|
522
|
+
* Refines case 5 (a checkpoint proposal for the slot re-executed as valid, with no checkpoint for the slot on L1)
|
|
523
|
+
* into whose fault it was that the proposal did not land:
|
|
524
|
+
*
|
|
525
|
+
* - `checkpoint-orphaned` (5b) when other proposers prevented it: the parent it built on never landed on L1 (it is
|
|
526
|
+
* missing, or a different checkpoint holds the parent's position), or, with a quorum of attestations, an earlier
|
|
527
|
+
* slot's checkpoint landed with its number after it built on the previous one (`unexpected-parent-appeared`).
|
|
528
|
+
* The latter happens when the earlier slot's proposal reached this proposer too late to build on.
|
|
529
|
+
* - `checkpoint-unpublished` (5a) when its parent is on L1 and a quorum of the committee attested, so the proposer
|
|
530
|
+
* had everything it needed to publish. A later slot that lands the same checkpoint number does not exempt it:
|
|
531
|
+
* that slot only got the number because this proposer failed to land it.
|
|
532
|
+
* - `checkpoint-valid` (5) otherwise: the slot had an equivocation, the tracker has no parent or payload data to
|
|
533
|
+
* judge by, or attestations fell short of quorum. Short of quorum is a fault of the attestors, who are tagged
|
|
534
|
+
* `attestation-missed`, except after an unexpected parent appeared (`unexpected-parent-appeared`), when
|
|
535
|
+
* refusing to attest was correct.
|
|
536
|
+
*
|
|
537
|
+
* Only attestations for the proposal's own payload count toward quorum, since those are the only ones its proposer
|
|
538
|
+
* could have published.
|
|
539
|
+
*/ async classifyUnpublishedProposal(slot, proposer, committee, p2pAttested) {
|
|
540
|
+
if (this.reexecutionTracker.hasEquivocation(slot)) {
|
|
541
|
+
return {
|
|
542
|
+
status: 'checkpoint-valid',
|
|
543
|
+
reason: 'equivocation'
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
const record = this.reexecutionTracker.getRecordForSlot(slot);
|
|
547
|
+
const checkpointNumber = record?.checkpointNumber;
|
|
548
|
+
const lastArchiveRoot = record?.lastArchiveRoot;
|
|
549
|
+
const payloadHash = record?.payloadHash;
|
|
550
|
+
if (checkpointNumber === undefined || lastArchiveRoot === undefined || payloadHash === undefined) {
|
|
551
|
+
return {
|
|
552
|
+
status: 'checkpoint-valid',
|
|
553
|
+
reason: 'no-proposal-data'
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
const logData = {
|
|
557
|
+
slot,
|
|
558
|
+
proposer: proposer.toString(),
|
|
559
|
+
checkpointNumber
|
|
560
|
+
};
|
|
561
|
+
const orphaned = (reason, extra = {})=>{
|
|
562
|
+
this.logger.verbose(`Valid checkpoint proposal for slot ${slot} was orphaned (${reason}): ${ORPHANED_PROPOSAL_REASON_DESCRIPTIONS[reason]}`, {
|
|
563
|
+
...logData,
|
|
564
|
+
...extra,
|
|
565
|
+
reason
|
|
566
|
+
});
|
|
567
|
+
return {
|
|
568
|
+
status: 'checkpoint-orphaned',
|
|
569
|
+
reason
|
|
570
|
+
};
|
|
571
|
+
};
|
|
572
|
+
// The first checkpoint builds on genesis, which is always on L1.
|
|
573
|
+
const parentNumber = checkpointNumber - 1;
|
|
574
|
+
if (parentNumber >= INITIAL_CHECKPOINT_NUMBER) {
|
|
575
|
+
const parent = await this.archiver.getCheckpointData({
|
|
576
|
+
number: CheckpointNumber(parentNumber)
|
|
577
|
+
});
|
|
578
|
+
if (!parent) {
|
|
579
|
+
return orphaned('parent-not-on-l1');
|
|
580
|
+
}
|
|
581
|
+
if (parent.archive.root.toString() !== lastArchiveRoot) {
|
|
582
|
+
return orphaned('parent-hash-mismatch');
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
// The proposer's own attestation counts, as it does when its sequencer collects attestations for L1.
|
|
586
|
+
const committeeMembers = new Set(committee.map((member)=>member.toString()));
|
|
587
|
+
const attestationCount = new Set(p2pAttested.filter((attestation)=>attestation.getPayloadHash() === payloadHash).map((attestation)=>attestation.getSender()?.toString()).filter((attestor)=>attestor !== undefined && committeeMembers.has(attestor))).size;
|
|
588
|
+
const quorum = computeQuorum(committee.length);
|
|
589
|
+
// A checkpoint landed for the slot itself would have made this case 6, so a holder of the same number comes from
|
|
590
|
+
// an earlier or a later slot. Only an earlier one can have stopped this proposal from landing.
|
|
591
|
+
const sameNumber = await this.archiver.getCheckpointData({
|
|
592
|
+
number: checkpointNumber
|
|
593
|
+
});
|
|
594
|
+
const sameNumberSlot = sameNumber?.header.slotNumber;
|
|
595
|
+
if (sameNumberSlot !== undefined && sameNumberSlot < slot) {
|
|
596
|
+
const conflictData = {
|
|
597
|
+
takenBySlot: sameNumberSlot,
|
|
598
|
+
attestationCount,
|
|
599
|
+
quorum
|
|
600
|
+
};
|
|
601
|
+
if (attestationCount < quorum) {
|
|
602
|
+
this.logger.verbose(`Valid checkpoint proposal for slot ${slot} fell short of quorum after checkpoint ${checkpointNumber} landed ` + `from earlier slot ${sameNumberSlot} (unexpected-parent-appeared), so missing attestations are not counted`, {
|
|
603
|
+
...logData,
|
|
604
|
+
...conflictData,
|
|
605
|
+
reason: 'unexpected-parent-appeared'
|
|
606
|
+
});
|
|
607
|
+
return {
|
|
608
|
+
status: 'checkpoint-valid',
|
|
609
|
+
reason: 'unexpected-parent-appeared'
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
return orphaned('unexpected-parent-appeared', conflictData);
|
|
613
|
+
}
|
|
614
|
+
if (attestationCount < quorum) {
|
|
615
|
+
return {
|
|
616
|
+
status: 'checkpoint-valid',
|
|
617
|
+
reason: 'below-quorum'
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
this.logger.info(`Proposer did not publish checkpoint ${checkpointNumber} for slot ${slot} despite quorum`, {
|
|
621
|
+
...logData,
|
|
622
|
+
attestationCount,
|
|
623
|
+
quorum
|
|
624
|
+
});
|
|
625
|
+
return {
|
|
626
|
+
status: 'checkpoint-unpublished'
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
/** Push the status for each slot for each validator. */ async updateValidators(slot, stats) {
|
|
630
|
+
this.historyGeneration++;
|
|
631
|
+
try {
|
|
632
|
+
await this.store.updateValidators(slot, stats);
|
|
633
|
+
} finally{
|
|
634
|
+
this.historyGeneration++;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Computes stats to be returned based on stored data. Calls without arguments cover the default window ending at the
|
|
639
|
+
* last processed slot and are served from a cache that is refreshed whenever that slot or the stored history changes.
|
|
640
|
+
*/ computeStats(args = {}) {
|
|
641
|
+
const isDefaultWindow = args.fromSlot === undefined && args.toSlot === undefined && args.validators === undefined;
|
|
642
|
+
// Before the first processed slot the default window ends at the wall-clock slot, which moves without any write.
|
|
643
|
+
if (!isDefaultWindow || this.lastProcessedSlot === undefined) {
|
|
644
|
+
return this.computeStatsUncached(args);
|
|
645
|
+
}
|
|
646
|
+
const { lastProcessedSlot, initialSlot, historyGeneration } = this;
|
|
647
|
+
if (this.defaultStatsCache?.lastProcessedSlot !== lastProcessedSlot || this.defaultStatsCache.initialSlot !== initialSlot || this.defaultStatsCache.historyGeneration !== historyGeneration) {
|
|
648
|
+
const stats = this.computeStatsUncached(args);
|
|
649
|
+
const entry = {
|
|
650
|
+
lastProcessedSlot,
|
|
651
|
+
initialSlot,
|
|
652
|
+
historyGeneration,
|
|
653
|
+
stats
|
|
654
|
+
};
|
|
655
|
+
this.defaultStatsCache = entry;
|
|
656
|
+
// A failed computation is dropped so the next caller retries instead of receiving the cached rejection.
|
|
657
|
+
stats.catch(()=>{
|
|
658
|
+
if (this.defaultStatsCache === entry) {
|
|
659
|
+
this.defaultStatsCache = undefined;
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
return this.defaultStatsCache.stats;
|
|
483
664
|
}
|
|
484
|
-
|
|
665
|
+
async computeStatsUncached({ fromSlot, toSlot, validators }) {
|
|
485
666
|
const histories = validators ? fromEntries(await Promise.all(validators.map(async (v)=>[
|
|
486
667
|
v.toString(),
|
|
487
668
|
await this.store.getHistory(v)
|
|
@@ -551,7 +732,7 @@ import EventEmitter from 'node:events';
|
|
|
551
732
|
computeStatsForValidator(address, allHistory, fromSlot, toSlot) {
|
|
552
733
|
let history = fromSlot ? allHistory.filter((h)=>BigInt(h.slot) >= fromSlot) : allHistory;
|
|
553
734
|
history = toSlot ? history.filter((h)=>BigInt(h.slot) <= toSlot) : history;
|
|
554
|
-
const lastProposal = history.filter((h)=>h.status === 'checkpoint-valid' || h.status === 'checkpoint-mined').at(-1);
|
|
735
|
+
const lastProposal = history.filter((h)=>h.status === 'checkpoint-valid' || h.status === 'checkpoint-unpublished' || h.status === 'checkpoint-orphaned' || h.status === 'checkpoint-mined').at(-1);
|
|
555
736
|
const lastAttestation = history.filter((h)=>h.status === 'attestation-sent').at(-1);
|
|
556
737
|
return {
|
|
557
738
|
address: EthAddress.fromString(address),
|
package/dest/sentinel/store.d.ts
CHANGED
|
@@ -40,4 +40,4 @@ export declare class SentinelStore {
|
|
|
40
40
|
private statusToNumber;
|
|
41
41
|
private statusFromNumber;
|
|
42
42
|
}
|
|
43
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
43
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmUuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZW50aW5lbC9zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBQy9FLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUVoRSxPQUFPLEtBQUssRUFBRSxpQkFBaUIsRUFBaUIsTUFBTSxzQkFBc0IsQ0FBQztBQUM3RSxPQUFPLEtBQUssRUFDVixzQkFBc0IsRUFDdEIscUJBQXFCLEVBQ3JCLDBCQUEwQixFQUMzQixNQUFNLCtCQUErQixDQUFDO0FBRXZDLHFCQUFhLGFBQWE7SUFXdEIsT0FBTyxDQUFDLEtBQUs7SUFDYixPQUFPLENBQUMsTUFBTTtJQVhoQixnQkFBdUIsY0FBYyxLQUFLO0lBRzFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUF1QztJQUlsRSxPQUFPLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBdUM7SUFFaEUsWUFDVSxLQUFLLEVBQUUsaUJBQWlCLEVBQ3hCLE1BQU0sRUFBRTtRQUFFLGFBQWEsRUFBRSxNQUFNLENBQUM7UUFBQyw4QkFBOEIsRUFBRSxNQUFNLENBQUE7S0FBRSxFQUlsRjtJQUVNLGdCQUFnQixXQUV0QjtJQUVNLGlDQUFpQyxXQUV2QztJQUVZLHNCQUFzQixDQUFDLEtBQUssRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFFLDBCQUEwQixpQkFNOUY7SUFFWSxtQkFBbUIsQ0FBQyxHQUFHLEVBQUUsVUFBVSxHQUFHLE9BQU8sQ0FBQztRQUFFLE1BQU0sRUFBRSxNQUFNLENBQUM7UUFBQyxLQUFLLEVBQUUsTUFBTSxDQUFDO1FBQUMsS0FBSyxFQUFFLFdBQVcsQ0FBQTtLQUFFLEVBQUUsQ0FBQyxDQUdsSDtJQUVELDhHQUE4RztJQUNqRyx3QkFBd0IsQ0FDbkMsU0FBUyxFQUFFLFVBQVUsRUFBRSxHQUN0QixPQUFPLENBQUM7UUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDO1FBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQztRQUFDLEtBQUssRUFBRSxXQUFXLENBQUE7S0FBRSxFQUFFLEVBQUUsQ0FBQyxDQUdwRTtZQUVhLDZCQUE2QjtJQTZCOUIsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLEtBQUssTUFBTSxFQUFFLEVBQUUscUJBQXFCLEdBQUcsU0FBUyxDQUFDLGlCQVFqSDtZQUVhLDBCQUEwQjtJQVEzQixZQUFZLElBQUksT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLE1BQU0sRUFBRSxFQUFFLHNCQUFzQixDQUFDLENBQUMsQ0FNbEY7SUFFWSxVQUFVLENBQUMsT0FBTyxFQUFFLFVBQVUsR0FBRyxPQUFPLENBQUMsc0JBQXNCLEdBQUcsU0FBUyxDQUFDLENBR3hGO0lBRUQsMEZBQTBGO0lBQzdFLGVBQWUsQ0FBQyxTQUFTLEVBQUUsVUFBVSxFQUFFLEdBQUcsT0FBTyxDQUFDLENBQUMsc0JBQXNCLEdBQUcsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUdyRztJQUVELE9BQU8sQ0FBQyxvQkFBb0I7SUFNNUIsT0FBTyxDQUFDLHNCQUFzQjtJQWE5QixPQUFPLENBQUMsZ0JBQWdCO0lBTXhCLE9BQU8sQ0FBQyxrQkFBa0I7SUFXMUIsT0FBTyxDQUFDLGNBQWM7SUE2QnRCLE9BQU8sQ0FBQyxnQkFBZ0I7Q0EwQnpCIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/sentinel/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAEhE,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EACrB,0BAA0B,EAC3B,MAAM,+BAA+B,CAAC;AAEvC,qBAAa,aAAa;IAWtB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IAXhB,gBAAuB,cAAc,KAAK;IAG1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuC;IAIlE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;IAEhE,YACU,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,8BAA8B,EAAE,MAAM,CAAA;KAAE,EAIlF;IAEM,gBAAgB,WAEtB;IAEM,iCAAiC,WAEvC;IAEY,sBAAsB,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,0BAA0B,iBAM9F;IAEY,mBAAmB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,EAAE,CAAC,CAGlH;IAED,8GAA8G;IACjG,wBAAwB,CACnC,SAAS,EAAE,UAAU,EAAE,GACtB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,EAAE,EAAE,CAAC,CAGpE;YAEa,6BAA6B;IA6B9B,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,qBAAqB,GAAG,SAAS,CAAC,iBAQjH;YAEa,0BAA0B;IAQ3B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAMlF;IAEY,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC,CAGxF;IAED,0FAA0F;IAC7E,eAAe,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,CAAC,sBAAsB,GAAG,SAAS,CAAC,EAAE,CAAC,CAGrG;IAED,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,sBAAsB;IAa9B,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/sentinel/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAEhE,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EACrB,0BAA0B,EAC3B,MAAM,+BAA+B,CAAC;AAEvC,qBAAa,aAAa;IAWtB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IAXhB,gBAAuB,cAAc,KAAK;IAG1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuC;IAIlE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;IAEhE,YACU,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,8BAA8B,EAAE,MAAM,CAAA;KAAE,EAIlF;IAEM,gBAAgB,WAEtB;IAEM,iCAAiC,WAEvC;IAEY,sBAAsB,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,0BAA0B,iBAM9F;IAEY,mBAAmB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,EAAE,CAAC,CAGlH;IAED,8GAA8G;IACjG,wBAAwB,CACnC,SAAS,EAAE,UAAU,EAAE,GACtB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,EAAE,EAAE,CAAC,CAGpE;YAEa,6BAA6B;IA6B9B,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,qBAAqB,GAAG,SAAS,CAAC,iBAQjH;YAEa,0BAA0B;IAQ3B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAMlF;IAEY,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC,CAGxF;IAED,0FAA0F;IAC7E,eAAe,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,CAAC,sBAAsB,GAAG,SAAS,CAAC,EAAE,CAAC,CAGrG;IAED,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,sBAAsB;IAa9B,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,cAAc;IA6BtB,OAAO,CAAC,gBAAgB;CA0BzB"}
|
package/dest/sentinel/store.js
CHANGED
|
@@ -158,6 +158,10 @@ export class SentinelStore {
|
|
|
158
158
|
return 7;
|
|
159
159
|
case 'checkpoint-unvalidated':
|
|
160
160
|
return 8;
|
|
161
|
+
case 'checkpoint-unpublished':
|
|
162
|
+
return 9;
|
|
163
|
+
case 'checkpoint-orphaned':
|
|
164
|
+
return 10;
|
|
161
165
|
default:
|
|
162
166
|
{
|
|
163
167
|
const _exhaustive = status;
|
|
@@ -183,6 +187,10 @@ export class SentinelStore {
|
|
|
183
187
|
return 'checkpoint-invalid';
|
|
184
188
|
case 8:
|
|
185
189
|
return 'checkpoint-unvalidated';
|
|
190
|
+
case 9:
|
|
191
|
+
return 'checkpoint-unpublished';
|
|
192
|
+
case 10:
|
|
193
|
+
return 'checkpoint-orphaned';
|
|
186
194
|
default:
|
|
187
195
|
throw new Error(`Unknown status: ${status}`);
|
|
188
196
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec-labs/aztec-node",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.1.0-nightly.20261024",
|
|
4
4
|
"main": "dest/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -65,38 +65,38 @@
|
|
|
65
65
|
]
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@aztec-foundation/bb.js": "6.0.0",
|
|
69
|
-
"@aztec-labs/archiver": "6.0.
|
|
70
|
-
"@aztec-labs/bb-prover": "6.0.
|
|
71
|
-
"@aztec-labs/blob-client": "6.0.
|
|
72
|
-
"@aztec-labs/blob-lib": "6.0.
|
|
73
|
-
"@aztec-labs/constants": "6.0.
|
|
74
|
-
"@aztec-labs/epoch-cache": "6.0.
|
|
75
|
-
"@aztec-labs/ethereum": "6.0.
|
|
76
|
-
"@aztec-labs/foundation": "6.0.
|
|
77
|
-
"@aztec-labs/kv-store": "6.0.
|
|
78
|
-
"@aztec-labs/node-keystore": "6.0.
|
|
79
|
-
"@aztec-labs/node-lib": "6.0.
|
|
80
|
-
"@aztec-labs/p2p": "6.0.
|
|
81
|
-
"@aztec-labs/protocol-contracts": "6.0.
|
|
82
|
-
"@aztec-labs/prover-client": "6.0.
|
|
83
|
-
"@aztec-labs/prover-node": "6.0.
|
|
84
|
-
"@aztec-labs/sequencer-client": "6.0.
|
|
85
|
-
"@aztec-labs/simulator": "6.0.
|
|
86
|
-
"@aztec-labs/slasher": "6.0.
|
|
87
|
-
"@aztec-labs/standard-contracts": "6.0.
|
|
88
|
-
"@aztec-labs/stdlib": "6.0.
|
|
89
|
-
"@aztec-labs/telemetry-client": "6.0.
|
|
90
|
-
"@aztec-labs/validator-client": "6.0.
|
|
91
|
-
"@aztec-labs/validator-ha-signer": "6.0.
|
|
92
|
-
"@aztec-labs/world-state": "6.0.
|
|
68
|
+
"@aztec-foundation/bb.js": "6.0.0-rc.7",
|
|
69
|
+
"@aztec-labs/archiver": "6.1.0-nightly.20261024",
|
|
70
|
+
"@aztec-labs/bb-prover": "6.1.0-nightly.20261024",
|
|
71
|
+
"@aztec-labs/blob-client": "6.1.0-nightly.20261024",
|
|
72
|
+
"@aztec-labs/blob-lib": "6.1.0-nightly.20261024",
|
|
73
|
+
"@aztec-labs/constants": "6.1.0-nightly.20261024",
|
|
74
|
+
"@aztec-labs/epoch-cache": "6.1.0-nightly.20261024",
|
|
75
|
+
"@aztec-labs/ethereum": "6.1.0-nightly.20261024",
|
|
76
|
+
"@aztec-labs/foundation": "6.1.0-nightly.20261024",
|
|
77
|
+
"@aztec-labs/kv-store": "6.1.0-nightly.20261024",
|
|
78
|
+
"@aztec-labs/node-keystore": "6.1.0-nightly.20261024",
|
|
79
|
+
"@aztec-labs/node-lib": "6.1.0-nightly.20261024",
|
|
80
|
+
"@aztec-labs/p2p": "6.1.0-nightly.20261024",
|
|
81
|
+
"@aztec-labs/protocol-contracts": "6.1.0-nightly.20261024",
|
|
82
|
+
"@aztec-labs/prover-client": "6.1.0-nightly.20261024",
|
|
83
|
+
"@aztec-labs/prover-node": "6.1.0-nightly.20261024",
|
|
84
|
+
"@aztec-labs/sequencer-client": "6.1.0-nightly.20261024",
|
|
85
|
+
"@aztec-labs/simulator": "6.1.0-nightly.20261024",
|
|
86
|
+
"@aztec-labs/slasher": "6.1.0-nightly.20261024",
|
|
87
|
+
"@aztec-labs/standard-contracts": "6.1.0-nightly.20261024",
|
|
88
|
+
"@aztec-labs/stdlib": "6.1.0-nightly.20261024",
|
|
89
|
+
"@aztec-labs/telemetry-client": "6.1.0-nightly.20261024",
|
|
90
|
+
"@aztec-labs/validator-client": "6.1.0-nightly.20261024",
|
|
91
|
+
"@aztec-labs/validator-ha-signer": "6.1.0-nightly.20261024",
|
|
92
|
+
"@aztec-labs/world-state": "6.1.0-nightly.20261024",
|
|
93
93
|
"koa": "^2.16.1",
|
|
94
94
|
"koa-router": "^13.1.1",
|
|
95
95
|
"tslib": "^2.4.0",
|
|
96
96
|
"viem": "2.57.1"
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|
|
99
|
-
"@aztec-labs/noir-protocol-circuits-types": "6.0.
|
|
99
|
+
"@aztec-labs/noir-protocol-circuits-types": "6.1.0-nightly.20261024",
|
|
100
100
|
"@jest/globals": "^30.0.0",
|
|
101
101
|
"@types/jest": "^30.0.0",
|
|
102
102
|
"@types/node": "^22.15.17",
|
|
@@ -275,6 +275,17 @@ export class NextBlockFeeCache {
|
|
|
275
275
|
return pinnedTips();
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
// The plan's L1 reads are pinned to the archiver's sync point, which only exists once the archiver has run a
|
|
279
|
+
// sync pass. Until then there is no L1 block to read the parent's fee header at, so price on the checkpointed tip,
|
|
280
|
+
// as the fee simulation itself falls back to L1's head.
|
|
281
|
+
const l1SyncPoint = frontier.l1SyncPoint;
|
|
282
|
+
if (l1SyncPoint === undefined) {
|
|
283
|
+
this.log.debug(
|
|
284
|
+
`Pricing the next-block boundary on checkpointed tip ${checkpointedCheckpointNumber}: no L1 sync point yet`,
|
|
285
|
+
);
|
|
286
|
+
return pinnedTips();
|
|
287
|
+
}
|
|
288
|
+
|
|
278
289
|
// The helper treats pipelining and invalidation as mutually exclusive; a proposed parent takes precedence.
|
|
279
290
|
const validationStatus = frontier.pendingChainValidationStatus;
|
|
280
291
|
const invalidateToPendingCheckpointNumber =
|
|
@@ -287,6 +298,8 @@ export class NextBlockFeeCache {
|
|
|
287
298
|
invalidateToPendingCheckpointNumber,
|
|
288
299
|
checkpointedCheckpointNumber,
|
|
289
300
|
rollup,
|
|
301
|
+
// The same L1 block the fee simulation is pinned to, so the parent's fee header and the fee agree.
|
|
302
|
+
l1BlockNumber: l1SyncPoint.blockNumber,
|
|
290
303
|
signatureContext: this.signatureContext,
|
|
291
304
|
log: this.log,
|
|
292
305
|
});
|
package/src/aztec-node/server.ts
CHANGED
|
@@ -54,7 +54,12 @@ import type {
|
|
|
54
54
|
ProtocolContractAddresses,
|
|
55
55
|
} from '@aztec-labs/stdlib/contract';
|
|
56
56
|
import type { L1RollupConstants } from '@aztec-labs/stdlib/epoch-helpers';
|
|
57
|
-
import {
|
|
57
|
+
import {
|
|
58
|
+
GasFees,
|
|
59
|
+
type ManaUsageEstimate,
|
|
60
|
+
type RollupFeeConfigProvider,
|
|
61
|
+
getNetworkTxGasLimits,
|
|
62
|
+
} from '@aztec-labs/stdlib/gas';
|
|
58
63
|
import type {
|
|
59
64
|
AztecNode,
|
|
60
65
|
AztecNodeAdmin,
|
|
@@ -146,6 +151,8 @@ export interface AztecNodeServiceDeps {
|
|
|
146
151
|
rollupContract: RollupContract | undefined;
|
|
147
152
|
feeProvider: FeeProvider;
|
|
148
153
|
nextBlockPredictor: NextBlockPredictor;
|
|
154
|
+
/** Live rollup fee settings, for the mana limit tx gas limits are derived from. Stopped with the node. */
|
|
155
|
+
feeConfigProvider: RollupFeeConfigProvider;
|
|
149
156
|
epochCache: EpochCacheInterface;
|
|
150
157
|
packageVersion: string;
|
|
151
158
|
peerProofVerifier: ClientProtocolCircuitVerifier;
|
|
@@ -199,6 +206,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
199
206
|
protected readonly rollupContract: RollupContract | undefined;
|
|
200
207
|
protected readonly feeProvider: FeeProvider;
|
|
201
208
|
protected readonly nextBlockPredictor: NextBlockPredictor;
|
|
209
|
+
protected readonly feeConfigProvider: RollupFeeConfigProvider;
|
|
202
210
|
protected readonly epochCache: EpochCacheInterface;
|
|
203
211
|
protected readonly packageVersion: string;
|
|
204
212
|
private peerProofVerifier: ClientProtocolCircuitVerifier;
|
|
@@ -231,6 +239,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
231
239
|
this.rollupContract = deps.rollupContract;
|
|
232
240
|
this.feeProvider = deps.feeProvider;
|
|
233
241
|
this.nextBlockPredictor = deps.nextBlockPredictor;
|
|
242
|
+
this.feeConfigProvider = deps.feeConfigProvider;
|
|
234
243
|
this.epochCache = deps.epochCache;
|
|
235
244
|
this.packageVersion = deps.packageVersion;
|
|
236
245
|
this.peerProofVerifier = deps.peerProofVerifier;
|
|
@@ -313,8 +322,15 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
313
322
|
return this.blockSource.getL2Tips();
|
|
314
323
|
}
|
|
315
324
|
|
|
316
|
-
public getL1Constants(): Promise<L1RollupConstants> {
|
|
317
|
-
|
|
325
|
+
public async getL1Constants(): Promise<L1RollupConstants> {
|
|
326
|
+
const constants = await this.blockSource.getL1Constants();
|
|
327
|
+
// Older clients' schemas still require `rollupManaLimit`, so keep sending it, now with the live value. Newer
|
|
328
|
+
// clients' schemas strip the extra key.
|
|
329
|
+
const response: L1RollupConstants & { rollupManaLimit: number } = {
|
|
330
|
+
...constants,
|
|
331
|
+
rollupManaLimit: Number(this.feeConfigProvider.getFeeConfig().manaLimit),
|
|
332
|
+
};
|
|
333
|
+
return response;
|
|
318
334
|
}
|
|
319
335
|
|
|
320
336
|
public getSyncedL2SlotNumber() {
|
|
@@ -465,7 +481,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
465
481
|
// timetable's blocks-per-checkpoint and the network-minimum per-block multipliers) — never this node's
|
|
466
482
|
// local caps or configured multipliers, which can make the node stricter at block-building time but
|
|
467
483
|
// cannot define what the network accepts for relay. Clients read txsLimits to set fallback gas limits.
|
|
468
|
-
const maxTxGas = getNetworkTxGasLimits(this.config, l1Constants);
|
|
484
|
+
const maxTxGas = getNetworkTxGasLimits(this.config, l1Constants, this.feeConfigProvider.getFeeConfig());
|
|
469
485
|
|
|
470
486
|
const nodeInfo: NodeInfo = {
|
|
471
487
|
nodeVersion,
|
|
@@ -632,6 +648,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
632
648
|
await tryStop(this.p2pClient);
|
|
633
649
|
await tryStop(this.nextBlockPredictor);
|
|
634
650
|
await tryStop(this.feeProvider);
|
|
651
|
+
await tryStop(this.feeConfigProvider);
|
|
635
652
|
// Dispose the AVM backend before world state: it kills the bb-avm-sim processes and closes the CDB IPC
|
|
636
653
|
// server, releasing their connections to the WSDB so it shuts down cleanly (and freeing the
|
|
637
654
|
// Server/Socket/ChildProcess handles that would otherwise keep the process alive after teardown).
|
|
@@ -827,7 +844,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
827
844
|
const l1Constants = await this.blockSource.getL1Constants();
|
|
828
845
|
// Enforce the same network admission limit the node advertises in getNodeInfo (network-wide, not this
|
|
829
846
|
// node's local caps), so a tx the wallet sized against txsLimits is not rejected here.
|
|
830
|
-
const networkTxGasLimits = getNetworkTxGasLimits(this.config, l1Constants);
|
|
847
|
+
const networkTxGasLimits = getNetworkTxGasLimits(this.config, l1Constants, this.feeConfigProvider.getFeeConfig());
|
|
831
848
|
const validator = createTxValidatorForAcceptingTxsOverRPC(
|
|
832
849
|
db,
|
|
833
850
|
this.contractDataSource,
|
package/src/factory.ts
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
createSlasher,
|
|
40
40
|
} from '@aztec-labs/slasher';
|
|
41
41
|
import { CheckpointReexecutionTracker } from '@aztec-labs/stdlib/checkpoint';
|
|
42
|
+
import { RollupFeeConfigTracker } from '@aztec-labs/stdlib/gas';
|
|
42
43
|
import { type ClientProtocolCircuitVerifier, tryStop } from '@aztec-labs/stdlib/interfaces/server';
|
|
43
44
|
import { type DebugLogStore, InMemoryDebugLogStore, NullDebugLogStore } from '@aztec-labs/stdlib/logs';
|
|
44
45
|
import { getPackageVersion } from '@aztec-labs/stdlib/update-checker';
|
|
@@ -185,12 +186,11 @@ export async function createAztecNodeService(
|
|
|
185
186
|
// Read-only Inbox handle: proposal validation confirms a checkpoint's final message position against the live
|
|
186
187
|
// bucket ring before accepting it, so every node needs one, validator or not.
|
|
187
188
|
const inboxContract = new InboxContract(publicClient, config.inboxAddress);
|
|
188
|
-
const [l1GenesisTime, slotDuration, epochDuration, rollupVersionFromRollup
|
|
189
|
+
const [l1GenesisTime, slotDuration, epochDuration, rollupVersionFromRollup] = await Promise.all([
|
|
189
190
|
rollupContract.getL1GenesisTime(),
|
|
190
191
|
rollupContract.getSlotDuration(),
|
|
191
192
|
rollupContract.getEpochDuration(),
|
|
192
193
|
rollupContract.getVersion(),
|
|
193
|
-
rollupContract.getManaLimit().then(Number),
|
|
194
194
|
] as const);
|
|
195
195
|
|
|
196
196
|
config.rollupVersion ??= Number(rollupVersionFromRollup);
|
|
@@ -211,6 +211,14 @@ export async function createAztecNodeService(
|
|
|
211
211
|
// Track started resources so we can clean up on partial failure during node creation.
|
|
212
212
|
const started: { stop?(): Promise<void> | void }[] = [];
|
|
213
213
|
try {
|
|
214
|
+
// Governance can change the rollup's fee settings (the mana target and limit among them) at any time, so every
|
|
215
|
+
// component that needs them reads them from this tracker rather than from a copy taken at startup.
|
|
216
|
+
const feeConfigTracker = await RollupFeeConfigTracker.create(rollupContract, {
|
|
217
|
+
logger: log.createChild('rollup-fee-config'),
|
|
218
|
+
});
|
|
219
|
+
feeConfigTracker.start();
|
|
220
|
+
started.push(feeConfigTracker);
|
|
221
|
+
|
|
214
222
|
config.skipOrphanProposedBlockPruning ||= !!config.useAutomineSequencer;
|
|
215
223
|
|
|
216
224
|
checkConfigMatchesRollup(config, {
|
|
@@ -234,7 +242,7 @@ export async function createAztecNodeService(
|
|
|
234
242
|
started.push({ stop: () => avmSimulator[Symbol.asyncDispose]() });
|
|
235
243
|
const archiver = await createArchiver(
|
|
236
244
|
config,
|
|
237
|
-
{ blobClient, epochCache, telemetry, dateProvider },
|
|
245
|
+
{ blobClient, epochCache, telemetry, dateProvider, feeConfigProvider: feeConfigTracker },
|
|
238
246
|
{ blockUntilSync: !config.skipArchiverInitialSync },
|
|
239
247
|
initialHeader,
|
|
240
248
|
initialBlockHash,
|
|
@@ -321,6 +329,7 @@ export async function createAztecNodeService(
|
|
|
321
329
|
worldStateSynchronizer,
|
|
322
330
|
epochCache,
|
|
323
331
|
new AdmissionMinFeesProvider(nextBlockPredictor, feeProvider),
|
|
332
|
+
feeConfigTracker,
|
|
324
333
|
packageVersion,
|
|
325
334
|
dateProvider,
|
|
326
335
|
telemetry,
|
|
@@ -340,13 +349,13 @@ export async function createAztecNodeService(
|
|
|
340
349
|
...config,
|
|
341
350
|
l1GenesisTime,
|
|
342
351
|
slotDuration: Number(slotDuration),
|
|
343
|
-
rollupManaLimit,
|
|
344
352
|
maxTxsPerCheckpoint: config.validateMaxTxsPerCheckpoint,
|
|
345
353
|
},
|
|
346
354
|
worldStateSynchronizer,
|
|
347
355
|
archiver,
|
|
348
356
|
dateProvider,
|
|
349
357
|
avmSimulator,
|
|
358
|
+
feeConfigTracker,
|
|
350
359
|
telemetry,
|
|
351
360
|
);
|
|
352
361
|
|
|
@@ -563,11 +572,12 @@ export async function createAztecNodeService(
|
|
|
563
572
|
|
|
564
573
|
// Create and start the sequencer client
|
|
565
574
|
const checkpointsBuilder = new CheckpointsBuilder(
|
|
566
|
-
{ ...config, l1GenesisTime, slotDuration: Number(slotDuration)
|
|
575
|
+
{ ...config, l1GenesisTime, slotDuration: Number(slotDuration) },
|
|
567
576
|
worldStateSynchronizer,
|
|
568
577
|
archiver,
|
|
569
578
|
dateProvider,
|
|
570
579
|
avmSimulator,
|
|
580
|
+
feeConfigTracker,
|
|
571
581
|
telemetry,
|
|
572
582
|
debugLogStore,
|
|
573
583
|
);
|
|
@@ -596,7 +606,6 @@ export async function createAztecNodeService(
|
|
|
596
606
|
l1GenesisTime,
|
|
597
607
|
slotDuration: Number(slotDuration),
|
|
598
608
|
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
599
|
-
rollupManaLimit,
|
|
600
609
|
},
|
|
601
610
|
autoSettle: config.automineEnableProveEpoch,
|
|
602
611
|
log,
|
|
@@ -612,6 +621,7 @@ export async function createAztecNodeService(
|
|
|
612
621
|
worldStateSynchronizer,
|
|
613
622
|
slasherClient,
|
|
614
623
|
checkpointsBuilder,
|
|
624
|
+
feeConfigProvider: feeConfigTracker,
|
|
615
625
|
l2BlockSource: archiver,
|
|
616
626
|
l1ToL2MessageSource: archiver,
|
|
617
627
|
telemetry,
|
|
@@ -683,6 +693,7 @@ export async function createAztecNodeService(
|
|
|
683
693
|
rollupContract,
|
|
684
694
|
feeProvider,
|
|
685
695
|
nextBlockPredictor,
|
|
696
|
+
feeConfigProvider: feeConfigTracker,
|
|
686
697
|
epochCache,
|
|
687
698
|
packageVersion,
|
|
688
699
|
peerProofVerifier,
|