@aztec/stdlib 5.0.0-nightly.20260409 → 5.0.0-nightly.20260411
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/config/sequencer-config.d.ts +2 -2
- package/dest/config/sequencer-config.d.ts.map +1 -1
- package/dest/config/sequencer-config.js +7 -0
- package/dest/gas/gas_fees.d.ts +1 -1
- package/dest/gas/gas_fees.d.ts.map +1 -1
- package/dest/gas/gas_fees.js +10 -1
- package/dest/interfaces/aztec-node-admin.d.ts +3 -11
- package/dest/interfaces/aztec-node-admin.d.ts.map +1 -1
- package/dest/interfaces/aztec-node-admin.js +1 -2
- package/dest/interfaces/aztec-node-debug.d.ts +21 -0
- package/dest/interfaces/aztec-node-debug.d.ts.map +1 -0
- package/dest/interfaces/aztec-node-debug.js +18 -0
- package/dest/interfaces/client.d.ts +2 -1
- package/dest/interfaces/client.d.ts.map +1 -1
- package/dest/interfaces/client.js +1 -0
- package/dest/interfaces/proving-job.d.ts +166 -166
- package/dest/interfaces/slasher.d.ts +1 -10
- package/dest/interfaces/slasher.d.ts.map +1 -1
- package/dest/interfaces/slasher.js +0 -2
- package/dest/interfaces/validator.d.ts +3 -6
- package/dest/interfaces/validator.d.ts.map +1 -1
- package/dest/l1-contracts/index.d.ts +2 -2
- package/dest/l1-contracts/index.d.ts.map +1 -1
- package/dest/l1-contracts/index.js +1 -1
- package/dest/p2p/checkpoint_proposal.d.ts +2 -2
- package/dest/p2p/checkpoint_proposal.d.ts.map +1 -1
- package/dest/p2p/checkpoint_proposal.js +3 -15
- package/dest/slashing/index.d.ts +2 -3
- package/dest/slashing/index.d.ts.map +1 -1
- package/dest/slashing/index.js +1 -2
- package/dest/slashing/serialization.d.ts +2 -6
- package/dest/slashing/serialization.d.ts.map +1 -1
- package/dest/slashing/serialization.js +0 -60
- package/dest/slashing/types.d.ts +4 -90
- package/dest/slashing/types.d.ts.map +1 -1
- package/dest/slashing/types.js +0 -14
- package/dest/slashing/{tally.d.ts → votes.d.ts} +1 -1
- package/dest/slashing/{tally.d.ts.map → votes.d.ts.map} +1 -1
- package/dest/slashing/{tally.js → votes.js} +1 -1
- package/dest/tests/mocks.d.ts +1 -1
- package/dest/tests/mocks.d.ts.map +1 -1
- package/dest/tests/mocks.js +11 -16
- package/dest/timetable/index.d.ts +51 -1
- package/dest/timetable/index.d.ts.map +1 -1
- package/dest/timetable/index.js +204 -14
- package/dest/tx/global_variable_builder.d.ts +3 -14
- package/dest/tx/global_variable_builder.d.ts.map +1 -1
- package/dest/tx/simulated_tx.d.ts +1 -1
- package/dest/tx/simulated_tx.js +1 -1
- package/dest/world-state/genesis_data.d.ts +11 -0
- package/dest/world-state/genesis_data.d.ts.map +1 -0
- package/dest/world-state/genesis_data.js +4 -0
- package/dest/world-state/index.d.ts +2 -1
- package/dest/world-state/index.d.ts.map +1 -1
- package/dest/world-state/index.js +1 -0
- package/package.json +8 -8
- package/src/config/sequencer-config.ts +11 -1
- package/src/gas/gas_fees.ts +12 -4
- package/src/interfaces/aztec-node-admin.ts +3 -6
- package/src/interfaces/aztec-node-debug.ts +40 -0
- package/src/interfaces/client.ts +1 -0
- package/src/interfaces/slasher.ts +0 -6
- package/src/interfaces/validator.ts +1 -4
- package/src/l1-contracts/index.ts +1 -1
- package/src/p2p/checkpoint_proposal.ts +10 -26
- package/src/slashing/index.ts +1 -2
- package/src/slashing/serialization.ts +1 -81
- package/src/slashing/types.ts +3 -35
- package/src/slashing/{tally.ts → votes.ts} +1 -1
- package/src/tests/mocks.ts +12 -10
- package/src/timetable/index.ts +293 -13
- package/src/tx/global_variable_builder.ts +2 -15
- package/src/tx/simulated_tx.ts +1 -1
- package/src/world-state/genesis_data.ts +15 -0
- package/src/world-state/index.ts +1 -0
- package/dest/l1-contracts/slash_factory.d.ts +0 -45
- package/dest/l1-contracts/slash_factory.d.ts.map +0 -1
- package/dest/l1-contracts/slash_factory.js +0 -158
- package/dest/slashing/empire.d.ts +0 -31
- package/dest/slashing/empire.d.ts.map +0 -1
- package/dest/slashing/empire.js +0 -87
- package/src/l1-contracts/slash_factory.ts +0 -180
- package/src/slashing/empire.ts +0 -104
|
@@ -9,7 +9,6 @@ import type {
|
|
|
9
9
|
BlockProposal,
|
|
10
10
|
BlockProposalOptions,
|
|
11
11
|
CheckpointAttestation,
|
|
12
|
-
CheckpointLastBlockData,
|
|
13
12
|
CheckpointProposal,
|
|
14
13
|
CheckpointProposalOptions,
|
|
15
14
|
} from '@aztec/stdlib/p2p';
|
|
@@ -118,8 +117,6 @@ export const ValidatorClientFullConfigSchema = zodFor<Omit<ValidatorClientFullCo
|
|
|
118
117
|
}),
|
|
119
118
|
);
|
|
120
119
|
|
|
121
|
-
export type CreateCheckpointProposalLastBlockData = Omit<CheckpointLastBlockData, 'txHashes'> & { txs: Tx[] };
|
|
122
|
-
|
|
123
120
|
export interface Validator {
|
|
124
121
|
start(): Promise<void>;
|
|
125
122
|
updateConfig(config: Partial<ValidatorClientFullConfig>): void;
|
|
@@ -140,7 +137,7 @@ export interface Validator {
|
|
|
140
137
|
checkpointHeader: CheckpointHeader,
|
|
141
138
|
archive: Fr,
|
|
142
139
|
feeAssetPriceModifier: bigint,
|
|
143
|
-
|
|
140
|
+
lastBlockProposal: BlockProposal | undefined,
|
|
144
141
|
proposerAddress: EthAddress | undefined,
|
|
145
142
|
options: CheckpointProposalOptions,
|
|
146
143
|
): Promise<CheckpointProposal>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
// No exports.
|
|
@@ -161,7 +161,7 @@ export class CheckpointProposal extends Gossipable {
|
|
|
161
161
|
checkpointHeader: CheckpointHeader,
|
|
162
162
|
archiveRoot: Fr,
|
|
163
163
|
feeAssetPriceModifier: bigint,
|
|
164
|
-
|
|
164
|
+
lastBlockProposal: BlockProposal | undefined,
|
|
165
165
|
payloadSigner: (payload: Buffer32, context: SigningContext) => Promise<Signature>,
|
|
166
166
|
): Promise<CheckpointProposal> {
|
|
167
167
|
// Sign the checkpoint payload with CHECKPOINT_PROPOSAL duty type
|
|
@@ -175,35 +175,19 @@ export class CheckpointProposal extends Gossipable {
|
|
|
175
175
|
|
|
176
176
|
const checkpointContext: SigningContext = {
|
|
177
177
|
slot: checkpointHeader.slotNumber,
|
|
178
|
-
blockNumber:
|
|
178
|
+
blockNumber: lastBlockProposal?.blockNumber ?? BlockNumber(0),
|
|
179
179
|
dutyType: DutyType.CHECKPOINT_PROPOSAL,
|
|
180
180
|
};
|
|
181
181
|
|
|
182
|
-
if (lastBlockInfo) {
|
|
183
|
-
// Sign block proposal before signing checkpoint proposal to ensure HA protection
|
|
184
|
-
const lastBlockProposal = await BlockProposal.createProposalFromSigner(
|
|
185
|
-
lastBlockInfo.blockHeader,
|
|
186
|
-
lastBlockInfo.indexWithinCheckpoint,
|
|
187
|
-
checkpointHeader.inHash,
|
|
188
|
-
archiveRoot,
|
|
189
|
-
lastBlockInfo.txHashes,
|
|
190
|
-
lastBlockInfo.txs,
|
|
191
|
-
payloadSigner,
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
const checkpointSignature = await payloadSigner(checkpointHash, checkpointContext);
|
|
195
|
-
|
|
196
|
-
return new CheckpointProposal(checkpointHeader, archiveRoot, feeAssetPriceModifier, checkpointSignature, {
|
|
197
|
-
blockHeader: lastBlockInfo.blockHeader,
|
|
198
|
-
indexWithinCheckpoint: lastBlockInfo.indexWithinCheckpoint,
|
|
199
|
-
txHashes: lastBlockInfo.txHashes,
|
|
200
|
-
signature: lastBlockProposal.signature,
|
|
201
|
-
signedTxs: lastBlockProposal.signedTxs,
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
182
|
const checkpointSignature = await payloadSigner(checkpointHash, checkpointContext);
|
|
206
|
-
|
|
183
|
+
|
|
184
|
+
return new CheckpointProposal(
|
|
185
|
+
checkpointHeader,
|
|
186
|
+
archiveRoot,
|
|
187
|
+
feeAssetPriceModifier,
|
|
188
|
+
checkpointSignature,
|
|
189
|
+
lastBlockProposal,
|
|
190
|
+
);
|
|
207
191
|
}
|
|
208
192
|
|
|
209
193
|
/**
|
package/src/slashing/index.ts
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
import { times } from '@aztec/foundation/collection';
|
|
2
1
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
2
|
import { BufferReader, bigintToUInt64BE, bigintToUInt128BE, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
4
3
|
|
|
5
|
-
import type {
|
|
6
|
-
Offense,
|
|
7
|
-
OffenseType,
|
|
8
|
-
SlashPayload,
|
|
9
|
-
SlashPayloadRound,
|
|
10
|
-
ValidatorSlash,
|
|
11
|
-
ValidatorSlashOffense,
|
|
12
|
-
} from './types.js';
|
|
4
|
+
import type { Offense, OffenseType } from './types.js';
|
|
13
5
|
|
|
14
6
|
export function serializeOffense(offense: Offense): Buffer {
|
|
15
7
|
return serializeToBuffer(
|
|
@@ -29,75 +21,3 @@ export function deserializeOffense(buffer: Buffer): Offense {
|
|
|
29
21
|
|
|
30
22
|
return { validator, amount, offenseType: offense, epochOrSlot };
|
|
31
23
|
}
|
|
32
|
-
|
|
33
|
-
function serializeValidatorSlashOffense(offense: ValidatorSlashOffense): Buffer {
|
|
34
|
-
return serializeToBuffer(bigintToUInt64BE(offense.epochOrSlot), offense.offenseType);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function deserializeValidatorSlashOffense(buffer: Buffer | BufferReader): ValidatorSlashOffense {
|
|
38
|
-
const reader = BufferReader.asReader(buffer);
|
|
39
|
-
return {
|
|
40
|
-
epochOrSlot: reader.readUInt64(),
|
|
41
|
-
offenseType: reader.readNumber() as OffenseType,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function serializeValidatorSlash(slash: ValidatorSlash): Buffer {
|
|
46
|
-
return serializeToBuffer(
|
|
47
|
-
slash.validator,
|
|
48
|
-
bigintToUInt128BE(slash.amount),
|
|
49
|
-
slash.offenses.length,
|
|
50
|
-
slash.offenses.map(serializeValidatorSlashOffense),
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function deserializeValidatorSlash(buffer: Buffer | BufferReader): ValidatorSlash {
|
|
55
|
-
const reader = BufferReader.asReader(buffer);
|
|
56
|
-
const validator = reader.readObject(EthAddress);
|
|
57
|
-
const amount = reader.readUInt128();
|
|
58
|
-
const offensesCount = reader.readNumber();
|
|
59
|
-
const offenses = times(offensesCount, () => deserializeValidatorSlashOffense(reader));
|
|
60
|
-
|
|
61
|
-
return { validator, amount, offenses };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function serializeSlashPayload(payload: SlashPayload): Buffer {
|
|
65
|
-
return serializeToBuffer(
|
|
66
|
-
payload.address,
|
|
67
|
-
payload.slashes.length,
|
|
68
|
-
payload.slashes.map(serializeValidatorSlash),
|
|
69
|
-
bigintToUInt64BE(payload.timestamp),
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function deserializeSlashPayload(buffer: Buffer): SlashPayload {
|
|
74
|
-
const reader = BufferReader.asReader(buffer);
|
|
75
|
-
const address = reader.readObject(EthAddress);
|
|
76
|
-
const slashesCount = reader.readNumber();
|
|
77
|
-
const slashes = times(slashesCount, () => deserializeValidatorSlash(reader));
|
|
78
|
-
const timestamp = reader.readUInt64();
|
|
79
|
-
return { address, slashes, timestamp };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function serializeSlashPayloadRound(payload: SlashPayloadRound): Buffer {
|
|
83
|
-
return serializeToBuffer(
|
|
84
|
-
payload.address,
|
|
85
|
-
payload.slashes.length,
|
|
86
|
-
payload.slashes.map(serializeValidatorSlash),
|
|
87
|
-
bigintToUInt64BE(payload.timestamp),
|
|
88
|
-
Number(payload.votes),
|
|
89
|
-
bigintToUInt64BE(payload.round),
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function deserializeSlashPayloadRound(buffer: Buffer): SlashPayloadRound {
|
|
94
|
-
const reader = BufferReader.asReader(buffer);
|
|
95
|
-
const address = reader.readObject(EthAddress);
|
|
96
|
-
const slashesCount = reader.readNumber();
|
|
97
|
-
const slashes = times(slashesCount, () => deserializeValidatorSlash(reader));
|
|
98
|
-
const timestamp = reader.readUInt64();
|
|
99
|
-
const votes = BigInt(reader.readNumber());
|
|
100
|
-
const round = reader.readUInt64();
|
|
101
|
-
|
|
102
|
-
return { address, slashes, timestamp, votes, round };
|
|
103
|
-
}
|
package/src/slashing/types.ts
CHANGED
|
@@ -126,45 +126,13 @@ export type ValidatorSlash = {
|
|
|
126
126
|
offenses: ValidatorSlashOffense[];
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
-
/**
|
|
130
|
-
export type SlashPayload = {
|
|
131
|
-
address: EthAddress;
|
|
132
|
-
slashes: ValidatorSlash[];
|
|
133
|
-
timestamp: bigint;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
/** Slash payload with round information from empire slash proposer */
|
|
137
|
-
export type SlashPayloadRound = SlashPayload & { votes: bigint; round: bigint };
|
|
138
|
-
|
|
139
|
-
export const SlashPayloadRoundSchema = zodFor<SlashPayloadRound>()(
|
|
140
|
-
z.object({
|
|
141
|
-
address: schemas.EthAddress,
|
|
142
|
-
timestamp: schemas.BigInt,
|
|
143
|
-
votes: schemas.BigInt,
|
|
144
|
-
round: schemas.BigInt,
|
|
145
|
-
slashes: z.array(
|
|
146
|
-
z.object({
|
|
147
|
-
validator: schemas.EthAddress,
|
|
148
|
-
amount: schemas.BigInt,
|
|
149
|
-
offenses: z.array(z.object({ offenseType: OffenseTypeSchema, epochOrSlot: schemas.BigInt })),
|
|
150
|
-
}),
|
|
151
|
-
),
|
|
152
|
-
}),
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
/** Votes for a validator slash in the consensus slash proposer */
|
|
129
|
+
/** Votes for a validator slash in the slashing proposer */
|
|
156
130
|
export type ValidatorSlashVote = number;
|
|
157
131
|
|
|
158
132
|
export type ProposerSlashAction =
|
|
159
|
-
/**
|
|
160
|
-
| { type: 'create-empire-payload'; data: ValidatorSlash[] }
|
|
161
|
-
/** Vote for a slashing payload on an empire-based slash proposer */
|
|
162
|
-
| { type: 'vote-empire-payload'; payload: EthAddress }
|
|
163
|
-
/** Execute a slashing payload on an empire-based slash proposer */
|
|
164
|
-
| { type: 'execute-empire-payload'; round: bigint }
|
|
165
|
-
/** Vote for offenses on a consensus slashing proposer */
|
|
133
|
+
/** Vote for offenses on the slashing proposer */
|
|
166
134
|
| { type: 'vote-offenses'; votes: ValidatorSlashVote[]; committees: EthAddress[][]; round: bigint }
|
|
167
|
-
/** Execute a slashing round on
|
|
135
|
+
/** Execute a slashing round on the slashing proposer */
|
|
168
136
|
| { type: 'execute-slash'; committees: EthAddress[][]; round: bigint };
|
|
169
137
|
|
|
170
138
|
export type ProposerSlashActionType = ProposerSlashAction['type'];
|
|
@@ -28,7 +28,7 @@ export function getSlashConsensusVotesFromOffenses(
|
|
|
28
28
|
targetCommitteeSize: number;
|
|
29
29
|
maxSlashedValidators?: number;
|
|
30
30
|
},
|
|
31
|
-
logger: Logger = createLogger('slasher:
|
|
31
|
+
logger: Logger = createLogger('slasher:votes'),
|
|
32
32
|
): ValidatorSlashVote[] {
|
|
33
33
|
const { slashingAmounts, targetCommitteeSize, maxSlashedValidators } = settings;
|
|
34
34
|
|
package/src/tests/mocks.ts
CHANGED
|
@@ -596,28 +596,30 @@ export const makeBlockProposal = (options?: MakeBlockProposalOptions): Promise<B
|
|
|
596
596
|
);
|
|
597
597
|
};
|
|
598
598
|
|
|
599
|
-
export const makeCheckpointProposal = (options?: MakeCheckpointProposalOptions): Promise<CheckpointProposal> => {
|
|
600
|
-
const blockHeader = options?.lastBlock?.blockHeader ?? makeBlockHeader(1);
|
|
599
|
+
export const makeCheckpointProposal = async (options?: MakeCheckpointProposalOptions): Promise<CheckpointProposal> => {
|
|
601
600
|
const checkpointHeader = options?.checkpointHeader ?? makeCheckpointHeader(1);
|
|
602
601
|
const archiveRoot = options?.archiveRoot ?? Fr.random();
|
|
603
602
|
const feeAssetPriceModifier = options?.feeAssetPriceModifier ?? 0n;
|
|
604
603
|
const signer = options?.signer ?? Secp256k1Signer.random();
|
|
605
604
|
|
|
606
|
-
// Build
|
|
607
|
-
const
|
|
608
|
-
? {
|
|
609
|
-
blockHeader,
|
|
610
|
-
indexWithinCheckpoint: options.lastBlock.indexWithinCheckpoint ?? IndexWithinCheckpoint(4),
|
|
611
|
-
|
|
605
|
+
// Build a signed block proposal if lastBlock options are provided
|
|
606
|
+
const lastBlockProposal = options?.lastBlock
|
|
607
|
+
? await makeBlockProposal({
|
|
608
|
+
blockHeader: options.lastBlock.blockHeader,
|
|
609
|
+
indexWithinCheckpoint: options.lastBlock.indexWithinCheckpoint ?? IndexWithinCheckpoint(4),
|
|
610
|
+
inHash: checkpointHeader.inHash,
|
|
611
|
+
archiveRoot,
|
|
612
|
+
txHashes: options.lastBlock.txHashes,
|
|
612
613
|
txs: options.lastBlock.txs,
|
|
613
|
-
|
|
614
|
+
signer,
|
|
615
|
+
})
|
|
614
616
|
: undefined;
|
|
615
617
|
|
|
616
618
|
return CheckpointProposal.createProposalFromSigner(
|
|
617
619
|
checkpointHeader,
|
|
618
620
|
archiveRoot,
|
|
619
621
|
feeAssetPriceModifier,
|
|
620
|
-
|
|
622
|
+
lastBlockProposal,
|
|
621
623
|
payload => Promise.resolve(signer.signMessage(payload)),
|
|
622
624
|
);
|
|
623
625
|
};
|
package/src/timetable/index.ts
CHANGED
|
@@ -25,6 +25,219 @@ export const DEFAULT_L1_PUBLISHING_TIME = 12;
|
|
|
25
25
|
/** Minimum execution time for building a block in seconds */
|
|
26
26
|
export const MIN_EXECUTION_TIME = 2;
|
|
27
27
|
|
|
28
|
+
export type CheckpointTimingConfig = {
|
|
29
|
+
aztecSlotDuration: number;
|
|
30
|
+
ethereumSlotDuration?: number;
|
|
31
|
+
blockDuration?: number;
|
|
32
|
+
checkpointAssembleTime?: number;
|
|
33
|
+
checkpointInitializationTime?: number;
|
|
34
|
+
l1PublishingTime?: number;
|
|
35
|
+
minExecutionTime?: number;
|
|
36
|
+
p2pPropagationTime?: number;
|
|
37
|
+
pipelining?: boolean;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export interface CheckpointTiming {
|
|
41
|
+
readonly aztecSlotDuration: number;
|
|
42
|
+
readonly blockDuration: number | undefined;
|
|
43
|
+
readonly checkpointAssembleTime: number;
|
|
44
|
+
readonly checkpointInitializationTime: number;
|
|
45
|
+
readonly l1PublishingTime: number;
|
|
46
|
+
readonly minExecutionTime: number;
|
|
47
|
+
readonly p2pPropagationTime: number;
|
|
48
|
+
readonly checkpointFinalizationTime: number;
|
|
49
|
+
readonly pipeliningAttestationGracePeriod: number;
|
|
50
|
+
readonly timeReservedAtEnd: number;
|
|
51
|
+
readonly minimumBuildSlotWork: number;
|
|
52
|
+
readonly initializeDeadline: number;
|
|
53
|
+
readonly checkpointAssemblyDeadline: number;
|
|
54
|
+
readonly checkpointAttestationStartDeadline: number;
|
|
55
|
+
readonly checkpointAttestationDeadline: number;
|
|
56
|
+
readonly checkpointPublishingDeadline: number;
|
|
57
|
+
|
|
58
|
+
calculateMaxBlocksPerSlot(): number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface PipelinedCheckpointTiming extends CheckpointTiming {
|
|
62
|
+
readonly proposalWindowIntoTargetSlot: number;
|
|
63
|
+
readonly attestationWindowIntoTargetSlot: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Shared base for checkpoint timing implementations.
|
|
68
|
+
*
|
|
69
|
+
* This class owns the common inputs and formulas used by both pipelined and
|
|
70
|
+
* non-pipelined scheduling. Variant-specific deadline math is delegated to the
|
|
71
|
+
* concrete subclasses below.
|
|
72
|
+
*/
|
|
73
|
+
abstract class BaseCheckpointTiming implements CheckpointTiming {
|
|
74
|
+
public readonly aztecSlotDuration: number;
|
|
75
|
+
public readonly blockDuration: number | undefined;
|
|
76
|
+
public readonly checkpointAssembleTime: number;
|
|
77
|
+
public readonly checkpointInitializationTime: number;
|
|
78
|
+
public readonly l1PublishingTime: number;
|
|
79
|
+
public readonly minExecutionTime: number;
|
|
80
|
+
public readonly p2pPropagationTime: number;
|
|
81
|
+
|
|
82
|
+
constructor(opts: CheckpointTimingConfig) {
|
|
83
|
+
this.aztecSlotDuration = opts.aztecSlotDuration;
|
|
84
|
+
this.blockDuration = opts.blockDuration;
|
|
85
|
+
|
|
86
|
+
this.checkpointAssembleTime = opts.checkpointAssembleTime ?? CHECKPOINT_ASSEMBLE_TIME;
|
|
87
|
+
this.checkpointInitializationTime = opts.checkpointInitializationTime ?? CHECKPOINT_INITIALIZATION_TIME;
|
|
88
|
+
this.l1PublishingTime = opts.l1PublishingTime ?? DEFAULT_L1_PUBLISHING_TIME;
|
|
89
|
+
this.minExecutionTime = opts.minExecutionTime ?? MIN_EXECUTION_TIME;
|
|
90
|
+
this.p2pPropagationTime = opts.p2pPropagationTime ?? DEFAULT_P2P_PROPAGATION_TIME;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public get checkpointFinalizationTime(): number {
|
|
94
|
+
// Allow enough time to
|
|
95
|
+
// - build the checkpoint
|
|
96
|
+
// - Round-trip over p2p
|
|
97
|
+
// - Publish to L1
|
|
98
|
+
return this.checkpointAssembleTime + this.p2pPropagationTime * 2 + this.l1PublishingTime;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public get pipeliningAttestationGracePeriod(): number {
|
|
102
|
+
// Allow enough time to
|
|
103
|
+
// - build the block
|
|
104
|
+
// - pass it back over p2p
|
|
105
|
+
return (this.blockDuration ?? 0) + this.p2pPropagationTime;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public abstract get timeReservedAtEnd(): number;
|
|
109
|
+
public abstract get minimumBuildSlotWork(): number;
|
|
110
|
+
|
|
111
|
+
public get initializeDeadline(): number {
|
|
112
|
+
return this.aztecSlotDuration - this.minimumBuildSlotWork;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public abstract get checkpointAssemblyDeadline(): number;
|
|
116
|
+
|
|
117
|
+
public get checkpointAttestationStartDeadline(): number {
|
|
118
|
+
return this.checkpointAssemblyDeadline;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public abstract get checkpointAttestationDeadline(): number;
|
|
122
|
+
public abstract get checkpointPublishingDeadline(): number;
|
|
123
|
+
|
|
124
|
+
public calculateMaxBlocksPerSlot(): number {
|
|
125
|
+
if (!this.blockDuration) {
|
|
126
|
+
return 1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const timeAvailableForBlocks = this.aztecSlotDuration - this.checkpointInitializationTime - this.timeReservedAtEnd;
|
|
130
|
+
return Math.floor(timeAvailableForBlocks / this.blockDuration);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Checkpoint timing model for the non-pipelined sequencer flow.
|
|
136
|
+
*
|
|
137
|
+
* In this mode, checkpoint assembly, attestation collection, and L1 publishing
|
|
138
|
+
* must all complete within the current Aztec slot.
|
|
139
|
+
*/
|
|
140
|
+
class StandardCheckpointTimingModel extends BaseCheckpointTiming {
|
|
141
|
+
public get timeReservedAtEnd(): number {
|
|
142
|
+
return (this.blockDuration ?? 0) + this.checkpointFinalizationTime;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public get minimumBuildSlotWork(): number {
|
|
146
|
+
return this.checkpointInitializationTime + this.minExecutionTime * 2 + this.checkpointFinalizationTime;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public get checkpointAssemblyDeadline(): number {
|
|
150
|
+
return this.aztecSlotDuration - this.l1PublishingTime - 2 * this.p2pPropagationTime;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public get checkpointAttestationDeadline(): number {
|
|
154
|
+
return this.aztecSlotDuration - this.l1PublishingTime;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public get checkpointPublishingDeadline(): number {
|
|
158
|
+
return this.aztecSlotDuration - this.l1PublishingTime;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Checkpoint timing model for proposer pipelining.
|
|
164
|
+
*
|
|
165
|
+
* In this mode, the build work still starts in the current slot, but checkpoint
|
|
166
|
+
* assembly and attestation collection can extend into the target slot. The extra
|
|
167
|
+
* target-slot window getters are intended for consumers such as P2P validators
|
|
168
|
+
* that need to validate pipelined messages against wallclock time.
|
|
169
|
+
*/
|
|
170
|
+
class PipelinedCheckpointTimingModel extends BaseCheckpointTiming implements PipelinedCheckpointTiming {
|
|
171
|
+
public get proposalWindowIntoTargetSlot(): number {
|
|
172
|
+
// Allow the p2p propagation time to receive a checkpoint proposal from leader
|
|
173
|
+
return this.p2pPropagationTime;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public get attestationWindowIntoTargetSlot(): number {
|
|
177
|
+
return this.aztecSlotDuration - this.l1PublishingTime;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public get timeReservedAtEnd(): number {
|
|
181
|
+
return this.checkpointAssembleTime + this.p2pPropagationTime;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public get minimumBuildSlotWork(): number {
|
|
185
|
+
return this.checkpointInitializationTime + this.minExecutionTime * 2;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public get checkpointAssemblyDeadline(): number {
|
|
189
|
+
// Allow enough time to
|
|
190
|
+
// - build all blocks
|
|
191
|
+
// - receive attestations
|
|
192
|
+
return this.aztecSlotDuration + this.pipeliningAttestationGracePeriod;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public get checkpointAttestationDeadline(): number {
|
|
196
|
+
// Allowed to be into the next wallclock slot minus the allocated l1 publishing time
|
|
197
|
+
return this.aztecSlotDuration * 2 - this.l1PublishingTime;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public get checkpointPublishingDeadline(): number {
|
|
201
|
+
// Allowed to be into the next wallclock slot minus the allocated l1 Publishing time
|
|
202
|
+
return this.aztecSlotDuration * 2 - this.l1PublishingTime;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Creates a checkpoint timing model for the requested scheduling mode.
|
|
208
|
+
*
|
|
209
|
+
* Most callers should use this factory and depend only on the shared
|
|
210
|
+
* `CheckpointTiming` interface. The returned implementation is selected from
|
|
211
|
+
* `opts.pipelining`.
|
|
212
|
+
*/
|
|
213
|
+
export function createCheckpointTimingModel(opts: CheckpointTimingConfig): CheckpointTiming {
|
|
214
|
+
validateCheckpointTimingConfig(opts);
|
|
215
|
+
const normalizedOpts = normalizeCheckpointTimingConfig(opts);
|
|
216
|
+
|
|
217
|
+
const timing = normalizedOpts.pipelining
|
|
218
|
+
? new PipelinedCheckpointTimingModel(normalizedOpts)
|
|
219
|
+
: new StandardCheckpointTimingModel(normalizedOpts);
|
|
220
|
+
validateCheckpointTimingModel(timing);
|
|
221
|
+
return timing;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Creates a pipelined checkpoint timing model with target-slot window accessors.
|
|
226
|
+
*
|
|
227
|
+
* Use this when the caller specifically needs the pipelined-only timing surface,
|
|
228
|
+
* such as proposal or attestation acceptance windows into the target slot.
|
|
229
|
+
*/
|
|
230
|
+
export function createPipelinedCheckpointTimingModel(
|
|
231
|
+
opts: Omit<CheckpointTimingConfig, 'pipelining'>,
|
|
232
|
+
): PipelinedCheckpointTiming {
|
|
233
|
+
validateCheckpointTimingConfig(opts);
|
|
234
|
+
const normalizedOpts = normalizeCheckpointTimingConfig(opts);
|
|
235
|
+
|
|
236
|
+
const timing = new PipelinedCheckpointTimingModel(normalizedOpts);
|
|
237
|
+
validateCheckpointTimingModel(timing);
|
|
238
|
+
return timing;
|
|
239
|
+
}
|
|
240
|
+
|
|
28
241
|
/**
|
|
29
242
|
* Calculates the maximum number of blocks that can be built in a slot.
|
|
30
243
|
* Used by both the sequencer timetable and p2p gossipsub scoring.
|
|
@@ -42,25 +255,92 @@ export function calculateMaxBlocksPerSlot(
|
|
|
42
255
|
checkpointAssembleTime?: number;
|
|
43
256
|
p2pPropagationTime?: number;
|
|
44
257
|
l1PublishingTime?: number;
|
|
258
|
+
pipelining?: boolean;
|
|
45
259
|
} = {},
|
|
46
260
|
): number {
|
|
47
|
-
|
|
48
|
-
|
|
261
|
+
return createCheckpointTimingModel({
|
|
262
|
+
aztecSlotDuration: aztecSlotDurationSec,
|
|
263
|
+
blockDuration: blockDurationSec,
|
|
264
|
+
checkpointAssembleTime: opts.checkpointAssembleTime,
|
|
265
|
+
checkpointInitializationTime: opts.checkpointInitializationTime,
|
|
266
|
+
l1PublishingTime: opts.l1PublishingTime,
|
|
267
|
+
p2pPropagationTime: opts.p2pPropagationTime,
|
|
268
|
+
pipelining: opts.pipelining,
|
|
269
|
+
}).calculateMaxBlocksPerSlot();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function assertNonNegative(name: string, value: number): void {
|
|
273
|
+
if (value < 0) {
|
|
274
|
+
throw new Error(`${name} must be non-negative (got ${value})`);
|
|
49
275
|
}
|
|
276
|
+
}
|
|
50
277
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
278
|
+
function validateCheckpointTimingConfig(opts: CheckpointTimingConfig): void {
|
|
279
|
+
if (opts.aztecSlotDuration <= 0) {
|
|
280
|
+
throw new Error(`aztecSlotDuration must be positive (got ${opts.aztecSlotDuration})`);
|
|
281
|
+
}
|
|
55
282
|
|
|
56
|
-
|
|
57
|
-
|
|
283
|
+
if (opts.ethereumSlotDuration !== undefined && opts.ethereumSlotDuration <= 0) {
|
|
284
|
+
throw new Error(`ethereumSlotDuration must be positive when provided (got ${opts.ethereumSlotDuration})`);
|
|
285
|
+
}
|
|
58
286
|
|
|
59
|
-
|
|
60
|
-
|
|
287
|
+
if (opts.blockDuration !== undefined && opts.blockDuration <= 0) {
|
|
288
|
+
throw new Error(`blockDuration must be positive when provided (got ${opts.blockDuration})`);
|
|
289
|
+
}
|
|
61
290
|
|
|
62
|
-
|
|
63
|
-
|
|
291
|
+
if (opts.minExecutionTime !== undefined && opts.minExecutionTime <= 0) {
|
|
292
|
+
throw new Error(`minExecutionTime must be positive when provided (got ${opts.minExecutionTime})`);
|
|
293
|
+
}
|
|
64
294
|
|
|
65
|
-
|
|
295
|
+
if (opts.checkpointAssembleTime !== undefined) {
|
|
296
|
+
assertNonNegative('checkpointAssembleTime', opts.checkpointAssembleTime);
|
|
297
|
+
}
|
|
298
|
+
if (opts.checkpointInitializationTime !== undefined) {
|
|
299
|
+
assertNonNegative('checkpointInitializationTime', opts.checkpointInitializationTime);
|
|
300
|
+
}
|
|
301
|
+
if (opts.l1PublishingTime !== undefined) {
|
|
302
|
+
assertNonNegative('l1PublishingTime', opts.l1PublishingTime);
|
|
303
|
+
}
|
|
304
|
+
if (opts.p2pPropagationTime !== undefined) {
|
|
305
|
+
assertNonNegative('p2pPropagationTime', opts.p2pPropagationTime);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function normalizeCheckpointTimingConfig(opts: CheckpointTimingConfig): CheckpointTimingConfig {
|
|
310
|
+
let checkpointAssembleTime = opts.checkpointAssembleTime ?? CHECKPOINT_ASSEMBLE_TIME;
|
|
311
|
+
let checkpointInitializationTime = opts.checkpointInitializationTime ?? CHECKPOINT_INITIALIZATION_TIME;
|
|
312
|
+
let minExecutionTime = opts.minExecutionTime ?? MIN_EXECUTION_TIME;
|
|
313
|
+
let p2pPropagationTime = opts.p2pPropagationTime ?? DEFAULT_P2P_PROPAGATION_TIME;
|
|
314
|
+
|
|
315
|
+
if (opts.ethereumSlotDuration !== undefined && opts.ethereumSlotDuration < 8) {
|
|
316
|
+
p2pPropagationTime = 0;
|
|
317
|
+
checkpointAssembleTime = 0.5;
|
|
318
|
+
checkpointInitializationTime = 0.5;
|
|
319
|
+
minExecutionTime = 1;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (opts.blockDuration !== undefined && minExecutionTime > opts.blockDuration) {
|
|
323
|
+
minExecutionTime = opts.blockDuration;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return {
|
|
327
|
+
...opts,
|
|
328
|
+
checkpointAssembleTime,
|
|
329
|
+
checkpointInitializationTime,
|
|
330
|
+
minExecutionTime,
|
|
331
|
+
p2pPropagationTime,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function validateCheckpointTimingModel(model: CheckpointTiming): void {
|
|
336
|
+
if (model.blockDuration === undefined) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const timeAvailableForBlocks = model.aztecSlotDuration - model.checkpointInitializationTime - model.timeReservedAtEnd;
|
|
341
|
+
if (timeAvailableForBlocks < model.blockDuration) {
|
|
342
|
+
throw new Error(
|
|
343
|
+
`Invalid timing configuration: only ${timeAvailableForBlocks}s available for block building, which is less than one blockDuration (${model.blockDuration}s).`,
|
|
344
|
+
);
|
|
345
|
+
}
|
|
66
346
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
1
|
+
import type { SimulationOverridesPlan } from '@aztec/ethereum/contracts';
|
|
3
2
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
3
|
import type { SlotNumber } from '@aztec/foundation/schemas';
|
|
5
4
|
|
|
@@ -8,18 +7,6 @@ import type { GasFees } from '../gas/gas_fees.js';
|
|
|
8
7
|
import type { UInt32 } from '../types/index.js';
|
|
9
8
|
import type { CheckpointGlobalVariables, GlobalVariables } from './global_variables.js';
|
|
10
9
|
|
|
11
|
-
/** Fee header fields needed for pipelining overrides. */
|
|
12
|
-
export type ForceProposedFeeHeader = {
|
|
13
|
-
checkpointNumber: CheckpointNumber;
|
|
14
|
-
feeHeader: FeeHeader;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
/** Options for building checkpoint global variables during pipelining. */
|
|
18
|
-
export type BuildCheckpointGlobalVariablesOpts = {
|
|
19
|
-
forcePendingCheckpointNumber?: CheckpointNumber;
|
|
20
|
-
forceProposedFeeHeader?: ForceProposedFeeHeader;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
10
|
/**
|
|
24
11
|
* Interface for building global variables for Aztec blocks.
|
|
25
12
|
*/
|
|
@@ -46,6 +33,6 @@ export interface GlobalVariableBuilder {
|
|
|
46
33
|
coinbase: EthAddress,
|
|
47
34
|
feeRecipient: AztecAddress,
|
|
48
35
|
slotNumber: SlotNumber,
|
|
49
|
-
|
|
36
|
+
simulationOverridesPlan?: SimulationOverridesPlan,
|
|
50
37
|
): Promise<CheckpointGlobalVariables>;
|
|
51
38
|
}
|
package/src/tx/simulated_tx.ts
CHANGED
|
@@ -161,7 +161,7 @@ export class TxSimulationResult {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
/**
|
|
164
|
-
* Recursively
|
|
164
|
+
* Recursively accumulate the return values of a call result and its nested executions,
|
|
165
165
|
* so they can be retrieved in order.
|
|
166
166
|
* @param executionResult
|
|
167
167
|
* @returns
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PublicDataTreeLeaf } from '../trees/index.js';
|
|
2
|
+
|
|
3
|
+
/** Data used to initialize the genesis block, including prefilled public state and an optional timestamp. */
|
|
4
|
+
export type GenesisData = {
|
|
5
|
+
/** Public data tree leaves to pre-populate in the genesis state (e.g. fee juice balances). */
|
|
6
|
+
prefilledPublicData: PublicDataTreeLeaf[];
|
|
7
|
+
/** Timestamp for the genesis block header. Defaults to 0 (canonical empty genesis) in production. */
|
|
8
|
+
genesisTimestamp: bigint;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/** An empty genesis data with no prefilled state and a zero timestamp. */
|
|
12
|
+
export const EMPTY_GENESIS_DATA: GenesisData = {
|
|
13
|
+
prefilledPublicData: [],
|
|
14
|
+
genesisTimestamp: 0n,
|
|
15
|
+
};
|
package/src/world-state/index.ts
CHANGED