Skip to content

Commit 89386a3

Browse files
author
AztecBot
committed
Merge branch 'next' into merge-train/avm
2 parents 43c13f0 + 9f2e319 commit 89386a3

File tree

20 files changed

+523
-83
lines changed

20 files changed

+523
-83
lines changed

yarn-project/aztec-node/src/aztec-node/server.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ import {
8282
tryStop,
8383
} from '@aztec/stdlib/interfaces/server';
8484
import type { LogFilter, PrivateLog, TxScopedL2Log } from '@aztec/stdlib/logs';
85-
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
85+
import { InboxLeaf, type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
8686
import { P2PClientType } from '@aztec/stdlib/p2p';
8787
import type { Offense, SlashPayloadRound } from '@aztec/stdlib/slashing';
8888
import type { NullifierLeafPreimage, PublicDataTreeLeaf, PublicDataTreeLeafPreimage } from '@aztec/stdlib/trees';
@@ -860,13 +860,19 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
860860
return [witness.index, witness.path];
861861
}
862862

863+
public async getL1ToL2MessageBlock(l1ToL2Message: Fr): Promise<number | undefined> {
864+
const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
865+
return messageIndex ? InboxLeaf.l2BlockFromIndex(messageIndex) : undefined;
866+
}
867+
863868
/**
864869
* Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block.
865870
* @param l1ToL2Message - The L1 to L2 message to check.
866871
* @returns Whether the message is synced and ready to be included in a block.
867872
*/
868873
public async isL1ToL2MessageSynced(l1ToL2Message: Fr): Promise<boolean> {
869-
return (await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message)) !== undefined;
874+
const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
875+
return messageIndex !== undefined;
870876
}
871877

872878
/**

yarn-project/aztec.js/src/api/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ export { waitForPXE } from '../utils/pxe.js';
1919
export { waitForNode, createAztecNodeClient, type AztecNode } from '../utils/node.js';
2020
export { getFeeJuiceBalance } from '../utils/fee_juice.js';
2121
export { readFieldCompressedString } from '../utils/field_compressed_string.js';
22+
export { isL1ToL2MessageReady, waitForL1ToL2MessageReady } from '../utils/cross_chain.js';

yarn-project/aztec.js/src/contract/batch_call.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ export class BatchCall extends BaseContractInteraction {
1414
super(wallet);
1515
}
1616

17+
/**
18+
* Creates a new instance with no actual calls. Useful for triggering a no-op.
19+
* @param wallet - The wallet to use for sending the batch call.
20+
*/
21+
public static empty(wallet: Wallet) {
22+
return new BatchCall(wallet, []);
23+
}
24+
1725
/**
1826
* Returns an execution request that represents this operation.
1927
* @param options - An optional object containing additional configuration for the request generation.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import type { Fr } from '@aztec/foundation/fields';
2+
import { retryUntil } from '@aztec/foundation/retry';
3+
4+
import type { PXE } from '../api/interfaces.js';
5+
6+
/**
7+
* Waits for the L1 to L2 message to be ready to be consumed.
8+
* @param pxe - PXE instance
9+
* @param l1ToL2MessageHash - Hash of the L1 to L2 message
10+
* @param opts - Options
11+
*/
12+
export async function waitForL1ToL2MessageReady(
13+
pxe: Pick<PXE, 'getBlockNumber' | 'getL1ToL2MessageBlock'>,
14+
l1ToL2MessageHash: Fr,
15+
opts: {
16+
/** Timeout for the operation in seconds */ timeoutSeconds: number;
17+
/** True if the message is meant to be consumed from a public function */ forPublicConsumption: boolean;
18+
},
19+
) {
20+
const messageBlockNumber = await pxe.getL1ToL2MessageBlock(l1ToL2MessageHash);
21+
return retryUntil(
22+
() => isL1ToL2MessageReady(pxe, l1ToL2MessageHash, { ...opts, messageBlockNumber }),
23+
`L1 to L2 message ${l1ToL2MessageHash.toString()} ready`,
24+
opts.timeoutSeconds,
25+
1,
26+
);
27+
}
28+
29+
/**
30+
* Returns whether the L1 to L2 message is ready to be consumed.
31+
* @param pxe - PXE instance
32+
* @param l1ToL2MessageHash - Hash of the L1 to L2 message
33+
* @param opts - Options
34+
* @returns True if the message is ready to be consumed, false otherwise
35+
*/
36+
export async function isL1ToL2MessageReady(
37+
pxe: Pick<PXE, 'getBlockNumber' | 'getL1ToL2MessageBlock'>,
38+
l1ToL2MessageHash: Fr,
39+
opts: {
40+
/** True if the message is meant to be consumed from a public function */ forPublicConsumption: boolean;
41+
/** Cached synced block number for the message (will be fetched from PXE otherwise) */ messageBlockNumber?: number;
42+
},
43+
): Promise<boolean> {
44+
const blockNumber = await pxe.getBlockNumber();
45+
const messageBlockNumber = opts.messageBlockNumber ?? (await pxe.getL1ToL2MessageBlock(l1ToL2MessageHash));
46+
if (messageBlockNumber === undefined) {
47+
return false;
48+
}
49+
50+
// Note that public messages can be consumed 1 block earlier, since the sequencer will include the messages
51+
// in the L1 to L2 message tree before executing the txs for the block. In private, however, we need to wait
52+
// until the message is included so we can make use of the membership witness.
53+
return opts.forPublicConsumption ? blockNumber + 1 >= messageBlockNumber : blockNumber >= messageBlockNumber;
54+
}

yarn-project/aztec/src/testing/anvil_test_watcher.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export class AnvilTestWatcher {
5050
}
5151

5252
setIsMarkingAsProven(isMarkingAsProven: boolean) {
53+
this.logger.warn(`Watcher is now ${isMarkingAsProven ? 'marking' : 'not marking'} blocks as proven`);
5354
this.isMarkingAsProven = isMarkingAsProven;
5455
}
5556

yarn-project/bot/src/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ export const botConfigMappings: ConfigMappingsType<BotConfig> = {
154154
l1ToL2MessageTimeoutSeconds: {
155155
env: 'BOT_L1_TO_L2_TIMEOUT_SECONDS',
156156
description: 'How long to wait for L1 to L2 messages to become available on L2',
157-
...numberConfigHelper(60),
157+
...numberConfigHelper(3600),
158158
},
159159
senderPrivateKey: {
160160
env: 'BOT_PRIVATE_KEY',

yarn-project/bot/src/factory.ts

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
type PXE,
1313
createLogger,
1414
createPXEClient,
15-
retryUntil,
15+
waitForL1ToL2MessageReady,
1616
} from '@aztec/aztec.js';
1717
import { createEthereumChain, createExtendedL1Client } from '@aztec/ethereum';
1818
import { Fr } from '@aztec/foundation/fields';
@@ -112,8 +112,10 @@ export class BotFactory {
112112
private async setupAccount() {
113113
const privateKey = this.config.senderPrivateKey?.getValue();
114114
if (privateKey) {
115+
this.log.info(`Setting up account with provided private key`);
115116
return await this.setupAccountWithPrivateKey(privateKey);
116117
} else {
118+
this.log.info(`Setting up test account`);
117119
return await this.setupTestAccount();
118120
}
119121
}
@@ -395,35 +397,31 @@ export class BotFactory {
395397
const mintAmount = await portal.getTokenManager().getMintAmount();
396398
const claim = await portal.bridgeTokensPublic(recipient, mintAmount, true /* mint */);
397399

398-
const isSynced = async () => await this.pxe.isL1ToL2MessageSynced(Fr.fromHexString(claim.messageHash));
399-
await retryUntil(isSynced, `message ${claim.messageHash} sync`, this.config.l1ToL2MessageTimeoutSeconds, 1);
400+
await this.withNoMinTxsPerBlock(() =>
401+
waitForL1ToL2MessageReady(this.pxe, Fr.fromHexString(claim.messageHash), {
402+
timeoutSeconds: this.config.l1ToL2MessageTimeoutSeconds,
403+
forPublicConsumption: false,
404+
}),
405+
);
400406

401407
this.log.info(`Created a claim for ${mintAmount} L1 fee juice to ${recipient}.`, claim);
402408

403-
// Progress by 2 L2 blocks so that the l1ToL2Message added above will be available to use on L2.
404-
await this.advanceL2Block();
405-
await this.advanceL2Block();
406-
407409
return claim;
408410
}
409411

410412
private async withNoMinTxsPerBlock<T>(fn: () => Promise<T>): Promise<T> {
411413
if (!this.nodeAdmin || !this.config.flushSetupTransactions) {
414+
this.log.verbose(`No node admin client or flushing not requested (not setting minTxsPerBlock to 0)`);
412415
return fn();
413416
}
414417
const { minTxsPerBlock } = await this.nodeAdmin.getConfig();
418+
this.log.warn(`Setting sequencer minTxsPerBlock to 0 from ${minTxsPerBlock} to flush setup transactions`);
415419
await this.nodeAdmin.setConfig({ minTxsPerBlock: 0 });
416420
try {
417421
return await fn();
418422
} finally {
423+
this.log.warn(`Restoring sequencer minTxsPerBlock to ${minTxsPerBlock}`);
419424
await this.nodeAdmin.setConfig({ minTxsPerBlock });
420425
}
421426
}
422-
423-
private async advanceL2Block() {
424-
await this.withNoMinTxsPerBlock(async () => {
425-
const initialBlockNumber = await this.node!.getBlockNumber();
426-
await retryUntil(async () => (await this.node!.getBlockNumber()) >= initialBlockNumber + 1);
427-
});
428-
}
429427
}

yarn-project/end-to-end/src/e2e_bot.test.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import { getInitialTestAccountsData } from '@aztec/accounts/testing';
2-
import type { PXE } from '@aztec/aztec.js';
2+
import { Fr, type PXE } from '@aztec/aztec.js';
33
import { AmmBot, Bot, type BotConfig, SupportedTokenContracts, getBotDefaultConfig } from '@aztec/bot';
44
import { AVM_MAX_PROCESSABLE_L2_GAS, MAX_PROCESSABLE_DA_GAS_PER_BLOCK } from '@aztec/constants';
5+
import { SecretValue } from '@aztec/foundation/config';
6+
import { bufferToHex } from '@aztec/foundation/string';
57

6-
import { setup } from './fixtures/utils.js';
8+
import { type EndToEndContext, getPrivateKeyFromIndex, setup } from './fixtures/utils.js';
79

810
describe('e2e_bot', () => {
911
let pxe: PXE;
1012
let teardown: () => Promise<void>;
1113

1214
let config: BotConfig;
15+
let ctx: EndToEndContext;
1316

1417
beforeAll(async () => {
1518
const initialFundedAccounts = await getInitialTestAccountsData();
16-
({ teardown, pxe } = await setup(1, {
17-
initialFundedAccounts,
18-
}));
19+
ctx = await setup(1, { initialFundedAccounts });
20+
({ teardown, pxe } = ctx);
1921
});
2022

2123
afterAll(() => teardown());
@@ -59,13 +61,7 @@ describe('e2e_bot', () => {
5961
});
6062

6163
it('sends token from the bot using PrivateToken', async () => {
62-
const easyBot = await Bot.create(
63-
{
64-
...config,
65-
contract: SupportedTokenContracts.PrivateTokenContract,
66-
},
67-
{ pxe },
68-
);
64+
const easyBot = await Bot.create({ ...config, contract: SupportedTokenContracts.PrivateTokenContract }, { pxe });
6965
const { recipient: recipientBefore } = await easyBot.getBalances();
7066

7167
await easyBot.run();
@@ -105,4 +101,25 @@ describe('e2e_bot', () => {
105101
).toBeTrue();
106102
});
107103
});
104+
105+
describe('setup via bridging funds cross-chain', () => {
106+
beforeAll(() => {
107+
config = {
108+
...getBotDefaultConfig(),
109+
followChain: 'PENDING',
110+
ammTxs: false,
111+
senderPrivateKey: new SecretValue(Fr.random()),
112+
l1PrivateKey: new SecretValue(bufferToHex(getPrivateKeyFromIndex(8)!)),
113+
l1RpcUrls: ctx.config.l1RpcUrls,
114+
flushSetupTransactions: true,
115+
};
116+
});
117+
118+
// See 'can consume L1 to L2 message in %s after inbox drifts away from the rollup'
119+
// in end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts for context on this test.
120+
it('creates bot after inbox drift', async () => {
121+
await ctx.cheatCodes.rollup.advanceInboxInProgress(10);
122+
await Bot.create(config, { pxe, node: ctx.aztecNode, nodeAdmin: ctx.aztecNodeAdmin });
123+
}, 300_000);
124+
});
108125
});

yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { AztecNodeConfig } from '@aztec/aztec-node';
22
import { AztecAddress, type AztecNode, EthAddress, type Logger, type PXE, createLogger } from '@aztec/aztec.js';
33
import { CheatCodes } from '@aztec/aztec/testing';
44
import {
5+
type DeployL1ContractsArgs,
56
type DeployL1ContractsReturnType,
67
type ExtendedViemWalletClient,
78
createExtendedL1Client,
@@ -23,6 +24,7 @@ import {
2324
deployAccounts,
2425
publicDeployAccounts,
2526
} from '../fixtures/snapshot_manager.js';
27+
import type { SetupOptions } from '../fixtures/utils.js';
2628
import { CrossChainTestHarness } from '../shared/cross_chain_test_harness.js';
2729

2830
const { E2E_DATA_PATH: dataPath } = process.env;
@@ -34,6 +36,7 @@ export class CrossChainMessagingTest {
3436
pxe!: PXE;
3537
aztecNodeConfig!: AztecNodeConfig;
3638
aztecNodeAdmin!: AztecNodeAdmin;
39+
ctx!: SubsystemsContext;
3740

3841
l1Client!: ExtendedViemWalletClient | undefined;
3942

@@ -52,23 +55,26 @@ export class CrossChainMessagingTest {
5255

5356
deployL1ContractsValues!: DeployL1ContractsReturnType;
5457

55-
constructor(testName: string) {
58+
constructor(testName: string, opts: SetupOptions = {}, deployL1ContractsArgs: Partial<DeployL1ContractsArgs> = {}) {
5659
this.logger = createLogger(`e2e:e2e_cross_chain_messaging:${testName}`);
57-
this.snapshotManager = createSnapshotManager(`e2e_cross_chain_messaging/${testName}`, dataPath);
60+
this.snapshotManager = createSnapshotManager(`e2e_cross_chain_messaging/${testName}`, dataPath, opts, {
61+
initialValidators: [],
62+
...deployL1ContractsArgs,
63+
});
5864
}
5965

6066
async assumeProven() {
6167
await this.cheatCodes.rollup.markAsProven();
6268
}
6369

6470
async setup() {
65-
const { aztecNode, pxe, aztecNodeConfig, deployL1ContractsValues } = await this.snapshotManager.setup();
66-
this.aztecNode = aztecNode;
67-
this.pxe = pxe;
68-
this.aztecNodeConfig = aztecNodeConfig;
71+
this.ctx = await this.snapshotManager.setup();
72+
this.aztecNode = this.ctx.aztecNode;
73+
this.pxe = this.ctx.pxe;
74+
this.aztecNodeConfig = this.ctx.aztecNodeConfig;
6975
this.cheatCodes = await CheatCodes.create(this.aztecNodeConfig.l1RpcUrls, this.pxe);
70-
this.deployL1ContractsValues = deployL1ContractsValues;
71-
this.aztecNodeAdmin = aztecNode;
76+
this.deployL1ContractsValues = this.ctx.deployL1ContractsValues;
77+
this.aztecNodeAdmin = this.ctx.aztecNode;
7278
}
7379

7480
snapshot = <T>(

0 commit comments

Comments
 (0)