@aztec/ethereum 0.0.1-commit.8f9871590 → 0.0.1-commit.9117c5f5a
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.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +4 -2
- package/dest/contracts/empire_base.d.ts +3 -1
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.d.ts +3 -1
- package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.js +9 -0
- package/dest/contracts/governance.js +3 -3
- package/dest/contracts/governance_proposer.d.ts +3 -1
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +9 -0
- package/dest/contracts/rollup.d.ts +5 -5
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +12 -2
- package/dest/deploy_aztec_l1_contracts.d.ts +2 -3
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_l1_contract.js +3 -3
- package/dest/generated/l1-contracts-defaults.d.ts +1 -1
- package/dest/generated/l1-contracts-defaults.js +1 -1
- package/dest/l1_tx_utils/config.d.ts +7 -1
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +14 -1
- package/dest/l1_tx_utils/factory.d.ts +18 -10
- package/dest/l1_tx_utils/factory.d.ts.map +1 -1
- package/dest/l1_tx_utils/factory.js +17 -7
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +15 -15
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +9 -15
- package/dest/l1_tx_utils/index-blobs.d.ts +3 -3
- package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -1
- package/dest/l1_tx_utils/index-blobs.js +2 -2
- package/dest/l1_tx_utils/index.d.ts +2 -1
- package/dest/l1_tx_utils/index.d.ts.map +1 -1
- package/dest/l1_tx_utils/index.js +1 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +16 -7
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +41 -36
- package/dest/l1_tx_utils/tx_delayer.d.ts +56 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
- package/dest/{test → l1_tx_utils}/tx_delayer.js +62 -34
- package/dest/test/index.d.ts +1 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +0 -2
- package/dest/test/start_anvil.d.ts +9 -3
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +128 -29
- package/dest/test/upgrade_utils.js +2 -2
- package/package.json +5 -7
- package/src/config.ts +2 -1
- package/src/contracts/empire_base.ts +2 -0
- package/src/contracts/empire_slashing_proposer.ts +6 -0
- package/src/contracts/governance.ts +3 -3
- package/src/contracts/governance_proposer.ts +6 -0
- package/src/contracts/rollup.ts +20 -6
- package/src/deploy_aztec_l1_contracts.ts +19 -2
- package/src/deploy_l1_contract.ts +3 -3
- package/src/generated/l1-contracts-defaults.ts +1 -1
- package/src/l1_tx_utils/config.ts +20 -0
- package/src/l1_tx_utils/factory.ts +31 -31
- package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +43 -54
- package/src/l1_tx_utils/index-blobs.ts +2 -2
- package/src/l1_tx_utils/index.ts +1 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +41 -26
- package/src/{test → l1_tx_utils}/tx_delayer.ts +78 -50
- package/src/test/index.ts +0 -2
- package/src/test/start_anvil.ts +146 -29
- package/src/test/upgrade_utils.ts +2 -2
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +0 -26
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +0 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +0 -26
- package/dest/test/delayed_tx_utils.d.ts +0 -13
- package/dest/test/delayed_tx_utils.d.ts.map +0 -1
- package/dest/test/delayed_tx_utils.js +0 -28
- package/dest/test/tx_delayer.d.ts +0 -36
- package/dest/test/tx_delayer.d.ts.map +0 -1
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
- package/src/test/delayed_tx_utils.ts +0 -52
|
@@ -2,8 +2,7 @@ import { omit } from '@aztec/foundation/collection';
|
|
|
2
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
3
3
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
4
4
|
import { inspect } from 'util';
|
|
5
|
-
import { keccak256, parseTransaction, publicActions, serializeTransaction, walletActions } from 'viem';
|
|
6
|
-
import { isExtendedClient } from '../types.js';
|
|
5
|
+
import { keccak256, parseTransaction, publicActions, recoverTransactionAddress, serializeTransaction, walletActions } from 'viem';
|
|
7
6
|
const MAX_WAIT_TIME_SECONDS = 180;
|
|
8
7
|
export function waitUntilBlock(client, blockNumber, logger, timeout) {
|
|
9
8
|
const publicClient = 'getBlockNumber' in client && typeof client.getBlockNumber === 'function' ? client : client.extend(publicActions);
|
|
@@ -35,59 +34,78 @@ export function waitUntilL1Timestamp(client, timestamp, logger, timeout) {
|
|
|
35
34
|
return currentTs >= BigInt(timestamp);
|
|
36
35
|
}, `Wait until L1 timestamp ${timestamp}`, timeout ?? MAX_WAIT_TIME_SECONDS, 0.1);
|
|
37
36
|
}
|
|
38
|
-
class
|
|
37
|
+
/** Manages tx delaying for testing, intercepting sendRawTransaction calls to delay or cancel them. */ export class Delayer {
|
|
39
38
|
dateProvider;
|
|
40
39
|
logger;
|
|
41
|
-
|
|
40
|
+
maxInclusionTimeIntoSlot;
|
|
41
|
+
ethereumSlotDuration;
|
|
42
|
+
nextWait;
|
|
43
|
+
sentTxHashes;
|
|
44
|
+
cancelledTxs;
|
|
45
|
+
constructor(dateProvider, opts, bindings){
|
|
42
46
|
this.dateProvider = dateProvider;
|
|
43
|
-
this.logger = createLogger('ethereum:tx_delayer');
|
|
44
47
|
this.maxInclusionTimeIntoSlot = undefined;
|
|
45
48
|
this.nextWait = undefined;
|
|
46
49
|
this.sentTxHashes = [];
|
|
47
50
|
this.cancelledTxs = [];
|
|
48
51
|
this.ethereumSlotDuration = BigInt(opts.ethereumSlotDuration);
|
|
52
|
+
this.logger = createLogger('ethereum:tx_delayer', bindings);
|
|
49
53
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
cancelledTxs;
|
|
55
|
-
getSentTxHashes() {
|
|
54
|
+
/** Returns the logger instance used by this delayer. */ getLogger() {
|
|
55
|
+
return this.logger;
|
|
56
|
+
}
|
|
57
|
+
/** Returns the hashes of all effectively sent txs. */ getSentTxHashes() {
|
|
56
58
|
return this.sentTxHashes;
|
|
57
59
|
}
|
|
58
|
-
getCancelledTxs() {
|
|
60
|
+
/** Returns the raw hex for all cancelled txs. */ getCancelledTxs() {
|
|
59
61
|
return this.cancelledTxs;
|
|
60
62
|
}
|
|
61
|
-
pauseNextTxUntilBlock(l1BlockNumber) {
|
|
63
|
+
/** Delays the next tx to be sent so it lands on the given L1 block number. */ pauseNextTxUntilBlock(l1BlockNumber) {
|
|
62
64
|
this.nextWait = {
|
|
63
65
|
l1BlockNumber: BigInt(l1BlockNumber)
|
|
64
66
|
};
|
|
65
67
|
}
|
|
66
|
-
pauseNextTxUntilTimestamp(l1Timestamp) {
|
|
68
|
+
/** Delays the next tx to be sent so it lands on the given timestamp. */ pauseNextTxUntilTimestamp(l1Timestamp) {
|
|
67
69
|
this.nextWait = {
|
|
68
70
|
l1Timestamp: BigInt(l1Timestamp)
|
|
69
71
|
};
|
|
70
72
|
}
|
|
71
|
-
cancelNextTx() {
|
|
73
|
+
/** Delays the next tx to be sent indefinitely. */ cancelNextTx() {
|
|
72
74
|
this.nextWait = {
|
|
73
75
|
indefinitely: true
|
|
74
76
|
};
|
|
75
77
|
}
|
|
76
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Sets max inclusion time into slot. If more than this many seconds have passed
|
|
80
|
+
* since the last L1 block was mined, then any tx will not be mined in the current
|
|
81
|
+
* L1 slot but will be deferred for the next one.
|
|
82
|
+
*/ setMaxInclusionTimeIntoSlot(seconds) {
|
|
77
83
|
this.maxInclusionTimeIntoSlot = seconds;
|
|
78
84
|
}
|
|
79
85
|
}
|
|
80
86
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
* Creates a new Delayer instance. Exposed so callers can create a single shared delayer
|
|
88
|
+
* and pass it to multiple `wrapClientWithDelayer` calls.
|
|
89
|
+
*/ export function createDelayer(dateProvider, opts, bindings) {
|
|
90
|
+
return new Delayer(dateProvider, opts, bindings);
|
|
91
|
+
}
|
|
92
|
+
/** Tries to recover the sender address from a serialized signed transaction. */ async function tryRecoverSender(serializedTransaction) {
|
|
93
|
+
try {
|
|
94
|
+
return await recoverTransactionAddress({
|
|
95
|
+
serializedTransaction: serializedTransaction
|
|
96
|
+
});
|
|
97
|
+
} catch {
|
|
98
|
+
return undefined;
|
|
87
99
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Wraps a viem client with tx delaying logic. Returns the wrapped client.
|
|
103
|
+
* The delayer intercepts sendRawTransaction calls and delays them based on the delayer's state.
|
|
104
|
+
*/ export function wrapClientWithDelayer(client, delayer) {
|
|
105
|
+
const logger = delayer.getLogger();
|
|
106
|
+
// Cast to ExtendedViemWalletClient for the extend chain since it has sendRawTransaction.
|
|
107
|
+
// The sendRawTransaction override is applied to all clients regardless of type.
|
|
108
|
+
const withRawTx = client// Tweak sendRawTransaction so it uses the delay defined in the delayer.
|
|
91
109
|
// Note that this will only work with local accounts (ie accounts for which we have the private key).
|
|
92
110
|
// Transactions signed by the node will not be delayed since they use sendTransaction directly,
|
|
93
111
|
// but we do not use them in our codebase at all.
|
|
@@ -97,6 +115,7 @@ class DelayerImpl {
|
|
|
97
115
|
let txHash;
|
|
98
116
|
const { serializedTransaction } = args[0];
|
|
99
117
|
const publicClient = client;
|
|
118
|
+
const sender = await tryRecoverSender(serializedTransaction);
|
|
100
119
|
if (delayer.nextWait !== undefined) {
|
|
101
120
|
// Check if we have been instructed to delay the next tx.
|
|
102
121
|
const waitUntil = delayer.nextWait;
|
|
@@ -105,13 +124,16 @@ class DelayerImpl {
|
|
|
105
124
|
txHash = computeTxHash(serializedTransaction);
|
|
106
125
|
// Cancel tx outright if instructed
|
|
107
126
|
if ('indefinitely' in waitUntil && waitUntil.indefinitely) {
|
|
108
|
-
logger.info(`Cancelling tx ${txHash}
|
|
127
|
+
logger.info(`Cancelling tx ${txHash}`, {
|
|
128
|
+
sender
|
|
129
|
+
});
|
|
109
130
|
delayer.cancelledTxs.push(serializedTransaction);
|
|
110
131
|
return Promise.resolve(txHash);
|
|
111
132
|
}
|
|
112
133
|
// Or wait until the desired block number or timestamp
|
|
113
134
|
wait = 'l1BlockNumber' in waitUntil ? waitUntilBlock(publicClient, waitUntil.l1BlockNumber - 1n, logger) : 'l1Timestamp' in waitUntil ? waitUntilL1Timestamp(publicClient, waitUntil.l1Timestamp - delayer.ethereumSlotDuration, logger) : undefined;
|
|
114
135
|
logger.info(`Delaying tx ${txHash} until ${inspect(waitUntil)}`, {
|
|
136
|
+
sender,
|
|
115
137
|
argsLen: args.length,
|
|
116
138
|
...omit(parseTransaction(serializedTransaction), 'data', 'sidecars')
|
|
117
139
|
});
|
|
@@ -124,6 +146,7 @@ class DelayerImpl {
|
|
|
124
146
|
const now = delayer.dateProvider.now();
|
|
125
147
|
txHash = computeTxHash(serializedTransaction);
|
|
126
148
|
const logData = {
|
|
149
|
+
sender,
|
|
127
150
|
...omit(parseTransaction(serializedTransaction), 'data', 'sidecars'),
|
|
128
151
|
lastBlockTimestamp,
|
|
129
152
|
now,
|
|
@@ -150,29 +173,34 @@ class DelayerImpl {
|
|
|
150
173
|
computedTxHash: txHash
|
|
151
174
|
});
|
|
152
175
|
}
|
|
153
|
-
logger.info(`Sent previously delayed tx ${clientTxHash}
|
|
176
|
+
logger.info(`Sent previously delayed tx ${clientTxHash}`, {
|
|
177
|
+
sender
|
|
178
|
+
});
|
|
154
179
|
delayer.sentTxHashes.push(clientTxHash);
|
|
155
180
|
}).catch((err)=>logger.error(`Error sending tx after delay`, err));
|
|
156
181
|
return Promise.resolve(txHash);
|
|
157
182
|
} else {
|
|
158
183
|
const txHash = await client.sendRawTransaction(...args);
|
|
159
|
-
logger.debug(`Sent tx immediately ${txHash}
|
|
184
|
+
logger.debug(`Sent tx immediately ${txHash}`, {
|
|
185
|
+
sender
|
|
186
|
+
});
|
|
160
187
|
delayer.sentTxHashes.push(txHash);
|
|
161
188
|
return txHash;
|
|
162
189
|
}
|
|
163
190
|
}
|
|
164
|
-
}))
|
|
191
|
+
}));
|
|
192
|
+
// Only re-bind wallet actions (sendTransaction, writeContract, deployContract) for wallet clients.
|
|
193
|
+
// This is needed for tests that use wallet actions directly rather than sendRawTransaction.
|
|
194
|
+
const isWalletClient = 'account' in client && client.account !== undefined;
|
|
195
|
+
const extended = isWalletClient ? withRawTx// Re-extend with sendTransaction so it uses the modified sendRawTransaction.
|
|
165
196
|
.extend((client)=>({
|
|
166
197
|
sendTransaction: walletActions(client).sendTransaction
|
|
167
198
|
}))// And with the actions that depend on the modified sendTransaction
|
|
168
199
|
.extend((client)=>({
|
|
169
200
|
writeContract: walletActions(client).writeContract,
|
|
170
201
|
deployContract: walletActions(client).deployContract
|
|
171
|
-
}));
|
|
172
|
-
return
|
|
173
|
-
client: extended,
|
|
174
|
-
delayer
|
|
175
|
-
};
|
|
202
|
+
})) : withRawTx;
|
|
203
|
+
return extended;
|
|
176
204
|
}
|
|
177
205
|
/**
|
|
178
206
|
* Compute the tx hash given the serialized tx. Note that if this is a blob tx, we need to
|
package/dest/test/index.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
export * from './delayed_tx_utils.js';
|
|
2
1
|
export * from './eth_cheat_codes.js';
|
|
3
2
|
export * from './eth_cheat_codes_with_state.js';
|
|
4
3
|
export * from './start_anvil.js';
|
|
5
|
-
export * from './tx_delayer.js';
|
|
6
4
|
export * from './upgrade_utils.js';
|
|
7
5
|
export * from './chain_monitor.js';
|
|
8
6
|
export * from './rollup_cheat_codes.js';
|
|
9
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
7
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsc0JBQXNCLENBQUM7QUFDckMsY0FBYyxpQ0FBaUMsQ0FBQztBQUNoRCxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxjQUFjLHlCQUF5QixDQUFDIn0=
|
package/dest/test/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,iCAAiC,CAAC;AAChD,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC"}
|
package/dest/test/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
export * from './delayed_tx_utils.js';
|
|
2
1
|
export * from './eth_cheat_codes.js';
|
|
3
2
|
export * from './eth_cheat_codes_with_state.js';
|
|
4
3
|
export * from './start_anvil.js';
|
|
5
|
-
export * from './tx_delayer.js';
|
|
6
4
|
export * from './upgrade_utils.js';
|
|
7
5
|
export * from './chain_monitor.js';
|
|
8
6
|
export * from './rollup_cheat_codes.js';
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/** Minimal interface matching the @viem/anvil Anvil shape used by callers. */
|
|
2
|
+
export interface Anvil {
|
|
3
|
+
readonly port: number;
|
|
4
|
+
readonly host: string;
|
|
5
|
+
readonly status: 'listening' | 'idle';
|
|
6
|
+
stop(): Promise<void>;
|
|
7
|
+
}
|
|
2
8
|
/**
|
|
3
9
|
* Ensures there's a running Anvil instance and returns the RPC URL.
|
|
4
10
|
*/
|
|
@@ -9,7 +15,7 @@ export declare function startAnvil(opts?: {
|
|
|
9
15
|
captureMethodCalls?: boolean;
|
|
10
16
|
accounts?: number;
|
|
11
17
|
chainId?: number;
|
|
12
|
-
/** The hardfork to use
|
|
18
|
+
/** The hardfork to use (e.g. 'cancun', 'latest'). */
|
|
13
19
|
hardfork?: string;
|
|
14
20
|
}): Promise<{
|
|
15
21
|
anvil: Anvil;
|
|
@@ -17,4 +23,4 @@ export declare function startAnvil(opts?: {
|
|
|
17
23
|
rpcUrl: string;
|
|
18
24
|
stop: () => Promise<void>;
|
|
19
25
|
}>;
|
|
20
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
26
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhcnRfYW52aWwuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0L3N0YXJ0X2FudmlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQU9BLDhFQUE4RTtBQUM5RSxNQUFNLFdBQVcsS0FBSztJQUNwQixRQUFRLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQztJQUN0QixRQUFRLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQztJQUN0QixRQUFRLENBQUMsTUFBTSxFQUFFLFdBQVcsR0FBRyxNQUFNLENBQUM7SUFDdEMsSUFBSSxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztDQUN2QjtBQUVEOztHQUVHO0FBQ0gsd0JBQXNCLFVBQVUsQ0FDOUIsSUFBSSxHQUFFO0lBQ0osSUFBSSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2QsV0FBVyxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3JCLEdBQUcsQ0FBQyxFQUFFLE9BQU8sQ0FBQztJQUNkLGtCQUFrQixDQUFDLEVBQUUsT0FBTyxDQUFDO0lBQzdCLFFBQVEsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNsQixPQUFPLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDakIscURBQXFEO0lBQ3JELFFBQVEsQ0FBQyxFQUFFLE1BQU0sQ0FBQztDQUNkLEdBQ0wsT0FBTyxDQUFDO0lBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQztJQUFDLFdBQVcsQ0FBQyxFQUFFLE1BQU0sRUFBRSxDQUFDO0lBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQztJQUFDLElBQUksRUFBRSxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtDQUFFLENBQUMsQ0EySDlGIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start_anvil.d.ts","sourceRoot":"","sources":["../../src/test/start_anvil.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"start_anvil.d.ts","sourceRoot":"","sources":["../../src/test/start_anvil.ts"],"names":[],"mappings":"AAOA,8EAA8E;AAC9E,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC;IACtC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,IAAI,GAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACd,GACL,OAAO,CAAC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CA2H9F"}
|
package/dest/test/start_anvil.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
2
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
3
3
|
import { fileURLToPath } from '@aztec/foundation/url';
|
|
4
|
-
import {
|
|
4
|
+
import { spawn } from 'child_process';
|
|
5
5
|
import { dirname, resolve } from 'path';
|
|
6
6
|
/**
|
|
7
7
|
* Ensures there's a running Anvil instance and returns the RPC URL.
|
|
@@ -9,47 +9,146 @@ import { dirname, resolve } from 'path';
|
|
|
9
9
|
const anvilBinary = resolve(dirname(fileURLToPath(import.meta.url)), '../../', 'scripts/anvil_kill_wrapper.sh');
|
|
10
10
|
const logger = opts.log ? createLogger('ethereum:anvil') : undefined;
|
|
11
11
|
const methodCalls = opts.captureMethodCalls ? [] : undefined;
|
|
12
|
-
let
|
|
13
|
-
// Start anvil.
|
|
14
|
-
// We go via a wrapper script to ensure if the parent dies, anvil dies.
|
|
12
|
+
let detectedPort;
|
|
15
13
|
const anvil = await retry(async ()=>{
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
host
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
accounts
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
14
|
+
const port = opts.port ?? (process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT) : 8545);
|
|
15
|
+
const args = [
|
|
16
|
+
'--host',
|
|
17
|
+
'127.0.0.1',
|
|
18
|
+
'--port',
|
|
19
|
+
String(port),
|
|
20
|
+
'--accounts',
|
|
21
|
+
String(opts.accounts ?? 20),
|
|
22
|
+
'--gas-limit',
|
|
23
|
+
String(45_000_000),
|
|
24
|
+
'--chain-id',
|
|
25
|
+
String(opts.chainId ?? 31337)
|
|
26
|
+
];
|
|
27
|
+
if (opts.l1BlockTime !== undefined) {
|
|
28
|
+
args.push('--block-time', String(opts.l1BlockTime));
|
|
29
|
+
}
|
|
30
|
+
if (opts.hardfork !== undefined) {
|
|
31
|
+
args.push('--hardfork', opts.hardfork);
|
|
32
|
+
}
|
|
33
|
+
const child = spawn(anvilBinary, args, {
|
|
34
|
+
stdio: [
|
|
35
|
+
'ignore',
|
|
36
|
+
'pipe',
|
|
37
|
+
'pipe'
|
|
38
|
+
],
|
|
39
|
+
env: {
|
|
40
|
+
...process.env,
|
|
41
|
+
RAYON_NUM_THREADS: '1'
|
|
32
42
|
}
|
|
33
43
|
});
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
// Wait for "Listening on" or an early exit.
|
|
45
|
+
await new Promise((resolve, reject)=>{
|
|
46
|
+
let stderr = '';
|
|
47
|
+
const onStdout = (data)=>{
|
|
48
|
+
const text = data.toString();
|
|
49
|
+
logger?.debug(text.trim());
|
|
50
|
+
methodCalls?.push(...text.match(/eth_[^\s]+/g) || []);
|
|
51
|
+
if (detectedPort === undefined && text.includes('Listening on')) {
|
|
52
|
+
const match = text.match(/Listening on ([^:]+):(\d+)/);
|
|
53
|
+
if (match) {
|
|
54
|
+
detectedPort = parseInt(match[2]);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (detectedPort !== undefined) {
|
|
58
|
+
child.stdout?.removeListener('data', onStdout);
|
|
59
|
+
child.stderr?.removeListener('data', onStderr);
|
|
60
|
+
child.removeListener('close', onClose);
|
|
61
|
+
resolve();
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const onStderr = (data)=>{
|
|
65
|
+
stderr += data.toString();
|
|
66
|
+
logger?.debug(data.toString().trim());
|
|
67
|
+
};
|
|
68
|
+
const onClose = (code)=>{
|
|
69
|
+
child.stdout?.removeListener('data', onStdout);
|
|
70
|
+
child.stderr?.removeListener('data', onStderr);
|
|
71
|
+
reject(new Error(`Anvil exited with code ${code} before listening. stderr: ${stderr}`));
|
|
72
|
+
};
|
|
73
|
+
child.stdout?.on('data', onStdout);
|
|
74
|
+
child.stderr?.on('data', onStderr);
|
|
75
|
+
child.once('close', onClose);
|
|
76
|
+
});
|
|
77
|
+
// Continue piping for logging / method-call capture after startup.
|
|
78
|
+
if (logger || opts.captureMethodCalls) {
|
|
79
|
+
child.stdout?.on('data', (data)=>{
|
|
80
|
+
const text = data.toString();
|
|
81
|
+
logger?.debug(text.trim());
|
|
82
|
+
methodCalls?.push(...text.match(/eth_[^\s]+/g) || []);
|
|
83
|
+
});
|
|
84
|
+
child.stderr?.on('data', (data)=>{
|
|
85
|
+
logger?.debug(data.toString().trim());
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
// Consume streams so the child process doesn't block on full pipe buffers.
|
|
89
|
+
child.stdout?.resume();
|
|
90
|
+
child.stderr?.resume();
|
|
37
91
|
}
|
|
38
|
-
return
|
|
92
|
+
return child;
|
|
39
93
|
}, 'Start anvil', makeBackoff([
|
|
40
94
|
5,
|
|
41
95
|
5,
|
|
42
96
|
5
|
|
43
97
|
]));
|
|
44
|
-
if (!
|
|
98
|
+
if (!detectedPort) {
|
|
45
99
|
throw new Error('Failed to start anvil');
|
|
46
100
|
}
|
|
47
|
-
|
|
48
|
-
|
|
101
|
+
const port = detectedPort;
|
|
102
|
+
let status = 'listening';
|
|
103
|
+
anvil.once('close', ()=>{
|
|
104
|
+
status = 'idle';
|
|
105
|
+
});
|
|
106
|
+
const stop = async ()=>{
|
|
107
|
+
if (status === 'idle') {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
await killChild(anvil);
|
|
111
|
+
};
|
|
112
|
+
const anvilObj = {
|
|
113
|
+
port,
|
|
114
|
+
host: '127.0.0.1',
|
|
115
|
+
get status () {
|
|
116
|
+
return status;
|
|
117
|
+
},
|
|
118
|
+
stop
|
|
119
|
+
};
|
|
49
120
|
return {
|
|
50
|
-
anvil,
|
|
121
|
+
anvil: anvilObj,
|
|
51
122
|
methodCalls,
|
|
52
|
-
stop
|
|
123
|
+
stop,
|
|
53
124
|
rpcUrl: `http://127.0.0.1:${port}`
|
|
54
125
|
};
|
|
55
126
|
}
|
|
127
|
+
/** Send SIGTERM, wait up to 5 s, then SIGKILL. All timers are always cleared. */ function killChild(child) {
|
|
128
|
+
return new Promise((resolve)=>{
|
|
129
|
+
if (child.exitCode !== null || child.killed) {
|
|
130
|
+
child.stdout?.destroy();
|
|
131
|
+
child.stderr?.destroy();
|
|
132
|
+
resolve();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
let killTimer;
|
|
136
|
+
const onClose = ()=>{
|
|
137
|
+
if (killTimer !== undefined) {
|
|
138
|
+
clearTimeout(killTimer);
|
|
139
|
+
}
|
|
140
|
+
// Destroy stdio streams so their PipeWrap handles don't keep the event loop alive.
|
|
141
|
+
child.stdout?.destroy();
|
|
142
|
+
child.stderr?.destroy();
|
|
143
|
+
resolve();
|
|
144
|
+
};
|
|
145
|
+
child.once('close', onClose);
|
|
146
|
+
child.kill('SIGTERM');
|
|
147
|
+
killTimer = setTimeout(()=>{
|
|
148
|
+
killTimer = undefined;
|
|
149
|
+
child.kill('SIGKILL');
|
|
150
|
+
}, 5000);
|
|
151
|
+
// Ensure the timer does not prevent Node from exiting.
|
|
152
|
+
killTimer.unref();
|
|
153
|
+
});
|
|
154
|
+
}
|
|
@@ -3,13 +3,13 @@ import { GovernanceAbi } from '@aztec/l1-artifacts/GovernanceAbi';
|
|
|
3
3
|
import { TestERC20Abi as StakingAssetAbi } from '@aztec/l1-artifacts/TestERC20Abi';
|
|
4
4
|
import { getContract } from 'viem';
|
|
5
5
|
import { extractProposalIdFromLogs } from '../contracts/governance.js';
|
|
6
|
-
import {
|
|
6
|
+
import { createL1TxUtils } from '../l1_tx_utils/index.js';
|
|
7
7
|
import { EthCheatCodes } from './eth_cheat_codes.js';
|
|
8
8
|
export async function executeGovernanceProposal(proposalId, governance, voteAmount, privateKey, l1Client, rpcUrls, logger) {
|
|
9
9
|
const proposal = await governance.read.getProposal([
|
|
10
10
|
proposalId
|
|
11
11
|
]);
|
|
12
|
-
const l1TxUtils =
|
|
12
|
+
const l1TxUtils = createL1TxUtils(l1Client);
|
|
13
13
|
const waitL1Block = async ()=>{
|
|
14
14
|
await l1TxUtils.sendAndMonitorTransaction({
|
|
15
15
|
to: l1Client.account.address,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/ethereum",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.9117c5f5a",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./account": "./dest/account.js",
|
|
@@ -50,11 +50,10 @@
|
|
|
50
50
|
"../package.common.json"
|
|
51
51
|
],
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
54
|
-
"@aztec/constants": "0.0.1-commit.
|
|
55
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
56
|
-
"@aztec/l1-artifacts": "0.0.1-commit.
|
|
57
|
-
"@viem/anvil": "^0.0.10",
|
|
53
|
+
"@aztec/blob-lib": "0.0.1-commit.9117c5f5a",
|
|
54
|
+
"@aztec/constants": "0.0.1-commit.9117c5f5a",
|
|
55
|
+
"@aztec/foundation": "0.0.1-commit.9117c5f5a",
|
|
56
|
+
"@aztec/l1-artifacts": "0.0.1-commit.9117c5f5a",
|
|
58
57
|
"dotenv": "^16.0.3",
|
|
59
58
|
"lodash.chunk": "^4.2.0",
|
|
60
59
|
"lodash.pickby": "^4.5.0",
|
|
@@ -69,7 +68,6 @@
|
|
|
69
68
|
"@types/lodash.pickby": "^4",
|
|
70
69
|
"@types/node": "^22.15.17",
|
|
71
70
|
"@typescript/native-preview": "7.0.0-dev.20260113.1",
|
|
72
|
-
"@viem/anvil": "^0.0.10",
|
|
73
71
|
"get-port": "^7.1.0",
|
|
74
72
|
"jest": "^30.0.0",
|
|
75
73
|
"jest-mock-extended": "^4.0.0",
|
package/src/config.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getConfigFromMappings,
|
|
7
7
|
getDefaultConfig,
|
|
8
8
|
numberConfigHelper,
|
|
9
|
+
omitConfigMappings,
|
|
9
10
|
optionalNumberConfigHelper,
|
|
10
11
|
} from '@aztec/foundation/config';
|
|
11
12
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
@@ -238,7 +239,7 @@ export const l1ContractsConfigMappings: ConfigMappingsType<L1ContractsConfig> =
|
|
|
238
239
|
description: 'The delay before a validator can exit the set',
|
|
239
240
|
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_EXIT_DELAY_SECONDS),
|
|
240
241
|
},
|
|
241
|
-
...l1TxUtilsConfigMappings,
|
|
242
|
+
...omitConfigMappings(l1TxUtilsConfigMappings, ['ethereumSlotDuration']),
|
|
242
243
|
};
|
|
243
244
|
|
|
244
245
|
/**
|
|
@@ -22,6 +22,8 @@ export interface IEmpireBase {
|
|
|
22
22
|
signerAddress: Hex,
|
|
23
23
|
signer: (msg: TypedDataDefinition) => Promise<Hex>,
|
|
24
24
|
): Promise<L1TxRequest>;
|
|
25
|
+
/** Checks if a payload was ever submitted to governance via submitRoundWinner. */
|
|
26
|
+
hasPayloadBeenProposed(payload: Hex, fromBlock: bigint): Promise<boolean>;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
export function encodeSignal(payload: Hex): Hex {
|
|
@@ -126,6 +126,12 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
|
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
/** Checks if a payload was ever submitted to governance via submitRoundWinner. */
|
|
130
|
+
public async hasPayloadBeenProposed(payload: Hex, fromBlock: bigint): Promise<boolean> {
|
|
131
|
+
const events = await this.proposer.getEvents.PayloadSubmitted({ payload }, { fromBlock, strict: true });
|
|
132
|
+
return events.length > 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
129
135
|
public listenToSubmittablePayloads(callback: (args: { payload: `0x${string}`; round: bigint }) => unknown) {
|
|
130
136
|
return this.proposer.watchEvent.PayloadSubmittable(
|
|
131
137
|
{},
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from 'viem';
|
|
15
15
|
|
|
16
16
|
import type { L1ContractAddresses } from '../l1_contract_addresses.js';
|
|
17
|
-
import {
|
|
17
|
+
import { createL1TxUtils } from '../l1_tx_utils/index.js';
|
|
18
18
|
import { type ExtendedViemWalletClient, type ViemClient, isExtendedClient } from '../types.js';
|
|
19
19
|
|
|
20
20
|
export type L1GovernanceContractAddresses = Pick<
|
|
@@ -194,7 +194,7 @@ export class GovernanceContract extends ReadOnlyGovernanceContract {
|
|
|
194
194
|
retries: number;
|
|
195
195
|
logger: Logger;
|
|
196
196
|
}) {
|
|
197
|
-
const l1TxUtils =
|
|
197
|
+
const l1TxUtils = createL1TxUtils(this.client, { logger });
|
|
198
198
|
const retryDelaySeconds = 12;
|
|
199
199
|
|
|
200
200
|
voteAmount = voteAmount ?? (await this.getPowerForProposal(proposalId));
|
|
@@ -252,7 +252,7 @@ export class GovernanceContract extends ReadOnlyGovernanceContract {
|
|
|
252
252
|
retries: number;
|
|
253
253
|
logger: Logger;
|
|
254
254
|
}) {
|
|
255
|
-
const l1TxUtils =
|
|
255
|
+
const l1TxUtils = createL1TxUtils(this.client, { logger });
|
|
256
256
|
const retryDelaySeconds = 12;
|
|
257
257
|
let success = false;
|
|
258
258
|
for (let i = 0; i < retries; i++) {
|
|
@@ -110,6 +110,12 @@ export class GovernanceProposerContract implements IEmpireBase {
|
|
|
110
110
|
};
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/** Checks if a payload was ever submitted to governance via submitRoundWinner. */
|
|
114
|
+
public async hasPayloadBeenProposed(payload: Hex, fromBlock: bigint): Promise<boolean> {
|
|
115
|
+
const events = await this.proposer.getEvents.PayloadSubmitted({ payload }, { fromBlock, strict: true });
|
|
116
|
+
return events.length > 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
113
119
|
public async submitRoundWinner(
|
|
114
120
|
round: bigint,
|
|
115
121
|
l1TxUtils: L1TxUtils,
|
package/src/contracts/rollup.ts
CHANGED
|
@@ -193,10 +193,10 @@ export type CheckpointProposedArgs = {
|
|
|
193
193
|
checkpointNumber: CheckpointNumber;
|
|
194
194
|
archive: Fr;
|
|
195
195
|
versionedBlobHashes: Buffer[];
|
|
196
|
-
/** Hash of attestations
|
|
197
|
-
attestationsHash
|
|
198
|
-
/** Digest of the payload
|
|
199
|
-
payloadDigest
|
|
196
|
+
/** Hash of attestations emitted in the CheckpointProposed event. */
|
|
197
|
+
attestationsHash: Buffer32;
|
|
198
|
+
/** Digest of the payload emitted in the CheckpointProposed event. */
|
|
199
|
+
payloadDigest: Buffer32;
|
|
200
200
|
};
|
|
201
201
|
|
|
202
202
|
/** Log type for CheckpointProposed events. */
|
|
@@ -1060,8 +1060,22 @@ export class RollupContract {
|
|
|
1060
1060
|
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
1061
1061
|
archive: Fr.fromString(log.args.archive!),
|
|
1062
1062
|
versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
|
|
1063
|
-
attestationsHash:
|
|
1064
|
-
|
|
1063
|
+
attestationsHash: (() => {
|
|
1064
|
+
if (!log.args.attestationsHash) {
|
|
1065
|
+
throw new Error(
|
|
1066
|
+
`CheckpointProposed event missing attestationsHash for checkpoint ${log.args.checkpointNumber}`,
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
return Buffer32.fromString(log.args.attestationsHash);
|
|
1070
|
+
})(),
|
|
1071
|
+
payloadDigest: (() => {
|
|
1072
|
+
if (!log.args.payloadDigest) {
|
|
1073
|
+
throw new Error(
|
|
1074
|
+
`CheckpointProposed event missing payloadDigest for checkpoint ${log.args.checkpointNumber}`,
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
return Buffer32.fromString(log.args.payloadDigest);
|
|
1078
|
+
})(),
|
|
1065
1079
|
},
|
|
1066
1080
|
}));
|
|
1067
1081
|
}
|
|
@@ -23,7 +23,6 @@ import type { L1ContractsConfig } from './config.js';
|
|
|
23
23
|
import { deployMulticall3 } from './contracts/multicall.js';
|
|
24
24
|
import { RollupContract } from './contracts/rollup.js';
|
|
25
25
|
import type { L1ContractAddresses } from './l1_contract_addresses.js';
|
|
26
|
-
import type { L1TxUtilsConfig } from './l1_tx_utils/config.js';
|
|
27
26
|
import type { ExtendedViemWalletClient } from './types.js';
|
|
28
27
|
|
|
29
28
|
const logger = createLogger('ethereum:deploy_aztec_l1_contracts');
|
|
@@ -491,7 +490,25 @@ export type VerificationRecord = {
|
|
|
491
490
|
libraries: VerificationLibraryEntry[];
|
|
492
491
|
};
|
|
493
492
|
|
|
494
|
-
export interface DeployAztecL1ContractsArgs
|
|
493
|
+
export interface DeployAztecL1ContractsArgs
|
|
494
|
+
extends Omit<
|
|
495
|
+
L1ContractsConfig,
|
|
496
|
+
| 'gasLimitBufferPercentage'
|
|
497
|
+
| 'maxGwei'
|
|
498
|
+
| 'maxBlobGwei'
|
|
499
|
+
| 'priorityFeeBumpPercentage'
|
|
500
|
+
| 'priorityFeeRetryBumpPercentage'
|
|
501
|
+
| 'minimumPriorityFeePerGas'
|
|
502
|
+
| 'maxSpeedUpAttempts'
|
|
503
|
+
| 'checkIntervalMs'
|
|
504
|
+
| 'stallTimeMs'
|
|
505
|
+
| 'txTimeoutMs'
|
|
506
|
+
| 'cancelTxOnTimeout'
|
|
507
|
+
| 'txCancellationFinalTimeoutMs'
|
|
508
|
+
| 'txUnseenConsideredDroppedMs'
|
|
509
|
+
| 'enableDelayer'
|
|
510
|
+
| 'txDelayerMaxInclusionTimeIntoSlot'
|
|
511
|
+
> {
|
|
495
512
|
/** The vk tree root. */
|
|
496
513
|
vkTreeRoot: Fr;
|
|
497
514
|
/** The hash of the protocol contracts. */
|